@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.
- package/dist/index.d.ts +11 -4
- package/dist/index.js +267 -1
- package/dist/runtimes/_cli-agent.d.ts +89 -0
- package/dist/runtimes/amp.d.ts +23 -0
- package/dist/runtimes/cli-agent.test.d.ts +9 -0
- package/dist/runtimes/codex.d.ts +21 -0
- package/dist/runtimes/openai-desktop.js +262 -1
- package/dist/runtimes/vercel.d.ts +41 -1
- package/dist/runtimes/vercel.js +10 -1
- package/dist/types/workflow-metadata.d.ts +19 -11
- package/dist/types/workflow.d.ts +2 -2
- package/package.json +1 -1
- package/src/index.ts +21 -2
- package/src/runtimes/_cli-agent.ts +194 -0
- package/src/runtimes/amp.ts +99 -0
- package/src/runtimes/codex.ts +114 -0
- package/src/runtimes/vercel.ts +52 -2
- package/src/types/workflow-metadata.ts +20 -11
- package/src/types/workflow.ts +2 -2
|
@@ -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
|
-
/**
|
|
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[]>;
|
package/dist/runtimes/vercel.js
CHANGED
|
@@ -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
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
|
41
|
-
*
|
|
42
|
-
|
|
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
|
package/dist/types/workflow.d.ts
CHANGED
|
@@ -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
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";
|