billion-context 0.1.97-pr.669.486 → 0.1.97-pr.669.488

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)) {
@@ -59234,13 +59303,14 @@ ${bodyBuffer.toString("utf8")}`);
59234
59303
  await withSessionLock(session, async () => {
59235
59304
  const runPrepare = () => {
59236
59305
  const cs2 = resolveCompress(opts.routes, route?.rewrittenUrl, parsed.model, opts.compress);
59306
+ const reasoningCfg = cs2.reasoning;
59237
59307
  const keepRecent = cs2.stripImagesKeepRecent ?? DEFAULT_STRIP_IMAGES_KEEP_RECENT;
59238
59308
  const stripped = cs2.stripImages ? stripHistoricalImages(parsed, protocol, keepRecent) : { body: parsed, removed: 0 };
59239
59309
  if (opts.debug && stripped.removed > 0) {
59240
59310
  log2("info", `[debug] strip-images: dropped ${stripped.removed} historical image part(s), kept last ${keepRecent} (session=${session.id})`);
59241
59311
  }
59242
59312
  const work = stripped.body;
59243
- 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);
59313
+ 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);
59244
59314
  };
59245
59315
  const isCodexCompactTrigger = protocol === "responses" && !responsesCompact && isCodexClient(req.headers) && hasCompactionTrigger(parsed.input);
59246
59316
  if (isCodexCompactTrigger) {
@@ -59328,6 +59398,13 @@ ${bodyBuffer.toString("utf8")}`);
59328
59398
  }
59329
59399
  }
59330
59400
  var ACP_TAG_MARK = "<acp ";
59401
+ function withReasoningDrop(msgs, reasoning, log2, sessionId) {
59402
+ const out = dropCompressReasoning(msgs, reasoning);
59403
+ if (out.length !== msgs.length) {
59404
+ log2("info", `[${sessionId}] compress-reasoning: dropped ${msgs.length - out.length} reasoning message(s) from closed compress turns (#651)`);
59405
+ }
59406
+ return out;
59407
+ }
59331
59408
  function stripKernelSummaries(messages, state) {
59332
59409
  const carried = /* @__PURE__ */ new Set();
59333
59410
  for (const b2 of state.blocks) {
@@ -59429,12 +59506,13 @@ function effectiveTokenCount(session, msgs) {
59429
59506
  if (!session.metadata.anonymousPrefixAffinity) return 0;
59430
59507
  return estimateCoreMessagesUpper(msgs);
59431
59508
  }
59432
- function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode) {
59509
+ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode, reasoning) {
59433
59510
  const sessionId = session.id;
59434
59511
  const stream2 = parsed.stream === true;
59435
59512
  ++session.stats.requests;
59436
59513
  session.hostCreditTokens = 0;
59437
59514
  const injectTools = opts.compress.injectTool && !pluginMode;
59515
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59438
59516
  if (isAutoModeClassifier(parsed)) {
59439
59517
  log2("info", `[${sessionId}] auto-mode classifier passthrough (skipping compress injection)`);
59440
59518
  return { body: JSON.stringify(parsed), session, processedMessages: [], originalMessages: [], anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: false, pluginMode, nudge: void 0, prompts };
@@ -59472,7 +59550,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
59472
59550
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59473
59551
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59474
59552
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59475
- processedMessages = stripKernelSummaries(turn.messages, turn.state);
59553
+ processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59476
59554
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59477
59555
  reapOrphanBlocks(session, msgs, deactivateBlock);
59478
59556
  rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
@@ -59554,12 +59632,13 @@ function clampOutgoingOutput(rebuilt, field, ctx, sessionId, log2) {
59554
59632
  log2("info", `[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`);
59555
59633
  }
59556
59634
  }
59557
- function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow) {
59635
+ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow, reasoning) {
59558
59636
  const sessionId = session.id;
59559
59637
  const stream2 = parsed.stream === true;
59560
59638
  ++session.stats.requests;
59561
59639
  session.hostCreditTokens = 0;
59562
59640
  let openaiSystemText = "";
59641
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59563
59642
  let openaiOutboundSystem;
59564
59643
  let processedMessages = [];
59565
59644
  let originalMessages = [];
@@ -59597,7 +59676,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59597
59676
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59598
59677
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59599
59678
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59600
- processedMessages = stripKernelSummaries(turn.messages, turn.state);
59679
+ processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59601
59680
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59602
59681
  reapOrphanBlocks(session, msgs, deactivateBlock);
59603
59682
  rebuiltMessages = systemToUser(coreToOpenai(processedMessages));
@@ -59637,11 +59716,12 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59637
59716
  markDirty(session);
59638
59717
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, protocol: "openai", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, openaiSystemText, renderTags: "text-only" };
59639
59718
  }
59640
- function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow) {
59719
+ function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow, reasoning) {
59641
59720
  const sessionId = session.id;
59642
59721
  const stream2 = parsed.stream === true;
59643
59722
  ++session.stats.requests;
59644
59723
  session.hostCreditTokens = 0;
59724
+ const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59645
59725
  if (reconcileNativeCompactionBoundary(session)) {
59646
59726
  log2("info", `[${sessionId}] reconciled ACP state after native Responses compact boundary`);
59647
59727
  }
@@ -59706,7 +59786,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
59706
59786
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59707
59787
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && !isCompactionTrigger && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59708
59788
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59709
- processedMessages = repairResponsesAssistantOrdering(stripKernelSummaries(turn.messages, turn.state), originalMessages);
59789
+ processedMessages = repairResponsesAssistantOrdering(stripReasoning(stripKernelSummaries(turn.messages, turn.state)), originalMessages);
59710
59790
  reapOrphanBlocks(session, msgs, deactivateBlock);
59711
59791
  rebuiltInput = patchResponsesInput(projection, processedMessages);
59712
59792
  const forgedSummaries = echoReplaced ? [] : session.metadata.codexForgedSummaries ?? [];
@@ -64341,6 +64421,7 @@ function resolveProxyOrigin() {
64341
64421
  var TOOL_TIMEOUT_MS = 6e4;
64342
64422
  var CONVERSATION_FROM_ENV = process.env.CLAUDE_CODE_SESSION_ID?.trim() || process.env.BILI_CONVERSATION_ID?.trim() || void 0;
64343
64423
  var IDENTITY_BINDING = Boolean(process.env.CLAUDE_CODE_SESSION_ID?.trim());
64424
+ var ORPHAN_ADOPT = IDENTITY_BINDING && process.env.BILI_MCP_NO_ORPHAN_ADOPT !== "1";
64344
64425
  var manifestTools = [];
64345
64426
  var conversationId = CONVERSATION_FROM_ENV;
64346
64427
  var registered = false;
@@ -64373,21 +64454,45 @@ function ensureManifest() {
64373
64454
  return manifestPromise;
64374
64455
  }
64375
64456
  async function forwardTool(tool, args, timeoutMs = TOOL_TIMEOUT_MS) {
64376
- let res;
64457
+ for (let attempt = 0; ; attempt++) {
64458
+ let res;
64459
+ try {
64460
+ res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/tool`, {
64461
+ method: "POST",
64462
+ headers: { "content-type": "application/json" },
64463
+ body: JSON.stringify({ conversationId, tool, args }),
64464
+ signal: AbortSignal.timeout(timeoutMs)
64465
+ });
64466
+ } catch (err2) {
64467
+ if (err2 instanceof Error && err2.name === "TimeoutError") throw new Error(`tool forward timed out after ${timeoutMs}ms: ${tool}`);
64468
+ throw err2;
64469
+ }
64470
+ const data = await res.json();
64471
+ if (res.ok && data.ok) return data.result ?? "";
64472
+ if (res.status === 404 && attempt === 0 && ORPHAN_ADOPT && conversationId && typeof data.error === "string" && data.error.includes("no model request has arrived")) {
64473
+ if (await adoptLatestActiveConversation()) continue;
64474
+ }
64475
+ throw new Error(data.error ?? `tool forward failed: ${res.status}`);
64476
+ }
64477
+ }
64478
+ async function adoptLatestActiveConversation() {
64377
64479
  try {
64378
- res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/tool`, {
64379
- method: "POST",
64380
- headers: { "content-type": "application/json" },
64381
- body: JSON.stringify({ conversationId, tool, args }),
64382
- signal: AbortSignal.timeout(timeoutMs)
64383
- });
64384
- } catch (err2) {
64385
- if (err2 instanceof Error && err2.name === "TimeoutError") throw new Error(`tool forward timed out after ${timeoutMs}ms: ${tool}`);
64386
- throw err2;
64480
+ const res = await fetch(
64481
+ `${resolveProxyOrigin()}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId ?? "")}&fallback=latest`,
64482
+ { signal: AbortSignal.timeout(5e3) }
64483
+ );
64484
+ if (!res.ok) return false;
64485
+ const data = await res.json();
64486
+ if (data.ok !== true || data.fallback !== true || !data.conversationId || data.conversationId === conversationId) return false;
64487
+ process.stderr.write(
64488
+ `[bili-mcp] conversation id no longer known by the proxy (host resumed its session?); adopting latest active conversation ${data.conversationId}
64489
+ `
64490
+ );
64491
+ conversationId = data.conversationId;
64492
+ return true;
64493
+ } catch {
64494
+ return false;
64387
64495
  }
64388
- const data = await res.json();
64389
- if (!res.ok || !data.ok) throw new Error(data.error ?? `tool forward failed: ${res.status}`);
64390
- return data.result ?? "";
64391
64496
  }
64392
64497
  var ERR_TOOL = -32602;
64393
64498
  async function handleMessage(msg) {
@@ -65033,7 +65138,7 @@ function discoverRoutes(client, config) {
65033
65138
  } else if (client === "trae") {
65034
65139
  const hosts = nonEmpty2(config.trae?.modelApiHost) ? [config.trae.modelApiHost] : TRAE_DEFAULT_MODEL_HOSTS;
65035
65140
  for (const h of hosts) {
65036
- const host = h.toLowerCase();
65141
+ const host = h.split(":", 2)[0].toLowerCase();
65037
65142
  if (host && !httpsSeen.has(host)) {
65038
65143
  httpsSeen.add(host);
65039
65144
  httpsDomains.push(host);