billion-context 0.1.56 → 0.1.57

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
@@ -43649,7 +43649,7 @@ function formatRanges(compressible, protectedRanges) {
43649
43649
  if (compressible.length === 0 && protectedRanges.length === 0) {
43650
43650
  return "[No specific ranges detected \u2014 compress any consumed content.]";
43651
43651
  }
43652
- const refNum2 = (ref) => {
43652
+ const refNum3 = (ref) => {
43653
43653
  const m2 = ref.match(/\d+/);
43654
43654
  return m2 ? parseInt(m2[0], 10) : 0;
43655
43655
  };
@@ -43658,8 +43658,8 @@ function formatRanges(compressible, protectedRanges) {
43658
43658
  entries.push({
43659
43659
  startRef: r.startRef,
43660
43660
  endRef: r.endRef,
43661
- startNum: refNum2(r.startRef),
43662
- endNum: refNum2(r.endRef),
43661
+ startNum: refNum3(r.startRef),
43662
+ endNum: refNum3(r.endRef),
43663
43663
  count: r.count,
43664
43664
  tokens: r.tokens,
43665
43665
  toolPct: r.toolPct,
@@ -43676,8 +43676,8 @@ function formatRanges(compressible, protectedRanges) {
43676
43676
  entries.push({
43677
43677
  startRef: r.startRef,
43678
43678
  endRef: r.endRef,
43679
- startNum: refNum2(r.startRef),
43680
- endNum: refNum2(r.endRef),
43679
+ startNum: refNum3(r.startRef),
43680
+ endNum: refNum3(r.endRef),
43681
43681
  count: r.count,
43682
43682
  tokens: r.tokens,
43683
43683
  toolPct: 0,
@@ -46427,13 +46427,13 @@ function renderUncompressedRanges(visible) {
46427
46427
  lines.push(" (no uncompressed messages)");
46428
46428
  return lines.join("\n");
46429
46429
  }
46430
- const refNum2 = (ref) => {
46430
+ const refNum22 = (ref) => {
46431
46431
  const m2 = ref.match(/\d+/);
46432
46432
  return m2 ? parseInt(m2[0], 10) : 0;
46433
46433
  };
46434
46434
  const merged = [];
46435
46435
  for (const m2 of visible) {
46436
- const num3 = refNum2(m2.ref);
46436
+ const num3 = refNum22(m2.ref);
46437
46437
  const last = merged[merged.length - 1];
46438
46438
  if (last && num3 === last.startNum + last.count) {
46439
46439
  last.endRef = m2.ref;
@@ -49919,6 +49919,213 @@ function rewriteJsonResponse(body, ctx) {
49919
49919
  return body;
49920
49920
  }
49921
49921
 
49922
+ // src/preflight.ts
49923
+ var MAX_PREFLIGHT_ROUNDS = 8;
49924
+ var CHUNK_FRACTION = 0.6;
49925
+ var MIN_CHUNK_TOKENS = 2e3;
49926
+ var MIN_SUMMARY_CHARS = 50;
49927
+ var MAX_SUMMARY_OUTPUT_TOKENS = 8192;
49928
+ function refMaps(messages, state) {
49929
+ const refToIdx = /* @__PURE__ */ new Map();
49930
+ const idxToRef = /* @__PURE__ */ new Map();
49931
+ const byRaw = state.messageRefs?.byRaw ?? {};
49932
+ messages.forEach((m2, i) => {
49933
+ const ref = byRaw[m2.id];
49934
+ if (!ref) return;
49935
+ if (!refToIdx.has(ref)) refToIdx.set(ref, i);
49936
+ idxToRef.set(i, ref);
49937
+ });
49938
+ return { refToIdx, idxToRef };
49939
+ }
49940
+ function refNum2(ref) {
49941
+ return Number(ref.replace(/\D/g, "")) || 0;
49942
+ }
49943
+ function estimateCoreMessages(messages) {
49944
+ let tokens = 0;
49945
+ for (const m2 of messages) tokens += defaultCountTokens(m2.text ?? "");
49946
+ return tokens;
49947
+ }
49948
+ function rangeChars2(messages, startIdx, endIdx) {
49949
+ let chars = 0;
49950
+ for (let i = startIdx; i <= endIdx && i < messages.length; i++) {
49951
+ chars += (messages[i].text ?? "").length;
49952
+ }
49953
+ return chars;
49954
+ }
49955
+ function renderRange(messages, startIdx, endIdx) {
49956
+ const parts = [];
49957
+ for (let i = startIdx; i <= endIdx && i < messages.length; i++) {
49958
+ const m2 = messages[i];
49959
+ const text = (m2.text ?? "").trim();
49960
+ if (!text) continue;
49961
+ const label = m2.contentType === "tool-call" ? `assistant tool-call ${m2.toolName ?? "?"}` : m2.contentType === "tool-result" ? `tool result ${m2.toolName ?? "?"}` : m2.contentType === "reasoning" ? "assistant reasoning" : m2.role;
49962
+ parts.push(`[${label}]
49963
+ ${text}`);
49964
+ }
49965
+ return parts.join("\n\n");
49966
+ }
49967
+ function splitChunks(messages, startIdx, endIdx, budgetTokens) {
49968
+ const chunks = [];
49969
+ let cur = startIdx;
49970
+ while (cur <= endIdx) {
49971
+ let tokens = 0;
49972
+ let last = cur;
49973
+ for (let i = cur; i <= endIdx; i++) {
49974
+ const t = defaultCountTokens(messages[i].text ?? "");
49975
+ if (tokens + t > budgetTokens && i > cur) break;
49976
+ tokens += t;
49977
+ last = i;
49978
+ }
49979
+ chunks.push([cur, last]);
49980
+ cur = last + 1;
49981
+ }
49982
+ return chunks;
49983
+ }
49984
+ function summaryPayload(protocol, model, system, content) {
49985
+ if (protocol === "anthropic") {
49986
+ return { model, max_tokens: MAX_SUMMARY_OUTPUT_TOKENS, system, messages: [{ role: "user", content }], stream: false };
49987
+ }
49988
+ if (protocol === "openai") {
49989
+ return { model, max_tokens: MAX_SUMMARY_OUTPUT_TOKENS, messages: [{ role: "system", content: system }, { role: "user", content }], stream: false };
49990
+ }
49991
+ return { model, max_output_tokens: MAX_SUMMARY_OUTPUT_TOKENS, instructions: system, input: [{ role: "user", content }], stream: false };
49992
+ }
49993
+ function extractSummaryText(protocol, json) {
49994
+ if (protocol === "anthropic") {
49995
+ const content = json.content;
49996
+ if (!Array.isArray(content)) return "";
49997
+ return content.map((c) => c && typeof c === "object" && c.type === "text" && typeof c.text === "string" ? c.text : "").join("");
49998
+ }
49999
+ if (protocol === "openai") {
50000
+ const choices = json.choices;
50001
+ if (!Array.isArray(choices) || choices.length === 0) return "";
50002
+ const msg = choices[0].message;
50003
+ if (!msg || typeof msg !== "object") return "";
50004
+ const c = msg.content;
50005
+ if (typeof c === "string") return c;
50006
+ if (Array.isArray(c)) {
50007
+ return c.map((p2) => p2 && typeof p2 === "object" && typeof p2.text === "string" ? p2.text : "").join("");
50008
+ }
50009
+ return "";
50010
+ }
50011
+ if (typeof json.output_text === "string") return json.output_text;
50012
+ const output = json.output;
50013
+ if (!Array.isArray(output)) return "";
50014
+ return output.map((o) => o && typeof o === "object" ? o.content : void 0).filter((c) => Array.isArray(c)).flatMap((c) => c).map((p2) => p2 && typeof p2 === "object" && typeof p2.text === "string" ? p2.text : "").join("");
50015
+ }
50016
+ async function summarizeRange(deps, content, startRef, endRef) {
50017
+ const system = buildCompressSystemPrompt(deps.prompts) + `
50018
+
50019
+ 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.`;
50020
+ const { response, clearTimer } = await fetchWithRetry(
50021
+ deps.url,
50022
+ {
50023
+ method: "POST",
50024
+ headers: { "content-type": "application/json", ...deps.headers },
50025
+ body: JSON.stringify(summaryPayload(deps.protocol, deps.model, system, content)),
50026
+ dispatcher: proxyDispatcher(deps.proxyUrl)
50027
+ },
50028
+ void 0,
50029
+ deps.signal,
50030
+ (info) => deps.log("warn", `[preflight] summary attempt ${info.attempt} got HTTP ${info.status}; retrying in ${info.delayMs}ms`)
50031
+ );
50032
+ try {
50033
+ const text = await response.text();
50034
+ let json;
50035
+ try {
50036
+ json = JSON.parse(text);
50037
+ } catch {
50038
+ deps.log("warn", `[preflight] summary response was not JSON: ${text.slice(0, 200)}`);
50039
+ return null;
50040
+ }
50041
+ if (!json || typeof json !== "object") return null;
50042
+ const summary = extractSummaryText(deps.protocol, json).trim();
50043
+ if (summary.length < MIN_SUMMARY_CHARS) {
50044
+ deps.log("warn", `[preflight] summary too short (${summary.length} chars); skipping range`);
50045
+ return null;
50046
+ }
50047
+ return summary;
50048
+ } finally {
50049
+ clearTimer();
50050
+ }
50051
+ }
50052
+ async function preflightCompress(deps, messages) {
50053
+ const limit = deps.config.modelContextLimit;
50054
+ const result = { compressedRanges: 0, savedTokens: 0 };
50055
+ if (limit <= 0) return result;
50056
+ const budget = Math.max(MIN_CHUNK_TOKENS, Math.floor(limit * CHUNK_FRACTION));
50057
+ const minChars = deps.config.compress.minCompressRange;
50058
+ let currentTokens = deps.session.stats.lastInputTokens;
50059
+ let startTokens = -1;
50060
+ for (let round = 0; round < MAX_PREFLIGHT_ROUNDS; round++) {
50061
+ if (deps.signal?.aborted) break;
50062
+ const turn = deps.core.processTurn({
50063
+ messages,
50064
+ state: deps.session.state,
50065
+ config: deps.config,
50066
+ tokenCount: currentTokens,
50067
+ renderTags: "text-only"
50068
+ });
50069
+ deps.session.state = turn.state;
50070
+ currentTokens = Math.max(deps.session.stats.lastInputTokens, estimateCoreMessages(turn.messages));
50071
+ if (startTokens < 0) startTokens = currentTokens;
50072
+ if (currentTokens < limit) break;
50073
+ const ranges = viableRanges(turn.nudge?.compressibleRanges ?? []);
50074
+ if (ranges.length === 0) break;
50075
+ const range = [...ranges].sort((a, b2) => refNum2(a.startRef) - refNum2(b2.startRef))[0];
50076
+ const { refToIdx } = refMaps(messages, deps.session.state);
50077
+ const startIdx = refToIdx.get(range.startRef);
50078
+ const endIdx = refToIdx.get(range.endRef);
50079
+ if (startIdx === void 0 || endIdx === void 0 || startIdx > endIdx) break;
50080
+ let appliedThisRound = 0;
50081
+ for (const [cs2, ce2] of splitChunks(messages, startIdx, endIdx, budget)) {
50082
+ if (currentTokens < limit) break;
50083
+ if (deps.signal?.aborted) break;
50084
+ const maps = refMaps(messages, deps.session.state);
50085
+ const startRef = maps.idxToRef.get(cs2);
50086
+ const endRef = maps.idxToRef.get(ce2);
50087
+ if (!startRef || !endRef) continue;
50088
+ if (rangeChars2(messages, cs2, ce2) < minChars) continue;
50089
+ const content = renderRange(messages, cs2, ce2);
50090
+ if (content.length === 0) continue;
50091
+ let summary;
50092
+ try {
50093
+ summary = await summarizeRange(deps, content, startRef, endRef);
50094
+ } catch (err2) {
50095
+ if (err2 instanceof UpstreamHttpError) {
50096
+ deps.log("warn", `[preflight] summarization failed: HTTP ${err2.status} ${err2.body.slice(0, 200)}`);
50097
+ } else {
50098
+ deps.log("warn", `[preflight] summarization failed: ${String(err2)}`);
50099
+ }
50100
+ break;
50101
+ }
50102
+ if (!summary) continue;
50103
+ const ctx = {
50104
+ core: deps.core,
50105
+ config: deps.config,
50106
+ messages,
50107
+ session: deps.session,
50108
+ log: (msg) => deps.log("info", msg)
50109
+ };
50110
+ const creditBefore = deps.session.stats.compressCreditTokens;
50111
+ const applied = applyRanges(parseCompressInput({ content: [{ startId: startRef, endId: endRef, summary, topic: "preflight overflow compress" }] }), ctx);
50112
+ if (applied.startsWith("[Compression FAILED")) {
50113
+ deps.log("warn", `[preflight] ${applied}`);
50114
+ continue;
50115
+ }
50116
+ const compressed = deps.session.stats.compressCreditTokens - creditBefore;
50117
+ currentTokens = Math.max(0, currentTokens - compressed + defaultCountTokens(summary));
50118
+ deps.session.stats.lastInputTokens += defaultCountTokens(summary);
50119
+ appliedThisRound += 1;
50120
+ result.compressedRanges += 1;
50121
+ }
50122
+ if (appliedThisRound === 0) break;
50123
+ }
50124
+ if (result.compressedRanges > 0) deps.session.stats.lastInputTokens = currentTokens;
50125
+ result.savedTokens = Math.max(0, startTokens - currentTokens);
50126
+ return result;
50127
+ }
50128
+
49922
50129
  // src/web/index.ts
49923
50130
  import { readFileSync as readFileSync3 } from "fs";
49924
50131
  import { dirname as dirname4, join as join3 } from "path";
@@ -50628,6 +50835,20 @@ function shouldReserveOutputHeadroom(protocol) {
50628
50835
 
50629
50836
  // src/loop/adapter-responses.ts
50630
50837
  var RESPONSES_ITEM_ID_MAX = 64;
50838
+ function normalizeResponsesMessageItems(input) {
50839
+ if (!Array.isArray(input)) return 0;
50840
+ let typed = 0;
50841
+ for (const item of input) {
50842
+ if (typeof item !== "object" || item === null) continue;
50843
+ const rec = item;
50844
+ if (rec["type"] !== void 0) continue;
50845
+ if (rec["role"] !== "user" && rec["role"] !== "assistant") continue;
50846
+ if (rec["content"] === void 0) continue;
50847
+ rec["type"] = "message";
50848
+ typed++;
50849
+ }
50850
+ return typed;
50851
+ }
50631
50852
  function sanitizeResponsesInputIds(input) {
50632
50853
  if (!Array.isArray(input)) return;
50633
50854
  for (const item of input) {
@@ -52469,7 +52690,10 @@ function takePendingPluginRegister() {
52469
52690
  var registeredIds = /* @__PURE__ */ new Map();
52470
52691
  function consumePluginRegisterFor(conversationId2) {
52471
52692
  const agent = registeredIds.get(conversationId2);
52472
- if (agent !== void 0) registeredIds.delete(conversationId2);
52693
+ if (agent !== void 0) {
52694
+ registeredIds.delete(conversationId2);
52695
+ registeredIds.set(conversationId2, agent);
52696
+ }
52473
52697
  return agent;
52474
52698
  }
52475
52699
  function handlePluginRegister(payload, res) {
@@ -54789,17 +55013,23 @@ ${bodyBuffer.toString("utf8")}`);
54789
55013
  conversationIdentityResponses(parsed, convHeader),
54790
55014
  parsed
54791
55015
  ) : void 0;
54792
- const conversation = protocol === "anthropic" ? conversationSignalAnthropic(parsed, convHeader) : protocol === "openai" ? conversationSignalOpenai(parsed, convHeader) : subagentNamespace(
55016
+ const openaiSignal = protocol === "openai" ? conversationSignalOpenai(parsed, convHeader) : "";
55017
+ const openaiIdentity = protocol === "openai" ? preferPromptCacheKeyIdentity(
55018
+ convHeader ? { value: openaiSignal, source: "header", clientProvided: true } : { value: openaiSignal, source: "content-fingerprint", clientProvided: false },
55019
+ parsed
55020
+ ) : void 0;
55021
+ const conversation = protocol === "anthropic" ? conversationSignalAnthropic(parsed, convHeader) : protocol === "openai" ? openaiIdentity?.value ?? openaiSignal : subagentNamespace(
54793
55022
  responsesIdentity?.value ?? conversationSignalResponses(parsed, convHeader),
54794
55023
  parsed.instructions
54795
55024
  );
54796
55025
  const sessionId = deriveSessionId(req.headers, protocol, upstreamOrigin, conversation);
54797
- const affinity = affinityToken(responsesIdentity ?? {
55026
+ const bodyIdentity = responsesIdentity ?? openaiIdentity;
55027
+ const affinity = affinityToken(bodyIdentity ?? {
54798
55028
  value: clientConv ?? conversation,
54799
55029
  source: clientConv ? "header" : "generated",
54800
55030
  clientProvided: !!clientConv
54801
55031
  });
54802
- const clientLabel = responsesIdentity?.clientProvided ? responsesIdentity.value : clientConversationHeader(req.headers);
55032
+ const clientLabel = bodyIdentity?.clientProvided ? bodyIdentity.value : clientConversationHeader(req.headers);
54803
55033
  const session = getSession(sessionId, { protocol, upstreamOrigin, label: clientLabel ?? void 0 });
54804
55034
  if (!pluginAgent) {
54805
55035
  const identityAgent = consumePluginRegisterFor(clientConv ?? conversation);
@@ -54822,7 +55052,7 @@ ${bodyBuffer.toString("utf8")}`);
54822
55052
  session.metadata.effectiveContextLimit = reqConfig.modelContextLimit;
54823
55053
  recordPluginSession(pluginConversation ?? conversation, session.id);
54824
55054
  }
54825
- if (protocol === "responses") {
55055
+ if (protocol === "responses" || protocol === "openai") {
54826
55056
  const pck = parsed.prompt_cache_key;
54827
55057
  if (typeof pck === "string" && pck.trim().length > 0) {
54828
55058
  recordPluginSession(pck.trim(), session.id);
@@ -54847,7 +55077,23 @@ ${bodyBuffer.toString("utf8")}`);
54847
55077
  acquireInFlight(session);
54848
55078
  try {
54849
55079
  await withSessionLock(session, async () => {
54850
- prepared = countTokens ? prepareCountTokens(parsed, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : responsesCompact ? prepareResponsesCompact(bodyBuffer, parsed, session) : prepareResponses(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode);
55080
+ const runPrepare = () => countTokens ? prepareCountTokens(parsed, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : responsesCompact ? prepareResponsesCompact(bodyBuffer, parsed, session) : prepareResponses(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode);
55081
+ prepared = runPrepare();
55082
+ if (!countTokens && !responsesCompact) {
55083
+ prepared = await preflightCompressIfNeeded(
55084
+ prepared,
55085
+ runPrepare,
55086
+ req,
55087
+ res,
55088
+ opts,
55089
+ core,
55090
+ reqConfig,
55091
+ parsed.model,
55092
+ route,
55093
+ affinity,
55094
+ log2
55095
+ );
55096
+ }
54851
55097
  await forward(req, res, opts, prepared.body, prepared, core, reqConfig, log2, route, affinity);
54852
55098
  if (prepared) {
54853
55099
  rememberPluginMessages(sessionId, prepared.processedMessages, prepared.originalMessages, prepared.nudge);
@@ -54865,8 +55111,15 @@ ${bodyBuffer.toString("utf8")}`);
54865
55111
  }
54866
55112
  }
54867
55113
  var ACP_TAG_MARK = "<acp ";
54868
- function stripKernelSummaries(messages) {
54869
- return messages.filter((m2) => !(m2.id ?? "").startsWith("acp_summary_"));
55114
+ function stripKernelSummaries(messages, state) {
55115
+ const carried = /* @__PURE__ */ new Set();
55116
+ for (const b2 of state.blocks) {
55117
+ if (!b2.active || !b2.compressCallId) continue;
55118
+ if (messages.some((m2) => m2.contentType === "tool-call" && m2.toolCallId === b2.compressCallId)) {
55119
+ carried.add(`acp_summary_${b2.blockId}`);
55120
+ }
55121
+ }
55122
+ return messages.filter((m2) => !(m2.id ?? "").startsWith("acp_summary_") || !carried.has(m2.id));
54870
55123
  }
54871
55124
  function diagTagSummary(messages, sessionId, strategy) {
54872
55125
  let textTagged = 0;
@@ -54921,7 +55174,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
54921
55174
  }
54922
55175
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
54923
55176
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
54924
- processedMessages = stripKernelSummaries(turn.messages);
55177
+ processedMessages = stripKernelSummaries(turn.messages, turn.state);
54925
55178
  reapOrphanBlocks(session, msgs, deactivateBlock);
54926
55179
  rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
54927
55180
  systemOut = injectSystem(parsed, opts, prompts);
@@ -54977,7 +55230,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
54977
55230
  }
54978
55231
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
54979
55232
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
54980
- processedMessages = stripKernelSummaries(turn.messages);
55233
+ processedMessages = stripKernelSummaries(turn.messages, turn.state);
54981
55234
  reapOrphanBlocks(session, msgs, deactivateBlock);
54982
55235
  rebuiltMessages = coreToOpenai(processedMessages);
54983
55236
  const sysParts = [];
@@ -55021,6 +55274,10 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
55021
55274
  let responsesProjection;
55022
55275
  let rebuiltInput = parsed.input;
55023
55276
  let toolsOut = parsed.tools;
55277
+ const typedItems = normalizeResponsesMessageItems(parsed.input);
55278
+ if (typedItems > 0) {
55279
+ log2("info", `[${sessionId}] stamped type:"message" on ${typedItems} type-less input item(s) before projection (omp wire form)`);
55280
+ }
55024
55281
  sanitizeResponsesInputIds(parsed.input);
55025
55282
  const droppedEmpty = dropWhitespaceResponsesMessages(parsed.input);
55026
55283
  if (droppedEmpty > 0) {
@@ -55050,7 +55307,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
55050
55307
  }
55051
55308
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
55052
55309
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
55053
- processedMessages = stripKernelSummaries(turn.messages);
55310
+ processedMessages = stripKernelSummaries(turn.messages, turn.state);
55054
55311
  reapOrphanBlocks(session, msgs, deactivateBlock);
55055
55312
  rebuiltInput = patchResponsesInput(projection, processedMessages);
55056
55313
  if (shouldInject && !process.env.ACP_NO_COMPRESS_PROMPT) {
@@ -55121,7 +55378,7 @@ function prepareCountTokens(parsed, core, config, log2, session) {
55121
55378
  try {
55122
55379
  const { msgs, cacheControls } = anthropicToCore(parsed);
55123
55380
  const turn = core.processTurn({ messages: msgs, state: session.state, config, tokenCount: session.stats.lastInputTokens, renderTags: "text-only" });
55124
- const stripped = stripKernelSummaries(turn.messages);
55381
+ const stripped = stripKernelSummaries(turn.messages, turn.state);
55125
55382
  const rebuiltMessages = coreToAnthropic(stripped, cacheControls);
55126
55383
  log2("info", `[${sessionId}] count_tokens pruned: ${msgs.length} \u2192 ${stripped.length} msgs`);
55127
55384
  return {
@@ -55208,11 +55465,71 @@ function injectResponsesTool(tools, toolsToAdd = ACP_TOOLS_RESPONSES) {
55208
55465
  const additions = toolsToAdd.filter((t) => !present.has(t.name));
55209
55466
  return [...tools, ...additions];
55210
55467
  }
55211
- async function forward(req, res, opts, body, prepared, core, config, log2, route, affinity) {
55468
+ function buildForwardTarget(req, opts, route, affinity) {
55212
55469
  const reqUrl = req.url ?? "";
55213
55470
  const isAbsoluteUrl = /^https?:\/\//i.test(reqUrl);
55214
55471
  const rewritten = route ? route.rewrittenUrl : isAbsoluteUrl ? reqUrl : opts.upstream + reqUrl;
55215
55472
  const upstreamUrl = rewritten.replace(/^mitm:\/\//, "https://");
55473
+ const headers = {};
55474
+ const reqConnNamed = connectionNamedHeaders(req.headers["connection"]);
55475
+ for (const [k2, v2] of Object.entries(req.headers)) {
55476
+ const lower = k2.toLowerCase();
55477
+ if (UPSTREAM_HOP_HEADERS.has(lower) || reqConnNamed.has(lower) || v2 === void 0) continue;
55478
+ headers[k2] = Array.isArray(v2) ? v2.join(", ") : v2;
55479
+ }
55480
+ headers["host"] = new URL(upstreamUrl).host;
55481
+ const betaKey = Object.keys(headers).find((h) => h.toLowerCase() === "x-codex-beta-features");
55482
+ if (betaKey) {
55483
+ const kept = headers[betaKey].split(",").map((s3) => s3.trim()).filter((f2) => f2 && f2 !== "remote_compaction_v2");
55484
+ if (kept.length > 0) headers[betaKey] = kept.join(",");
55485
+ else delete headers[betaKey];
55486
+ }
55487
+ if (affinity && !clientConversationHeader(req.headers)) {
55488
+ headers["x-session-id"] = affinity;
55489
+ }
55490
+ const proxyUrl = resolveProxy(opts.routes, opts.proxy, route?.rewrittenUrl ?? upstreamUrl, opts.proxyFallback);
55491
+ return { upstreamUrl, headers, proxyUrl };
55492
+ }
55493
+ async function preflightCompressIfNeeded(prepared, runPrepare, req, res, opts, core, config, model, route, affinity, log2) {
55494
+ const session = prepared.session;
55495
+ const limit = config.modelContextLimit;
55496
+ const tokenCount = Math.max(session.stats.lastInputTokens, estimateCoreMessages(prepared.processedMessages));
55497
+ if (limit <= 0 || !model || tokenCount < limit) return prepared;
55498
+ if ((prepared.nudge?.compressibleRanges ?? []).length === 0) return prepared;
55499
+ log2("warn", `[${session.id}] context ${tokenCount} tokens exceeds model window ${limit} (model=${model}); preflight compressing before forward`);
55500
+ const { upstreamUrl, headers, proxyUrl } = buildForwardTarget(req, opts, route, affinity);
55501
+ const clientAbort = new AbortController();
55502
+ res.on("close", () => {
55503
+ if (!res.writableEnded) clientAbort.abort();
55504
+ });
55505
+ const started = Date.now();
55506
+ const result = await preflightCompress(
55507
+ {
55508
+ core,
55509
+ session,
55510
+ config,
55511
+ prompts: prepared.prompts ?? defaultPrompts,
55512
+ protocol: prepared.protocol,
55513
+ url: upstreamUrl,
55514
+ headers,
55515
+ model,
55516
+ proxyUrl,
55517
+ signal: clientAbort.signal,
55518
+ log: log2
55519
+ },
55520
+ prepared.originalMessages
55521
+ );
55522
+ if (result.compressedRanges > 0) {
55523
+ log2("info", `[${session.id}] preflight compressed ${result.compressedRanges} range(s), ~${result.savedTokens} tokens saved (${tokenCount} \u2192 ${session.stats.lastInputTokens}) in ${Date.now() - started}ms; rebuilding payload`);
55524
+ const rebuilt = runPrepare();
55525
+ session.stats.requests -= 1;
55526
+ return rebuilt;
55527
+ }
55528
+ log2("warn", `[${session.id}] preflight could not compress enough (~${result.savedTokens} tokens saved); forwarding as-is`);
55529
+ return prepared;
55530
+ }
55531
+ async function forward(req, res, opts, body, prepared, core, config, log2, route, affinity) {
55532
+ const { upstreamUrl, headers, proxyUrl } = buildForwardTarget(req, opts, route, affinity);
55216
55533
  log2("info", `forward ${req.method} \u2192 ${upstreamUrl}`);
55217
55534
  if (process.env.ACP_DEBUG && prepared) {
55218
55535
  const sid = prepared.session.id;
@@ -55254,24 +55571,6 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
55254
55571
  } catch {
55255
55572
  }
55256
55573
  }
55257
- const headers = {};
55258
- const reqConnNamed = connectionNamedHeaders(req.headers["connection"]);
55259
- for (const [k2, v2] of Object.entries(req.headers)) {
55260
- const lower = k2.toLowerCase();
55261
- if (UPSTREAM_HOP_HEADERS.has(lower) || reqConnNamed.has(lower) || v2 === void 0) continue;
55262
- headers[k2] = Array.isArray(v2) ? v2.join(", ") : v2;
55263
- }
55264
- headers["host"] = new URL(upstreamUrl).host;
55265
- const betaKey = Object.keys(headers).find((h) => h.toLowerCase() === "x-codex-beta-features");
55266
- if (betaKey) {
55267
- const kept = headers[betaKey].split(",").map((s3) => s3.trim()).filter((f2) => f2 && f2 !== "remote_compaction_v2");
55268
- if (kept.length > 0) headers[betaKey] = kept.join(",");
55269
- else delete headers[betaKey];
55270
- }
55271
- if (affinity && !clientConversationHeader(req.headers)) {
55272
- headers["x-session-id"] = affinity;
55273
- }
55274
- const proxyUrl = resolveProxy(opts.routes, opts.proxy, route?.rewrittenUrl ?? upstreamUrl, opts.proxyFallback);
55275
55574
  if (opts.debug) {
55276
55575
  const hdrLog = {};
55277
55576
  for (const [hk, hv] of Object.entries(headers)) {