agentbox-sdk 0.1.301 → 0.1.303
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/{Sandbox-CByFJI8X.d.ts → Sandbox-K6VNqKeo.d.ts} +1 -1
- package/dist/agents/index.d.ts +5 -5
- package/dist/agents/index.js +3 -3
- package/dist/{chunk-INMA52FV.js → chunk-AVXJMCBC.js} +17 -0
- package/dist/{chunk-4MBB6QHD.js → chunk-GBM7LKZF.js} +539 -161
- package/dist/{chunk-ZOWBRUQR.js → chunk-NWAXQ7UD.js} +136 -2
- package/dist/{chunk-LPKKT6YT.js → chunk-QNNAAVJV.js} +80 -9
- package/dist/events/index.d.ts +4 -4
- package/dist/events/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/sandboxes/index.d.ts +4 -4
- package/dist/sandboxes/index.js +2 -2
- package/dist/{types-B3N-Qo2q.d.ts → types-Ozo1rHKs.d.ts} +34 -13
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createNormalizedEvent,
|
|
3
3
|
normalizeRawAgentEvent,
|
|
4
4
|
toAISDKStream
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NWAXQ7UD.js";
|
|
6
6
|
import {
|
|
7
7
|
AgentBoxError,
|
|
8
8
|
AsyncQueue,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
sleep,
|
|
20
20
|
time,
|
|
21
21
|
waitFor
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-AVXJMCBC.js";
|
|
23
23
|
import {
|
|
24
24
|
shellQuote
|
|
25
25
|
} from "./chunk-NSJM57Z4.js";
|
|
@@ -998,6 +998,28 @@ var HostSetupTarget = class {
|
|
|
998
998
|
}
|
|
999
999
|
);
|
|
1000
1000
|
}
|
|
1001
|
+
async probe(command, extraEnv) {
|
|
1002
|
+
return time(
|
|
1003
|
+
debugRuntime,
|
|
1004
|
+
`host probe ${shortLabel(command)}`,
|
|
1005
|
+
async () => {
|
|
1006
|
+
const handle = spawnCommand({
|
|
1007
|
+
command: process.env.SHELL || "sh",
|
|
1008
|
+
args: ["-c", command],
|
|
1009
|
+
cwd: this.cwd,
|
|
1010
|
+
env: {
|
|
1011
|
+
...process.env,
|
|
1012
|
+
...this.baseEnv,
|
|
1013
|
+
...this.env,
|
|
1014
|
+
...extraEnv ?? {}
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
const exitCode = await handle.wait();
|
|
1018
|
+
return exitCode === 0;
|
|
1019
|
+
},
|
|
1020
|
+
(ok) => ({ ok })
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1001
1023
|
async cleanup() {
|
|
1002
1024
|
await rm(this.layout.rootDir, { recursive: true, force: true });
|
|
1003
1025
|
}
|
|
@@ -1052,13 +1074,34 @@ var SandboxSetupTarget = class {
|
|
|
1052
1074
|
}
|
|
1053
1075
|
});
|
|
1054
1076
|
if (result && result.exitCode !== 0) {
|
|
1077
|
+
const output = result.combinedOutput?.trim();
|
|
1078
|
+
const detail = output ? `
|
|
1079
|
+
${output}` : "";
|
|
1055
1080
|
throw new Error(
|
|
1056
|
-
`Sandbox setup command failed (${result.exitCode}): ${command}`
|
|
1081
|
+
`Sandbox setup command failed (${result.exitCode}): ${command}${detail}`
|
|
1057
1082
|
);
|
|
1058
1083
|
}
|
|
1059
1084
|
}
|
|
1060
1085
|
);
|
|
1061
1086
|
}
|
|
1087
|
+
async probe(command, extraEnv) {
|
|
1088
|
+
return time(
|
|
1089
|
+
debugRuntime,
|
|
1090
|
+
`sandbox probe ${shortLabel(command)}`,
|
|
1091
|
+
async () => {
|
|
1092
|
+
const result = await this.options.sandbox?.run(command, {
|
|
1093
|
+
cwd: this.options.cwd,
|
|
1094
|
+
env: {
|
|
1095
|
+
...this.options.env ?? {},
|
|
1096
|
+
...this.env,
|
|
1097
|
+
...extraEnv ?? {}
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
return Boolean(result && result.exitCode === 0);
|
|
1101
|
+
},
|
|
1102
|
+
(ok) => ({ ok })
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1062
1105
|
async cleanup() {
|
|
1063
1106
|
}
|
|
1064
1107
|
};
|
|
@@ -1092,6 +1135,7 @@ import path5 from "path";
|
|
|
1092
1135
|
var MANIFEST_FILENAME = "setup-manifest.json";
|
|
1093
1136
|
var TARGET_MANIFEST_FILENAME = "setup-target.json";
|
|
1094
1137
|
var INSTALL_SCRIPT_FILENAME = "install.sh";
|
|
1138
|
+
var SETUP_ID_FILENAME = "setup.id";
|
|
1095
1139
|
var MANIFEST_VERSION = 1;
|
|
1096
1140
|
function hashArtifact(artifact) {
|
|
1097
1141
|
const hasher = createHash("sha256");
|
|
@@ -1110,6 +1154,74 @@ function computeTargetArtifacts(artifacts) {
|
|
|
1110
1154
|
}
|
|
1111
1155
|
return result;
|
|
1112
1156
|
}
|
|
1157
|
+
function computeSetupId(parts) {
|
|
1158
|
+
const hasher = createHash("sha256");
|
|
1159
|
+
hasher.update(`v${MANIFEST_VERSION}
|
|
1160
|
+
`);
|
|
1161
|
+
for (const a of [...parts.artifacts ?? []].sort(
|
|
1162
|
+
(x, y) => x.path.localeCompare(y.path)
|
|
1163
|
+
)) {
|
|
1164
|
+
hasher.update(`a:${a.path}:${hashArtifact(a)}
|
|
1165
|
+
`);
|
|
1166
|
+
}
|
|
1167
|
+
for (const cmd of parts.installCommands ?? []) {
|
|
1168
|
+
hasher.update(`c:${hashCommand(cmd)}
|
|
1169
|
+
`);
|
|
1170
|
+
}
|
|
1171
|
+
if (parts.daemon) {
|
|
1172
|
+
hasher.update(
|
|
1173
|
+
`d:${parts.daemon.port}:${parts.daemon.healthPath}:${parts.daemon.expectedVersionMatch ?? ""}
|
|
1174
|
+
`
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
for (const extra of parts.extras ?? []) {
|
|
1178
|
+
hasher.update(`x:${extra}
|
|
1179
|
+
`);
|
|
1180
|
+
}
|
|
1181
|
+
return hasher.digest("hex");
|
|
1182
|
+
}
|
|
1183
|
+
async function preflightSetup(target, setupId, daemon) {
|
|
1184
|
+
return time(
|
|
1185
|
+
debugSetup,
|
|
1186
|
+
`preflightSetup ${target.provider}`,
|
|
1187
|
+
async () => {
|
|
1188
|
+
const setupIdFile = path5.posix.join(
|
|
1189
|
+
target.layout.rootDir,
|
|
1190
|
+
SETUP_ID_FILENAME
|
|
1191
|
+
);
|
|
1192
|
+
const checks = [
|
|
1193
|
+
`[ -f ${shellQuote(setupIdFile)} ]`,
|
|
1194
|
+
`[ "$(cat ${shellQuote(setupIdFile)} 2>/dev/null)" = ${shellQuote(setupId)} ]`
|
|
1195
|
+
];
|
|
1196
|
+
if (daemon) {
|
|
1197
|
+
const url = `http://127.0.0.1:${daemon.port}${daemon.healthPath}`;
|
|
1198
|
+
if (daemon.expectedVersionMatch) {
|
|
1199
|
+
checks.push(
|
|
1200
|
+
`curl -fsS --max-time 2 ${shellQuote(url)} 2>/dev/null | grep -q ${shellQuote(daemon.expectedVersionMatch)}`
|
|
1201
|
+
);
|
|
1202
|
+
} else {
|
|
1203
|
+
checks.push(
|
|
1204
|
+
`curl -fsS --max-time 2 ${shellQuote(url)} >/dev/null 2>&1`
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
return target.probe(checks.join(" && "));
|
|
1209
|
+
},
|
|
1210
|
+
(ok) => ({ ok })
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
async function markSetupComplete(target, setupId) {
|
|
1214
|
+
await time(
|
|
1215
|
+
debugSetup,
|
|
1216
|
+
`markSetupComplete ${target.provider}`,
|
|
1217
|
+
() => target.runCommand(
|
|
1218
|
+
[
|
|
1219
|
+
`mkdir -p ${shellQuote(target.layout.rootDir)}`,
|
|
1220
|
+
`printf '%s' ${shellQuote(setupId)} > ${shellQuote(path5.posix.join(target.layout.rootDir, SETUP_ID_FILENAME))}`
|
|
1221
|
+
].join(" && ")
|
|
1222
|
+
)
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1113
1225
|
function buildInstallScript(rootDir, installCommandsByKey) {
|
|
1114
1226
|
const commandsB64 = Buffer.from(
|
|
1115
1227
|
JSON.stringify(installCommandsByKey),
|
|
@@ -1445,7 +1557,10 @@ function extractCodexCostData(events) {
|
|
|
1445
1557
|
let sawUsage = false;
|
|
1446
1558
|
for (const event of events) {
|
|
1447
1559
|
const params = asRecord(event.params);
|
|
1448
|
-
const
|
|
1560
|
+
const tokenUsage = asRecord(params?.tokenUsage);
|
|
1561
|
+
const turn = asRecord(params?.turn);
|
|
1562
|
+
const turnTokenUsage = asRecord(turn?.tokenUsage);
|
|
1563
|
+
const usageCandidate = asRecord(event.usage) ?? asRecord(params?.usage) ?? asRecord(tokenUsage?.last) ?? asRecord(tokenUsage?.total) ?? tokenUsage ?? asRecord(turn?.usage) ?? asRecord(turnTokenUsage?.last) ?? asRecord(turnTokenUsage?.total) ?? turnTokenUsage;
|
|
1449
1564
|
if (usageCandidate) {
|
|
1450
1565
|
sawUsage = true;
|
|
1451
1566
|
mergeUsage(usage, usageCandidate);
|
|
@@ -1513,12 +1628,23 @@ function buildClaudeQueryOptions(params) {
|
|
|
1513
1628
|
settings: params.settingsPath,
|
|
1514
1629
|
extraArgs,
|
|
1515
1630
|
includePartialMessages: true,
|
|
1631
|
+
thinking: { type: "adaptive", display: "summarized" },
|
|
1516
1632
|
...run.model ? { model: run.model } : {},
|
|
1517
1633
|
...run.reasoning ? { effort: run.reasoning } : {},
|
|
1518
1634
|
...provider?.permissionMode ? { permissionMode: provider.permissionMode } : {},
|
|
1519
1635
|
...provider?.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
|
|
1520
1636
|
...provider?.allowedTools?.length ? { allowedTools: provider.allowedTools } : {},
|
|
1521
|
-
...run.resumeSessionId ? { resume: run.resumeSessionId } : {}
|
|
1637
|
+
...run.resumeSessionId ? { resume: run.resumeSessionId } : {},
|
|
1638
|
+
// Fork-at-message: claude-agent-sdk natively supports slicing a
|
|
1639
|
+
// resumed transcript at a message UUID and writing the continuation
|
|
1640
|
+
// under a new session id when `forkSession: true` is set. The
|
|
1641
|
+
// captured message UUID comes from `SDKAssistantMessage.uuid`,
|
|
1642
|
+
// surfaced on normalized `message.started` events.
|
|
1643
|
+
...run.forkSessionId ? {
|
|
1644
|
+
resume: run.forkSessionId,
|
|
1645
|
+
resumeSessionAt: run.forkAtMessageId,
|
|
1646
|
+
forkSession: true
|
|
1647
|
+
} : {}
|
|
1522
1648
|
};
|
|
1523
1649
|
}
|
|
1524
1650
|
function toRawEvent(runId, payload, type) {
|
|
@@ -1921,6 +2047,11 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
1921
2047
|
/**
|
|
1922
2048
|
* Sandbox-side preparation. Uploads `.claude/` artifacts and ensures
|
|
1923
2049
|
* the daemon is running. `execute()` then dials the daemon directly.
|
|
2050
|
+
*
|
|
2051
|
+
* Warm-path short-circuit: a single no-upload `preflightSetup` probes
|
|
2052
|
+
* the `setup.id` marker + daemon `/__version` on loopback. If both
|
|
2053
|
+
* match what we'd produce, we skip the artifact upload AND the daemon
|
|
2054
|
+
* boot entirely.
|
|
1924
2055
|
*/
|
|
1925
2056
|
async setup(request) {
|
|
1926
2057
|
await time(debugClaude, "claude-code setup()", async () => {
|
|
@@ -1954,6 +2085,20 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
1954
2085
|
{ path: settingsPath, content: JSON.stringify(hookSettings, null, 2) },
|
|
1955
2086
|
{ path: mcpConfigPath, content: mcpConfigJson }
|
|
1956
2087
|
];
|
|
2088
|
+
const daemonInfo = {
|
|
2089
|
+
port: DAEMON_PORT,
|
|
2090
|
+
healthPath: "/__version",
|
|
2091
|
+
expectedVersionMatch: DAEMON_PROTOCOL_VERSION
|
|
2092
|
+
};
|
|
2093
|
+
const setupId = computeSetupId({
|
|
2094
|
+
artifacts,
|
|
2095
|
+
installCommands,
|
|
2096
|
+
daemon: daemonInfo
|
|
2097
|
+
});
|
|
2098
|
+
if (await preflightSetup(target, setupId, daemonInfo)) {
|
|
2099
|
+
debugClaude("claude-code setup() preflight hit \u2014 skipping");
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
1957
2102
|
const env = { ...options.env ?? {}, ...target.env };
|
|
1958
2103
|
await Promise.all([
|
|
1959
2104
|
time(
|
|
@@ -1963,6 +2108,7 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
1963
2108
|
),
|
|
1964
2109
|
ensureClaudeCodeDaemon(options, env)
|
|
1965
2110
|
]);
|
|
2111
|
+
await markSetupComplete(target, setupId);
|
|
1966
2112
|
});
|
|
1967
2113
|
}
|
|
1968
2114
|
async execute(request, sink) {
|
|
@@ -2092,6 +2238,8 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2092
2238
|
let pendingMessages = 1;
|
|
2093
2239
|
let firstStreamEventLogged = false;
|
|
2094
2240
|
let firstTextDeltaLogged = false;
|
|
2241
|
+
let lastTerminalReason;
|
|
2242
|
+
let lastIsError = false;
|
|
2095
2243
|
const rawPayloads = [];
|
|
2096
2244
|
try {
|
|
2097
2245
|
for await (const item of parseNdjsonStream(response.body)) {
|
|
@@ -2179,6 +2327,8 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2179
2327
|
}
|
|
2180
2328
|
if (message.type === "result") {
|
|
2181
2329
|
const result = message;
|
|
2330
|
+
lastTerminalReason = result.terminal_reason;
|
|
2331
|
+
lastIsError = result.is_error;
|
|
2182
2332
|
const resultText = result.subtype === "success" ? result.result : accumulatedText;
|
|
2183
2333
|
if (resultText && resultText !== accumulatedText) {
|
|
2184
2334
|
accumulatedText = resultText;
|
|
@@ -2189,22 +2339,43 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2189
2339
|
}
|
|
2190
2340
|
}
|
|
2191
2341
|
const finalText = accumulatedText;
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2342
|
+
const isCancelled = lastTerminalReason === "aborted_streaming" || lastTerminalReason === "aborted_tools";
|
|
2343
|
+
const isError = !isCancelled && lastIsError;
|
|
2344
|
+
if (isCancelled) {
|
|
2345
|
+
debugClaude(
|
|
2346
|
+
"\u2605 run.cancelled (%dms since execute start) reason=%s",
|
|
2347
|
+
Date.now() - executeStartedAt,
|
|
2348
|
+
lastTerminalReason
|
|
2349
|
+
);
|
|
2350
|
+
sink.cancel({
|
|
2351
|
+
text: finalText,
|
|
2352
|
+
costData: extractClaudeCostData(rawPayloads)
|
|
2353
|
+
});
|
|
2354
|
+
} else if (isError) {
|
|
2355
|
+
debugClaude(
|
|
2356
|
+
"\u2605 run.error (%dms since execute start) reason=%s",
|
|
2357
|
+
Date.now() - executeStartedAt,
|
|
2358
|
+
lastTerminalReason
|
|
2359
|
+
);
|
|
2360
|
+
sink.fail(new Error(finalText || `claude-code run failed (terminal_reason: ${lastTerminalReason})`));
|
|
2361
|
+
} else {
|
|
2362
|
+
debugClaude(
|
|
2363
|
+
"\u2605 run.completed (%dms since execute start) chars=%d",
|
|
2364
|
+
Date.now() - executeStartedAt,
|
|
2365
|
+
finalText.length
|
|
2366
|
+
);
|
|
2367
|
+
sink.emitEvent(
|
|
2368
|
+
createNormalizedEvent(
|
|
2369
|
+
"run.completed",
|
|
2370
|
+
{ provider: request.provider, runId: request.runId },
|
|
2371
|
+
{ text: finalText }
|
|
2372
|
+
)
|
|
2373
|
+
);
|
|
2374
|
+
sink.complete({
|
|
2375
|
+
text: finalText,
|
|
2376
|
+
costData: extractClaudeCostData(rawPayloads)
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2208
2379
|
} finally {
|
|
2209
2380
|
fetchAbort.abort();
|
|
2210
2381
|
}
|
|
@@ -2487,7 +2658,8 @@ function buildThreadParams(cwd, options, request) {
|
|
|
2487
2658
|
// Persist the rollout on disk so follow-up runs can call `thread/resume`.
|
|
2488
2659
|
// `ephemeral: true` threads have no rollout file and resume fails with
|
|
2489
2660
|
// "no rollout found for thread id ...".
|
|
2490
|
-
experimentalRawEvents: true
|
|
2661
|
+
experimentalRawEvents: true,
|
|
2662
|
+
developerInstructions: request.run.systemPrompt ?? null
|
|
2491
2663
|
};
|
|
2492
2664
|
}
|
|
2493
2665
|
function buildResumeParams(cwd, options, request) {
|
|
@@ -2496,7 +2668,18 @@ function buildResumeParams(cwd, options, request) {
|
|
|
2496
2668
|
cwd,
|
|
2497
2669
|
model: request.run.model ?? null,
|
|
2498
2670
|
approvalPolicy: isInteractiveApproval(options) ? "untrusted" : "never",
|
|
2499
|
-
sandbox: buildCodexSandboxMode(options)
|
|
2671
|
+
sandbox: buildCodexSandboxMode(options),
|
|
2672
|
+
developerInstructions: request.run.systemPrompt ?? null
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
function buildForkParams(cwd, options, request) {
|
|
2676
|
+
return {
|
|
2677
|
+
threadId: request.run.forkSessionId,
|
|
2678
|
+
cwd,
|
|
2679
|
+
model: request.run.model ?? null,
|
|
2680
|
+
approvalPolicy: isInteractiveApproval(options) ? "untrusted" : "never",
|
|
2681
|
+
sandbox: buildCodexSandboxMode(options),
|
|
2682
|
+
developerInstructions: request.run.systemPrompt ?? null
|
|
2500
2683
|
};
|
|
2501
2684
|
}
|
|
2502
2685
|
function buildTurnSandboxPolicy(options) {
|
|
@@ -2514,27 +2697,14 @@ function buildTurnSandboxPolicy(options) {
|
|
|
2514
2697
|
networkAccess: "enabled"
|
|
2515
2698
|
};
|
|
2516
2699
|
}
|
|
2517
|
-
function buildTurnCollaborationMode(request) {
|
|
2518
|
-
const systemPrompt = request.run.systemPrompt;
|
|
2519
|
-
if (!systemPrompt) {
|
|
2520
|
-
return void 0;
|
|
2521
|
-
}
|
|
2522
|
-
return {
|
|
2523
|
-
mode: "custom",
|
|
2524
|
-
settings: {
|
|
2525
|
-
developer_instructions: systemPrompt
|
|
2526
|
-
}
|
|
2527
|
-
};
|
|
2528
|
-
}
|
|
2529
2700
|
function buildCodexTurnStartParams(params) {
|
|
2530
|
-
const { threadId, inputItems, request
|
|
2701
|
+
const { threadId, inputItems, request } = params;
|
|
2531
2702
|
const sandboxPolicy = buildTurnSandboxPolicy(request.options);
|
|
2532
2703
|
return {
|
|
2533
2704
|
threadId,
|
|
2534
2705
|
input: inputItems,
|
|
2535
2706
|
approvalPolicy: isInteractiveApproval(request.options) ? "untrusted" : "never",
|
|
2536
2707
|
...sandboxPolicy ? { sandboxPolicy } : {},
|
|
2537
|
-
...turnStartOverrides ?? {},
|
|
2538
2708
|
model: request.run.model ?? null,
|
|
2539
2709
|
effort: request.run.reasoning ?? null,
|
|
2540
2710
|
outputSchema: null
|
|
@@ -2781,7 +2951,12 @@ async function ensureCodexLoginViaConfig(request, target) {
|
|
|
2781
2951
|
[
|
|
2782
2952
|
'if [ -z "${OPENAI_API_KEY:-}" ]; then exit 0; fi',
|
|
2783
2953
|
'mkdir -p "${CODEX_HOME:-$HOME/.codex}"',
|
|
2784
|
-
|
|
2954
|
+
// Merge stderr into stdout so providers that don't surface stderr
|
|
2955
|
+
// (e.g. Daytona's `executeCommand`, which collapses to a single
|
|
2956
|
+
// `result` field) still propagate the underlying error message
|
|
2957
|
+
// back to the caller — otherwise a failed login leaves us with a
|
|
2958
|
+
// bare "exit 1" and no diagnostic.
|
|
2959
|
+
"printenv OPENAI_API_KEY | env -u XDG_CONFIG_HOME codex login --with-api-key 2>&1"
|
|
2785
2960
|
].join("; "),
|
|
2786
2961
|
Object.keys(extraEnv).length > 0 ? extraEnv : void 0
|
|
2787
2962
|
);
|
|
@@ -2887,12 +3062,26 @@ async function setupCodex(request) {
|
|
|
2887
3062
|
...sharedTarget.env,
|
|
2888
3063
|
...options.provider?.env ?? {}
|
|
2889
3064
|
});
|
|
3065
|
+
const { artifacts: serverArtifacts } = buildArtifactsFor(sharedTarget);
|
|
3066
|
+
const { artifacts: skillArtifacts2, installCommands: installCommands2 } = await prepareSkillArtifacts(provider, options.skills, target2.layout);
|
|
3067
|
+
const daemonInfo = {
|
|
3068
|
+
port: REMOTE_CODEX_APP_SERVER_PORT,
|
|
3069
|
+
healthPath: "/readyz"
|
|
3070
|
+
};
|
|
3071
|
+
const setupId2 = computeSetupId({
|
|
3072
|
+
artifacts: [...serverArtifacts, ...skillArtifacts2],
|
|
3073
|
+
installCommands: installCommands2,
|
|
3074
|
+
daemon: daemonInfo
|
|
3075
|
+
});
|
|
3076
|
+
if (await preflightSetup(sharedTarget, setupId2, daemonInfo)) {
|
|
3077
|
+
debugCodex("codex remote setup() preflight hit \u2014 skipping");
|
|
3078
|
+
return;
|
|
3079
|
+
}
|
|
2890
3080
|
await time(
|
|
2891
3081
|
debugCodex,
|
|
2892
3082
|
"ensureCodexLogin",
|
|
2893
3083
|
() => ensureCodexLoginViaConfig(request, sharedTarget)
|
|
2894
3084
|
);
|
|
2895
|
-
const { artifacts: serverArtifacts } = buildArtifactsFor(sharedTarget);
|
|
2896
3085
|
await applyDifferentialSetup(sharedTarget, serverArtifacts, []);
|
|
2897
3086
|
const binary = options.provider?.binary ?? "codex";
|
|
2898
3087
|
const pidFilePath = path9.posix.join(
|
|
@@ -2940,28 +3129,34 @@ async function setupCodex(request) {
|
|
|
2940
3129
|
);
|
|
2941
3130
|
}
|
|
2942
3131
|
try {
|
|
2943
|
-
const { artifacts: skillArtifacts2, installCommands: installCommands2 } = await prepareSkillArtifacts(provider, options.skills, target2.layout);
|
|
2944
3132
|
await applyDifferentialSetup(target2, skillArtifacts2, installCommands2);
|
|
2945
3133
|
} catch (error) {
|
|
2946
3134
|
await target2.cleanup().catch(() => void 0);
|
|
2947
3135
|
throw error;
|
|
2948
3136
|
}
|
|
3137
|
+
await markSetupComplete(sharedTarget, setupId2);
|
|
2949
3138
|
return;
|
|
2950
3139
|
}
|
|
2951
3140
|
const target = await createSetupTarget(provider, "shared-setup", options);
|
|
3141
|
+
const { artifacts: skillArtifacts, installCommands } = await prepareSkillArtifacts(provider, options.skills, target.layout);
|
|
3142
|
+
const { artifacts: configArtifacts } = buildArtifactsFor(target);
|
|
3143
|
+
const allArtifacts = [...skillArtifacts, ...configArtifacts];
|
|
3144
|
+
const setupId = computeSetupId({
|
|
3145
|
+
artifacts: allArtifacts,
|
|
3146
|
+
installCommands
|
|
3147
|
+
});
|
|
3148
|
+
if (await preflightSetup(target, setupId)) {
|
|
3149
|
+
debugCodex("codex local setup() preflight hit \u2014 skipping");
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
2952
3152
|
try {
|
|
2953
3153
|
await ensureCodexLoginViaConfig(request, target);
|
|
2954
3154
|
} catch (error) {
|
|
2955
3155
|
await target.cleanup().catch(() => void 0);
|
|
2956
3156
|
throw error;
|
|
2957
3157
|
}
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
await applyDifferentialSetup(
|
|
2961
|
-
target,
|
|
2962
|
-
[...skillArtifacts, ...configArtifacts],
|
|
2963
|
-
installCommands
|
|
2964
|
-
);
|
|
3158
|
+
await applyDifferentialSetup(target, allArtifacts, installCommands);
|
|
3159
|
+
await markSetupComplete(target, setupId);
|
|
2965
3160
|
}
|
|
2966
3161
|
async function createRuntime(request, inputParts) {
|
|
2967
3162
|
const options = request.options;
|
|
@@ -2998,8 +3193,7 @@ async function createRuntime(request, inputParts) {
|
|
|
2998
3193
|
port: REMOTE_CODEX_APP_SERVER_PORT,
|
|
2999
3194
|
codexDir
|
|
3000
3195
|
},
|
|
3001
|
-
inputItems
|
|
3002
|
-
turnStartOverrides: buildTurnCollaborationMode(request)
|
|
3196
|
+
inputItems
|
|
3003
3197
|
};
|
|
3004
3198
|
}
|
|
3005
3199
|
const codexArgs = buildCodexCommandArgs(
|
|
@@ -3037,8 +3231,7 @@ async function createRuntime(request, inputParts) {
|
|
|
3037
3231
|
await handle.kill();
|
|
3038
3232
|
},
|
|
3039
3233
|
raw: { handle, codexDir },
|
|
3040
|
-
inputItems
|
|
3041
|
-
turnStartOverrides: buildTurnCollaborationMode(request)
|
|
3234
|
+
inputItems
|
|
3042
3235
|
};
|
|
3043
3236
|
}
|
|
3044
3237
|
const processHandle = spawnCommand({
|
|
@@ -3060,8 +3253,7 @@ async function createRuntime(request, inputParts) {
|
|
|
3060
3253
|
await processHandle.kill();
|
|
3061
3254
|
},
|
|
3062
3255
|
raw: { processHandle, codexDir },
|
|
3063
|
-
inputItems
|
|
3064
|
-
turnStartOverrides: buildTurnCollaborationMode(request)
|
|
3256
|
+
inputItems
|
|
3065
3257
|
};
|
|
3066
3258
|
}
|
|
3067
3259
|
async function buildCodexInputItems(options, inputParts) {
|
|
@@ -3118,7 +3310,9 @@ var CodexAgentAdapter = class {
|
|
|
3118
3310
|
let rootThreadId;
|
|
3119
3311
|
let turnId;
|
|
3120
3312
|
let pendingTurns = 1;
|
|
3313
|
+
let abortInvoked = false;
|
|
3121
3314
|
sink.setAbort(async () => {
|
|
3315
|
+
abortInvoked = true;
|
|
3122
3316
|
const threadIdAtAbort = rootThreadId;
|
|
3123
3317
|
const turnIdAtAbort = turnId;
|
|
3124
3318
|
if (threadIdAtAbort && turnIdAtAbort) {
|
|
@@ -3164,8 +3358,8 @@ var CodexAgentAdapter = class {
|
|
|
3164
3358
|
};
|
|
3165
3359
|
sink.onMessage(sendTurn);
|
|
3166
3360
|
const rawPayloads = [];
|
|
3361
|
+
let streamedText = "";
|
|
3167
3362
|
const completion = new Promise((resolve, reject) => {
|
|
3168
|
-
let finalText = "";
|
|
3169
3363
|
void (async () => {
|
|
3170
3364
|
let firstClientMessageLogged = false;
|
|
3171
3365
|
for await (const message of client.messages()) {
|
|
@@ -3202,7 +3396,7 @@ var CodexAgentAdapter = class {
|
|
|
3202
3396
|
for (const event of toNormalizedCodexEvents(request.runId, message)) {
|
|
3203
3397
|
sink.emitEvent(event);
|
|
3204
3398
|
if (event.type === "text.delta") {
|
|
3205
|
-
|
|
3399
|
+
streamedText += event.delta;
|
|
3206
3400
|
}
|
|
3207
3401
|
}
|
|
3208
3402
|
if (message.method === "thread/started" && !rootThreadId) {
|
|
@@ -3214,7 +3408,14 @@ var CodexAgentAdapter = class {
|
|
|
3214
3408
|
if (message.method === "turn/completed" && (!message.params?.threadId || message.params.threadId === rootThreadId)) {
|
|
3215
3409
|
pendingTurns--;
|
|
3216
3410
|
if (pendingTurns <= 0) {
|
|
3217
|
-
|
|
3411
|
+
const turn = message.params?.turn;
|
|
3412
|
+
const interrupted = turn?.status === "interrupted";
|
|
3413
|
+
resolve({
|
|
3414
|
+
text: streamedText,
|
|
3415
|
+
turnId,
|
|
3416
|
+
threadId: rootThreadId,
|
|
3417
|
+
interrupted
|
|
3418
|
+
});
|
|
3218
3419
|
return;
|
|
3219
3420
|
}
|
|
3220
3421
|
}
|
|
@@ -3241,13 +3442,27 @@ var CodexAgentAdapter = class {
|
|
|
3241
3442
|
await client.notify("initialized", {});
|
|
3242
3443
|
}
|
|
3243
3444
|
const cwd = request.options.cwd ?? process.cwd();
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3445
|
+
let threadResponse;
|
|
3446
|
+
let threadResultEventName;
|
|
3447
|
+
if (request.run.forkSessionId) {
|
|
3448
|
+
threadResponse = await client.request(
|
|
3449
|
+
"thread/fork",
|
|
3450
|
+
buildForkParams(cwd, request.options, request)
|
|
3451
|
+
);
|
|
3452
|
+
threadResultEventName = "thread/fork:result";
|
|
3453
|
+
} else if (request.run.resumeSessionId) {
|
|
3454
|
+
threadResponse = await client.request(
|
|
3455
|
+
"thread/resume",
|
|
3456
|
+
buildResumeParams(cwd, request.options, request)
|
|
3457
|
+
);
|
|
3458
|
+
threadResultEventName = "thread/resume:result";
|
|
3459
|
+
} else {
|
|
3460
|
+
threadResponse = await client.request(
|
|
3461
|
+
"thread/start",
|
|
3462
|
+
buildThreadParams(cwd, request.options, request)
|
|
3463
|
+
);
|
|
3464
|
+
threadResultEventName = "thread/start:result";
|
|
3465
|
+
}
|
|
3251
3466
|
rootThreadId = threadResponse.thread.id;
|
|
3252
3467
|
if ("bindThread" in client && typeof client.bindThread === "function") {
|
|
3253
3468
|
client.bindThread(threadResponse.thread.id);
|
|
@@ -3255,28 +3470,79 @@ var CodexAgentAdapter = class {
|
|
|
3255
3470
|
sink.setSessionId(threadResponse.thread.id);
|
|
3256
3471
|
rawPayloads.push(threadResponse);
|
|
3257
3472
|
sink.emitRaw(
|
|
3258
|
-
toRawEvent2(
|
|
3259
|
-
request.runId,
|
|
3260
|
-
threadResponse,
|
|
3261
|
-
request.run.resumeSessionId ? "thread/resume:result" : "thread/start:result"
|
|
3262
|
-
)
|
|
3473
|
+
toRawEvent2(request.runId, threadResponse, threadResultEventName)
|
|
3263
3474
|
);
|
|
3475
|
+
if (request.run.forkSessionId) {
|
|
3476
|
+
const targetTurnId = request.run.forkAtMessageId;
|
|
3477
|
+
const turns = threadResponse.thread.turns ?? [];
|
|
3478
|
+
const targetIndex = turns.findIndex((turn) => turn.id === targetTurnId);
|
|
3479
|
+
if (targetIndex < 0) {
|
|
3480
|
+
throw new Error(
|
|
3481
|
+
`Codex fork: turn id ${String(targetTurnId)} not found in source thread ${request.run.forkSessionId}.`
|
|
3482
|
+
);
|
|
3483
|
+
}
|
|
3484
|
+
const numTurns = turns.length - 1 - targetIndex;
|
|
3485
|
+
if (numTurns > 0) {
|
|
3486
|
+
const rollbackResponse = await client.request(
|
|
3487
|
+
"thread/rollback",
|
|
3488
|
+
{ threadId: rootThreadId, numTurns }
|
|
3489
|
+
);
|
|
3490
|
+
rawPayloads.push(rollbackResponse);
|
|
3491
|
+
sink.emitRaw(
|
|
3492
|
+
toRawEvent2(
|
|
3493
|
+
request.runId,
|
|
3494
|
+
rollbackResponse,
|
|
3495
|
+
"thread/rollback:result"
|
|
3496
|
+
)
|
|
3497
|
+
);
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3264
3500
|
await client.request(
|
|
3265
3501
|
"turn/start",
|
|
3266
3502
|
buildCodexTurnStartParams({
|
|
3267
3503
|
threadId: threadResponse.thread.id,
|
|
3268
3504
|
inputItems: runtime.inputItems,
|
|
3269
|
-
request
|
|
3270
|
-
turnStartOverrides: runtime.turnStartOverrides
|
|
3505
|
+
request
|
|
3271
3506
|
})
|
|
3272
3507
|
);
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3508
|
+
let completionResult;
|
|
3509
|
+
let completionError;
|
|
3510
|
+
try {
|
|
3511
|
+
completionResult = await completion;
|
|
3512
|
+
} catch (err) {
|
|
3513
|
+
completionError = err;
|
|
3514
|
+
}
|
|
3515
|
+
if (completionError !== void 0) {
|
|
3516
|
+
if (abortInvoked) {
|
|
3517
|
+
debugCodex(
|
|
3518
|
+
"\u2605 run.cancelled (%dms since execute start)",
|
|
3519
|
+
Date.now() - executeStartedAt
|
|
3520
|
+
);
|
|
3521
|
+
sink.cancel({
|
|
3522
|
+
text: streamedText || void 0,
|
|
3523
|
+
costData: extractCodexCostData(rawPayloads)
|
|
3524
|
+
});
|
|
3525
|
+
} else {
|
|
3526
|
+
sink.fail(completionError);
|
|
3527
|
+
}
|
|
3528
|
+
} else {
|
|
3529
|
+
const { text, interrupted } = completionResult;
|
|
3530
|
+
if (abortInvoked || interrupted) {
|
|
3531
|
+
debugCodex(
|
|
3532
|
+
"\u2605 run.cancelled (%dms since execute start) interrupted=%s",
|
|
3533
|
+
Date.now() - executeStartedAt,
|
|
3534
|
+
interrupted
|
|
3535
|
+
);
|
|
3536
|
+
sink.cancel({ text, costData: extractCodexCostData(rawPayloads) });
|
|
3537
|
+
} else {
|
|
3538
|
+
debugCodex(
|
|
3539
|
+
"\u2605 run.completed (%dms since execute start) chars=%d",
|
|
3540
|
+
Date.now() - executeStartedAt,
|
|
3541
|
+
text?.length ?? 0
|
|
3542
|
+
);
|
|
3543
|
+
sink.complete({ text, costData: extractCodexCostData(rawPayloads) });
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3280
3546
|
} finally {
|
|
3281
3547
|
await runtime.cleanup().catch(() => void 0);
|
|
3282
3548
|
}
|
|
@@ -3500,12 +3766,11 @@ var OPEN_CODE_REASONING_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
|
3500
3766
|
function openCodeAgentSlug(reasoning) {
|
|
3501
3767
|
return reasoning ? `agentbox-${reasoning}` : "agentbox";
|
|
3502
3768
|
}
|
|
3503
|
-
function buildOpenCodeConfig(options,
|
|
3769
|
+
function buildOpenCodeConfig(options, interactiveApproval) {
|
|
3504
3770
|
const mcpConfig = buildOpenCodeMcpConfig(options.mcps);
|
|
3505
3771
|
const commandsConfig = buildOpenCodeCommandsConfig(options.commands);
|
|
3506
3772
|
const baseAgent = {
|
|
3507
3773
|
mode: "primary",
|
|
3508
|
-
prompt: systemPrompt,
|
|
3509
3774
|
permission: buildOpenCodePermissionConfig(interactiveApproval),
|
|
3510
3775
|
tools: {
|
|
3511
3776
|
write: true,
|
|
@@ -3521,10 +3786,15 @@ function buildOpenCodeConfig(options, systemPrompt, interactiveApproval) {
|
|
|
3521
3786
|
{ ...baseAgent, reasoningEffort: level }
|
|
3522
3787
|
])
|
|
3523
3788
|
);
|
|
3789
|
+
const googleBaseUrl = options.env?.GOOGLE_BASE_URL;
|
|
3524
3790
|
return {
|
|
3525
3791
|
$schema: "https://opencode.ai/config.json",
|
|
3526
3792
|
...mcpConfig ? { mcp: mcpConfig } : {},
|
|
3527
3793
|
...commandsConfig ? { command: commandsConfig } : {},
|
|
3794
|
+
provider: {
|
|
3795
|
+
openrouter: { options: { baseURL: "https://openrouter.ai/api/v1" } },
|
|
3796
|
+
...googleBaseUrl ? { google: { options: { baseURL: googleBaseUrl } } } : {}
|
|
3797
|
+
},
|
|
3528
3798
|
agent: {
|
|
3529
3799
|
agentbox: baseAgent,
|
|
3530
3800
|
...reasoningVariants,
|
|
@@ -3537,19 +3807,6 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3537
3807
|
const sandbox = request.options.sandbox;
|
|
3538
3808
|
const options = request.options;
|
|
3539
3809
|
const port = SANDBOX_OPENCODE_PORT;
|
|
3540
|
-
const healthCheck = await time(
|
|
3541
|
-
debugOpencode,
|
|
3542
|
-
"health probe (warm path)",
|
|
3543
|
-
() => sandbox.run(
|
|
3544
|
-
`curl -fsS http://127.0.0.1:${port}/global/health >/dev/null 2>&1`,
|
|
3545
|
-
{ cwd: options.cwd, timeoutMs: 5e3 }
|
|
3546
|
-
)
|
|
3547
|
-
);
|
|
3548
|
-
if (healthCheck.exitCode === 0) {
|
|
3549
|
-
debugOpencode("opencode server already running \u2014 reusing");
|
|
3550
|
-
return;
|
|
3551
|
-
}
|
|
3552
|
-
debugOpencode("opencode server not running \u2014 cold-spawning");
|
|
3553
3810
|
const plugins = assertHooksSupported(request.provider, options);
|
|
3554
3811
|
assertCommandsSupported(request.provider, options.commands);
|
|
3555
3812
|
const interactiveApproval = isInteractiveApproval(options);
|
|
@@ -3570,26 +3827,32 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3570
3827
|
const configPath = path10.join(target.layout.opencodeDir, "agentbox.json");
|
|
3571
3828
|
const openCodeConfig = buildOpenCodeConfig(
|
|
3572
3829
|
options,
|
|
3573
|
-
request.config.systemPrompt ?? "",
|
|
3574
3830
|
interactiveApproval
|
|
3575
3831
|
);
|
|
3832
|
+
const allArtifacts = [
|
|
3833
|
+
...skillArtifacts,
|
|
3834
|
+
...pluginArtifacts,
|
|
3835
|
+
{
|
|
3836
|
+
path: configPath,
|
|
3837
|
+
content: JSON.stringify(openCodeConfig, null, 2)
|
|
3838
|
+
}
|
|
3839
|
+
];
|
|
3840
|
+
const daemonInfo = { port, healthPath: "/global/health" };
|
|
3841
|
+
const setupId = computeSetupId({
|
|
3842
|
+
artifacts: allArtifacts,
|
|
3843
|
+
installCommands,
|
|
3844
|
+
daemon: daemonInfo
|
|
3845
|
+
});
|
|
3846
|
+
if (await preflightSetup(target, setupId, daemonInfo)) {
|
|
3847
|
+
debugOpencode("opencode setup() preflight hit \u2014 skipping");
|
|
3848
|
+
return;
|
|
3849
|
+
}
|
|
3576
3850
|
const commonEnv = {
|
|
3577
3851
|
OPENCODE_CONFIG: configPath,
|
|
3578
3852
|
OPENCODE_CONFIG_DIR: target.layout.opencodeDir,
|
|
3579
3853
|
OPENCODE_DISABLE_DEFAULT_PLUGINS: "true"
|
|
3580
3854
|
};
|
|
3581
|
-
await applyDifferentialSetup(
|
|
3582
|
-
target,
|
|
3583
|
-
[
|
|
3584
|
-
...skillArtifacts,
|
|
3585
|
-
...pluginArtifacts,
|
|
3586
|
-
{
|
|
3587
|
-
path: configPath,
|
|
3588
|
-
content: JSON.stringify(openCodeConfig, null, 2)
|
|
3589
|
-
}
|
|
3590
|
-
],
|
|
3591
|
-
installCommands
|
|
3592
|
-
);
|
|
3855
|
+
await applyDifferentialSetup(target, allArtifacts, installCommands);
|
|
3593
3856
|
const binary = options.provider?.binary ?? "opencode";
|
|
3594
3857
|
const pidFilePath = path10.posix.join(
|
|
3595
3858
|
target.layout.rootDir,
|
|
@@ -3652,6 +3915,7 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3652
3915
|
`OpenCode server did not become ready within ${SANDBOX_OPENCODE_READY_TIMEOUT_MS}ms.`
|
|
3653
3916
|
);
|
|
3654
3917
|
});
|
|
3918
|
+
await markSetupComplete(target, setupId);
|
|
3655
3919
|
});
|
|
3656
3920
|
}
|
|
3657
3921
|
async function ensureLocalOpenCodeServer(request) {
|
|
@@ -3684,28 +3948,28 @@ async function ensureLocalOpenCodeServer(request) {
|
|
|
3684
3948
|
target.layout.opencodeDir
|
|
3685
3949
|
);
|
|
3686
3950
|
const configPath = path10.join(target.layout.opencodeDir, "agentbox.json");
|
|
3687
|
-
const openCodeConfig = buildOpenCodeConfig(
|
|
3688
|
-
options,
|
|
3689
|
-
request.config.systemPrompt ?? "",
|
|
3690
|
-
interactiveApproval
|
|
3691
|
-
);
|
|
3951
|
+
const openCodeConfig = buildOpenCodeConfig(options, interactiveApproval);
|
|
3692
3952
|
const commonEnv = {
|
|
3693
3953
|
OPENCODE_CONFIG: configPath,
|
|
3694
3954
|
OPENCODE_CONFIG_DIR: target.layout.opencodeDir,
|
|
3695
3955
|
OPENCODE_DISABLE_DEFAULT_PLUGINS: "true"
|
|
3696
3956
|
};
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3957
|
+
const allArtifacts = [
|
|
3958
|
+
...skillArtifacts,
|
|
3959
|
+
...pluginArtifacts,
|
|
3960
|
+
{
|
|
3961
|
+
path: configPath,
|
|
3962
|
+
content: JSON.stringify(openCodeConfig, null, 2)
|
|
3963
|
+
}
|
|
3964
|
+
];
|
|
3965
|
+
const setupId = computeSetupId({
|
|
3966
|
+
artifacts: allArtifacts,
|
|
3707
3967
|
installCommands
|
|
3708
|
-
);
|
|
3968
|
+
});
|
|
3969
|
+
const preflightHit = await preflightSetup(target, setupId);
|
|
3970
|
+
if (!preflightHit) {
|
|
3971
|
+
await applyDifferentialSetup(target, allArtifacts, installCommands);
|
|
3972
|
+
}
|
|
3709
3973
|
spawnCommand({
|
|
3710
3974
|
command: options.provider?.binary ?? "opencode",
|
|
3711
3975
|
args: [
|
|
@@ -3727,6 +3991,7 @@ async function ensureLocalOpenCodeServer(request) {
|
|
|
3727
3991
|
`http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`,
|
|
3728
3992
|
{ timeoutMs: LOCAL_OPENCODE_READY_TIMEOUT_MS }
|
|
3729
3993
|
);
|
|
3994
|
+
await markSetupComplete(target, setupId);
|
|
3730
3995
|
}
|
|
3731
3996
|
async function setupOpenCode(request) {
|
|
3732
3997
|
if (request.options.sandbox) {
|
|
@@ -3820,7 +4085,11 @@ var OpenCodeAgentAdapter = class {
|
|
|
3820
4085
|
let sseTask;
|
|
3821
4086
|
const dispatchAbort = new AbortController();
|
|
3822
4087
|
let capturedSessionId;
|
|
4088
|
+
let sessionErrorFromSse;
|
|
4089
|
+
let sessionAbortedFromSse = false;
|
|
4090
|
+
let userAbortRequested = false;
|
|
3823
4091
|
sink.setAbort(async () => {
|
|
4092
|
+
userAbortRequested = true;
|
|
3824
4093
|
const sessionIdAtAbort = capturedSessionId;
|
|
3825
4094
|
if (sessionIdAtAbort) {
|
|
3826
4095
|
try {
|
|
@@ -3849,7 +4118,23 @@ var OpenCodeAgentAdapter = class {
|
|
|
3849
4118
|
});
|
|
3850
4119
|
try {
|
|
3851
4120
|
const interactiveApproval = isInteractiveApproval(request.options);
|
|
3852
|
-
|
|
4121
|
+
let forkedSession = null;
|
|
4122
|
+
if (request.run.forkSessionId) {
|
|
4123
|
+
forkedSession = await fetchJson(
|
|
4124
|
+
`${runtime.baseUrl}/session/${encodeURIComponent(request.run.forkSessionId)}/fork`,
|
|
4125
|
+
{
|
|
4126
|
+
method: "POST",
|
|
4127
|
+
headers: {
|
|
4128
|
+
"content-type": "application/json",
|
|
4129
|
+
...runtime.previewHeaders
|
|
4130
|
+
},
|
|
4131
|
+
body: JSON.stringify({
|
|
4132
|
+
messageID: request.run.forkAtMessageId
|
|
4133
|
+
})
|
|
4134
|
+
}
|
|
4135
|
+
);
|
|
4136
|
+
}
|
|
4137
|
+
const createdSession = request.run.resumeSessionId || forkedSession ? null : await fetchJson(
|
|
3853
4138
|
`${runtime.baseUrl}/session`,
|
|
3854
4139
|
{
|
|
3855
4140
|
method: "POST",
|
|
@@ -3862,7 +4147,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
3862
4147
|
})
|
|
3863
4148
|
}
|
|
3864
4149
|
);
|
|
3865
|
-
const sessionId = request.run.resumeSessionId ?? createdSession?.id ?? createdSession?.sessionId;
|
|
4150
|
+
const sessionId = request.run.resumeSessionId ?? forkedSession?.id ?? forkedSession?.sessionId ?? createdSession?.id ?? createdSession?.sessionId;
|
|
3866
4151
|
if (!sessionId) {
|
|
3867
4152
|
throw new Error("OpenCode did not return a session id.");
|
|
3868
4153
|
}
|
|
@@ -3952,6 +4237,15 @@ var OpenCodeAgentAdapter = class {
|
|
|
3952
4237
|
const properties = payloadRecord.properties;
|
|
3953
4238
|
const eventSessionId = typeof properties?.sessionID === "string" ? properties.sessionID : void 0;
|
|
3954
4239
|
if (!eventSessionId || eventSessionId === sessionId) {
|
|
4240
|
+
if (payloadRecord.type === "session.error") {
|
|
4241
|
+
const errData = properties?.error;
|
|
4242
|
+
if (errData?.name === "MessageAbortedError") {
|
|
4243
|
+
sessionAbortedFromSse = true;
|
|
4244
|
+
} else {
|
|
4245
|
+
const errMsg = typeof errData?.data?.message === "string" ? errData.data.message : typeof errData?.message === "string" ? errData.message : "OpenCode session error";
|
|
4246
|
+
sessionErrorFromSse = new Error(errMsg);
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
3955
4249
|
debugOpencode(
|
|
3956
4250
|
"\u2605 %s for session=%s \u2014 aborting in-flight dispatch",
|
|
3957
4251
|
payloadRecord.type,
|
|
@@ -4040,6 +4334,11 @@ var OpenCodeAgentAdapter = class {
|
|
|
4040
4334
|
},
|
|
4041
4335
|
body: JSON.stringify({
|
|
4042
4336
|
...request.run.model ? { model: toOpenCodeModel(request.run.model) } : {},
|
|
4337
|
+
// Per-message system prompt — keeps systemPrompt out of
|
|
4338
|
+
// the on-disk agent config so changing it doesn't
|
|
4339
|
+
// invalidate setupId. Sent on every dispatch (the field
|
|
4340
|
+
// is per-message, not session-sticky).
|
|
4341
|
+
...request.run.systemPrompt ? { system: request.run.systemPrompt } : {},
|
|
4043
4342
|
agent: agentSlug,
|
|
4044
4343
|
parts
|
|
4045
4344
|
})
|
|
@@ -4121,30 +4420,48 @@ var OpenCodeAgentAdapter = class {
|
|
|
4121
4420
|
pendingMessages++;
|
|
4122
4421
|
void dispatchMessage(mapToOpenCodeParts(inputParts));
|
|
4123
4422
|
await allDone;
|
|
4124
|
-
if (
|
|
4125
|
-
|
|
4423
|
+
if (userAbortRequested || sessionAbortedFromSse) {
|
|
4424
|
+
debugOpencode(
|
|
4425
|
+
"\u2605 run.cancelled (%dms since execute start)",
|
|
4426
|
+
Date.now() - executeStartedAt
|
|
4427
|
+
);
|
|
4428
|
+
sseAbort.abort();
|
|
4429
|
+
await sseTask;
|
|
4430
|
+
sink.cancel({
|
|
4431
|
+
text: streamedTextFromSse || void 0,
|
|
4432
|
+
costData: extractOpenCodeCostData(rawPayloads)
|
|
4433
|
+
});
|
|
4434
|
+
} else if (sessionErrorFromSse) {
|
|
4435
|
+
sseAbort.abort();
|
|
4436
|
+
await sseTask;
|
|
4437
|
+
sink.fail(sessionErrorFromSse);
|
|
4438
|
+
} else if (dispatchError && !(dispatchAbort.signal.aborted && dispatchError?.name === "AbortError")) {
|
|
4439
|
+
sseAbort.abort();
|
|
4440
|
+
await sseTask;
|
|
4441
|
+
sink.fail(dispatchError);
|
|
4442
|
+
} else {
|
|
4443
|
+
debugOpencode(
|
|
4444
|
+
"\u2605 run.completed (%dms since execute start) chars=%d",
|
|
4445
|
+
Date.now() - executeStartedAt,
|
|
4446
|
+
finalText.length
|
|
4447
|
+
);
|
|
4448
|
+
sink.emitEvent(
|
|
4449
|
+
createNormalizedEvent(
|
|
4450
|
+
"run.completed",
|
|
4451
|
+
{
|
|
4452
|
+
provider: request.provider,
|
|
4453
|
+
runId: request.runId
|
|
4454
|
+
},
|
|
4455
|
+
{ text: finalText }
|
|
4456
|
+
)
|
|
4457
|
+
);
|
|
4458
|
+
sseAbort.abort();
|
|
4459
|
+
await sseTask;
|
|
4460
|
+
sink.complete({
|
|
4461
|
+
text: finalText,
|
|
4462
|
+
costData: extractOpenCodeCostData(rawPayloads)
|
|
4463
|
+
});
|
|
4126
4464
|
}
|
|
4127
|
-
debugOpencode(
|
|
4128
|
-
"\u2605 run.completed (%dms since execute start) chars=%d",
|
|
4129
|
-
Date.now() - executeStartedAt,
|
|
4130
|
-
finalText.length
|
|
4131
|
-
);
|
|
4132
|
-
sink.emitEvent(
|
|
4133
|
-
createNormalizedEvent(
|
|
4134
|
-
"run.completed",
|
|
4135
|
-
{
|
|
4136
|
-
provider: request.provider,
|
|
4137
|
-
runId: request.runId
|
|
4138
|
-
},
|
|
4139
|
-
{ text: finalText }
|
|
4140
|
-
)
|
|
4141
|
-
);
|
|
4142
|
-
sseAbort.abort();
|
|
4143
|
-
await sseTask;
|
|
4144
|
-
sink.complete({
|
|
4145
|
-
text: finalText,
|
|
4146
|
-
costData: extractOpenCodeCostData(rawPayloads)
|
|
4147
|
-
});
|
|
4148
4465
|
} finally {
|
|
4149
4466
|
sseAbort.abort();
|
|
4150
4467
|
if (sseTask) {
|
|
@@ -4308,17 +4625,14 @@ var AgentRunController = class {
|
|
|
4308
4625
|
resolveSessionIdReady;
|
|
4309
4626
|
rejectSessionIdReady;
|
|
4310
4627
|
resolveFinished;
|
|
4311
|
-
rejectFinished;
|
|
4312
4628
|
constructor(provider, id) {
|
|
4313
4629
|
this.provider = provider;
|
|
4314
4630
|
this.id = id;
|
|
4315
4631
|
let resolveFinished;
|
|
4316
|
-
let rejectFinished;
|
|
4317
4632
|
let resolveSessionIdReady;
|
|
4318
4633
|
let rejectSessionIdReady;
|
|
4319
|
-
this.finished = new Promise((resolve
|
|
4634
|
+
this.finished = new Promise((resolve) => {
|
|
4320
4635
|
resolveFinished = resolve;
|
|
4321
|
-
rejectFinished = reject;
|
|
4322
4636
|
});
|
|
4323
4637
|
this.sessionIdReady = new Promise((resolve, reject) => {
|
|
4324
4638
|
resolveSessionIdReady = resolve;
|
|
@@ -4326,7 +4640,6 @@ var AgentRunController = class {
|
|
|
4326
4640
|
});
|
|
4327
4641
|
void this.sessionIdReady.catch(() => void 0);
|
|
4328
4642
|
this.resolveFinished = resolveFinished;
|
|
4329
|
-
this.rejectFinished = rejectFinished;
|
|
4330
4643
|
this.resolveSessionIdReady = resolveSessionIdReady;
|
|
4331
4644
|
this.rejectSessionIdReady = rejectSessionIdReady;
|
|
4332
4645
|
}
|
|
@@ -4462,11 +4775,19 @@ var AgentRunController = class {
|
|
|
4462
4775
|
this.eventQueue.finish();
|
|
4463
4776
|
this.rawQueue.finish();
|
|
4464
4777
|
if (!this.sessionId) {
|
|
4465
|
-
const
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4778
|
+
const errorMsg = "Agent run completed before a provider session id was set.";
|
|
4779
|
+
this.rejectSessionIdReady(new Error(errorMsg));
|
|
4780
|
+
this.resolveFinished({
|
|
4781
|
+
id: this.id,
|
|
4782
|
+
provider: this.provider,
|
|
4783
|
+
sessionId: "",
|
|
4784
|
+
text: this.text,
|
|
4785
|
+
rawEvents: [...this.rawEventsList],
|
|
4786
|
+
events: [...this.events],
|
|
4787
|
+
costData: this.costData,
|
|
4788
|
+
isCancelled: false,
|
|
4789
|
+
error: errorMsg
|
|
4790
|
+
});
|
|
4470
4791
|
return;
|
|
4471
4792
|
}
|
|
4472
4793
|
this.resolveFinished({
|
|
@@ -4476,7 +4797,44 @@ var AgentRunController = class {
|
|
|
4476
4797
|
text: this.text,
|
|
4477
4798
|
rawEvents: [...this.rawEventsList],
|
|
4478
4799
|
events: [...this.events],
|
|
4479
|
-
costData: this.costData
|
|
4800
|
+
costData: this.costData,
|
|
4801
|
+
isCancelled: false
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
cancel(result) {
|
|
4805
|
+
if (this.settled) {
|
|
4806
|
+
return;
|
|
4807
|
+
}
|
|
4808
|
+
this.settled = true;
|
|
4809
|
+
this.clearPendingPermissions(
|
|
4810
|
+
new Error(
|
|
4811
|
+
"Agent run was cancelled before pending permission requests resolved."
|
|
4812
|
+
)
|
|
4813
|
+
);
|
|
4814
|
+
if (result?.text) {
|
|
4815
|
+
this.text = result.text;
|
|
4816
|
+
}
|
|
4817
|
+
if (result && "costData" in result) {
|
|
4818
|
+
this.costData = result.costData ?? null;
|
|
4819
|
+
}
|
|
4820
|
+
this.emitEvent(
|
|
4821
|
+
createNormalizedEvent(
|
|
4822
|
+
"run.cancelled",
|
|
4823
|
+
{ provider: this.provider, runId: this.id },
|
|
4824
|
+
{ text: this.text || void 0 }
|
|
4825
|
+
)
|
|
4826
|
+
);
|
|
4827
|
+
this.eventQueue.finish();
|
|
4828
|
+
this.rawQueue.finish();
|
|
4829
|
+
this.resolveFinished({
|
|
4830
|
+
id: this.id,
|
|
4831
|
+
provider: this.provider,
|
|
4832
|
+
sessionId: this.sessionId ?? "",
|
|
4833
|
+
text: this.text,
|
|
4834
|
+
rawEvents: [...this.rawEventsList],
|
|
4835
|
+
events: [...this.events],
|
|
4836
|
+
costData: this.costData,
|
|
4837
|
+
isCancelled: true
|
|
4480
4838
|
});
|
|
4481
4839
|
}
|
|
4482
4840
|
fail(error) {
|
|
@@ -4503,7 +4861,17 @@ var AgentRunController = class {
|
|
|
4503
4861
|
if (!this.sessionId) {
|
|
4504
4862
|
this.rejectSessionIdReady(normalizedError);
|
|
4505
4863
|
}
|
|
4506
|
-
this.
|
|
4864
|
+
this.resolveFinished({
|
|
4865
|
+
id: this.id,
|
|
4866
|
+
provider: this.provider,
|
|
4867
|
+
sessionId: this.sessionId ?? "",
|
|
4868
|
+
text: this.text,
|
|
4869
|
+
rawEvents: [...this.rawEventsList],
|
|
4870
|
+
events: [...this.events],
|
|
4871
|
+
costData: this.costData,
|
|
4872
|
+
isCancelled: false,
|
|
4873
|
+
error: normalizedError.message
|
|
4874
|
+
});
|
|
4507
4875
|
}
|
|
4508
4876
|
async abort() {
|
|
4509
4877
|
this.abortRequested = true;
|
|
@@ -4558,7 +4926,7 @@ var Agent = class {
|
|
|
4558
4926
|
* second `setup()` against the same sandbox does ~one round-trip of
|
|
4559
4927
|
* work.
|
|
4560
4928
|
*/
|
|
4561
|
-
async setup(
|
|
4929
|
+
async setup() {
|
|
4562
4930
|
if (this.setupPromise) {
|
|
4563
4931
|
await this.setupPromise;
|
|
4564
4932
|
return;
|
|
@@ -4568,8 +4936,7 @@ var Agent = class {
|
|
|
4568
4936
|
this.setupPromise = (async () => {
|
|
4569
4937
|
await this.adapter.setup({
|
|
4570
4938
|
provider: this.provider,
|
|
4571
|
-
options: this.options
|
|
4572
|
-
config
|
|
4939
|
+
options: this.options
|
|
4573
4940
|
});
|
|
4574
4941
|
debugAgent(
|
|
4575
4942
|
"setup() returned provider=%s after %dms",
|
|
@@ -4585,6 +4952,17 @@ var Agent = class {
|
|
|
4585
4952
|
}
|
|
4586
4953
|
}
|
|
4587
4954
|
stream(runConfig) {
|
|
4955
|
+
if (runConfig.resumeSessionId && runConfig.forkSessionId) {
|
|
4956
|
+
throw new Error(
|
|
4957
|
+
"AgentRunConfig.resumeSessionId and forkSessionId are mutually exclusive."
|
|
4958
|
+
);
|
|
4959
|
+
}
|
|
4960
|
+
if (runConfig.forkSessionId && !runConfig.forkAtMessageId) {
|
|
4961
|
+
throw new Error("AgentRunConfig.forkSessionId requires forkAtMessageId.");
|
|
4962
|
+
}
|
|
4963
|
+
if (runConfig.forkAtMessageId && !runConfig.forkSessionId) {
|
|
4964
|
+
throw new Error("AgentRunConfig.forkAtMessageId requires forkSessionId.");
|
|
4965
|
+
}
|
|
4588
4966
|
const runId = runConfig.runId ?? randomUUID2();
|
|
4589
4967
|
const streamCalledAt = Date.now();
|
|
4590
4968
|
debugAgent("stream() provider=%s runId=%s", this.provider, runId);
|