135 lines · 4.6 KB · TypeScript
RawDownload
// ---------------------------------------------------------------------------// @executor/execution/promise — Promise-native surface for the execution// engine.// ---------------------------------------------------------------------------//// `engine.ts` is Effect-native; this module runs each method with// `Effect.runPromise` at the boundary so hosts that can't compose Effects// (the MCP SDK tool handlers, plain async call sites) can still use the// engine. Callers already inside an Effect context should import directly// from `@executor/execution` to keep trace context intact.// --------------------------------------------------------------------------- import { Effect } from "effect";import type * as Cause from "effect/Cause"; import type {  ElicitationContext,  ElicitationResponse,  Executor as PromiseExecutor,} from "@executor/sdk";import type { CodeExecutionError, CodeExecutor, ExecuteResult } from "@executor/codemode-core"; import {  createExecutionEngine as createEffectExecutionEngine,  type ExecutionEngine as EffectExecutionEngine,  type ExecutionResult,  type PausedExecution,  type ResumeResponse,} from "./engine"; export type ElicitationHandler = (  ctx: ElicitationContext,) => Promise<ElicitationResponse>; export type ExecutionEngineConfig<  E extends Cause.YieldableError = CodeExecutionError,> = {  readonly executor: PromiseExecutor;  readonly codeExecutor: CodeExecutor<E>;}; export type ExecutionEngine = {  readonly execute: (    code: string,    options: { readonly onElicitation: ElicitationHandler },  ) => Promise<ExecuteResult>;  readonly executeWithPause: (code: string) => Promise<ExecutionResult>;  readonly resume: (    executionId: string,    response: ResumeResponse,  ) => Promise<ExecutionResult | null>;  readonly getDescription: () => Promise<string>;}; /** * Wrap a Promise-style executor into the Effect shape the engine consumes. * Only the four method families the engine actually touches need wrapping: * `tools.{invoke,list,schema,definitions}` and `sources.list`. */const wrapPromiseExecutor = (pe: PromiseExecutor): any => ({  scope: (pe as any).scope,  tools: {    invoke: (id: unknown, args: unknown, options: unknown) =>      Effect.tryPromise({        try: () => (pe.tools as any).invoke(id, args, options),        catch: (cause) => cause,      }),    list: (filter?: unknown) =>      Effect.tryPromise({        try: () => (pe.tools as any).list(filter),        catch: (cause) => cause,      }).pipe(Effect.orDie),    schema: (id: unknown) =>      Effect.tryPromise({        try: () => (pe.tools as any).schema(id),        catch: (cause) => cause,      }),    definitions: () =>      Effect.tryPromise({        try: () => (pe.tools as any).definitions(),        catch: (cause) => cause,      }).pipe(Effect.orDie),  },  sources: {    list: () =>      Effect.tryPromise({        try: () => (pe.sources as any).list(),        catch: (cause) => cause,      }).pipe(Effect.orDie),  },}); /** * Promise-wrap an Effect-native `ExecutionEngine` (from `./engine`). * Exposed separately so callers that already hold an Effect engine * (apps/cloud's execution-stack composes both) can convert it for hosts * that need the Promise surface (host-mcp). */export const toPromiseExecutionEngine = <E extends Cause.YieldableError>(  engine: EffectExecutionEngine<E>,): ExecutionEngine => ({  execute: (code, options) =>    Effect.runPromise(      engine.execute(code, {        onElicitation: (ctx) =>          Effect.tryPromise(() => options.onElicitation(ctx)).pipe(Effect.orDie),      }),    ),  executeWithPause: (code) => Effect.runPromise(engine.executeWithPause(code)),  resume: (executionId, response) => Effect.runPromise(engine.resume(executionId, response)),  getDescription: () => Effect.runPromise(engine.getDescription),}); export const createExecutionEngine = <  E extends Cause.YieldableError = CodeExecutionError,>(  config: ExecutionEngineConfig<E>,): ExecutionEngine =>  toPromiseExecutionEngine(    createEffectExecutionEngine({      executor: wrapPromiseExecutor(config.executor),      codeExecutor: config.codeExecutor,    }),  ); // ---------------------------------------------------------------------------// Re-exports — plain types/helpers that don't carry Effect signatures.// --------------------------------------------------------------------------- export { formatExecuteResult, formatPausedExecution } from "./engine"; export type { ExecutionResult, PausedExecution, ResumeResponse }; export { buildExecuteDescription } from "./description";export { ExecutionToolError } from "./errors";

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t