billion-context 0.1.100 → 0.1.101-pr.687.511

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
@@ -47777,7 +47777,14 @@ async function fetchWithTimeout(url, opts, timeoutMs, externalSignal) {
47777
47777
  const finalOpts = {
47778
47778
  ...opts,
47779
47779
  signal: controller.signal,
47780
- dispatcher: opts.dispatcher ?? directDispatcher(effective)
47780
+ dispatcher: opts.dispatcher ?? directDispatcher(effective),
47781
+ // Forward-proxy correctness: never silently follow a redirect.
47782
+ // undici's default (follow) downgrades POST→GET and drops the body
47783
+ // on 301/302/303, so a redirecting upstream (CDN/WAF) turns a valid
47784
+ // POST into a 405 at the redirect target. Pass the 3xx through to
47785
+ // the client, which follows it with its own policy. Internal bili
47786
+ // fetches that want to follow (registry, upstream test) opt in.
47787
+ redirect: opts.redirect ?? "manual"
47781
47788
  };
47782
47789
  const raw = await fetch(url, finalOpts);
47783
47790
  if (raw.body) {
@@ -48580,6 +48587,7 @@ function parseRouteEntry(v2) {
48580
48587
  if (obj.compress) route.compress = obj.compress;
48581
48588
  const compatRoles = parseCompatRoles(obj.compat?.roles);
48582
48589
  if (compatRoles) route.compat = { roles: compatRoles };
48590
+ if (typeof obj.passthrough === "boolean") route.passthrough = obj.passthrough;
48583
48591
  return route;
48584
48592
  }
48585
48593
  if (v2 === null) return {};
@@ -49009,7 +49017,8 @@ async function fetchFresh() {
49009
49017
  try {
49010
49018
  const { response, clearTimer } = await fetchWithTimeout(REGISTRY_URL, {
49011
49019
  ...opts,
49012
- headers: { Accept: "application/json" }
49020
+ headers: { Accept: "application/json" },
49021
+ redirect: "follow"
49013
49022
  }, 15e3);
49014
49023
  const text = await response.text();
49015
49024
  clearTimer();
@@ -49248,7 +49257,9 @@ function isCodexClient(headers) {
49248
49257
  const ua = headers["user-agent"];
49249
49258
  if (!ua) return false;
49250
49259
  const s3 = Array.isArray(ua) ? ua[0] : ua;
49251
- return typeof s3 === "string" && CODEX_UA_PREFIXES.some((p2) => s3.startsWith(p2));
49260
+ if (typeof s3 !== "string") return false;
49261
+ if (CODEX_UA_PREFIXES.some((p2) => s3.startsWith(p2))) return true;
49262
+ return s3.includes("codex");
49252
49263
  }
49253
49264
  function hasCompactionTrigger(input) {
49254
49265
  if (!Array.isArray(input)) return false;
@@ -51502,20 +51513,44 @@ ${body}`;
51502
51513
  }
51503
51514
 
51504
51515
  // src/loop/tag-echo-filter.ts
51505
- var PAIRED = /\x3cacp\s[^<>]{0,256}>([^<>]{0,64})<\/acp>/;
51506
- var LONE_OPEN = /\x3cacp(?:\s[^<>]{0,256})?>/;
51507
- var LONE_CLOSE = /<\/acp(?=[\s>])[^<>]{0,32}>/;
51508
- var PARTIAL_TAIL = /(\x3cacp\s[^<>]*|\x3c\/acp(?:\s[^<>]{0,32})?|<\/?a?c?p?)$/;
51509
- var TRUNC_OPEN = /\x3cacp\s[^<>]*$/;
51510
- var TRUNC_CLOSE = /\x3c\/acp(?:\s[^<>]{0,32})?$/;
51511
- var CLOSE_TAG = "</acp";
51516
+ function buildAcplikeName() {
51517
+ const cores = ["acp", "apc", "cap", "cpa", "pac", "pca"];
51518
+ const names = new Set(cores);
51519
+ for (const c of cores) {
51520
+ for (const ch of ["a", "c", "p", "i"]) {
51521
+ for (let pos = 0; pos <= c.length; pos++) names.add(c.slice(0, pos) + ch + c.slice(pos));
51522
+ }
51523
+ }
51524
+ return [...names].sort((a, b2) => b2.length - a.length).join("|");
51525
+ }
51526
+ var ACP_NAME_ALT = `(?:${buildAcplikeName()})`;
51527
+ var NAME = ACP_NAME_ALT;
51528
+ var PAIRED = new RegExp("<" + NAME + "\\s[^<>]{0,256}>([^<>]{0,64})<\\/" + NAME + ">");
51529
+ var LONE_OPEN = new RegExp("<" + NAME + "(?:\\s[^<>]{0,256})?>");
51530
+ var LONE_CLOSE = new RegExp("<\\/" + NAME + "(?=[\\s>])[^<>]{0,32}>");
51531
+ var PARTIAL_TAIL = new RegExp("(<" + NAME + "\\s[^<>]*|<\\/" + NAME + "(?:\\s[^<>]{0,32})?|<\\/?[acip]*)$");
51532
+ var TRUNC_OPEN = new RegExp("<" + NAME + "\\s[^<>]*$");
51533
+ var TRUNC_CLOSE = new RegExp("<\\/" + NAME + "(?:\\s[^<>]{0,32})?$");
51534
+ var DEFINITE_TAIL = new RegExp("^<" + NAME + "\\s|^<\\/" + NAME);
51535
+ var OPEN_WITH_ATTRS = new RegExp("^<" + NAME + "\\s");
51536
+ var CLOSE_HEAD = "</";
51537
+ var CLOSE_NAME_ANCHORED = new RegExp("^" + NAME);
51512
51538
  var HOLD_LIMIT = 128;
51513
51539
  var TAG_OPEN_CAP = 4096;
51514
51540
  var SWALLOW_CAP = 80;
51541
+ function looseCloseEnd(s3) {
51542
+ let idx = s3.indexOf(CLOSE_HEAD);
51543
+ while (idx >= 0) {
51544
+ const m2 = CLOSE_NAME_ANCHORED.exec(s3.slice(idx + 2));
51545
+ if (m2 && s3[idx + 2 + m2[0].length] === ">") return idx + 2 + m2[0].length + 1;
51546
+ idx = s3.indexOf(CLOSE_HEAD, idx + 1);
51547
+ }
51548
+ return -1;
51549
+ }
51515
51550
  function stripAcpTags(text) {
51516
51551
  return text.replace(new RegExp(PAIRED.source, "g"), "").replace(new RegExp(LONE_OPEN.source, "g"), "").replace(new RegExp(LONE_CLOSE.source, "g"), "").replace(new RegExp(TRUNC_OPEN.source), "").replace(new RegExp(TRUNC_CLOSE.source), "");
51517
51552
  }
51518
- var RENDER_TAG_DETECT = /\x3c\/?acp(?=[\s>])|\\u003c\/?acp(?=[\s>\\])/;
51553
+ var RENDER_TAG_DETECT = new RegExp("<\\/?" + NAME + "(?=[\\s>])|\\\\u003c\\/?" + NAME + "(?=[\\s>\\\\])");
51519
51554
  function containsRenderTagText(s3) {
51520
51555
  return RENDER_TAG_DETECT.test(s3);
51521
51556
  }
@@ -51532,6 +51567,8 @@ function createTagEchoFilter(onDrop) {
51532
51567
  let swallowed = "";
51533
51568
  let droppedAny = false;
51534
51569
  let notified = false;
51570
+ let inputChars = 0;
51571
+ let outputChars = 0;
51535
51572
  const drop = (snippet) => {
51536
51573
  droppedAny = true;
51537
51574
  if (onDrop && !notified) {
@@ -51545,10 +51582,9 @@ function createTagEchoFilter(onDrop) {
51545
51582
  for (; ; ) {
51546
51583
  if (swallowUntilClose) {
51547
51584
  const combined = swallowed + buf;
51548
- const closeIdx = combined.indexOf(CLOSE_TAG);
51549
- if (closeIdx >= 0 && combined[closeIdx + CLOSE_TAG.length] === ">") {
51550
- const end = closeIdx + CLOSE_TAG.length + 1;
51551
- drop(swallowed + combined.slice(0, end));
51585
+ const end = looseCloseEnd(combined);
51586
+ if (end >= 0) {
51587
+ drop(combined.slice(0, end));
51552
51588
  swallowed = "";
51553
51589
  swallowUntilClose = false;
51554
51590
  buf = combined.slice(end);
@@ -51573,7 +51609,7 @@ function createTagEchoFilter(onDrop) {
51573
51609
  if (!m2) {
51574
51610
  const t = PARTIAL_TAIL.exec(buf);
51575
51611
  if (t) {
51576
- const definite = /^\x3cacp\s/.test(t[0]) || /^\x3c\/acp/.test(t[0]);
51612
+ const definite = DEFINITE_TAIL.test(t[0]);
51577
51613
  const cap = definite ? TAG_OPEN_CAP : HOLD_LIMIT;
51578
51614
  if (t[0].length <= cap) {
51579
51615
  held = t[0];
@@ -51592,7 +51628,7 @@ function createTagEchoFilter(onDrop) {
51592
51628
  drop(m2[0]);
51593
51629
  out += buf.slice(0, m2.index);
51594
51630
  buf = buf.slice(m2.index + m2[0].length);
51595
- if (m2 === o && /^\x3cacp\s/.test(m2[0])) {
51631
+ if (m2 === o && OPEN_WITH_ATTRS.test(m2[0])) {
51596
51632
  swallowUntilClose = true;
51597
51633
  swallowed = "";
51598
51634
  }
@@ -51601,9 +51637,12 @@ function createTagEchoFilter(onDrop) {
51601
51637
  };
51602
51638
  return {
51603
51639
  push(delta) {
51640
+ inputChars += delta.length;
51604
51641
  const chunk = held + delta;
51605
51642
  held = "";
51606
- return process2(chunk);
51643
+ const r = process2(chunk);
51644
+ outputChars += r.length;
51645
+ return r;
51607
51646
  },
51608
51647
  flush() {
51609
51648
  const rest = swallowed + held;
@@ -51611,27 +51650,36 @@ function createTagEchoFilter(onDrop) {
51611
51650
  swallowed = "";
51612
51651
  held = "";
51613
51652
  swallowUntilClose = false;
51653
+ let result;
51614
51654
  if (wasSwallowing) {
51615
51655
  if (rest.length > 0) drop(rest);
51616
- return "";
51617
- }
51618
- const t = new RegExp(TRUNC_OPEN.source).exec(rest);
51619
- if (t) {
51620
- drop(t[0]);
51621
- return rest.slice(0, t.index);
51622
- }
51623
- const tc = new RegExp(TRUNC_CLOSE.source).exec(rest);
51624
- if (tc) {
51625
- drop(tc[0]);
51626
- return rest.slice(0, tc.index);
51656
+ result = "";
51657
+ } else {
51658
+ const t = new RegExp(TRUNC_OPEN.source).exec(rest);
51659
+ if (t) {
51660
+ drop(t[0]);
51661
+ result = rest.slice(0, t.index);
51662
+ } else {
51663
+ const tc = new RegExp(TRUNC_CLOSE.source).exec(rest);
51664
+ if (tc) {
51665
+ drop(tc[0]);
51666
+ result = rest.slice(0, tc.index);
51667
+ } else {
51668
+ result = rest;
51669
+ }
51670
+ }
51627
51671
  }
51628
- return rest;
51672
+ outputChars += result.length;
51673
+ return result;
51629
51674
  },
51630
51675
  dropped() {
51631
51676
  return droppedAny;
51632
51677
  },
51633
51678
  pending() {
51634
51679
  return held.length > 0 || swallowUntilClose;
51680
+ },
51681
+ stats() {
51682
+ return { inputChars, outputChars, dropped: droppedAny };
51635
51683
  }
51636
51684
  };
51637
51685
  }
@@ -51936,16 +51984,41 @@ function splitChunks(messages, startIdx, endIdx, budget, minUnits, countText = d
51936
51984
  }
51937
51985
  return chunks;
51938
51986
  }
51939
- function summaryPayload(protocol, model, system, content, stream2) {
51987
+ function summaryPayload(protocol, model, system, content, stream2, includeMaxOutputTokens) {
51940
51988
  if (protocol === "anthropic") {
51941
51989
  return { model, max_tokens: MAX_SUMMARY_OUTPUT_TOKENS, system, messages: [{ role: "user", content }], stream: stream2 };
51942
51990
  }
51943
51991
  if (protocol === "openai") {
51944
51992
  return { model, max_tokens: MAX_SUMMARY_OUTPUT_TOKENS, messages: [{ role: "system", content: system }, { role: "user", content }], stream: stream2 };
51945
51993
  }
51946
- return { model, max_output_tokens: MAX_SUMMARY_OUTPUT_TOKENS, instructions: system, input: [{ role: "user", content }], stream: stream2, store: false };
51994
+ const payload = { model, instructions: system, input: [{ role: "user", content }], stream: stream2, store: false };
51995
+ if (includeMaxOutputTokens) payload.max_output_tokens = MAX_SUMMARY_OUTPUT_TOKENS;
51996
+ return payload;
51947
51997
  }
51948
51998
  var STREAM_REQUIRED_RE = /\bstream\b[^\n]{0,60}\btrue\b/i;
51999
+ var MAX_OUTPUT_TOKENS_REJECTED_RE = /\bmax_output_tokens\b/i;
52000
+ function noMaxOutputTokensKey(deps) {
52001
+ return `${deps.url}\0${deps.model}`;
52002
+ }
52003
+ function hasLearnedNoMaxOutputTokens(deps) {
52004
+ const learned = deps.session.metadata.preflightNoMaxOutputTokens;
52005
+ return typeof learned === "object" && learned !== null && learned[noMaxOutputTokensKey(deps)] === true;
52006
+ }
52007
+ function rememberNoMaxOutputTokens(deps) {
52008
+ const learned = deps.session.metadata.preflightNoMaxOutputTokens;
52009
+ const map = typeof learned === "object" && learned !== null ? learned : {};
52010
+ map[noMaxOutputTokensKey(deps)] = true;
52011
+ deps.session.metadata.preflightNoMaxOutputTokens = map;
52012
+ }
52013
+ var SUMMARY_STRIP_HEADERS = /* @__PURE__ */ new Set(["x-openai-internal-codex-responses-lite"]);
52014
+ function summaryHeaders(deps) {
52015
+ const headers = {};
52016
+ for (const [k2, v2] of Object.entries(deps.headers)) {
52017
+ if (SUMMARY_STRIP_HEADERS.has(k2.toLowerCase())) continue;
52018
+ headers[k2] = v2;
52019
+ }
52020
+ return headers;
52021
+ }
51949
52022
  function extractSummaryFromSse(protocol, text) {
51950
52023
  let out = "";
51951
52024
  for (const line of text.split("\n")) {
@@ -52009,25 +52082,39 @@ async function summarizeRange(deps, content, startRef, endRef) {
52009
52082
  const system = buildCompressSystemPrompt(deps.prompts) + `
52010
52083
 
52011
52084
  TASK: The conversation segment below (messages ${startRef}\u2013${endRef}) must be compressed because the session context exceeds the current model's window. Write a tier-1 compression summary of the segment following every rule above. Output ONLY the summary text \u2014 no preamble, no closing remarks, no tool calls.`;
52012
- const learned = deps.session.metadata.preflightStreamSummary === true;
52013
- try {
52014
- return await requestSummary(deps, system, content, learned);
52015
- } catch (err2) {
52016
- if (err2 instanceof UpstreamHttpError && err2.status === 400 && !learned && STREAM_REQUIRED_RE.test(err2.body)) {
52017
- deps.session.metadata.preflightStreamSummary = true;
52018
- deps.log("info", "[preflight] upstream requires stream for summaries; retrying with SSE (learned for this session)");
52019
- return await requestSummary(deps, system, content, true);
52085
+ let stream2 = deps.session.metadata.preflightStreamSummary === true;
52086
+ let includeMaxOutputTokens = !(deps.protocol === "responses" && hasLearnedNoMaxOutputTokens(deps));
52087
+ for (; ; ) {
52088
+ try {
52089
+ return await requestSummary(deps, system, content, stream2, includeMaxOutputTokens);
52090
+ } catch (err2) {
52091
+ if (err2 instanceof UpstreamHttpError && err2.status === 400) {
52092
+ let adapted = false;
52093
+ if (!stream2 && STREAM_REQUIRED_RE.test(err2.body)) {
52094
+ deps.session.metadata.preflightStreamSummary = true;
52095
+ stream2 = true;
52096
+ adapted = true;
52097
+ deps.log("info", "[preflight] upstream requires stream for summaries; retrying with SSE (learned for this session)");
52098
+ }
52099
+ if (deps.protocol === "responses" && includeMaxOutputTokens && MAX_OUTPUT_TOKENS_REJECTED_RE.test(err2.body)) {
52100
+ rememberNoMaxOutputTokens(deps);
52101
+ includeMaxOutputTokens = false;
52102
+ adapted = true;
52103
+ deps.log("info", `[preflight] upstream rejects max_output_tokens for summaries (model=${deps.model}); retrying without it (learned for this session+upstream+model)`);
52104
+ }
52105
+ if (adapted) continue;
52106
+ }
52107
+ throw err2;
52020
52108
  }
52021
- throw err2;
52022
52109
  }
52023
52110
  }
52024
- async function requestSummary(deps, system, content, stream2) {
52111
+ async function requestSummary(deps, system, content, stream2, includeMaxOutputTokens) {
52025
52112
  const { response, clearTimer } = await fetchWithRetry(
52026
52113
  deps.url,
52027
52114
  {
52028
52115
  method: "POST",
52029
- headers: { "content-type": "application/json", ...deps.headers },
52030
- body: JSON.stringify(summaryPayload(deps.protocol, deps.model, system, content, stream2)),
52116
+ headers: { "content-type": "application/json", ...summaryHeaders(deps) },
52117
+ body: JSON.stringify(summaryPayload(deps.protocol, deps.model, system, content, stream2, includeMaxOutputTokens)),
52031
52118
  dispatcher: proxyDispatcher(deps.proxyUrl)
52032
52119
  },
52033
52120
  void 0,
@@ -53664,6 +53751,18 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
53664
53751
  }
53665
53752
  }
53666
53753
 
53754
+ // src/degenerate-turn.ts
53755
+ function degenerateTurnWarning(o) {
53756
+ if ((o.reason ?? o.terminalReason) !== o.terminalReason) return null;
53757
+ if (o.toolCalls > 0) return null;
53758
+ if (o.text.outputChars > 0) return null;
53759
+ const bits = [];
53760
+ if (o.sawThinking) bits.push("thinking present");
53761
+ if (o.text.dropped && o.text.inputChars > 0) bits.push(`${o.text.inputChars} chars of emitted text stripped as render-tag echo`);
53762
+ else bits.push("no visible text emitted");
53763
+ return `[degenerate-turn] ${o.wire}: turn ended ${o.terminalReason} with zero visible text and zero tool calls (${bits.join("; ")}) \u2014 the agent receives an empty turn and may stall until nudged (#673)`;
53764
+ }
53765
+
53667
53766
  // src/loop/adapter-responses.ts
53668
53767
  var RESPONSES_ITEM_ID_MAX = 64;
53669
53768
  function normalizeResponsesMessageItems(input) {
@@ -53727,7 +53826,7 @@ function dropWhitespaceResponsesMessages(input) {
53727
53826
  }
53728
53827
  return dropped;
53729
53828
  }
53730
- var RENDER_TAG_RE = /\x3cacp\s[^>]*\x3e[^<]*\x3c\/acp\x3e|\x3cacp\s[^>]*\/\x3e/g;
53829
+ var RENDER_TAG_RE = new RegExp("<" + ACP_NAME_ALT + "\\s[^>]*>[^<]*<\\/" + ACP_NAME_ALT + ">|<" + ACP_NAME_ALT + "\\s[^>]*\\/>", "g");
53731
53830
  function stripRenderTags(text) {
53732
53831
  return text.replace(RENDER_TAG_RE, "");
53733
53832
  }
@@ -53942,6 +54041,17 @@ data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId
53942
54041
  yield { kind: "text", delta: tail, ...raw ? { raw } : {} };
53943
54042
  }
53944
54043
  };
54044
+ let sawReasoning = false;
54045
+ let toolCallsEmitted = 0;
54046
+ let degenerateWarned = false;
54047
+ const maybeWarnDegenerate = (reason) => {
54048
+ if (degenerateWarned) return;
54049
+ const msg = degenerateTurnWarning({ reason, terminalReason: "completed", toolCalls: toolCallsEmitted, text: tagFilter.stats(), sawThinking: sawReasoning, wire: "responses" });
54050
+ if (msg) {
54051
+ degenerateWarned = true;
54052
+ log("warn", msg);
54053
+ }
54054
+ };
53945
54055
  for await (const eventStr of iterSseEvents(upstream)) {
53946
54056
  const explicitType = extractEventType(eventStr);
53947
54057
  const dataLine = extractDataLine(eventStr);
@@ -53954,6 +54064,7 @@ data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId
53954
54064
  }
53955
54065
  const type = explicitType ?? (typeof obj.type === "string" ? obj.type : null);
53956
54066
  if (!type) continue;
54067
+ if (type.startsWith("response.reasoning")) sawReasoning = true;
53957
54068
  const rawBuf = Buffer.from(eventStr + "\n\n", "utf8");
53958
54069
  if (round === 1 && typeof obj.output_index === "number") {
53959
54070
  outputIndex = Math.max(outputIndex, obj.output_index + 1);
@@ -54037,6 +54148,7 @@ data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId
54037
54148
  if (fc) {
54038
54149
  if (typeof item.arguments === "string" && item.arguments) fc.arguments = item.arguments;
54039
54150
  pending.delete(itemId);
54151
+ toolCallsEmitted++;
54040
54152
  yield {
54041
54153
  kind: "tool_call",
54042
54154
  name: fc.name,
@@ -54045,6 +54157,7 @@ data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId
54045
54157
  };
54046
54158
  } else {
54047
54159
  yield { kind: "meta", chunk: rawBuf, firstRoundOnly: false };
54160
+ toolCallsEmitted++;
54048
54161
  yield {
54049
54162
  kind: "tool_call",
54050
54163
  name: typeof item.name === "string" ? item.name : "",
@@ -54081,6 +54194,7 @@ data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId
54081
54194
  outputTokens: typeof respUsage?.output_tokens === "number" ? respUsage.output_tokens : void 0,
54082
54195
  cachedTokens: typeof pd?.cached_tokens === "number" ? pd.cached_tokens : void 0
54083
54196
  };
54197
+ maybeWarnDegenerate("completed");
54084
54198
  yield { kind: "done", finishReason: "completed" };
54085
54199
  } else if (type === "response.incomplete") {
54086
54200
  yield* flushFilter();
@@ -54398,11 +54512,23 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54398
54512
  yield { kind: "text", delta: tail, raw: buildContent(tail) };
54399
54513
  }
54400
54514
  };
54515
+ let sawReasoning = false;
54516
+ let toolCallsEmitted = 0;
54517
+ let degenerateWarned = false;
54518
+ const maybeWarnDegenerate = (reason) => {
54519
+ if (degenerateWarned) return;
54520
+ const msg = degenerateTurnWarning({ reason, terminalReason: "stop", toolCalls: toolCallsEmitted, text: tagFilter.stats(), sawThinking: sawReasoning, wire: "openai" });
54521
+ if (msg) {
54522
+ degenerateWarned = true;
54523
+ log("warn", msg);
54524
+ }
54525
+ };
54401
54526
  const rawToolChunks = [];
54402
54527
  let sawRealToolCall = false;
54403
54528
  const flushPendingAsStructured = function* () {
54404
54529
  for (const [, tc] of pending) {
54405
54530
  if (tc.name.length > 0 || tc.id.length > 0) {
54531
+ toolCallsEmitted++;
54406
54532
  yield {
54407
54533
  kind: "tool_call",
54408
54534
  name: tc.name,
@@ -54425,6 +54551,7 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54425
54551
  }
54426
54552
  for (const [idx, tc] of pending) {
54427
54553
  if (realIndexes.has(idx) && (tc.name.length > 0 || tc.id.length > 0)) {
54554
+ toolCallsEmitted++;
54428
54555
  yield {
54429
54556
  kind: "tool_call",
54430
54557
  name: tc.name,
@@ -54444,6 +54571,7 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54444
54571
  }
54445
54572
  for (const [idx, tc] of pending) {
54446
54573
  if (!realIndexes.has(idx) && tc.name.length > 0) {
54574
+ toolCallsEmitted++;
54447
54575
  yield {
54448
54576
  kind: "tool_call",
54449
54577
  name: tc.name,
@@ -54468,6 +54596,7 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54468
54596
  if (sawRealToolCall) {
54469
54597
  yield { kind: "meta", chunk: Buffer.from(eventStr + "\n\n", "utf8") };
54470
54598
  }
54599
+ maybeWarnDegenerate("stop");
54471
54600
  yield { kind: "done", finishReason: "stop", ...sawRealToolCall ? { suppressCompletion: true } : {} };
54472
54601
  continue;
54473
54602
  }
@@ -54513,9 +54642,11 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54513
54642
  if (sawRealToolCall) {
54514
54643
  const chunk = patchUsageChunk(eventStr, parsed, u2 ?? {}, hostCredit);
54515
54644
  yield { kind: "meta", chunk };
54645
+ maybeWarnDegenerate(finishReason);
54516
54646
  yield { kind: "done", finishReason, suppressCompletion: true };
54517
54647
  continue;
54518
54648
  } else {
54649
+ maybeWarnDegenerate(finishReason);
54519
54650
  yield {
54520
54651
  kind: "done",
54521
54652
  finishReason: hadToolCalls && finishReason === "stop" ? "tool_calls" : finishReason
@@ -54524,6 +54655,7 @@ function createOpenaiAdapter(requestBody, clientSystem, hostCredit = 0, absorbNa
54524
54655
  }
54525
54656
  if (!delta) continue;
54526
54657
  if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
54658
+ sawReasoning = true;
54527
54659
  yield { kind: "reasoning", delta: delta.reasoning_content, raw: finishReason ? stripFinishReasonChunk(rawBuf) : rawBuf };
54528
54660
  }
54529
54661
  if (delta.tool_calls) {
@@ -54801,6 +54933,17 @@ ${systemPrompt}` : systemPrompt;
54801
54933
  log("warn", `[tag-echo] stripped model-emitted render tag: ${snippet.slice(0, 80).replace(/\n/g, " ")}`);
54802
54934
  });
54803
54935
  let lastTextIndex = null;
54936
+ let sawThinking = false;
54937
+ let toolCallsEmitted = 0;
54938
+ let degenerateWarned = false;
54939
+ const maybeWarnDegenerate = (reason) => {
54940
+ if (degenerateWarned) return;
54941
+ const msg = degenerateTurnWarning({ reason, terminalReason: "end_turn", toolCalls: toolCallsEmitted, text: tagFilter.stats(), sawThinking, wire: "anthropic" });
54942
+ if (msg) {
54943
+ degenerateWarned = true;
54944
+ log("warn", msg);
54945
+ }
54946
+ };
54804
54947
  for await (const eventStr of iterSseEvents2(upstream)) {
54805
54948
  const parsed = parseAnthropicSse(eventStr);
54806
54949
  if (!parsed) continue;
@@ -54837,7 +54980,10 @@ ${systemPrompt}` : systemPrompt;
54837
54980
  const id = typeof block.id === "string" ? block.id : `toolu_${upstreamIndex}`;
54838
54981
  pending.set(upstreamIndex, { id, name, json: "" });
54839
54982
  } else {
54840
- if (block.type === "thinking" || block.type === "redacted_thinking") thinkingIndexes.add(upstreamIndex);
54983
+ if (block.type === "thinking" || block.type === "redacted_thinking") {
54984
+ thinkingIndexes.add(upstreamIndex);
54985
+ sawThinking = true;
54986
+ }
54841
54987
  const ci2 = clientIndex++;
54842
54988
  indexMap.set(upstreamIndex, ci2);
54843
54989
  openBlocks.push(ci2);
@@ -54882,6 +55028,7 @@ ${systemPrompt}` : systemPrompt;
54882
55028
  const tb = pending.get(upstreamIndex);
54883
55029
  if (tb) {
54884
55030
  pending.delete(upstreamIndex);
55031
+ toolCallsEmitted++;
54885
55032
  yield {
54886
55033
  kind: "tool_call",
54887
55034
  name: tb.name,
@@ -54928,6 +55075,7 @@ ${systemPrompt}` : systemPrompt;
54928
55075
  cachedTokens: roundCached
54929
55076
  };
54930
55077
  }
55078
+ maybeWarnDegenerate(stopReason);
54931
55079
  yield { kind: "done", finishReason: stopReason };
54932
55080
  } else if (type === "message_stop") {
54933
55081
  if (lastTextIndex !== null) {
@@ -54946,6 +55094,7 @@ ${systemPrompt}` : systemPrompt;
54946
55094
  cachedTokens: roundCached
54947
55095
  };
54948
55096
  }
55097
+ maybeWarnDegenerate(stopReason);
54949
55098
  yield { kind: "done", finishReason: stopReason ?? "end_turn" };
54950
55099
  } else if (round === 1) {
54951
55100
  yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
@@ -56556,11 +56705,18 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56556
56705
 
56557
56706
  `;
56558
56707
  };
56708
+ let sawToolUse = false;
56709
+ let sawThinking = false;
56710
+ let visibleTextChars = 0;
56711
+ let finalFinishReason;
56559
56712
  const flushTails = () => {
56560
56713
  let out = "";
56561
56714
  for (const s3 of streams.values()) {
56562
56715
  const tail = s3.filter.flush();
56563
- if (tail.length > 0) out += syntheticTail(s3.field, s3.index, tail);
56716
+ if (tail.length > 0) {
56717
+ out += syntheticTail(s3.field, s3.index, tail);
56718
+ if (s3.field === "content" || s3.field === "text") visibleTextChars += tail.length;
56719
+ }
56564
56720
  }
56565
56721
  return out;
56566
56722
  };
@@ -56583,6 +56739,28 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56583
56739
  reason: "plugin chat passthrough stream ended without a completion event"
56584
56740
  });
56585
56741
  };
56742
+ const maybeWarnDegenerate = () => {
56743
+ if (!sawTerminal || res.destroyed || res.writableEnded) return;
56744
+ let inputChars = 0;
56745
+ let dropped = false;
56746
+ for (const s3 of streams.values()) {
56747
+ const st2 = s3.filter.stats();
56748
+ inputChars += st2.inputChars;
56749
+ dropped = dropped || st2.dropped;
56750
+ }
56751
+ const msg = degenerateTurnWarning({
56752
+ reason: finalFinishReason,
56753
+ terminalReason: protocol === "anthropic" ? "end_turn" : "stop",
56754
+ toolCalls: sawToolUse ? 1 : 0,
56755
+ text: { inputChars, outputChars: visibleTextChars, dropped },
56756
+ sawThinking,
56757
+ wire: `plugin-passthrough-${protocol}`
56758
+ });
56759
+ if (msg) {
56760
+ log("warn", msg);
56761
+ log2?.(msg);
56762
+ }
56763
+ };
56586
56764
  const pushField = (field, index, text) => {
56587
56765
  const s3 = filterFor(field, index);
56588
56766
  const clean = s3.filter.push(text);
@@ -56602,21 +56780,28 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56602
56780
  let hadText = false;
56603
56781
  for (let ci2 = 0; ci2 < choices.length; ci2++) {
56604
56782
  const ch = choices[ci2];
56783
+ if (ch && typeof ch["finish_reason"] === "string") finalFinishReason = ch["finish_reason"];
56605
56784
  const d = ch?.["delta"];
56606
56785
  if (!d || typeof d !== "object") continue;
56607
56786
  const dd = d;
56787
+ if (dd["tool_calls"] !== void 0) sawToolUse = true;
56608
56788
  for (const field of ["content", "reasoning_content", "reasoning"]) {
56609
56789
  const v2 = dd[field];
56610
56790
  if (typeof v2 !== "string") continue;
56611
56791
  hadText = true;
56792
+ if (field !== "content" && v2.length > 0) sawThinking = true;
56612
56793
  if (!mayStartRenderTag(v2) && !anyPending()) {
56613
56794
  if (v2.length > 0) keptText = true;
56795
+ if (field === "content") visibleTextChars += v2.length;
56614
56796
  continue;
56615
56797
  }
56616
56798
  const index = typeof ch?.["index"] === "number" ? ch["index"] : ci2;
56617
56799
  const [clean, changed] = pushField(field, index, v2);
56618
56800
  if (clean.length === 0) droppedText = true;
56619
- else keptText = true;
56801
+ else {
56802
+ keptText = true;
56803
+ if (field === "content") visibleTextChars += clean.length;
56804
+ }
56620
56805
  if (changed) {
56621
56806
  if (!rebuilt) {
56622
56807
  rebuilt = { ...ev, choices: choices.map((c) => ({ ...c, delta: { ...c["delta"] } })) };
@@ -56635,6 +56820,13 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56635
56820
  return rawEvent + "\n\n";
56636
56821
  };
56637
56822
  const processAnthropic = (ev, rawEvent) => {
56823
+ if (ev["type"] === "content_block_start") {
56824
+ const cb = ev["content_block"];
56825
+ const bt2 = cb && typeof cb === "object" ? cb["type"] : void 0;
56826
+ if (bt2 === "tool_use") sawToolUse = true;
56827
+ else if (bt2 === "thinking" || bt2 === "redacted_thinking") sawThinking = true;
56828
+ return anyPending() ? flushTails() + rawEvent + "\n\n" : rawEvent + "\n\n";
56829
+ }
56638
56830
  if (ev["type"] !== "content_block_delta") {
56639
56831
  return anyPending() ? flushTails() + rawEvent + "\n\n" : rawEvent + "\n\n";
56640
56832
  }
@@ -56645,11 +56837,17 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56645
56837
  return rawEvent + "\n\n";
56646
56838
  }
56647
56839
  const raw = d[field];
56840
+ if (field === "thinking" && raw.length > 0) sawThinking = true;
56648
56841
  if (!mayStartRenderTag(raw) && !anyPending()) {
56842
+ if (field === "text" && raw.length > 0) visibleTextChars += raw.length;
56649
56843
  return rawEvent + "\n\n";
56650
56844
  }
56651
56845
  const [clean, changed] = pushField(field, index, raw);
56652
- if (!changed) return rawEvent + "\n\n";
56846
+ if (!changed) {
56847
+ if (field === "text" && raw.length > 0) visibleTextChars += raw.length;
56848
+ return rawEvent + "\n\n";
56849
+ }
56850
+ if (field === "text" && clean.length > 0) visibleTextChars += clean.length;
56653
56851
  if (clean.length === 0 && Object.keys(d ?? {}).length <= 2) return "";
56654
56852
  return rebuildEvent(rawEvent, { ...ev, delta: { ...d, [field]: clean } });
56655
56853
  };
@@ -56680,6 +56878,10 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56680
56878
  continue;
56681
56879
  }
56682
56880
  if (ev["type"] === "message_stop") sawTerminal = true;
56881
+ if (ev["type"] === "message_delta") {
56882
+ const d = ev["delta"];
56883
+ if (d && typeof d["stop_reason"] === "string") finalFinishReason = d["stop_reason"];
56884
+ }
56683
56885
  const sample = usageFromSseEvent(ev);
56684
56886
  if (sample) mergeUsageSample(acc, sample);
56685
56887
  let backfilled = false;
@@ -56703,6 +56905,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
56703
56905
  if (rest.length > 0 && !res.destroyed && !res.writableEnded) await write(rest);
56704
56906
  settleUsage();
56705
56907
  maybeNoteTruncated();
56908
+ maybeWarnDegenerate();
56706
56909
  } catch (e) {
56707
56910
  settleUsage();
56708
56911
  maybeNoteTruncated();
@@ -56739,6 +56942,9 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
56739
56942
  log("warn", `[tag-echo] stripped model-emitted render tag (plugin passthrough): ${snippet.slice(0, 80).replace(/\n/g, " ")}`);
56740
56943
  log2?.(`[tag-echo] stripped model-emitted render tag from plugin passthrough text`);
56741
56944
  });
56945
+ let sawFunctionCall = false;
56946
+ let sawReasoning = false;
56947
+ let responseStatus;
56742
56948
  const write = (s3) => {
56743
56949
  if (!res.write(Buffer.from(s3, "utf8"))) {
56744
56950
  return new Promise((r) => res.once("drain", () => r()));
@@ -56759,6 +56965,22 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
56759
56965
  reason: "plugin responses passthrough stream ended without a completion event"
56760
56966
  });
56761
56967
  };
56968
+ const maybeWarnDegenerate = () => {
56969
+ if (!sawTerminal || res.destroyed || res.writableEnded) return;
56970
+ const st2 = tagFilter.stats();
56971
+ const msg = degenerateTurnWarning({
56972
+ reason: responseStatus,
56973
+ terminalReason: "completed",
56974
+ toolCalls: sawFunctionCall ? 1 : 0,
56975
+ text: st2,
56976
+ sawThinking: sawReasoning,
56977
+ wire: "plugin-passthrough-responses"
56978
+ });
56979
+ if (msg) {
56980
+ log("warn", msg);
56981
+ log2?.(msg);
56982
+ }
56983
+ };
56762
56984
  let lastDeltaMeta = null;
56763
56985
  const flushTail = (after) => {
56764
56986
  const tail = tagFilter.flush();
@@ -56798,6 +57020,16 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
56798
57020
  const sample = usageFromSseEvent(ev);
56799
57021
  if (sample) mergeUsageSample(acc, sample);
56800
57022
  const type = ev["type"];
57023
+ if (typeof type === "string") {
57024
+ if (type.startsWith("response.reasoning")) sawReasoning = true;
57025
+ if (type === "response.output_item.added" || type === "response.output_item.done") {
57026
+ const item = ev["item"];
57027
+ const it2 = item?.["type"];
57028
+ if (it2 === "function_call" || it2 === "custom_tool_call") sawFunctionCall = true;
57029
+ }
57030
+ const resp = ev["response"];
57031
+ if (resp && typeof resp["status"] === "string") responseStatus = resp["status"];
57032
+ }
56801
57033
  if (type === "response.output_text.done" || type === "response.content_part.done" || type === "response.output_item.done" || type === "response.completed" || type === "response.failed" || type === "response.incomplete") {
56802
57034
  if (type === "response.completed" || type === "response.failed" || type === "response.incomplete") sawTerminal = true;
56803
57035
  let evOut = ev;
@@ -56843,6 +57075,7 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
56843
57075
  const rest = flushTail("");
56844
57076
  if (rest.length > 0) await write(rest);
56845
57077
  }
57078
+ maybeWarnDegenerate();
56846
57079
  settleUsage();
56847
57080
  maybeNoteTruncated();
56848
57081
  } catch (e) {
@@ -56967,6 +57200,10 @@ function resolveDshHome(env) {
56967
57200
  const h = os.homedir();
56968
57201
  return nonEmpty2(env.DSH_HOME) ? env.DSH_HOME : path10.join(h, ".dsh");
56969
57202
  }
57203
+ function resolveCodexHome(env) {
57204
+ const h = os.homedir();
57205
+ return nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path10.join(h, ".codex");
57206
+ }
56970
57207
  function parseDshSettingsYaml(text) {
56971
57208
  const out = [];
56972
57209
  const seen = /* @__PURE__ */ new Set();
@@ -58918,6 +59155,7 @@ async function handle(req, res, opts, core, config, log2, instanceId, instanceSt
58918
59155
  try {
58919
59156
  const result = await fetchWithTimeout(targetUrl2, {
58920
59157
  method: "HEAD",
59158
+ redirect: "follow",
58921
59159
  ...proxyUrl ? { dispatcher: proxyDispatcher(proxyUrl, 15e3) } : {}
58922
59160
  }, 15e3);
58923
59161
  result.clearTimer();
@@ -59114,7 +59352,11 @@ ${bodyBuffer.toString("utf8")}`);
59114
59352
  }
59115
59353
  }
59116
59354
  let prepared = null;
59117
- if (!opts.passthrough && hopMarker === void 0 && protocol && parsed && typeof parsed === "object") {
59355
+ const routePassthrough = !opts.passthrough && findRoute(opts.routes, route?.rewrittenUrl)?.passthrough === true;
59356
+ if (routePassthrough && hopMarker === void 0 && protocol && parsed) {
59357
+ log2("info", `[route-passthrough] ${maskUrlsInText(route?.rewrittenUrl ?? "")} matches a passthrough route \u2014 forwarding verbatim, kernel bypassed`);
59358
+ }
59359
+ if (!opts.passthrough && !routePassthrough && hopMarker === void 0 && protocol && parsed && typeof parsed === "object") {
59118
59360
  const sessionHeader = headerValue2(req, opts.sessionHeader);
59119
59361
  let pluginAgent = pluginAgentHeader(req.headers);
59120
59362
  let pluginConversation = pluginConversationHeader(req.headers);
@@ -59375,7 +59617,7 @@ ${bodyBuffer.toString("utf8")}`);
59375
59617
  }
59376
59618
  }
59377
59619
  if (!prepared) {
59378
- if (protocol === null && !opts.passthrough && !isModelDiscoveryPath(urlPath)) {
59620
+ if (protocol === null && !opts.passthrough && !routePassthrough && !isModelDiscoveryPath(urlPath)) {
59379
59621
  logUnrecognizedPath(log2, req.url ?? "");
59380
59622
  }
59381
59623
  await forward(req, res, opts, bodyBuffer, null, core, reqConfig, log2, route, instanceId, void 0);
@@ -59477,10 +59719,11 @@ function diagNudge(turn, sessionId, tokenCount, limit, model, willInject) {
59477
59719
  const modelTag = model ? ` model=${model}` : "";
59478
59720
  return `[${sessionId}] nudge ${inject}: usage=${pct2} (${tokenCount}/${limit}), growth=${growth}/${floor} (ref=${ref}, interval=${interval}), pendingT1=${pendingT1}/${interval}${modelTag}, reason="${n.reason.slice(0, 120)}"`;
59479
59721
  }
59480
- function armHostUsageCredit(session, originalMessages, processedMessages, hostUsageCredit, log2) {
59722
+ function armHostUsageCredit(session, originalMessages, processedMessages, headers, hostUsageCredit, log2) {
59481
59723
  session.hostCreditTokens = 0;
59482
59724
  if (hostUsageCredit === "off") return;
59483
59725
  if (session.metadata.pluginAgent === "pi" || session.metadata.pluginAgent === "omp") return;
59726
+ if (isCodexClient(headers)) return;
59484
59727
  session.hostCreditTokens = processedMessages.length > 0 ? Math.max(0, estimateCoreMessages(originalMessages) - estimateCoreMessages(processedMessages)) : 0;
59485
59728
  if (session.hostCreditTokens > 0) {
59486
59729
  log2("info", `[${session.id}] host usage backfill armed: +${session.hostCreditTokens} tok (forwarded view is folded); host usage will report the uncompressed baseline`);
@@ -59561,7 +59804,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
59561
59804
  markDirty(session);
59562
59805
  const rebuilt = { ...parsed, messages: rebuiltMessages, system: systemOut, tools: toolsOut };
59563
59806
  delete rebuilt.prompt_cache_key;
59564
- armHostUsageCredit(session, originalMessages, processedMessages, opts.hostUsageCredit, log2);
59807
+ armHostUsageCredit(session, originalMessages, processedMessages, req.headers, opts.hostUsageCredit, log2);
59565
59808
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, renderTags: "text-only" };
59566
59809
  }
59567
59810
  var OUTPUT_CLAMP_MARGIN_PCT = 0.05;
@@ -59693,7 +59936,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59693
59936
  if (stream2 && rebuilt.stream_options === void 0) {
59694
59937
  rebuilt.stream_options = { include_usage: true };
59695
59938
  }
59696
- armHostUsageCredit(session, originalMessages, processedMessages, opts.hostUsageCredit, log2);
59939
+ armHostUsageCredit(session, originalMessages, processedMessages, req.headers, opts.hostUsageCredit, log2);
59697
59940
  if (!isTitleGen && openaiOutboundSystem !== void 0) {
59698
59941
  session.metadata.systemPromptTokens = countSystemAndToolsTokens(openaiOutboundSystem, toolsOut);
59699
59942
  }
@@ -59845,7 +60088,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
59845
60088
  });
59846
60089
  log2("info", `[${sessionId}] responses forward tools=[${fwdTools.join(",")}] injectTool=${injectTools}${pluginMode ? " (plugin mode: wire injection suppressed)" : ""} NO_INJECT_TOOL=${!!process.env.ACP_NO_INJECT_TOOL} NO_COMPRESS_PROMPT=${!!process.env.ACP_NO_COMPRESS_PROMPT}`);
59847
60090
  }
59848
- armHostUsageCredit(session, originalMessages, processedMessages, opts.hostUsageCredit, log2);
60091
+ armHostUsageCredit(session, originalMessages, processedMessages, req.headers, opts.hostUsageCredit, log2);
59849
60092
  if (transformOk) {
59850
60093
  session.metadata.systemPromptTokens = countSystemAndToolsTokens(responsesDevContent ?? "", toolsOut);
59851
60094
  }
@@ -64860,17 +65103,22 @@ args = [${JSON.stringify(path14.join(selfPackageRoot(), "dist", "mcp.js"))}]
64860
65103
  env = { BILI_MCP_PROXY = ${JSON.stringify(proxyOriginForInstall())} }
64861
65104
  `;
64862
65105
  }
65106
+ function malformedCodexArgs(block) {
65107
+ return /^[ \t]*args[ \t]*=[ \t]*["']/m.test(block);
65108
+ }
64863
65109
  function codexInstall() {
64864
65110
  const file = codexToml();
64865
65111
  const text = fs11.existsSync(file) ? fs11.readFileSync(file, "utf8") : "";
64866
65112
  const existing = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
64867
65113
  if (existing !== null) {
64868
65114
  const block = text.slice(existing.index, text.indexOf("\n[", existing.index + 1) === -1 ? void 0 : text.indexOf("\n[", existing.index + 1));
64869
- if (block.includes(`BILI_MCP_PROXY = ${JSON.stringify(proxyOriginForInstall())}`)) return `codex: already installed (${file})`;
64870
- const refreshed = text.slice(0, existing.index) + codexBlock().replace(/^\n/, "") + text.slice(existing.index + block.length);
65115
+ const canonical = codexBlock().replace(/^\n/, "");
65116
+ if (block.trimEnd() === canonical.trimEnd()) return `codex: already installed (${file})`;
65117
+ const refreshed = text.slice(0, existing.index) + canonical + text.slice(existing.index + block.length);
64871
65118
  backupOnce(file);
64872
65119
  fs11.writeFileSync(file, refreshed);
64873
- return `codex: refreshed proxy origin -> ${file} [mcp_servers.bili]`;
65120
+ const healed = malformedCodexArgs(block) ? " (repaired args: was not an array)" : "";
65121
+ return `codex: refreshed [mcp_servers.bili] -> ${file}${healed}`;
64874
65122
  }
64875
65123
  fs11.mkdirSync(path14.dirname(file), { recursive: true });
64876
65124
  backupOnce(file);
@@ -65279,6 +65527,20 @@ function buildCodexMcpArgs(origin, conversationId2) {
65279
65527
  `mcp_servers.bili.env.BILI_CONVERSATION_ID=${JSON.stringify(conversationId2)}`
65280
65528
  ];
65281
65529
  }
65530
+ function prepareCodexMcpInjection(opts) {
65531
+ if (opts.platform !== "win32") {
65532
+ return { clientArgs: buildCodexMcpArgs(opts.origin, opts.conversationId), envPatch: {} };
65533
+ }
65534
+ const overlay = prepareCodexHome(opts.codexHome, opts.origin, opts.conversationId);
65535
+ if (!overlay) {
65536
+ return {
65537
+ clientArgs: [],
65538
+ envPatch: {},
65539
+ warning: "could not prepare the codex MCP overlay (<CODEX_HOME>-bili) \u2014 launching without native bili MCP tools; wire-injected compression is still active."
65540
+ };
65541
+ }
65542
+ return { clientArgs: [], envPatch: { CODEX_HOME: overlay } };
65543
+ }
65282
65544
  function overlayLockPath(overlay) {
65283
65545
  return path15.join(overlay, ".bili-launch.pid");
65284
65546
  }
@@ -65706,6 +65968,39 @@ function prepareDshHome(dshHome, origin, rewrites) {
65706
65968
  writeOverlayFileAtomic(overlay, "settings.yaml", lines.join(eol));
65707
65969
  return overlay;
65708
65970
  }
65971
+ function stripCodexBiliBlock(text) {
65972
+ const m2 = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
65973
+ if (m2 === null) return text;
65974
+ const start = m2.index;
65975
+ const lineStart = text.lastIndexOf("\n", start - 1) + 1;
65976
+ const after = text.slice(start);
65977
+ const firstNewline = after.indexOf("\n");
65978
+ const nextTable = firstNewline < 0 ? -1 : after.slice(firstNewline + 1).search(/^[ \t]*\[/m);
65979
+ const end = nextTable >= 0 ? start + firstNewline + 1 + nextTable : text.length;
65980
+ return (text.slice(0, lineStart).replace(/\n+$/, "\n") + text.slice(end)).replace(/^\n+/, "");
65981
+ }
65982
+ function mergeCodexBiliBlock(text, origin, conversationId2) {
65983
+ const script = selfDistFile("mcp.js");
65984
+ const block = `
65985
+ [mcp_servers.bili]
65986
+ command = ${JSON.stringify(process.execPath)}
65987
+ args = [${JSON.stringify(script)}]
65988
+ env = { BILI_MCP_PROXY = ${JSON.stringify(origin)}, BILI_CONVERSATION_ID = ${JSON.stringify(conversationId2)} }
65989
+ `;
65990
+ const base = stripCodexBiliBlock(text);
65991
+ return base + (base.endsWith("\n") || base.length === 0 ? "" : "\n") + block;
65992
+ }
65993
+ function prepareCodexHome(codexHome, origin, conversationId2) {
65994
+ let txt = "";
65995
+ try {
65996
+ txt = fs12.readFileSync(path15.join(codexHome, "config.toml"), "utf8");
65997
+ } catch {
65998
+ }
65999
+ const overlay = `${codexHome}-bili`;
66000
+ if (!refreshOverlayHome(codexHome, overlay, "config.toml")) return void 0;
66001
+ writeOverlayFileAtomic(overlay, "config.toml", mergeCodexBiliBlock(txt, origin, conversationId2));
66002
+ return overlay;
66003
+ }
65709
66004
  function writeDshAcpPatch(dshHome) {
65710
66005
  const pluginUrl = pathToFileURL(selfDistFile("agent/dsh-acp.js")).href;
65711
66006
  const dir = `${dshHome}-bili`;
@@ -65952,10 +66247,31 @@ function stopProxy(handle2) {
65952
66247
  } catch {
65953
66248
  }
65954
66249
  }
66250
+ function quoteWinToken(token) {
66251
+ if (!/\s/.test(token) || token.includes('"')) return token;
66252
+ return `"${token}"`;
66253
+ }
66254
+ function buildWindowsCommandLine(cmd, args) {
66255
+ return `"${[cmd, ...args].map(quoteWinToken).join(" ")}"`;
66256
+ }
66257
+ function planClientSpawn(cmd, args, env, platform = process.platform) {
66258
+ if (platform !== "win32") return { command: cmd, args: [...args] };
66259
+ const lower = cmd.toLowerCase();
66260
+ const base = cmd.slice(Math.max(cmd.lastIndexOf("/"), cmd.lastIndexOf("\\")) + 1);
66261
+ const needsCmd = lower.endsWith(".cmd") || lower.endsWith(".bat") || !path15.extname(base);
66262
+ if (!needsCmd) return { command: cmd, args: [...args] };
66263
+ const comspec = nonEmpty2(env.COMSPEC) ? env.COMSPEC : "cmd.exe";
66264
+ return {
66265
+ command: comspec,
66266
+ args: ["/d", "/s", "/c", buildWindowsCommandLine(cmd, args)],
66267
+ windowsVerbatimArguments: true
66268
+ };
66269
+ }
65955
66270
  function runClient(cmd, args, env, deps) {
65956
66271
  const spawnImpl = deps?.spawnImpl ?? spawn;
66272
+ const plan = planClientSpawn(cmd, args, env, deps?.platform);
65957
66273
  return new Promise((resolve, reject) => {
65958
- const child = spawnImpl(cmd, args, { stdio: "inherit", env, shell: process.platform === "win32" });
66274
+ const child = spawnImpl(plan.command, plan.args, { stdio: "inherit", env, windowsVerbatimArguments: plan.windowsVerbatimArguments });
65959
66275
  child.on?.("error", (...rest) => reject(rest[0]));
65960
66276
  child.on?.("exit", (...rest) => {
65961
66277
  const code = rest[0];
@@ -66136,7 +66452,6 @@ async function runLaunch(params, deps = {}) {
66136
66452
  const codexConversationId = injectMcp ? randomUUID5() : void 0;
66137
66453
  if (directUrl) {
66138
66454
  env = { ...process.env, BILLION_CONTEXT_PROXY: origin };
66139
- if (codexConversationId) clientArgs = [...buildCodexMcpArgs(origin, codexConversationId), ...clientArgs];
66140
66455
  } else {
66141
66456
  env = buildCodexEnv(origin, resolveCombinedCaPath(process.env), process.env);
66142
66457
  clientArgs = buildCodexArgs(origin, routes.httpRewrites, routes.httpsRewrites, clientArgs);
@@ -66151,7 +66466,17 @@ async function runLaunch(params, deps = {}) {
66151
66466
  clientArgs = [...budgetArgs, ...clientArgs];
66152
66467
  console.error(`bili: codex budget aligned \u2014 ${budgetArgs.slice(2).join(", ")} (model: ${config.codex?.model})`);
66153
66468
  }
66154
- if (injectMcp && codexConversationId) clientArgs = [...buildCodexMcpArgs(origin, codexConversationId), ...clientArgs];
66469
+ }
66470
+ if (injectMcp && codexConversationId) {
66471
+ const inj = prepareCodexMcpInjection({
66472
+ platform: process.platform,
66473
+ codexHome: resolveCodexHome(process.env),
66474
+ origin,
66475
+ conversationId: codexConversationId
66476
+ });
66477
+ if (inj.clientArgs.length > 0) clientArgs = [...inj.clientArgs, ...clientArgs];
66478
+ Object.assign(env, inj.envPatch);
66479
+ if (inj.warning) console.error(`bili: ${inj.warning}`);
66155
66480
  }
66156
66481
  } else {
66157
66482
  env = directUrl ? buildClaudePluginEnv(origin, true, process.env) : buildClaudeEnv(origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);