billion-context 0.1.97 → 0.1.98-pr.672.490

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
@@ -48726,6 +48726,7 @@ function mergeCompress(global2, provider, model) {
48726
48726
  const promptLevels = [global2?.prompts, provider?.prompts, model?.prompts].filter(Boolean);
48727
48727
  const rangeOf = (s3) => s3?.minCompressRangeChars ?? s3?.minCompressRange;
48728
48728
  const absorbLevels = [global2?.absorb, provider?.absorb, model?.absorb].filter(Boolean);
48729
+ const reasoningLevels = [global2?.reasoning, provider?.reasoning, model?.reasoning].filter(Boolean);
48729
48730
  return {
48730
48731
  modelContextLimit: pick("modelContextLimit"),
48731
48732
  maxContextLimit: pick("maxContextLimit"),
@@ -48739,7 +48740,11 @@ function mergeCompress(global2, provider, model) {
48739
48740
  acknowledgePromptsRisk: pick("acknowledgePromptsRisk"),
48740
48741
  absorb: absorbLevels.length > 0 ? Object.assign({}, ...absorbLevels) : void 0,
48741
48742
  stripImages: pick("stripImages"),
48742
- stripImagesKeepRecent: pick("stripImagesKeepRecent")
48743
+ stripImagesKeepRecent: pick("stripImagesKeepRecent"),
48744
+ // `reasoning` is a third nested-object field merged sub-field-wise
48745
+ // exactly like `absorb`/`prompts`: a model-level `threshold` must not
48746
+ // discard a provider-level `drop: false`.
48747
+ reasoning: reasoningLevels.length > 0 ? Object.assign({}, ...reasoningLevels) : void 0
48743
48748
  };
48744
48749
  }
48745
48750
  function resolveCompress(routes, upstreamUrl, model, global2) {
@@ -48819,6 +48824,53 @@ function resolveRequestConfig(base, routes, embeddedUrl, model, native, globalCo
48819
48824
  return applyCompressSettings(base, limit, compress);
48820
48825
  }
48821
48826
 
48827
+ // src/reasoning-drop.ts
48828
+ var DEFAULT_COMPRESS_REASONING = { drop: true, threshold: 2048 };
48829
+ function resolveReasoningDrop(cfg) {
48830
+ let threshold = DEFAULT_COMPRESS_REASONING.threshold;
48831
+ if (cfg?.threshold !== void 0) {
48832
+ const t = cfg.threshold;
48833
+ if (typeof t === "number" && Number.isFinite(t) && t >= 0) {
48834
+ threshold = Math.floor(t);
48835
+ }
48836
+ }
48837
+ return { drop: cfg?.drop !== false, threshold };
48838
+ }
48839
+ function dropCompressReasoning(messages, cfg) {
48840
+ const { drop, threshold } = resolveReasoningDrop(cfg);
48841
+ if (!drop || messages.length === 0) return messages;
48842
+ try {
48843
+ const last = messages.length - 1;
48844
+ const resultAt = /* @__PURE__ */ new Map();
48845
+ for (let i = 0; i <= last; i++) {
48846
+ const m2 = messages[i];
48847
+ if (m2.contentType === "tool-result" && typeof m2.toolCallId === "string" && !resultAt.has(m2.toolCallId)) {
48848
+ resultAt.set(m2.toolCallId, i);
48849
+ }
48850
+ }
48851
+ const dropIdx = /* @__PURE__ */ new Set();
48852
+ for (let i = 0; i <= last; i++) {
48853
+ const m2 = messages[i];
48854
+ if (m2.contentType !== "tool-call" || m2.toolName !== "compress") continue;
48855
+ const ri2 = typeof m2.toolCallId === "string" ? resultAt.get(m2.toolCallId) : void 0;
48856
+ if (ri2 === void 0 || ri2 <= i || ri2 >= last) continue;
48857
+ let total = 0;
48858
+ let j2 = i - 1;
48859
+ while (j2 >= 0 && messages[j2].contentType === "reasoning") {
48860
+ total += (messages[j2].text ?? "").length;
48861
+ j2--;
48862
+ }
48863
+ if (total > threshold) {
48864
+ for (let k2 = j2 + 1; k2 < i; k2++) dropIdx.add(k2);
48865
+ }
48866
+ }
48867
+ if (dropIdx.size === 0) return messages;
48868
+ return messages.filter((_2, idx) => !dropIdx.has(idx));
48869
+ } catch {
48870
+ return messages;
48871
+ }
48872
+ }
48873
+
48822
48874
  // src/strip-images.ts
48823
48875
  var DEFAULT_STRIP_IMAGES_KEEP_RECENT = 5;
48824
48876
  var IMAGE_PLACEHOLDER = "[image]";
@@ -56255,15 +56307,28 @@ function handlePluginManifest(res) {
56255
56307
  statusEndpoint: "/__bili/plugin/status"
56256
56308
  }));
56257
56309
  }
56310
+ function conversationIdForSession(sessionId) {
56311
+ let bestId;
56312
+ let bestSeen = -Infinity;
56313
+ for (const [cid, entry] of conversations) {
56314
+ if (entry.sessionId === sessionId && entry.lastSeen > bestSeen) {
56315
+ bestId = cid;
56316
+ bestSeen = entry.lastSeen;
56317
+ }
56318
+ }
56319
+ return bestId;
56320
+ }
56258
56321
  function handlePluginStatus(conversationId2, res, deps, fallbackLatest = false) {
56259
56322
  let entry = conversations.get(conversationId2);
56260
56323
  let session = entry ? peekSession(entry.sessionId) : void 0;
56261
56324
  let viaFallback = false;
56325
+ let resolvedConversationId = conversationId2;
56262
56326
  if ((!entry || !session) && fallbackLatest) {
56263
56327
  const latest = listSessions().filter((s3) => s3.restored !== true).sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
56264
56328
  if (latest) {
56265
56329
  session = latest;
56266
56330
  viaFallback = true;
56331
+ resolvedConversationId = conversationIdForSession(latest.id) ?? conversationId2;
56267
56332
  } else {
56268
56333
  res.writeHead(404, { "content-type": "application/json" });
56269
56334
  res.end(JSON.stringify({ ok: false, error: "no session with activity since boot \u2014 issue a model request or pass the conversation id" }));
@@ -56313,7 +56378,7 @@ function handlePluginStatus(conversationId2, res, deps, fallbackLatest = false)
56313
56378
  res.writeHead(200, { "content-type": "application/json" });
56314
56379
  res.end(JSON.stringify({
56315
56380
  ok: true,
56316
- conversationId: conversationId2,
56381
+ conversationId: resolvedConversationId,
56317
56382
  fallback: viaFallback || void 0,
56318
56383
  label: session.meta.label ?? null,
56319
56384
  pluginAgent: session.metadata.pluginAgent ?? null,
@@ -56348,8 +56413,12 @@ async function handlePluginTool(payload, res, deps) {
56348
56413
  const entry = conversations.get(conversationId2);
56349
56414
  const session = entry ? peekSession(entry.sessionId) : void 0;
56350
56415
  if (!entry || !session) {
56416
+ deps.log("warn", `[plugin] tool "${tool}" rejected for conversation ${conversationId2}: ${entry ? "id registered but session not resident in this proxy instance" : "id never registered (stale shim session id after host resume?)"}`);
56351
56417
  res.writeHead(404, { "content-type": "application/json" });
56352
- res.end(JSON.stringify({ ok: false, error: "unknown plugin conversation (no model request has arrived with this conversation id yet)" }));
56418
+ res.end(JSON.stringify({
56419
+ ok: false,
56420
+ error: !entry ? "unknown plugin conversation (no model request has arrived with this conversation id yet)" : "unknown plugin conversation (id registered but its session is not resident in this proxy instance \u2014 a fresh model request re-binds it)"
56421
+ }));
56353
56422
  return;
56354
56423
  }
56355
56424
  if (!isProxyToolFor(tool, session, deps.config)) {
@@ -59214,13 +59283,14 @@ ${bodyBuffer.toString("utf8")}`);
59214
59283
  await withSessionLock(session, async () => {
59215
59284
  const runPrepare = () => {
59216
59285
  const cs2 = resolveCompress(opts.routes, route?.rewrittenUrl, parsed.model, opts.compress);
59286
+ const reasoningCfg = cs2.reasoning;
59217
59287
  const keepRecent = cs2.stripImagesKeepRecent ?? DEFAULT_STRIP_IMAGES_KEEP_RECENT;
59218
59288
  const stripped = cs2.stripImages ? stripHistoricalImages(parsed, protocol, keepRecent) : { body: parsed, removed: 0 };
59219
59289
  if (opts.debug && stripped.removed > 0) {
59220
59290
  log2("info", `[debug] strip-images: dropped ${stripped.removed} historical image part(s), kept last ${keepRecent} (session=${session.id})`);
59221
59291
  }
59222
59292
  const work = stripped.body;
59223
- return countTokens ? prepareCountTokens(work, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, nativeWindow) : responsesCompact ? prepareResponsesCompact(stripped.removed > 0 ? Buffer.from(JSON.stringify(work)) : bodyBuffer, work, session, req, core, reqConfig, log2) : prepareResponses(work, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin, nativeWindow);
59293
+ return countTokens ? prepareCountTokens(work, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, reasoningCfg) : protocol === "openai" ? prepareOpenai(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, nativeWindow, reasoningCfg) : responsesCompact ? prepareResponsesCompact(stripped.removed > 0 ? Buffer.from(JSON.stringify(work)) : bodyBuffer, work, session, req, core, reqConfig, log2) : prepareResponses(work, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin, nativeWindow, reasoningCfg);
59224
59294
  };
59225
59295
  const isCodexCompactTrigger = protocol === "responses" && !responsesCompact && isCodexClient(req.headers) && hasCompactionTrigger(parsed.input);
59226
59296
  if (isCodexCompactTrigger) {
@@ -59308,6 +59378,13 @@ ${bodyBuffer.toString("utf8")}`);
59308
59378
  }
59309
59379
  }
59310
59380
  var ACP_TAG_MARK = "<acp ";
59381
+ function withReasoningDrop(msgs, reasoning, log2, sessionId) {
59382
+ const out = dropCompressReasoning(msgs, reasoning);
59383
+ if (out.length !== msgs.length) {
59384
+ log2("info", `[${sessionId}] compress-reasoning: dropped ${msgs.length - out.length} reasoning message(s) from closed compress turns (#651)`);
59385
+ }
59386
+ return out;
59387
+ }
59311
59388
  function stripKernelSummaries(messages, state) {
59312
59389
  const carried = /* @__PURE__ */ new Set();
59313
59390
  for (const b2 of state.blocks) {
@@ -59409,12 +59486,13 @@ function effectiveTokenCount(session, msgs) {
59409
59486
  if (!session.metadata.anonymousPrefixAffinity) return 0;
59410
59487
  return estimateCoreMessagesUpper(msgs);
59411
59488
  }
59412
- function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode) {
59489
+ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode, reasoning) {
59413
59490
  const sessionId = session.id;
59414
59491
  const stream2 = parsed.stream === true;
59415
59492
  ++session.stats.requests;
59416
59493
  session.hostCreditTokens = 0;
59417
59494
  const injectTools = opts.compress.injectTool && !pluginMode;
59495
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59418
59496
  if (isAutoModeClassifier(parsed)) {
59419
59497
  log2("info", `[${sessionId}] auto-mode classifier passthrough (skipping compress injection)`);
59420
59498
  return { body: JSON.stringify(parsed), session, processedMessages: [], originalMessages: [], anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: false, pluginMode, nudge: void 0, prompts };
@@ -59452,7 +59530,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
59452
59530
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59453
59531
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59454
59532
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59455
- processedMessages = stripKernelSummaries(turn.messages, turn.state);
59533
+ processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59456
59534
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59457
59535
  reapOrphanBlocks(session, msgs, deactivateBlock);
59458
59536
  rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
@@ -59534,12 +59612,13 @@ function clampOutgoingOutput(rebuilt, field, ctx, sessionId, log2) {
59534
59612
  log2("info", `[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`);
59535
59613
  }
59536
59614
  }
59537
- function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow) {
59615
+ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow, reasoning) {
59538
59616
  const sessionId = session.id;
59539
59617
  const stream2 = parsed.stream === true;
59540
59618
  ++session.stats.requests;
59541
59619
  session.hostCreditTokens = 0;
59542
59620
  let openaiSystemText = "";
59621
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59543
59622
  let openaiOutboundSystem;
59544
59623
  let processedMessages = [];
59545
59624
  let originalMessages = [];
@@ -59577,7 +59656,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59577
59656
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59578
59657
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59579
59658
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59580
- processedMessages = stripKernelSummaries(turn.messages, turn.state);
59659
+ processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59581
59660
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59582
59661
  reapOrphanBlocks(session, msgs, deactivateBlock);
59583
59662
  rebuiltMessages = systemToUser(coreToOpenai(processedMessages));
@@ -59617,11 +59696,12 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59617
59696
  markDirty(session);
59618
59697
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, protocol: "openai", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, openaiSystemText, renderTags: "text-only" };
59619
59698
  }
59620
- function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow) {
59699
+ function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow, reasoning) {
59621
59700
  const sessionId = session.id;
59622
59701
  const stream2 = parsed.stream === true;
59623
59702
  ++session.stats.requests;
59624
59703
  session.hostCreditTokens = 0;
59704
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59625
59705
  if (reconcileNativeCompactionBoundary(session)) {
59626
59706
  log2("info", `[${sessionId}] reconciled ACP state after native Responses compact boundary`);
59627
59707
  }
@@ -59686,7 +59766,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
59686
59766
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59687
59767
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && !isCompactionTrigger && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59688
59768
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59689
- processedMessages = repairResponsesAssistantOrdering(stripKernelSummaries(turn.messages, turn.state), originalMessages);
59769
+ processedMessages = repairResponsesAssistantOrdering(stripReasoning(stripKernelSummaries(turn.messages, turn.state)), originalMessages);
59690
59770
  reapOrphanBlocks(session, msgs, deactivateBlock);
59691
59771
  rebuiltInput = patchResponsesInput(projection, processedMessages);
59692
59772
  const forgedSummaries = echoReplaced ? [] : session.metadata.codexForgedSummaries ?? [];
@@ -64321,6 +64401,7 @@ function resolveProxyOrigin() {
64321
64401
  var TOOL_TIMEOUT_MS = 6e4;
64322
64402
  var CONVERSATION_FROM_ENV = process.env.CLAUDE_CODE_SESSION_ID?.trim() || process.env.BILI_CONVERSATION_ID?.trim() || void 0;
64323
64403
  var IDENTITY_BINDING = Boolean(process.env.CLAUDE_CODE_SESSION_ID?.trim());
64404
+ var ORPHAN_ADOPT = IDENTITY_BINDING && process.env.BILI_MCP_NO_ORPHAN_ADOPT !== "1";
64324
64405
  var manifestTools = [];
64325
64406
  var conversationId = CONVERSATION_FROM_ENV;
64326
64407
  var registered = false;
@@ -64353,21 +64434,45 @@ function ensureManifest() {
64353
64434
  return manifestPromise;
64354
64435
  }
64355
64436
  async function forwardTool(tool, args, timeoutMs = TOOL_TIMEOUT_MS) {
64356
- let res;
64437
+ for (let attempt = 0; ; attempt++) {
64438
+ let res;
64439
+ try {
64440
+ res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/tool`, {
64441
+ method: "POST",
64442
+ headers: { "content-type": "application/json" },
64443
+ body: JSON.stringify({ conversationId, tool, args }),
64444
+ signal: AbortSignal.timeout(timeoutMs)
64445
+ });
64446
+ } catch (err2) {
64447
+ if (err2 instanceof Error && err2.name === "TimeoutError") throw new Error(`tool forward timed out after ${timeoutMs}ms: ${tool}`);
64448
+ throw err2;
64449
+ }
64450
+ const data = await res.json();
64451
+ if (res.ok && data.ok) return data.result ?? "";
64452
+ if (res.status === 404 && attempt === 0 && ORPHAN_ADOPT && conversationId && typeof data.error === "string" && data.error.includes("no model request has arrived")) {
64453
+ if (await adoptLatestActiveConversation()) continue;
64454
+ }
64455
+ throw new Error(data.error ?? `tool forward failed: ${res.status}`);
64456
+ }
64457
+ }
64458
+ async function adoptLatestActiveConversation() {
64357
64459
  try {
64358
- res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/tool`, {
64359
- method: "POST",
64360
- headers: { "content-type": "application/json" },
64361
- body: JSON.stringify({ conversationId, tool, args }),
64362
- signal: AbortSignal.timeout(timeoutMs)
64363
- });
64364
- } catch (err2) {
64365
- if (err2 instanceof Error && err2.name === "TimeoutError") throw new Error(`tool forward timed out after ${timeoutMs}ms: ${tool}`);
64366
- throw err2;
64460
+ const res = await fetch(
64461
+ `${resolveProxyOrigin()}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId ?? "")}&fallback=latest`,
64462
+ { signal: AbortSignal.timeout(5e3) }
64463
+ );
64464
+ if (!res.ok) return false;
64465
+ const data = await res.json();
64466
+ if (data.ok !== true || data.fallback !== true || !data.conversationId || data.conversationId === conversationId) return false;
64467
+ process.stderr.write(
64468
+ `[bili-mcp] conversation id no longer known by the proxy (host resumed its session?); adopting latest active conversation ${data.conversationId}
64469
+ `
64470
+ );
64471
+ conversationId = data.conversationId;
64472
+ return true;
64473
+ } catch {
64474
+ return false;
64367
64475
  }
64368
- const data = await res.json();
64369
- if (!res.ok || !data.ok) throw new Error(data.error ?? `tool forward failed: ${res.status}`);
64370
- return data.result ?? "";
64371
64476
  }
64372
64477
  var ERR_TOOL = -32602;
64373
64478
  async function handleMessage(msg) {