134 lines · 4.8 KB · TypeScript
RawDownload
import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi";import { Schema } from "effect"; import { InternalError } from "@executor-js/sdk/shared"; // ---------------------------------------------------------------------------// Schemas// --------------------------------------------------------------------------- const ExecuteRequest = Schema.Struct({  code: Schema.String,  // When true the caller is the human approver: approval-gated tools run to  // completion instead of pausing. Set by the operator-facing Run/Test panel,  // where clicking Run is itself the approval. `block` policies still apply.  autoApprove: Schema.optional(Schema.Boolean),  /**   * Set when the caller is a rendered artifact rather than the console's own   * code surface — the artifact page has no MCP client, so the shell reaches   * the server here instead of through `execute-action`.   *   * It narrows the request in both directions: the code must be one   * proxy-shaped tool call, and the integration role it names is resolved   * through that artifact's stored connection bindings. Absent, this is   * ordinary codemode and nothing changes.   */  artifactId: Schema.optional(Schema.String),}); const CompletedResult = Schema.Struct({  status: Schema.Literal("completed"),  text: Schema.String,  structured: Schema.Unknown,  isError: Schema.Boolean,}); const PausedResult = Schema.Struct({  status: Schema.Literal("paused"),  text: Schema.String,  structured: Schema.Unknown,}); const ExecuteResponse = Schema.Union([CompletedResult, PausedResult]); const ResumeRequest = Schema.Struct({  action: Schema.Literals(["accept", "decline", "cancel"]),  content: Schema.optional(Schema.Unknown),  /** How long an accepted approval lasts, when the paused interaction's   *  terms offer a choice (`interaction.meta.persist` lists the scopes).   *  Omitted, the approval is for this call only. */  persist: Schema.optional(Schema.String),}); const ResumeResponse = Schema.Union([CompletedResult, PausedResult]); const PausedExecutionInfo = Schema.Struct({  text: Schema.String,  structured: Schema.Unknown,}); const ExecutionNotFoundError = Schema.TaggedStruct("ExecutionNotFoundError", {  executionId: Schema.String,}).annotate({ httpApiStatus: 404 }); /** * The approval window closed before the human answered. * * Separate from `ExecutionNotFoundError` because the two mean different things * to the person clicking Approve: an unknown id is a client bug, while an * expired approval is an ordinary outcome with a clear next step — nothing ran, * so triggering the action again is safe. The shell renders this as its * expired-approval state rather than an error. */const ApprovalExpiredError = Schema.TaggedStruct("ApprovalExpiredError", {  executionId: Schema.String,})  .annotate({ httpApiStatus: 410 })  .annotate({    description:      "The approval window closed before the action was approved. Nothing ran; trigger the action again.",  }); /** * An artifact-originated execution that could not be turned into a call: the * code was not the shell proxy's emission, the artifact is not this caller's, * or a role in it has no connection bound. * * `role` and `integration` accompany `binding_unresolved` so a client can offer * to rebind rather than only report the failure. */const ArtifactActionError = Schema.TaggedStruct("ArtifactActionError", {  error: Schema.Literals(["invalid_action_code", "artifact_unavailable", "binding_unresolved"]),  reason: Schema.String,  role: Schema.optional(Schema.String),  integration: Schema.optional(Schema.String),})  .annotate({ httpApiStatus: 400 })  .annotate({    description:      "A rendered artifact's tool call could not be resolved: bad shape, unknown artifact, or an unbound integration role.",  }); // ---------------------------------------------------------------------------// Params// --------------------------------------------------------------------------- const ExecutionParams = { executionId: Schema.String }; // ---------------------------------------------------------------------------// Group// --------------------------------------------------------------------------- export const ExecutionsApi = HttpApiGroup.make("executions")  .add(    HttpApiEndpoint.get("getPaused", "/executions/:executionId", {      params: ExecutionParams,      success: PausedExecutionInfo,      error: [InternalError, ExecutionNotFoundError],    }),  )  .add(    HttpApiEndpoint.post("execute", "/executions", {      payload: ExecuteRequest,      success: ExecuteResponse,      error: [InternalError, ArtifactActionError],    }),  )  .add(    HttpApiEndpoint.post("resume", "/executions/:executionId/resume", {      params: ExecutionParams,      payload: ResumeRequest,      success: ResumeResponse,      error: [InternalError, ExecutionNotFoundError, ApprovalExpiredError],    }),  );