agentbox-sdk 0.1.317 → 0.1.319

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.
@@ -2,8 +2,8 @@ import {
2
2
  Agent,
3
3
  agentboxRoot,
4
4
  getAgentLayout
5
- } from "../chunk-75KPGNTE.js";
6
- import "../chunk-2DH5OVG4.js";
5
+ } from "../chunk-2IHQY3WC.js";
6
+ import "../chunk-775FIGGL.js";
7
7
  import {
8
8
  AGENT_RESERVED_PORTS,
9
9
  collectAllAgentReservedPorts
@@ -2,7 +2,7 @@ import {
2
2
  createNormalizedEvent,
3
3
  normalizeRawAgentEvent,
4
4
  toAISDKStream
5
- } from "./chunk-2DH5OVG4.js";
5
+ } from "./chunk-775FIGGL.js";
6
6
  import {
7
7
  AgentBoxError,
8
8
  AsyncQueue,
@@ -2328,6 +2328,7 @@ var ClaudeCodeAgentAdapter = class {
2328
2328
  )
2329
2329
  );
2330
2330
  let accumulatedText = "";
2331
+ let streamedThinkingChars = 0;
2331
2332
  let pendingMessages = 1;
2332
2333
  let firstStreamEventLogged = false;
2333
2334
  let firstTextDeltaLogged = false;
@@ -2399,8 +2400,15 @@ var ClaudeCodeAgentAdapter = class {
2399
2400
  );
2400
2401
  }
2401
2402
  const partial = message;
2403
+ if (partial.parent_tool_use_id) continue;
2404
+ const streamType = partial.event?.type;
2405
+ if (streamType === "message_start") {
2406
+ accumulatedText = "";
2407
+ streamedThinkingChars = 0;
2408
+ }
2402
2409
  const { text, thinking } = extractStreamDeltas(partial);
2403
2410
  if (thinking) {
2411
+ streamedThinkingChars += thinking.length;
2404
2412
  sink.emitEvent(
2405
2413
  createNormalizedEvent(
2406
2414
  "reasoning.delta",
@@ -2430,8 +2438,9 @@ var ClaudeCodeAgentAdapter = class {
2430
2438
  }
2431
2439
  if (message.type === "assistant") {
2432
2440
  const asst = message;
2441
+ if (asst.parent_tool_use_id) continue;
2433
2442
  const thinking = extractAssistantThinking(asst);
2434
- if (thinking) {
2443
+ if (thinking && streamedThinkingChars === 0) {
2435
2444
  sink.emitEvent(
2436
2445
  createNormalizedEvent(
2437
2446
  "reasoning.delta",
@@ -2571,6 +2580,7 @@ var ClaudeCodeAgentAdapter = class {
2571
2580
  };
2572
2581
 
2573
2582
  // src/agents/providers/codex.ts
2583
+ import crypto from "crypto";
2574
2584
  import path9 from "path";
2575
2585
 
2576
2586
  // src/agents/transports/app-server.ts
@@ -2797,6 +2807,61 @@ function codexConfigDir(options) {
2797
2807
  }
2798
2808
  var REMOTE_CODEX_APP_SERVER_PORT = 43181;
2799
2809
  var REMOTE_CODEX_APP_SERVER_ID = "shared-app-server";
2810
+ var CODEX_APP_SERVER_TOKEN_FILENAME = "codex-app-server-token";
2811
+ function defaultRemoteCodexTokenPath() {
2812
+ return path9.posix.join(
2813
+ agentboxRoot(AgentProvider.Codex, true),
2814
+ CODEX_APP_SERVER_TOKEN_FILENAME
2815
+ );
2816
+ }
2817
+ var codexAppServerTokenCache = /* @__PURE__ */ new WeakMap();
2818
+ async function readCodexAppServerTokenFile(sandbox, tokenFilePath) {
2819
+ const result = await sandbox.run(
2820
+ `if [ -f ${shellQuote(tokenFilePath)} ]; then cat ${shellQuote(tokenFilePath)}; fi`
2821
+ );
2822
+ if (result.exitCode !== 0) {
2823
+ return void 0;
2824
+ }
2825
+ const value = result.stdout.trim();
2826
+ return value.length > 0 ? value : void 0;
2827
+ }
2828
+ function resolveCodexAppServerToken(sandbox, tokenFilePath, create) {
2829
+ let cached = codexAppServerTokenCache.get(sandbox);
2830
+ if (!cached) {
2831
+ cached = (async () => {
2832
+ const existing = await readCodexAppServerTokenFile(
2833
+ sandbox,
2834
+ tokenFilePath
2835
+ );
2836
+ if (existing) {
2837
+ return existing;
2838
+ }
2839
+ if (create) {
2840
+ return crypto.randomBytes(32).toString("hex");
2841
+ }
2842
+ throw new Error(
2843
+ `Codex app-server token file is missing at ${tokenFilePath}. setup() must run before connecting to the codex app-server.`
2844
+ );
2845
+ })().catch((error) => {
2846
+ codexAppServerTokenCache.delete(sandbox);
2847
+ throw error;
2848
+ });
2849
+ codexAppServerTokenCache.set(sandbox, cached);
2850
+ }
2851
+ return cached;
2852
+ }
2853
+ function ensureCodexAppServerToken(sandbox, tokenFilePath) {
2854
+ return resolveCodexAppServerToken(sandbox, tokenFilePath, true);
2855
+ }
2856
+ function getCodexAppServerToken(sandbox, tokenFilePath = defaultRemoteCodexTokenPath()) {
2857
+ return resolveCodexAppServerToken(sandbox, tokenFilePath, false);
2858
+ }
2859
+ function withCodexAppServerAuthHeaders(base, token) {
2860
+ return {
2861
+ ...base,
2862
+ Authorization: `Bearer ${token}`
2863
+ };
2864
+ }
2800
2865
  function compactEnv(values) {
2801
2866
  return Object.fromEntries(
2802
2867
  Object.entries(values).filter(([, value]) => value !== void 0)
@@ -3131,9 +3196,10 @@ async function withCodexAppServer(request, body) {
3131
3196
  );
3132
3197
  }
3133
3198
  const previewUrl = await sandbox.getPreviewLink(REMOTE_CODEX_APP_SERVER_PORT);
3199
+ const token = await getCodexAppServerToken(sandbox);
3134
3200
  const transport = await connectJsonRpcWebSocket(
3135
3201
  toRemoteCodexWebSocketUrl(previewUrl),
3136
- { headers: sandbox.previewHeaders }
3202
+ { headers: withCodexAppServerAuthHeaders(sandbox.previewHeaders, token) }
3137
3203
  );
3138
3204
  const client = new JsonRpcLineClient(
3139
3205
  transport.source,
@@ -3219,7 +3285,19 @@ async function setupCodex(request) {
3219
3285
  ...sharedTarget.env,
3220
3286
  ...options.provider?.env ?? {}
3221
3287
  });
3222
- const { artifacts: serverArtifacts } = buildArtifactsFor(sharedTarget);
3288
+ const tokenFilePath = path9.posix.join(
3289
+ sharedTarget.layout.rootDir,
3290
+ CODEX_APP_SERVER_TOKEN_FILENAME
3291
+ );
3292
+ const appServerToken = await ensureCodexAppServerToken(
3293
+ sandbox,
3294
+ tokenFilePath
3295
+ );
3296
+ const { artifacts: baseServerArtifacts } = buildArtifactsFor(sharedTarget);
3297
+ const serverArtifacts = [
3298
+ ...baseServerArtifacts,
3299
+ { path: tokenFilePath, content: appServerToken }
3300
+ ];
3223
3301
  const { artifacts: skillArtifacts2, installCommands: installCommands2 } = await prepareSkillArtifacts(provider, options.skills, target2.layout);
3224
3302
  const enableRtk2 = options.enableRtk === true;
3225
3303
  const daemonInfo = {
@@ -3260,6 +3338,7 @@ async function setupCodex(request) {
3260
3338
  `mkdir -p ${shellQuote(sharedTarget.layout.rootDir)}`,
3261
3339
  `if curl -fsS http://127.0.0.1:${REMOTE_CODEX_APP_SERVER_PORT}/readyz >/dev/null 2>&1; then exit 0; fi`,
3262
3340
  `if [ -f ${shellQuote(pidFilePath)} ]; then kill "$(cat ${shellQuote(pidFilePath)})" >/dev/null 2>&1 || true; rm -f ${shellQuote(pidFilePath)}; fi`,
3341
+ `chmod 600 ${shellQuote(tokenFilePath)}`,
3263
3342
  `(${[
3264
3343
  `nohup ${[
3265
3344
  "env",
@@ -3268,7 +3347,15 @@ async function setupCodex(request) {
3268
3347
  [
3269
3348
  "app-server",
3270
3349
  "--listen",
3271
- `ws://0.0.0.0:${REMOTE_CODEX_APP_SERVER_PORT}`
3350
+ `ws://0.0.0.0:${REMOTE_CODEX_APP_SERVER_PORT}`,
3351
+ // Auth on non-loopback listeners is opt-in in codex; without
3352
+ // these flags the 0.0.0.0 app-server accepts unauthenticated
3353
+ // clients. Requires codex >= 0.133 (`--ws-auth` flag); older
3354
+ // pinned binaries will fail to launch on the unknown arg.
3355
+ "--ws-auth",
3356
+ "capability-token",
3357
+ "--ws-token-file",
3358
+ tokenFilePath
3272
3359
  ],
3273
3360
  options
3274
3361
  )
@@ -3343,9 +3430,10 @@ async function createRuntime(request, inputParts) {
3343
3430
  "getPreviewLink app-server",
3344
3431
  () => sandbox.getPreviewLink(REMOTE_CODEX_APP_SERVER_PORT)
3345
3432
  );
3433
+ const token = await getCodexAppServerToken(sandbox);
3346
3434
  const transport = await connectRemoteCodexAppServer(
3347
3435
  toRemoteCodexWebSocketUrl(previewUrl),
3348
- sandbox.previewHeaders
3436
+ withCodexAppServerAuthHeaders(sandbox.previewHeaders, token)
3349
3437
  );
3350
3438
  debugCodex("\u2605 codex transport established");
3351
3439
  return {
@@ -3790,12 +3878,74 @@ var CodexAgentAdapter = class {
3790
3878
  };
3791
3879
 
3792
3880
  // src/agents/providers/opencode.ts
3881
+ import { createHash as createHash2 } from "crypto";
3793
3882
  import path10 from "path";
3794
3883
  var SANDBOX_OPENCODE_PORT = 4096;
3795
3884
  var LOCAL_OPENCODE_PORT = 4096;
3796
3885
  var SANDBOX_OPENCODE_READY_TIMEOUT_MS = 9e4;
3797
3886
  var LOCAL_OPENCODE_READY_TIMEOUT_MS = 2e4;
3798
3887
  var SHARED_OPENCODE_TARGET_ID = "shared-opencode-server";
3888
+ var LLM_API_KEY_ENV_VARS = [
3889
+ "OPENROUTER_API_KEY",
3890
+ "OPENAI_API_KEY",
3891
+ "ANTHROPIC_API_KEY",
3892
+ "GOOGLE_GENERATIVE_AI_API_KEY",
3893
+ "GEMINI_API_KEY"
3894
+ ];
3895
+ function hashLlmApiKeys(env) {
3896
+ const hasher = createHash2("sha256");
3897
+ for (const key of LLM_API_KEY_ENV_VARS) {
3898
+ if (env?.[key] !== void 0) {
3899
+ hasher.update(`${key}=${env[key]}
3900
+ `);
3901
+ }
3902
+ }
3903
+ return hasher.digest("hex");
3904
+ }
3905
+ async function killLocalOpenCodeServer() {
3906
+ await time(debugOpencode, "kill local opencode server", async () => {
3907
+ const killer = spawnCommand({
3908
+ command: "sh",
3909
+ args: [
3910
+ "-c",
3911
+ `lsof -ti tcp:${LOCAL_OPENCODE_PORT} | xargs kill 2>/dev/null || true`
3912
+ ]
3913
+ });
3914
+ await killer.wait().catch(() => void 0);
3915
+ await waitFor(
3916
+ async () => {
3917
+ try {
3918
+ const res = await fetch(
3919
+ `http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`
3920
+ );
3921
+ return !res.ok;
3922
+ } catch {
3923
+ return true;
3924
+ }
3925
+ },
3926
+ { timeoutMs: 5e3, intervalMs: 200 }
3927
+ ).catch(() => void 0);
3928
+ });
3929
+ }
3930
+ async function killSandboxOpenCodeServer(sandbox, pidFilePath, cwd, port) {
3931
+ await time(debugOpencode, "kill sandbox opencode server", async () => {
3932
+ await sandbox.run(
3933
+ `kill -- -"$(cat ${shellQuote(pidFilePath)})" 2>/dev/null || kill "$(cat ${shellQuote(pidFilePath)})" 2>/dev/null || true`,
3934
+ { cwd, timeoutMs: 5e3 }
3935
+ ).catch(() => void 0);
3936
+ const deadline = Date.now() + 5e3;
3937
+ while (Date.now() < deadline) {
3938
+ const probe = await sandbox.run(
3939
+ `curl -fsS --max-time 2 http://127.0.0.1:${port}/global/health >/dev/null 2>&1`,
3940
+ { cwd, timeoutMs: 5e3 }
3941
+ );
3942
+ if (probe.exitCode !== 0) {
3943
+ return;
3944
+ }
3945
+ await sleep(200);
3946
+ }
3947
+ });
3948
+ }
3799
3949
  function toRawEvent3(runId, payload, type) {
3800
3950
  return {
3801
3951
  provider: AgentProvider.OpenCode,
@@ -3891,6 +4041,10 @@ function buildOpenCodeConfig(options, interactiveApproval) {
3891
4041
  const googleBaseUrl = options.env?.GOOGLE_BASE_URL;
3892
4042
  const openRouterBaseUrl = options.env?.OPENROUTER_BASE_URL;
3893
4043
  const openRouterPlugins = options.openRouterPlugins && options.openRouterPlugins.length > 0 ? options.openRouterPlugins : void 0;
4044
+ const openRouterExtraBody = {
4045
+ transforms: ["middle-out"],
4046
+ ...openRouterPlugins ? { plugins: openRouterPlugins } : {}
4047
+ };
3894
4048
  return {
3895
4049
  $schema: "https://opencode.ai/config.json",
3896
4050
  ...mcpConfig ? { mcp: mcpConfig } : {},
@@ -3899,7 +4053,7 @@ function buildOpenCodeConfig(options, interactiveApproval) {
3899
4053
  openrouter: {
3900
4054
  options: {
3901
4055
  baseURL: openRouterBaseUrl || "https://openrouter.ai/api/v1",
3902
- ...openRouterPlugins ? { plugins: openRouterPlugins } : {}
4056
+ extraBody: openRouterExtraBody
3903
4057
  }
3904
4058
  },
3905
4059
  ...googleBaseUrl ? { google: { options: { baseURL: googleBaseUrl } } } : {}
@@ -3949,7 +4103,10 @@ async function ensureSandboxOpenCodeServer(request) {
3949
4103
  artifacts: allArtifacts,
3950
4104
  installCommands,
3951
4105
  daemon: daemonInfo,
3952
- extras: [`enableRtk:${enableRtk}`]
4106
+ extras: [
4107
+ `enableRtk:${enableRtk}`,
4108
+ `apiKeys:${hashLlmApiKeys(options.env)}`
4109
+ ]
3953
4110
  });
3954
4111
  if (await preflightSetup(target, setupId, daemonInfo)) {
3955
4112
  debugOpencode("opencode setup() preflight hit \u2014 skipping");
@@ -3990,6 +4147,7 @@ async function ensureSandboxOpenCodeServer(request) {
3990
4147
  `disown 2>/dev/null || true`
3991
4148
  ].join(" ")})`
3992
4149
  ].join(" && ");
4150
+ await killSandboxOpenCodeServer(sandbox, pidFilePath, options.cwd, port);
3993
4151
  const launchResult = await time(
3994
4152
  debugOpencode,
3995
4153
  "spawn opencode serve",
@@ -4030,16 +4188,6 @@ async function ensureSandboxOpenCodeServer(request) {
4030
4188
  }
4031
4189
  async function ensureLocalOpenCodeServer(request) {
4032
4190
  const options = request.options;
4033
- try {
4034
- await waitForHttpReady(
4035
- `http://127.0.0.1:${LOCAL_OPENCODE_PORT}/global/health`,
4036
- { timeoutMs: 1e3 }
4037
- );
4038
- debugOpencode("local opencode server already running \u2014 reusing");
4039
- return;
4040
- } catch {
4041
- debugOpencode("local opencode server not running \u2014 cold-spawning");
4042
- }
4043
4191
  const plugins = assertHooksSupported(request.provider, options);
4044
4192
  assertCommandsSupported(request.provider, options.commands);
4045
4193
  const interactiveApproval = isInteractiveApproval(options);
@@ -4072,14 +4220,23 @@ async function ensureLocalOpenCodeServer(request) {
4072
4220
  content: JSON.stringify(openCodeConfig, null, 2)
4073
4221
  }
4074
4222
  ];
4223
+ const daemonInfo = {
4224
+ port: LOCAL_OPENCODE_PORT,
4225
+ healthPath: "/global/health"
4226
+ };
4075
4227
  const setupId = computeSetupId({
4076
4228
  artifacts: allArtifacts,
4077
- installCommands
4229
+ installCommands,
4230
+ daemon: daemonInfo,
4231
+ extras: [`apiKeys:${hashLlmApiKeys(options.env)}`]
4078
4232
  });
4079
- const preflightHit = await preflightSetup(target, setupId);
4080
- if (!preflightHit) {
4081
- await applyDifferentialSetup(target, allArtifacts, installCommands);
4233
+ if (await preflightSetup(target, setupId, daemonInfo)) {
4234
+ debugOpencode("local opencode server up-to-date \u2014 reusing");
4235
+ return;
4082
4236
  }
4237
+ debugOpencode("local opencode server drifted/absent \u2014 (re)spawning");
4238
+ await applyDifferentialSetup(target, allArtifacts, installCommands);
4239
+ await killLocalOpenCodeServer();
4083
4240
  spawnCommand({
4084
4241
  command: options.provider?.binary ?? "opencode",
4085
4242
  args: [
@@ -189,9 +189,35 @@ function isRecord(value) {
189
189
  function clone(value) {
190
190
  return JSON.parse(JSON.stringify(value));
191
191
  }
192
+ function isCodexNoiseEvent(method) {
193
+ if (!method) return false;
194
+ if (method.startsWith("mcpServer/")) return true;
195
+ return method.toLowerCase().includes("delta");
196
+ }
192
197
  var CodexLogAssembler = class {
193
198
  byItemId = /* @__PURE__ */ new Map();
194
199
  textByItemId = /* @__PURE__ */ new Map();
200
+ // Non-item events (turn/completed usage, error notifications, thread
201
+ // responses). Returned by `process()` for the live channel; tracked here so
202
+ // `getSnapshots()` — the end-of-run persistence source — keeps them too.
203
+ passThroughSnapshots = [];
204
+ // First-seen chronological order across items and passthroughs.
205
+ snapshotOrder = [];
206
+ trackItem(itemId, snapshot) {
207
+ if (!this.byItemId.has(itemId)) {
208
+ this.snapshotOrder.push({ kind: "item", id: itemId });
209
+ }
210
+ this.byItemId.set(itemId, snapshot);
211
+ }
212
+ pushPassThrough(event) {
213
+ const passthrough = clone(event);
214
+ this.snapshotOrder.push({
215
+ kind: "passthrough",
216
+ index: this.passThroughSnapshots.length
217
+ });
218
+ this.passThroughSnapshots.push(passthrough);
219
+ return clone(passthrough);
220
+ }
195
221
  process(event) {
196
222
  if (!isRecord(event)) {
197
223
  return [];
@@ -201,7 +227,7 @@ var CodexLogAssembler = class {
201
227
  const item = isRecord(params.item) ? clone(params.item) : null;
202
228
  if (method === "item/started" || method === "item/updated" || method === "item/completed") {
203
229
  if (item && typeof item.id === "string") {
204
- this.byItemId.set(item.id, clone(event));
230
+ this.trackItem(item.id, clone(event));
205
231
  const text = typeof item.text === "string" ? item.text : void 0;
206
232
  if (text !== void 0) {
207
233
  this.textByItemId.set(item.id, text);
@@ -247,7 +273,8 @@ var CodexLogAssembler = class {
247
273
  })
248
274
  ];
249
275
  }
250
- return [clone(event)];
276
+ if (isCodexNoiseEvent(method)) return [];
277
+ return [this.pushPassThrough(event)];
251
278
  }
252
279
  /**
253
280
  * Repopulate state from a sequence of previously-assembled snapshots so the
@@ -256,12 +283,24 @@ var CodexLogAssembler = class {
256
283
  seed(snapshots) {
257
284
  this.byItemId.clear();
258
285
  this.textByItemId.clear();
286
+ this.passThroughSnapshots.length = 0;
287
+ this.snapshotOrder.length = 0;
259
288
  for (const snapshot of snapshots) {
260
289
  if (!isRecord(snapshot)) continue;
261
290
  const params = isRecord(snapshot.params) ? snapshot.params : {};
262
291
  const item = isRecord(params.item) ? params.item : null;
263
- if (!item || typeof item.id !== "string") continue;
264
- this.byItemId.set(item.id, clone(snapshot));
292
+ if (!item || typeof item.id !== "string") {
293
+ const method = typeof snapshot.method === "string" ? snapshot.method : void 0;
294
+ if (!isCodexNoiseEvent(method)) {
295
+ this.snapshotOrder.push({
296
+ kind: "passthrough",
297
+ index: this.passThroughSnapshots.length
298
+ });
299
+ this.passThroughSnapshots.push(clone(snapshot));
300
+ }
301
+ continue;
302
+ }
303
+ this.trackItem(item.id, clone(snapshot));
265
304
  const text = typeof item.text === "string" ? item.text : void 0;
266
305
  if (text !== void 0) {
267
306
  this.textByItemId.set(item.id, text);
@@ -288,11 +327,16 @@ var CodexLogAssembler = class {
288
327
  }
289
328
  }
290
329
  };
291
- this.byItemId.set(itemId, next);
330
+ this.trackItem(itemId, next);
292
331
  return clone(next);
293
332
  }
294
333
  getSnapshots() {
295
- return Array.from(this.byItemId.values()).map(clone);
334
+ const out = [];
335
+ for (const entry of this.snapshotOrder) {
336
+ const snapshot = entry.kind === "item" ? this.byItemId.get(entry.id) : this.passThroughSnapshots[entry.index];
337
+ if (snapshot) out.push(clone(snapshot));
338
+ }
339
+ return out;
296
340
  }
297
341
  };
298
342
  var OpenCodeLogAssembler = class {
@@ -314,6 +358,39 @@ var OpenCodeLogAssembler = class {
314
358
  childSessionToTaskCallId = /* @__PURE__ */ new Map();
315
359
  childMessageIdToTaskCallId = /* @__PURE__ */ new Map();
316
360
  messageIdToSessionId = /* @__PURE__ */ new Map();
361
+ // Part-less events (user `message.updated`, session lifecycle, errors).
362
+ // Returned by `process()` for the live channel; tracked here so
363
+ // `getSnapshots()` — the end-of-run persistence source — keeps them too.
364
+ // `message.updated` events are keyed by info.id (they re-emit on metadata
365
+ // updates, latest wins); everything else appends.
366
+ keyedPassThrough = /* @__PURE__ */ new Map();
367
+ passThroughSnapshots = [];
368
+ // First-seen chronological order across parts and passthroughs.
369
+ snapshotOrder = [];
370
+ trackPart(partId, snapshot) {
371
+ if (!this.byPartId.has(partId)) {
372
+ this.snapshotOrder.push({ kind: "part", id: partId });
373
+ }
374
+ this.byPartId.set(partId, snapshot);
375
+ }
376
+ pushPassThrough(event) {
377
+ const passthrough = clone(event);
378
+ const info = isRecord(event.properties) ? isRecord(event.properties.info) ? event.properties.info : null : null;
379
+ if (event.type === "message.updated" && info && typeof info.id === "string") {
380
+ const key = `message:${info.id}`;
381
+ if (!this.keyedPassThrough.has(key)) {
382
+ this.snapshotOrder.push({ kind: "keyed", key });
383
+ }
384
+ this.keyedPassThrough.set(key, passthrough);
385
+ return clone(passthrough);
386
+ }
387
+ this.snapshotOrder.push({
388
+ kind: "passthrough",
389
+ index: this.passThroughSnapshots.length
390
+ });
391
+ this.passThroughSnapshots.push(passthrough);
392
+ return clone(passthrough);
393
+ }
317
394
  process(event) {
318
395
  if (!isRecord(event)) {
319
396
  return [];
@@ -356,7 +433,7 @@ var OpenCodeLogAssembler = class {
356
433
  }
357
434
  if (type === "message.updated" && typeof info?.id === "string" && info.role === "user") {
358
435
  this.userMessageIds.add(info.id);
359
- return [clone(event)];
436
+ return [this.pushPassThrough(event)];
360
437
  }
361
438
  const parentTaskCallId = this.resolveParentTaskCallId(
362
439
  effectiveSid,
@@ -412,10 +489,10 @@ var OpenCodeLogAssembler = class {
412
489
  );
413
490
  }
414
491
  }
415
- this.byPartId.set(eventPart.id, enriched);
492
+ this.trackPart(eventPart.id, enriched);
416
493
  return [clone(enriched)];
417
494
  }
418
- return [clone(event)];
495
+ return [this.pushPassThrough(event)];
419
496
  }
420
497
  seed(snapshots) {
421
498
  this.userMessageIds.clear();
@@ -426,6 +503,9 @@ var OpenCodeLogAssembler = class {
426
503
  this.childSessionToTaskCallId.clear();
427
504
  this.childMessageIdToTaskCallId.clear();
428
505
  this.messageIdToSessionId.clear();
506
+ this.keyedPassThrough.clear();
507
+ this.passThroughSnapshots.length = 0;
508
+ this.snapshotOrder.length = 0;
429
509
  for (const snapshot of snapshots) {
430
510
  if (!isRecord(snapshot)) continue;
431
511
  const type = typeof snapshot.type === "string" ? snapshot.type : "";
@@ -440,11 +520,16 @@ var OpenCodeLogAssembler = class {
440
520
  }
441
521
  if (type === "message.updated" && typeof info?.id === "string" && info.role === "user") {
442
522
  this.userMessageIds.add(info.id);
523
+ this.pushPassThrough(snapshot);
443
524
  continue;
444
525
  }
445
526
  const part = isRecord(properties.part) ? properties.part : isRecord(snapshot.part) ? snapshot.part : null;
527
+ if (!part || typeof part.id !== "string") {
528
+ this.pushPassThrough(snapshot);
529
+ continue;
530
+ }
446
531
  if (part && typeof part.id === "string") {
447
- this.byPartId.set(part.id, clone(snapshot));
532
+ this.trackPart(part.id, clone(snapshot));
448
533
  if (typeof part.text === "string") {
449
534
  this.textByPartId.set(part.id, part.text);
450
535
  }
@@ -538,13 +623,27 @@ var OpenCodeLogAssembler = class {
538
623
  part
539
624
  }
540
625
  };
541
- this.byPartId.set(partId, next);
626
+ this.trackPart(partId, next);
542
627
  return clone(next);
543
628
  }
544
629
  getSnapshots() {
545
- return Array.from(this.byPartId.values()).map(clone);
630
+ const out = [];
631
+ for (const entry of this.snapshotOrder) {
632
+ const snapshot = entry.kind === "part" ? this.byPartId.get(entry.id) : entry.kind === "keyed" ? this.keyedPassThrough.get(entry.key) : this.passThroughSnapshots[entry.index];
633
+ if (snapshot) out.push(clone(snapshot));
634
+ }
635
+ return out;
546
636
  }
547
637
  };
638
+ function isClaudeNoiseEvent(event) {
639
+ const type = typeof event.type === "string" ? event.type : "";
640
+ if (type === "rate_limit_event" || type === "tool_progress") return true;
641
+ if (type === "system") {
642
+ const sub = typeof event.subtype === "string" ? event.subtype : "";
643
+ return sub === "status" || sub === "hook_started" || sub === "hook_response" || sub === "hook_progress" || sub === "api_retry" || sub === "auth_status";
644
+ }
645
+ return false;
646
+ }
548
647
  var ClaudeCodeLogAssembler = class {
549
648
  currentMessageId = null;
550
649
  textByMessageId = /* @__PURE__ */ new Map();
@@ -565,6 +664,12 @@ var ClaudeCodeLogAssembler = class {
565
664
  // insertion order so `getSnapshots()` returns the full trace, not just the
566
665
  // deduped assistant messages.
567
666
  passThroughSnapshots = [];
667
+ // First-seen chronological order of everything `getSnapshots()` returns:
668
+ // messages anchor at the position of their first event (message_start or
669
+ // first assistant block) and passthroughs at arrival. Without this the
670
+ // persisted trace would list every message first and every tool_result /
671
+ // system event after, scrambling replay order for sequential consumers.
672
+ snapshotOrder = [];
568
673
  process(event) {
569
674
  if (!isRecord(event)) return [];
570
675
  const type = typeof event.type === "string" ? event.type : "";
@@ -606,24 +711,32 @@ var ClaudeCodeLogAssembler = class {
606
711
  const message = isRecord(event.message) ? event.message : null;
607
712
  const id = message && typeof message.id === "string" ? message.id : null;
608
713
  if (!id || !message) {
609
- const passthrough2 = clone(event);
610
- this.passThroughSnapshots.push(passthrough2);
611
- return [clone(passthrough2)];
714
+ return [this.pushPassThrough(event)];
612
715
  }
613
716
  this.setParentToolUseId(id, event);
614
717
  const final = extractClaudeAssistantContent(message);
615
- this.textByMessageId.set(id, final.text);
616
- if (final.thinking) {
718
+ const streamedText = this.textByMessageId.get(id) ?? "";
719
+ if (final.text.length > streamedText.length) {
720
+ this.textByMessageId.set(id, final.text);
721
+ }
722
+ const streamedThinking = this.thinkingByMessageId.get(id) ?? "";
723
+ if (final.thinking.length > streamedThinking.length) {
617
724
  this.thinkingByMessageId.set(id, final.thinking);
618
725
  }
619
726
  this.mergeExtraBlocks(id, final.extraBlocks);
620
- const snapshot = this.upsertMessage(id);
621
- this.currentMessageId = null;
622
- return [snapshot];
727
+ return [this.upsertMessage(id)];
623
728
  }
729
+ if (isClaudeNoiseEvent(event)) return [];
730
+ return [this.pushPassThrough(event)];
731
+ }
732
+ pushPassThrough(event) {
624
733
  const passthrough = clone(event);
734
+ this.snapshotOrder.push({
735
+ kind: "passthrough",
736
+ index: this.passThroughSnapshots.length
737
+ });
625
738
  this.passThroughSnapshots.push(passthrough);
626
- return [clone(passthrough)];
739
+ return clone(passthrough);
627
740
  }
628
741
  seed(snapshots) {
629
742
  this.currentMessageId = null;
@@ -633,15 +746,26 @@ var ClaudeCodeLogAssembler = class {
633
746
  this.byMessageId.clear();
634
747
  this.extraBlocksByMessageId.clear();
635
748
  this.passThroughSnapshots.length = 0;
749
+ this.snapshotOrder.length = 0;
636
750
  for (const snapshot of snapshots) {
637
751
  if (!isRecord(snapshot)) continue;
638
752
  if (snapshot.type !== "message.updated") {
639
- this.passThroughSnapshots.push(clone(snapshot));
753
+ if (!isClaudeNoiseEvent(snapshot)) {
754
+ this.snapshotOrder.push({
755
+ kind: "passthrough",
756
+ index: this.passThroughSnapshots.length
757
+ });
758
+ this.passThroughSnapshots.push(clone(snapshot));
759
+ }
640
760
  continue;
641
761
  }
642
762
  const messageId = typeof snapshot.messageId === "string" ? snapshot.messageId : null;
643
763
  if (!messageId) continue;
764
+ if (!this.byMessageId.has(messageId)) {
765
+ this.snapshotOrder.push({ kind: "message", id: messageId });
766
+ }
644
767
  this.byMessageId.set(messageId, clone(snapshot));
768
+ this.currentMessageId = messageId;
645
769
  const parentToolUseId = typeof snapshot.parent_tool_use_id === "string" ? snapshot.parent_tool_use_id : null;
646
770
  this.parentToolUseIdByMessageId.set(messageId, parentToolUseId);
647
771
  const message = isRecord(snapshot.message) ? snapshot.message : null;
@@ -707,13 +831,18 @@ var ClaudeCodeLogAssembler = class {
707
831
  content
708
832
  }
709
833
  };
834
+ if (!this.byMessageId.has(messageId)) {
835
+ this.snapshotOrder.push({ kind: "message", id: messageId });
836
+ }
710
837
  this.byMessageId.set(messageId, next);
711
838
  return clone(next);
712
839
  }
713
840
  getSnapshots() {
714
841
  const out = [];
715
- for (const snapshot of this.byMessageId.values()) out.push(clone(snapshot));
716
- for (const snapshot of this.passThroughSnapshots) out.push(clone(snapshot));
842
+ for (const entry of this.snapshotOrder) {
843
+ const snapshot = entry.kind === "message" ? this.byMessageId.get(entry.id) : this.passThroughSnapshots[entry.index];
844
+ if (snapshot) out.push(clone(snapshot));
845
+ }
717
846
  return out;
718
847
  }
719
848
  };
@@ -4,7 +4,7 @@ import {
4
4
  normalizeRawAgentEvent,
5
5
  toAISDKEvent,
6
6
  toAISDKStream
7
- } from "../chunk-2DH5OVG4.js";
7
+ } from "../chunk-775FIGGL.js";
8
8
  import "../chunk-GOFJNFAD.js";
9
9
  export {
10
10
  ProviderLogAssembler,
package/dist/index.js CHANGED
@@ -2,14 +2,14 @@ import {
2
2
  Agent,
3
3
  agentboxRoot,
4
4
  getAgentLayout
5
- } from "./chunk-75KPGNTE.js";
5
+ } from "./chunk-2IHQY3WC.js";
6
6
  import {
7
7
  ProviderLogAssembler,
8
8
  createNormalizedEvent,
9
9
  normalizeRawAgentEvent,
10
10
  toAISDKEvent,
11
11
  toAISDKStream
12
- } from "./chunk-2DH5OVG4.js";
12
+ } from "./chunk-775FIGGL.js";
13
13
  import {
14
14
  Sandbox,
15
15
  SandboxAdapter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbox-sdk",
3
- "version": "0.1.317",
3
+ "version": "0.1.319",
4
4
  "description": "Swappable coding agents and sandbox providers for Bun and TypeScript.",
5
5
  "license": "MIT",
6
6
  "repository": {