billion-context 0.1.93 → 0.1.94-pr.633.454

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
@@ -43650,7 +43650,7 @@ function formatRanges(compressible, protectedRanges) {
43650
43650
  if (compressible.length === 0 && protectedRanges.length === 0) {
43651
43651
  return "[No specific ranges detected \u2014 compress any consumed content.]";
43652
43652
  }
43653
- const refNum4 = (ref) => {
43653
+ const refNum3 = (ref) => {
43654
43654
  const m2 = ref.match(/\d+/);
43655
43655
  return m2 ? parseInt(m2[0], 10) : 0;
43656
43656
  };
@@ -43659,8 +43659,8 @@ function formatRanges(compressible, protectedRanges) {
43659
43659
  entries.push({
43660
43660
  startRef: r.startRef,
43661
43661
  endRef: r.endRef,
43662
- startNum: refNum4(r.startRef),
43663
- endNum: refNum4(r.endRef),
43662
+ startNum: refNum3(r.startRef),
43663
+ endNum: refNum3(r.endRef),
43664
43664
  count: r.count,
43665
43665
  tokens: r.tokens,
43666
43666
  toolPct: r.toolPct,
@@ -43677,8 +43677,8 @@ function formatRanges(compressible, protectedRanges) {
43677
43677
  entries.push({
43678
43678
  startRef: r.startRef,
43679
43679
  endRef: r.endRef,
43680
- startNum: refNum4(r.startRef),
43681
- endNum: refNum4(r.endRef),
43680
+ startNum: refNum3(r.startRef),
43681
+ endNum: refNum3(r.endRef),
43682
43682
  count: r.count,
43683
43683
  tokens: r.tokens,
43684
43684
  toolPct: 0,
@@ -45328,10 +45328,6 @@ function adjustBoundariesForReasoningPairs(startIndex, endIndex, messages) {
45328
45328
  }
45329
45329
  return { startIndex: newStartIndex, endIndex: newEndIndex };
45330
45330
  }
45331
- function refNum(ref) {
45332
- const n = parseInt(ref.slice(1), 10);
45333
- return Number.isNaN(n) ? -1 : n;
45334
- }
45335
45331
  function estimateTextTokens(text) {
45336
45332
  return Math.ceil(text.length / 4);
45337
45333
  }
@@ -45384,42 +45380,50 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
45384
45380
  const compressibleMsgs = [];
45385
45381
  const protectedMsgs = [];
45386
45382
  const protectedCallIds = collectProtectedToolCallIds(messages, config);
45383
+ let skipSinceCompressible = false;
45384
+ let skipSinceProtected = false;
45387
45385
  for (const msg of messages) {
45388
- if (isSyntheticOrPruned(msg, state)) continue;
45389
45386
  const ref = state.messageRefs.byRaw[msg.id];
45390
45387
  if (!ref || ref === "BLOCKED") continue;
45391
- const rn2 = refNum(ref);
45388
+ if (isSyntheticOrPruned(msg, state)) {
45389
+ skipSinceCompressible = true;
45390
+ skipSinceProtected = true;
45391
+ continue;
45392
+ }
45392
45393
  if (isMessageProtectedWithPairing(msg, config, protectedCallIds)) {
45393
45394
  protectedMsgs.push({
45394
45395
  ref,
45395
- refNum: rn2,
45396
+ gapBefore: skipSinceProtected,
45396
45397
  tokens: countTokens(msg.text ?? ""),
45397
45398
  tools: msg.toolName ? [msg.toolName] : []
45398
45399
  });
45400
+ skipSinceProtected = false;
45401
+ skipSinceCompressible = true;
45399
45402
  continue;
45400
45403
  }
45401
45404
  if (protectedZoneRefs?.has(ref)) {
45405
+ skipSinceCompressible = true;
45406
+ skipSinceProtected = true;
45402
45407
  continue;
45403
45408
  }
45404
45409
  compressibleMsgs.push({
45405
45410
  ref,
45406
- refNum: rn2,
45411
+ gapBefore: skipSinceCompressible,
45407
45412
  tokens: countTokens(msg.text ?? ""),
45408
45413
  chars: (msg.text ?? "").length,
45409
45414
  isTool: isToolMessage(msg),
45410
45415
  isUser: msg.role === "user"
45411
45416
  });
45417
+ skipSinceCompressible = false;
45418
+ skipSinceProtected = true;
45412
45419
  }
45413
45420
  const compressible = [];
45414
45421
  let cur = null;
45415
- let prevRefNum = -2;
45416
45422
  for (const info of compressibleMsgs) {
45417
- const hasGap = info.refNum > prevRefNum + 1;
45418
- if (cur && (info.isUser && cur.count >= 3 || hasGap)) {
45423
+ if (cur && (info.isUser && cur.count >= 3 || info.gapBefore)) {
45419
45424
  compressible.push(cur);
45420
45425
  cur = null;
45421
45426
  }
45422
- prevRefNum = info.refNum;
45423
45427
  if (!cur) {
45424
45428
  cur = {
45425
45429
  startRef: info.ref,
@@ -45446,14 +45450,11 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
45446
45450
  if (cur) compressible.push(cur);
45447
45451
  const protectedRanges = [];
45448
45452
  let pcur = null;
45449
- let pPrevRefNum = -2;
45450
45453
  for (const info of protectedMsgs) {
45451
- const hasGap = info.refNum > pPrevRefNum + 1;
45452
- if (pcur && hasGap) {
45454
+ if (pcur && info.gapBefore) {
45453
45455
  protectedRanges.push(pcur);
45454
45456
  pcur = null;
45455
45457
  }
45456
- pPrevRefNum = info.refNum;
45457
45458
  if (!pcur) {
45458
45459
  pcur = {
45459
45460
  startRef: info.ref,
@@ -46647,7 +46648,7 @@ function renderUncompressedRanges(visible) {
46647
46648
  lines.push(" (no uncompressed messages)");
46648
46649
  return lines.join("\n");
46649
46650
  }
46650
- const refNum22 = (ref) => {
46651
+ const refNum3 = (ref) => {
46651
46652
  const m2 = ref.match(/\d+/);
46652
46653
  return m2 ? parseInt(m2[0], 10) : 0;
46653
46654
  };
@@ -46664,7 +46665,7 @@ function renderUncompressedRanges(visible) {
46664
46665
  };
46665
46666
  const merged = [];
46666
46667
  for (const m2 of visible) {
46667
- const num3 = refNum22(m2.ref);
46668
+ const num3 = refNum3(m2.ref);
46668
46669
  const last = merged[merged.length - 1];
46669
46670
  if (last && num3 === last.startNum + last.count) {
46670
46671
  last.endRef = m2.ref;
@@ -46740,6 +46741,74 @@ function renderCompressedDrilldown(blocks, state, sort, limit, countTokens) {
46740
46741
  }
46741
46742
  return lines.join("\n");
46742
46743
  }
46744
+ function renderMessage2(m2) {
46745
+ const parts = [];
46746
+ switch (m2.contentType) {
46747
+ case "text":
46748
+ parts.push(m2.text ?? "");
46749
+ break;
46750
+ case "tool-call":
46751
+ parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` args: ${m2.text ?? ""}`);
46752
+ break;
46753
+ case "tool-result":
46754
+ parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` \u2192 ${m2.text ?? ""}`);
46755
+ break;
46756
+ case "reasoning":
46757
+ parts.push(`_reasoning_: ${m2.text ?? ""}`);
46758
+ break;
46759
+ }
46760
+ const body = parts.join("\n").trim();
46761
+ return body === "" ? "_(empty)_" : body + "\n";
46762
+ }
46763
+ function renderHandoff(input) {
46764
+ const { coreMessages, state, full, meta } = input;
46765
+ const lines = [];
46766
+ lines.push("# billion-context session handoff");
46767
+ lines.push("");
46768
+ lines.push(`- title: ${meta.title ?? "(untitled)"}`);
46769
+ if (meta.label) lines.push(`- label: ${meta.label}`);
46770
+ lines.push(`- session id: ${meta.sessionId}`);
46771
+ for (const bullet of meta.extraBullets ?? []) lines.push(bullet);
46772
+ if (meta.contextTokens) lines.push(`- last context tokens: ~${meta.contextTokens}`);
46773
+ lines.push(`- compression blocks: ${state.blocks.length} (active ${state.blocks.filter((b2) => b2.active).length})`);
46774
+ lines.push("");
46775
+ const folded = input.folded === true;
46776
+ const view = full || folded ? coreMessages : prune(coreMessages, state);
46777
+ lines.push(full && !folded ? `## Full conversation (${coreMessages.length} messages)` : folded ? `## Conversation (persisted folded snapshot, ${coreMessages.length} messages)` : `## Conversation (folded view as the model saw it, ${coreMessages.length} client messages)`);
46778
+ lines.push("");
46779
+ if (view.length === 0) {
46780
+ lines.push("No conversation messages to export.");
46781
+ lines.push("");
46782
+ }
46783
+ let lastRole = "";
46784
+ for (const m2 of view) {
46785
+ if (m2.role !== lastRole) {
46786
+ lines.push(`### ${m2.role}`);
46787
+ lines.push("");
46788
+ lastRole = m2.role;
46789
+ }
46790
+ lines.push(renderMessage2(m2));
46791
+ }
46792
+ lines.push("");
46793
+ if (full && folded) {
46794
+ for (const b2 of input.blocksFull ?? []) {
46795
+ lines.push(`## Block ${b2.blockId}${b2.topic ? ` \u2014 ${b2.topic}` : ""}`);
46796
+ lines.push("");
46797
+ lines.push(`### Original messages (${b2.count})`);
46798
+ lines.push("");
46799
+ lines.push(b2.fullText.trim());
46800
+ lines.push("");
46801
+ }
46802
+ }
46803
+ return lines.join("\n");
46804
+ }
46805
+ function matchSession(sessions2, selector, labelOf) {
46806
+ const exact = sessions2.filter((s3) => s3.id === selector);
46807
+ if (exact.length > 0) return exact;
46808
+ const byLabel = sessions2.filter((s3) => labelOf(s3) === selector);
46809
+ if (byLabel.length > 0) return byLabel;
46810
+ return sessions2.filter((s3) => s3.id.startsWith(selector) || (labelOf(s3) ?? "").startsWith(selector));
46811
+ }
46743
46812
  function parseCompressArgs(input, opts) {
46744
46813
  const callId = opts?.callId;
46745
46814
  const diag = { ok: false, kind: "ok", invalidItems: 0 };
@@ -46760,6 +46829,23 @@ function parseStringInput(raw, callId, diag) {
46760
46829
  diag.rawPrefix = raw.slice(0, 800);
46761
46830
  diag.length = raw.length;
46762
46831
  const cleaned = stripFence(raw.trim());
46832
+ const first = parseStringCore(cleaned, callId, diag);
46833
+ if (first.ranges.length === 0 || first.diagnostics.invalidItems > 0) {
46834
+ const normalized = normalizeSingleQuotes(cleaned);
46835
+ if (normalized !== void 0) {
46836
+ const retryDiag = { ok: false, kind: "ok", invalidItems: 0 };
46837
+ retryDiag.rawPrefix = diag.rawPrefix;
46838
+ retryDiag.length = diag.length;
46839
+ const retry = parseStringCore(normalized, callId, retryDiag);
46840
+ if (retry.ranges.length > first.ranges.length) {
46841
+ retryDiag.quoteSalvage = true;
46842
+ return retry;
46843
+ }
46844
+ }
46845
+ }
46846
+ return first;
46847
+ }
46848
+ function parseStringCore(cleaned, callId, diag) {
46763
46849
  if (cleaned === "") {
46764
46850
  diag.kind = "empty-input";
46765
46851
  return finish([], diag);
@@ -46803,6 +46889,7 @@ function parseObjectValue(value, callId, diag) {
46803
46889
  }
46804
46890
  entries = parsed.entries;
46805
46891
  salvaged = parsed.salvaged;
46892
+ if (parsed.quoteRepaired) diag.quoteSalvage = true;
46806
46893
  } else {
46807
46894
  diag.kind = "content-not-array";
46808
46895
  return finish([], diag);
@@ -46824,7 +46911,17 @@ function parseObjectValue(value, callId, diag) {
46824
46911
  }
46825
46912
  function parseContentArray(s3) {
46826
46913
  const cleaned = stripFence(s3.trim());
46827
- let value = cleaned === "" ? void 0 : tryParseLenient(cleaned);
46914
+ const direct = parseContentArrayCore(cleaned);
46915
+ if (direct !== null && direct.entries.length > 0) return direct;
46916
+ const normalized = normalizeSingleQuotes(cleaned);
46917
+ if (normalized !== void 0) {
46918
+ const retry = parseContentArrayCore(normalized);
46919
+ if (retry !== null && retry.entries.length > 0) return { ...retry, quoteRepaired: true };
46920
+ }
46921
+ return direct;
46922
+ }
46923
+ function parseContentArrayCore(s3) {
46924
+ let value = s3 === "" ? void 0 : tryParseLenient(s3);
46828
46925
  if (typeof value === "string") {
46829
46926
  value = tryParseLenient(stripFence(value));
46830
46927
  }
@@ -46832,7 +46929,7 @@ function parseContentArray(s3) {
46832
46929
  return { entries: value, salvaged: false };
46833
46930
  }
46834
46931
  if (value === void 0) {
46835
- const entries = salvageContentEntries('{"content": ' + cleaned);
46932
+ const entries = salvageContentEntries('{"content": ' + s3);
46836
46933
  return { entries, salvaged: entries.length > 0 };
46837
46934
  }
46838
46935
  return null;
@@ -46905,6 +47002,71 @@ function tryParseLenient(s3) {
46905
47002
  }
46906
47003
  return void 0;
46907
47004
  }
47005
+ function normalizeSingleQuotes(raw) {
47006
+ if (!raw.includes("'") || !raw.includes("{") && !raw.includes("[")) return void 0;
47007
+ let out = "";
47008
+ let changed = false;
47009
+ let inDouble = false;
47010
+ let inSingle = false;
47011
+ for (let i = 0; i < raw.length; i++) {
47012
+ const ch = raw.charAt(i);
47013
+ if (inDouble) {
47014
+ out += ch;
47015
+ if (ch === "\\" && i + 1 < raw.length) {
47016
+ out += raw.charAt(i + 1);
47017
+ i++;
47018
+ } else if (ch === '"') {
47019
+ inDouble = false;
47020
+ }
47021
+ continue;
47022
+ }
47023
+ if (inSingle) {
47024
+ if (ch === "\\" && i + 1 < raw.length) {
47025
+ const next = raw.charAt(i + 1);
47026
+ out += next === "'" ? "'" : "\\" + next;
47027
+ i++;
47028
+ continue;
47029
+ }
47030
+ if (ch === "'") {
47031
+ out += '"';
47032
+ inSingle = false;
47033
+ changed = true;
47034
+ continue;
47035
+ }
47036
+ if (ch === '"') {
47037
+ out += '\\"';
47038
+ continue;
47039
+ }
47040
+ if (ch === "\n") {
47041
+ out += "\\n";
47042
+ continue;
47043
+ }
47044
+ if (ch === "\r") {
47045
+ out += "\\r";
47046
+ continue;
47047
+ }
47048
+ if (ch === " ") {
47049
+ out += "\\t";
47050
+ continue;
47051
+ }
47052
+ out += ch;
47053
+ continue;
47054
+ }
47055
+ if (ch === '"') {
47056
+ inDouble = true;
47057
+ out += ch;
47058
+ continue;
47059
+ }
47060
+ if (ch === "'") {
47061
+ inSingle = true;
47062
+ out += '"';
47063
+ changed = true;
47064
+ continue;
47065
+ }
47066
+ out += ch;
47067
+ }
47068
+ return changed ? out : void 0;
47069
+ }
46908
47070
  function stripFence(s3) {
46909
47071
  if (!s3.startsWith("```")) return s3;
46910
47072
  const firstNewline = s3.indexOf("\n");
@@ -48293,6 +48455,7 @@ function loadOptions(env = process.env) {
48293
48455
  passthrough: passthrough.enabled,
48294
48456
  passthroughSource: passthrough.source,
48295
48457
  autoUpdate: (env.ACP_AUTO_UPDATE ?? (fileConfig.autoUpdate === false ? "0" : "1")) !== "0",
48458
+ updateTag: (env.ACP_UPDATE_TAG ?? fileConfig.updateTag ?? "latest").trim() || "latest",
48296
48459
  logFile: env.ACP_LOG_FILE !== void 0 ? env.ACP_LOG_FILE || void 0 : fileConfig.logFile,
48297
48460
  mitm: {
48298
48461
  enabled: (env.BILI_MITM ?? (fileConfig.mitm?.enabled === false ? "0" : "1")) !== "0",
@@ -49141,6 +49304,7 @@ function anthropicToCore(body) {
49141
49304
  const msgs = [];
49142
49305
  const cacheControls = /* @__PURE__ */ new Map();
49143
49306
  const clusters = new ClusterCounter();
49307
+ const toolNames = /* @__PURE__ */ new Map();
49144
49308
  for (const m2 of body.messages) {
49145
49309
  const blocks = typeof m2.content === "string" ? [{ type: "text", text: m2.content }] : m2.content;
49146
49310
  for (const b2 of blocks) {
@@ -49166,6 +49330,7 @@ function anthropicToCore(body) {
49166
49330
  toolCallId: b2.id,
49167
49331
  text: safeStringify(b2.input)
49168
49332
  });
49333
+ toolNames.set(b2.id, b2.name);
49169
49334
  if (b2.cache_control) cacheControls.set(id, b2.cache_control);
49170
49335
  break;
49171
49336
  }
@@ -49173,12 +49338,14 @@ function anthropicToCore(body) {
49173
49338
  const text = typeof b2.content === "string" ? b2.content : b2.content.map((c) => c.text).join("\n");
49174
49339
  const base = deriveMessageId("tool", "tool-result", text, { toolCallId: b2.tool_use_id });
49175
49340
  const id = clusters.next(base);
49341
+ const name = toolNames.get(b2.tool_use_id);
49176
49342
  msgs.push({
49177
49343
  id,
49178
49344
  role: "tool",
49179
49345
  contentType: "tool-result",
49180
49346
  toolCallId: b2.tool_use_id,
49181
49347
  text,
49348
+ ...name ? { toolName: name } : {},
49182
49349
  ...b2.is_error === true ? { toolIsError: true } : {}
49183
49350
  });
49184
49351
  if (b2.cache_control) cacheControls.set(id, b2.cache_control);
@@ -49326,6 +49493,7 @@ function openaiToCore(body) {
49326
49493
  const msgs = [];
49327
49494
  const systemParts = [];
49328
49495
  const clusters = new ClusterCounter();
49496
+ const toolNames = /* @__PURE__ */ new Map();
49329
49497
  for (const m2 of body.messages) {
49330
49498
  switch (m2.role) {
49331
49499
  case "system":
@@ -49393,6 +49561,7 @@ function openaiToCore(body) {
49393
49561
  toolCallId: tc.id,
49394
49562
  text: tc.function.arguments ?? ""
49395
49563
  });
49564
+ toolNames.set(tc.id, tc.function.name);
49396
49565
  }
49397
49566
  }
49398
49567
  break;
@@ -49401,12 +49570,14 @@ function openaiToCore(body) {
49401
49570
  const base = deriveMessageId("tool", "tool-result", stringContent(m2.content), {
49402
49571
  toolCallId: m2.tool_call_id ?? ""
49403
49572
  });
49573
+ const name = m2.name || toolNames.get(m2.tool_call_id ?? "");
49404
49574
  msgs.push({
49405
49575
  id: clusters.next(base),
49406
49576
  role: "tool",
49407
49577
  contentType: "tool-result",
49408
49578
  toolCallId: m2.tool_call_id ?? "",
49409
- text: stringContent(m2.content)
49579
+ text: stringContent(m2.content),
49580
+ ...name ? { toolName: name } : {}
49410
49581
  });
49411
49582
  break;
49412
49583
  }
@@ -49511,7 +49682,7 @@ function allImageParts(content) {
49511
49682
  if (typeof p2 !== "object" || p2 === null) continue;
49512
49683
  if (!("type" in p2) || p2.type !== "image_url" || !("image_url" in p2)) continue;
49513
49684
  const imagePart = p2;
49514
- const url = imagePart.image_url.url;
49685
+ const url = imagePart.image_url?.url;
49515
49686
  if (typeof url === "string" && parseDataUrl(url)) out.push(p2);
49516
49687
  }
49517
49688
  return out;
@@ -49523,6 +49694,14 @@ var OPAQUE_ITEM_TYPES = /* @__PURE__ */ new Set([
49523
49694
  function isOpaqueItem(item) {
49524
49695
  return OPAQUE_ITEM_TYPES.has(item.type);
49525
49696
  }
49697
+ var EASY_INPUT_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "system", "developer"]);
49698
+ function normalizeEasyInputItem(item) {
49699
+ if (typeof item.type === "string") return item;
49700
+ if (EASY_INPUT_ROLES.has(String(item.role))) {
49701
+ return { ...item, type: "message" };
49702
+ }
49703
+ return item;
49704
+ }
49526
49705
  function shouldDropAllReasoning() {
49527
49706
  return (process.env.ACP_REASONING_KEEP ?? "").trim().toLowerCase() === "none";
49528
49707
  }
@@ -49559,6 +49738,7 @@ function responsesToCore(body) {
49559
49738
  const layout = [];
49560
49739
  let droppedReasoning = 0;
49561
49740
  const clusters = new ClusterCounter();
49741
+ const toolNames = /* @__PURE__ */ new Map();
49562
49742
  let idx = 0;
49563
49743
  if (typeof body.instructions === "string" && body.instructions.trim()) systemParts.push(body.instructions);
49564
49744
  if (typeof body.input === "string") {
@@ -49566,7 +49746,8 @@ function responsesToCore(body) {
49566
49746
  msgs.push({ id, role: "user", contentType: "text", text: body.input });
49567
49747
  return { msgs, systemParts, preamble, customToolCallIds, layout, droppedReasoning, stringInput: { original: body.input, coreId: id } };
49568
49748
  }
49569
- for (const item of body.input) {
49749
+ for (const raw of body.input) {
49750
+ const item = normalizeEasyInputItem(raw);
49570
49751
  let coreId;
49571
49752
  if (isOpaqueItem(item)) preamble.push(item);
49572
49753
  switch (item.type) {
@@ -49641,13 +49822,15 @@ function responsesToCore(body) {
49641
49822
  text: call.arguments ?? "",
49642
49823
  rawResponsesItem: item
49643
49824
  });
49825
+ toolNames.set(call.call_id, call.name);
49644
49826
  break;
49645
49827
  }
49646
49828
  case "function_call_output": {
49647
49829
  const output = item;
49648
49830
  const text = typeof output.output === "string" ? output.output : JSON.stringify(output.output);
49649
49831
  coreId = clusters.next(deriveMessageId("tool", "tool-result", text, { toolCallId: output.call_id }));
49650
- msgs.push({ id: coreId, role: "tool", contentType: "tool-result", toolCallId: output.call_id, text, rawResponsesItem: item });
49832
+ const name = toolNames.get(output.call_id);
49833
+ msgs.push({ id: coreId, role: "tool", contentType: "tool-result", toolCallId: output.call_id, text, ...name ? { toolName: name } : {}, rawResponsesItem: item });
49651
49834
  break;
49652
49835
  }
49653
49836
  case "computer_call":
@@ -49669,6 +49852,7 @@ function responsesToCore(body) {
49669
49852
  const argText = ctc.input ?? ctc.arguments ?? "";
49670
49853
  coreId = clusters.next(deriveMessageId("assistant", "tool-call", argText, { toolCallId: callId, toolName: ctc.name ?? "custom" }));
49671
49854
  msgs.push({ id: coreId, role: "assistant", contentType: "tool-call", toolName: ctc.name ?? "custom", toolCallId: callId, text: argText, rawResponsesItem: item });
49855
+ toolNames.set(callId, ctc.name ?? "custom");
49672
49856
  break;
49673
49857
  }
49674
49858
  case "custom_tool_call_output": {
@@ -49677,7 +49861,8 @@ function responsesToCore(body) {
49677
49861
  customToolCallIds.add(callId);
49678
49862
  const outText = typeof ctco.output === "string" ? ctco.output : JSON.stringify(ctco.output ?? "");
49679
49863
  coreId = clusters.next(deriveMessageId("tool", "tool-result", outText, { toolCallId: callId }));
49680
- msgs.push({ id: coreId, role: "tool", contentType: "tool-result", toolCallId: callId, text: outText, rawResponsesItem: item });
49864
+ const name = toolNames.get(callId);
49865
+ msgs.push({ id: coreId, role: "tool", contentType: "tool-result", toolCallId: callId, text: outText, ...name ? { toolName: name } : {}, rawResponsesItem: item });
49681
49866
  break;
49682
49867
  }
49683
49868
  default:
@@ -50998,97 +51183,14 @@ var ABSORB_TOOL_RESPONSES = {
50998
51183
  parameters: ABSORB_TOOL_OPENAI.function.parameters
50999
51184
  };
51000
51185
  function parseCompressInput(input, callId) {
51001
- const first = parseCompressArgs(input, { callId });
51002
- if (first.ranges.length === 0 || first.diagnostics.invalidItems > 0) {
51003
- const normalized = normalizeQuoteShape(input);
51004
- if (normalized !== void 0) {
51005
- const retry = parseCompressArgs(normalized, { callId });
51006
- if (retry.ranges.length > first.ranges.length) {
51007
- log("warn", `[acp-compress-input] quote-salvage: recovered ${retry.ranges.length} range(s) after single->double quote normalization (was ${first.ranges.length}, kind=${first.diagnostics.kind})`);
51008
- return { ranges: retry.ranges, diagnostics: retry.diagnostics };
51009
- }
51010
- }
51011
- }
51012
- if (!first.diagnostics.ok && first.diagnostics.kind !== "ok") {
51013
- log("warn", `[acp-compress-input] rejected: kind=${first.diagnostics.kind} invalidItems=${first.diagnostics.invalidItems}${first.diagnostics.keys ? ` keys=[${first.diagnostics.keys.join(",")}]` : ""}${first.diagnostics.length !== void 0 ? ` len=${first.diagnostics.length}` : ""}${first.diagnostics.invalidReasons && first.diagnostics.invalidReasons.length > 0 ? ` reasons=[${first.diagnostics.invalidReasons.join(" | ")}]` : ""}`);
51186
+ const parsed = parseCompressArgs(input, { callId });
51187
+ if (parsed.diagnostics.quoteSalvage === true) {
51188
+ log("warn", `[acp-compress-input] quote-salvage: recovered ${parsed.ranges.length} range(s) after single->double quote normalization (kind=${parsed.diagnostics.kind})`);
51014
51189
  }
51015
- return { ranges: first.ranges, diagnostics: first.diagnostics };
51016
- }
51017
- function normalizeQuoteShape(input) {
51018
- if (typeof input === "string") return normalizeSingleQuotes(input);
51019
- if (input !== null && typeof input === "object" && !Array.isArray(input)) {
51020
- const obj = input;
51021
- if (typeof obj["content"] === "string") {
51022
- const fixed = normalizeSingleQuotes(obj["content"]);
51023
- if (fixed !== void 0) return { ...obj, content: fixed };
51024
- }
51190
+ if (!parsed.diagnostics.ok && parsed.diagnostics.kind !== "ok") {
51191
+ log("warn", `[acp-compress-input] rejected: kind=${parsed.diagnostics.kind} invalidItems=${parsed.diagnostics.invalidItems}${parsed.diagnostics.keys ? ` keys=[${parsed.diagnostics.keys.join(",")}]` : ""}${parsed.diagnostics.length !== void 0 ? ` len=${parsed.diagnostics.length}` : ""}${parsed.diagnostics.invalidReasons && parsed.diagnostics.invalidReasons.length > 0 ? ` reasons=[${parsed.diagnostics.invalidReasons.join(" | ")}]` : ""}`);
51025
51192
  }
51026
- return void 0;
51027
- }
51028
- function normalizeSingleQuotes(raw) {
51029
- if (!raw.includes("'") || !raw.includes("{") && !raw.includes("[")) return void 0;
51030
- let out = "";
51031
- let changed = false;
51032
- let inDouble = false;
51033
- let inSingle = false;
51034
- for (let i = 0; i < raw.length; i++) {
51035
- const ch = raw.charAt(i);
51036
- if (inDouble) {
51037
- out += ch;
51038
- if (ch === "\\" && i + 1 < raw.length) {
51039
- out += raw.charAt(i + 1);
51040
- i++;
51041
- } else if (ch === '"') {
51042
- inDouble = false;
51043
- }
51044
- continue;
51045
- }
51046
- if (inSingle) {
51047
- if (ch === "\\" && i + 1 < raw.length) {
51048
- const next = raw.charAt(i + 1);
51049
- out += next === "'" ? "'" : "\\" + next;
51050
- i++;
51051
- continue;
51052
- }
51053
- if (ch === "'") {
51054
- out += '"';
51055
- inSingle = false;
51056
- changed = true;
51057
- continue;
51058
- }
51059
- if (ch === '"') {
51060
- out += '\\"';
51061
- continue;
51062
- }
51063
- if (ch === "\n") {
51064
- out += "\\n";
51065
- continue;
51066
- }
51067
- if (ch === "\r") {
51068
- out += "\\r";
51069
- continue;
51070
- }
51071
- if (ch === " ") {
51072
- out += "\\t";
51073
- continue;
51074
- }
51075
- out += ch;
51076
- continue;
51077
- }
51078
- if (ch === '"') {
51079
- inDouble = true;
51080
- out += ch;
51081
- continue;
51082
- }
51083
- if (ch === "'") {
51084
- inSingle = true;
51085
- out += '"';
51086
- changed = true;
51087
- continue;
51088
- }
51089
- out += ch;
51090
- }
51091
- return changed ? out : void 0;
51193
+ return { ranges: parsed.ranges, diagnostics: parsed.diagnostics };
51092
51194
  }
51093
51195
  var STAGED_COMPRESS_GUIDANCE = "\n\n[Smooth-transition guidance: when you compress, prefer a SMALLER, TAIL-biased range \u2014 compress the most recent large content and keep the stable prefix (the earliest messages) intact. A large single rewrite changes the request shape sharply and can trip provider risk-control; smaller tail-biased folds keep the prefix cache alive and the transition gentle.]";
51094
51196
  function withStagedCompressGuidance(text) {
@@ -51535,7 +51637,7 @@ ${lines.join("\n\n")}`;
51535
51637
  }
51536
51638
  return `[Unknown proxy tool: ${toolName}]`;
51537
51639
  }
51538
- function refNum2(ref) {
51640
+ function refNum(ref) {
51539
51641
  return Number(ref.replace(/\D/g, "")) || 0;
51540
51642
  }
51541
51643
  function applyRanges(parsed, ctx) {
@@ -51584,7 +51686,7 @@ ${reasons.map((r) => `- ${r}`).join("\n")}` : "";
51584
51686
  }
51585
51687
  const preContext = ctx.session.stats.lastInputTokens;
51586
51688
  const shrinkRatio = preContext > 0 ? r.tokensCompressed / preContext : 0;
51587
- const foldPoint = [...ranges].sort((a, b2) => refNum2(a.startRef) - refNum2(b2.startRef))[0]?.startRef ?? "unknown";
51689
+ const foldPoint = [...ranges].sort((a, b2) => refNum(a.startRef) - refNum(b2.startRef))[0]?.startRef ?? "unknown";
51588
51690
  ctx.session.lastCompress = { at: Date.now(), shrinkRatio, foldPoint, blocks: r.blocksCreated, tokensCompressed: r.tokensCompressed };
51589
51691
  ctx.log(`[acp-compress-obs] shrink ${Math.round(shrinkRatio * 100)}% (~${r.tokensCompressed}/${preContext} tok) foldPoint=${foldPoint} blocks=${r.blocksCreated}`);
51590
51692
  const warn = r.warnings.length > 0 ? ` ${r.warnings.join("; ")}` : "";
@@ -51651,7 +51753,7 @@ function refMaps(messages, state) {
51651
51753
  });
51652
51754
  return { refToIdx, idxToRef };
51653
51755
  }
51654
- function refNum3(ref) {
51756
+ function refNum2(ref) {
51655
51757
  return Number(ref.replace(/\D/g, "")) || 0;
51656
51758
  }
51657
51759
  function estimateCoreMessages(messages) {
@@ -51901,7 +52003,7 @@ async function preflightCompress(deps, messages) {
51901
52003
  failure = { kind: "exhausted", detail: relaxed ? relaxedExhaustedDetail : "no compressible ranges remain in the conversation" };
51902
52004
  break;
51903
52005
  }
51904
- const ordered = [...ranges].sort((a, b2) => refNum3(a.startRef) - refNum3(b2.startRef));
52006
+ const ordered = [...ranges].sort((a, b2) => refNum2(a.startRef) - refNum2(b2.startRef));
51905
52007
  let appliedThisRound = 0;
51906
52008
  for (const range of ordered) {
51907
52009
  if (currentTokens < limit) break;
@@ -63656,6 +63758,12 @@ var To = (s3) => {
63656
63758
  import path12 from "path";
63657
63759
  import { fileURLToPath as fileURLToPath3 } from "url";
63658
63760
  var REGISTRY_BASE = "https://registry.npmjs.org";
63761
+ function normalizeUpdateTag(tag) {
63762
+ return (tag ?? "latest").trim() || "latest";
63763
+ }
63764
+ function registryUrlFor(packageName, tag) {
63765
+ return `${REGISTRY_BASE}/${packageName}/${encodeURIComponent(tag)}`;
63766
+ }
63659
63767
  var CHECK_INTERVAL_MS = 3 * 60 * 1e3;
63660
63768
  var THROTTLE_FILE = path12.join(cacheDir(), ".update-check");
63661
63769
  var LOCK_FILE = path12.join(cacheDir(), ".update-lock");
@@ -63666,22 +63774,42 @@ function shouldStealLock(holderAlive, ageMs) {
63666
63774
  var timer2;
63667
63775
  var inFlight = false;
63668
63776
  var firstCheckDone = false;
63669
- function parseVersion(v2) {
63670
- return v2.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
63671
- }
63672
- function isNewer(latest, current) {
63673
- const l = parseVersion(latest);
63674
- const c = parseVersion(current);
63777
+ function isVersionNewer(latest, current) {
63778
+ const next = parseSemVer(latest);
63779
+ const prev = parseSemVer(current);
63780
+ if (!next || !prev) return false;
63675
63781
  for (let i = 0; i < 3; i++) {
63676
- const lv = l[i] ?? 0;
63677
- const cv = c[i] ?? 0;
63678
- if (lv > cv) return true;
63679
- if (lv < cv) return false;
63782
+ const a = next.parts[i] ?? 0;
63783
+ const b2 = prev.parts[i] ?? 0;
63784
+ if (a !== b2) return a > b2;
63785
+ }
63786
+ if (!next.pre.length && prev.pre.length) return true;
63787
+ if (next.pre.length && !prev.pre.length) return false;
63788
+ for (let i = 0; i < Math.max(next.pre.length, prev.pre.length); i++) {
63789
+ const a = next.pre[i];
63790
+ const b2 = prev.pre[i];
63791
+ if (a === void 0) return false;
63792
+ if (b2 === void 0) return true;
63793
+ if (a === b2) continue;
63794
+ const aNumber = /^\d+$/.test(a) ? Number(a) : void 0;
63795
+ const bNumber = /^\d+$/.test(b2) ? Number(b2) : void 0;
63796
+ if (aNumber !== void 0 && bNumber !== void 0) return aNumber > bNumber;
63797
+ if (aNumber !== void 0) return false;
63798
+ if (bNumber !== void 0) return true;
63799
+ return a > b2;
63680
63800
  }
63681
63801
  return false;
63682
63802
  }
63803
+ function parseSemVer(version2) {
63804
+ const match = version2.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.+)?$/);
63805
+ if (!match) return void 0;
63806
+ return {
63807
+ parts: [Number(match[1]), Number(match[2]), Number(match[3])],
63808
+ pre: match[4]?.split(".") ?? []
63809
+ };
63810
+ }
63683
63811
  function staleInstallStatus(diskVersion, runningVersion) {
63684
- return diskVersion !== void 0 && isNewer(diskVersion, runningVersion) ? "restart" : "current";
63812
+ return diskVersion !== void 0 && isVersionNewer(diskVersion, runningVersion) ? "restart" : "current";
63685
63813
  }
63686
63814
  async function readLastCheck() {
63687
63815
  try {
@@ -63887,7 +64015,8 @@ async function checkForUpdate(opts, force = false) {
63887
64015
  return;
63888
64016
  }
63889
64017
  log("info", `[update] checking npm registry for ${opts.packageName}${sinceLastSec < 0 ? " (startup check)" : sinceLastSec === 0 ? "" : ` (last check ${sinceLastSec}s ago)`}\u2026`);
63890
- const url = `${REGISTRY_BASE}/${opts.packageName}/latest`;
64018
+ const tag = normalizeUpdateTag(opts.updateTag);
64019
+ const url = registryUrlFor(opts.packageName, tag);
63891
64020
  const registryDispatcher = egressDispatcher(opts, url);
63892
64021
  const res = await fetchWithEgress(url, {
63893
64022
  signal: AbortSignal.timeout(5e3),
@@ -63906,11 +64035,11 @@ async function checkForUpdate(opts, force = false) {
63906
64035
  }
63907
64036
  const diskVersion = installDir ? await readDiskVersion(installDir) : void 0;
63908
64037
  const currentVersion = diskVersion ?? opts.currentVersion;
63909
- if (!isNewer(latest, currentVersion)) {
64038
+ if (!isVersionNewer(latest, currentVersion)) {
63910
64039
  if (staleInstallStatus(diskVersion, opts.currentVersion) === "restart") {
63911
64040
  log("warn", `[update] running v${opts.currentVersion} but v${diskVersion} is installed \u2014 restart bili to activate (auto-update replaced the on-disk install; this process is still on the old code)`);
63912
64041
  } else {
63913
- log("info", `[update] current=${currentVersion} latest=${latest} (up to date)`);
64042
+ log("info", `[update] current=${currentVersion} latest=${latest} tag=${tag} (up to date)`);
63914
64043
  }
63915
64044
  return;
63916
64045
  }
@@ -65975,7 +66104,33 @@ function latestBlockTime(s3) {
65975
66104
  for (const b2 of s3.state.blocks) if (b2.createdAt > latest) latest = b2.createdAt;
65976
66105
  return latest;
65977
66106
  }
65978
- function renderHandoff(s3, full) {
66107
+ function renderHandoff2(s3, full) {
66108
+ const messages = s3.lastMessages;
66109
+ if (messages && messages.length > 0) {
66110
+ const folded = s3.lastMessagesFolded === true;
66111
+ const blocksFull = full && folded ? s3.state.blocks.filter((b2) => b2.active).map((b2) => {
66112
+ const content = s3.blockContents.get(b2.blockId);
66113
+ return content ? { blockId: b2.blockId, topic: b2.topic, count: content.full.count, fullText: content.full.text } : void 0;
66114
+ }).filter((x) => x !== void 0) : void 0;
66115
+ return renderHandoff({
66116
+ coreMessages: messages,
66117
+ state: s3.state,
66118
+ full,
66119
+ folded,
66120
+ blocksFull,
66121
+ meta: {
66122
+ title: s3.meta.title,
66123
+ label: s3.meta.label,
66124
+ sessionId: s3.id,
66125
+ contextTokens: s3.stats.contextTokens,
66126
+ extraBullets: [
66127
+ ...s3.meta.protocol ? [`- protocol: ${s3.meta.protocol}`] : [],
66128
+ ...s3.meta.upstreamOrigin ? [`- upstream: ${s3.meta.upstreamOrigin}`] : [],
66129
+ `- requests: ${s3.stats.requests}`
66130
+ ]
66131
+ }
66132
+ });
66133
+ }
65979
66134
  const lines = [];
65980
66135
  lines.push(`# billion-context session handoff`);
65981
66136
  lines.push("");
@@ -65988,38 +66143,6 @@ function renderHandoff(s3, full) {
65988
66143
  if (s3.stats.contextTokens) lines.push(`- last context tokens: ~${s3.stats.contextTokens}`);
65989
66144
  lines.push(`- compression blocks: ${s3.state.blocks.length} (active ${s3.state.blocks.filter((b2) => b2.active).length})`);
65990
66145
  lines.push("");
65991
- const messages = s3.lastMessages;
65992
- if (messages && messages.length > 0) {
65993
- const folded = s3.lastMessagesFolded === true;
65994
- const view = full || folded ? messages : prune(messages, s3.state);
65995
- lines.push(
65996
- full && !folded ? `## Full conversation (${messages.length} messages)` : folded ? `## Conversation (persisted folded snapshot, ${messages.length} messages)` : `## Conversation (folded view as the model saw it, ${messages.length} client messages)`
65997
- );
65998
- lines.push("");
65999
- let lastRole = "";
66000
- for (const m2 of view) {
66001
- if (m2.role !== lastRole) {
66002
- lines.push(`### ${m2.role}`);
66003
- lines.push("");
66004
- lastRole = m2.role;
66005
- }
66006
- lines.push(renderMessage2(m2));
66007
- }
66008
- lines.push("");
66009
- if (full && folded) {
66010
- for (const b2 of s3.state.blocks.filter((x) => x.active)) {
66011
- const content = s3.blockContents.get(b2.blockId);
66012
- if (!content) continue;
66013
- lines.push(`## Block ${b2.blockId}${b2.topic ? ` \u2014 ${b2.topic}` : ""}`);
66014
- lines.push("");
66015
- lines.push(`### Original messages (${content.full.count})`);
66016
- lines.push("");
66017
- lines.push(content.full.text.trim());
66018
- lines.push("");
66019
- }
66020
- }
66021
- return lines.join("\n");
66022
- }
66023
66146
  const active = s3.state.blocks.filter((b2) => b2.active);
66024
66147
  if (active.length === 0) {
66025
66148
  lines.push("No active compression blocks and no persisted conversation snapshot (v2 session file). Original messages are only persisted when they are compressed into a block, so this session's conversation content is not available for export.");
@@ -66048,32 +66171,8 @@ function renderHandoff(s3, full) {
66048
66171
  }
66049
66172
  return lines.join("\n");
66050
66173
  }
66051
- function renderMessage2(m2) {
66052
- const parts = [];
66053
- switch (m2.contentType) {
66054
- case "text":
66055
- parts.push(m2.text ?? "");
66056
- break;
66057
- case "tool-call":
66058
- parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` args: ${m2.text ?? ""}`);
66059
- break;
66060
- case "tool-result":
66061
- parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` \u2192 ${m2.text ?? ""}`);
66062
- break;
66063
- case "reasoning":
66064
- parts.push(`_reasoning_: ${m2.text ?? ""}`);
66065
- break;
66066
- }
66067
- const body = parts.join("\n").trim();
66068
- return body === "" ? "_(empty)_" : body + "\n";
66069
- }
66070
- function matchSession(sessions2, selector) {
66071
- const exact = sessions2.filter((s3) => s3.id === selector);
66072
- if (exact.length > 0) return exact;
66073
- const byLabel = sessions2.filter((s3) => s3.meta.label === selector);
66074
- if (byLabel.length > 0) return byLabel;
66075
- const byPrefix = sessions2.filter((s3) => s3.id.startsWith(selector) || (s3.meta.label ?? "").startsWith(selector));
66076
- return byPrefix;
66174
+ function matchSession2(sessions2, selector) {
66175
+ return matchSession(sessions2, selector, (s3) => s3.meta.label);
66077
66176
  }
66078
66177
  async function exportSession(selector, opts = {}) {
66079
66178
  const store = new SessionStore({ dir: opts.dir, enabled: true });
@@ -66088,7 +66187,7 @@ async function exportSession(selector, opts = {}) {
66088
66187
  );
66089
66188
  return ["Persisted sessions:", "", ...rows.map((r) => ` ${r}`), "", "Usage: bili export <session-id|label> [--output handoff.md] [--full]"].join("\n");
66090
66189
  }
66091
- const matches = matchSession(all, selector);
66190
+ const matches = matchSession2(all, selector);
66092
66191
  if (matches.length === 0) {
66093
66192
  throw new Error(`no session matches "${selector}" (run "bili export" to list sessions)`);
66094
66193
  }
@@ -66096,7 +66195,7 @@ async function exportSession(selector, opts = {}) {
66096
66195
  const ids = matches.map((s3) => s3.id).join(", ");
66097
66196
  throw new Error(`selector "${selector}" matches ${matches.length} sessions (${ids}); use the full session id`);
66098
66197
  }
66099
- const markdown = renderHandoff(matches[0], opts.full ?? false);
66198
+ const markdown = renderHandoff2(matches[0], opts.full ?? false);
66100
66199
  if (opts.output) {
66101
66200
  mkdirSync6(path16.dirname(path16.resolve(opts.output)), { recursive: true });
66102
66201
  writeFileSync5(opts.output, markdown, "utf8");
@@ -66421,14 +66520,16 @@ async function main() {
66421
66520
  if (v2 !== void 0) process.env[k2] = v2;
66422
66521
  }
66423
66522
  let updaterResolveProxy;
66523
+ let updateTag;
66424
66524
  try {
66425
66525
  const o = loadOptions();
66426
66526
  updaterResolveProxy = (url) => resolveProxy(o.routes, o.proxy, url, o.proxyFallback);
66527
+ updateTag = o.updateTag;
66427
66528
  } catch (e) {
66428
66529
  console.error(`bili update: config load failed (${String(e)}); updater egress goes direct`);
66429
66530
  }
66430
66531
  await checkForUpdate(
66431
- { packageName: PACKAGE_NAME, currentVersion: VERSION3, autoUpdate: true, resolveProxy: updaterResolveProxy },
66532
+ { packageName: PACKAGE_NAME, currentVersion: VERSION3, autoUpdate: true, resolveProxy: updaterResolveProxy, updateTag },
66432
66533
  true
66433
66534
  );
66434
66535
  return;
@@ -66456,7 +66557,8 @@ async function main() {
66456
66557
  packageName: PACKAGE_NAME,
66457
66558
  currentVersion: VERSION3,
66458
66559
  autoUpdate: true,
66459
- resolveProxy: (url) => resolveProxy(opts.routes, opts.proxy, url, opts.proxyFallback)
66560
+ resolveProxy: (url) => resolveProxy(opts.routes, opts.proxy, url, opts.proxyFallback),
66561
+ updateTag: opts.updateTag
66460
66562
  });
66461
66563
  }
66462
66564
  }