@agent-compose/sdk 0.2.5 → 0.3.1

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.
package/README.md CHANGED
@@ -64,10 +64,10 @@ export default defineWorkflow({
64
64
  ```
65
65
 
66
66
  `defineWorkflow` is a thin sugar — it returns the bare `run` function with
67
- `networkPolicy` / `placeholders` / `snapshot` / `saveSnapshot` attached as
68
- metadata that the bundler picks up at registration time. A plain
69
- `export default async (ctx, sandbox) => {...}` is also valid; you just lose
70
- the metadata channel.
67
+ `networkPolicy` / `placeholders` / `snapshots` / `memory` / `postRunHooks`
68
+ attached as metadata that the bundler picks up at registration time. A
69
+ plain `export default async (ctx, sandbox) => {...}` is also valid; you
70
+ just lose the metadata channel.
71
71
 
72
72
  ### What the workflow can do with `ctx`
73
73
 
@@ -183,7 +183,7 @@ await client.register({
183
183
  runtimes: bundled.runtimes, // [{ name, source }] — embedded so the runner has them locally
184
184
  schedule: "*/30 * * * *", // optional cron
185
185
  factorySlug: "default", // optional — defaults to "default"
186
- // snapshot, saveSnapshot, networkPolicy, placeholders — all optional
186
+ // snapshots, memory, postRunHooks, networkPolicy, placeholders — all optional
187
187
  });
188
188
  ```
189
189
 
@@ -216,9 +216,10 @@ async run() { return … } })` resolves to). `setMetadata()` writes to a
216
216
  separate `metadata` field — useful for "side-channel" facts (PR url, plan
217
217
  url) without polluting the structured return.
218
218
 
219
- `invoke` and `invokeAndWait` both accept `{ factorySlug, snapshot,
220
- saveSnapshot, parentRunId }` as the third argument. `factorySlug` defaults
221
- to `"default"`.
219
+ `invoke` and `invokeAndWait` both accept `{ factorySlug, snapshots,
220
+ memory, postRunHooks, networkPolicy, placeholders, parentRunId }` as the
221
+ third argument. Per-invocation `snapshots` merges field-by-field with
222
+ the registered default. `factorySlug` defaults to `"default"`.
222
223
 
223
224
  ### Auto parent/child tracing
224
225
 
@@ -348,26 +349,37 @@ CLI equivalent: `agentc usage`.
348
349
  ## Snapshots (replay-friendly sandboxes)
349
350
 
350
351
  Long-running workflows can capture the runner sandbox as a Vercel snapshot
351
- on success (`saveSnapshot: true`). Other workflows reference that snapshot
352
- via the `snapshot` field to boot into the same prepared VM (deps installed,
353
- repo cloned, etc.) instead of repeating setup.
352
+ on success (`snapshots: { saveLatest: true }`). Other workflows reference
353
+ that snapshot via `snapshots.bootFrom` to boot into the same prepared VM
354
+ (deps installed, repo cloned, etc.) instead of repeating setup.
354
355
 
355
356
  ```ts
356
357
  // Capture per-invocation:
357
- await client.invoke("my-workflow", input, { saveSnapshot: true });
358
+ await client.invoke("my-workflow", input, { snapshots: { saveLatest: true } });
358
359
 
359
- // Boot from a different snapshot per invocation (per-invocation override):
360
- await client.invoke("my-workflow", input, { snapshot: "<run-id-or-name>" });
360
+ // Boot from a captured snapshot — pick the id from `agentc snapshot
361
+ // list` or the dashboard snapshots page:
362
+ await client.invoke("my-workflow", input, {
363
+ snapshots: { bootFrom: { snapshotId: "snap_…" } },
364
+ });
365
+
366
+ // Set a default at registration time:
367
+ defineWorkflow({ run, snapshots: { saveLatest: true } });
361
368
 
362
- // Or set a default at registration time:
363
- defineWorkflow({ run, saveSnapshot: true });
369
+ // Retain every step's snapshot (not just the latest):
370
+ defineWorkflow({ run, snapshots: { saveLatest: true, retainSteps: true } });
364
371
 
365
372
  // Browse / clean up:
366
- const snaps = await client.listSnapshots({ workflow: "my-workflow", limit: 50 });
367
- await client.deleteSnapshot(snaps[0].runId);
373
+ const page = await client.listSnapshotsPage({ workflow: "my-workflow", limit: 50 });
374
+ const snaps = page.data;
375
+ await client.deleteRunSnapshot(snaps[0].runId, snaps[0].snapshotId);
368
376
  ```
369
377
 
370
- CLI equivalents: `agentc snapshot list` / `agentc snapshot delete <run-id>`.
378
+ CLI equivalents: `agentc snapshot list` / `agentc snapshot delete <run-id> <snapshot-id>`.
379
+
380
+ ### Per-invocation overrides merge field-by-field
381
+
382
+ The `snapshots` object on `invoke()` is **merged** with the registered template's `snapshots` config — you can override `bootFrom` alone without losing `saveLatest`, or vice versa. Same for `memory` (boolean) and `postRunHooks` (string[]).
371
383
 
372
384
  ---
373
385
 
package/dist/client.d.ts CHANGED
@@ -13,12 +13,20 @@
13
13
  import type { SandboxNetworkPolicy } from "./sandbox.js";
14
14
  import type { RunEvent } from "./types/events.js";
15
15
  import type { WorkflowPlan } from "./types/workflow-plan.js";
16
+ import type { SnapshotConfig, IOSchema } from "./types/workflow-metadata.js";
16
17
  import type { WorkflowManifest } from "./utils/bundler.js";
17
18
  export interface RegisterResult {
18
19
  id: string;
19
20
  name: string;
20
21
  version: string;
21
22
  runtimes?: RegisteredRuntime[];
23
+ /** Non-fatal advisories from the server. Surfaced at register time so the
24
+ * operator sees them while still in front of the terminal — currently
25
+ * covers "memory extraction is configured but its workflow is not
26
+ * registered in this factory". Empty/undefined when registration was
27
+ * cleanly resolved against everything the workflow declares it
28
+ * depends on. */
29
+ warnings?: string[];
22
30
  }
23
31
  export interface RegisteredRuntime {
24
32
  id: string;
@@ -44,25 +52,32 @@ export interface RegisterWorkflowInput {
44
52
  runtimes?: RuntimeSourceInput[];
45
53
  networkPolicy?: unknown;
46
54
  placeholders?: Record<string, string>;
47
- /** Reference to a snapshot the runner should boot from at run start. */
48
- snapshot?: string;
49
- /** If true, runs default to capturing a long-lived sandbox snapshot on success. */
50
- saveSnapshot?: boolean;
55
+ /** All snapshot config — `bootFrom` (where to restore at run start),
56
+ * `save`, `retain`. See `WorkflowMetadata.snapshots`. */
57
+ snapshots?: SnapshotConfig;
51
58
  /** Provider-neutral execution plan detected by the CLI bundler. */
52
59
  workflowPlan?: WorkflowPlan;
53
- /** Workflow Memory extraction config. Defaults to "default" when omitted. */
54
- memory?: "default" | false | {
55
- workflow: string;
56
- };
60
+ /** Run the built-in memory extractor after this workflow completes.
61
+ * Opt-in; defaults to false when omitted. */
62
+ memory?: boolean;
63
+ /** Ordered list of workflow names that run as post-hooks after this
64
+ * workflow completes. The memory extractor (when `memory: true`)
65
+ * runs as an additional hook alongside these. */
66
+ postRunHooks?: readonly string[];
67
+ /** Input schema extracted from the workflow's `input` zod schema. */
68
+ inputSchema?: IOSchema;
69
+ /** Output schema extracted from the workflow's `output` zod schema. */
70
+ outputSchema?: IOSchema;
57
71
  /** Factory slug. Defaults to `"default"`. */
58
72
  factorySlug?: string;
59
73
  }
60
74
  export type RunState = "running" | "success" | "failed" | "abandoned" | "canceled";
61
75
  export interface InvokeWorkflowOptions {
62
- /** Per-invocation snapshot override: run UUID, workflow name, or `name@version`. */
63
- snapshot?: string;
64
- /** Per-invocation snapshot capture override. */
65
- saveSnapshot?: boolean;
76
+ /** Per-invocation snapshot config override. `snapshots.bootFrom`
77
+ * replaces the template's boot source; `snapshots.saveLatest` and
78
+ * `snapshots.retainSteps` override capture mode. Anything omitted
79
+ * falls back to the template's registered default. */
80
+ snapshots?: SnapshotConfig;
66
81
  /** Per-invocation network policy override. Replaces the template-level
67
82
  * policy for this run only — registered metadata is not mutated. */
68
83
  networkPolicy?: SandboxNetworkPolicy;
@@ -71,6 +86,13 @@ export interface InvokeWorkflowOptions {
71
86
  * vars after brokering. Replaces the template-level placeholders for
72
87
  * this run only — registered metadata is not mutated. */
73
88
  placeholders?: Record<string, string>;
89
+ /** Per-invocation memory-extractor override — `false` skips the
90
+ * built-in memory hook for this run; omitting leaves the registered
91
+ * default in place. */
92
+ memory?: boolean;
93
+ /** Per-invocation post-hook override — replaces the registered
94
+ * `postRunHooks` array for this run only. */
95
+ postRunHooks?: readonly string[];
74
96
  /** Explicit parent run id. Pass `null` to suppress ambient RUN_ID auto-detection. */
75
97
  parentRunId?: string | null;
76
98
  /** Agent loop inside the parent run that caused this invoke, when applicable. */
@@ -86,8 +108,12 @@ export interface InvokeResult {
86
108
  id: string;
87
109
  }
88
110
  export interface ListSnapshotsOptions {
111
+ /** Factory slug. Defaults to `"default"`. */
112
+ factorySlug?: string;
89
113
  workflow?: string;
90
114
  limit?: number;
115
+ /** Cursor returned as `next_cursor` from `listSnapshotsPage`. */
116
+ before?: string;
91
117
  }
92
118
  export interface TemplateRow {
93
119
  name: string;
@@ -275,32 +301,55 @@ export interface CancelRunResponse {
275
301
  canceledAt: string;
276
302
  }
277
303
  export interface SnapshotListEntry {
304
+ snapshotId: string;
305
+ kind: "latest" | "step";
306
+ stepIndex: number | null;
278
307
  runId: string;
279
308
  workflow: string | null;
280
309
  version: string | null;
281
- vercelSnapshotId: string;
282
- endedAt: string | null;
310
+ createdAt: string | null;
311
+ /** Provider-reported on-disk size, or null when unavailable. */
312
+ sizeBytes: number | null;
313
+ }
314
+ export interface SnapshotListResponse {
315
+ object: "list";
316
+ data: SnapshotListEntry[];
317
+ has_more: boolean;
318
+ next_cursor: string | null;
319
+ }
320
+ export interface RunSnapshotEntry {
321
+ snapshotId: string;
322
+ /** `"latest"` = current/last pointer on the run.
323
+ * `"step"` = retained per-step snapshot. */
324
+ kind: "latest" | "step";
325
+ stepIndex: number | null;
326
+ createdAt: string | null;
327
+ /** Provider-reported on-disk size, or null when unavailable. */
328
+ sizeBytes: number | null;
329
+ }
330
+ export interface AgentComposeClientOptions {
331
+ /** Your team's API key — minted from the dashboard or `agentc keys create`.
332
+ * Required. Resolved from `process.env.AGENT_COMPOSE_API_KEY` when omitted. */
333
+ apiKey?: string;
334
+ /** Override the API host. Defaults to `process.env.AGENT_COMPOSE_URL` if
335
+ * set, otherwise the public host (`https://api.agentcompose.ai`). Most
336
+ * callers should leave this unset — the only consumers that need it are
337
+ * the CLI's local-dev path and tests that point at a fake server. */
338
+ baseUrl?: string;
283
339
  }
284
340
  export declare class AgentComposeClient {
285
341
  private readonly fetch;
286
342
  private readonly baseUrl;
287
343
  private readonly apiKey;
288
- constructor(baseUrl: string, apiKey: string);
344
+ constructor(options?: AgentComposeClientOptions);
289
345
  /** Register (or update) a workflow template inside a factory. Defaults to
290
346
  * the team's `default` factory when `factorySlug` is omitted. */
291
347
  register(payload: RegisterWorkflowInput): Promise<RegisterResult>;
292
348
  /** Invoke a workflow. Returns run ID immediately — workflow runs asynchronously.
293
349
  *
294
- * `snapshot`: per-invocation override of the template-level `snapshot`
295
- * field. Same forms — a run UUID, a workflow name, or `name@version`.
296
- * Use this when one template needs to boot from many different
297
- * snapshots (e.g. a benchmark workflow running against a different
298
- * starting state per invocation). Does not change the template's
299
- * registered default; only affects this run.
300
- *
301
- * `saveSnapshot`: `true` overrides the workflow default; `false` opts
302
- * out. When the run captures a snapshot, its id is stamped on the row
303
- * and can be referenced as the `snapshot` field on other workflows.
350
+ * `snapshots`: per-invocation snapshot config override. `bootFrom`
351
+ * accepts `{ snapshotId }`; `saveLatest` / `retainSteps` control
352
+ * capture. Merged field-by-field with the registered default.
304
353
  *
305
354
  * `parentRunId`: links the new run to another of the same account's
306
355
  * currently-running runs. When omitted, the client auto-detects from
@@ -320,10 +369,18 @@ export declare class AgentComposeClient {
320
369
  * tests, tune up for long-running workflows. The parent-child auto-
321
370
  * detection from `invoke()` applies here too. */
322
371
  invokeAndWait<TOutput = unknown>(name: string, input?: Record<string, unknown>, opts?: InvokeAndWaitOptions): Promise<RunStatus<TOutput>>;
323
- /** List runs this account has captured snapshots for. */
372
+ /** List captured snapshots in a factory. */
324
373
  listSnapshots(opts?: ListSnapshotsOptions): Promise<SnapshotListEntry[]>;
374
+ /** List one page of captured snapshots in a factory. */
375
+ listSnapshotsPage(opts?: ListSnapshotsOptions): Promise<SnapshotListResponse>;
325
376
  /** Delete the snapshot captured by a specific run. Frees Vercel storage. */
326
377
  deleteSnapshot(runId: string): Promise<void>;
378
+ /** List all snapshots captured for a single run — the latest pointer
379
+ * plus any retained per-step rows (`snapshots: { retainSteps: true }`). */
380
+ listRunSnapshots(runId: string): Promise<RunSnapshotEntry[]>;
381
+ /** Delete one snapshot from a run by id. Walks both the latest pointer
382
+ * and the retention rows; provider-side delete is best-effort. */
383
+ deleteRunSnapshot(runId: string, snapshotId: string): Promise<void>;
327
384
  /** Poll run status. */
328
385
  getStatus<TOutput = unknown>(runId: string): Promise<RunStatus<TOutput>>;
329
386
  /** Full run detail, including input/output and lifecycle events. */
package/dist/index.d.ts CHANGED
@@ -16,7 +16,8 @@ export type { WorkflowDefinition } from "./types/workflow.js";
16
16
  export { defineSandboxEnvironment } from "./types/sandbox-environment.js";
17
17
  export type { SandboxEnvironmentDefinition } from "./types/sandbox-environment.js";
18
18
  export type { AgentRuntime, McpServerConfig, ModelExecutionContract, ToolCallGateResult, RuntimeOptions, } from "./types/runtime.js";
19
- export type { WorkflowFn, WorkflowCtx, WorkflowRun, AgentBudget, WorkflowHooks, } from "./types/workflow.js";
19
+ export type { WorkflowFn, WorkflowCtx, WorkflowRun, AgentBudget, WorkflowHooks, SnapshotConfig, BootSnapshot, IOSchema, OutputSchema, WorkflowMemoryConfig, } from "./types/workflow.js";
20
+ export type { RunSnapshotEntry } from "./client.js";
20
21
  export type { WorkflowPlan, WorkflowStepPlan } from "./types/workflow-plan.js";
21
22
  export type { BaseExecutionContext, InvokeChild } from "./types/execution-context.js";
22
23
  export { RequestContext, ReservedKeyError, NonSerialisableValueError, AC_RESERVED_PREFIX, AC_TEAM_ID, AC_RUN_ID, AC_WORKFLOW_ID, AC_FACTORY_ID, AC_API_KEY_SCOPES, AC_PARENT_RUN_ID, AC_ABORT_SIGNAL, } from "./request-context/index.js";
@@ -26,7 +27,7 @@ export type { Processor, ProcessorContext, ProcessorVerdict, ToolCall, } from ".
26
27
  export type { AgentMessage, AgentMessageInit, AgentMessageText, AgentMessageThinking, AgentMessageToolUse, AgentMessageToolResult, AgentMessageDone, AgentMessageError, AgentMessageUsage, AgentStatus, } from "./types/protocol.js";
27
28
  export type { SandboxProvider, DesktopSandboxProvider, } from "./types/sandbox.js";
28
29
  export { AgentComposeClient } from "./client.js";
29
- export type { RegisterResult, RegisterWorkflowInput, RuntimeSourceInput, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, ListSnapshotsOptions, TemplateRow, ListTemplatesOptions, CreateFactoryInput, UpdateFactoryInput, SecretOptions, SetSecretResult, SecretListEntry, CreateApiKeyInput, StreamRunLogsOptions, EventSubjectType, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, RegisteredRuntime, RunState, RunStatus, FactoryRow, SnapshotListEntry, ApiKey, ApiKeyCreated, UsageRollupRow, UsageResponse, CancelRunResponse, } from "./client.js";
30
+ export type { RegisterResult, RegisterWorkflowInput, RuntimeSourceInput, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, ListSnapshotsOptions, TemplateRow, ListTemplatesOptions, CreateFactoryInput, UpdateFactoryInput, SecretOptions, SetSecretResult, SecretListEntry, CreateApiKeyInput, StreamRunLogsOptions, EventSubjectType, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, RegisteredRuntime, RunState, RunStatus, FactoryRow, SnapshotListEntry, SnapshotListResponse, ApiKey, ApiKeyCreated, UsageRollupRow, UsageResponse, CancelRunResponse, } from "./client.js";
30
31
  export { parseSseStream } from "./sse.js";
31
32
  export { AgentComposeError } from "./errors.js";
32
33
  export { formatError } from "./utils/errors.js";
package/dist/index.js CHANGED
@@ -477,18 +477,24 @@ var WORKFLOW_BRAND = Symbol.for("@agent-compose/sdk.Workflow");
477
477
  // src/types/workflow-metadata.ts
478
478
  function extractMetadata(source) {
479
479
  const out = {};
480
+ if (source.description !== undefined)
481
+ out.description = source.description;
480
482
  if (source.networkPolicy !== undefined)
481
483
  out.networkPolicy = freezeMetadataValue(source.networkPolicy);
482
484
  if (source.placeholders !== undefined)
483
485
  out.placeholders = Object.freeze({ ...source.placeholders });
484
- if (source.snapshot !== undefined)
485
- out.snapshot = source.snapshot;
486
- if (source.saveSnapshot !== undefined)
487
- out.saveSnapshot = source.saveSnapshot;
486
+ if (source.inputSchema !== undefined)
487
+ out.inputSchema = freezeMetadataValue(source.inputSchema);
488
+ if (source.outputSchema !== undefined)
489
+ out.outputSchema = freezeMetadataValue(source.outputSchema);
490
+ if (source.snapshots !== undefined)
491
+ out.snapshots = Object.freeze({ ...source.snapshots });
488
492
  if (source.processors !== undefined)
489
493
  out.processors = Object.freeze([...source.processors]);
490
494
  if (source.memory !== undefined)
491
- out.memory = typeof source.memory === "object" && source.memory !== null ? Object.freeze({ ...source.memory }) : source.memory;
495
+ out.memory = source.memory;
496
+ if (source.postRunHooks !== undefined)
497
+ out.postRunHooks = Object.freeze([...source.postRunHooks]);
492
498
  return Object.freeze(out);
493
499
  }
494
500
  function freezeMetadataValue(value) {
@@ -583,7 +589,9 @@ function defineSandboxEnvironment(env) {
583
589
  throw new Error(`defineSandboxEnvironment(${env.name}): 'setup' must be a function`);
584
590
  }
585
591
  return defineWorkflow({
586
- saveSnapshot: env.saveSnapshot ?? true,
592
+ ...env.description !== undefined ? { description: env.description } : {},
593
+ snapshots: env.snapshots ?? { saveLatest: true },
594
+ memory: env.memory ?? false,
587
595
  run: async (_ctx, sandbox) => env.setup(sandbox)
588
596
  });
589
597
  }
@@ -695,12 +703,18 @@ function templatePath(factorySlug, ...rest) {
695
703
  const tail = rest.length > 0 ? "/" + rest.map(encodeURIComponent).join("/") : "";
696
704
  return `/api/v1/factories/${encodeURIComponent(factorySlug)}/templates${tail}`;
697
705
  }
706
+ var PUBLIC_API_HOST = "https://api.agentcompose.ai";
698
707
 
699
708
  class AgentComposeClient {
700
709
  fetch;
701
710
  baseUrl;
702
711
  apiKey;
703
- constructor(baseUrl, apiKey) {
712
+ constructor(options = {}) {
713
+ const apiKey = options.apiKey ?? (typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_API_KEY : undefined) ?? "";
714
+ if (!apiKey) {
715
+ throw new Error("AgentComposeClient: `apiKey` is required. Pass it as `{ apiKey }` " + "or set the AGENT_COMPOSE_API_KEY env var.");
716
+ }
717
+ const baseUrl = options.baseUrl ?? (typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_URL : undefined) ?? PUBLIC_API_HOST;
704
718
  this.baseUrl = baseUrl.replace(/\/$/, "");
705
719
  this.apiKey = apiKey;
706
720
  this.fetch = ofetch.create({
@@ -723,10 +737,11 @@ class AgentComposeClient {
723
737
  method: "POST",
724
738
  body: {
725
739
  input,
726
- ...opts?.snapshot !== undefined ? { snapshot: opts.snapshot } : {},
727
- ...opts?.saveSnapshot !== undefined ? { saveSnapshot: opts.saveSnapshot } : {},
740
+ ...opts?.snapshots !== undefined ? { snapshots: opts.snapshots } : {},
728
741
  ...opts?.networkPolicy !== undefined ? { networkPolicy: opts.networkPolicy } : {},
729
742
  ...opts?.placeholders !== undefined ? { placeholders: opts.placeholders } : {},
743
+ ...opts?.memory !== undefined ? { memory: opts.memory } : {},
744
+ ...opts?.postRunHooks !== undefined ? { postRunHooks: opts.postRunHooks } : {},
730
745
  ...parentRunId ? { parentRunId } : {},
731
746
  ...opts?.agentId ? { agentId: opts.agentId } : {}
732
747
  }
@@ -747,16 +762,29 @@ class AgentComposeClient {
747
762
  throw new AgentComposeError(504, `invokeAndWait: run ${runId} did not settle within ${timeoutMs}ms`);
748
763
  }
749
764
  async listSnapshots(opts) {
765
+ const body = await this.listSnapshotsPage(opts);
766
+ return body.data;
767
+ }
768
+ async listSnapshotsPage(opts) {
769
+ const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
750
770
  const q2 = new URLSearchParams;
751
771
  if (opts?.workflow)
752
772
  q2.set("workflow", opts.workflow);
753
773
  if (opts?.limit != null)
754
774
  q2.set("limit", String(opts.limit));
755
- const body = await this.fetch(`/api/v1/snapshots${q2.toString() ? `?${q2}` : ""}`);
756
- return body.data;
775
+ if (opts?.before)
776
+ q2.set("before", opts.before);
777
+ return this.fetch(`/api/v1/factories/${encodeURIComponent(factorySlug)}/snapshots${q2.toString() ? `?${q2}` : ""}`);
757
778
  }
758
779
  deleteSnapshot(runId) {
759
- return this.fetch(`/api/v1/workflows/${runId}/snapshot`, { method: "DELETE" });
780
+ return this.fetch(`/api/v1/workflows/${encodeURIComponent(runId)}/snapshot`, { method: "DELETE" });
781
+ }
782
+ async listRunSnapshots(runId) {
783
+ const body = await this.fetch(`/api/v1/workflows/${encodeURIComponent(runId)}/snapshots`);
784
+ return body.data;
785
+ }
786
+ deleteRunSnapshot(runId, snapshotId) {
787
+ return this.fetch(`/api/v1/workflows/${encodeURIComponent(runId)}/snapshots/${encodeURIComponent(snapshotId)}`, { method: "DELETE" });
760
788
  }
761
789
  getStatus(runId) {
762
790
  return this.fetch(`/api/v1/workflows/${runId}/status`);
@@ -1017,17 +1045,59 @@ async function bundleWorkflow(workflowPath, overrides) {
1017
1045
  sourceHash: sha256(source),
1018
1046
  bundlerVersion: BUNDLER_VERSION
1019
1047
  };
1048
+ const inputSchema = extractIOSchema(workflow.input);
1049
+ const outputSchema = extractIOSchema(workflow.output);
1020
1050
  return {
1021
1051
  source,
1022
1052
  manifest,
1023
1053
  workflowPlan: plan,
1024
1054
  networkPolicy: overrides?.networkPolicy ?? metadata.networkPolicy,
1025
1055
  placeholders: overrides?.placeholders ?? metadata.placeholders,
1026
- ...metadata.snapshot !== undefined ? { snapshot: metadata.snapshot } : {},
1027
- ...metadata.saveSnapshot !== undefined ? { saveSnapshot: metadata.saveSnapshot } : {},
1028
- ...metadata.memory !== undefined ? { memory: metadata.memory } : {}
1056
+ ...inputSchema !== undefined ? { inputSchema } : {},
1057
+ ...outputSchema !== undefined ? { outputSchema } : {},
1058
+ ...metadata.snapshots !== undefined ? { snapshots: metadata.snapshots } : {},
1059
+ ...metadata.memory !== undefined ? { memory: metadata.memory } : {},
1060
+ ...metadata.postRunHooks !== undefined ? { postRunHooks: metadata.postRunHooks } : {}
1029
1061
  };
1030
1062
  }
1063
+ function extractIOSchema(zodSchema) {
1064
+ let json;
1065
+ try {
1066
+ const z3 = __require("zod");
1067
+ if (!z3.toJSONSchema)
1068
+ return;
1069
+ json = z3.toJSONSchema(zodSchema);
1070
+ } catch {
1071
+ return;
1072
+ }
1073
+ if (!json || typeof json !== "object")
1074
+ return;
1075
+ if (Object.keys(json).filter((k) => k !== "$schema").length === 0)
1076
+ return;
1077
+ const out = {};
1078
+ if (json.type !== undefined)
1079
+ out.type = json.type;
1080
+ if (json.description !== undefined)
1081
+ out.description = String(json.description);
1082
+ if (json.properties && typeof json.properties === "object") {
1083
+ const props = {};
1084
+ for (const [key, raw] of Object.entries(json.properties)) {
1085
+ if (raw && typeof raw === "object") {
1086
+ const r = raw;
1087
+ props[key] = {};
1088
+ if (r.type !== undefined)
1089
+ props[key].type = r.type;
1090
+ if (r.description !== undefined)
1091
+ props[key].description = String(r.description);
1092
+ }
1093
+ }
1094
+ if (Object.keys(props).length > 0)
1095
+ out.properties = props;
1096
+ }
1097
+ if (Array.isArray(json.required))
1098
+ out.required = json.required.map(String);
1099
+ return out;
1100
+ }
1031
1101
  // src/utils/schemas.ts
1032
1102
  import { z as z3 } from "zod";
1033
1103
  var AgentStatusSchema = z3.object({
@@ -1544,7 +1614,11 @@ function makeVercelSandboxProvider(sb, globalEnvs) {
1544
1614
  },
1545
1615
  async snapshot() {
1546
1616
  const res = await sb.snapshot({ expiration: 0 });
1547
- return { snapshotId: res.snapshotId };
1617
+ const sizeBytes = typeof res.sizeBytes === "number" ? res.sizeBytes : undefined;
1618
+ return {
1619
+ snapshotId: res.snapshotId,
1620
+ ...sizeBytes !== undefined ? { sizeBytes } : {}
1621
+ };
1548
1622
  }
1549
1623
  };
1550
1624
  }
@@ -2049,7 +2123,7 @@ function buildInvokeChild(runId, opts = {}) {
2049
2123
  if (!baseUrl || !apiKey) {
2050
2124
  throw new Error("ctx.invokeChild requires AGENT_COMPOSE_URL and AGENT_COMPOSE_API_KEY");
2051
2125
  }
2052
- childClient = new AgentComposeClient(baseUrl, apiKey);
2126
+ childClient = new AgentComposeClient({ apiKey, baseUrl });
2053
2127
  return childClient;
2054
2128
  };
2055
2129
  return (name, input, childOpts) => getChildClient().invokeAndWait(name, input, {