agentbox-sdk 0.1.0 → 0.1.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/README.md +29 -14
- package/dist/{Sandbox-DTprxRZf.d.ts → Sandbox-BQX-sWzs.d.ts} +49 -6
- package/dist/agents/index.d.ts +24 -4
- package/dist/agents/index.js +13 -4
- package/dist/chunk-2NKMDGYH.js +18 -0
- package/dist/{chunk-BW43ESRM.js → chunk-G27423WX.js} +293 -309
- package/dist/{chunk-HMBWQSVN.js → chunk-O7HCJXKW.js} +28 -1
- package/dist/{chunk-QRQFQTGH.js → chunk-X7AWPYDK.js} +401 -13
- package/dist/cli.js +16 -8
- package/dist/enums.d.ts +25 -0
- package/dist/enums.js +8 -0
- package/dist/events/index.d.ts +4 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +15 -4
- package/dist/sandboxes/index.d.ts +12 -2
- package/dist/sandboxes/index.js +7 -3
- package/dist/{types-BwcoN0n-.d.ts → types-Et22oPap.d.ts} +3 -2
- package/package.json +9 -2
- /package/dist/{chunk-JFDP556Q.js → chunk-NSJM57Z4.js} +0 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
toAISDKStream
|
|
5
5
|
} from "./chunk-7FLLQJ6J.js";
|
|
6
6
|
import {
|
|
7
|
+
AGENT_RESERVED_PORTS,
|
|
7
8
|
AgentBoxError,
|
|
8
9
|
AsyncQueue,
|
|
9
10
|
UnsupportedProviderError,
|
|
@@ -12,10 +13,14 @@ import {
|
|
|
12
13
|
linesFromTextChunks,
|
|
13
14
|
sleep,
|
|
14
15
|
waitFor
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-O7HCJXKW.js";
|
|
16
17
|
import {
|
|
17
18
|
shellQuote
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NSJM57Z4.js";
|
|
20
|
+
import {
|
|
21
|
+
AgentProvider,
|
|
22
|
+
SandboxProvider
|
|
23
|
+
} from "./chunk-2NKMDGYH.js";
|
|
19
24
|
|
|
20
25
|
// src/agents/Agent.ts
|
|
21
26
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
@@ -87,7 +92,7 @@ async function resolveUserInputParts(input) {
|
|
|
87
92
|
}
|
|
88
93
|
async function validateProviderUserInput(provider, input) {
|
|
89
94
|
const parts = await resolveUserInputParts(input);
|
|
90
|
-
if (provider ===
|
|
95
|
+
if (provider === AgentProvider.Codex) {
|
|
91
96
|
const unsupportedPart = parts.find((part) => part.type === "file");
|
|
92
97
|
if (unsupportedPart) {
|
|
93
98
|
throw new AgentBoxError(
|
|
@@ -103,7 +108,7 @@ async function validateProviderUserInput(provider, input) {
|
|
|
103
108
|
}
|
|
104
109
|
return parts;
|
|
105
110
|
}
|
|
106
|
-
if (provider ===
|
|
111
|
+
if (provider === AgentProvider.ClaudeCode) {
|
|
107
112
|
for (const part of parts) {
|
|
108
113
|
if (part.type === "image") {
|
|
109
114
|
if (!CLAUDE_IMAGE_MEDIA_TYPES.has(part.mediaType)) {
|
|
@@ -514,7 +519,7 @@ function assertCommandsSupported(provider, commands) {
|
|
|
514
519
|
if (!commands || commands.length === 0) {
|
|
515
520
|
return;
|
|
516
521
|
}
|
|
517
|
-
if (provider ===
|
|
522
|
+
if (provider === AgentProvider.Codex) {
|
|
518
523
|
throw new Error(
|
|
519
524
|
"Custom commands are not supported for Codex in this package yet."
|
|
520
525
|
);
|
|
@@ -550,10 +555,10 @@ function readProviderPlugins(options) {
|
|
|
550
555
|
return options.provider?.plugins;
|
|
551
556
|
}
|
|
552
557
|
function legacySharedHooksError(provider) {
|
|
553
|
-
return provider ===
|
|
558
|
+
return provider === AgentProvider.OpenCode ? "OpenCode hook plugins must be configured on options.provider.plugins. The shared options.hooks field was removed because hook semantics differ by provider." : `${provider === AgentProvider.ClaudeCode ? "Claude Code" : "Codex"} hooks must be configured on options.provider.hooks. The shared options.hooks field was removed because hook semantics differ by provider.`;
|
|
554
559
|
}
|
|
555
560
|
function invalidGroupedHooksShapeError(provider) {
|
|
556
|
-
return `${provider ===
|
|
561
|
+
return `${provider === AgentProvider.ClaudeCode ? "Claude Code" : "Codex"} hooks must use the native grouped hooks object shape under options.provider.hooks, with each event mapped to an array of matcher groups.`;
|
|
557
562
|
}
|
|
558
563
|
function hasMalformedGroupedHookEntries(hooks) {
|
|
559
564
|
return Object.values(hooks).some(
|
|
@@ -644,7 +649,7 @@ function assertHooksSupported(provider, options) {
|
|
|
644
649
|
}
|
|
645
650
|
const providerHooks = readProviderHooks(options);
|
|
646
651
|
const providerPlugins = readProviderPlugins(options);
|
|
647
|
-
if (provider ===
|
|
652
|
+
if (provider === AgentProvider.OpenCode) {
|
|
648
653
|
if (providerHooks !== void 0) {
|
|
649
654
|
throw new Error(opencodeHooksFieldError());
|
|
650
655
|
}
|
|
@@ -1033,18 +1038,17 @@ async function createRuntimeTarget(provider, runId, options) {
|
|
|
1033
1038
|
import path6 from "path";
|
|
1034
1039
|
function getSkillTargetDir(provider, layout, skillName) {
|
|
1035
1040
|
switch (provider) {
|
|
1036
|
-
case
|
|
1041
|
+
case AgentProvider.ClaudeCode:
|
|
1037
1042
|
return path6.join(layout.claudeDir, "skills", skillName);
|
|
1038
|
-
case
|
|
1043
|
+
case AgentProvider.OpenCode:
|
|
1039
1044
|
return path6.join(layout.opencodeDir, "skills", skillName);
|
|
1040
|
-
case
|
|
1045
|
+
case AgentProvider.Codex:
|
|
1041
1046
|
return path6.join(layout.agentsDir, "skills", skillName);
|
|
1042
1047
|
}
|
|
1043
1048
|
}
|
|
1044
1049
|
function buildSkillsInstallerCommand(provider, skill) {
|
|
1045
1050
|
const repo = skill.repo ?? "https://github.com/anthropics/skills";
|
|
1046
|
-
|
|
1047
|
-
return `npx skills add ${shellQuote(repo)} -g --skill ${shellQuote(skill.name)} --agent ${shellQuote(agent)} -y`;
|
|
1051
|
+
return `npx skills add ${shellQuote(repo)} -g --skill ${shellQuote(skill.name)} --agent ${shellQuote(provider)} -y`;
|
|
1048
1052
|
}
|
|
1049
1053
|
async function prepareSkillArtifacts(provider, skills, layout) {
|
|
1050
1054
|
const artifacts = [];
|
|
@@ -1369,10 +1373,12 @@ var SharedSdkWsChannel = class {
|
|
|
1369
1373
|
};
|
|
1370
1374
|
var MAX_PENDING_MESSAGES_PER_RUN = 1e3;
|
|
1371
1375
|
var SharedSdkWsConnection = class {
|
|
1372
|
-
constructor(url) {
|
|
1376
|
+
constructor(url, headers = {}) {
|
|
1373
1377
|
this.url = url;
|
|
1378
|
+
this.headers = headers;
|
|
1374
1379
|
}
|
|
1375
1380
|
url;
|
|
1381
|
+
headers;
|
|
1376
1382
|
socket;
|
|
1377
1383
|
channels = /* @__PURE__ */ new Map();
|
|
1378
1384
|
pendingMessages = /* @__PURE__ */ new Map();
|
|
@@ -1380,7 +1386,7 @@ var SharedSdkWsConnection = class {
|
|
|
1380
1386
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
1381
1387
|
return;
|
|
1382
1388
|
}
|
|
1383
|
-
const socket = new WebSocket(this.url);
|
|
1389
|
+
const socket = new WebSocket(this.url, { headers: this.headers });
|
|
1384
1390
|
this.socket = socket;
|
|
1385
1391
|
socket.on("message", (data) => {
|
|
1386
1392
|
const lines = data.toString().split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -1512,7 +1518,7 @@ var REMOTE_SDK_RELAY_PATH = "/tmp/agentbox/claude-code/relay.mjs";
|
|
|
1512
1518
|
var sharedRemoteConnectionBySandbox = /* @__PURE__ */ new WeakMap();
|
|
1513
1519
|
function toRawEvent(runId, payload, type) {
|
|
1514
1520
|
return {
|
|
1515
|
-
provider:
|
|
1521
|
+
provider: AgentProvider.ClaudeCode,
|
|
1516
1522
|
runId,
|
|
1517
1523
|
type,
|
|
1518
1524
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1990,16 +1996,16 @@ function toClaudeRelayUrl(port, runId) {
|
|
|
1990
1996
|
return parsed.toString();
|
|
1991
1997
|
}
|
|
1992
1998
|
function buildLocalSdkUrl(server, sandboxProvider) {
|
|
1993
|
-
if (sandboxProvider ===
|
|
1999
|
+
if (sandboxProvider === SandboxProvider.LocalDocker) {
|
|
1994
2000
|
return server.url.replace("127.0.0.1", "host.docker.internal").replace("0.0.0.0", "host.docker.internal");
|
|
1995
2001
|
}
|
|
1996
2002
|
return server.url;
|
|
1997
2003
|
}
|
|
1998
|
-
async function connectRemoteTransport(url) {
|
|
2004
|
+
async function connectRemoteTransport(url, headers = {}) {
|
|
1999
2005
|
const startedAt = Date.now();
|
|
2000
2006
|
let lastError;
|
|
2001
2007
|
while (Date.now() - startedAt < 3e4) {
|
|
2002
|
-
const client = new SharedSdkWsConnection(url);
|
|
2008
|
+
const client = new SharedSdkWsConnection(url, headers);
|
|
2003
2009
|
try {
|
|
2004
2010
|
await Promise.race([
|
|
2005
2011
|
client.start(),
|
|
@@ -2018,11 +2024,11 @@ async function connectRemoteTransport(url) {
|
|
|
2018
2024
|
}
|
|
2019
2025
|
throw lastError ?? new Error(`Could not connect to remote SDK bridge at ${url}.`);
|
|
2020
2026
|
}
|
|
2021
|
-
async function canConnectToRemoteRelay(previewUrl) {
|
|
2027
|
+
async function canConnectToRemoteRelay(previewUrl, headers = {}) {
|
|
2022
2028
|
const parsed = new URL(toWebSocketUrl(previewUrl));
|
|
2023
2029
|
parsed.searchParams.set("role", "claude");
|
|
2024
2030
|
parsed.searchParams.set("runId", "__probe__");
|
|
2025
|
-
const client = new SharedSdkWsConnection(parsed.toString());
|
|
2031
|
+
const client = new SharedSdkWsConnection(parsed.toString(), headers);
|
|
2026
2032
|
try {
|
|
2027
2033
|
await Promise.race([
|
|
2028
2034
|
client.start(),
|
|
@@ -2056,7 +2062,7 @@ async function ensureSharedRemoteConnection(sandbox, previewUrl) {
|
|
|
2056
2062
|
}
|
|
2057
2063
|
const created = (async () => {
|
|
2058
2064
|
const url = toSharedHostWebSocketUrl(previewUrl);
|
|
2059
|
-
const connection = await connectRemoteTransport(url);
|
|
2065
|
+
const connection = await connectRemoteTransport(url, sandbox.previewHeaders);
|
|
2060
2066
|
return { previewUrl, connection };
|
|
2061
2067
|
})();
|
|
2062
2068
|
sharedRemoteConnectionBySandbox.set(key, created);
|
|
@@ -2071,7 +2077,8 @@ async function ensureRemoteRelay(request, prepared) {
|
|
|
2071
2077
|
const sandbox = request.options.sandbox;
|
|
2072
2078
|
await sandbox.openPort(REMOTE_SDK_RELAY_PORT);
|
|
2073
2079
|
const previewUrl = await sandbox.getPreviewLink(REMOTE_SDK_RELAY_PORT);
|
|
2074
|
-
|
|
2080
|
+
const previewHeaders = sandbox.previewHeaders;
|
|
2081
|
+
if (await canConnectToRemoteRelay(previewUrl, previewHeaders)) {
|
|
2075
2082
|
return {
|
|
2076
2083
|
relayPort: REMOTE_SDK_RELAY_PORT,
|
|
2077
2084
|
relayPath: REMOTE_SDK_RELAY_PATH,
|
|
@@ -2102,7 +2109,7 @@ async function ensureRemoteRelay(request, prepared) {
|
|
|
2102
2109
|
});
|
|
2103
2110
|
const startedAt = Date.now();
|
|
2104
2111
|
while (Date.now() - startedAt < 3e4) {
|
|
2105
|
-
if (await canConnectToRemoteRelay(previewUrl)) {
|
|
2112
|
+
if (await canConnectToRemoteRelay(previewUrl, previewHeaders)) {
|
|
2106
2113
|
return {
|
|
2107
2114
|
relayPort: REMOTE_SDK_RELAY_PORT,
|
|
2108
2115
|
relayPath: REMOTE_SDK_RELAY_PATH,
|
|
@@ -2121,7 +2128,7 @@ async function ensureRemoteRelay(request, prepared) {
|
|
|
2121
2128
|
async function createLocalRuntime(request, prepared) {
|
|
2122
2129
|
const sandboxProvider = request.options.sandbox?.provider;
|
|
2123
2130
|
const transport = new SdkWsServer({
|
|
2124
|
-
host: sandboxProvider ===
|
|
2131
|
+
host: sandboxProvider === SandboxProvider.LocalDocker ? "0.0.0.0" : "127.0.0.1"
|
|
2125
2132
|
});
|
|
2126
2133
|
await transport.start();
|
|
2127
2134
|
const args = prepared.buildArgs(buildLocalSdkUrl(transport, sandboxProvider));
|
|
@@ -2198,7 +2205,7 @@ async function createRemoteSandboxRuntime(request, prepared) {
|
|
|
2198
2205
|
};
|
|
2199
2206
|
}
|
|
2200
2207
|
async function createRuntime(request) {
|
|
2201
|
-
if (request.options.sandbox && request.options.sandbox.provider !==
|
|
2208
|
+
if (request.options.sandbox && request.options.sandbox.provider !== SandboxProvider.LocalDocker) {
|
|
2202
2209
|
await request.options.sandbox.openPort(REMOTE_SDK_RELAY_PORT);
|
|
2203
2210
|
const prepared2 = await prepareClaudeRuntime(request);
|
|
2204
2211
|
return createRemoteSandboxRuntime(request, prepared2);
|
|
@@ -2206,36 +2213,6 @@ async function createRuntime(request) {
|
|
|
2206
2213
|
const prepared = await prepareClaudeRuntime(request);
|
|
2207
2214
|
return createLocalRuntime(request, prepared);
|
|
2208
2215
|
}
|
|
2209
|
-
function buildDirectClaudeArgs(buildArgs, prompt) {
|
|
2210
|
-
const args = buildArgs("ws://127.0.0.1:9/");
|
|
2211
|
-
const directArgs = [];
|
|
2212
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
2213
|
-
const current = args[index];
|
|
2214
|
-
if (current === void 0) {
|
|
2215
|
-
continue;
|
|
2216
|
-
}
|
|
2217
|
-
if (current === "--sdk-url" || current === "--input-format") {
|
|
2218
|
-
index += 1;
|
|
2219
|
-
continue;
|
|
2220
|
-
}
|
|
2221
|
-
directArgs.push(current);
|
|
2222
|
-
}
|
|
2223
|
-
if (!directArgs.includes("--verbose")) {
|
|
2224
|
-
const printIndex = directArgs.indexOf("--print");
|
|
2225
|
-
if (printIndex === -1) {
|
|
2226
|
-
directArgs.unshift("--verbose");
|
|
2227
|
-
} else {
|
|
2228
|
-
directArgs.splice(printIndex + 1, 0, "--verbose");
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
const promptIndex = directArgs.lastIndexOf("-p");
|
|
2232
|
-
if (promptIndex !== -1 && promptIndex + 1 < directArgs.length) {
|
|
2233
|
-
directArgs[promptIndex + 1] = prompt;
|
|
2234
|
-
} else {
|
|
2235
|
-
directArgs.push("-p", prompt);
|
|
2236
|
-
}
|
|
2237
|
-
return directArgs;
|
|
2238
|
-
}
|
|
2239
2216
|
var ClaudeCodeAgentAdapter = class {
|
|
2240
2217
|
async execute(request, sink) {
|
|
2241
2218
|
const inputParts = await validateProviderUserInput(
|
|
@@ -2243,203 +2220,42 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2243
2220
|
request.run.input
|
|
2244
2221
|
);
|
|
2245
2222
|
const userContent = mapToClaudeUserContent(inputParts);
|
|
2246
|
-
if (request.options.sandbox?.provider === "e2b" && typeof userContent === "string" && !request.run.systemPrompt && !request.options.subAgents?.length) {
|
|
2247
|
-
const prepared = await prepareClaudeRuntime(request);
|
|
2248
|
-
const args = buildDirectClaudeArgs(prepared.buildArgs, userContent);
|
|
2249
|
-
const handle = await request.options.sandbox.runAsync(
|
|
2250
|
-
[request.options.provider?.binary ?? "claude", ...args],
|
|
2251
|
-
{
|
|
2252
|
-
cwd: request.options.cwd,
|
|
2253
|
-
env: {
|
|
2254
|
-
...prepared.env,
|
|
2255
|
-
IS_SANDBOX: "1"
|
|
2256
|
-
},
|
|
2257
|
-
timeoutMs: 0
|
|
2258
|
-
}
|
|
2259
|
-
);
|
|
2260
|
-
sink.setRaw({
|
|
2261
|
-
handle,
|
|
2262
|
-
layout: prepared.target.layout,
|
|
2263
|
-
mode: "e2b-direct"
|
|
2264
|
-
});
|
|
2265
|
-
sink.setAbort(async () => {
|
|
2266
|
-
await handle.kill().catch(() => void 0);
|
|
2267
|
-
await handle.wait().catch(() => void 0);
|
|
2268
|
-
await prepared.target.cleanup().catch(() => void 0);
|
|
2269
|
-
});
|
|
2270
|
-
sink.emitEvent(
|
|
2271
|
-
createNormalizedEvent("run.started", {
|
|
2272
|
-
provider: request.provider,
|
|
2273
|
-
runId: request.runId
|
|
2274
|
-
})
|
|
2275
|
-
);
|
|
2276
|
-
const completion2 = new Promise((resolve, reject) => {
|
|
2277
|
-
let accumulatedText2 = "";
|
|
2278
|
-
async function* stdoutChunks() {
|
|
2279
|
-
for await (const event of handle) {
|
|
2280
|
-
if (event.type === "stdout" && event.chunk) {
|
|
2281
|
-
yield event.chunk;
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
void (async () => {
|
|
2286
|
-
for await (const line of linesFromTextChunks(stdoutChunks())) {
|
|
2287
|
-
const trimmed = line.trim();
|
|
2288
|
-
if (!trimmed) {
|
|
2289
|
-
continue;
|
|
2290
|
-
}
|
|
2291
|
-
let message;
|
|
2292
|
-
try {
|
|
2293
|
-
message = JSON.parse(trimmed);
|
|
2294
|
-
} catch {
|
|
2295
|
-
continue;
|
|
2296
|
-
}
|
|
2297
|
-
sink.emitRaw(toRawEvent(request.runId, message, message.type));
|
|
2298
|
-
if (message.type === "system" && message.subtype === "init") {
|
|
2299
|
-
const sessionId2 = String(message.session_id ?? "");
|
|
2300
|
-
if (sessionId2) {
|
|
2301
|
-
sink.setSessionId(sessionId2);
|
|
2302
|
-
}
|
|
2303
|
-
sink.emitEvent(
|
|
2304
|
-
createNormalizedEvent("message.started", {
|
|
2305
|
-
provider: request.provider,
|
|
2306
|
-
runId: request.runId
|
|
2307
|
-
})
|
|
2308
|
-
);
|
|
2309
|
-
continue;
|
|
2310
|
-
}
|
|
2311
|
-
if (message.type === "stream_event") {
|
|
2312
|
-
const delta = extractStreamDelta(message);
|
|
2313
|
-
if (delta) {
|
|
2314
|
-
accumulatedText2 += delta;
|
|
2315
|
-
sink.emitEvent(
|
|
2316
|
-
createNormalizedEvent(
|
|
2317
|
-
"text.delta",
|
|
2318
|
-
{
|
|
2319
|
-
provider: request.provider,
|
|
2320
|
-
runId: request.runId
|
|
2321
|
-
},
|
|
2322
|
-
{ delta }
|
|
2323
|
-
)
|
|
2324
|
-
);
|
|
2325
|
-
}
|
|
2326
|
-
continue;
|
|
2327
|
-
}
|
|
2328
|
-
if (message.type === "assistant") {
|
|
2329
|
-
const text = extractAssistantText(message);
|
|
2330
|
-
if (text) {
|
|
2331
|
-
accumulatedText2 = text;
|
|
2332
|
-
sink.emitEvent(
|
|
2333
|
-
createNormalizedEvent(
|
|
2334
|
-
"text.delta",
|
|
2335
|
-
{
|
|
2336
|
-
provider: request.provider,
|
|
2337
|
-
runId: request.runId
|
|
2338
|
-
},
|
|
2339
|
-
{ delta: text }
|
|
2340
|
-
)
|
|
2341
|
-
);
|
|
2342
|
-
}
|
|
2343
|
-
sink.emitEvent(
|
|
2344
|
-
createNormalizedEvent(
|
|
2345
|
-
"message.completed",
|
|
2346
|
-
{
|
|
2347
|
-
provider: request.provider,
|
|
2348
|
-
runId: request.runId
|
|
2349
|
-
},
|
|
2350
|
-
{ text }
|
|
2351
|
-
)
|
|
2352
|
-
);
|
|
2353
|
-
continue;
|
|
2354
|
-
}
|
|
2355
|
-
if (message.type === "result") {
|
|
2356
|
-
if (String(message.subtype ?? "success") === "success") {
|
|
2357
|
-
resolve({ text: accumulatedText2 });
|
|
2358
|
-
} else {
|
|
2359
|
-
reject(
|
|
2360
|
-
new Error(
|
|
2361
|
-
String(
|
|
2362
|
-
message.result ?? message.error ?? "Claude Code run failed."
|
|
2363
|
-
)
|
|
2364
|
-
)
|
|
2365
|
-
);
|
|
2366
|
-
}
|
|
2367
|
-
return;
|
|
2368
|
-
}
|
|
2369
|
-
if (message.type === "auth_status" && message.authenticated === false) {
|
|
2370
|
-
reject(
|
|
2371
|
-
new Error("Claude Code reported an authentication failure.")
|
|
2372
|
-
);
|
|
2373
|
-
return;
|
|
2374
|
-
}
|
|
2375
|
-
if (message.type === "control_request") {
|
|
2376
|
-
reject(
|
|
2377
|
-
new Error(
|
|
2378
|
-
"Claude Code direct E2B mode does not yet support interactive control requests."
|
|
2379
|
-
)
|
|
2380
|
-
);
|
|
2381
|
-
return;
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
const result = await handle.wait().catch((error) => error);
|
|
2385
|
-
reject(
|
|
2386
|
-
new Error(
|
|
2387
|
-
result instanceof Error ? String(result) : "Claude Code direct E2B mode ended before returning a result."
|
|
2388
|
-
)
|
|
2389
|
-
);
|
|
2390
|
-
})().catch(reject);
|
|
2391
|
-
});
|
|
2392
|
-
try {
|
|
2393
|
-
const { text } = await completion2;
|
|
2394
|
-
await handle.wait().catch(() => void 0);
|
|
2395
|
-
sink.emitEvent(
|
|
2396
|
-
createNormalizedEvent(
|
|
2397
|
-
"run.completed",
|
|
2398
|
-
{ provider: request.provider, runId: request.runId },
|
|
2399
|
-
{ text }
|
|
2400
|
-
)
|
|
2401
|
-
);
|
|
2402
|
-
sink.complete({ text });
|
|
2403
|
-
} catch (error) {
|
|
2404
|
-
await handle.kill().catch(() => void 0);
|
|
2405
|
-
await handle.wait().catch(() => void 0);
|
|
2406
|
-
sink.fail(error);
|
|
2407
|
-
} finally {
|
|
2408
|
-
await prepared.target.cleanup().catch(() => void 0);
|
|
2409
|
-
}
|
|
2410
|
-
return async () => {
|
|
2411
|
-
await handle.kill().catch(() => void 0);
|
|
2412
|
-
await handle.wait().catch(() => void 0);
|
|
2413
|
-
};
|
|
2414
|
-
}
|
|
2415
|
-
const runtime = await createRuntime(request);
|
|
2416
|
-
sink.setRaw(runtime.raw);
|
|
2417
|
-
sink.setAbort(runtime.cleanup);
|
|
2418
|
-
sink.emitEvent(
|
|
2419
|
-
createNormalizedEvent("run.started", {
|
|
2420
|
-
provider: request.provider,
|
|
2421
|
-
runId: request.runId
|
|
2422
|
-
})
|
|
2423
|
-
);
|
|
2424
2223
|
let sessionId = "";
|
|
2425
2224
|
let accumulatedText = "";
|
|
2426
2225
|
let usedStreaming = false;
|
|
2427
2226
|
let pendingMessages = 1;
|
|
2428
2227
|
const autoApproveTools = shouldAutoApproveClaudeTools(request.options);
|
|
2228
|
+
const transportRef = {};
|
|
2229
|
+
const queuedSends = [];
|
|
2429
2230
|
sink.onMessage(async (content) => {
|
|
2430
2231
|
pendingMessages++;
|
|
2431
2232
|
const parts = await validateProviderUserInput(request.provider, content);
|
|
2432
2233
|
const mapped = mapToClaudeUserContent(parts);
|
|
2433
2234
|
accumulatedText = "";
|
|
2434
2235
|
usedStreaming = false;
|
|
2435
|
-
|
|
2236
|
+
const payload = {
|
|
2436
2237
|
type: "user",
|
|
2437
2238
|
message: { role: "user", content: mapped },
|
|
2438
2239
|
parent_tool_use_id: null,
|
|
2439
2240
|
session_id: sessionId || request.run.resumeSessionId || "",
|
|
2440
2241
|
uuid: randomUUID2()
|
|
2441
|
-
}
|
|
2242
|
+
};
|
|
2243
|
+
if (transportRef.current) {
|
|
2244
|
+
await transportRef.current.send(payload);
|
|
2245
|
+
} else {
|
|
2246
|
+
queuedSends.push(payload);
|
|
2247
|
+
}
|
|
2442
2248
|
});
|
|
2249
|
+
const runtime = await createRuntime(request);
|
|
2250
|
+
transportRef.current = runtime.transport;
|
|
2251
|
+
sink.setRaw(runtime.raw);
|
|
2252
|
+
sink.setAbort(runtime.cleanup);
|
|
2253
|
+
sink.emitEvent(
|
|
2254
|
+
createNormalizedEvent("run.started", {
|
|
2255
|
+
provider: request.provider,
|
|
2256
|
+
runId: request.runId
|
|
2257
|
+
})
|
|
2258
|
+
);
|
|
2443
2259
|
const completion = new Promise((resolve, reject) => {
|
|
2444
2260
|
void (async () => {
|
|
2445
2261
|
for await (const message of runtime.transport.messages()) {
|
|
@@ -2599,6 +2415,9 @@ var ClaudeCodeAgentAdapter = class {
|
|
|
2599
2415
|
runId: request.runId
|
|
2600
2416
|
})
|
|
2601
2417
|
);
|
|
2418
|
+
for (const queued of queuedSends.splice(0)) {
|
|
2419
|
+
await runtime.transport.send(queued);
|
|
2420
|
+
}
|
|
2602
2421
|
const { text } = await completion;
|
|
2603
2422
|
sink.emitEvent(
|
|
2604
2423
|
createNormalizedEvent(
|
|
@@ -2631,7 +2450,21 @@ async function fetchJson(url, init) {
|
|
|
2631
2450
|
if (!response.ok) {
|
|
2632
2451
|
throw new Error(`Request to ${url} failed with ${response.status}.`);
|
|
2633
2452
|
}
|
|
2634
|
-
|
|
2453
|
+
const text = await response.text();
|
|
2454
|
+
if (text.length === 0) {
|
|
2455
|
+
throw new Error(
|
|
2456
|
+
`Request to ${url} returned status ${response.status} with an empty body.`
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
try {
|
|
2460
|
+
return JSON.parse(text);
|
|
2461
|
+
} catch (error) {
|
|
2462
|
+
const preview = text.length > 200 ? `${text.slice(0, 200)}\u2026` : text;
|
|
2463
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
2464
|
+
throw new Error(
|
|
2465
|
+
`Could not parse JSON response from ${url} (status ${response.status}): ${cause}. Body: ${preview}`
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2635
2468
|
}
|
|
2636
2469
|
async function* streamSse(url, init) {
|
|
2637
2470
|
const response = await fetch(url, init);
|
|
@@ -2672,9 +2505,9 @@ async function* streamSse(url, init) {
|
|
|
2672
2505
|
})();
|
|
2673
2506
|
yield* queue;
|
|
2674
2507
|
}
|
|
2675
|
-
async function connectJsonRpcWebSocket(url) {
|
|
2508
|
+
async function connectJsonRpcWebSocket(url, options) {
|
|
2676
2509
|
const notifications = new AsyncQueue();
|
|
2677
|
-
const socket = new WebSocket2(url);
|
|
2510
|
+
const socket = new WebSocket2(url, { headers: options?.headers });
|
|
2678
2511
|
await new Promise((resolve, reject) => {
|
|
2679
2512
|
const cleanup = () => {
|
|
2680
2513
|
socket.off("open", handleOpen);
|
|
@@ -2817,7 +2650,9 @@ function buildThreadParams(cwd, options, request) {
|
|
|
2817
2650
|
approvalPolicy: isInteractiveApproval(options) ? "untrusted" : "never",
|
|
2818
2651
|
sandbox: buildCodexSandboxMode(options),
|
|
2819
2652
|
serviceName: "agentbox",
|
|
2820
|
-
|
|
2653
|
+
// Persist the rollout on disk so follow-up runs can call `thread/resume`.
|
|
2654
|
+
// `ephemeral: true` threads have no rollout file and resume fails with
|
|
2655
|
+
// "no rollout found for thread id ...".
|
|
2821
2656
|
experimentalRawEvents: true
|
|
2822
2657
|
};
|
|
2823
2658
|
}
|
|
@@ -2834,7 +2669,7 @@ function buildTurnSandboxPolicy(options) {
|
|
|
2834
2669
|
if (!options.sandbox) {
|
|
2835
2670
|
return void 0;
|
|
2836
2671
|
}
|
|
2837
|
-
if (options.sandbox.provider ===
|
|
2672
|
+
if (options.sandbox.provider === SandboxProvider.LocalDocker) {
|
|
2838
2673
|
return {
|
|
2839
2674
|
type: "workspaceWrite",
|
|
2840
2675
|
networkAccess: true
|
|
@@ -2858,7 +2693,7 @@ function buildTurnCollaborationMode(request) {
|
|
|
2858
2693
|
}
|
|
2859
2694
|
function toRawEvent2(runId, payload, type) {
|
|
2860
2695
|
return {
|
|
2861
|
-
provider:
|
|
2696
|
+
provider: AgentProvider.Codex,
|
|
2862
2697
|
runId,
|
|
2863
2698
|
type,
|
|
2864
2699
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2876,7 +2711,7 @@ function buildCodexCommandArgs(binary, args) {
|
|
|
2876
2711
|
}
|
|
2877
2712
|
function toNormalizedCodexEvents(runId, notification) {
|
|
2878
2713
|
const base = {
|
|
2879
|
-
provider:
|
|
2714
|
+
provider: AgentProvider.Codex,
|
|
2880
2715
|
runId,
|
|
2881
2716
|
raw: toRawEvent2(runId, notification, notification.method)
|
|
2882
2717
|
};
|
|
@@ -3070,16 +2905,22 @@ async function materializeCodexImage(target, part, index) {
|
|
|
3070
2905
|
);
|
|
3071
2906
|
return imagePath;
|
|
3072
2907
|
}
|
|
2908
|
+
function resolveCodexOpenAiBaseUrl(request) {
|
|
2909
|
+
return request.options.env?.OPENAI_BASE_URL ?? request.options.provider?.env?.OPENAI_BASE_URL;
|
|
2910
|
+
}
|
|
3073
2911
|
async function ensureCodexLogin(request, target) {
|
|
3074
|
-
const openAiApiKey = request.options.env?.OPENAI_API_KEY;
|
|
3075
|
-
|
|
3076
|
-
|
|
2912
|
+
const openAiApiKey = request.options.env?.OPENAI_API_KEY ?? request.options.provider?.env?.OPENAI_API_KEY;
|
|
2913
|
+
const openAiBaseUrl = resolveCodexOpenAiBaseUrl(request);
|
|
2914
|
+
const extraEnv = {};
|
|
2915
|
+
if (openAiApiKey) {
|
|
2916
|
+
extraEnv.OPENAI_API_KEY = openAiApiKey;
|
|
2917
|
+
}
|
|
2918
|
+
if (openAiBaseUrl) {
|
|
2919
|
+
extraEnv.OPENAI_BASE_URL = openAiBaseUrl;
|
|
3077
2920
|
}
|
|
3078
2921
|
await target.runCommand(
|
|
3079
|
-
'if [ -z "$OPENAI_API_KEY" ]; then exit
|
|
3080
|
-
|
|
3081
|
-
OPENAI_API_KEY: openAiApiKey
|
|
3082
|
-
}
|
|
2922
|
+
'if [ -z "${OPENAI_API_KEY:-}" ]; then exit 0; fi; printenv OPENAI_API_KEY | env -u CODEX_HOME -u XDG_CONFIG_HOME codex login --with-api-key >/dev/null 2>&1',
|
|
2923
|
+
Object.keys(extraEnv).length > 0 ? extraEnv : void 0
|
|
3083
2924
|
);
|
|
3084
2925
|
}
|
|
3085
2926
|
function toRemoteCodexWebSocketUrl(url) {
|
|
@@ -3087,12 +2928,12 @@ function toRemoteCodexWebSocketUrl(url) {
|
|
|
3087
2928
|
parsed.protocol = parsed.protocol === "https:" ? "wss:" : "ws:";
|
|
3088
2929
|
return parsed.toString();
|
|
3089
2930
|
}
|
|
3090
|
-
async function connectRemoteCodexAppServer(url) {
|
|
2931
|
+
async function connectRemoteCodexAppServer(url, headers = {}) {
|
|
3091
2932
|
const startedAt = Date.now();
|
|
3092
2933
|
let lastError;
|
|
3093
2934
|
while (Date.now() - startedAt < 3e4) {
|
|
3094
2935
|
try {
|
|
3095
|
-
return await connectJsonRpcWebSocket(url);
|
|
2936
|
+
return await connectJsonRpcWebSocket(url, { headers });
|
|
3096
2937
|
} catch (error) {
|
|
3097
2938
|
lastError = error;
|
|
3098
2939
|
await sleep(250);
|
|
@@ -3117,7 +2958,7 @@ async function waitForInternalCodexReady(sandbox, port, cwd, env) {
|
|
|
3117
2958
|
}
|
|
3118
2959
|
async function createRuntime2(request, inputParts) {
|
|
3119
2960
|
const options = request.options;
|
|
3120
|
-
const usesRemoteWebSocket = options.sandbox && options.sandbox.provider !==
|
|
2961
|
+
const usesRemoteWebSocket = options.sandbox && options.sandbox.provider !== SandboxProvider.LocalDocker;
|
|
3121
2962
|
const hooks = assertHooksSupported(request.provider, options);
|
|
3122
2963
|
assertCommandsSupported(request.provider, options.commands);
|
|
3123
2964
|
if (usesRemoteWebSocket && options.sandbox) {
|
|
@@ -3167,6 +3008,10 @@ async function createRuntime2(request, inputParts) {
|
|
|
3167
3008
|
}
|
|
3168
3009
|
const configArgs2 = [];
|
|
3169
3010
|
configArgs2.push("-c", `features.multi_agent=${enableMultiAgent2}`);
|
|
3011
|
+
const openAiBaseUrl2 = resolveCodexOpenAiBaseUrl(request);
|
|
3012
|
+
if (openAiBaseUrl2) {
|
|
3013
|
+
configArgs2.push("-c", `openai_base_url=${JSON.stringify(openAiBaseUrl2)}`);
|
|
3014
|
+
}
|
|
3170
3015
|
const binary = options.provider?.binary ?? "codex";
|
|
3171
3016
|
const pidFilePath = path9.posix.join(
|
|
3172
3017
|
sharedTarget.layout.rootDir,
|
|
@@ -3251,7 +3096,8 @@ async function createRuntime2(request, inputParts) {
|
|
|
3251
3096
|
);
|
|
3252
3097
|
inputItems2.push(...buildCodexSkillInputItems(preparedSkills2));
|
|
3253
3098
|
const transport = await connectRemoteCodexAppServer(
|
|
3254
|
-
toRemoteCodexWebSocketUrl(previewUrl)
|
|
3099
|
+
toRemoteCodexWebSocketUrl(previewUrl),
|
|
3100
|
+
sandbox.previewHeaders
|
|
3255
3101
|
);
|
|
3256
3102
|
return {
|
|
3257
3103
|
source: transport.source,
|
|
@@ -3349,6 +3195,10 @@ async function createRuntime2(request, inputParts) {
|
|
|
3349
3195
|
);
|
|
3350
3196
|
}
|
|
3351
3197
|
configArgs.push("-c", `features.multi_agent=${enableMultiAgent}`);
|
|
3198
|
+
const openAiBaseUrl = resolveCodexOpenAiBaseUrl(request);
|
|
3199
|
+
if (openAiBaseUrl) {
|
|
3200
|
+
configArgs.push("-c", `openai_base_url=${JSON.stringify(openAiBaseUrl)}`);
|
|
3201
|
+
}
|
|
3352
3202
|
const textPrompt = joinTextParts(
|
|
3353
3203
|
inputParts.filter(
|
|
3354
3204
|
(part) => part.type === "text"
|
|
@@ -3447,7 +3297,6 @@ var CodexAgentAdapter = class {
|
|
|
3447
3297
|
);
|
|
3448
3298
|
const runtime = await createRuntime2(request, inputParts);
|
|
3449
3299
|
sink.setRaw(runtime.raw);
|
|
3450
|
-
sink.setAbort(runtime.cleanup);
|
|
3451
3300
|
sink.emitEvent(
|
|
3452
3301
|
createNormalizedEvent("run.started", {
|
|
3453
3302
|
provider: request.provider,
|
|
@@ -3462,6 +3311,28 @@ var CodexAgentAdapter = class {
|
|
|
3462
3311
|
let rootThreadId;
|
|
3463
3312
|
let turnId;
|
|
3464
3313
|
let pendingTurns = 1;
|
|
3314
|
+
sink.setAbort(async () => {
|
|
3315
|
+
const threadIdAtAbort = rootThreadId;
|
|
3316
|
+
const turnIdAtAbort = turnId;
|
|
3317
|
+
if (threadIdAtAbort && turnIdAtAbort) {
|
|
3318
|
+
try {
|
|
3319
|
+
await Promise.race([
|
|
3320
|
+
client.request("turn/interrupt", {
|
|
3321
|
+
threadId: threadIdAtAbort,
|
|
3322
|
+
turnId: turnIdAtAbort
|
|
3323
|
+
}),
|
|
3324
|
+
new Promise(
|
|
3325
|
+
(_, reject) => setTimeout(
|
|
3326
|
+
() => reject(new Error("codex turn/interrupt timed out")),
|
|
3327
|
+
3e3
|
|
3328
|
+
)
|
|
3329
|
+
)
|
|
3330
|
+
]);
|
|
3331
|
+
} catch {
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
await runtime.cleanup().catch(() => void 0);
|
|
3335
|
+
});
|
|
3465
3336
|
const sendTurn = async (content) => {
|
|
3466
3337
|
if (!rootThreadId) {
|
|
3467
3338
|
throw new Error("Cannot send message before thread is started.");
|
|
@@ -3598,7 +3469,7 @@ var SANDBOX_OPENCODE_READY_TIMEOUT_MS = 9e4;
|
|
|
3598
3469
|
var SHARED_OPENCODE_TARGET_ID = "shared-opencode-server";
|
|
3599
3470
|
function toRawEvent3(runId, payload, type) {
|
|
3600
3471
|
return {
|
|
3601
|
-
provider:
|
|
3472
|
+
provider: AgentProvider.OpenCode,
|
|
3602
3473
|
runId,
|
|
3603
3474
|
type,
|
|
3604
3475
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3725,6 +3596,7 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3725
3596
|
const options = request.options;
|
|
3726
3597
|
const port = SANDBOX_OPENCODE_PORT;
|
|
3727
3598
|
await sandbox.openPort(port);
|
|
3599
|
+
const previewHeaders = sandbox.previewHeaders;
|
|
3728
3600
|
const healthCheck = await sandbox.run(
|
|
3729
3601
|
`curl -fsS http://127.0.0.1:${port}/global/health >/dev/null 2>&1`,
|
|
3730
3602
|
{ cwd: options.cwd, timeoutMs: 5e3 }
|
|
@@ -3733,6 +3605,7 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3733
3605
|
const baseUrl2 = (await sandbox.getPreviewLink(port)).replace(/\/$/, "");
|
|
3734
3606
|
return {
|
|
3735
3607
|
baseUrl: baseUrl2,
|
|
3608
|
+
previewHeaders,
|
|
3736
3609
|
cleanup: async () => {
|
|
3737
3610
|
},
|
|
3738
3611
|
raw: { baseUrl: baseUrl2, port, reused: true }
|
|
@@ -3806,12 +3679,29 @@ async function ensureSandboxOpenCodeServer(request) {
|
|
|
3806
3679
|
`Could not start OpenCode server: ${launchResult.combinedOutput || launchResult.stderr}`
|
|
3807
3680
|
);
|
|
3808
3681
|
}
|
|
3682
|
+
const readyDeadline = Date.now() + SANDBOX_OPENCODE_READY_TIMEOUT_MS;
|
|
3683
|
+
let ready = false;
|
|
3684
|
+
while (Date.now() < readyDeadline) {
|
|
3685
|
+
const probe = await sandbox.run(
|
|
3686
|
+
`curl -fsS http://127.0.0.1:${port}/global/health >/dev/null 2>&1`,
|
|
3687
|
+
{ cwd: options.cwd, timeoutMs: 5e3 }
|
|
3688
|
+
);
|
|
3689
|
+
if (probe.exitCode === 0) {
|
|
3690
|
+
ready = true;
|
|
3691
|
+
break;
|
|
3692
|
+
}
|
|
3693
|
+
await sleep(500);
|
|
3694
|
+
}
|
|
3695
|
+
if (!ready) {
|
|
3696
|
+
await target.cleanup().catch(() => void 0);
|
|
3697
|
+
throw new Error(
|
|
3698
|
+
`OpenCode server did not become ready within ${SANDBOX_OPENCODE_READY_TIMEOUT_MS}ms.`
|
|
3699
|
+
);
|
|
3700
|
+
}
|
|
3809
3701
|
const baseUrl = (await sandbox.getPreviewLink(port)).replace(/\/$/, "");
|
|
3810
|
-
await waitForHttpReady(`${baseUrl}/global/health`, {
|
|
3811
|
-
timeoutMs: SANDBOX_OPENCODE_READY_TIMEOUT_MS
|
|
3812
|
-
});
|
|
3813
3702
|
return {
|
|
3814
3703
|
baseUrl,
|
|
3704
|
+
previewHeaders,
|
|
3815
3705
|
cleanup: async () => {
|
|
3816
3706
|
await target.cleanup().catch(() => void 0);
|
|
3817
3707
|
},
|
|
@@ -3874,6 +3764,7 @@ async function createLocalRuntime2(request) {
|
|
|
3874
3764
|
await waitForHttpReady(`${baseUrl}/global/health`, { timeoutMs: 2e4 });
|
|
3875
3765
|
return {
|
|
3876
3766
|
baseUrl,
|
|
3767
|
+
previewHeaders: {},
|
|
3877
3768
|
cleanup: async () => {
|
|
3878
3769
|
await processHandle.kill();
|
|
3879
3770
|
await target.cleanup();
|
|
@@ -3893,9 +3784,41 @@ var OpenCodeAgentAdapter = class {
|
|
|
3893
3784
|
request.provider,
|
|
3894
3785
|
request.run.input
|
|
3895
3786
|
);
|
|
3787
|
+
let pendingMessages = 0;
|
|
3788
|
+
let finalText = "";
|
|
3789
|
+
let dispatchError;
|
|
3790
|
+
let resolveAllDone;
|
|
3791
|
+
const allDone = new Promise((resolve) => {
|
|
3792
|
+
resolveAllDone = resolve;
|
|
3793
|
+
});
|
|
3794
|
+
const checkDone = () => {
|
|
3795
|
+
if (pendingMessages === 0) {
|
|
3796
|
+
resolveAllDone();
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
let sendToSession;
|
|
3800
|
+
const queuedParts = [];
|
|
3801
|
+
sink.onMessage(async (content) => {
|
|
3802
|
+
pendingMessages++;
|
|
3803
|
+
try {
|
|
3804
|
+
const parts = await validateProviderUserInput(request.provider, content);
|
|
3805
|
+
const mapped = mapToOpenCodeParts(parts);
|
|
3806
|
+
if (sendToSession) {
|
|
3807
|
+
sendToSession(mapped);
|
|
3808
|
+
} else {
|
|
3809
|
+
queuedParts.push(mapped);
|
|
3810
|
+
}
|
|
3811
|
+
} catch (error) {
|
|
3812
|
+
pendingMessages--;
|
|
3813
|
+
if (!dispatchError) {
|
|
3814
|
+
dispatchError = error;
|
|
3815
|
+
}
|
|
3816
|
+
checkDone();
|
|
3817
|
+
throw error;
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3896
3820
|
const runtime = await createRuntime3(request);
|
|
3897
3821
|
sink.setRaw(runtime.raw);
|
|
3898
|
-
sink.setAbort(runtime.cleanup);
|
|
3899
3822
|
sink.emitEvent(
|
|
3900
3823
|
createNormalizedEvent("run.started", {
|
|
3901
3824
|
provider: request.provider,
|
|
@@ -3904,13 +3827,47 @@ var OpenCodeAgentAdapter = class {
|
|
|
3904
3827
|
);
|
|
3905
3828
|
const sseAbort = new AbortController();
|
|
3906
3829
|
let sseTask;
|
|
3830
|
+
const dispatchAbort = new AbortController();
|
|
3831
|
+
let capturedSessionId;
|
|
3832
|
+
sink.setAbort(async () => {
|
|
3833
|
+
const sessionIdAtAbort = capturedSessionId;
|
|
3834
|
+
if (sessionIdAtAbort) {
|
|
3835
|
+
try {
|
|
3836
|
+
await Promise.race([
|
|
3837
|
+
fetchJson(
|
|
3838
|
+
`${runtime.baseUrl}/session/${sessionIdAtAbort}/abort`,
|
|
3839
|
+
{
|
|
3840
|
+
method: "POST",
|
|
3841
|
+
headers: {
|
|
3842
|
+
"content-type": "application/json",
|
|
3843
|
+
...runtime.previewHeaders
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
),
|
|
3847
|
+
new Promise(
|
|
3848
|
+
(_, reject) => setTimeout(
|
|
3849
|
+
() => reject(
|
|
3850
|
+
new Error("opencode POST /session/abort timed out")
|
|
3851
|
+
),
|
|
3852
|
+
3e3
|
|
3853
|
+
)
|
|
3854
|
+
)
|
|
3855
|
+
]);
|
|
3856
|
+
} catch {
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
dispatchAbort.abort();
|
|
3860
|
+
});
|
|
3907
3861
|
try {
|
|
3908
3862
|
const interactiveApproval = isInteractiveApproval(request.options);
|
|
3909
3863
|
const createdSession = request.run.resumeSessionId ? null : await fetchJson(
|
|
3910
3864
|
`${runtime.baseUrl}/session`,
|
|
3911
3865
|
{
|
|
3912
3866
|
method: "POST",
|
|
3913
|
-
headers: {
|
|
3867
|
+
headers: {
|
|
3868
|
+
"content-type": "application/json",
|
|
3869
|
+
...runtime.previewHeaders
|
|
3870
|
+
},
|
|
3914
3871
|
body: JSON.stringify({
|
|
3915
3872
|
title: `AgentBox ${request.runId}`
|
|
3916
3873
|
})
|
|
@@ -3923,6 +3880,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
3923
3880
|
sseTask = (async () => {
|
|
3924
3881
|
try {
|
|
3925
3882
|
for await (const event of streamSse(`${runtime.baseUrl}/event`, {
|
|
3883
|
+
headers: runtime.previewHeaders,
|
|
3926
3884
|
signal: sseAbort.signal
|
|
3927
3885
|
})) {
|
|
3928
3886
|
let payload = event.data;
|
|
@@ -3945,7 +3903,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
3945
3903
|
raw,
|
|
3946
3904
|
payload
|
|
3947
3905
|
);
|
|
3948
|
-
const
|
|
3906
|
+
const response = interactiveApproval ? await sink.requestPermission(permissionEvent) : {
|
|
3949
3907
|
requestId: permissionEvent.requestId,
|
|
3950
3908
|
decision: "allow"
|
|
3951
3909
|
};
|
|
@@ -3953,9 +3911,12 @@ var OpenCodeAgentAdapter = class {
|
|
|
3953
3911
|
`${runtime.baseUrl}/session/${sessionId}/permissions/${permissionEvent.requestId}`,
|
|
3954
3912
|
{
|
|
3955
3913
|
method: "POST",
|
|
3956
|
-
headers: {
|
|
3914
|
+
headers: {
|
|
3915
|
+
"content-type": "application/json",
|
|
3916
|
+
...runtime.previewHeaders
|
|
3917
|
+
},
|
|
3957
3918
|
body: JSON.stringify({
|
|
3958
|
-
response:
|
|
3919
|
+
response: response.decision === "allow" ? response.remember ? "always" : "once" : "reject"
|
|
3959
3920
|
})
|
|
3960
3921
|
}
|
|
3961
3922
|
);
|
|
@@ -3969,11 +3930,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
3969
3930
|
} catch {
|
|
3970
3931
|
}
|
|
3971
3932
|
})();
|
|
3972
|
-
|
|
3973
|
-
console.warn(
|
|
3974
|
-
"[agentbox] sendMessage is not yet supported for the opencode provider. Use resumeSessionId for follow-ups instead."
|
|
3975
|
-
);
|
|
3976
|
-
});
|
|
3933
|
+
capturedSessionId = sessionId;
|
|
3977
3934
|
sink.setSessionId(sessionId);
|
|
3978
3935
|
sink.emitRaw(
|
|
3979
3936
|
toRawEvent3(
|
|
@@ -3988,39 +3945,67 @@ var OpenCodeAgentAdapter = class {
|
|
|
3988
3945
|
runId: request.runId
|
|
3989
3946
|
})
|
|
3990
3947
|
);
|
|
3991
|
-
const
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
3948
|
+
const dispatchMessage = async (parts) => {
|
|
3949
|
+
try {
|
|
3950
|
+
const response = await fetchJson(
|
|
3951
|
+
`${runtime.baseUrl}/session/${sessionId}/message`,
|
|
3952
|
+
{
|
|
3953
|
+
method: "POST",
|
|
3954
|
+
signal: dispatchAbort.signal,
|
|
3955
|
+
headers: {
|
|
3956
|
+
"content-type": "application/json",
|
|
3957
|
+
...runtime.previewHeaders
|
|
3958
|
+
},
|
|
3959
|
+
body: JSON.stringify({
|
|
3960
|
+
...request.run.model ? { model: toOpenCodeModel(request.run.model) } : {},
|
|
3961
|
+
agent: "agentbox",
|
|
3962
|
+
parts
|
|
3963
|
+
})
|
|
3964
|
+
}
|
|
3965
|
+
);
|
|
3966
|
+
const rawResponse = toRawEvent3(
|
|
3967
|
+
request.runId,
|
|
3968
|
+
response,
|
|
3969
|
+
"message.response"
|
|
3970
|
+
);
|
|
3971
|
+
sink.emitRaw(rawResponse);
|
|
3972
|
+
for (const event of normalizeRawAgentEvent(rawResponse)) {
|
|
3973
|
+
sink.emitEvent(event);
|
|
3974
|
+
}
|
|
3975
|
+
const text = extractText(response);
|
|
3976
|
+
if (text) {
|
|
3977
|
+
finalText = text;
|
|
3978
|
+
sink.emitEvent(
|
|
3979
|
+
createNormalizedEvent(
|
|
3980
|
+
"text.delta",
|
|
3981
|
+
{
|
|
3982
|
+
provider: request.provider,
|
|
3983
|
+
runId: request.runId
|
|
3984
|
+
},
|
|
3985
|
+
{ delta: text }
|
|
3986
|
+
)
|
|
3987
|
+
);
|
|
3988
|
+
}
|
|
3989
|
+
} catch (error) {
|
|
3990
|
+
if (!dispatchError) {
|
|
3991
|
+
dispatchError = error;
|
|
3992
|
+
}
|
|
3993
|
+
} finally {
|
|
3994
|
+
pendingMessages--;
|
|
3995
|
+
checkDone();
|
|
4001
3996
|
}
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
sink.emitRaw(rawResponse);
|
|
4009
|
-
for (const event of normalizeRawAgentEvent(rawResponse)) {
|
|
4010
|
-
sink.emitEvent(event);
|
|
3997
|
+
};
|
|
3998
|
+
sendToSession = (parts) => {
|
|
3999
|
+
void dispatchMessage(parts);
|
|
4000
|
+
};
|
|
4001
|
+
for (const queued of queuedParts.splice(0)) {
|
|
4002
|
+
sendToSession(queued);
|
|
4011
4003
|
}
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
{
|
|
4018
|
-
provider: request.provider,
|
|
4019
|
-
runId: request.runId
|
|
4020
|
-
},
|
|
4021
|
-
{ delta: text }
|
|
4022
|
-
)
|
|
4023
|
-
);
|
|
4004
|
+
pendingMessages++;
|
|
4005
|
+
void dispatchMessage(mapToOpenCodeParts(inputParts));
|
|
4006
|
+
await allDone;
|
|
4007
|
+
if (dispatchError) {
|
|
4008
|
+
throw dispatchError;
|
|
4024
4009
|
}
|
|
4025
4010
|
sink.emitEvent(
|
|
4026
4011
|
createNormalizedEvent(
|
|
@@ -4029,12 +4014,12 @@ var OpenCodeAgentAdapter = class {
|
|
|
4029
4014
|
provider: request.provider,
|
|
4030
4015
|
runId: request.runId
|
|
4031
4016
|
},
|
|
4032
|
-
{ text }
|
|
4017
|
+
{ text: finalText }
|
|
4033
4018
|
)
|
|
4034
4019
|
);
|
|
4035
4020
|
sseAbort.abort();
|
|
4036
4021
|
await sseTask;
|
|
4037
|
-
sink.complete({ text });
|
|
4022
|
+
sink.complete({ text: finalText });
|
|
4038
4023
|
} finally {
|
|
4039
4024
|
sseAbort.abort();
|
|
4040
4025
|
if (sseTask) {
|
|
@@ -4097,21 +4082,20 @@ function buildRunConfig(options, runConfig) {
|
|
|
4097
4082
|
}
|
|
4098
4083
|
function createAdapter(provider) {
|
|
4099
4084
|
switch (provider) {
|
|
4100
|
-
case
|
|
4085
|
+
case AgentProvider.Codex:
|
|
4101
4086
|
return new CodexAgentAdapter();
|
|
4102
|
-
case
|
|
4087
|
+
case AgentProvider.OpenCode:
|
|
4103
4088
|
return new OpenCodeAgentAdapter();
|
|
4104
|
-
case
|
|
4089
|
+
case AgentProvider.ClaudeCode:
|
|
4105
4090
|
return new ClaudeCodeAgentAdapter();
|
|
4106
4091
|
default:
|
|
4107
4092
|
throw new UnsupportedProviderError("agent", provider);
|
|
4108
4093
|
}
|
|
4109
4094
|
}
|
|
4110
4095
|
function prepareAgentOptions(provider, options) {
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
openCodeOptions.sandbox?.openPort(port);
|
|
4096
|
+
const ports = AGENT_RESERVED_PORTS[provider] ?? [];
|
|
4097
|
+
for (const port of ports) {
|
|
4098
|
+
void options.sandbox?.openPort(port);
|
|
4115
4099
|
}
|
|
4116
4100
|
return options;
|
|
4117
4101
|
}
|