@agent-compose/sdk 0.5.2 → 0.5.6

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.
@@ -18,7 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/runtimes/vercel.ts
21
- import { streamText, stepCountIs, tool } from "ai";
21
+ import { streamText, stepCountIs, tool, gateway } from "ai";
22
22
 
23
23
  // src/types/runtime.ts
24
24
  function defineRuntime(pkg) {
@@ -387,6 +387,8 @@ class VercelRunner {
387
387
  options;
388
388
  config;
389
389
  supportsToolCallProcessor = true;
390
+ kind;
391
+ model;
390
392
  tools;
391
393
  messages = [];
392
394
  constructor(sandbox, options, config) {
@@ -394,6 +396,8 @@ class VercelRunner {
394
396
  this.options = options;
395
397
  this.config = config;
396
398
  this.tools = config.tools ?? codingTools;
399
+ this.kind = config.kind;
400
+ this.model = config.modelId;
397
401
  }
398
402
  async gateToolCall(call, ctx) {
399
403
  const verdict = await runProcessorChain(this.options.processors ?? [], (p) => p.processToolCall, call, ctx);
@@ -511,6 +515,10 @@ function createVercelRuntime(config) {
511
515
  create: (sandbox, opts) => new VercelRunner(sandbox, opts, config)
512
516
  });
513
517
  }
518
+ async function listVercelRuntimeModels() {
519
+ const { models } = await gateway.getAvailableModels();
520
+ return models.filter((m) => m.modelType == null || m.modelType === "language").map((m) => ({ id: m.id, name: m.name })).sort((a, b) => a.id.localeCompare(b.id));
521
+ }
514
522
  // src/types/workflow.ts
515
523
  import { z as z3 } from "zod";
516
524
 
@@ -2368,6 +2376,259 @@ function createClaudeRuntime(config = {}) {
2368
2376
  });
2369
2377
  }
2370
2378
  var claude_default = createClaudeRuntime();
2379
+ // src/runtimes/_cli-agent.ts
2380
+ function now3() {
2381
+ return new Date().toISOString();
2382
+ }
2383
+ function shellQuote(value) {
2384
+ return `'${value.replace(/'/g, `'\\''`)}'`;
2385
+ }
2386
+
2387
+ class CliAgentRunner {
2388
+ sandbox;
2389
+ options;
2390
+ spec;
2391
+ configModel;
2392
+ kind;
2393
+ constructor(sandbox, options, spec, configModel) {
2394
+ this.sandbox = sandbox;
2395
+ this.options = options;
2396
+ this.spec = spec;
2397
+ this.configModel = configModel;
2398
+ this.kind = spec.kind;
2399
+ }
2400
+ get model() {
2401
+ return this.configModel ?? this.options.model ?? this.spec.defaultModel;
2402
+ }
2403
+ installed = false;
2404
+ async ensureInstalled() {
2405
+ if (this.installed)
2406
+ return;
2407
+ const probe = await this.sandbox.commands.run(`command -v ${this.spec.bin}`);
2408
+ if (probe.exitCode === 0) {
2409
+ this.installed = true;
2410
+ return;
2411
+ }
2412
+ const res = await this.sandbox.commands.run(this.spec.install, { timeoutMs: 300000 });
2413
+ if (res.exitCode !== 0) {
2414
+ throw new Error(`failed to install ${this.spec.bin}: ${(res.stderr || res.stdout || "").slice(-500)}`);
2415
+ }
2416
+ this.installed = true;
2417
+ }
2418
+ async* sendMessage(opts) {
2419
+ yield { type: "init", sessionId: opts.sessionId ?? "", timestamp: now3() };
2420
+ let sessionId = opts.sessionId;
2421
+ let sawError = false;
2422
+ try {
2423
+ await this.ensureInstalled();
2424
+ const promptPath = `/tmp/ac-${this.spec.kind}-${this.options.agentId ?? "agent"}-${opts.iteration ?? 0}.in`;
2425
+ await this.sandbox.files.write(promptPath, this.spec.promptPayload(opts.prompt));
2426
+ const cmd = this.spec.buildCommand({
2427
+ promptPath,
2428
+ sessionId: opts.sessionId,
2429
+ model: this.model,
2430
+ cwd: this.options.cwd
2431
+ });
2432
+ const lines = new AsyncQueue;
2433
+ let buf = "";
2434
+ const onStdout = (data) => {
2435
+ buf += data;
2436
+ let nl;
2437
+ while ((nl = buf.indexOf(`
2438
+ `)) >= 0) {
2439
+ const line = buf.slice(0, nl).trim();
2440
+ buf = buf.slice(nl + 1);
2441
+ if (line)
2442
+ lines.push(line);
2443
+ }
2444
+ };
2445
+ const runPromise = this.sandbox.commands.run(cmd, {
2446
+ ...this.options.cwd ? { cwd: this.options.cwd } : {},
2447
+ onStdout
2448
+ }).then((res2) => {
2449
+ const tail = buf.trim();
2450
+ if (tail)
2451
+ lines.push(tail);
2452
+ lines.close();
2453
+ return res2;
2454
+ }, (err) => {
2455
+ lines.close();
2456
+ throw err;
2457
+ });
2458
+ for await (const line of lines) {
2459
+ let parsed;
2460
+ try {
2461
+ parsed = JSON.parse(line);
2462
+ } catch {
2463
+ continue;
2464
+ }
2465
+ const sid = this.spec.extractSessionId(parsed);
2466
+ if (sid)
2467
+ sessionId = sid;
2468
+ for (const msg of this.spec.mapEvent(parsed)) {
2469
+ if (msg.type === "error")
2470
+ sawError = true;
2471
+ yield msg;
2472
+ }
2473
+ }
2474
+ const res = await runPromise;
2475
+ if (res.exitCode !== 0 && !sawError) {
2476
+ const tail = (res.stderr ?? "").slice(-2000);
2477
+ yield { type: "error", text: `${this.spec.kind} exited with code ${res.exitCode}${tail ? `: ${tail}` : ""}`, timestamp: now3() };
2478
+ return;
2479
+ }
2480
+ if (!sawError)
2481
+ yield { type: "done", sessionId: sessionId ?? "", timestamp: now3() };
2482
+ } catch (err) {
2483
+ yield { type: "error", text: formatError(err), timestamp: now3() };
2484
+ }
2485
+ }
2486
+ }
2487
+ function createCliAgentRuntime(spec, configModel) {
2488
+ return defineRuntime({
2489
+ create: (sandbox, opts) => new CliAgentRunner(sandbox, opts, spec, configModel)
2490
+ });
2491
+ }
2492
+
2493
+ // src/runtimes/codex.ts
2494
+ function now4() {
2495
+ return new Date().toISOString();
2496
+ }
2497
+ var codexSpec = {
2498
+ kind: "codex",
2499
+ authEnv: "CODEX_API_KEY",
2500
+ bin: "codex",
2501
+ install: 'sudo npm install -g @openai/codex && (command -v codex >/dev/null 2>&1 || sudo ln -sf "$(npm prefix -g)/bin/codex" /usr/local/bin/codex)',
2502
+ promptPayload: (prompt) => prompt,
2503
+ buildCommand: ({ promptPath, sessionId, model, cwd }) => {
2504
+ const flags = [
2505
+ "--json",
2506
+ "--skip-git-repo-check",
2507
+ "--dangerously-bypass-approvals-and-sandbox",
2508
+ ...model ? ["-m", shellQuote(model)] : [],
2509
+ ...cwd ? ["-C", shellQuote(cwd)] : []
2510
+ ].join(" ");
2511
+ const exec = sessionId ? `codex exec resume ${shellQuote(sessionId)} ${flags}` : `codex exec ${flags}`;
2512
+ return `${exec} - < ${shellQuote(promptPath)}`;
2513
+ },
2514
+ extractSessionId: (p) => p.type === "thread.started" && typeof p.thread_id === "string" ? p.thread_id : undefined,
2515
+ mapEvent: (p) => {
2516
+ const ts = now4();
2517
+ switch (p.type) {
2518
+ case "item.started":
2519
+ case "item.completed": {
2520
+ const item = p.item;
2521
+ if (!item)
2522
+ return [];
2523
+ const itype = String(item.type ?? "");
2524
+ if (itype === "agent_message") {
2525
+ return p.type === "item.completed" ? [{ type: "text", text: String(item.text ?? ""), timestamp: ts }] : [];
2526
+ }
2527
+ if (itype === "reasoning") {
2528
+ return p.type === "item.completed" ? [{ type: "thinking", text: String(item.text ?? ""), timestamp: ts }] : [];
2529
+ }
2530
+ if (itype === "command_execution") {
2531
+ const id = String(item.id ?? "");
2532
+ if (p.type === "item.started") {
2533
+ return [{ type: "tool_use", toolName: "shell", toolInput: { command: String(item.command ?? "") }, toolUseId: id, timestamp: ts }];
2534
+ }
2535
+ const failed = item.status === "failed" || typeof item.exit_code === "number" && item.exit_code !== 0;
2536
+ return [{ type: "tool_result", toolUseId: id, output: String(item.aggregated_output ?? item.output ?? ""), isError: failed, timestamp: ts }];
2537
+ }
2538
+ if (p.type === "item.completed") {
2539
+ return [{ type: "tool_use", toolName: itype || "item", toolInput: item, toolUseId: String(item.id ?? ""), timestamp: ts }];
2540
+ }
2541
+ return [];
2542
+ }
2543
+ case "turn.completed": {
2544
+ const u = p.usage;
2545
+ if (!u)
2546
+ return [];
2547
+ return [{
2548
+ type: "usage",
2549
+ inputTokens: u.input_tokens ?? 0,
2550
+ outputTokens: u.output_tokens ?? 0,
2551
+ cacheReadTokens: u.cached_input_tokens ?? 0,
2552
+ cacheCreationTokens: 0,
2553
+ durationMs: 0,
2554
+ numTurns: 1,
2555
+ timestamp: ts
2556
+ }];
2557
+ }
2558
+ case "turn.failed":
2559
+ case "error":
2560
+ return [{ type: "error", text: formatError(p.error ?? p.message ?? p), timestamp: ts }];
2561
+ default:
2562
+ return [];
2563
+ }
2564
+ }
2565
+ };
2566
+ function createCodexRuntime(config = {}) {
2567
+ return createCliAgentRuntime(codexSpec, config.model);
2568
+ }
2569
+ var codex_default = createCodexRuntime();
2570
+ // src/runtimes/amp.ts
2571
+ function now5() {
2572
+ return new Date().toISOString();
2573
+ }
2574
+ function blocks(msg) {
2575
+ const inner = msg.message?.content ?? msg.content ?? [];
2576
+ return inner;
2577
+ }
2578
+ var ampSpec = {
2579
+ kind: "amp",
2580
+ authEnv: "AMP_API_KEY",
2581
+ bin: "amp",
2582
+ install: 'sudo npm install -g @ampcode/cli && (command -v amp >/dev/null 2>&1 || sudo ln -sf "$(npm prefix -g)/bin/amp" /usr/local/bin/amp)',
2583
+ promptPayload: (prompt) => JSON.stringify({ type: "user", message: { role: "user", content: [{ type: "text", text: prompt }] } }) + `
2584
+ `,
2585
+ buildCommand: ({ promptPath, sessionId }) => {
2586
+ const cont = sessionId ? `threads continue ${shellQuote(sessionId)} ` : "";
2587
+ return `amp ${cont}-x --stream-json --stream-json-input < ${shellQuote(promptPath)}`;
2588
+ },
2589
+ extractSessionId: (p) => typeof p.session_id === "string" ? p.session_id : undefined,
2590
+ mapEvent: (p) => {
2591
+ const ts = now5();
2592
+ if (p.type === "assistant") {
2593
+ return blocks(p).flatMap((b) => {
2594
+ if (b.type === "text")
2595
+ return [{ type: "text", text: String(b.text ?? ""), timestamp: ts }];
2596
+ if (b.type === "thinking")
2597
+ return [{ type: "thinking", text: String(b.thinking ?? ""), timestamp: ts }];
2598
+ if (b.type === "tool_use")
2599
+ return [{ type: "tool_use", toolName: String(b.name ?? ""), toolInput: b.input ?? {}, toolUseId: String(b.id ?? ""), timestamp: ts }];
2600
+ return [];
2601
+ });
2602
+ }
2603
+ if (p.type === "user") {
2604
+ return blocks(p).flatMap((b) => b.type === "tool_result" ? [{ type: "tool_result", toolUseId: String(b.tool_use_id ?? ""), output: typeof b.content === "string" ? b.content : JSON.stringify(b.content ?? ""), isError: Boolean(b.is_error), timestamp: ts }] : []);
2605
+ }
2606
+ if (p.type === "result") {
2607
+ const out = [];
2608
+ const u = p.usage;
2609
+ if (u)
2610
+ out.push({
2611
+ type: "usage",
2612
+ inputTokens: u.input_tokens ?? 0,
2613
+ outputTokens: u.output_tokens ?? 0,
2614
+ cacheReadTokens: u.cache_read_input_tokens ?? 0,
2615
+ cacheCreationTokens: u.cache_creation_input_tokens ?? 0,
2616
+ durationMs: Number(p.duration_ms ?? 0),
2617
+ numTurns: Number(p.num_turns ?? 0),
2618
+ timestamp: ts
2619
+ });
2620
+ if (p.is_error || p.subtype === "error") {
2621
+ out.push({ type: "error", text: formatError(p.result ?? p.error), timestamp: ts });
2622
+ }
2623
+ return out;
2624
+ }
2625
+ return [];
2626
+ }
2627
+ };
2628
+ function createAmpRuntime(config = {}) {
2629
+ return createCliAgentRuntime(ampSpec, config.model);
2630
+ }
2631
+ var amp_default = createAmpRuntime();
2371
2632
  // src/sandbox.ts
2372
2633
  import { promises as fs2 } from "node:fs";
2373
2634
  import { dirname as dirname2 } from "node:path";
@@ -7,18 +7,38 @@ import type { AgentMessage, ModelExecutionContract, RuntimeOptions, SandboxProvi
7
7
  import { type CodingTool } from "../tools/index.js";
8
8
  import type { ProcessorContext, ToolCall } from "../processors/processor.js";
9
9
  export interface VercelRuntimeConfig {
10
- /** Vercel AI SDK language model (e.g. openai("gpt-5"), anthropic("claude-sonnet-4-5")). */
10
+ /** The model to drive — this is the only thing that varies per provider;
11
+ * there is no per-provider runtime. `LanguageModel` accepts every provider:
12
+ * - a gateway model-id string routed via the Vercel AI Gateway (set
13
+ * `AI_GATEWAY_API_KEY`; no provider package needed), e.g. "openai/gpt-5",
14
+ * "google/gemini-2.5-pro", "xai/grok-4", "deepseek/deepseek-chat",
15
+ * "mistral/mistral-large-latest", "anthropic/claude-sonnet-4-5";
16
+ * - or a `LanguageModel` object from a provider package (add the dep + set
17
+ * its API-key env), e.g. `openai("gpt-5")`, `google("gemini-2.5-pro")`. */
11
18
  model: LanguageModel;
12
19
  /** Optional system prompt prepended to every model call. */
13
20
  system?: string;
14
21
  /** Override/extend the default coding tools. Defaults: Read, Write, Edit, Bash. */
15
22
  tools?: readonly CodingTool[];
23
+ /** Short runtime self-id surfaced on `agent.spawned` so the dashboard can
24
+ * show a per-agent runtime icon (e.g. "openai", "gemini"). Provider presets
25
+ * set this; bare `createVercelRuntime` callers can leave it unset. */
26
+ kind?: string;
27
+ /** Display model id surfaced on `agent.spawned` (the Agent tab labels which
28
+ * model each agent ran). `model` above is the AI SDK LanguageModel object;
29
+ * this is its human-readable id string. */
30
+ modelId?: string;
16
31
  }
17
32
  export declare class VercelRunner implements ModelExecutionContract {
18
33
  private readonly sandbox;
19
34
  private readonly options;
20
35
  private readonly config;
21
36
  supportsToolCallProcessor: boolean;
37
+ /** Surfaced on `agent.spawned` for the dashboard's per-agent runtime icon +
38
+ * model label. Set from the (provider preset's) config; undefined for a
39
+ * bare `createVercelRuntime` that didn't label itself. */
40
+ readonly kind?: string;
41
+ readonly model?: string;
22
42
  private readonly tools;
23
43
  private readonly messages;
24
44
  constructor(sandbox: SandboxProvider, options: RuntimeOptions, config: VercelRuntimeConfig);
@@ -44,3 +64,23 @@ export declare class VercelRunner implements ModelExecutionContract {
44
64
  }): AsyncGenerator<AgentMessage>;
45
65
  }
46
66
  export declare function createVercelRuntime(config: VercelRuntimeConfig): import("../index.js").AgentRuntime<SandboxProvider>;
67
+ /** One model offered by the Vercel AI Gateway. Pass `id` straight to
68
+ * `createVercelRuntime({ model: id })`. */
69
+ export interface VercelRuntimeModel {
70
+ /** Gateway model id, e.g. "openai/gpt-5". Usable directly as the runtime model. */
71
+ id: string;
72
+ /** Human-readable display name. */
73
+ name: string;
74
+ }
75
+ /**
76
+ * List the models the Vercel runtime accepts as a gateway model-id string — the
77
+ * LIVE Vercel AI Gateway catalog, so it never goes stale. This is the canonical
78
+ * answer to "what models can I pass to `createVercelRuntime`?" for the string
79
+ * form (`createVercelRuntime({ model: "openai/gpt-5" })`).
80
+ *
81
+ * Requires `AI_GATEWAY_API_KEY`. The other form — a `LanguageModel` object from
82
+ * an `@ai-sdk/<provider>` package — supports whatever that provider package
83
+ * does (see its docs); there's no single cross-form list because the runtime is
84
+ * model-agnostic. Browse the catalog in a UI at https://vercel.com/ai-gateway/models.
85
+ */
86
+ export declare function listVercelRuntimeModels(): Promise<VercelRuntimeModel[]>;
@@ -18,7 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/runtimes/vercel.ts
21
- import { streamText, stepCountIs, tool } from "ai";
21
+ import { streamText, stepCountIs, tool, gateway } from "ai";
22
22
 
23
23
  // src/types/runtime.ts
24
24
  function defineRuntime(pkg) {
@@ -387,6 +387,8 @@ class VercelRunner {
387
387
  options;
388
388
  config;
389
389
  supportsToolCallProcessor = true;
390
+ kind;
391
+ model;
390
392
  tools;
391
393
  messages = [];
392
394
  constructor(sandbox, options, config) {
@@ -394,6 +396,8 @@ class VercelRunner {
394
396
  this.options = options;
395
397
  this.config = config;
396
398
  this.tools = config.tools ?? codingTools;
399
+ this.kind = config.kind;
400
+ this.model = config.modelId;
397
401
  }
398
402
  async gateToolCall(call, ctx) {
399
403
  const verdict = await runProcessorChain(this.options.processors ?? [], (p) => p.processToolCall, call, ctx);
@@ -511,7 +515,12 @@ function createVercelRuntime(config) {
511
515
  create: (sandbox, opts) => new VercelRunner(sandbox, opts, config)
512
516
  });
513
517
  }
518
+ async function listVercelRuntimeModels() {
519
+ const { models } = await gateway.getAvailableModels();
520
+ return models.filter((m) => m.modelType == null || m.modelType === "language").map((m) => ({ id: m.id, name: m.name })).sort((a, b) => a.id.localeCompare(b.id));
521
+ }
514
522
  export {
523
+ listVercelRuntimeModels,
515
524
  createVercelRuntime,
516
525
  VercelRunner
517
526
  };
@@ -22,24 +22,32 @@ import type { Processor } from "../processors/processor.js";
22
22
  * workflow completes. Boolean toggle — custom post-run workflows live
23
23
  * in the separate `postRunHooks` array on `WorkflowMetadata`. */
24
24
  export type WorkflowMemoryConfig = boolean;
25
- /** Where a run boots from. The snapshot id is the unit of identity —
26
- * each captured snapshot already records the workflow + version it
27
- * came from on the snapshot row, so there's no separate "latest of
28
- * workflow X" resolution at dispatch time. Operators pick a snapshot
29
- * from the dashboard snapshot list (or `agentc snapshot list`) and
30
- * paste the id here.
31
- *
32
- * Omit `bootFrom` entirely to boot a fresh base sandbox. */
25
+ /** Boot from a specific captured snapshot, addressed by its id. Operators
26
+ * pick one from the dashboard snapshot list (or `agentc snapshot list`) and
27
+ * paste the id here. */
33
28
  export type BootSnapshot = {
34
29
  snapshotId: string;
35
30
  };
31
+ /** Boot from this workflow's OWN most recent snapshot, scoped to its content
32
+ * hash. The first run — and the first after a re-register changes the source
33
+ * — finds none and boots a fresh base sandbox; `"reuse"` also implies
34
+ * `saveLatest`, so that run captures a snapshot and every run after it boots
35
+ * from it. This lets a runtime install its tooling once (e.g. a CLI-agent
36
+ * runtime `npm i -g`'ing its CLI) and skip the install on every later run,
37
+ * with no hardcoded snapshot id to manage. Re-registering with changed
38
+ * source rolls the content hash, which transparently invalidates the cache
39
+ * and re-installs on the next run. */
40
+ export type ReuseSnapshot = "reuse";
36
41
  /** Snapshot configuration — boot source plus capture knobs. One object
37
42
  * per workflow / per invocation; collapsing boot + capture under a
38
43
  * single key reads as "all snapshot config lives here." */
39
44
  export interface SnapshotConfig {
40
- /** Where the runner restores from at run start. Structured (workflow
41
- * ref or snapshot id) so the intent is explicit at the call site. */
42
- bootFrom?: BootSnapshot;
45
+ /** Where the runner restores from at run start:
46
+ * - `{ snapshotId }` — a specific captured snapshot.
47
+ * - `"reuse"` — this workflow's own latest snapshot (content-hash scoped);
48
+ * fresh on the first run / after a re-register. Implies `saveLatest`.
49
+ * - omitted — a fresh base sandbox. */
50
+ bootFrom?: BootSnapshot | ReuseSnapshot;
43
51
  /** Capture the sandbox state on terminal success. The latest pointer
44
52
  * on `workflow_runs.vercel_snapshot_id` always tracks the most
45
53
  * recent capture; without `retainSteps`, prior captures are deleted
@@ -26,8 +26,8 @@ export type { WorkflowMetadata } from "./workflow-metadata.js";
26
26
  export interface AgentEventSink {
27
27
  emit(event: AgentLifecycleEvent): void | Promise<void>;
28
28
  }
29
- import type { WorkflowMemoryConfig, SnapshotConfig, BootSnapshot, IOSchema, OutputSchema } from "./workflow-metadata.js";
30
- export type { WorkflowMemoryConfig, SnapshotConfig, BootSnapshot, IOSchema, OutputSchema };
29
+ import type { WorkflowMemoryConfig, SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema } from "./workflow-metadata.js";
30
+ export type { WorkflowMemoryConfig, SnapshotConfig, BootSnapshot, ReuseSnapshot, IOSchema, OutputSchema };
31
31
  /** Turn/iteration budget for `agent(opts)`. Re-exported here so authors
32
32
  * can type per-invoke budget overrides they pass as workflow input. */
33
33
  export interface AgentBudget {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-compose/sdk",
3
- "version": "0.5.2",
3
+ "version": "0.5.6",
4
4
  "description": "Client library for agent-compose — define agents, runtimes, and workflows, and invoke them against an agent-compose server.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -38,6 +38,7 @@ export type {
38
38
  WorkflowHooks,
39
39
  SnapshotConfig,
40
40
  BootSnapshot,
41
+ ReuseSnapshot,
41
42
  IOSchema,
42
43
  OutputSchema,
43
44
  WorkflowMemoryConfig,
@@ -120,6 +121,7 @@ export type {
120
121
  RequestAgentPauseOptions, RequestAgentPauseResponse,
121
122
  SendAgentMessageOptions, SendAgentMessageResponse,
122
123
  AnswerSteerOptions,
124
+ ResumePauseOptions, ResumePauseResponse, ResumePauseSuccess, ResumePausePending, ResumePauseActor,
123
125
  } from "./client.js";
124
126
 
125
127
  // SSE parser — exposed so tests and downstream callers can reuse it.
@@ -147,8 +149,25 @@ export { AgentStatusSchema } from "./utils/schemas.js";
147
149
  export { createClaudeRuntime, ClaudeRunner } from "./runtimes/claude.js";
148
150
  export type { ClaudeRuntimeConfig } from "./runtimes/claude.js";
149
151
  export { default as claudeRuntime } from "./runtimes/claude.js";
150
- export { createVercelRuntime, VercelRunner } from "./runtimes/vercel.js";
151
- export type { VercelRuntimeConfig } from "./runtimes/vercel.js";
152
+ export { createVercelRuntime, VercelRunner, listVercelRuntimeModels } from "./runtimes/vercel.js";
153
+ export type { VercelRuntimeConfig, VercelRuntimeModel } from "./runtimes/vercel.js";
154
+ // There is no per-provider runtime — the model is a parameter, not a runtime.
155
+ // `createVercelRuntime({ model })` drives any provider: pass a gateway model-id
156
+ // string ("openai/gpt-5", "google/gemini-2.5-pro", "anthropic/claude-…") or a
157
+ // LanguageModel object from any @ai-sdk/<provider> package. To DISCOVER which
158
+ // gateway models are available, call `listVercelRuntimeModels()` (live catalog)
159
+ // or browse https://vercel.com/ai-gateway/models. `GatewayModelId` is the
160
+ // string-form model-id type. See docs/custom-runtimes.md.
161
+ export type { GatewayModelId } from "ai";
162
+ // CLI-agent runtimes — drive an external agentic CLI (codex / amp) inside the
163
+ // sandbox and stream-parse its JSONL. No heavy npm deps (the CLI lives in the
164
+ // sandbox image), so these are root-exported like claudeRuntime.
165
+ export { createCodexRuntime } from "./runtimes/codex.js";
166
+ export type { CodexRuntimeConfig } from "./runtimes/codex.js";
167
+ export { default as codexRuntime } from "./runtimes/codex.js";
168
+ export { createAmpRuntime } from "./runtimes/amp.js";
169
+ export type { AmpRuntimeConfig } from "./runtimes/amp.js";
170
+ export { default as ampRuntime } from "./runtimes/amp.js";
152
171
 
153
172
  // Built-in coding tools for Vercel AI SDK runtime.
154
173
  export { bashTool, codingTools, editTool, readTool, writeTool } from "./tools/index.js";