@agent-compose/sdk 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent-loop.d.ts +8 -0
- package/dist/agent/run-agent.d.ts +4 -0
- package/dist/client.d.ts +50 -6
- package/dist/display.d.ts +16 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +256 -39
- package/dist/runtimes/_cli-agent.d.ts +9 -7
- package/dist/runtimes/claude-code.d.ts +10 -8
- package/dist/runtimes/codex.d.ts +4 -1
- package/dist/runtimes/openai-desktop.js +249 -38
- package/dist/types/api-conversations.d.ts +31 -0
- package/dist/types/api-factory.d.ts +25 -0
- package/dist/types/api-runs.d.ts +46 -1
- package/dist/types/protocol.d.ts +8 -0
- package/dist/types/workflow-metadata.d.ts +8 -0
- package/dist/utils/bundler.d.ts +56 -0
- package/dist/workflow-steps/workflow.d.ts +7 -0
- package/dist/workflows/invoke-child.d.ts +18 -0
- package/dist/workflows/invoke-child.test.d.ts +9 -0
- package/package.json +2 -2
- package/src/agent/agent-loop.ts +9 -0
- package/src/agent/run-agent.ts +5 -0
- package/src/client.ts +145 -10
- package/src/display.ts +61 -15
- package/src/index.ts +11 -3
- package/src/runtimes/_cli-agent.ts +9 -7
- package/src/runtimes/claude-code.ts +25 -15
- package/src/runtimes/codex.ts +11 -3
- package/src/types/api-conversations.ts +25 -0
- package/src/types/api-factory.ts +32 -0
- package/src/types/api-runs.ts +48 -1
- package/src/types/protocol.ts +8 -0
- package/src/types/workflow-metadata.ts +9 -0
- package/src/utils/bundler.ts +213 -3
- package/src/workflow-steps/workflow.ts +7 -0
- package/src/workflows/invoke-child.ts +47 -11
|
@@ -959,6 +959,8 @@ function extractMetadata(source) {
|
|
|
959
959
|
out.invokePolicy = freezeMetadataValue(source.invokePolicy);
|
|
960
960
|
if (source.environmentBuild !== undefined)
|
|
961
961
|
out.environmentBuild = source.environmentBuild;
|
|
962
|
+
if (source.factoryDrive !== undefined)
|
|
963
|
+
out.factoryDrive = source.factoryDrive;
|
|
962
964
|
return Object.freeze(out);
|
|
963
965
|
}
|
|
964
966
|
function freezeMetadataValue(value) {
|
|
@@ -1446,14 +1448,47 @@ class AgentComposeClient {
|
|
|
1446
1448
|
...opts?.placeholders !== undefined ? { placeholders: opts.placeholders } : {},
|
|
1447
1449
|
...opts?.size !== undefined ? { size: opts.size } : {},
|
|
1448
1450
|
...parentRunId ? { parentRunId } : {},
|
|
1449
|
-
...opts?.agentId ? { agentId: opts.agentId } : {}
|
|
1451
|
+
...opts?.agentId ? { agentId: opts.agentId } : {},
|
|
1452
|
+
...opts?.funding !== undefined ? { funding: opts.funding } : {},
|
|
1453
|
+
...opts?.fundingSecret !== undefined ? { fundingSecret: opts.fundingSecret } : {}
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
invokeInline(workflow, input, opts) {
|
|
1458
|
+
const parentRunId = opts?.parentRunId === undefined ? detectAmbientParentRunId() : opts.parentRunId;
|
|
1459
|
+
const factorySlug = opts?.factorySlug ?? DEFAULT_FACTORY;
|
|
1460
|
+
const headers = {};
|
|
1461
|
+
if (opts?.idempotencyKey)
|
|
1462
|
+
headers["Idempotency-Key"] = opts.idempotencyKey;
|
|
1463
|
+
return this.fetch(`/api/v1/factories/${encodeURIComponent(factorySlug)}/invoke`, {
|
|
1464
|
+
method: "POST",
|
|
1465
|
+
...opts?.idempotencyKey ? { headers } : {},
|
|
1466
|
+
body: {
|
|
1467
|
+
workflow,
|
|
1468
|
+
input,
|
|
1469
|
+
...opts?.title !== undefined ? { title: opts.title } : {},
|
|
1470
|
+
...opts?.snapshots !== undefined ? { snapshots: opts.snapshots } : {},
|
|
1471
|
+
...opts?.networkPolicy !== undefined ? { networkPolicy: opts.networkPolicy } : {},
|
|
1472
|
+
...opts?.placeholders !== undefined ? { placeholders: opts.placeholders } : {},
|
|
1473
|
+
...opts?.size !== undefined ? { size: opts.size } : {},
|
|
1474
|
+
...parentRunId ? { parentRunId } : {},
|
|
1475
|
+
...opts?.agentId ? { agentId: opts.agentId } : {},
|
|
1476
|
+
...opts?.funding !== undefined ? { funding: opts.funding } : {},
|
|
1477
|
+
...opts?.fundingSecret !== undefined ? { fundingSecret: opts.fundingSecret } : {}
|
|
1450
1478
|
}
|
|
1451
1479
|
});
|
|
1452
1480
|
}
|
|
1453
1481
|
async invokeAndWait(name, input, opts) {
|
|
1482
|
+
const { id: runId } = await this.invoke(name, input, opts);
|
|
1483
|
+
return this.waitForRun(runId, opts);
|
|
1484
|
+
}
|
|
1485
|
+
async invokeInlineAndWait(workflow, input, opts) {
|
|
1486
|
+
const { id: runId } = await this.invokeInline(workflow, input, opts);
|
|
1487
|
+
return this.waitForRun(runId, opts);
|
|
1488
|
+
}
|
|
1489
|
+
async waitForRun(runId, opts) {
|
|
1454
1490
|
const timeoutMs = opts?.timeoutMs ?? 30 * 60 * 1000;
|
|
1455
1491
|
const pollMs = opts?.pollIntervalMs ?? 1000;
|
|
1456
|
-
const { id: runId } = await this.invoke(name, input, opts);
|
|
1457
1492
|
const deadline = Date.now() + timeoutMs;
|
|
1458
1493
|
while (Date.now() < deadline) {
|
|
1459
1494
|
const status = await this.getStatus(runId);
|
|
@@ -1462,7 +1497,7 @@ class AgentComposeClient {
|
|
|
1462
1497
|
}
|
|
1463
1498
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
1464
1499
|
}
|
|
1465
|
-
throw new AgentComposeError(504, `
|
|
1500
|
+
throw new AgentComposeError(504, `waitForRun: run ${runId} did not settle within ${timeoutMs}ms`);
|
|
1466
1501
|
}
|
|
1467
1502
|
async listSnapshots(opts) {
|
|
1468
1503
|
const body = await this.listSnapshotsPage(opts);
|
|
@@ -1598,6 +1633,11 @@ class AgentComposeClient {
|
|
|
1598
1633
|
preview: a.preview
|
|
1599
1634
|
}));
|
|
1600
1635
|
}
|
|
1636
|
+
async getRunArtifactBytes(runId, path) {
|
|
1637
|
+
const q2 = new URLSearchParams({ path });
|
|
1638
|
+
const buf = await this.fetch(`/api/v1/workflows/${encodeURIComponent(runId)}/artifacts/content?${q2}`, { responseType: "arrayBuffer" });
|
|
1639
|
+
return new Uint8Array(buf);
|
|
1640
|
+
}
|
|
1601
1641
|
async putFactoryFile(path, content, opts) {
|
|
1602
1642
|
const factorySlug = opts?.factorySlug ?? (typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_FACTORY : undefined) ?? DEFAULT_FACTORY;
|
|
1603
1643
|
const runToken = typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_RUN_TOKEN : undefined;
|
|
@@ -1621,12 +1661,28 @@ class AgentComposeClient {
|
|
|
1621
1661
|
const q2 = new URLSearchParams({ path });
|
|
1622
1662
|
if (opts?.revision !== undefined)
|
|
1623
1663
|
q2.set("revision", String(opts.revision));
|
|
1664
|
+
if (opts?.branch !== undefined)
|
|
1665
|
+
q2.set("branch", opts.branch);
|
|
1624
1666
|
const buf = await this.fetch(`/api/v1/factories/${encodeURIComponent(factorySlug)}/files/content?${q2}`, { responseType: "arrayBuffer" });
|
|
1625
1667
|
return new Uint8Array(buf);
|
|
1626
1668
|
}
|
|
1627
1669
|
async getFactoryFile(path, opts) {
|
|
1628
1670
|
return new TextDecoder().decode(await this.getFactoryFileBytes(path, opts));
|
|
1629
1671
|
}
|
|
1672
|
+
async createDriveMountSession(opts) {
|
|
1673
|
+
const factorySlug = opts?.factorySlug ?? (typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_FACTORY : undefined) ?? DEFAULT_FACTORY;
|
|
1674
|
+
return this.fetch(`/api/v1/factories/${encodeURIComponent(factorySlug)}/files/mount-sessions`, {
|
|
1675
|
+
method: "POST",
|
|
1676
|
+
body: {
|
|
1677
|
+
...opts?.conversationId ? { conversationId: opts.conversationId } : {},
|
|
1678
|
+
...opts?.host ? { host: opts.host } : {}
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
async releaseDriveMountSession(conversationId, opts) {
|
|
1683
|
+
const factorySlug = opts?.factorySlug ?? (typeof process !== "undefined" ? process.env?.AGENT_COMPOSE_FACTORY : undefined) ?? DEFAULT_FACTORY;
|
|
1684
|
+
return this.fetch(`/api/v1/factories/${encodeURIComponent(factorySlug)}/files/mount-sessions/${encodeURIComponent(conversationId)}/release`, { method: "POST", body: {} });
|
|
1685
|
+
}
|
|
1630
1686
|
listConversations(opts) {
|
|
1631
1687
|
const q2 = new URLSearchParams;
|
|
1632
1688
|
if (opts?.cursor)
|
|
@@ -1639,8 +1695,9 @@ class AgentComposeClient {
|
|
|
1639
1695
|
q2.set("cursor", opts.cursor);
|
|
1640
1696
|
return this.fetch(`/api/v1/sessions?${q2}`);
|
|
1641
1697
|
}
|
|
1642
|
-
getConversation(id) {
|
|
1643
|
-
|
|
1698
|
+
getConversation(id, opts) {
|
|
1699
|
+
const q2 = opts?.limit !== undefined ? `?limit=${opts.limit}` : "";
|
|
1700
|
+
return this.fetch(`/api/v1/conversations/${encodeURIComponent(id)}${q2}`);
|
|
1644
1701
|
}
|
|
1645
1702
|
createCloudSession(input) {
|
|
1646
1703
|
return this.fetch(`/api/v1/sessions/cloud`, {
|
|
@@ -1658,7 +1715,10 @@ class AgentComposeClient {
|
|
|
1658
1715
|
...input.templateId ? { templateId: input.templateId } : {},
|
|
1659
1716
|
...input.sandboxSize ? { sandboxSize: input.sandboxSize } : {},
|
|
1660
1717
|
...input.networkPolicy !== undefined ? { networkPolicy: input.networkPolicy } : {},
|
|
1661
|
-
...input.connectorProfileId !== undefined ? { connectorProfileId: input.connectorProfileId } : {}
|
|
1718
|
+
...input.connectorProfileId !== undefined ? { connectorProfileId: input.connectorProfileId } : {},
|
|
1719
|
+
...input.setupCommand !== undefined ? { setupCommand: input.setupCommand } : {},
|
|
1720
|
+
...input.handoffOrigin !== undefined ? { handoffOrigin: input.handoffOrigin } : {},
|
|
1721
|
+
...input.seedFiles !== undefined ? { seedFiles: input.seedFiles } : {}
|
|
1662
1722
|
}
|
|
1663
1723
|
});
|
|
1664
1724
|
}
|
|
@@ -2466,6 +2526,7 @@ class AcpClientPeer {
|
|
|
2466
2526
|
}
|
|
2467
2527
|
// src/utils/bundler.ts
|
|
2468
2528
|
import { createHash as createHash2 } from "node:crypto";
|
|
2529
|
+
import { dirname as dirname2 } from "node:path";
|
|
2469
2530
|
import { parse as babelParse } from "@babel/parser";
|
|
2470
2531
|
|
|
2471
2532
|
// src/utils/source-loader.ts
|
|
@@ -2495,15 +2556,119 @@ class WorkflowSourceValidationError extends Error {
|
|
|
2495
2556
|
this.name = "WorkflowSourceValidationError";
|
|
2496
2557
|
}
|
|
2497
2558
|
}
|
|
2559
|
+
var SDK_PACKAGE = "@agent-compose/sdk";
|
|
2560
|
+
var SDK_SPECIFIER_ALIASES = [
|
|
2561
|
+
"agentc/sdk",
|
|
2562
|
+
"@agentc/sdk",
|
|
2563
|
+
"agentc-sdk",
|
|
2564
|
+
"agent-compose/sdk",
|
|
2565
|
+
"agentcompose/sdk",
|
|
2566
|
+
"@agentcompose/sdk",
|
|
2567
|
+
"agent-compose-sdk"
|
|
2568
|
+
];
|
|
2569
|
+
var SDK_ALIAS_SET = new Set(SDK_SPECIFIER_ALIASES);
|
|
2570
|
+
function resolveSdkAlias(specifier) {
|
|
2571
|
+
return SDK_ALIAS_SET.has(specifier) ? SDK_PACKAGE : null;
|
|
2572
|
+
}
|
|
2573
|
+
function aliasFilter() {
|
|
2574
|
+
const alternation = SDK_SPECIFIER_ALIASES.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2575
|
+
return new RegExp(`^(?:${alternation})$`);
|
|
2576
|
+
}
|
|
2577
|
+
function sdkAliasPlugin(bun) {
|
|
2578
|
+
return {
|
|
2579
|
+
name: "agent-compose-sdk-alias",
|
|
2580
|
+
setup(build) {
|
|
2581
|
+
build.onResolve({ filter: aliasFilter() }, (args) => {
|
|
2582
|
+
const target = resolveSdkAlias(args.path);
|
|
2583
|
+
if (!target)
|
|
2584
|
+
return;
|
|
2585
|
+
const from = args.importer ? dirname2(args.importer) : args.resolveDir;
|
|
2586
|
+
try {
|
|
2587
|
+
return { path: bun.resolveSync(target, from && from.length > 0 ? from : process.cwd()) };
|
|
2588
|
+
} catch {
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
function readUnresolvedSpecifier(diag) {
|
|
2596
|
+
if (!diag || typeof diag !== "object")
|
|
2597
|
+
return null;
|
|
2598
|
+
const d = diag;
|
|
2599
|
+
if (typeof d.specifier === "string" && d.specifier.length > 0)
|
|
2600
|
+
return d.specifier;
|
|
2601
|
+
const message = typeof d.message === "string" ? d.message : "";
|
|
2602
|
+
const m = /Could not resolve:?\s*"([^"]+)"/.exec(message);
|
|
2603
|
+
return m ? m[1] : null;
|
|
2604
|
+
}
|
|
2605
|
+
function flattenDiagnostics(failure) {
|
|
2606
|
+
const out = [];
|
|
2607
|
+
const seen = new Set;
|
|
2608
|
+
const walk = (node, depth) => {
|
|
2609
|
+
if (!node || depth > 4 || seen.has(node))
|
|
2610
|
+
return;
|
|
2611
|
+
seen.add(node);
|
|
2612
|
+
if (Array.isArray(node)) {
|
|
2613
|
+
for (const sub of node)
|
|
2614
|
+
walk(sub, depth + 1);
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2617
|
+
out.push(node);
|
|
2618
|
+
if (typeof node === "object") {
|
|
2619
|
+
const n = node;
|
|
2620
|
+
if (Array.isArray(n.errors))
|
|
2621
|
+
for (const sub of n.errors)
|
|
2622
|
+
walk(sub, depth + 1);
|
|
2623
|
+
if (n.cause)
|
|
2624
|
+
walk(n.cause, depth + 1);
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
walk(failure, 0);
|
|
2628
|
+
return out;
|
|
2629
|
+
}
|
|
2630
|
+
function diagnosticText(diag) {
|
|
2631
|
+
if (diag instanceof Error)
|
|
2632
|
+
return diag.message || String(diag);
|
|
2633
|
+
if (diag && typeof diag === "object" && typeof diag.message === "string") {
|
|
2634
|
+
return diag.message;
|
|
2635
|
+
}
|
|
2636
|
+
return String(diag);
|
|
2637
|
+
}
|
|
2638
|
+
function explainBundleFailure(err, label) {
|
|
2639
|
+
const diagnostics = flattenDiagnostics(err);
|
|
2640
|
+
const unresolved = [];
|
|
2641
|
+
for (const diag of diagnostics) {
|
|
2642
|
+
const specifier = readUnresolvedSpecifier(diag);
|
|
2643
|
+
if (specifier && !unresolved.includes(specifier))
|
|
2644
|
+
unresolved.push(specifier);
|
|
2645
|
+
}
|
|
2646
|
+
if (unresolved.length > 0) {
|
|
2647
|
+
const quoted = unresolved.map((s) => `"${s}"`).join(", ");
|
|
2648
|
+
return `Could not resolve ${quoted} — workflow source imports the platform SDK as "${SDK_PACKAGE}". ` + `Fix the import specifier in ${label}; anything that is genuinely a third-party ` + `package must be installed where the source is bundled.`;
|
|
2649
|
+
}
|
|
2650
|
+
const detail = diagnostics.map(diagnosticText).filter((t) => t.length > 0 && t !== "Bundle failed").join(`
|
|
2651
|
+
`);
|
|
2652
|
+
return `Failed to bundle ${label}:
|
|
2653
|
+
${detail || "the bundler reported no diagnostics"}`;
|
|
2654
|
+
}
|
|
2498
2655
|
async function bundle(path, label) {
|
|
2499
2656
|
const bun = globalThis;
|
|
2500
2657
|
if (!bun.Bun?.build)
|
|
2501
2658
|
throw new Error("bundleWorkflow requires the Bun runtime (Bun.build)");
|
|
2502
|
-
|
|
2659
|
+
let result;
|
|
2660
|
+
try {
|
|
2661
|
+
result = await bun.Bun.build({
|
|
2662
|
+
entrypoints: [path],
|
|
2663
|
+
format: "esm",
|
|
2664
|
+
target: "node",
|
|
2665
|
+
plugins: [sdkAliasPlugin(bun.Bun)]
|
|
2666
|
+
});
|
|
2667
|
+
} catch (err) {
|
|
2668
|
+
throw new WorkflowSourceValidationError(explainBundleFailure(err, label));
|
|
2669
|
+
}
|
|
2503
2670
|
if (!result.success) {
|
|
2504
|
-
throw new
|
|
2505
|
-
${result.logs.map((l) => l.message).join(`
|
|
2506
|
-
`)}`);
|
|
2671
|
+
throw new WorkflowSourceValidationError(explainBundleFailure(result.logs, label));
|
|
2507
2672
|
}
|
|
2508
2673
|
return result.outputs[0].text();
|
|
2509
2674
|
}
|
|
@@ -2621,7 +2786,8 @@ async function bundleWorkflow(workflowPath, overrides) {
|
|
|
2621
2786
|
...metadata.connectors !== undefined ? { connectors: metadata.connectors } : {},
|
|
2622
2787
|
...metadata.connectorOperation !== undefined ? { connectorOperation: metadata.connectorOperation } : {},
|
|
2623
2788
|
...metadata.invokePolicy !== undefined ? { invokePolicy: metadata.invokePolicy } : {},
|
|
2624
|
-
...metadata.environmentBuild !== undefined ? { environmentBuild: metadata.environmentBuild } : {}
|
|
2789
|
+
...metadata.environmentBuild !== undefined ? { environmentBuild: metadata.environmentBuild } : {},
|
|
2790
|
+
...metadata.factoryDrive !== undefined ? { factoryDrive: metadata.factoryDrive } : {}
|
|
2625
2791
|
};
|
|
2626
2792
|
}
|
|
2627
2793
|
function extractIOSchema(zodSchema) {
|
|
@@ -3019,7 +3185,8 @@ async function agentLoop(opts) {
|
|
|
3019
3185
|
label,
|
|
3020
3186
|
allowedTools: opts.allowedTools ?? DEFAULT_ALLOWED_TOOLS,
|
|
3021
3187
|
...client.model != null ? { model: client.model } : {},
|
|
3022
|
-
...client.kind != null ? { runtimeKind: client.kind } : {}
|
|
3188
|
+
...client.kind != null ? { runtimeKind: client.kind } : {},
|
|
3189
|
+
...opts.phase != null ? { phase: opts.phase } : {}
|
|
3023
3190
|
});
|
|
3024
3191
|
}
|
|
3025
3192
|
const flushState = async (currentIteration) => {
|
|
@@ -3986,7 +4153,7 @@ var codexSpec = {
|
|
|
3986
4153
|
"--skip-git-repo-check",
|
|
3987
4154
|
"--dangerously-bypass-approvals-and-sandbox",
|
|
3988
4155
|
...model ? ["-m", shellQuote(model)] : [],
|
|
3989
|
-
...effort ? ["-c", `model_reasoning_effort=${effort}`] : [],
|
|
4156
|
+
...effort ? ["-c", `model_reasoning_effort=${effort === "max" ? "xhigh" : effort}`] : [],
|
|
3990
4157
|
...cwd ? ["-C", shellQuote(cwd)] : []
|
|
3991
4158
|
].join(" ");
|
|
3992
4159
|
const exec = sessionId ? `codex exec resume ${shellQuote(sessionId)} ${flags}` : `codex exec ${flags}`;
|
|
@@ -4208,7 +4375,7 @@ function toolResultText(content) {
|
|
|
4208
4375
|
}
|
|
4209
4376
|
return content == null ? "" : JSON.stringify(content) ?? "";
|
|
4210
4377
|
}
|
|
4211
|
-
var
|
|
4378
|
+
var CLAUDE_CODE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
4212
4379
|
var claudeCodeSpec = {
|
|
4213
4380
|
kind: "claude-code",
|
|
4214
4381
|
authEnv: "ANTHROPIC_API_KEY",
|
|
@@ -4224,14 +4391,15 @@ var claudeCodeSpec = {
|
|
|
4224
4391
|
"--include-partial-messages",
|
|
4225
4392
|
"--dangerously-skip-permissions",
|
|
4226
4393
|
...model ? [`--model ${shellQuote(model)}`] : [],
|
|
4394
|
+
...effort ? [`--effort ${effort}`] : [],
|
|
4227
4395
|
...sessionId ? [`--resume ${shellQuote(sessionId)}`] : []
|
|
4228
4396
|
].join(" ");
|
|
4229
|
-
|
|
4230
|
-
return `${cwd ? `cd ${shellQuote(cwd)} && ` : ""}${thinking}IS_SANDBOX=1 claude ${flags} < ${shellQuote(promptPath)}`;
|
|
4397
|
+
return `${cwd ? `cd ${shellQuote(cwd)} && ` : ""}IS_SANDBOX=1 claude ${flags} < ${shellQuote(promptPath)}`;
|
|
4231
4398
|
},
|
|
4232
4399
|
extractSessionId: (p) => typeof p.session_id === "string" ? p.session_id : undefined,
|
|
4233
4400
|
mapEvent: (p) => {
|
|
4234
4401
|
const ts = now10();
|
|
4402
|
+
const parent = typeof p.parent_tool_use_id === "string" && p.parent_tool_use_id.length > 0 ? { parentToolUseId: p.parent_tool_use_id } : {};
|
|
4235
4403
|
switch (p.type) {
|
|
4236
4404
|
case "assistant": {
|
|
4237
4405
|
const message = p.message;
|
|
@@ -4249,6 +4417,7 @@ var claudeCodeSpec = {
|
|
|
4249
4417
|
toolName: String(b.name ?? "tool"),
|
|
4250
4418
|
toolInput: b.input ?? {},
|
|
4251
4419
|
toolUseId: String(b.id ?? ""),
|
|
4420
|
+
...parent,
|
|
4252
4421
|
timestamp: ts
|
|
4253
4422
|
}];
|
|
4254
4423
|
}
|
|
@@ -4263,6 +4432,7 @@ var claudeCodeSpec = {
|
|
|
4263
4432
|
toolUseId: String(b.tool_use_id ?? ""),
|
|
4264
4433
|
output: toolResultText(b.content),
|
|
4265
4434
|
isError: b.is_error === true,
|
|
4435
|
+
...parent,
|
|
4266
4436
|
timestamp: ts
|
|
4267
4437
|
}] : []);
|
|
4268
4438
|
}
|
|
@@ -4892,7 +5062,7 @@ var vercelProviderDef = {
|
|
|
4892
5062
|
|
|
4893
5063
|
// src/sandbox/providers/local.ts
|
|
4894
5064
|
import { promises as fs2 } from "node:fs";
|
|
4895
|
-
import { dirname as
|
|
5065
|
+
import { dirname as dirname3 } from "node:path";
|
|
4896
5066
|
import { spawn } from "node:child_process";
|
|
4897
5067
|
import { Readable, Writable } from "node:stream";
|
|
4898
5068
|
function makeLocalSandboxProvider() {
|
|
@@ -4958,7 +5128,7 @@ function makeLocalSandboxProvider() {
|
|
|
4958
5128
|
},
|
|
4959
5129
|
files: {
|
|
4960
5130
|
async write(path, content) {
|
|
4961
|
-
await fs2.mkdir(
|
|
5131
|
+
await fs2.mkdir(dirname3(path), { recursive: true });
|
|
4962
5132
|
await fs2.writeFile(path, content);
|
|
4963
5133
|
},
|
|
4964
5134
|
async read(path) {
|
|
@@ -5509,6 +5679,15 @@ async function runWorkflow(wf, ctx, opts) {
|
|
|
5509
5679
|
}
|
|
5510
5680
|
}
|
|
5511
5681
|
// src/workflows/invoke-child.ts
|
|
5682
|
+
function deriveInvokeChildIdempotencyKey(parentRunId, childName) {
|
|
5683
|
+
const step = getActiveStep();
|
|
5684
|
+
if (!step)
|
|
5685
|
+
return null;
|
|
5686
|
+
const ordinal = nextPauseOrdinalInActiveStep(`invoke-child:${childName}`);
|
|
5687
|
+
if (ordinal === null)
|
|
5688
|
+
return null;
|
|
5689
|
+
return `invoke-child:${parentRunId}:step${step.stepIndex}:${childName}:${ordinal}`;
|
|
5690
|
+
}
|
|
5512
5691
|
function buildInvokeChild(runId, opts = {}) {
|
|
5513
5692
|
let childClient = null;
|
|
5514
5693
|
const getChildClient = () => {
|
|
@@ -5522,11 +5701,15 @@ function buildInvokeChild(runId, opts = {}) {
|
|
|
5522
5701
|
childClient = new AgentComposeClient({ apiKey, baseUrl });
|
|
5523
5702
|
return childClient;
|
|
5524
5703
|
};
|
|
5525
|
-
return (name, input, childOpts) =>
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5704
|
+
return (name, input, childOpts) => {
|
|
5705
|
+
const idempotencyKey = childOpts?.idempotencyKey ?? deriveInvokeChildIdempotencyKey(runId, name) ?? undefined;
|
|
5706
|
+
return getChildClient().invokeAndWait(name, input, {
|
|
5707
|
+
...childOpts,
|
|
5708
|
+
...idempotencyKey !== undefined ? { idempotencyKey } : {},
|
|
5709
|
+
parentRunId: runId,
|
|
5710
|
+
factorySlug: childOpts?.factorySlug ?? opts.defaultFactorySlug ?? process.env.AGENT_COMPOSE_FACTORY ?? process.env.AGENT_COMPOSE_FACTORY_SLUG ?? "default"
|
|
5711
|
+
});
|
|
5712
|
+
};
|
|
5530
5713
|
}
|
|
5531
5714
|
// src/workflow-steps/step.ts
|
|
5532
5715
|
var CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
|
|
@@ -6599,6 +6782,7 @@ async function agent(opts) {
|
|
|
6599
6782
|
runtime: (runtimeOpts) => opts.runtime.create(opts.sandbox, { ...runtimeOpts, agentManual: buildAgentContextDoc(process.env) }),
|
|
6600
6783
|
agentId,
|
|
6601
6784
|
...opts.label !== undefined ? { label: opts.label } : {},
|
|
6785
|
+
...opts.phase !== undefined ? { phase: opts.phase } : {},
|
|
6602
6786
|
...opts.budget?.turnsPerIteration !== undefined ? { turnsPerIteration: opts.budget.turnsPerIteration } : {},
|
|
6603
6787
|
...opts.budget?.maxIterations !== undefined ? { maxIterations: opts.budget.maxIterations } : {},
|
|
6604
6788
|
...opts.tools !== undefined ? { allowedTools: opts.tools } : {},
|
|
@@ -6669,7 +6853,21 @@ function clampPlanEntries(raw) {
|
|
|
6669
6853
|
var TABLE_MAX_COLUMNS = 12;
|
|
6670
6854
|
var TABLE_MAX_ROWS = 100;
|
|
6671
6855
|
var TABLE_CELL_MAX_CHARS = 200;
|
|
6672
|
-
var
|
|
6856
|
+
var DRIVE_PATH_MAX_CHARS = 512;
|
|
6857
|
+
function isPlausibleDrivePath(raw) {
|
|
6858
|
+
if (raw.trim().length === 0 || raw.length > DRIVE_PATH_MAX_CHARS)
|
|
6859
|
+
return false;
|
|
6860
|
+
if (raw.startsWith("-"))
|
|
6861
|
+
return false;
|
|
6862
|
+
if (/[\u0000-\u001f\u007f\\]/.test(raw))
|
|
6863
|
+
return false;
|
|
6864
|
+
if (/[|<>;`]|\$\(/.test(raw))
|
|
6865
|
+
return false;
|
|
6866
|
+
const trimmed = raw.replace(/^\/+|\/+$/g, "");
|
|
6867
|
+
if (trimmed.length === 0)
|
|
6868
|
+
return false;
|
|
6869
|
+
return trimmed.split("/").every((seg) => seg !== "" && seg !== "." && seg !== "..");
|
|
6870
|
+
}
|
|
6673
6871
|
function clampCellString(s) {
|
|
6674
6872
|
return s.length > TABLE_CELL_MAX_CHARS ? `${s.slice(0, TABLE_CELL_MAX_CHARS - 1)}…` : s;
|
|
6675
6873
|
}
|
|
@@ -6860,7 +7058,7 @@ function parseDisplayMarker(line) {
|
|
|
6860
7058
|
}
|
|
6861
7059
|
case "document": {
|
|
6862
7060
|
const path = str("path");
|
|
6863
|
-
if (!path)
|
|
7061
|
+
if (!path || !isPlausibleDrivePath(path))
|
|
6864
7062
|
return null;
|
|
6865
7063
|
return {
|
|
6866
7064
|
kind: "document",
|
|
@@ -6875,7 +7073,7 @@ function parseDisplayMarker(line) {
|
|
|
6875
7073
|
}
|
|
6876
7074
|
case "image": {
|
|
6877
7075
|
const path = str("path");
|
|
6878
|
-
if (!path || path
|
|
7076
|
+
if (!path || !isPlausibleDrivePath(path))
|
|
6879
7077
|
return null;
|
|
6880
7078
|
return {
|
|
6881
7079
|
kind: "image",
|
|
@@ -7014,6 +7212,8 @@ function detectAgentcInvocation(command) {
|
|
|
7014
7212
|
const w = words[i];
|
|
7015
7213
|
if (SHELL_STOPPERS.has(w))
|
|
7016
7214
|
break;
|
|
7215
|
+
if (/^\d*>&\d+$/.test(w))
|
|
7216
|
+
continue;
|
|
7017
7217
|
if (w.startsWith("--")) {
|
|
7018
7218
|
if (VALUE_FLAGS.has(w) && i + 1 < words.length && !SHELL_STOPPERS.has(words[i + 1])) {
|
|
7019
7219
|
flags.set(w, words[i + 1]);
|
|
@@ -7026,6 +7226,7 @@ function detectAgentcInvocation(command) {
|
|
|
7026
7226
|
const factorySlug = flags.get("--factory");
|
|
7027
7227
|
const withSlug = factorySlug ? { factorySlug } : {};
|
|
7028
7228
|
const uuid = (v) => v && UUID_RE.test(v) ? v : null;
|
|
7229
|
+
const drivePath = (v) => v && isPlausibleDrivePath(v) ? v : null;
|
|
7029
7230
|
if (args[0] === "display") {
|
|
7030
7231
|
switch (args[1]) {
|
|
7031
7232
|
case "run": {
|
|
@@ -7036,19 +7237,27 @@ function detectAgentcInvocation(command) {
|
|
|
7036
7237
|
const runId = uuid(args[2]);
|
|
7037
7238
|
return runId ? { verb: "display-changes", runId, ...withSlug } : null;
|
|
7038
7239
|
}
|
|
7039
|
-
case "document":
|
|
7040
|
-
|
|
7240
|
+
case "document": {
|
|
7241
|
+
const path = drivePath(args[2]);
|
|
7242
|
+
return path ? { verb: "display-document", path, ...withSlug } : null;
|
|
7243
|
+
}
|
|
7041
7244
|
case "plan":
|
|
7042
7245
|
return { verb: "display-plan" };
|
|
7043
|
-
case "image":
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7246
|
+
case "image": {
|
|
7247
|
+
const path = drivePath(args[2]);
|
|
7248
|
+
return path ? { verb: "display-image", path, ...withSlug } : null;
|
|
7249
|
+
}
|
|
7250
|
+
case "preview": {
|
|
7251
|
+
const path = drivePath(args[2]);
|
|
7252
|
+
return path ? { verb: "display-preview", path } : null;
|
|
7253
|
+
}
|
|
7047
7254
|
case "table": {
|
|
7048
7255
|
const file = flags.get("--file");
|
|
7049
7256
|
const hasData = flags.has("--data");
|
|
7050
|
-
if (file && !hasData)
|
|
7051
|
-
|
|
7257
|
+
if (file && !hasData) {
|
|
7258
|
+
const path = drivePath(file);
|
|
7259
|
+
return path ? { verb: "display-table", source: "file", path } : null;
|
|
7260
|
+
}
|
|
7052
7261
|
if (hasData && !file)
|
|
7053
7262
|
return { verb: "display-table", source: "inline" };
|
|
7054
7263
|
return null;
|
|
@@ -7060,11 +7269,12 @@ function detectAgentcInvocation(command) {
|
|
|
7060
7269
|
case "diff": {
|
|
7061
7270
|
const from = flags.get("--from");
|
|
7062
7271
|
const to = flags.get("--to");
|
|
7063
|
-
|
|
7272
|
+
const path = drivePath(args[2]);
|
|
7273
|
+
if (!path || !from || !to)
|
|
7064
7274
|
return null;
|
|
7065
7275
|
if (!REVISION_SELECTOR_RE.test(from) || !REVISION_SELECTOR_RE.test(to))
|
|
7066
7276
|
return null;
|
|
7067
|
-
return { verb: "display-diff", path
|
|
7277
|
+
return { verb: "display-diff", path, from, to };
|
|
7068
7278
|
}
|
|
7069
7279
|
case "ask": {
|
|
7070
7280
|
const prompt = flags.get("--prompt");
|
|
@@ -7095,8 +7305,9 @@ function detectAgentcInvocation(command) {
|
|
|
7095
7305
|
const runId = uuid(args[2]);
|
|
7096
7306
|
return runId ? { verb: "run-get", runId } : null;
|
|
7097
7307
|
}
|
|
7098
|
-
if (args[0] === "files" && args[1] === "read"
|
|
7099
|
-
|
|
7308
|
+
if (args[0] === "files" && args[1] === "read") {
|
|
7309
|
+
const path = drivePath(args[2]);
|
|
7310
|
+
return path ? { verb: "files-read", path, ...withSlug } : null;
|
|
7100
7311
|
}
|
|
7101
7312
|
return null;
|
|
7102
7313
|
}
|
|
@@ -157,6 +157,16 @@ export interface ConversationDetail {
|
|
|
157
157
|
name: string;
|
|
158
158
|
description: string;
|
|
159
159
|
}> | null;
|
|
160
|
+
/** Where this conversation's UNMERGED work lives: a cloud session writes
|
|
161
|
+
* its own private drive branch, and every drive read a client makes for
|
|
162
|
+
* THAT factory must carry `?branch=` or it resolves against `main`,
|
|
163
|
+
* where session-born files do not exist. Non-null only for a session
|
|
164
|
+
* with a drive branch and a resolvable factory; null/absent = main
|
|
165
|
+
* only (read loosely — older servers omit it). */
|
|
166
|
+
sessionDrive?: {
|
|
167
|
+
factorySlug: string;
|
|
168
|
+
branch: string;
|
|
169
|
+
} | null;
|
|
160
170
|
viewerLastReadAt: string | null;
|
|
161
171
|
/** The caller's role in this conversation (ADR-0045) — drives client
|
|
162
172
|
* affordances only; the server remains the authority on every action.
|
|
@@ -226,6 +236,27 @@ export interface CreateCloudSessionInput {
|
|
|
226
236
|
* profile ids, or "none" for a bare session. Omitted = the owner's
|
|
227
237
|
* default profile. */
|
|
228
238
|
connectorProfileId?: string;
|
|
239
|
+
/** Idempotent dependency-setup command run by every fresh sandbox acquire
|
|
240
|
+
* after the drive mounts (`bun install`, `npm ci`, …). Strict charset —
|
|
241
|
+
* no shell metacharacters (400). Mutually exclusive with `templateId`
|
|
242
|
+
* (a snapshot carries its own installed state). */
|
|
243
|
+
setupCommand?: string;
|
|
244
|
+
/** Provenance of a session born by `agentc session import`: where the
|
|
245
|
+
* imported local session lived and which harness thread seeded it. */
|
|
246
|
+
handoffOrigin?: {
|
|
247
|
+
cwd: string;
|
|
248
|
+
sourceAcpSessionId: string | null;
|
|
249
|
+
agentKind: string;
|
|
250
|
+
mirrorConversationId: string | null;
|
|
251
|
+
};
|
|
252
|
+
/** Imported claude memories (session-import spec §memories): guest-home
|
|
253
|
+
* seeds re-applied on every fresh acquire. Paths under .claude/ only;
|
|
254
|
+
* strict base64; 256KB decoded total (server-capped). */
|
|
255
|
+
seedFiles?: Array<{
|
|
256
|
+
path: string;
|
|
257
|
+
contentB64: string;
|
|
258
|
+
mode: "write" | "append";
|
|
259
|
+
}>;
|
|
229
260
|
}
|
|
230
261
|
export interface CloudSessionCreated {
|
|
231
262
|
conversation: ConversationRow;
|
|
@@ -89,6 +89,11 @@ export interface RegisterWorkflowInput {
|
|
|
89
89
|
* server skips the /factory mount for its runs (#13). See
|
|
90
90
|
* `WorkflowMetadata.environmentBuild`. */
|
|
91
91
|
environmentBuild?: boolean;
|
|
92
|
+
/** Drive requirement declared via `defineWorkflow({ factoryDrive })`.
|
|
93
|
+
* Omitted ⇒ `"required"` on the server (a failed /factory mount fails
|
|
94
|
+
* the run); `"none"` = explicit no-drive opt-out. See
|
|
95
|
+
* `WorkflowMetadata.factoryDrive`. */
|
|
96
|
+
factoryDrive?: "required" | "none";
|
|
92
97
|
/** Factory slug. Defaults to `"default"`. */
|
|
93
98
|
factorySlug?: string;
|
|
94
99
|
}
|
|
@@ -181,6 +186,26 @@ export interface FactoryFileWriteResult {
|
|
|
181
186
|
sizeBytes: number;
|
|
182
187
|
created: boolean;
|
|
183
188
|
}
|
|
189
|
+
/** A minted local-mount grant: the user branch, the signed gateway token, and
|
|
190
|
+
* where to dial. The backing `conversationId` is the mount's review surface
|
|
191
|
+
* (its branch changes list + merge ride the session-changes routes). */
|
|
192
|
+
export interface DriveMountSession {
|
|
193
|
+
conversationId: string;
|
|
194
|
+
branch: string;
|
|
195
|
+
/** Signed gateway mount token (user principal, exclusive mode). Treat as a
|
|
196
|
+
* secret: write it to a 0600 token file, never argv/env of children. */
|
|
197
|
+
token: string;
|
|
198
|
+
gatewayWsUrl: string;
|
|
199
|
+
/** Token expiry, unix seconds — re-mint (same `conversationId`) before it. */
|
|
200
|
+
expiresAtS: number;
|
|
201
|
+
diskId: string;
|
|
202
|
+
}
|
|
203
|
+
export interface CreateDriveMountSessionInput {
|
|
204
|
+
/** Re-mint for an existing mount session (remount / token refresh). */
|
|
205
|
+
conversationId?: string;
|
|
206
|
+
/** The mounting machine's hostname — carried in the mount's title. */
|
|
207
|
+
host?: string;
|
|
208
|
+
}
|
|
184
209
|
/** A factory: a project-level grouping of workflows inside a team. */
|
|
185
210
|
export interface FactoryRow {
|
|
186
211
|
id: string;
|
package/dist/types/api-runs.d.ts
CHANGED
|
@@ -9,7 +9,18 @@
|
|
|
9
9
|
import type { SandboxNetworkPolicy, SandboxSize } from "../sandbox.js";
|
|
10
10
|
import type { SnapshotConfig } from "./workflow-metadata.js";
|
|
11
11
|
import type { RunContext } from "./api-scopes.js";
|
|
12
|
+
import type { BundledWorkflow } from "../utils/bundler.js";
|
|
12
13
|
export type RunState = "running" | "success" | "failed" | "abandoned" | "canceled";
|
|
14
|
+
/** INLINE invoke payload (`POST /factories/:slug/invoke`): everything
|
|
15
|
+
* `bundleWorkflow` produced — source, the REQUIRED manifest binding the
|
|
16
|
+
* bytes, the workflow plan, and the build fields — plus the name the run
|
|
17
|
+
* reports as its workflow. The server runs it through the same
|
|
18
|
+
* validate/build core as registration but writes NO registry row: the run
|
|
19
|
+
* snapshots the validated source (auditable, replayable) and the name
|
|
20
|
+
* stays free for real registrations. */
|
|
21
|
+
export type InlineWorkflowPayload = BundledWorkflow & {
|
|
22
|
+
name: string;
|
|
23
|
+
};
|
|
13
24
|
export interface InvokeWorkflowOptions {
|
|
14
25
|
/** Per-invocation snapshot config override. `snapshots.bootFrom`
|
|
15
26
|
* replaces the template's boot source; `snapshots.saveLatest` and
|
|
@@ -38,11 +49,45 @@ export interface InvokeWorkflowOptions {
|
|
|
38
49
|
* with the same key inside the server's dedup window returns the original
|
|
39
50
|
* run instead of starting a new one (matches `resumePause`'s pattern). */
|
|
40
51
|
idempotencyKey?: string;
|
|
41
|
-
|
|
52
|
+
/** Who pays for this run's model calls:
|
|
53
|
+
*
|
|
54
|
+
* - `"default"` (Auto) — the initiating human's connected subscription
|
|
55
|
+
* when one is enabled for workflows, else platform credits;
|
|
56
|
+
* - `"platform"` — always platform credits (metered);
|
|
57
|
+
* - `"subscription"` — REQUIRE the initiating human's plan. If it
|
|
58
|
+
* cannot be honored the invoke FAILS (412) rather than quietly
|
|
59
|
+
* spending credits;
|
|
60
|
+
* - `"byok"` — a factory secret named by `fundingSecret`, injected as
|
|
61
|
+
* the runtime's raw provider key. Never metered.
|
|
62
|
+
*
|
|
63
|
+
* Omitted → the workflow's own default (its `settings.funding`), else
|
|
64
|
+
* Auto. */
|
|
65
|
+
funding?: FundingChoice;
|
|
66
|
+
/** `funding: "byok"` only — the FACTORY SECRET NAME whose value funds the
|
|
67
|
+
* run. Must be a provider key variable (ANTHROPIC_API_KEY,
|
|
68
|
+
* OPENAI_API_KEY, CODEX_API_KEY, OPENROUTER_API_KEY) — that is where the
|
|
69
|
+
* sandbox's runtimes read it. The name only; the value never leaves the
|
|
70
|
+
* server's secret store. */
|
|
71
|
+
fundingSecret?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Inference-funding choice for a run — a lane the caller PINS, or
|
|
74
|
+
* `"default"` (Auto, the automatic ladder). Mirrors the same vocabulary
|
|
75
|
+
* cloud sessions use. */
|
|
76
|
+
export type FundingChoice = "default" | "platform" | "subscription" | "byok";
|
|
42
77
|
export interface InvokeAndWaitOptions extends InvokeWorkflowOptions {
|
|
43
78
|
timeoutMs?: number;
|
|
44
79
|
pollIntervalMs?: number;
|
|
45
80
|
}
|
|
81
|
+
/** Options for `invokeInline` — the named-invoke options plus the run-title
|
|
82
|
+
* override (an inline run has no registered template to inherit one from). */
|
|
83
|
+
export interface InvokeInlineOptions extends InvokeWorkflowOptions {
|
|
84
|
+
/** Run title override — defaults to the workflow name. */
|
|
85
|
+
title?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface InvokeInlineAndWaitOptions extends InvokeInlineOptions {
|
|
88
|
+
timeoutMs?: number;
|
|
89
|
+
pollIntervalMs?: number;
|
|
90
|
+
}
|
|
46
91
|
export interface InvokeResult {
|
|
47
92
|
id: string;
|
|
48
93
|
}
|