billion-context-pi 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -611,9 +611,13 @@ var TAG_CLOSE = LT + "/acp" + GT;
611
611
  function acpTag(ref, tokens, type) {
612
612
  return TAG_OPEN + 'tokens="' + formatTokens(tokens) + '" type="' + type + '"' + GT + ref + TAG_CLOSE;
613
613
  }
614
- function renderMessage(message, map, countTokens) {
614
+ function renderMessage(message, map, countTokens, strategy) {
615
615
  const ref = refForRaw(map, message.id);
616
616
  if (!ref || ref === BLOCKED_REF) return message;
617
+ if (strategy === "none") return message;
618
+ if (strategy === "text-only" && message.contentType !== "text") {
619
+ return message;
620
+ }
617
621
  const ownTagRe = new RegExp(
618
622
  "^" + escapeRegex(TAG_OPEN) + "[^>]*" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + "\\n?"
619
623
  );
@@ -624,21 +628,24 @@ function renderMessage(message, map, countTokens) {
624
628
  if (!cleanText) return { ...message, text: prefix };
625
629
  return { ...message, text: prefix + cleanText };
626
630
  }
627
- function renderVisibleRefs(messages, state, countTokens = (text) => Math.ceil(text.length / 4)) {
631
+ function renderVisibleRefs(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
628
632
  const map = state.messageRefs;
629
633
  return messages.map(
630
- (message) => renderMessage(message, map, countTokens)
634
+ (message) => renderMessage(message, map, countTokens, strategy)
631
635
  );
632
636
  }
633
- var renderRefsNode = {
634
- name: "render-refs",
635
- run(io, ctx) {
636
- return {
637
- ...io,
638
- messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens)
639
- };
640
- }
641
- };
637
+ function createRenderRefsNode(strategy) {
638
+ return {
639
+ name: "render-refs",
640
+ run(io, ctx) {
641
+ return {
642
+ ...io,
643
+ messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens, strategy)
644
+ };
645
+ }
646
+ };
647
+ }
648
+ var renderRefsNode = createRenderRefsNode("all");
642
649
  var ALWAYS_PROTECTED_TOOLS = ["compress"];
643
650
  var NEVER_PRESERVE_RECENT_TOOLS = [
644
651
  "decompress",
@@ -1009,7 +1016,9 @@ function createCore(ports = {}) {
1009
1016
  state: input.state,
1010
1017
  effects: {}
1011
1018
  };
1012
- const result = runPipeline(defaultNodes(), initial, ctx);
1019
+ const strategy = input.renderTags ?? "all";
1020
+ const nodes = buildNodes(strategy);
1021
+ const result = runPipeline(nodes, initial, ctx);
1013
1022
  return {
1014
1023
  messages: result.messages,
1015
1024
  state: result.state,
@@ -1039,7 +1048,10 @@ function createCore(ports = {}) {
1039
1048
  };
1040
1049
  }
1041
1050
  function defaultNodes() {
1042
- return [
1051
+ return buildNodes("all");
1052
+ }
1053
+ function buildNodes(strategy) {
1054
+ const base = [
1043
1055
  assignRefsNode,
1044
1056
  syncBlocksNode,
1045
1057
  pruneNode,
@@ -1047,9 +1059,10 @@ function createCore(ports = {}) {
1047
1059
  hideCompressCallsNode,
1048
1060
  recommendNode,
1049
1061
  nudgeNode,
1050
- emergencyTruncateNode,
1051
- renderRefsNode
1062
+ emergencyTruncateNode
1052
1063
  ];
1064
+ if (strategy === "none") return base;
1065
+ return [...base, createRenderRefsNode(strategy)];
1053
1066
  }
1054
1067
  return { processTurn, applyCompression, defaultNodes, decompress, search, status };
1055
1068
  }
@@ -2342,6 +2355,8 @@ function makePreview(text, query, len) {
2342
2355
  }
2343
2356
 
2344
2357
  // src/config.ts
2358
+ var DEFAULT_TOOL_BASH_TIMEOUT = 60;
2359
+ var DEFAULT_TOOL_OUTPUT_MAX_BYTES = 2e5;
2345
2360
  function resolveConfig(adapter, liveContextLimit) {
2346
2361
  const envLimit = process.env.ACP_MODEL_CONTEXT_LIMIT;
2347
2362
  const envLimitNum = envLimit ? Number(envLimit) : NaN;
@@ -2359,7 +2374,15 @@ var REF_TAG = new RegExp("^(?:<acp\\s[^>]*>m\\d{5}</acp>|\\[m\\d{1,5}\\])\\s?\\n
2359
2374
  function entriesToCoreMessages(entries) {
2360
2375
  const out = [];
2361
2376
  for (const entry of entries) {
2362
- if (entry.type !== "message") continue;
2377
+ if (entry.type !== "message") {
2378
+ if (entry.type === "custom_message") {
2379
+ const text = extractText(entry.content);
2380
+ if (text.length > 0) {
2381
+ out.push({ id: entry.id, role: "user", contentType: "text", text });
2382
+ }
2383
+ }
2384
+ continue;
2385
+ }
2363
2386
  const cores = projectMessage(entry.message, entry.id);
2364
2387
  out.push(...cores);
2365
2388
  }
@@ -7183,7 +7206,7 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
7183
7206
  config
7184
7207
  });
7185
7208
  await runtime.save(applied.state, ctx);
7186
- const { blocksCreated, tokensCompressed, errors } = applied.result;
7209
+ const { blocksCreated, tokensCompressed, errors, warnings } = applied.result;
7187
7210
  const afterTokens = Math.max(0, beforeTokens - tokensCompressed);
7188
7211
  const newBlocks = applied.state.blocks.slice(-blocksCreated);
7189
7212
  debug.event("compress-out", {
@@ -7200,6 +7223,7 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
7200
7223
  newBlocks: newBlocks.map((b) => ({ blockId: b.blockId, tier: b.tier, summaryLen: b.summary.length, directMsgCount: b.directMessageIds.length, effectiveMsgCount: b.effectiveMessageIds.length, summary: b.summary }))
7201
7224
  });
7202
7225
  const lines = [`\u25A3 ACP | ${formatK2(beforeTokens)} \u2192 ${formatK2(afterTokens)} tokens (~${formatK2(tokensCompressed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
7226
+ if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
7203
7227
  if (errors.length > 0) lines.push("Errors: " + errors.join("; "));
7204
7228
  return lines.join("\n");
7205
7229
  }
@@ -7625,15 +7649,19 @@ var MAX_DEPTH = 2;
7625
7649
  var SYNC_TIMEOUT_MS = 5 * 6e4;
7626
7650
  var RESULT_SUMMARY_CHARS = 500;
7627
7651
  var OUT_DIR = join4(tmpdir2(), "acp-delegate");
7652
+ var ACP_TOOLS = ["compress", "decompress", "search_context", "acp_status"];
7653
+ var RESTRICTED_TOOLS = "read,bash,grep,find,ls";
7628
7654
  var AGENTS = {
7629
7655
  reviewer: {
7630
- tools: "read,bash",
7656
+ tools: RESTRICTED_TOOLS,
7657
+ restricted: true,
7631
7658
  prompt: `You are a senior code reviewer with read-only access.
7632
7659
  Read the given code and report: bugs, security/safety risks, correctness issues, and concrete improvement suggestions.
7633
7660
  Be specific \u2014 cite file:line for every finding. Do NOT modify any files; only read and report.`
7634
7661
  },
7635
7662
  researcher: {
7636
- tools: "read,bash",
7663
+ tools: RESTRICTED_TOOLS,
7664
+ restricted: true,
7637
7665
  prompt: `You are a code researcher with read-only access.
7638
7666
  Investigate the codebase to answer the question thoroughly. Report findings with exact file:line references, function/type signatures, and relevant code snippets.
7639
7667
  Do NOT modify any files; only read and report.`
@@ -7645,13 +7673,15 @@ Make exactly the requested code changes \u2014 minimal, focused, following exist
7645
7673
  After editing, briefly summarize what you changed and why. Do not expand scope.`
7646
7674
  },
7647
7675
  planner: {
7648
- tools: "read,bash",
7676
+ tools: RESTRICTED_TOOLS,
7677
+ restricted: true,
7649
7678
  prompt: `You are a technical planner with read-only access.
7650
7679
  Analyze the task and produce a concrete, ordered step-by-step implementation plan with rationale for each step.
7651
7680
  Cite file:line for code you reference. Do NOT modify any files; only read and propose.`
7652
7681
  },
7653
7682
  oracle: {
7654
- tools: "read,bash",
7683
+ tools: RESTRICTED_TOOLS,
7684
+ restricted: true,
7655
7685
  prompt: `You are an expert advisor with read-only access.
7656
7686
  Answer the question concisely with clear reasoning. Cite file:line when referencing code. Do NOT modify any files.`
7657
7687
  }
@@ -7707,7 +7737,7 @@ var agentListLine = (name) => {
7707
7737
  planner: "analyze + propose step-by-step plan (read-only)",
7708
7738
  oracle: "answer questions / advise (read-only)"
7709
7739
  };
7710
- return ` \u2022 ${name} \u2014 ${blurb[name]} [tools: ${def.tools}]`;
7740
+ return ` \u2022 ${name} - ${blurb[name]} [tools: ${def.tools}${def.restricted ? " + ACP context tools" : ""}]`;
7711
7741
  };
7712
7742
  function makeDelegateTool(pi) {
7713
7743
  return {
@@ -7748,6 +7778,12 @@ function remainingLineForWait(selfRunId) {
7748
7778
  const remaining = Array.from(runs.values()).filter((r) => r.status === "running" && r.runId !== selfRunId).length;
7749
7779
  return remaining > 0 ? ` ${remaining} delegate${remaining === 1 ? " is" : "s are"} still running.` : "";
7750
7780
  }
7781
+ function injectedWaitMessage(run, runId, remainingLine) {
7782
+ if (!run.injected) return null;
7783
+ const file = run.result?.file;
7784
+ const fileLine = file ? ` If you need details, read the result file: \`${file}\`.` : "";
7785
+ return `Delegate \`${runId}\` already delivered its result via a system notification when it finished \u2014 no need to wait on it again.${remainingLine}${fileLine}`;
7786
+ }
7751
7787
  function makeDelegateWaitTool(_pi) {
7752
7788
  return {
7753
7789
  name: "acp_delegate_wait",
@@ -7770,6 +7806,11 @@ function makeDelegateWaitTool(_pi) {
7770
7806
  return { details: void 0, content: [{ type: "text", text: `Delegate \`${args.runId}\` was cancelled (no result).${remainingLineForWait(args.runId)}` }] };
7771
7807
  }
7772
7808
  if (run.status !== "running") {
7809
+ const dedup = injectedWaitMessage(run, args.runId, remainingLineForWait(args.runId));
7810
+ if (dedup) {
7811
+ run.consumed = true;
7812
+ return { details: void 0, content: [{ type: "text", text: dedup }] };
7813
+ }
7773
7814
  run.consumed = true;
7774
7815
  if (!run.result) {
7775
7816
  return { details: void 0, content: [{ type: "text", text: `Delegate \`${args.runId}\` finished but no result is available (persist error).` }] };
@@ -7934,6 +7975,7 @@ async function runDelegate(pi, args, ctx, signal) {
7934
7975
  return;
7935
7976
  }
7936
7977
  const injected = injectResult(pi, args.agent, runId, args.task, code, file2);
7978
+ run.injected = injected;
7937
7979
  debug.event("delegate-done", { runId, code, status: run.status, injected, outLen: output.length, file: file2 });
7938
7980
  delegateStatusWidget.poke();
7939
7981
  }).catch((err) => {
@@ -7979,6 +8021,11 @@ async function buildChildArgs(args, rolePrompt, ctx) {
7979
8021
 
7980
8022
  Complete the task below.`, "utf8");
7981
8023
  const cliArgs = ["-p", "--no-session", "--append-system-prompt", promptFile];
8024
+ const agentDef = AGENTS[args.agent];
8025
+ if (agentDef?.restricted) {
8026
+ const merged = [.../* @__PURE__ */ new Set([...agentDef.tools.split(",").map((s) => s.trim()), ...ACP_TOOLS])];
8027
+ cliArgs.push("--tools", merged.join(","));
8028
+ }
7982
8029
  if (args.model && args.model.includes("/")) {
7983
8030
  const [providerId, ...rest] = args.model.split("/");
7984
8031
  const modelId = rest.join("/");
@@ -8185,7 +8232,7 @@ async function statusReport(runtime, ctx) {
8185
8232
  const activeBlocksList = state.blocks.filter((b) => b.active);
8186
8233
  const totalBlocksList = state.blocks;
8187
8234
  const lines = [];
8188
- const versionStr = "0.1.24" ? `billion-context-pi@${"0.1.24"}` : "";
8235
+ const versionStr = "0.1.26" ? `billion-context-pi@${"0.1.26"}` : "";
8189
8236
  lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
8190
8237
  lines.push("\u2502 ACP Context Analysis \u2502");
8191
8238
  lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
@@ -8327,6 +8374,116 @@ When a background delegate finishes, an automated completion notification is inj
8327
8374
  - Arrive asynchronously: if you have moved on to other work, only act on a notification if it is relevant to the current task; otherwise note it and continue.
8328
8375
  `;
8329
8376
 
8377
+ // src/tool-guardrails.ts
8378
+ import {
8379
+ isBashToolResult,
8380
+ isToolCallEventType
8381
+ } from "@earendil-works/pi-coding-agent";
8382
+ function resolveBashTimeout(input, defaultTimeout) {
8383
+ if (input.timeout !== void 0) return void 0;
8384
+ const d = defaultTimeout ?? DEFAULT_TOOL_BASH_TIMEOUT;
8385
+ if (!Number.isFinite(d) || d <= 0) return void 0;
8386
+ return d;
8387
+ }
8388
+ function capToolOutput(content, maxBytes, fullPath) {
8389
+ const max = maxBytes ?? DEFAULT_TOOL_OUTPUT_MAX_BYTES;
8390
+ if (!Number.isFinite(max) || max <= 0) return void 0;
8391
+ const kept = [];
8392
+ const texts = [];
8393
+ for (const c of content) {
8394
+ if (c.type === "text") texts.push(c.text);
8395
+ else kept.push(c);
8396
+ }
8397
+ if (texts.length === 0) return void 0;
8398
+ const combined = texts.join("\n");
8399
+ const total = Buffer.byteLength(combined, "utf8");
8400
+ if (total <= max) return void 0;
8401
+ const head = keepHead(combined, max);
8402
+ const dropped = total - Buffer.byteLength(head, "utf8");
8403
+ kept.push({ type: "text", text: head + buildCapNotice(dropped, max, fullPath) });
8404
+ return kept;
8405
+ }
8406
+ var TIMEOUT_RE = /Command timed out after (\d+) seconds/;
8407
+ function detectBashTimeout(content) {
8408
+ for (const c of content) {
8409
+ if (c.type !== "text") continue;
8410
+ const m = c.text.match(TIMEOUT_RE);
8411
+ if (m) return Number(m[1]);
8412
+ }
8413
+ return void 0;
8414
+ }
8415
+ function appendTimeoutNotice(content, secs) {
8416
+ const notice = buildTimeoutNotice(secs);
8417
+ const next = [...content];
8418
+ for (let i = next.length - 1; i >= 0; i--) {
8419
+ const part = next[i];
8420
+ if (part && part.type === "text") {
8421
+ next[i] = { type: "text", text: part.text + notice };
8422
+ return next;
8423
+ }
8424
+ }
8425
+ next.push({ type: "text", text: notice });
8426
+ return next;
8427
+ }
8428
+ function keepHead(str, maxBytes) {
8429
+ const buf = Buffer.from(str, "utf8");
8430
+ if (buf.length <= maxBytes) return str;
8431
+ let end = maxBytes;
8432
+ while (end > 0) {
8433
+ const b = buf[end];
8434
+ if (b === void 0 || (b & 192) !== 128) break;
8435
+ end--;
8436
+ }
8437
+ let head = buf.subarray(0, end).toString("utf8");
8438
+ const nl = head.lastIndexOf("\n");
8439
+ if (nl >= Math.floor(maxBytes / 2)) head = head.slice(0, nl);
8440
+ return head;
8441
+ }
8442
+ function buildCapNotice(dropped, maxBytes, fullPath) {
8443
+ const where = fullPath ? `Full output saved to: ${fullPath} \u2014 read it to see everything.` : "To see more, narrow the query or redirect output to a file and read the relevant slice.";
8444
+ return `
8445
+
8446
+ [ACP guardrail: output capped at ${formatBytes(maxBytes)} (~${formatBytes(dropped)} dropped). ${where}]`;
8447
+ }
8448
+ function buildTimeoutNotice(secs) {
8449
+ const suggested = Math.min(Math.max(Math.ceil(secs * 2), 120), 3600);
8450
+ return `
8451
+
8452
+ [ACP guardrail: command killed after ${secs}s. To give it more time, re-run the bash tool with a larger \`timeout\` argument (e.g. \`"timeout": ${suggested}\`).]`;
8453
+ }
8454
+ function formatBytes(n) {
8455
+ return n >= 1024 ? `${(n / 1024).toFixed(1)}KB` : `${n}B`;
8456
+ }
8457
+ function wireToolGuardrails(pi, runtime) {
8458
+ pi.on("tool_call", (event) => {
8459
+ if (!isToolCallEventType("bash", event)) return;
8460
+ const t = resolveBashTimeout(event.input, runtime.adapter.toolBashDefaultTimeout);
8461
+ if (t !== void 0) {
8462
+ event.input.timeout = t;
8463
+ debug.event("guardrail-bash-timeout", { applied: t });
8464
+ }
8465
+ });
8466
+ pi.on("tool_result", (event) => {
8467
+ const isBash = isBashToolResult(event);
8468
+ const fullPath = isBash ? event.details?.fullOutputPath : void 0;
8469
+ const timeoutSecs = isBash && event.isError ? detectBashTimeout(event.content) : void 0;
8470
+ let modified;
8471
+ const max = runtime.adapter.toolOutputMaxBytes;
8472
+ if (max !== void 0 && max > 0) {
8473
+ const next = capToolOutput(event.content, max, fullPath);
8474
+ if (next) {
8475
+ modified = next;
8476
+ debug.event("guardrail-output-cap", { max, hadPath: !!fullPath });
8477
+ }
8478
+ }
8479
+ if (timeoutSecs !== void 0) {
8480
+ modified = appendTimeoutNotice(modified ?? event.content, timeoutSecs);
8481
+ debug.event("guardrail-bash-timeout-notice", { secs: timeoutSecs });
8482
+ }
8483
+ if (modified) return { content: modified };
8484
+ });
8485
+ }
8486
+
8330
8487
  // src/update.ts
8331
8488
  import { readFile, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
8332
8489
  import { join as join5, dirname as dirname3 } from "path";
@@ -8433,7 +8590,7 @@ async function checkForUpdate(autoUpdate, notify) {
8433
8590
  const data = await res.json();
8434
8591
  const latest = data.version;
8435
8592
  if (!latest) return;
8436
- const current = runtimeVersion ?? "0.1.24";
8593
+ const current = runtimeVersion ?? "0.1.26";
8437
8594
  debug.event("update-check", {
8438
8595
  current,
8439
8596
  latest,
@@ -8468,7 +8625,7 @@ import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename
8468
8625
  import { existsSync } from "fs";
8469
8626
  import { homedir as homedir4 } from "os";
8470
8627
  import { join as join6 } from "path";
8471
- var ACP_TOOLS = ["compress", "decompress", "search_context", "acp_status"];
8628
+ var ACP_TOOLS2 = ["compress", "decompress", "search_context", "acp_status"];
8472
8629
  var BUILTIN_DEFAULT_TOOLS = {
8473
8630
  advisor: ["read", "grep", "find", "ls", "bash", "intercom"],
8474
8631
  "context-builder": ["read", "grep", "find", "ls", "bash", "write", "web_search", "intercom"],
@@ -8488,9 +8645,9 @@ function resolveAgentDir() {
8488
8645
  }
8489
8646
  function desiredTools(existing, name) {
8490
8647
  const base = Array.isArray(existing?.tools) && existing.tools.length > 0 ? [...existing.tools] : [...BUILTIN_DEFAULT_TOOLS[name] ?? []];
8491
- const hasAll = ACP_TOOLS.every((t) => base.includes(t));
8648
+ const hasAll = ACP_TOOLS2.every((t) => base.includes(t));
8492
8649
  if (hasAll) return { tools: base, changed: false };
8493
- for (const t of ACP_TOOLS) if (!base.includes(t)) base.push(t);
8650
+ for (const t of ACP_TOOLS2) if (!base.includes(t)) base.push(t);
8494
8651
  return { tools: base, changed: true };
8495
8652
  }
8496
8653
  async function ensureSubagentAcpTools(settingsPath) {
@@ -8561,7 +8718,7 @@ async function ensureSubagentAcpTools(settingsPath) {
8561
8718
  if (typeof v !== "object" || v === null) throw new Error("agentOverrides missing after write");
8562
8719
  for (const name of Object.keys(BUILTIN_DEFAULT_TOOLS)) {
8563
8720
  const tools = v[name]?.tools;
8564
- if (!Array.isArray(tools) || !ACP_TOOLS.every((t) => tools.includes(t))) {
8721
+ if (!Array.isArray(tools) || !ACP_TOOLS2.every((t) => tools.includes(t))) {
8565
8722
  throw new Error(`${name} missing ACP tools after write`);
8566
8723
  }
8567
8724
  }
@@ -8613,7 +8770,7 @@ async function loadUserConfig(cwd) {
8613
8770
  function join8(...parts) {
8614
8771
  return path3.join(...parts);
8615
8772
  }
8616
- var KNOWN = /* @__PURE__ */ new Set(["debug", "autoUpdate", "modelContextLimit", "delegate"]);
8773
+ var KNOWN = /* @__PURE__ */ new Set(["debug", "autoUpdate", "modelContextLimit", "delegate", "toolBashDefaultTimeout", "toolOutputMaxBytes"]);
8617
8774
  function pickKnown(parsed) {
8618
8775
  const out = {};
8619
8776
  for (const [k, v] of Object.entries(parsed)) {
@@ -8641,6 +8798,7 @@ function createAcpExtension(adapter = {}) {
8641
8798
  wireSessionLifecycle(pi, runtime);
8642
8799
  wireContextTransform(pi, runtime);
8643
8800
  wireSystemPrompt(pi, runtime);
8801
+ wireToolGuardrails(pi, runtime);
8644
8802
  pi.registerTool(makeCompressTool(runtime));
8645
8803
  pi.registerTool(makeDecompressTool(runtime));
8646
8804
  pi.registerTool(makeSearchTool(runtime));
@@ -8767,7 +8925,12 @@ ${prompt}` };
8767
8925
  function collectOriginals(entries) {
8768
8926
  const map = /* @__PURE__ */ new Map();
8769
8927
  for (const entry of entries) {
8770
- if (entry.type === "message") map.set(entry.id, entry.message);
8928
+ if (entry.type === "message") {
8929
+ map.set(entry.id, entry.message);
8930
+ } else if (entry.type === "custom_message") {
8931
+ const content = typeof entry.content === "string" ? [{ type: "text", text: entry.content }] : entry.content;
8932
+ map.set(entry.id, { role: "user", content });
8933
+ }
8771
8934
  }
8772
8935
  return map;
8773
8936
  }