@agent-compose/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Sandbox provider registry — creates and manages isolated execution environments.
3
+ *
4
+ * Providers: "vercel" (Vercel Sandbox), "e2b" (E2B), "e2b-desktop" (E2B Desktop).
5
+ * Each provider validates its required env vars at creation time.
6
+ */
7
+ import { Sandbox } from "e2b";
8
+ import { Sandbox as Desktop } from "@e2b/desktop";
9
+ import type { SandboxProvider, DesktopSandboxProvider } from "./types/sandbox.js";
10
+ export type { SandboxProvider, DesktopSandboxProvider } from "./types/sandbox.js";
11
+ export declare const AGENT_COMPOSE_TAG: string;
12
+ /**
13
+ * Vercel-compatible network policy for outbound HTTPS requests.
14
+ * When a sandbox makes a request matching a domain in `allow`, the Vercel
15
+ * firewall injects the specified headers before forwarding — credentials never
16
+ * exist inside the VM. E2B ignores this field (future self-hosted mapping TBD).
17
+ */
18
+ export type SandboxNetworkPolicy = "allow-all" | "deny-all" | {
19
+ allow?: string[] | Record<string, Array<{
20
+ transform?: Array<{
21
+ headers?: Record<string, string>;
22
+ }>;
23
+ }>>;
24
+ subnets?: {
25
+ allow?: string[];
26
+ deny?: string[];
27
+ };
28
+ };
29
+ export interface SandboxCreateOpts {
30
+ envs: Record<string, string>;
31
+ metadata: Record<string, string>;
32
+ timeoutMs: number;
33
+ /** Provider-specific template/snapshot identifier. E2B: template ID; Vercel: snapshot ID. */
34
+ template?: string;
35
+ /** Outbound request policy. Vercel only — E2B silently ignores. */
36
+ networkPolicy?: SandboxNetworkPolicy;
37
+ }
38
+ /**
39
+ * What the provider reports as "currently alive" — the single input to orphan
40
+ * reconciliation. `metadata` is best-effort: E2B populates it from sandbox
41
+ * labels, Vercel leaves it empty (the API has no metadata field). Callers
42
+ * that need runId correlation cross-reference `sandboxId` against their own
43
+ * state (server: `workflow_runs.sandbox_id` + `run_agent_sandboxes.provider_sandbox_id`).
44
+ */
45
+ export interface OwnedSandbox {
46
+ sandboxId: string;
47
+ createdAt: Date;
48
+ metadata: Record<string, string>;
49
+ }
50
+ interface SandboxProviderDef {
51
+ requiredEnv: Record<string, string>;
52
+ create: (opts: SandboxCreateOpts, env: Record<string, string>) => Promise<SandboxProvider>;
53
+ reconnect?: (sandboxId: string) => Promise<SandboxProvider>;
54
+ killAll?: (env: Record<string, string>) => Promise<void>;
55
+ /**
56
+ * Returns the number of sandboxes currently running against this provider.
57
+ * Used for quota observability — account-wide, not per-instance.
58
+ *
59
+ * E2B scopes by our AGENT_COMPOSE_TAG metadata so each machine only reports
60
+ * its own sandboxes; DD aggregates across instances with `sum by {provider}`.
61
+ * Vercel has no user metadata support, so it counts every running sandbox in
62
+ * the configured project (assumed dedicated to agent-compose).
63
+ */
64
+ getActiveCount?: (env: Record<string, string>) => Promise<number>;
65
+ /**
66
+ * Provider's view of what's currently alive for our account/fleet.
67
+ * The reconciliation SoT — a sandbox missing from this list IS dead,
68
+ * regardless of what our DB says. Implemented by listing the provider's
69
+ * running sandboxes; E2B filters by metadata tag, Vercel lists the whole
70
+ * project (it has no metadata search). 200-row cap applies to Vercel.
71
+ */
72
+ listOwned?: (env: Record<string, string>) => Promise<OwnedSandbox[]>;
73
+ /**
74
+ * Delete a snapshot by id. Called from the customer-initiated
75
+ * `DELETE /workflows/:runId/snapshot` route. Best-effort — the DB is
76
+ * source of truth; an orphan on the provider side is benign and cleaned
77
+ * up eventually by the provider's own retention.
78
+ */
79
+ deleteSnapshot?: (snapshotId: string, env: Record<string, string>) => Promise<void>;
80
+ }
81
+ export declare function makeSandboxProvider(sb: Sandbox | Desktop): SandboxProvider;
82
+ export declare function makeDesktopSandboxProvider(sb: Desktop): DesktopSandboxProvider;
83
+ /**
84
+ * Parse an SSE exec stream from a ReadableStream.
85
+ * Used by the agent sandbox broker in runner.ts.
86
+ */
87
+ export declare function parseSseExecStream(body: ReadableStream<Uint8Array>, opts?: {
88
+ onStdout?: (d: string) => void;
89
+ onStderr?: (d: string) => void;
90
+ }): Promise<{
91
+ exitCode: number;
92
+ stdout: string;
93
+ }>;
94
+ /** Minimal SandboxProvider that targets the current process's host VM.
95
+ * `commands.run` → `child_process.spawn`; `files.write` → `fs.writeFile`;
96
+ * `kill` is a no-op because the caller IS the VM. Used by
97
+ * `defineSandboxEnvironment` so setup recipes read like imperative
98
+ * provisioning scripts. Uses `node:child_process` — works under both Node
99
+ * (the runner executes `node /tmp/runner.bundle.js`) and Bun. */
100
+ export declare function makeLocalSandboxProvider(): SandboxProvider;
101
+ declare const SANDBOX_PROVIDERS: Record<string, SandboxProviderDef>;
102
+ /** Provision a sandbox for the named provider. */
103
+ export declare function createSandbox(provider: string, opts: SandboxCreateOpts): Promise<SandboxProvider>;
104
+ /** Reconnect to an existing sandbox by provider + provider-native sandbox ID. */
105
+ export declare function reconnectSandbox(provider: string, sandboxId: string): Promise<SandboxProvider>;
106
+ /** Delete a snapshot by id on the named provider. No live sandbox needed. */
107
+ export declare function deleteSandboxSnapshot(provider: string, snapshotId: string): Promise<void>;
108
+ /**
109
+ * Current active-sandbox count per configured provider, for quota gauges.
110
+ * Skips providers whose required env isn't set or which don't implement
111
+ * `getActiveCount`. Errors are surfaced per-provider so one flaky provider
112
+ * doesn't silence the rest.
113
+ */
114
+ export declare function getSandboxQuotas(): Promise<Record<string, number | Error>>;
115
+ /**
116
+ * List every alive sandbox owned by this fleet, across all configured
117
+ * providers — the orphan-reconciler SoT. Providers without `listOwned`
118
+ * or missing env are skipped. Errors propagate per-provider so one flaky
119
+ * provider doesn't silence the rest.
120
+ */
121
+ export declare function listOwnedSandboxes(): Promise<Record<string, OwnedSandbox[] | Error>>;
122
+ /** Kill a sandbox by provider + native ID. Used by the orphan reconciler. */
123
+ export declare function killSandboxById(provider: string, sandboxId: string): Promise<void>;
124
+ /** Kill all sandboxes across all registered providers. Call at startup to clean up after crashes. */
125
+ export declare function killAllSandboxes(onError?: (provider: string, err: unknown) => void): Promise<void>;
126
+ export { SANDBOX_PROVIDERS };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * RunEvent — the canonical streaming contract for agent-compose SSE streams.
3
+ *
4
+ * Emitted by the server via pg_notify and forwarded to clients over
5
+ * GET /api/v1/workflows/:id/stream. Every event carries `runId`, `at` (unix ms),
6
+ * and `seq` (the DB row id for Last-Event-ID resumption).
7
+ *
8
+ * The `event` field doubles as the SSE `event:` name.
9
+ */
10
+ export type RunEvent = {
11
+ event: "agent_event";
12
+ runId: string;
13
+ at: number;
14
+ seq?: number;
15
+ msgType: string;
16
+ toolName?: string;
17
+ toolDetail?: string;
18
+ isError?: boolean;
19
+ } | {
20
+ event: "agent_spawned";
21
+ runId: string;
22
+ at: number;
23
+ seq?: number;
24
+ agentIndex: number;
25
+ agentId: string;
26
+ label: string;
27
+ sandboxId: string;
28
+ agentName: string;
29
+ parentAgentId: string | null;
30
+ } | {
31
+ event: "agent_settled";
32
+ runId: string;
33
+ at: number;
34
+ seq?: number;
35
+ agentIndex: number;
36
+ agentId: string;
37
+ label: string;
38
+ outcome: "success" | "failed";
39
+ durationMs: number;
40
+ failureReason?: string;
41
+ } | {
42
+ event: "step_started";
43
+ runId: string;
44
+ at: number;
45
+ seq?: number;
46
+ step: string;
47
+ } | {
48
+ event: "step_completed";
49
+ runId: string;
50
+ at: number;
51
+ seq?: number;
52
+ step: string;
53
+ durationMs: number;
54
+ } | {
55
+ event: "step_failed";
56
+ runId: string;
57
+ at: number;
58
+ seq?: number;
59
+ step: string;
60
+ durationMs: number;
61
+ reason: string;
62
+ } | {
63
+ event: "run_complete";
64
+ runId: string;
65
+ at: number;
66
+ seq?: number;
67
+ } | {
68
+ event: "run_failed";
69
+ runId: string;
70
+ at: number;
71
+ seq?: number;
72
+ reason: string;
73
+ } | {
74
+ event: "workflow_log";
75
+ runId: string;
76
+ at: number;
77
+ seq?: number;
78
+ level: "info" | "warn" | "error";
79
+ msg: string;
80
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Agent message protocol — the stream of events emitted by a runtime's ModelExecutionContract.
3
+ */
4
+ interface AgentMessageBase {
5
+ timestamp: string;
6
+ }
7
+ export interface AgentMessageInit extends AgentMessageBase {
8
+ type: "init";
9
+ sessionId: string;
10
+ }
11
+ export interface AgentMessageText extends AgentMessageBase {
12
+ type: "text";
13
+ text: string;
14
+ }
15
+ export interface AgentMessageThinking extends AgentMessageBase {
16
+ type: "thinking";
17
+ text: string;
18
+ }
19
+ export interface AgentMessageToolUse extends AgentMessageBase {
20
+ type: "tool_use";
21
+ toolName: string;
22
+ toolInput: Record<string, unknown>;
23
+ toolUseId: string;
24
+ }
25
+ export interface AgentMessageToolResult extends AgentMessageBase {
26
+ type: "tool_result";
27
+ toolUseId: string;
28
+ output: string;
29
+ isError: boolean;
30
+ }
31
+ export interface AgentMessageDone extends AgentMessageBase {
32
+ type: "done";
33
+ sessionId: string;
34
+ }
35
+ export interface AgentMessageError extends AgentMessageBase {
36
+ type: "error";
37
+ text: string;
38
+ }
39
+ export interface AgentMessageUsage extends AgentMessageBase {
40
+ type: "usage";
41
+ inputTokens: number;
42
+ outputTokens: number;
43
+ cacheReadTokens: number;
44
+ cacheCreationTokens: number;
45
+ durationMs: number;
46
+ numTurns: number;
47
+ }
48
+ export type AgentMessage = AgentMessageInit | AgentMessageText | AgentMessageThinking | AgentMessageToolUse | AgentMessageToolResult | AgentMessageDone | AgentMessageError | AgentMessageUsage;
49
+ /** Status block the agent emits to signal iteration completion or blockers. */
50
+ export interface AgentStatus {
51
+ summary: string;
52
+ completed: string[];
53
+ blockers: string[];
54
+ exit_signal: boolean;
55
+ }
56
+ export {};
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Agent runtime types — the execution strategy for driving a model.
3
+ */
4
+ import type { SandboxProvider } from "./sandbox.js";
5
+ import type { AgentMessage } from "./protocol.js";
6
+ /** Configuration for a single MCP server. */
7
+ export interface McpServerConfig {
8
+ command: string;
9
+ args?: string[];
10
+ env?: Record<string, string>;
11
+ }
12
+ /** Options passed to a runtime when creating a ModelExecutionContract. */
13
+ export interface RuntimeOptions {
14
+ allowedTools?: string[];
15
+ maxTurns?: number;
16
+ model?: string;
17
+ /** Label prefix for all stderr output. */
18
+ label?: string;
19
+ /** Working directory — the claude CLI process starts here so relative paths work correctly. */
20
+ cwd?: string;
21
+ }
22
+ /**
23
+ * The execution contract every runtime must satisfy.
24
+ * Given a prompt, yield a stream of agent events.
25
+ */
26
+ export interface ModelExecutionContract {
27
+ sendMessage(opts: {
28
+ prompt: string;
29
+ sessionId?: string;
30
+ signal?: AbortSignal;
31
+ }): AsyncGenerator<AgentMessage>;
32
+ }
33
+ /**
34
+ * An agent runtime — a model execution strategy that drives an agent inside a sandbox.
35
+ *
36
+ * The sandbox provider (e.g. "vercel", "e2b") is an infrastructure concern
37
+ * configured via SANDBOX_PROVIDER — not part of the runtime definition.
38
+ * For non-sandbox agents (API calls, etc.) make the call directly in the workflow;
39
+ * spawnAgent is a sandbox concept.
40
+ */
41
+ export interface AgentRuntime<S extends SandboxProvider = SandboxProvider> {
42
+ create(sandbox: S, opts: RuntimeOptions): ModelExecutionContract;
43
+ }
44
+ /**
45
+ * Declare a registerable runtime. Validates required fields at module load time.
46
+ * Use `export default defineRuntime({...})` as the single export in runtime source files.
47
+ */
48
+ export declare function defineRuntime<S extends SandboxProvider = SandboxProvider>(pkg: AgentRuntime<S>): AgentRuntime<S>;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * A sandbox environment is a workflow whose job is to leave its VM in a
3
+ * configured state, then snapshot it so other workflows can boot from that
4
+ * state. Snapshots are **opt-in**: the wrapper below sets `snapshot: true`
5
+ * by default (opt out with `snapshot: false` if you only want side effects).
6
+ *
7
+ * Once captured, reference the snapshot from another workflow's
8
+ * `sandboxEnvironment` field by run UUID, workflow name, or `name@version`:
9
+ *
10
+ * sandboxEnvironment: "my-setup" // most recent successful snapshot
11
+ * sandboxEnvironment: "my-setup@v1" // version-scoped recency
12
+ * sandboxEnvironment: "<run-uuid>" // pinned to an exact run
13
+ *
14
+ * `defineSandboxEnvironment` is sugar over `defineWorkflow` — it makes the
15
+ * setup recipe read like an imperative script by supplying the local
16
+ * sandbox provider (the runner's own VM) to the callback.
17
+ *
18
+ * Typical flow:
19
+ * 1. Author a setup file with `defineSandboxEnvironment`.
20
+ * 2. `agentc register setup.ts --build` — registers and invokes once to
21
+ * capture the snapshot.
22
+ * 3. Other workflows declare `sandboxEnvironment: "name"` and boot from it.
23
+ * 4. `agentc snapshot list` / `delete` to manage the Vercel storage bill.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { defineSandboxEnvironment } from "@agent-compose/sdk";
28
+ *
29
+ * export default defineSandboxEnvironment({
30
+ * name: "python",
31
+ * setup: async (sb) => {
32
+ * await sb.commands.run("sudo dnf install -y python3-pip");
33
+ * },
34
+ * });
35
+ * ```
36
+ */
37
+ import type { SandboxProvider } from "./sandbox.js";
38
+ import type { WorkflowFn } from "./workflow.js";
39
+ export interface SandboxEnvironmentDefinition {
40
+ name: string;
41
+ description?: string;
42
+ setup: (sb: SandboxProvider) => Promise<void>;
43
+ /** Override the sugar's `snapshot: true` default. Set `false` to opt out
44
+ * of snapshot capture (rarely useful — an env with no snapshot can't be
45
+ * referenced as `sandboxEnvironment`). */
46
+ snapshot?: boolean;
47
+ }
48
+ export declare function defineSandboxEnvironment(env: SandboxEnvironmentDefinition): WorkflowFn<void>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Sandbox abstraction — the compute environment an agent runs inside.
3
+ * Provider-agnostic: E2B, Vercel, Docker, or any other backend implements this.
4
+ */
5
+ /** Base compute interface — pure I/O, no filesystem path or git concerns. */
6
+ export interface SandboxProvider {
7
+ sandboxId: string;
8
+ /** Working directory for the agent process. Set by onStart after environment setup. */
9
+ cwd?: string;
10
+ commands: {
11
+ run(cmd: string, opts?: {
12
+ cwd?: string;
13
+ timeoutMs?: number;
14
+ envs?: Record<string, string>;
15
+ onStdout?: (data: string) => void;
16
+ onStderr?: (data: string) => void;
17
+ background?: boolean;
18
+ }): Promise<{
19
+ exitCode: number;
20
+ stdout: string;
21
+ }>;
22
+ };
23
+ files: {
24
+ write(path: string, content: string): Promise<unknown>;
25
+ };
26
+ kill(): Promise<void>;
27
+ /** Capture the running sandbox's state as a reusable snapshot. Vercel
28
+ * supports it natively; E2B's model is Dockerfile-based and doesn't map
29
+ * cleanly — `undefined` on providers that don't. Used by the server's
30
+ * `--build` flow to stamp the snapshot id on the workflow row. */
31
+ snapshot?(): Promise<{
32
+ snapshotId: string;
33
+ }>;
34
+ }
35
+ /** Stateless provider-level snapshot deletion — no live sandbox needed,
36
+ * called from customer-initiated `DELETE /workflows/:runId/snapshot`. */
37
+ export type DeleteSnapshotFn = (snapshotId: string) => Promise<void>;
38
+ /** Extends SandboxProvider with desktop GUI capabilities. */
39
+ export interface DesktopSandboxProvider extends SandboxProvider {
40
+ screenshot(): Promise<Buffer>;
41
+ leftClick(x: number, y: number): Promise<void>;
42
+ doubleClick(x: number, y: number): Promise<void>;
43
+ rightClick(x: number, y: number): Promise<void>;
44
+ middleClick(x: number, y: number): Promise<void>;
45
+ moveMouse(x: number, y: number): Promise<void>;
46
+ write(text: string): Promise<void>;
47
+ press(key: string): Promise<void>;
48
+ scroll(direction: "up" | "down", ticks: number): Promise<void>;
49
+ drag(from: [number, number], to: [number, number]): Promise<void>;
50
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Workflow types — the context and function signature for authoring workflows.
3
+ *
4
+ * A workflow is `async (ctx, sandbox) => T`. Two positional args by design:
5
+ *
6
+ * - `ctx` carries facts + observability about THIS run (id, input,
7
+ * setMetadata, step). Metadata bag.
8
+ * - `sandbox` is a capability handed to you by the engine for doing work
9
+ * (exec commands, write files). Pass it to `runAgent({ sandbox, ... })`
10
+ * and to any helper that takes a SandboxProvider (git utilities, file
11
+ * writers). Constructed once per run; reuse it.
12
+ *
13
+ * LLM agent loops live in `runAgent(opts)` (sdk/src/agent/run-agent.ts).
14
+ * Invoking other workflows uses `AgentComposeClient.invoke[AndWait](...)`.
15
+ */
16
+ import type { SandboxNetworkPolicy } from "../sandbox.js";
17
+ import type { SandboxProvider } from "./sandbox.js";
18
+ /** The identity of this workflow run. */
19
+ export interface WorkflowRun {
20
+ id: string;
21
+ }
22
+ /** Turn/iteration budget for `runAgent(opts)`. Re-exported here so authors
23
+ * can type per-invoke budget overrides they pass as workflow input. */
24
+ export interface AgentBudget {
25
+ turnsPerIteration: number;
26
+ maxIterations: number;
27
+ }
28
+ /** Context passed to a workflow function — facts + observability for this run. */
29
+ export interface WorkflowCtx {
30
+ run: WorkflowRun;
31
+ input?: Record<string, unknown>;
32
+ /** Persist key-value metadata on the run record (e.g. prUrl, planUrl). */
33
+ setMetadata: (data: Record<string, unknown>) => Promise<void>;
34
+ /**
35
+ * Wrap a named step for observability. Emits step_started / step_completed /
36
+ * step_failed lifecycle events with duration. Use for long phases you want
37
+ * visible on the run's timeline (setup, external API calls, submit).
38
+ */
39
+ step<T>(name: string, fn: () => Promise<T>): Promise<T>;
40
+ }
41
+ /** A workflow is `async (ctx, sandbox) => T`. */
42
+ export type WorkflowFn<T = unknown> = (ctx: WorkflowCtx, sandbox: SandboxProvider) => Promise<T>;
43
+ /**
44
+ * Declare a workflow with server-side metadata.
45
+ * Use `export default defineWorkflow({ run, networkPolicy, ... })` to attach
46
+ * a runner network policy so the server brokers credentials for the workflow
47
+ * sandbox.
48
+ *
49
+ * Without defineWorkflow, a plain `export default async (ctx) => {...}` still
50
+ * works — the workflow just runs with secrets passed directly in env.
51
+ */
52
+ export interface WorkflowDefinition<T = unknown> {
53
+ run: WorkflowFn<T>;
54
+ /**
55
+ * Name (or `name@version`) of another workflow whose built snapshot this
56
+ * workflow's runner boots into. Any workflow registered with `--build`
57
+ * can be used as a sandbox environment.
58
+ */
59
+ sandboxEnvironment?: string;
60
+ /**
61
+ * Capture a snapshot of the sandbox on successful /complete. Snapshots are
62
+ * long-lived (never auto-expire) — customers list + delete them explicitly
63
+ * via `agentc snapshot list/delete`. Per-invocation `invoke({ snapshot })`
64
+ * overrides this default. `defineSandboxEnvironment` sugar sets this to
65
+ * true by default.
66
+ */
67
+ snapshot?: boolean;
68
+ /**
69
+ * Outbound network policy for the runner sandbox.
70
+ * Use "*": [] to allow all traffic while still injecting headers for specific domains.
71
+ * Secret values are referenced as $VARIABLE and resolved from GCP at dispatch time.
72
+ * Vercel only — E2B ignores.
73
+ *
74
+ * @example
75
+ * networkPolicy: {
76
+ * allow: {
77
+ * "*": [],
78
+ * "api.github.com": [{ transform: [{ headers: { "Authorization": "basic:$GITHUB_TOKEN" } }] }],
79
+ * }
80
+ * }
81
+ */
82
+ networkPolicy?: SandboxNetworkPolicy;
83
+ /**
84
+ * Optional placeholder env var values for secrets referenced in the network policy.
85
+ * By default, brokered secrets are removed from the runner env entirely — the real
86
+ * values are only ever present inside the Vercel firewall config, never in the VM.
87
+ * Only set this if a tool or SDK validates the env var format on startup before
88
+ * making any requests (e.g. some CLIs check that ANTHROPIC_API_KEY looks like a
89
+ * real key). The placeholder is a syntactically valid but non-functional stand-in.
90
+ *
91
+ * @example
92
+ * placeholders: {
93
+ * ANTHROPIC_API_KEY: `sk-ant-api03-${"a".repeat(95)}`,
94
+ * }
95
+ */
96
+ placeholders?: Record<string, string>;
97
+ }
98
+ /**
99
+ * Attach server-side metadata to a workflow function.
100
+ * The returned function is a valid WorkflowFn with metadata fields attached
101
+ * for the bundler / registration layer to read.
102
+ */
103
+ export declare function defineWorkflow<T = unknown>(def: WorkflowDefinition<T>): WorkflowFn<T> & Pick<WorkflowDefinition, "networkPolicy" | "placeholders" | "sandboxEnvironment" | "snapshot">;
104
+ /** Observability-only lifecycle hooks — passed to the workflow engine, not workflow authors. */
105
+ export interface WorkflowHooks {
106
+ onStepStart?: (step: string) => void;
107
+ onStepComplete?: (step: string, durationMs: number) => void;
108
+ onStepFail?: (step: string, durationMs: number, reason: string) => void;
109
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Bundle a workflow for registration.
3
+ *
4
+ * Shared between the CLI (agentc register) and tests. Uses `Bun.build`
5
+ * to bundle TypeScript sources into a self-contained ESM module.
6
+ *
7
+ * Post de-broker there are no agent bundles to produce — workflows embed
8
+ * their agent loops inline via `runAgent(...)`, and workflows invoke other
9
+ * workflows via the public SDK client.
10
+ */
11
+ import type { SandboxNetworkPolicy } from "../sandbox.js";
12
+ export interface BundledWorkflow {
13
+ source: string;
14
+ networkPolicy?: SandboxNetworkPolicy;
15
+ placeholders?: Record<string, string>;
16
+ /** Name (or `name@version`) of another workflow whose built snapshot this
17
+ * workflow boots from, if declared via `sandboxEnvironment`. */
18
+ sandboxEnvironment?: string;
19
+ /** Default snapshot-on-success flag from the workflow definition, if any. */
20
+ snapshot?: boolean;
21
+ }
22
+ /** Bundle a workflow from source. */
23
+ export declare function bundleWorkflow(workflowPath: string, overrides?: {
24
+ networkPolicy?: SandboxNetworkPolicy;
25
+ placeholders?: Record<string, string>;
26
+ }): Promise<BundledWorkflow>;
@@ -0,0 +1,2 @@
1
+ /** Find the runtime name referenced via runtime: "name" in workflow source. */
2
+ export declare function discoverRuntimeName(source: string): string | null;
@@ -0,0 +1,2 @@
1
+ /** Convert any thrown value to a string message. */
2
+ export declare function formatError(err: unknown): string;
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ /** Zod schema for the AgentStatus block agents emit to signal iteration completion. */
3
+ export declare const AgentStatusSchema: z.ZodObject<{
4
+ summary: z.ZodString;
5
+ completed: z.ZodArray<z.ZodString>;
6
+ blockers: z.ZodArray<z.ZodString>;
7
+ exit_signal: z.ZodBoolean;
8
+ }, z.core.$strip>;
@@ -0,0 +1,6 @@
1
+ export declare const TMP_DIR: string;
2
+ export declare const LATEST_VERSION = "$LATEST";
3
+ export declare function importSourceModule<T>(source: string, tmpPath: string): Promise<{
4
+ mod: T;
5
+ cleanup: () => Promise<void>;
6
+ }>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Workflow engine — runs a workflow function with a minimal ctx.
3
+ *
4
+ * Post de-broker there is no agent-spawning primitive here. Workflows that
5
+ * want to embed an LLM agent call `runAgent(opts)` directly from
6
+ * `@agent-compose/sdk`. Workflows that want to invoke OTHER workflows use
7
+ * `AgentComposeClient.invoke[AndWait](...)`. The engine's only job now is:
8
+ *
9
+ * - build the `ctx` the workflow function receives
10
+ * - funnel `onStepStart / onStepComplete / onStepFail` hooks
11
+ * - classify errors into `WorkflowError` vs `EngineError` for the runner
12
+ * harness to emit on /fail
13
+ */
14
+ import type { WorkflowHooks, WorkflowCtx, WorkflowFn } from "../types/workflow.js";
15
+ /**
16
+ * Thrown from `runWorkflow` when the authored workflow threw.
17
+ * User-level; not a bug in the platform.
18
+ */
19
+ export declare class WorkflowError extends Error {
20
+ readonly kind: "workflow";
21
+ constructor(message: string, options?: ErrorOptions);
22
+ }
23
+ /**
24
+ * Thrown when the runner harness itself cannot run (or finish) a workflow —
25
+ * bundle missing, max-runtime exceeded, sandbox provider died, secret
26
+ * resolution broken. Platform-level; investigate us, not the user's code.
27
+ *
28
+ * `subsystem` narrows where the failure originated so monitors + dashboards
29
+ * can break down alerts without string-matching on messages.
30
+ */
31
+ export type EngineSubsystem = "bundle" | "timeout" | "sandbox" | "dispatch" | "unknown";
32
+ export declare class EngineError extends Error {
33
+ readonly kind: "engine";
34
+ readonly subsystem: EngineSubsystem;
35
+ constructor(message: string, subsystem?: EngineSubsystem, options?: ErrorOptions);
36
+ }
37
+ /** Classify any thrown value into the wire-level `kind` expected by `/fail`. */
38
+ export declare function classifyError(err: unknown): "workflow" | "engine";
39
+ export declare function parseNameVersion(ref: string): {
40
+ name: string;
41
+ version: string | undefined;
42
+ };
43
+ export interface WorkflowResult<T = unknown> {
44
+ /** The value returned by the workflow function. `null` for void workflows. */
45
+ response: T | null;
46
+ }
47
+ export declare function runWorkflow<T = unknown>(wf: WorkflowFn<T>, ctx: Pick<WorkflowCtx, "run" | "input">, opts?: {
48
+ hooks?: WorkflowHooks;
49
+ setMetadata?: (data: Record<string, unknown>) => Promise<void>;
50
+ }): Promise<WorkflowResult<T>>;