@agent-compose/sdk 0.5.7 → 0.5.8
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/agent/__tests__/run-agent-liveness.test.d.ts +17 -0
- package/dist/agent/agent-context.d.ts +67 -0
- package/dist/agent/agent-loop.d.ts +1 -0
- package/dist/client.d.ts +65 -2
- package/dist/index.d.ts +6 -3
- package/dist/index.js +226 -22
- package/dist/pause/wrappers.d.ts +7 -11
- package/dist/runtimes/openai-desktop.js +223 -22
- package/dist/sandbox.d.ts +24 -0
- package/dist/step-invocation/types.d.ts +1 -1
- package/dist/types/execution-context.d.ts +1 -3
- package/dist/types/workflow-metadata.d.ts +12 -1
- package/dist/types/workflow.d.ts +9 -2
- package/dist/utils/bundler.d.ts +3 -1
- package/dist/workflow-steps/workflow.d.ts +4 -1
- package/package.json +1 -1
- package/src/agent/agent-context.ts +212 -0
- package/src/agent/agent-loop.ts +31 -12
- package/src/agent/run-agent.ts +37 -1
- package/src/client.ts +89 -2
- package/src/index.ts +6 -2
- package/src/pause/wrappers.ts +7 -21
- package/src/sandbox.ts +78 -23
- package/src/step-invocation/types.ts +1 -1
- package/src/types/execution-context.ts +1 -3
- package/src/types/workflow-metadata.ts +14 -1
- package/src/types/workflow.ts +9 -3
- package/src/utils/bundler.ts +4 -1
- package/src/workflow-steps/workflow.ts +4 -1
- package/src/workflows/invoke-child.ts +7 -1
package/src/sandbox.ts
CHANGED
|
@@ -71,6 +71,35 @@ export type SandboxNetworkPolicy =
|
|
|
71
71
|
subnets?: SandboxNetworkSubnetPolicy;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
/** Sandbox machine size. A coarse small/medium/large knob that maps to
|
|
75
|
+
* provider machine specs at create time. Vercel honours it natively via
|
|
76
|
+
* `resources.vcpus` (2048 MB RAM per vCPU). E2B sizing is baked into the
|
|
77
|
+
* template, so E2B ignores this field. Default: "small". */
|
|
78
|
+
/** Sandbox hardware SKU. Named for the actual machine spec (vCPU + RAM) rather
|
|
79
|
+
* than abstract t-shirt sizes. Memory is always 2048 MB per vCPU:
|
|
80
|
+
* 2vcpu-4gb = 2 vCPU / 4 GiB (Vercel's own default machine)
|
|
81
|
+
* 4vcpu-8gb = 4 vCPU / 8 GiB
|
|
82
|
+
* 8vcpu-16gb = 8 vCPU / 16 GiB (per-sandbox ceiling on STANDARD accounts —
|
|
83
|
+
* probed live: 16 & 32 vCPU 400 on dev)
|
|
84
|
+
* 32vcpu-64gb = 32 vCPU / 64 GiB (ENTERPRISE ONLY — standard accounts reject >8 vCPU) */
|
|
85
|
+
export type SandboxSize = "2vcpu-4gb" | "4vcpu-8gb" | "8vcpu-16gb" | "32vcpu-64gb";
|
|
86
|
+
|
|
87
|
+
/** SKU → Vercel vCPU count (RAM follows at 2048 MB/vCPU). */
|
|
88
|
+
export const SANDBOX_VCPUS: Record<SandboxSize, number> = {
|
|
89
|
+
"2vcpu-4gb": 2,
|
|
90
|
+
"4vcpu-8gb": 4,
|
|
91
|
+
"8vcpu-16gb": 8,
|
|
92
|
+
"32vcpu-64gb": 32,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/** SDK fallback size when neither the caller nor the deployment specifies one.
|
|
96
|
+
* Deliberately conservative — the OPERATIONAL default is chosen per-environment
|
|
97
|
+
* by the server via the `SANDBOX_DEFAULT_SIZE` env var (prod = Enterprise →
|
|
98
|
+
* `32vcpu-64gb`; dev = `8vcpu-16gb`, since the dev account caps at 8 vCPU).
|
|
99
|
+
* TODO(sandbox-size): the prod default is temporarily `32vcpu-64gb` for a
|
|
100
|
+
* memory-hungry workload — lower it back when no longer needed. */
|
|
101
|
+
export const DEFAULT_SANDBOX_SIZE: SandboxSize = "2vcpu-4gb";
|
|
102
|
+
|
|
74
103
|
export interface SandboxCreateOpts {
|
|
75
104
|
envs: Record<string, string>;
|
|
76
105
|
metadata: Record<string, string>;
|
|
@@ -78,6 +107,9 @@ export interface SandboxCreateOpts {
|
|
|
78
107
|
/** Provider-specific template/snapshot identifier. E2B: template id or
|
|
79
108
|
* snapshot id (omit → E2B's default base). Vercel: snapshot id (omit → node24). */
|
|
80
109
|
template?: string;
|
|
110
|
+
/** Machine size. Vercel maps it to `resources.vcpus`; E2B ignores it
|
|
111
|
+
* (size is template-defined). Omit → `DEFAULT_SANDBOX_SIZE`. */
|
|
112
|
+
size?: SandboxSize;
|
|
81
113
|
/** Outbound request policy with header transforms — ONE shape for every
|
|
82
114
|
* provider; only the enforcement point differs. Vercel's firewall
|
|
83
115
|
* enforces + injects natively from this value. E2B enforces it via an
|
|
@@ -417,16 +449,11 @@ function makeVercelSandboxProvider(sb: any, globalEnvs?: Record<string, string>)
|
|
|
417
449
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
418
450
|
const handle: any = await sb.runCommand({ cmd: "sh", args: ["-c", cmd], cwd: opts?.cwd, env: mergeEnvs(opts?.envs), detached: true, signal, ...(opts?.sudo ? { sudo: true } : {}) })
|
|
419
451
|
.catch((err: unknown) => asUnavailable(err, true));
|
|
420
|
-
// Reconnect to the already-running command on transient
|
|
421
|
-
// `h.logs()` replays
|
|
422
|
-
//
|
|
423
|
-
//
|
|
424
|
-
|
|
425
|
-
// A failure here (mid-stream / on `wait`) is NOT safe to retry: the
|
|
426
|
-
// runner already launched, so user code may have produced side
|
|
427
|
-
// effects. Surface it as a terminal `SandboxUnavailableError` so it's
|
|
428
|
-
// classified honestly but not auto-replayed.
|
|
429
|
-
try {
|
|
452
|
+
// Stream + wait. Reconnect to the already-running command on transient
|
|
453
|
+
// stream failures (e.g. BrotliDecompressionError). `h.logs()` replays
|
|
454
|
+
// from the start on reconnect, so reset accumulators per attempt to
|
|
455
|
+
// avoid double-counting.
|
|
456
|
+
const collect = async () => {
|
|
430
457
|
await pRetry(async (attempt) => {
|
|
431
458
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
432
459
|
const h: any = attempt === 1 ? handle : await sb.getCommand(handle.cmdId);
|
|
@@ -438,17 +465,34 @@ function makeVercelSandboxProvider(sb: any, globalEnvs?: Record<string, string>)
|
|
|
438
465
|
}, { retries: 3, minTimeout: 1_000, factor: 2 });
|
|
439
466
|
const finished = await handle.wait();
|
|
440
467
|
return { exitCode: finished.exitCode, stdout, stderr };
|
|
468
|
+
};
|
|
469
|
+
// `timeoutMs` MUST be authoritative. The AbortSignal alone is not: a
|
|
470
|
+
// command that RUNS but emits nothing (e.g. a wedged `archil checkout`
|
|
471
|
+
// on a blocked data plane) leaves `logs()`/`wait()` pending and the
|
|
472
|
+
// abort never interrupts the await — the call hangs for the activity's
|
|
473
|
+
// whole multi-hour ceiling. Race a hard client-side deadline so a hung
|
|
474
|
+
// command fails fast and the caller's degrade/retry policy takes over.
|
|
475
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
476
|
+
const deadline = opts?.timeoutMs
|
|
477
|
+
? new Promise<never>((_, reject) => {
|
|
478
|
+
timer = setTimeout(
|
|
479
|
+
() => reject(new Error(`command timed out after ${opts.timeoutMs}ms: ${cmd.slice(0, 200)}`)),
|
|
480
|
+
opts.timeoutMs);
|
|
481
|
+
})
|
|
482
|
+
: undefined;
|
|
483
|
+
try {
|
|
484
|
+
return await (deadline ? Promise.race([collect(), deadline]) : collect());
|
|
441
485
|
} catch (err) {
|
|
442
|
-
// A
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
// terminal sandbox-unavailable failed whole runs
|
|
446
|
-
// slow mount probe
|
|
447
|
-
|
|
448
|
-
if (signal?.aborted) {
|
|
449
|
-
throw new Error(`command timed out after ${opts?.timeoutMs}ms: ${cmd.slice(0, 200)}`);
|
|
450
|
-
}
|
|
486
|
+
// A timeout (hard deadline or AbortSignal) is a COMMAND overrunning
|
|
487
|
+
// its budget, not the sandbox dying — the VM is alive. Surface it as
|
|
488
|
+
// a plain error so the caller's own retry/deadline policy decides
|
|
489
|
+
// (classifying it as terminal sandbox-unavailable failed whole runs
|
|
490
|
+
// over a single slow mount probe, observed live).
|
|
491
|
+
if (err instanceof Error && err.message.startsWith("command timed out after")) throw err;
|
|
492
|
+
if (signal?.aborted) throw new Error(`command timed out after ${opts?.timeoutMs}ms: ${cmd.slice(0, 200)}`);
|
|
451
493
|
return asUnavailable(err, false);
|
|
494
|
+
} finally {
|
|
495
|
+
if (timer) clearTimeout(timer);
|
|
452
496
|
}
|
|
453
497
|
},
|
|
454
498
|
},
|
|
@@ -567,14 +611,19 @@ const SANDBOX_PROVIDERS: Record<string, SandboxProviderDef> = {
|
|
|
567
611
|
// bakes on top of this base chains from it — the base tools are in
|
|
568
612
|
// every derived snapshot for free.
|
|
569
613
|
const tmpl = opts.template ?? process.env.VERCEL_DEFAULT_SNAPSHOT;
|
|
614
|
+
// Machine size → vCPUs (RAM auto-follows at 2048 MB/vCPU). Always sent
|
|
615
|
+
// explicitly so the spec is deterministic and self-documenting rather
|
|
616
|
+
// than riding Vercel's implicit default; "small" maps to that default
|
|
617
|
+
// anyway, so existing runs are unchanged.
|
|
618
|
+
const resources = { vcpus: SANDBOX_VCPUS[opts.size ?? DEFAULT_SANDBOX_SIZE] };
|
|
570
619
|
// `persistent: false` — @vercel/sandbox 2.x creates persistent-by-default
|
|
571
620
|
// sandboxes: stop() auto-snapshots (and keeps billing storage), commands
|
|
572
621
|
// transparently resume a stopped VM, and kill no longer destroys. Our
|
|
573
622
|
// sandboxes are single-run and lifecycle-managed by the engine (explicit
|
|
574
623
|
// snapshot() / kill()), so opt out in BOTH branches.
|
|
575
624
|
const sb = await VercelSandbox.create(tmpl
|
|
576
|
-
? { source: { type: "snapshot" as const, snapshotId: tmpl }, timeout: opts.timeoutMs, env: opts.envs, tags, persistent: false, ...np, ...creds }
|
|
577
|
-
: { runtime: "node24" as const, timeout: opts.timeoutMs, env: opts.envs, tags, persistent: false, ...np, ...creds },
|
|
625
|
+
? { source: { type: "snapshot" as const, snapshotId: tmpl }, timeout: opts.timeoutMs, env: opts.envs, tags, persistent: false, resources, ...np, ...creds }
|
|
626
|
+
: { runtime: "node24" as const, timeout: opts.timeoutMs, env: opts.envs, tags, persistent: false, resources, ...np, ...creds },
|
|
578
627
|
);
|
|
579
628
|
// Pass envs as globalEnvs so they're injected into every runCommand subprocess.
|
|
580
629
|
// (Vercel's Sandbox.create env parameter does not flow to runCommand subprocesses.)
|
|
@@ -649,7 +698,10 @@ const SANDBOX_PROVIDERS: Record<string, SandboxProviderDef> = {
|
|
|
649
698
|
},
|
|
650
699
|
"e2b": {
|
|
651
700
|
requiredEnv: { E2B_API_KEY: "E2B API key — e2b.dev/dashboard" },
|
|
652
|
-
|
|
701
|
+
// `size` dropped here: E2B has no create-time resource knob (specs are
|
|
702
|
+
// baked into the template/snapshot), so sizing on E2B = a pre-sized
|
|
703
|
+
// template, not this field. Honoured only on Vercel.
|
|
704
|
+
create: async ({ template, timeoutMs, networkPolicy: _np, size: _size, ...rest }) => {
|
|
653
705
|
// `template` is an E2B template id, a snapshot id (a valid create source
|
|
654
706
|
// that persists beyond its origin sandbox — bootFrom parity), or absent →
|
|
655
707
|
// E2B's default base (Debian + node + npm/python/git), mirroring Vercel's
|
|
@@ -722,7 +774,10 @@ const SANDBOX_PROVIDERS: Record<string, SandboxProviderDef> = {
|
|
|
722
774
|
// its transforms carry live connector tokens, and a credential-bearing
|
|
723
775
|
// object must never cross into a third-party library's option bag.
|
|
724
776
|
// Lifetime is clamped to E2B's per-plan cap the same way.
|
|
725
|
-
|
|
777
|
+
// `size` dropped here: E2B has no create-time resource knob (specs are
|
|
778
|
+
// baked into the template/snapshot), so sizing on E2B = a pre-sized
|
|
779
|
+
// template, not this field. Honoured only on Vercel.
|
|
780
|
+
create: async ({ template, timeoutMs, networkPolicy: _np, size: _size, ...rest }) => {
|
|
726
781
|
if (!template) throw new Error("E2B Desktop provider requires an explicit `template` (Dockerfile-based — no default base image)");
|
|
727
782
|
return makeDesktopSandboxProvider(
|
|
728
783
|
await Desktop.create(template, { ...rest, timeoutMs: Math.min(timeoutMs, e2bMaxSandboxMs()) }),
|
|
@@ -43,7 +43,7 @@ export type StepResult<TOutput = unknown> =
|
|
|
43
43
|
* it so the runtime type and the parsed shape can't drift.
|
|
44
44
|
*
|
|
45
45
|
* Loose by design (the inner zod shape stops at orchestration fields
|
|
46
|
-
* the engine needs): the SDK wrapper layer (`
|
|
46
|
+
* the engine needs): the SDK wrapper layer (`sleep` /
|
|
47
47
|
* `sleep` / `waitForEvent`) owns its own payload contract, and the
|
|
48
48
|
* engine treats `payload` as opaque. */
|
|
49
49
|
export const StepPauseRequestSchema = z.object({
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { InvokeAndWaitOptions, RunStatus } from "../client.js";
|
|
4
4
|
import type { RequestContext } from "../request-context/request-context.js";
|
|
5
5
|
import type { PauseRequest } from "../pause/pause-core.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { WaitForEventRequest } from "../pause/wrappers.js";
|
|
7
7
|
import type { SandboxProvider } from "./sandbox.js";
|
|
8
8
|
|
|
9
9
|
/** The identity of this workflow run. */
|
|
@@ -46,8 +46,6 @@ export interface BaseExecutionContext {
|
|
|
46
46
|
* PauseExpiredError / PauseSchemaError. See ADR-0006 / ADR-0011.
|
|
47
47
|
*/
|
|
48
48
|
pause<T = unknown>(req: PauseRequest<T>): Promise<T>;
|
|
49
|
-
/** Pause for a typed decision (a `schema` is required). Wrapper over `pause`. */
|
|
50
|
-
requestDecision<T>(req: RequestDecisionRequest<T>): Promise<T>;
|
|
51
49
|
/** Lightweight timed pause — resolves after `durationMs`, no snapshot. */
|
|
52
50
|
sleep(durationMs: number): Promise<void>;
|
|
53
51
|
/** Pause until an event resumes by `correlationKey`. Wrapper over `pause`. */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `workflow-steps/workflow.ts` — it is the cycle-break point.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { SandboxNetworkPolicy } from "../sandbox.js";
|
|
12
|
+
import type { SandboxNetworkPolicy, SandboxSize } from "../sandbox.js";
|
|
13
13
|
import type { Processor } from "../processors/processor.js";
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -141,6 +141,16 @@ export interface InvokePolicy {
|
|
|
141
141
|
workflows?: string[];
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/** Sandbox machine resources for a workflow's runs. A coarse size knob
|
|
145
|
+
* today; kept as its own object so finer controls (disk, gpu, …) can be
|
|
146
|
+
* added later without reshaping `WorkflowMetadata`. */
|
|
147
|
+
export interface SandboxResources {
|
|
148
|
+
/** Machine size — `small | medium | large`. Maps to provider specs at
|
|
149
|
+
* create time (Vercel: 2 / 4 / 8 vCPU, 2048 MB RAM per vCPU). Omit →
|
|
150
|
+
* `"small"`. E2B sizing is template-defined and ignores this. */
|
|
151
|
+
size?: SandboxSize;
|
|
152
|
+
}
|
|
153
|
+
|
|
144
154
|
export interface WorkflowMetadata {
|
|
145
155
|
/** One-line, human-readable description of what the workflow does.
|
|
146
156
|
* Surfaced on the dashboard template tile + run page header. Authors
|
|
@@ -161,6 +171,8 @@ export interface WorkflowMetadata {
|
|
|
161
171
|
outputSchema?: IOSchema;
|
|
162
172
|
/** All snapshot config — boot source + capture mode. */
|
|
163
173
|
snapshots?: SnapshotConfig;
|
|
174
|
+
/** Sandbox machine resources (size). Optional; omit → small. */
|
|
175
|
+
resources?: SandboxResources;
|
|
164
176
|
processors?: readonly Processor[];
|
|
165
177
|
/** Connector requirements — providers whose APIs this workflow calls.
|
|
166
178
|
* Dispatch resolves an authorized grant per provider and injects a
|
|
@@ -198,6 +210,7 @@ export function extractMetadata(source: Partial<WorkflowMetadata>): WorkflowMeta
|
|
|
198
210
|
if (source.inputSchema !== undefined) out.inputSchema = freezeMetadataValue(source.inputSchema);
|
|
199
211
|
if (source.outputSchema !== undefined) out.outputSchema = freezeMetadataValue(source.outputSchema);
|
|
200
212
|
if (source.snapshots !== undefined) out.snapshots = Object.freeze({ ...source.snapshots });
|
|
213
|
+
if (source.resources !== undefined) out.resources = Object.freeze({ ...source.resources });
|
|
201
214
|
if (source.processors !== undefined) out.processors = Object.freeze([...source.processors]);
|
|
202
215
|
if (source.connectors !== undefined) out.connectors = freezeMetadataValue(source.connectors);
|
|
203
216
|
if (source.connectorOperation !== undefined) out.connectorOperation = Object.freeze({ ...source.connectorOperation });
|
package/src/types/workflow.ts
CHANGED
|
@@ -37,8 +37,8 @@ export interface AgentEventSink {
|
|
|
37
37
|
emit(event: AgentLifecycleEvent): void | Promise<void>;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
import type { SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema } from "./workflow-metadata.js";
|
|
41
|
-
export type { SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema };
|
|
40
|
+
import type { SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema, SandboxResources } from "./workflow-metadata.js";
|
|
41
|
+
export type { SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema, SandboxResources };
|
|
42
42
|
|
|
43
43
|
/** Turn/iteration budget for `agent(opts)`. Re-exported here so authors
|
|
44
44
|
* can type per-invoke budget overrides they pass as workflow input. */
|
|
@@ -120,6 +120,13 @@ export interface WorkflowDefinition<
|
|
|
120
120
|
* `invoke({ snapshots })` overrides this default.
|
|
121
121
|
*/
|
|
122
122
|
snapshots?: SnapshotConfig;
|
|
123
|
+
/**
|
|
124
|
+
* Sandbox machine size — `small` (default) | `medium` | `large`. Maps to
|
|
125
|
+
* provider machine specs at create (Vercel: 2 / 4 / 8 vCPU, 2048 MB RAM
|
|
126
|
+
* per vCPU). Optional; omit for `small`. E2B sizing is template-defined
|
|
127
|
+
* and ignores this. Per-invocation `invoke({ size })` overrides it.
|
|
128
|
+
*/
|
|
129
|
+
resources?: SandboxResources;
|
|
123
130
|
/**
|
|
124
131
|
* Outbound network policy for the runner sandbox.
|
|
125
132
|
* Use "*": [] to allow all traffic while still injecting headers for specific domains.
|
|
@@ -239,7 +246,6 @@ function compileRunForm<TOutput, TInput extends Record<string, unknown>>(
|
|
|
239
246
|
agentEvents: stepCtx.agentEvents,
|
|
240
247
|
checkpoint: stepCtx.checkpoint,
|
|
241
248
|
pause: stepCtx.pause,
|
|
242
|
-
requestDecision: stepCtx.requestDecision,
|
|
243
249
|
sleep: stepCtx.sleep,
|
|
244
250
|
waitForEvent: stepCtx.waitForEvent,
|
|
245
251
|
processors: metadata.processors ?? [],
|
package/src/utils/bundler.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { parse as babelParse } from "@babel/parser";
|
|
|
25
25
|
import type { File, ExportDefaultDeclaration, CallExpression, Expression, Statement } from "@babel/types";
|
|
26
26
|
import { importSourceModule } from "./source-loader.js";
|
|
27
27
|
import type { SnapshotConfig } from "../types/workflow.js";
|
|
28
|
-
import type { IOSchema, OutputSchema, ConnectorRequirements, ConnectorOperationTag, InvokePolicy } from "../types/workflow-metadata.js";
|
|
28
|
+
import type { IOSchema, OutputSchema, ConnectorRequirements, ConnectorOperationTag, InvokePolicy, SandboxResources } from "../types/workflow-metadata.js";
|
|
29
29
|
import type { SandboxNetworkPolicy } from "../sandbox.js";
|
|
30
30
|
import { isWorkflow } from "../workflow-steps/workflow.js";
|
|
31
31
|
import type { Workflow } from "../workflow-steps/types.js";
|
|
@@ -98,6 +98,8 @@ export interface BundledWorkflow {
|
|
|
98
98
|
/** Snapshot config from the workflow definition — `bootFrom` (where to
|
|
99
99
|
* restore at run start), `save`, `retain`. */
|
|
100
100
|
snapshots?: SnapshotConfig;
|
|
101
|
+
/** Sandbox machine size declared via `defineWorkflow({ resources: { size } })`. */
|
|
102
|
+
resources?: SandboxResources;
|
|
101
103
|
workflowPlan: WorkflowPlan;
|
|
102
104
|
/** Compact JSON-Schema-shaped description of the workflow's input
|
|
103
105
|
* type. Extracted from the workflow's declared `input` zod schema
|
|
@@ -334,6 +336,7 @@ export async function bundleWorkflow(
|
|
|
334
336
|
...(inputSchema !== undefined ? { inputSchema } : {}),
|
|
335
337
|
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
336
338
|
...(metadata.snapshots !== undefined ? { snapshots: metadata.snapshots } : {}),
|
|
339
|
+
...(metadata.resources !== undefined ? { resources: metadata.resources } : {}),
|
|
337
340
|
...(metadata.connectors !== undefined ? { connectors: metadata.connectors } : {}),
|
|
338
341
|
...(metadata.connectorOperation !== undefined ? { connectorOperation: metadata.connectorOperation } : {}),
|
|
339
342
|
...(metadata.invokePolicy !== undefined ? { invokePolicy: metadata.invokePolicy } : {}),
|
|
@@ -23,7 +23,7 @@ import type { z } from "zod";
|
|
|
23
23
|
import type { Step, Workflow } from "./types.js";
|
|
24
24
|
import { WORKFLOW_BRAND } from "./types.js";
|
|
25
25
|
import { extractMetadata } from "../types/workflow-metadata.js";
|
|
26
|
-
import type { SnapshotConfig } from "../types/workflow-metadata.js";
|
|
26
|
+
import type { SnapshotConfig, SandboxResources } from "../types/workflow-metadata.js";
|
|
27
27
|
import type { SandboxNetworkPolicy } from "../sandbox.js";
|
|
28
28
|
import type { Processor } from "../processors/processor.js";
|
|
29
29
|
|
|
@@ -51,6 +51,9 @@ export interface StepWorkflowDefinition<TInput, TOutput> {
|
|
|
51
51
|
networkPolicy?: SandboxNetworkPolicy;
|
|
52
52
|
placeholders?: Record<string, string>;
|
|
53
53
|
snapshots?: SnapshotConfig;
|
|
54
|
+
/** Sandbox machine size — small (default) | medium | large. Vercel maps
|
|
55
|
+
* it to vCPUs; E2B sizing is template-defined. Omit → small. */
|
|
56
|
+
resources?: SandboxResources;
|
|
54
57
|
processors?: readonly Processor[];
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -24,6 +24,12 @@ export function buildInvokeChild(
|
|
|
24
24
|
return (name, input, childOpts) => getChildClient().invokeAndWait(name, input, {
|
|
25
25
|
...childOpts,
|
|
26
26
|
parentRunId: runId,
|
|
27
|
-
|
|
27
|
+
// The runner sets `AGENT_COMPOSE_FACTORY` (the run's factory slug — see
|
|
28
|
+
// activities.ts loadRunnerEnvs). Default the child to it so it lands in the
|
|
29
|
+
// SAME factory as the parent — the per-run API key is factory-scoped, so a
|
|
30
|
+
// child dispatched into another factory 403s. (Was reading the never-set
|
|
31
|
+
// `AGENT_COMPOSE_FACTORY_SLUG`, silently falling back to "default".)
|
|
32
|
+
factorySlug: childOpts?.factorySlug ?? opts.defaultFactorySlug
|
|
33
|
+
?? process.env.AGENT_COMPOSE_FACTORY ?? process.env.AGENT_COMPOSE_FACTORY_SLUG ?? "default",
|
|
28
34
|
});
|
|
29
35
|
}
|