@agent-compose/sdk 0.1.0 → 0.2.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.
package/dist/client.d.ts CHANGED
@@ -1,9 +1,16 @@
1
1
  /**
2
2
  * AgentComposeClient — HTTP client for the agent-compose server API.
3
3
  *
4
- * register() accepts pre-built sources — use the CLI (agent-compose register)
5
- * or build sources yourself and pass them directly.
4
+ * Templates always live inside a factory (project). Methods that touch a
5
+ * specific template (`register`, `invoke`, `setSecret`, `listSecrets`,
6
+ * `deleteSecret`) take an optional `factorySlug`; when omitted, they target
7
+ * the team's auto-created `default` factory. There is no second URL space
8
+ * for "templates without a factory" — every workflow belongs to exactly one.
9
+ *
10
+ * `register()` accepts pre-built sources — use the CLI (`agent-compose
11
+ * register`) or build sources yourself and pass them directly.
6
12
  */
13
+ import type { RunEvent } from "./types/events.js";
7
14
  export interface RegisterResult {
8
15
  id: string;
9
16
  name: string;
@@ -16,9 +23,54 @@ export interface RegisterResult {
16
23
  }
17
24
  export interface RunStatus {
18
25
  id: string;
19
- status: "running" | "success" | "failed" | "abandoned";
26
+ status: "running" | "success" | "failed" | "abandoned" | "canceled";
20
27
  output?: Record<string, unknown>;
21
28
  }
29
+ /** Row shape returned by `GET /api-keys`. */
30
+ export interface ApiKey {
31
+ object: "api_key";
32
+ id: string;
33
+ name: string | null;
34
+ last4: string | null;
35
+ scopes: string[];
36
+ teamId: string;
37
+ createdByUserId: string | null;
38
+ /** Non-null when the key is restricted to a single factory. */
39
+ factoryId: string | null;
40
+ createdAt: string;
41
+ expiresAt: string | null;
42
+ lastUsedAt: string | null;
43
+ revokedAt: string | null;
44
+ }
45
+ /** Response from `POST /api-keys`. The `key` field is the plaintext token —
46
+ * shown once at creation, never retrievable again. */
47
+ export interface ApiKeyCreated extends ApiKey {
48
+ key: string;
49
+ }
50
+ /** Single rollup row from `GET /api/v1/usage`. */
51
+ export interface UsageRollupRow {
52
+ eventType: string;
53
+ unit: string;
54
+ total: number;
55
+ tags: Record<string, unknown>;
56
+ }
57
+ /** Response from `GET /api/v1/usage`. */
58
+ export interface UsageResponse {
59
+ object: "list";
60
+ data: UsageRollupRow[];
61
+ has_more: boolean;
62
+ from: string | null;
63
+ to: string | null;
64
+ }
65
+ /** Response from `POST /api/v1/workflows/:id/cancel`. The endpoint is
66
+ * idempotent: cancelling a run that's already terminal returns its current
67
+ * outcome verbatim (rather than throwing or pretending it just canceled),
68
+ * so `status` widens to every terminal value the server might surface. */
69
+ export interface CancelRunResponse {
70
+ runId: string;
71
+ status: "canceled" | "success" | "failed" | "abandoned";
72
+ canceledAt: string;
73
+ }
22
74
  export interface SnapshotListEntry {
23
75
  runId: string;
24
76
  workflow: string | null;
@@ -28,8 +80,11 @@ export interface SnapshotListEntry {
28
80
  }
29
81
  export declare class AgentComposeClient {
30
82
  private readonly fetch;
83
+ private readonly baseUrl;
84
+ private readonly apiKey;
31
85
  constructor(baseUrl: string, apiKey: string);
32
- /** Register a workflow with pre-built sources. */
86
+ /** Register (or update) a workflow template inside a factory. Defaults to
87
+ * the team's `default` factory when `factorySlug` is omitted. */
33
88
  register(payload: {
34
89
  name: string;
35
90
  source: string;
@@ -41,19 +96,31 @@ export declare class AgentComposeClient {
41
96
  }>;
42
97
  networkPolicy?: unknown;
43
98
  placeholders?: Record<string, string>;
44
- /** Name (or `name@version`) of another workflow whose snapshot this
45
- * workflow's runner boots from. Must reference a workflow previously
46
- * registered with `--build`. */
47
- sandboxEnvironment?: string;
99
+ /** Reference to a snapshot the runner should boot from at run start.
100
+ * A run UUID, workflow name, or `name@version`. The referenced
101
+ * workflow must have been registered with `--build` (or any prior
102
+ * successful run with `saveSnapshot: true`). Per-invocation
103
+ * `invoke({ snapshot })` overrides this default. */
104
+ snapshot?: string;
48
105
  /** If true, runs default to capturing a long-lived sandbox snapshot on
49
- * success. Individual invocations can override via `invoke(..., { snapshot })`. */
50
- snapshot?: boolean;
106
+ * success. Individual invocations can override via
107
+ * `invoke(..., { saveSnapshot })`. */
108
+ saveSnapshot?: boolean;
109
+ /** Factory slug. Defaults to `"default"`. */
110
+ factorySlug?: string;
51
111
  }): Promise<RegisterResult>;
52
112
  /** Invoke a workflow. Returns run ID immediately — workflow runs asynchronously.
53
113
  *
54
- * `snapshot`: `true` overrides the workflow default; `false` opts out. When
55
- * the run captures a snapshot, its id is stamped on the row and can be
56
- * referenced as `sandboxEnvironment` by other workflows.
114
+ * `snapshot`: per-invocation override of the template-level `snapshot`
115
+ * field. Same forms — a run UUID, a workflow name, or `name@version`.
116
+ * Use this when one template needs to boot from many different
117
+ * snapshots (e.g. a benchmark workflow running against a different
118
+ * starting state per invocation). Does not change the template's
119
+ * registered default; only affects this run.
120
+ *
121
+ * `saveSnapshot`: `true` overrides the workflow default; `false` opts
122
+ * out. When the run captures a snapshot, its id is stamped on the row
123
+ * and can be referenced as the `snapshot` field on other workflows.
57
124
  *
58
125
  * `parentRunId`: links the new run to another of the same account's
59
126
  * currently-running runs. When omitted, the client auto-detects from
@@ -61,10 +128,14 @@ export declare class AgentComposeClient {
61
128
  * so workflows invoking other workflows get the parent/child tree for
62
129
  * free. Pass `null` to suppress auto-detection (e.g. invoking a top-level
63
130
  * sibling workflow from inside a runner for a reason unrelated to the
64
- * current run). Explicit non-null wins over auto-detection. */
131
+ * current run). Explicit non-null wins over auto-detection.
132
+ *
133
+ * `factorySlug`: defaults to `"default"`. */
65
134
  invoke(name: string, input?: Record<string, unknown>, opts?: {
66
- snapshot?: boolean;
135
+ snapshot?: string;
136
+ saveSnapshot?: boolean;
67
137
  parentRunId?: string | null;
138
+ factorySlug?: string;
68
139
  }): Promise<{
69
140
  id: string;
70
141
  }>;
@@ -76,8 +147,10 @@ export declare class AgentComposeClient {
76
147
  * tests, tune up for long-running workflows. The parent-child auto-
77
148
  * detection from `invoke()` applies here too. */
78
149
  invokeAndWait(name: string, input?: Record<string, unknown>, opts?: {
79
- snapshot?: boolean;
150
+ snapshot?: string;
151
+ saveSnapshot?: boolean;
80
152
  parentRunId?: string | null;
153
+ factorySlug?: string;
81
154
  timeoutMs?: number;
82
155
  pollIntervalMs?: number;
83
156
  }): Promise<RunStatus>;
@@ -90,21 +163,100 @@ export declare class AgentComposeClient {
90
163
  deleteSnapshot(runId: string): Promise<void>;
91
164
  /** Poll run status. */
92
165
  getStatus(runId: string): Promise<RunStatus>;
93
- /** List registered workflow templates. */
94
- listTemplates(): Promise<Array<{
166
+ /** List registered workflow templates. When `factorySlug` is supplied,
167
+ * scopes to that factory; otherwise returns every template the team can
168
+ * see across every factory in one round trip — each row carries its
169
+ * `factorySlug` so callers can route per-template actions to the right
170
+ * factory. */
171
+ listTemplates(opts?: {
172
+ factorySlug?: string;
173
+ }): Promise<Array<{
95
174
  name: string;
96
175
  version: string;
176
+ factorySlug: string;
97
177
  }>>;
178
+ /** List factories for the caller's team. */
179
+ listFactories(): Promise<FactoryRow[]>;
180
+ /** Create a factory. `slug` must be lowercase kebab-case and unique
181
+ * within the team. */
182
+ createFactory(payload: {
183
+ slug: string;
184
+ name: string;
185
+ description?: string;
186
+ }): Promise<FactoryRow>;
187
+ /** Get a factory by slug. */
188
+ getFactory(slug: string): Promise<FactoryRow>;
189
+ /** Rename or describe a factory. */
190
+ updateFactory(slug: string, updates: {
191
+ name?: string;
192
+ description?: string;
193
+ }): Promise<FactoryRow>;
194
+ /** Delete a factory. Refuses `default` and any factory still
195
+ * containing workflows. */
196
+ deleteFactory(slug: string): Promise<void>;
98
197
  /** Create or update a workflow secret. Value is stored in GCP Secret Manager. */
99
- setSecret(workflowName: string, key: string, value: string): Promise<{
198
+ setSecret(workflowName: string, key: string, value: string, opts?: {
199
+ factorySlug?: string;
200
+ }): Promise<{
100
201
  key: string;
101
202
  }>;
102
203
  /** List secret keys registered for a workflow (metadata only — values are never returned). */
103
- listSecrets(workflowName: string): Promise<Array<{
204
+ listSecrets(workflowName: string, opts?: {
205
+ factorySlug?: string;
206
+ }): Promise<Array<{
104
207
  key: string;
105
208
  createdAt: string;
106
209
  updatedAt: string;
107
210
  }>>;
108
211
  /** Delete a workflow secret. */
109
- deleteSecret(workflowName: string, key: string): Promise<void>;
212
+ deleteSecret(workflowName: string, key: string, opts?: {
213
+ factorySlug?: string;
214
+ }): Promise<void>;
215
+ /** Create a new API key on the caller's team. The plaintext `key` is
216
+ * returned once — it cannot be retrieved later.
217
+ *
218
+ * When `factorySlug` is set, the new key is restricted to that factory.
219
+ * Factory-scoped keys can only mint other keys bound to the same factory. */
220
+ createApiKey(input: {
221
+ name?: string;
222
+ scopes?: string[];
223
+ expiresAt?: string;
224
+ factorySlug?: string;
225
+ }): Promise<ApiKeyCreated>;
226
+ /** List API keys on the caller's team (metadata only — plaintext keys are
227
+ * never returned). */
228
+ listApiKeys(): Promise<ApiKey[]>;
229
+ /** Billable usage rollup for the caller's team over the [from, to) window. */
230
+ getUsage(from: Date, to: Date): Promise<UsageResponse>;
231
+ /** Cancel an in-progress run. Idempotent: cancelling an already-terminal
232
+ * run returns the current state without throwing. The server stamps the
233
+ * run as `canceled` and kills any live sandboxes. */
234
+ cancelRun(runId: string): Promise<CancelRunResponse>;
235
+ /** Stream lifecycle events for a run as an async iterable. Yields parsed
236
+ * `RunEvent` payloads in order; caller breaks on terminal events
237
+ * (`run_complete`, `run_failed`, `run_canceled`).
238
+ *
239
+ * `lastEventId` enables resume — pass the highest `seq` you've already
240
+ * processed to receive only events you missed.
241
+ *
242
+ * `signal` can be used to abort the stream from the caller side.
243
+ *
244
+ * Uses raw `fetch` (not ofetch) because SSE requires access to the
245
+ * response's `ReadableStream`, which ofetch consumes when parsing. Auth
246
+ * + base URL are still sourced from the same constructor inputs, and
247
+ * non-2xx responses throw the same `AgentComposeError`. */
248
+ streamRunLogs(runId: string, opts?: {
249
+ lastEventId?: number;
250
+ signal?: AbortSignal;
251
+ }): AsyncGenerator<RunEvent>;
252
+ }
253
+ /** A factory: a project-level grouping of workflows inside a team. */
254
+ export interface FactoryRow {
255
+ id: string;
256
+ teamId: string;
257
+ slug: string;
258
+ name: string;
259
+ description: string | null;
260
+ createdAt: string;
261
+ updatedAt: string;
110
262
  }
package/dist/index.d.ts CHANGED
@@ -20,7 +20,8 @@ export type { WorkflowFn, WorkflowCtx, WorkflowRun, AgentBudget, WorkflowHooks,
20
20
  export type { AgentMessage, AgentMessageInit, AgentMessageText, AgentMessageThinking, AgentMessageToolUse, AgentMessageToolResult, AgentMessageDone, AgentMessageError, AgentMessageUsage, AgentStatus, } from "./types/protocol.js";
21
21
  export type { SandboxProvider, DesktopSandboxProvider, } from "./types/sandbox.js";
22
22
  export { AgentComposeClient } from "./client.js";
23
- export type { RegisterResult, RunStatus } from "./client.js";
23
+ export type { RegisterResult, RunStatus, FactoryRow, SnapshotListEntry, ApiKey, ApiKeyCreated, UsageRollupRow, UsageResponse, CancelRunResponse, } from "./client.js";
24
+ export { parseSseStream } from "./sse.js";
24
25
  export { AgentComposeError } from "./errors.js";
25
26
  export { formatError } from "./utils/errors.js";
26
27
  export { discoverRuntimeName } from "./utils/discovery.js";
package/dist/index.js CHANGED
@@ -28,8 +28,8 @@ function defineWorkflow(def) {
28
28
  return Object.assign(def.run, {
29
29
  networkPolicy: def.networkPolicy,
30
30
  placeholders: def.placeholders,
31
- sandboxEnvironment: def.sandboxEnvironment,
32
- snapshot: def.snapshot
31
+ snapshot: def.snapshot,
32
+ saveSnapshot: def.saveSnapshot
33
33
  });
34
34
  }
35
35
  // src/sandbox.ts
@@ -350,7 +350,7 @@ function defineSandboxEnvironment(env) {
350
350
  throw new Error(`defineSandboxEnvironment(${env.name}): 'setup' must be a function`);
351
351
  }
352
352
  return defineWorkflow({
353
- snapshot: env.snapshot ?? true,
353
+ saveSnapshot: env.saveSnapshot ?? true,
354
354
  run: () => env.setup(makeLocalSandboxProvider())
355
355
  });
356
356
  }
@@ -367,18 +367,74 @@ class AgentComposeError extends Error {
367
367
  }
368
368
  }
369
369
 
370
+ // src/sse.ts
371
+ async function* parseSseStream(body) {
372
+ const reader = body.getReader();
373
+ const decoder = new TextDecoder;
374
+ let buffer = "";
375
+ let event = "";
376
+ let seq = 0;
377
+ let dataLines = [];
378
+ try {
379
+ while (true) {
380
+ const { done, value } = await reader.read();
381
+ if (done)
382
+ break;
383
+ buffer += decoder.decode(value, { stream: true });
384
+ const lines = buffer.split(`
385
+ `);
386
+ buffer = lines.pop() ?? "";
387
+ for (const line of lines) {
388
+ if (line.startsWith("id:")) {
389
+ seq = Number(line.slice(3).trim());
390
+ continue;
391
+ }
392
+ if (line.startsWith("event:")) {
393
+ event = line.slice(6).trim();
394
+ continue;
395
+ }
396
+ if (line.startsWith("data:")) {
397
+ dataLines.push(line.slice(5).trim());
398
+ continue;
399
+ }
400
+ if (line === "" && dataLines.length > 0) {
401
+ try {
402
+ const data = JSON.parse(dataLines.join(`
403
+ `));
404
+ yield { id: seq, event, data };
405
+ } catch {}
406
+ event = "";
407
+ seq = 0;
408
+ dataLines = [];
409
+ }
410
+ }
411
+ }
412
+ } finally {
413
+ reader.releaseLock();
414
+ }
415
+ }
416
+
370
417
  // src/client.ts
371
418
  var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
419
+ var DEFAULT_FACTORY = "default";
372
420
  function detectAmbientParentRunId() {
373
421
  const envRunId = typeof process !== "undefined" ? process.env?.RUN_ID : undefined;
374
422
  return envRunId && UUID_REGEX.test(envRunId) ? envRunId : null;
375
423
  }
424
+ function templatePath(factorySlug, ...rest) {
425
+ const tail = rest.length > 0 ? "/" + rest.map(encodeURIComponent).join("/") : "";
426
+ return `/api/v1/factories/${encodeURIComponent(factorySlug)}/templates${tail}`;
427
+ }
376
428
 
377
429
  class AgentComposeClient {
378
430
  fetch;
431
+ baseUrl;
432
+ apiKey;
379
433
  constructor(baseUrl, apiKey) {
434
+ this.baseUrl = baseUrl.replace(/\/$/, "");
435
+ this.apiKey = apiKey;
380
436
  this.fetch = ofetch.create({
381
- baseURL: baseUrl.replace(/\/$/, ""),
437
+ baseURL: this.baseUrl,
382
438
  headers: { Authorization: `Bearer ${apiKey}` },
383
439
  async onResponseError({ response }) {
384
440
  const body = response._data;
@@ -387,15 +443,18 @@ class AgentComposeClient {
387
443
  });
388
444
  }
389
445
  register(payload) {
390
- return this.fetch("/api/v1/templates", { method: "POST", body: payload });
446
+ const { factorySlug = DEFAULT_FACTORY, ...body } = payload;
447
+ return this.fetch(templatePath(factorySlug), { method: "POST", body });
391
448
  }
392
449
  invoke(name, input, opts) {
393
450
  const parentRunId = opts?.parentRunId === undefined ? detectAmbientParentRunId() : opts.parentRunId;
394
- return this.fetch(`/api/v1/templates/${name}/invoke`, {
451
+ const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
452
+ return this.fetch(templatePath(factorySlug, name, "invoke"), {
395
453
  method: "POST",
396
454
  body: {
397
455
  input,
398
456
  ...opts?.snapshot !== undefined ? { snapshot: opts.snapshot } : {},
457
+ ...opts?.saveSnapshot !== undefined ? { saveSnapshot: opts.saveSnapshot } : {},
399
458
  ...parentRunId ? { parentRunId } : {}
400
459
  }
401
460
  });
@@ -405,7 +464,9 @@ class AgentComposeClient {
405
464
  const pollMs = opts?.pollIntervalMs ?? 1000;
406
465
  const { id: runId } = await this.invoke(name, input, {
407
466
  ...opts?.snapshot !== undefined ? { snapshot: opts.snapshot } : {},
408
- ...opts?.parentRunId !== undefined ? { parentRunId: opts.parentRunId } : {}
467
+ ...opts?.saveSnapshot !== undefined ? { saveSnapshot: opts.saveSnapshot } : {},
468
+ ...opts?.parentRunId !== undefined ? { parentRunId: opts.parentRunId } : {},
469
+ ...opts?.factorySlug !== undefined ? { factorySlug: opts.factorySlug } : {}
409
470
  });
410
471
  const deadline = Date.now() + timeoutMs;
411
472
  while (Date.now() < deadline) {
@@ -432,19 +493,78 @@ class AgentComposeClient {
432
493
  getStatus(runId) {
433
494
  return this.fetch(`/api/v1/workflows/${runId}/status`);
434
495
  }
435
- async listTemplates() {
436
- const body = await this.fetch("/api/v1/templates");
496
+ async listTemplates(opts) {
497
+ const path = opts?.factorySlug ? templatePath(opts.factorySlug) : "/api/v1/templates";
498
+ const body = await this.fetch(path);
437
499
  return body.templates;
438
500
  }
439
- setSecret(workflowName, key, value) {
440
- return this.fetch(`/api/v1/templates/${workflowName}/secrets`, { method: "POST", body: { key, value } });
501
+ async listFactories() {
502
+ const body = await this.fetch("/api/v1/factories");
503
+ return body.factories;
504
+ }
505
+ createFactory(payload) {
506
+ return this.fetch("/api/v1/factories", { method: "POST", body: payload });
441
507
  }
442
- async listSecrets(workflowName) {
443
- const body = await this.fetch(`/api/v1/templates/${workflowName}/secrets`);
508
+ getFactory(slug) {
509
+ return this.fetch(`/api/v1/factories/${encodeURIComponent(slug)}`);
510
+ }
511
+ updateFactory(slug, updates) {
512
+ return this.fetch(`/api/v1/factories/${encodeURIComponent(slug)}`, { method: "PATCH", body: updates });
513
+ }
514
+ deleteFactory(slug) {
515
+ return this.fetch(`/api/v1/factories/${encodeURIComponent(slug)}`, { method: "DELETE" });
516
+ }
517
+ setSecret(workflowName, key, value, opts) {
518
+ const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
519
+ return this.fetch(templatePath(factorySlug, workflowName, "secrets"), {
520
+ method: "POST",
521
+ body: { key, value }
522
+ });
523
+ }
524
+ async listSecrets(workflowName, opts) {
525
+ const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
526
+ const body = await this.fetch(templatePath(factorySlug, workflowName, "secrets"));
444
527
  return body.secrets.map((s) => ({ key: s.secretKey, createdAt: s.createdAt, updatedAt: s.updatedAt }));
445
528
  }
446
- deleteSecret(workflowName, key) {
447
- return this.fetch(`/api/v1/templates/${workflowName}/secrets/${key}`, { method: "DELETE" });
529
+ deleteSecret(workflowName, key, opts) {
530
+ const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
531
+ return this.fetch(templatePath(factorySlug, workflowName, "secrets", key), { method: "DELETE" });
532
+ }
533
+ createApiKey(input) {
534
+ return this.fetch("/api-keys", { method: "POST", body: input });
535
+ }
536
+ async listApiKeys() {
537
+ const body = await this.fetch("/api-keys");
538
+ return body.data;
539
+ }
540
+ getUsage(from, to) {
541
+ const qs = `?from=${encodeURIComponent(from.toISOString())}&to=${encodeURIComponent(to.toISOString())}`;
542
+ return this.fetch(`/api/v1/usage${qs}`);
543
+ }
544
+ cancelRun(runId) {
545
+ return this.fetch(`/api/v1/workflows/${encodeURIComponent(runId)}/cancel`, { method: "POST" });
546
+ }
547
+ async* streamRunLogs(runId, opts) {
548
+ const headers = { Authorization: `Bearer ${this.apiKey}` };
549
+ if (opts?.lastEventId && opts.lastEventId > 0) {
550
+ headers["Last-Event-ID"] = String(opts.lastEventId);
551
+ }
552
+ const res = await fetch(`${this.baseUrl}/api/v1/workflows/${encodeURIComponent(runId)}/stream`, {
553
+ headers,
554
+ ...opts?.signal ? { signal: opts.signal } : {}
555
+ });
556
+ if (!res.ok || !res.body) {
557
+ let message = res.statusText;
558
+ try {
559
+ const body = await res.json();
560
+ if (body.error)
561
+ message = body.error;
562
+ } catch {}
563
+ throw new AgentComposeError(res.status, message);
564
+ }
565
+ for await (const ev of parseSseStream(res.body)) {
566
+ yield ev.data;
567
+ }
448
568
  }
449
569
  }
450
570
  // src/utils/errors.ts
@@ -499,16 +619,16 @@ async function bundleWorkflow(workflowPath, overrides) {
499
619
  const wfBits = await extractFromBundle(source, "workflow", (wf) => wf ? {
500
620
  networkPolicy: wf.networkPolicy,
501
621
  placeholders: wf.placeholders,
502
- sandboxEnvironment: wf.sandboxEnvironment,
503
- snapshot: wf.snapshot
622
+ snapshot: wf.snapshot,
623
+ saveSnapshot: wf.saveSnapshot
504
624
  } : undefined);
505
- const { networkPolicy, placeholders, sandboxEnvironment, snapshot } = wfBits ?? {};
625
+ const { networkPolicy, placeholders, snapshot, saveSnapshot } = wfBits ?? {};
506
626
  return {
507
627
  source,
508
628
  networkPolicy: overrides?.networkPolicy ?? networkPolicy,
509
629
  placeholders: overrides?.placeholders ?? placeholders,
510
- ...sandboxEnvironment ? { sandboxEnvironment } : {},
511
- ...snapshot !== undefined ? { snapshot } : {}
630
+ ...snapshot !== undefined ? { snapshot } : {},
631
+ ...saveSnapshot !== undefined ? { saveSnapshot } : {}
512
632
  };
513
633
  }
514
634
  // src/utils/schemas.ts
@@ -1077,6 +1197,7 @@ export {
1077
1197
  runWorkflow,
1078
1198
  runAgent,
1079
1199
  reconnectSandbox,
1200
+ parseSseStream,
1080
1201
  parseSseExecStream,
1081
1202
  parseNameVersion,
1082
1203
  parseAgentStatus,