agentbox-sdk 0.1.519 → 0.1.520

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 CHANGED
@@ -134,6 +134,22 @@ default 30 minutes, `0` settles at the first turn end as before, `Infinity`
134
134
  waits forever. On expiry the tasks are stopped best-effort and the run
135
135
  completes with the last turn's text.
136
136
 
137
+ ### Event retention
138
+
139
+ `AgentResult.events` and `AgentResult.rawEvents` replay everything a run
140
+ emitted, which means a run holds its whole transcript — every tool result,
141
+ every file the agent read — in memory until it settles. A host that consumes
142
+ the live stream (`for await (const event of run)` / `run.rawEvents()`) never
143
+ reads those arrays, so it can turn retention off:
144
+
145
+ ```ts
146
+ const agent = new Agent("claude-code", { sandbox, retainEvents: false });
147
+ ```
148
+
149
+ Both arrays then settle as `[]`. Streamed events, `text` and `costData` are
150
+ unaffected — cost is accumulated as payloads arrive rather than recomputed
151
+ from a retained transcript.
152
+
137
153
  ### Harness commands
138
154
 
139
155
  A run whose input starts with `/name args` carries the harness's own slash
@@ -1,5 +1,5 @@
1
- import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, ak as RawAgentEvent, b as AgentAttachRequest, B as AttachedRun, ar as SetupLayout, ax as UserContent } from '../types-DjHP7dFq.js';
2
- export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AgentUserAnswer, z as AgentUserQuestion, E as ClaudeCodeAgentOptions, F as ClaudeCodeHookConfig, G as ClaudeCodeHookEvent, H as ClaudeCodeHookHandler, I as ClaudeCodeHookMatcherGroup, J as ClaudeCodeHooksConfig, K as ClaudeCodeProviderOptions, L as CodexAgentOptions, M as CodexCommandHook, N as CodexHookEvent, O as CodexHookMatcherGroup, P as CodexHooksConfig, Q as CodexModelProviderConfig, R as CodexProviderOptions, S as CodexSkillEntry, T as DataContent, U as EmbeddedSkillConfig, V as FilePart, W as HarnessCommandDescriptor, X as HarnessCommandInvocation, Y as HarnessCommandSource, _ as ImagePart, $ as MAX_HARNESS_COMMANDS, a0 as MAX_HARNESS_COMMAND_ARGUMENT_HINT, a1 as MAX_HARNESS_COMMAND_DESCRIPTION, a2 as MAX_HARNESS_COMMAND_NAME, aa as OpenCodeAgentOptions, ab as OpenCodeCommandEntry, ac as OpenCodePluginConfig, ad as OpenCodePluginEvent, ae as OpenCodePluginHookConfig, af as OpenCodeProviderOptions, ag as OpenCodeSkillEntry, ah as OpenRouterPlugin, am as RepoSkillConfig, at as TextPart, ay as UserContentPart, az as builtinHarnessCommands, aA as claudeHarnessCommands, aB as codexHarnessCommands, aC as codexSkillMention, aF as openCodeHarnessCommands, aG as parseHarnessCommandInvocation, aH as skillDirective } from '../types-DjHP7dFq.js';
1
+ import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, ak as RawAgentEvent, b as AgentAttachRequest, B as AttachedRun, ar as SetupLayout, ax as UserContent } from '../types-Bhntrw9V.js';
2
+ export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AgentUserAnswer, z as AgentUserQuestion, E as ClaudeCodeAgentOptions, F as ClaudeCodeHookConfig, G as ClaudeCodeHookEvent, H as ClaudeCodeHookHandler, I as ClaudeCodeHookMatcherGroup, J as ClaudeCodeHooksConfig, K as ClaudeCodeProviderOptions, L as CodexAgentOptions, M as CodexCommandHook, N as CodexHookEvent, O as CodexHookMatcherGroup, P as CodexHooksConfig, Q as CodexModelProviderConfig, R as CodexProviderOptions, S as CodexSkillEntry, T as DataContent, U as EmbeddedSkillConfig, V as FilePart, W as HarnessCommandDescriptor, X as HarnessCommandInvocation, Y as HarnessCommandSource, _ as ImagePart, $ as MAX_HARNESS_COMMANDS, a0 as MAX_HARNESS_COMMAND_ARGUMENT_HINT, a1 as MAX_HARNESS_COMMAND_DESCRIPTION, a2 as MAX_HARNESS_COMMAND_NAME, aa as OpenCodeAgentOptions, ab as OpenCodeCommandEntry, ac as OpenCodePluginConfig, ad as OpenCodePluginEvent, ae as OpenCodePluginHookConfig, af as OpenCodeProviderOptions, ag as OpenCodeSkillEntry, ah as OpenRouterPlugin, am as RepoSkillConfig, at as TextPart, ay as UserContentPart, az as builtinHarnessCommands, aA as claudeHarnessCommands, aB as codexHarnessCommands, aC as codexSkillMention, aF as openCodeHarnessCommands, aG as parseHarnessCommandInvocation, aH as skillDirective } from '../types-Bhntrw9V.js';
3
3
  import { S as Sandbox } from '../Sandbox-DcKAU-E3.js';
4
4
  export { AgentProvider } from '../enums.js';
5
5
  import 'e2b';
@@ -15,12 +15,12 @@ import {
15
15
  parseHarnessCommandInvocation,
16
16
  resolveHarnessCommand,
17
17
  skillDirective
18
- } from "../chunk-REVRD4IY.js";
18
+ } from "../chunk-7PZKMK4U.js";
19
19
  import "../chunk-V4M4LPPT.js";
20
20
  import {
21
21
  AGENT_RESERVED_PORTS,
22
22
  collectAllAgentReservedPorts
23
- } from "../chunk-MTQ2S46C.js";
23
+ } from "../chunk-D4LSWCFA.js";
24
24
  import "../chunk-NSJM57Z4.js";
25
25
  import {
26
26
  AgentProvider
@@ -20,7 +20,7 @@ import {
20
20
  sleep,
21
21
  time,
22
22
  waitFor
23
- } from "./chunk-MTQ2S46C.js";
23
+ } from "./chunk-D4LSWCFA.js";
24
24
  import {
25
25
  shellQuote
26
26
  } from "./chunk-NSJM57Z4.js";
@@ -2034,75 +2034,83 @@ function compactCostData(costData) {
2034
2034
  };
2035
2035
  return Object.keys(compacted).length > 0 ? compacted : null;
2036
2036
  }
2037
- function extractClaudeCostData(events) {
2038
- for (let i = events.length - 1; i >= 0; i--) {
2039
- const event = events[i];
2040
- if (!event) {
2041
- continue;
2042
- }
2043
- if (event.type !== "result") {
2044
- continue;
2045
- }
2046
- const totalCost = typeof event.total_cost_usd === "number" ? event.total_cost_usd : void 0;
2047
- const usage = {};
2048
- const modelUsage = asRecord(event.modelUsage);
2049
- if (modelUsage) {
2050
- for (const value of Object.values(modelUsage)) {
2051
- mergeUsage(usage, asRecord(value));
2037
+ function createClaudeCostAccumulator() {
2038
+ let lastResult;
2039
+ return {
2040
+ add(event) {
2041
+ if (event && event.type === "result") lastResult = event;
2042
+ },
2043
+ result() {
2044
+ const event = lastResult;
2045
+ if (!event) return null;
2046
+ const totalCost = typeof event.total_cost_usd === "number" ? event.total_cost_usd : void 0;
2047
+ const usage = {};
2048
+ const modelUsage = asRecord(event.modelUsage);
2049
+ if (modelUsage) {
2050
+ for (const value of Object.values(modelUsage)) {
2051
+ mergeUsage(usage, asRecord(value));
2052
+ }
2053
+ } else {
2054
+ mergeUsage(usage, asRecord(event.usage));
2052
2055
  }
2053
- } else {
2054
- mergeUsage(usage, asRecord(event.usage));
2055
- }
2056
- return compactCostData({
2057
- ...totalCost !== void 0 ? { total_cost_usd: totalCost } : {},
2058
- duration_ms: typeof event.duration_ms === "number" ? event.duration_ms : void 0,
2059
- duration_api_ms: typeof event.duration_api_ms === "number" ? event.duration_api_ms : void 0,
2060
- num_turns: typeof event.num_turns === "number" ? event.num_turns : void 0,
2061
- usage
2062
- });
2063
- }
2064
- return null;
2056
+ return compactCostData({
2057
+ ...totalCost !== void 0 ? { total_cost_usd: totalCost } : {},
2058
+ duration_ms: typeof event.duration_ms === "number" ? event.duration_ms : void 0,
2059
+ duration_api_ms: typeof event.duration_api_ms === "number" ? event.duration_api_ms : void 0,
2060
+ num_turns: typeof event.num_turns === "number" ? event.num_turns : void 0,
2061
+ usage
2062
+ });
2063
+ }
2064
+ };
2065
2065
  }
2066
- function extractCodexCostData(events) {
2066
+ function createCodexCostAccumulator() {
2067
2067
  const usage = {};
2068
2068
  let sawUsage = false;
2069
- for (const event of events) {
2070
- const params = asRecord(event.params);
2071
- const tokenUsage = asRecord(params?.tokenUsage);
2072
- const turn = asRecord(params?.turn);
2073
- const turnTokenUsage = asRecord(turn?.tokenUsage);
2074
- 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;
2075
- if (usageCandidate) {
2076
- sawUsage = true;
2077
- mergeUsage(usage, usageCandidate);
2069
+ return {
2070
+ add(event) {
2071
+ if (!event) return;
2072
+ const params = asRecord(event.params);
2073
+ const tokenUsage = asRecord(params?.tokenUsage);
2074
+ const turn = asRecord(params?.turn);
2075
+ const turnTokenUsage = asRecord(turn?.tokenUsage);
2076
+ 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;
2077
+ if (usageCandidate) {
2078
+ sawUsage = true;
2079
+ mergeUsage(usage, usageCandidate);
2080
+ }
2081
+ },
2082
+ result() {
2083
+ return sawUsage ? compactCostData({ usage }) : null;
2078
2084
  }
2079
- }
2080
- return sawUsage ? compactCostData({ usage }) : null;
2085
+ };
2081
2086
  }
2082
- function extractOpenCodeCostData(events) {
2087
+ function createOpenCodeCostAccumulator() {
2083
2088
  const usage = {};
2084
2089
  let totalCost = 0;
2085
2090
  let sawCostData = false;
2086
- for (const event of events) {
2087
- const properties = asRecord(event.properties);
2088
- const part = asRecord(properties?.part) ?? asRecord(event.part);
2089
- if (part?.type !== "step-finish") {
2090
- continue;
2091
- }
2092
- if (typeof part.cost === "number") {
2093
- totalCost += part.cost;
2094
- sawCostData = true;
2095
- }
2096
- const tokens = asRecord(part.tokens);
2097
- if (tokens) {
2098
- sawCostData = true;
2099
- mergeUsage(usage, tokens);
2091
+ return {
2092
+ add(event) {
2093
+ if (!event) return;
2094
+ const properties = asRecord(event.properties);
2095
+ const part = asRecord(properties?.part) ?? asRecord(event.part);
2096
+ if (part?.type !== "step-finish") return;
2097
+ if (typeof part.cost === "number") {
2098
+ totalCost += part.cost;
2099
+ sawCostData = true;
2100
+ }
2101
+ const tokens = asRecord(part.tokens);
2102
+ if (tokens) {
2103
+ sawCostData = true;
2104
+ mergeUsage(usage, tokens);
2105
+ }
2106
+ },
2107
+ result() {
2108
+ return sawCostData ? compactCostData({
2109
+ ...totalCost > 0 ? { total_cost_usd: totalCost } : {},
2110
+ usage
2111
+ }) : null;
2100
2112
  }
2101
- }
2102
- return sawCostData ? compactCostData({
2103
- ...totalCost > 0 ? { total_cost_usd: totalCost } : {},
2104
- usage
2105
- }) : null;
2113
+ };
2106
2114
  }
2107
2115
 
2108
2116
  // src/agents/background-tasks.ts
@@ -2362,7 +2370,7 @@ var BackgroundWaitFinish = class {
2362
2370
  };
2363
2371
 
2364
2372
  // src/agents/providers/claude-code.ts
2365
- var DAEMON_PROTOCOL_VERSION = "10";
2373
+ var DAEMON_PROTOCOL_VERSION = "11";
2366
2374
  var DAEMON_PORT = 43180;
2367
2375
  var DAEMON_PATH = "/tmp/agentbox/claude-code/daemon.mjs";
2368
2376
  var DAEMON_LOG_PATH = "/tmp/agentbox/claude-code/daemon.log";
@@ -3037,7 +3045,7 @@ async function handleAbort(_req, res, runId) {
3037
3045
  res.end();
3038
3046
  return;
3039
3047
  }
3040
- await run.query.interrupt().catch(() => {});
3048
+ await run.query?.interrupt().catch(() => {});
3041
3049
  res.writeHead(204);
3042
3050
  res.end();
3043
3051
  }
@@ -3053,6 +3061,20 @@ async function handleDelete(_req, res, runId) {
3053
3061
  res.end();
3054
3062
  }
3055
3063
 
3064
+ // Every route runs through this. A handler that throws must never become an
3065
+ // unhandled rejection: this process owns every live run in the sandbox plus
3066
+ // whatever background work is parked here, and a default-exit would take all
3067
+ // of it down over one bad request.
3068
+ function guard(promise, res) {
3069
+ promise.catch((error) => {
3070
+ console.error("[claude-code-daemon] request failed:", error?.stack ?? error);
3071
+ try {
3072
+ if (!res.headersSent) res.writeHead(500, { "content-type": "text/plain" });
3073
+ if (!res.writableEnded) res.end();
3074
+ } catch {}
3075
+ });
3076
+ }
3077
+
3056
3078
  const server = http.createServer((req, res) => {
3057
3079
  if (req.method === "GET" && req.url === "/__version") {
3058
3080
  res.writeHead(200, { "content-type": "text/plain" });
@@ -3070,42 +3092,58 @@ const server = http.createServer((req, res) => {
3070
3092
  const url = req.url ?? "";
3071
3093
  const permissionRoute = url.match(/^\\/runs\\/([^/]+)\\/permission$/);
3072
3094
  if (req.method === "POST" && permissionRoute) {
3073
- handlePermission(req, res, decodeURIComponent(permissionRoute[1])).catch(() => { if (!res.headersSent) res.writeHead(400); res.end(); });
3095
+ guard(handlePermission(req, res, decodeURIComponent(permissionRoute[1])), res);
3074
3096
  return;
3075
3097
  }
3076
3098
  let m;
3077
3099
  if (req.method === "POST" && (m = url.match(/^\\/runs\\/([^/]+)\\/start$/))) {
3078
- handleStart(req, res, decodeURIComponent(m[1]));
3100
+ guard(handleStart(req, res, decodeURIComponent(m[1])), res);
3079
3101
  return;
3080
3102
  }
3081
3103
  if (req.method === "POST" && (m = url.match(/^\\/runs\\/([^/]+)\\/sendMessage$/))) {
3082
- handleSendMessage(req, res, decodeURIComponent(m[1]));
3104
+ guard(handleSendMessage(req, res, decodeURIComponent(m[1])), res);
3083
3105
  return;
3084
3106
  }
3085
3107
  if (req.method === "POST" && (m = url.match(/^\\/runs\\/([^/]+)\\/abort$/))) {
3086
- handleAbort(req, res, decodeURIComponent(m[1]));
3108
+ guard(handleAbort(req, res, decodeURIComponent(m[1])), res);
3087
3109
  return;
3088
3110
  }
3089
3111
  if (req.method === "POST" && (m = url.match(/^\\/runs\\/([^/]+)\\/park$/))) {
3090
- handlePark(req, res, decodeURIComponent(m[1])).catch(() => { if (!res.headersSent) res.writeHead(400); res.end(); });
3112
+ guard(handlePark(req, res, decodeURIComponent(m[1])), res);
3091
3113
  return;
3092
3114
  }
3093
3115
  if (req.method === "DELETE" && (m = url.match(/^\\/runs\\/([^/]+)$/))) {
3094
- handleDelete(req, res, decodeURIComponent(m[1]));
3116
+ guard(handleDelete(req, res, decodeURIComponent(m[1])), res);
3095
3117
  return;
3096
3118
  }
3097
3119
  res.writeHead(404, { "content-type": "text/plain" });
3098
3120
  res.end("not found");
3099
3121
  });
3100
3122
 
3123
+ server.on("error", (error) => {
3124
+ console.error("[claude-code-daemon] server error:", error?.stack ?? error);
3125
+ });
3126
+
3101
3127
  server.listen(port, "0.0.0.0", () => {
3102
3128
  console.error("[claude-code-daemon] listening on :" + port + " v" + VERSION);
3103
3129
  });
3104
3130
 
3131
+ // Last line of defence. Node's default is to exit on either of these, which
3132
+ // would tear down every live run and every parked CLI in this sandbox over
3133
+ // one stray error (a write to a socket that just died, a malformed frame).
3134
+ // Staying up costs nothing: a run whose own stream is broken still unwinds
3135
+ // through its sink's "close" handler.
3136
+ process.on("unhandledRejection", (reason) => {
3137
+ console.error("[claude-code-daemon] unhandled rejection:", reason?.stack ?? reason);
3138
+ });
3139
+ process.on("uncaughtException", (error) => {
3140
+ console.error("[claude-code-daemon] uncaught exception:", error?.stack ?? error);
3141
+ });
3142
+
3105
3143
  const shutdown = () => {
3106
3144
  for (const r of liveRuns.values()) {
3107
3145
  r.prompt.end();
3108
- r.query.interrupt().catch(() => {});
3146
+ r.query?.interrupt().catch(() => {});
3109
3147
  }
3110
3148
  server.close();
3111
3149
  setTimeout(() => process.exit(0), 100).unref();
@@ -3396,7 +3434,10 @@ var ClaudeCodeAgentAdapter = class {
3396
3434
  const executeStartedAt = Date.now();
3397
3435
  debugClaude("execute() start runId=%s", request.runId);
3398
3436
  const sandbox = request.options.sandbox;
3399
- if (!sandbox) return executeNativeClaude(request, sink);
3437
+ if (!sandbox) {
3438
+ await executeNativeClaude(request, sink);
3439
+ return;
3440
+ }
3400
3441
  const claudeDir = claudeConfigDir(request.options);
3401
3442
  const settingsPath = path8.join(claudeDir, "settings.json");
3402
3443
  const mcpConfigPath = path8.join(claudeDir, "agentbox-mcp.json");
@@ -3538,55 +3579,71 @@ ${serialized}` : serialized;
3538
3579
  )
3539
3580
  );
3540
3581
  const tracker = new BackgroundTaskTracker();
3541
- const permissionMessages = async function* () {
3542
- for await (const item of parseNdjsonStream(response.body)) {
3543
- const control = item;
3544
- if (!control._permission) {
3545
- yield item;
3546
- continue;
3582
+ const pendingReplies = /* @__PURE__ */ new Set();
3583
+ let replyError;
3584
+ const answerPermission = async (ask) => {
3585
+ const isQuestion = ask.toolName === "AskUserQuestion";
3586
+ const isPlan = ask.toolName === "ExitPlanMode";
3587
+ const answer = await sink.requestPermission({
3588
+ type: "permission.requested",
3589
+ provider: request.provider,
3590
+ runId: request.runId,
3591
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3592
+ requestId: ask.requestId,
3593
+ kind: isQuestion ? "question" : isPlan ? "plan" : "tool",
3594
+ toolName: ask.toolName,
3595
+ title: isQuestion ? "Your input is needed" : isPlan ? "Review the plan" : ask.title ?? `Allow ${ask.toolName}?`,
3596
+ input: ask.input,
3597
+ ...isQuestion ? { questions: normalizeUserQuestions("claude-code", ask.input) } : {}
3598
+ });
3599
+ const reply = await fetch(
3600
+ `${baseUrl}/runs/${encodeURIComponent(request.runId)}/permission`,
3601
+ {
3602
+ method: "POST",
3603
+ headers: { "content-type": "application/json", ...authHeaders },
3604
+ signal: fetchAbort.signal,
3605
+ body: JSON.stringify({
3606
+ requestId: ask.requestId,
3607
+ response: answer.decision === "allow" ? {
3608
+ behavior: "allow",
3609
+ updatedInput: isQuestion ? {
3610
+ ...ask.input,
3611
+ answers: questionReply(
3612
+ "claude-code",
3613
+ ask.input,
3614
+ answer.answers ?? []
3615
+ )
3616
+ } : ask.input
3617
+ } : {
3618
+ behavior: "deny",
3619
+ message: "The user declined this request."
3620
+ }
3621
+ })
3547
3622
  }
3548
- const ask = control._permission;
3549
- const isQuestion = ask.toolName === "AskUserQuestion";
3550
- const isPlan = ask.toolName === "ExitPlanMode";
3551
- const answer = await sink.requestPermission({
3552
- type: "permission.requested",
3553
- provider: request.provider,
3554
- runId: request.runId,
3555
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3556
- requestId: ask.requestId,
3557
- kind: isQuestion ? "question" : isPlan ? "plan" : "tool",
3558
- toolName: ask.toolName,
3559
- title: isQuestion ? "Your input is needed" : isPlan ? "Review the plan" : ask.title ?? `Allow ${ask.toolName}?`,
3560
- input: ask.input,
3561
- ...isQuestion ? { questions: normalizeUserQuestions("claude-code", ask.input) } : {}
3562
- });
3563
- const reply = await fetch(
3564
- `${baseUrl}/runs/${encodeURIComponent(request.runId)}/permission`,
3565
- {
3566
- method: "POST",
3567
- headers: { "content-type": "application/json", ...authHeaders },
3568
- signal: fetchAbort.signal,
3569
- body: JSON.stringify({
3570
- requestId: ask.requestId,
3571
- response: answer.decision === "allow" ? {
3572
- behavior: "allow",
3573
- updatedInput: isQuestion ? {
3574
- ...ask.input,
3575
- answers: questionReply(
3576
- "claude-code",
3577
- ask.input,
3578
- answer.answers ?? []
3579
- )
3580
- } : ask.input
3581
- } : {
3582
- behavior: "deny",
3583
- message: "The user declined this request."
3584
- }
3585
- })
3623
+ );
3624
+ if (!reply.ok)
3625
+ throw new Error(`Claude permission response failed: ${reply.status}`);
3626
+ };
3627
+ const permissionMessages = async function* () {
3628
+ try {
3629
+ for await (const item of parseNdjsonStream(response.body)) {
3630
+ if (replyError !== void 0) throw replyError;
3631
+ const control = item;
3632
+ if (!control._permission) {
3633
+ yield item;
3634
+ continue;
3586
3635
  }
3587
- );
3588
- if (!reply.ok)
3589
- throw new Error(`Claude permission response failed: ${reply.status}`);
3636
+ const pending = answerPermission(control._permission).catch(
3637
+ (error) => {
3638
+ if (replyError === void 0 && !cancelled) replyError = error;
3639
+ }
3640
+ );
3641
+ pendingReplies.add(pending);
3642
+ void pending.finally(() => pendingReplies.delete(pending));
3643
+ }
3644
+ if (replyError !== void 0) throw replyError;
3645
+ } finally {
3646
+ await Promise.allSettled([...pendingReplies]);
3590
3647
  }
3591
3648
  };
3592
3649
  const parking = request.options.provider?.parkBackgroundWork;
@@ -3626,7 +3683,6 @@ ${serialized}` : serialized;
3626
3683
  },
3627
3684
  tracker
3628
3685
  );
3629
- return async () => void 0;
3630
3686
  }
3631
3687
  /**
3632
3688
  * Stateless abort. POSTs to the in-sandbox daemon's
@@ -3695,7 +3751,7 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
3695
3751
  let firstTextDeltaLogged = false;
3696
3752
  let lastTerminalReason;
3697
3753
  let lastIsError = false;
3698
- const rawPayloads = [];
3754
+ const cost = createClaudeCostAccumulator();
3699
3755
  const timeoutMs = resolveBackgroundTaskTimeoutMs(
3700
3756
  request.options.backgroundTaskTimeoutMs
3701
3757
  );
@@ -3709,6 +3765,7 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
3709
3765
  let leave = cleanup;
3710
3766
  let foreignResults = 0;
3711
3767
  let nothingParked = false;
3768
+ const queuedCommands = /* @__PURE__ */ new Set();
3712
3769
  let lastTasksKey = JSON.stringify({
3713
3770
  tasks: [],
3714
3771
  waiting: false,
@@ -3817,7 +3874,7 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
3817
3874
  }
3818
3875
  }
3819
3876
  const message = item;
3820
- rawPayloads.push(message);
3877
+ cost.add(message);
3821
3878
  sink.emitRaw(toRawEvent(request.runId, message, message.type));
3822
3879
  if (tracker.ingest(message) && pendingWait) {
3823
3880
  debugClaude(
@@ -3834,6 +3891,15 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
3834
3891
  );
3835
3892
  if (sessionState === "idle" && pendingWait && (tracker.liveTasks().length === 0 || await tryPark()))
3836
3893
  break;
3894
+ if (message.type === "command_lifecycle") {
3895
+ const lifecycle = message;
3896
+ const id = lifecycle.command_uuid;
3897
+ if (id) {
3898
+ if (lifecycle.state === "queued") queuedCommands.add(id);
3899
+ else queuedCommands.delete(id);
3900
+ }
3901
+ continue;
3902
+ }
3837
3903
  if (message.type === "system") {
3838
3904
  const sub = message.subtype;
3839
3905
  if (sub === "init") {
@@ -3959,6 +4025,16 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
3959
4025
  streamedThinkingChars = 0;
3960
4026
  continue;
3961
4027
  }
4028
+ const origin = message.origin;
4029
+ if (origin?.kind === "task-notification" && queuedCommands.size > 0) {
4030
+ debugClaude(
4031
+ "\u2605 notification turn ended while this run's prompt is still queued; not its answer"
4032
+ );
4033
+ sawResult = true;
4034
+ accumulatedText = "";
4035
+ streamedThinkingChars = 0;
4036
+ continue;
4037
+ }
3962
4038
  sawResult = true;
3963
4039
  const result = message;
3964
4040
  lastTerminalReason = result.terminal_reason;
@@ -4028,7 +4104,7 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
4028
4104
  );
4029
4105
  sink.cancel({
4030
4106
  text: finalText,
4031
- costData: extractClaudeCostData(rawPayloads)
4107
+ costData: cost.result()
4032
4108
  });
4033
4109
  } else if (isError) {
4034
4110
  debugClaude(
@@ -4056,7 +4132,7 @@ async function consumeClaudeMessages(request, sink, messages, executeStartedAt,
4056
4132
  );
4057
4133
  sink.complete({
4058
4134
  text: finalText,
4059
- costData: extractClaudeCostData(rawPayloads),
4135
+ costData: cost.result(),
4060
4136
  // Told, not guessed: an attach that found nothing parked ran no turn
4061
4137
  // at all, which from the outside looks exactly like a real tool-only
4062
4138
  // turn that produced no answer text and no usage.
@@ -4278,7 +4354,6 @@ async function executeNativeClaude(request, sink, wait = {}) {
4278
4354
  } finally {
4279
4355
  await stop();
4280
4356
  }
4281
- return stop;
4282
4357
  }
4283
4358
 
4284
4359
  // src/agents/providers/codex.ts
@@ -5570,7 +5645,7 @@ var CodexAgentAdapter = class {
5570
5645
  };
5571
5646
  };
5572
5647
  sink.onMessage(sendTurn);
5573
- const rawPayloads = [];
5648
+ const cost = createCodexCostAccumulator();
5574
5649
  const pendingFileChanges = /* @__PURE__ */ new Map();
5575
5650
  const fileItemKey = (params, itemId) => typeof params?.threadId === "string" && typeof params.turnId === "string" && typeof itemId === "string" ? `${params.threadId}:${params.turnId}:${itemId}` : void 0;
5576
5651
  let streamedText = "";
@@ -5642,7 +5717,7 @@ var CodexAgentAdapter = class {
5642
5717
  );
5643
5718
  }
5644
5719
  const raw = toRawEvent2(request.runId, message, message.method);
5645
- rawPayloads.push(message);
5720
+ cost.add(message);
5646
5721
  sink.emitRaw(raw);
5647
5722
  const item = message.params?.item;
5648
5723
  const itemKey = fileItemKey(message.params, item?.id);
@@ -5808,7 +5883,7 @@ var CodexAgentAdapter = class {
5808
5883
  client.bindThread(threadResponse.thread.id);
5809
5884
  }
5810
5885
  sink.setSessionId(threadResponse.thread.id);
5811
- rawPayloads.push(threadResponse);
5886
+ cost.add(threadResponse);
5812
5887
  sink.emitRaw(
5813
5888
  toRawEvent2(request.runId, threadResponse, threadResultEventName)
5814
5889
  );
@@ -5870,7 +5945,7 @@ var CodexAgentAdapter = class {
5870
5945
  );
5871
5946
  sink.cancel({
5872
5947
  text: streamedText || lastTurn?.text || void 0,
5873
- costData: extractCodexCostData(rawPayloads)
5948
+ costData: cost.result()
5874
5949
  });
5875
5950
  } else {
5876
5951
  sink.fail(completionError);
@@ -5883,21 +5958,20 @@ var CodexAgentAdapter = class {
5883
5958
  Date.now() - executeStartedAt,
5884
5959
  interrupted
5885
5960
  );
5886
- sink.cancel({ text: text2, costData: extractCodexCostData(rawPayloads) });
5961
+ sink.cancel({ text: text2, costData: cost.result() });
5887
5962
  } else {
5888
5963
  debugCodex(
5889
5964
  "\u2605 run.completed (%dms since execute start) chars=%d",
5890
5965
  Date.now() - executeStartedAt,
5891
5966
  text2?.length ?? 0
5892
5967
  );
5893
- sink.complete({ costData: extractCodexCostData(rawPayloads) });
5968
+ sink.complete({ costData: cost.result() });
5894
5969
  }
5895
5970
  }
5896
5971
  } finally {
5897
5972
  pendingWait?.clear();
5898
5973
  await runtime.cleanup().catch(() => void 0);
5899
5974
  }
5900
- return async () => void 0;
5901
5975
  }
5902
5976
  /**
5903
5977
  * Stateless abort. Calls `turn/interrupt` against the in-sandbox
@@ -6650,7 +6724,7 @@ var OpenCodeAgentAdapter = class {
6650
6724
  runId: request.runId
6651
6725
  })
6652
6726
  );
6653
- const rawPayloads = [];
6727
+ const cost = createOpenCodeCostAccumulator();
6654
6728
  const sseAbort = new AbortController();
6655
6729
  let sseTask;
6656
6730
  let capturedSessionId;
@@ -6901,7 +6975,7 @@ var OpenCodeAgentAdapter = class {
6901
6975
  `sse:${event.event ?? "message"}`
6902
6976
  );
6903
6977
  if (payload && typeof payload === "object" && !Array.isArray(payload)) {
6904
- rawPayloads.push(payload);
6978
+ cost.add(payload);
6905
6979
  }
6906
6980
  sink.emitRaw(raw);
6907
6981
  const eventType = typeof payload?.type === "string" ? String(payload.type) : event.event;
@@ -7146,7 +7220,7 @@ var OpenCodeAgentAdapter = class {
7146
7220
  )
7147
7221
  );
7148
7222
  if (createdSession) {
7149
- rawPayloads.push(createdSession);
7223
+ cost.add(createdSession);
7150
7224
  }
7151
7225
  sink.emitEvent(
7152
7226
  createNormalizedEvent("message.started", {
@@ -7325,7 +7399,7 @@ var OpenCodeAgentAdapter = class {
7325
7399
  );
7326
7400
  sink.cancel({
7327
7401
  text: streamedTextFromSse || void 0,
7328
- costData: extractOpenCodeCostData(rawPayloads)
7402
+ costData: cost.result()
7329
7403
  });
7330
7404
  } else if (sessionErrorFromSse) {
7331
7405
  sink.fail(sessionErrorFromSse);
@@ -7366,7 +7440,7 @@ var OpenCodeAgentAdapter = class {
7366
7440
  );
7367
7441
  sink.complete({
7368
7442
  text: lastAssistantText,
7369
- costData: extractOpenCodeCostData(rawPayloads)
7443
+ costData: cost.result()
7370
7444
  });
7371
7445
  } else if (sseSilent) {
7372
7446
  sink.fail(
@@ -7382,7 +7456,6 @@ var OpenCodeAgentAdapter = class {
7382
7456
  await sseTask.catch(() => void 0);
7383
7457
  }
7384
7458
  }
7385
- return async () => void 0;
7386
7459
  }
7387
7460
  /**
7388
7461
  * Stateless abort. Resolve the in-sandbox base URL via
@@ -7536,6 +7609,12 @@ function prepareAgentOptions(_provider, options) {
7536
7609
  var AgentRunController = class {
7537
7610
  id;
7538
7611
  provider;
7612
+ /**
7613
+ * Whether to keep every event for {@link AgentResult}. Off, the queues
7614
+ * still deliver to live consumers but nothing is retained — see
7615
+ * {@link AgentOptionsBase.retainEvents}.
7616
+ */
7617
+ retainEvents;
7539
7618
  sessionId;
7540
7619
  raw;
7541
7620
  sessionIdReady;
@@ -7557,9 +7636,10 @@ var AgentRunController = class {
7557
7636
  resolveSessionIdReady;
7558
7637
  rejectSessionIdReady;
7559
7638
  resolveFinished;
7560
- constructor(provider, id) {
7639
+ constructor(provider, id, retainEvents = true) {
7561
7640
  this.provider = provider;
7562
7641
  this.id = id;
7642
+ this.retainEvents = retainEvents;
7563
7643
  let resolveFinished;
7564
7644
  let resolveSessionIdReady;
7565
7645
  let rejectSessionIdReady;
@@ -7598,11 +7678,11 @@ var AgentRunController = class {
7598
7678
  this.resolveSessionIdReady(sessionId);
7599
7679
  }
7600
7680
  emitRaw(event) {
7601
- this.rawEventsList.push(event);
7681
+ if (this.retainEvents) this.rawEventsList.push(event);
7602
7682
  this.rawQueue.push(event);
7603
7683
  }
7604
7684
  pushEvent(event) {
7605
- this.events.push(event);
7685
+ if (this.retainEvents) this.events.push(event);
7606
7686
  if (event.type === "text.delta") {
7607
7687
  this.text += event.delta;
7608
7688
  } else if ((event.type === "message.completed" || event.type === "run.completed") && event.text) {
@@ -7958,7 +8038,11 @@ var Agent = class {
7958
8038
  const runId = runConfig.runId ?? randomUUID3();
7959
8039
  const streamCalledAt = Date.now();
7960
8040
  debugAgent("stream() provider=%s runId=%s", this.provider, runId);
7961
- const run = new AgentRunController(this.provider, runId);
8041
+ const run = new AgentRunController(
8042
+ this.provider,
8043
+ runId,
8044
+ this.options.retainEvents !== false
8045
+ );
7962
8046
  const setupPromise = this.setupPromise;
7963
8047
  const provider = this.provider;
7964
8048
  const options = this.options;
@@ -7974,15 +8058,12 @@ var Agent = class {
7974
8058
  options,
7975
8059
  run: buildRunConfig(options, runConfig)
7976
8060
  };
7977
- const cleanup = await adapter.execute(request, run);
8061
+ await adapter.execute(request, run);
7978
8062
  debugAgent(
7979
8063
  "adapter.execute() returned for runId=%s after %dms",
7980
8064
  runId,
7981
8065
  Date.now() - streamCalledAt
7982
8066
  );
7983
- run.setAbort(async () => {
7984
- await cleanup();
7985
- });
7986
8067
  } catch (error) {
7987
8068
  run.fail(error);
7988
8069
  }
@@ -75,8 +75,18 @@ var AsyncQueue = class {
75
75
  this.resolvers.shift()?.resolve({ done: true, value: void 0 });
76
76
  }
77
77
  }
78
+ /**
79
+ * Fail the queue for whatever has not been delivered yet.
80
+ *
81
+ * A queue that already {@link finish}ed stays finished: every event reached
82
+ * the consumer and the transport merely closed afterwards (a websocket
83
+ * "error" landing right behind its "close"), which is not a run failure.
84
+ * Buffered items also survive — {@link next} drains them before it throws —
85
+ * so a transport that dies mid-stream still hands over everything it
86
+ * received instead of discarding the tail.
87
+ */
78
88
  fail(error) {
79
- if (this.failure) {
89
+ if (this.closed || this.failure) {
80
90
  return;
81
91
  }
82
92
  this.failure = asError(error);
@@ -85,13 +95,13 @@ var AsyncQueue = class {
85
95
  }
86
96
  }
87
97
  async next() {
88
- if (this.failure) {
89
- throw this.failure;
90
- }
91
98
  if (this.items.length > 0) {
92
99
  const value = this.items.shift();
93
100
  return { done: false, value };
94
101
  }
102
+ if (this.failure) {
103
+ throw this.failure;
104
+ }
95
105
  if (this.closed) {
96
106
  return { done: true, value: void 0 };
97
107
  }
@@ -10,7 +10,7 @@ import {
10
10
  sleep,
11
11
  suppressUnhandledRejection,
12
12
  time
13
- } from "./chunk-MTQ2S46C.js";
13
+ } from "./chunk-D4LSWCFA.js";
14
14
  import {
15
15
  shellQuote,
16
16
  toShellCommand
@@ -1,4 +1,4 @@
1
- export { A as AISDKEvent, C as BackgroundTask, D as BackgroundTasksEvent, Z as HarnessCommandsEvent, a3 as MessageCompletedEvent, a4 as MessageInjectedEvent, a5 as MessageStartedEvent, a6 as NativePlanEvent, a7 as NormalizedAgentEvent, a8 as NormalizedAgentEventBase, a9 as NormalizedAgentEventType, ai as PermissionRequestedEvent, aj as PermissionResolvedEvent, ak as RawAgentEvent, al as ReasoningDeltaEvent, an as RunCancelledEvent, ao as RunCompletedEvent, ap as RunErrorEvent, aq as RunStartedEvent, as as TextDeltaEvent, au as ToolCallCompletedEvent, av as ToolCallDeltaEvent, aw as ToolCallStartedEvent, aD as createNormalizedEvent, aE as normalizeRawAgentEvent, aI as toAISDKEvent, aJ as toAISDKStream } from '../types-DjHP7dFq.js';
1
+ export { A as AISDKEvent, C as BackgroundTask, D as BackgroundTasksEvent, Z as HarnessCommandsEvent, a3 as MessageCompletedEvent, a4 as MessageInjectedEvent, a5 as MessageStartedEvent, a6 as NativePlanEvent, a7 as NormalizedAgentEvent, a8 as NormalizedAgentEventBase, a9 as NormalizedAgentEventType, ai as PermissionRequestedEvent, aj as PermissionResolvedEvent, ak as RawAgentEvent, al as ReasoningDeltaEvent, an as RunCancelledEvent, ao as RunCompletedEvent, ap as RunErrorEvent, aq as RunStartedEvent, as as TextDeltaEvent, au as ToolCallCompletedEvent, av as ToolCallDeltaEvent, aw as ToolCallStartedEvent, aD as createNormalizedEvent, aE as normalizeRawAgentEvent, aI as toAISDKEvent, aJ as toAISDKStream } from '../types-Bhntrw9V.js';
2
2
  import { AgentProvider } from '../enums.js';
3
3
  import '../Sandbox-DcKAU-E3.js';
4
4
  import 'e2b';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AgentUserAnswer, z as AgentUserQuestion, B as AttachedRun, C as BackgroundTask, D as BackgroundTasksEvent, E as ClaudeCodeAgentOptions, F as ClaudeCodeHookConfig, G as ClaudeCodeHookEvent, H as ClaudeCodeHookHandler, I as ClaudeCodeHookMatcherGroup, J as ClaudeCodeHooksConfig, K as ClaudeCodeProviderOptions, L as CodexAgentOptions, M as CodexCommandHook, N as CodexHookEvent, O as CodexHookMatcherGroup, P as CodexHooksConfig, Q as CodexModelProviderConfig, R as CodexProviderOptions, S as CodexSkillEntry, T as DataContent, U as EmbeddedSkillConfig, V as FilePart, W as HarnessCommandDescriptor, X as HarnessCommandInvocation, Y as HarnessCommandSource, Z as HarnessCommandsEvent, _ as ImagePart, $ as MAX_HARNESS_COMMANDS, a0 as MAX_HARNESS_COMMAND_ARGUMENT_HINT, a1 as MAX_HARNESS_COMMAND_DESCRIPTION, a2 as MAX_HARNESS_COMMAND_NAME, a3 as MessageCompletedEvent, a4 as MessageInjectedEvent, a5 as MessageStartedEvent, a6 as NativePlanEvent, a7 as NormalizedAgentEvent, a8 as NormalizedAgentEventBase, a9 as NormalizedAgentEventType, aa as OpenCodeAgentOptions, ab as OpenCodeCommandEntry, ac as OpenCodePluginConfig, ad as OpenCodePluginEvent, ae as OpenCodePluginHookConfig, af as OpenCodeProviderOptions, ag as OpenCodeSkillEntry, ah as OpenRouterPlugin, ai as PermissionRequestedEvent, aj as PermissionResolvedEvent, ak as RawAgentEvent, al as ReasoningDeltaEvent, am as RepoSkillConfig, an as RunCancelledEvent, ao as RunCompletedEvent, ap as RunErrorEvent, aq as RunStartedEvent, ar as SetupLayout, as as TextDeltaEvent, at as TextPart, au as ToolCallCompletedEvent, av as ToolCallDeltaEvent, aw as ToolCallStartedEvent, ax as UserContent, ay as UserContentPart, az as builtinHarnessCommands, aA as claudeHarnessCommands, aB as codexHarnessCommands, aC as codexSkillMention, aD as createNormalizedEvent, aE as normalizeRawAgentEvent, aF as openCodeHarnessCommands, aG as parseHarnessCommandInvocation, aH as skillDirective, aI as toAISDKEvent, aJ as toAISDKStream } from './types-DjHP7dFq.js';
1
+ export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AgentUserAnswer, z as AgentUserQuestion, B as AttachedRun, C as BackgroundTask, D as BackgroundTasksEvent, E as ClaudeCodeAgentOptions, F as ClaudeCodeHookConfig, G as ClaudeCodeHookEvent, H as ClaudeCodeHookHandler, I as ClaudeCodeHookMatcherGroup, J as ClaudeCodeHooksConfig, K as ClaudeCodeProviderOptions, L as CodexAgentOptions, M as CodexCommandHook, N as CodexHookEvent, O as CodexHookMatcherGroup, P as CodexHooksConfig, Q as CodexModelProviderConfig, R as CodexProviderOptions, S as CodexSkillEntry, T as DataContent, U as EmbeddedSkillConfig, V as FilePart, W as HarnessCommandDescriptor, X as HarnessCommandInvocation, Y as HarnessCommandSource, Z as HarnessCommandsEvent, _ as ImagePart, $ as MAX_HARNESS_COMMANDS, a0 as MAX_HARNESS_COMMAND_ARGUMENT_HINT, a1 as MAX_HARNESS_COMMAND_DESCRIPTION, a2 as MAX_HARNESS_COMMAND_NAME, a3 as MessageCompletedEvent, a4 as MessageInjectedEvent, a5 as MessageStartedEvent, a6 as NativePlanEvent, a7 as NormalizedAgentEvent, a8 as NormalizedAgentEventBase, a9 as NormalizedAgentEventType, aa as OpenCodeAgentOptions, ab as OpenCodeCommandEntry, ac as OpenCodePluginConfig, ad as OpenCodePluginEvent, ae as OpenCodePluginHookConfig, af as OpenCodeProviderOptions, ag as OpenCodeSkillEntry, ah as OpenRouterPlugin, ai as PermissionRequestedEvent, aj as PermissionResolvedEvent, ak as RawAgentEvent, al as ReasoningDeltaEvent, am as RepoSkillConfig, an as RunCancelledEvent, ao as RunCompletedEvent, ap as RunErrorEvent, aq as RunStartedEvent, ar as SetupLayout, as as TextDeltaEvent, at as TextPart, au as ToolCallCompletedEvent, av as ToolCallDeltaEvent, aw as ToolCallStartedEvent, ax as UserContent, ay as UserContentPart, az as builtinHarnessCommands, aA as claudeHarnessCommands, aB as codexHarnessCommands, aC as codexSkillMention, aD as createNormalizedEvent, aE as normalizeRawAgentEvent, aF as openCodeHarnessCommands, aG as parseHarnessCommandInvocation, aH as skillDirective, aI as toAISDKEvent, aJ as toAISDKStream } from './types-Bhntrw9V.js';
2
2
  export { AGENT_RESERVED_PORTS, Agent, HarnessCapabilities, HarnessCommand, agentboxRoot, collectAllAgentReservedPorts, getAgentLayout, harnessCapabilities, resolveHarnessCommand } from './agents/index.js';
3
3
  export { A as AsyncCommandHandle, C as CommandEvent, a as CommandOptions, b as CommandResult, D as DaytonaProviderOptions, c as DaytonaSandboxOptions, E as E2bProviderOptions, d as E2bSandboxOptions, G as GitCloneOptions, L as LocalDockerProviderOptions, e as LocalDockerSandboxOptions, M as ModalProviderOptions, f as ModalSandboxOptions, S as Sandbox, g as SandboxDescriptor, h as SandboxListOptions, i as SandboxOptions, j as SandboxOptionsBase, k as SandboxOptionsMap, l as SandboxProviderName, m as SandboxRaw, n as SandboxRawMap, o as SandboxResourceSpec, T as TarballEntry, V as VercelGitSource, p as VercelProviderOptions, q as VercelSandboxOptions } from './Sandbox-DcKAU-E3.js';
4
4
  export { SandboxAdapter, buildGitCloneCommand } from './sandboxes/index.js';
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  parseHarnessCommandInvocation,
16
16
  resolveHarnessCommand,
17
17
  skillDirective
18
- } from "./chunk-REVRD4IY.js";
18
+ } from "./chunk-7PZKMK4U.js";
19
19
  import {
20
20
  ProviderLogAssembler,
21
21
  createNormalizedEvent,
@@ -27,11 +27,11 @@ import {
27
27
  Sandbox,
28
28
  SandboxAdapter,
29
29
  buildGitCloneCommand
30
- } from "./chunk-76AFK7XN.js";
30
+ } from "./chunk-ZQUE5KT6.js";
31
31
  import {
32
32
  AGENT_RESERVED_PORTS,
33
33
  collectAllAgentReservedPorts
34
- } from "./chunk-MTQ2S46C.js";
34
+ } from "./chunk-D4LSWCFA.js";
35
35
  import "./chunk-NSJM57Z4.js";
36
36
  import {
37
37
  AgentProvider,
@@ -2,8 +2,8 @@ import {
2
2
  Sandbox,
3
3
  SandboxAdapter,
4
4
  buildGitCloneCommand
5
- } from "../chunk-76AFK7XN.js";
6
- import "../chunk-MTQ2S46C.js";
5
+ } from "../chunk-ZQUE5KT6.js";
6
+ import "../chunk-D4LSWCFA.js";
7
7
  import "../chunk-NSJM57Z4.js";
8
8
  import {
9
9
  SandboxProvider
@@ -625,6 +625,20 @@ interface AgentOptionsBase {
625
625
  * settles immediately.
626
626
  */
627
627
  backgroundTaskTimeoutMs?: number;
628
+ /**
629
+ * Keep every normalized and raw event in memory for the life of the run so
630
+ * {@link AgentResult.events} / {@link AgentResult.rawEvents} can replay it
631
+ * (default `true`).
632
+ *
633
+ * Set `false` when the caller consumes the live stream (`for await (const
634
+ * event of run)` / `run.rawEvents()`) and never reads the arrays off the
635
+ * result. A long run's transcript — every tool result, every file the agent
636
+ * read — is otherwise retained twice over and copied once more when the run
637
+ * settles, which dominates memory for a host running many concurrent runs
638
+ * in one process. With retention off both arrays settle as `[]`; `text`,
639
+ * `costData` and every streamed event are unaffected.
640
+ */
641
+ retainEvents?: boolean;
628
642
  approvalMode?: AgentApprovalMode;
629
643
  /** Route questions and plan approvals to the caller even with automatic tool approval. */
630
644
  interactiveQuestions?: boolean;
@@ -817,7 +831,9 @@ interface AgentResult {
817
831
  text: string;
818
832
  isCancelled: boolean;
819
833
  error?: string;
834
+ /** Empty when {@link AgentOptionsBase.retainEvents} is `false`. */
820
835
  rawEvents: RawAgentEvent[];
836
+ /** Empty when {@link AgentOptionsBase.retainEvents} is `false`. */
821
837
  events: NormalizedAgentEvent[];
822
838
  costData?: AgentCostData | null;
823
839
  /**
@@ -970,7 +986,16 @@ interface AgentProviderAdapter<P extends AgentProviderName = AgentProviderName>
970
986
  * app-server per run).
971
987
  */
972
988
  killServer(request: AgentSetupRequest<P>): Promise<void>;
973
- execute(request: AgentExecutionRequest<P>, sink: AgentRunSink): Promise<() => Promise<void> | void>;
989
+ /**
990
+ * Drive one run to completion. Resolves only once the run has settled
991
+ * (`sink.complete` / `cancel` / `fail`), so it must not be awaited before
992
+ * the caller starts reading the sink's streams.
993
+ *
994
+ * Cancellation is registered through `sink.setAbort` the moment a
995
+ * transport exists — not returned from here, which would only ever arrive
996
+ * after the run was already over.
997
+ */
998
+ execute(request: AgentExecutionRequest<P>, sink: AgentRunSink): Promise<void>;
974
999
  /**
975
1000
  * Stateless abort. Dial the in-sandbox provider server, issue the
976
1001
  * provider's "interrupt the in-flight turn" primitive, close.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbox-sdk",
3
- "version": "0.1.519",
3
+ "version": "0.1.520",
4
4
  "description": "Swappable coding agents and sandbox providers for Bun and TypeScript.",
5
5
  "license": "MIT",
6
6
  "repository": {