billion-context 0.1.75-pr.487.306 → 0.1.75-pr.489.307

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
@@ -49951,13 +49951,7 @@ function buildSession(parsed) {
49951
49951
  metadata: parsed.metadata ?? {},
49952
49952
  state: mergeState(parsed.state),
49953
49953
  createdAt: parsed.createdAt ?? Date.now(),
49954
- // #404: lastSeen reflects the on-disk savedAt (the last real
49955
- // activity), NOT the restore moment — a restart must not fabricate
49956
- // activity for every session (broke fallback=latest ties, panel
49957
- // freshness, and eviction ordering). Consumers that need "has this
49958
- // session been used since boot" read the restored flag.
49959
- lastSeen: parsed.savedAt ?? Date.now(),
49960
- restored: true,
49954
+ lastSeen: Date.now(),
49961
49955
  blockContents,
49962
49956
  lastMessages: Array.isArray(parsed.messages) ? parsed.messages : void 0,
49963
49957
  inFlight: 0,
@@ -50012,8 +50006,7 @@ async function initSessions() {
50012
50006
  await store.migrateLegacyIds();
50013
50007
  const loaded = await store.loadAll();
50014
50008
  if (loaded.size > MAX_SESSIONS) {
50015
- const freshness = (s3) => Math.max(s3.createdAt ?? 0, s3.lastSeen ?? 0);
50016
- const entries = [...loaded.entries()].sort((a, b2) => freshness(b2[1]) - freshness(a[1]));
50009
+ const entries = [...loaded.entries()].sort((a, b2) => (b2[1].createdAt ?? 0) - (a[1].createdAt ?? 0));
50017
50010
  for (const [id, s3] of entries) {
50018
50011
  if (sessions.size >= MAX_SESSIONS) break;
50019
50012
  sessions.set(id, s3);
@@ -50026,7 +50019,6 @@ function getSession(id, meta) {
50026
50019
  const existing = sessions.get(id);
50027
50020
  if (existing) {
50028
50021
  existing.lastSeen = Date.now();
50029
- existing.restored = false;
50030
50022
  if (meta?.protocol && !existing.meta.protocol) existing.meta.protocol = meta.protocol;
50031
50023
  if (meta?.upstreamOrigin && !existing.meta.upstreamOrigin) existing.meta.upstreamOrigin = meta.upstreamOrigin;
50032
50024
  if (meta?.label && !existing.meta.label) existing.meta.label = meta.label;
@@ -50036,7 +50028,6 @@ function getSession(id, meta) {
50036
50028
  const reloaded = store.loadSync(id, meta);
50037
50029
  if (reloaded) {
50038
50030
  reloaded.lastSeen = Date.now();
50039
- reloaded.restored = false;
50040
50031
  reloaded.persisted = true;
50041
50032
  sessions.set(id, reloaded);
50042
50033
  return reloaded;
@@ -50705,7 +50696,7 @@ function summaryPayload(protocol, model, system, content) {
50705
50696
  if (protocol === "openai") {
50706
50697
  return { model, max_tokens: MAX_SUMMARY_OUTPUT_TOKENS, messages: [{ role: "system", content: system }, { role: "user", content }], stream: false };
50707
50698
  }
50708
- return { model, max_output_tokens: MAX_SUMMARY_OUTPUT_TOKENS, instructions: system, input: [{ role: "user", content }], stream: false };
50699
+ return { model, max_output_tokens: MAX_SUMMARY_OUTPUT_TOKENS, instructions: system, input: [{ role: "user", content }], stream: false, store: false };
50709
50700
  }
50710
50701
  function extractSummaryText(protocol, json) {
50711
50702
  if (protocol === "anthropic") {
@@ -50771,7 +50762,7 @@ TASK: The conversation segment below (messages ${startRef}\u2013${endRef}) must
50771
50762
  var ABORTED_FAILURE = { kind: "aborted", detail: "the client disconnected during preflight compression" };
50772
50763
  async function preflightCompress(deps, messages) {
50773
50764
  const limit = deps.config.modelContextLimit;
50774
- const result = { compressedRanges: 0, savedTokens: 0, payloadEstimate: estimateCoreMessages(messages) };
50765
+ const result = { compressedRanges: 0, savedTokens: 0, payloadEstimate: estimateCoreMessages(messages) + (deps.imageFloor ?? 0) };
50775
50766
  if (limit <= 0) return result;
50776
50767
  const budget = Math.max(MIN_CHUNK_TOKENS, Math.floor(limit * CHUNK_FRACTION));
50777
50768
  const minChars = deps.config.compress.minCompressRange;
@@ -50791,8 +50782,8 @@ async function preflightCompress(deps, messages) {
50791
50782
  renderTags: "text-only"
50792
50783
  });
50793
50784
  deps.session.state = turn.state;
50794
- currentTokens = Math.max(deps.session.stats.lastInputTokens, estimateCoreMessages(turn.messages));
50795
- result.payloadEstimate = estimateCoreMessages(turn.messages);
50785
+ currentTokens = Math.max(deps.session.stats.lastInputTokens, estimateCoreMessages(turn.messages) + (deps.imageFloor ?? 0));
50786
+ result.payloadEstimate = estimateCoreMessages(turn.messages) + (deps.imageFloor ?? 0);
50796
50787
  if (startTokens < 0) startTokens = currentTokens;
50797
50788
  if (currentTokens < limit) break;
50798
50789
  const ranges = viableRanges(turn.nudge?.compressibleRanges ?? []);
@@ -50878,6 +50869,78 @@ async function preflightCompress(deps, messages) {
50878
50869
  return result;
50879
50870
  }
50880
50871
 
50872
+ // src/image-tokens.ts
50873
+ var REMOTE_IMAGE_TOKENS = 4096;
50874
+ function imageTokenCap() {
50875
+ const v2 = Number(process.env.BILI_IMAGE_TOKEN_CAP ?? "");
50876
+ return Number.isInteger(v2) && v2 > 0 ? v2 : 0;
50877
+ }
50878
+ function applyCap(cost) {
50879
+ const cap = imageTokenCap();
50880
+ return cap > 0 ? Math.min(cost, cap) : cost;
50881
+ }
50882
+ function costForUrl(url) {
50883
+ if (url.startsWith("data:")) {
50884
+ const i = url.indexOf("base64,");
50885
+ if (i >= 0) return applyCap(Math.ceil((url.length - i - "base64,".length) / 4));
50886
+ }
50887
+ return applyCap(REMOTE_IMAGE_TOKENS);
50888
+ }
50889
+ function isObj(v2) {
50890
+ return typeof v2 === "object" && v2 !== null;
50891
+ }
50892
+ function urlOf(v2) {
50893
+ if (typeof v2 === "string") return v2;
50894
+ if (isObj(v2) && typeof v2.url === "string") return v2.url;
50895
+ return void 0;
50896
+ }
50897
+ function imageTokensInParsedBody(protocol, body) {
50898
+ if (!isObj(body)) return 0;
50899
+ let total = 0;
50900
+ if (protocol === "responses") {
50901
+ const input = body.input;
50902
+ if (!Array.isArray(input)) return 0;
50903
+ for (const item of input) {
50904
+ if (!isObj(item) || !Array.isArray(item.content)) continue;
50905
+ for (const part of item.content) {
50906
+ if (!isObj(part) || part.type !== "input_image") continue;
50907
+ const url = urlOf(part.image_url);
50908
+ if (url) total += costForUrl(url);
50909
+ }
50910
+ }
50911
+ return total;
50912
+ }
50913
+ const messages = body.messages;
50914
+ if (!Array.isArray(messages)) return 0;
50915
+ for (const m2 of messages) {
50916
+ if (!isObj(m2) || !Array.isArray(m2.content)) continue;
50917
+ for (const part of m2.content) {
50918
+ if (!isObj(part)) continue;
50919
+ if (protocol === "openai") {
50920
+ if (part.type !== "image_url") continue;
50921
+ const url = urlOf(part.image_url);
50922
+ if (url) total += costForUrl(url);
50923
+ } else {
50924
+ if (part.type !== "image") continue;
50925
+ const src = part.source;
50926
+ if (isObj(src) && src.type === "base64" && typeof src.data === "string") total += applyCap(Math.ceil(src.data.length / 4));
50927
+ else if (isObj(src) && src.type === "url" && typeof src.url === "string") total += costForUrl(src.url);
50928
+ }
50929
+ }
50930
+ }
50931
+ return total;
50932
+ }
50933
+ function imageTokensInRawBody(protocol, raw) {
50934
+ const s3 = typeof raw === "string" ? raw : raw.toString("utf8");
50935
+ const probe = protocol === "responses" ? s3.includes("input_image") : protocol === "openai" ? s3.includes("image_url") : s3.includes('"type":"image"') || s3.includes('"type": "image"');
50936
+ if (!probe) return 0;
50937
+ try {
50938
+ return imageTokensInParsedBody(protocol, JSON.parse(s3));
50939
+ } catch {
50940
+ return 0;
50941
+ }
50942
+ }
50943
+
50881
50944
  // src/web/index.ts
50882
50945
  import { readFileSync as readFileSync3 } from "fs";
50883
50946
  import { dirname as dirname4, join as join3 } from "path";
@@ -51047,7 +51110,7 @@ async function saveProviders(){const button=byId("save-providers");busy(button,t
51047
51110
  async function saveCompress(){const button=byId("save-compress");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");try{const text=byId("compress-json").value.trim();const compress=text?JSON.parse(text):null;await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({compress})});toast("\u538B\u7F29\u53C2\u6570\u5DF2\u70ED\u66F4\u65B0")}catch(error){toast(String(error),true)}finally{busy(button,false)}}
51048
51111
  async function loadOverrides(){try{const data=await loadConfig();const providers=data.providers||{};const box=byId("upstream-overrides");const entries=Object.entries(providers);if(entries.length===0){box.innerHTML='<p class="status">\u6682\u65E0 Provider\u3002\u5728"\u9AD8\u7EA7\u8BBE\u7F6E"\u9875\u6DFB\u52A0 Provider \u540E\u53EF\u5728\u6B64\u6309 URL \u914D\u7F6E\u4EE3\u7406\u3002</p>';return}box.innerHTML='<table><thead><tr><th>Provider URL</th><th>\u4E0A\u6E38\u4EE3\u7406\uFF08\u7A7A=\u7EE7\u627F\u5168\u5C40\uFF09</th></tr></thead><tbody>'+entries.map(([url,route])=>'<tr><td class="mono">'+escapeHtml(url)+'</td><td><input class="mono override-proxy" data-url="'+escapeHtml(url)+'" value="'+escapeHtml((route&&route.proxy)||"")+'" placeholder="\u7EE7\u627F\u5168\u5C40"></td></tr>').join("")+'</tbody></table>'}catch(error){byId("upstream-overrides").textContent=String(error)}}
51049
51112
  async function saveOverrides(){const button=byId("save-overrides");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");try{const data=await loadConfig();const providers=data.providers||{};document.querySelectorAll(".override-proxy").forEach((input)=>{const url=input.dataset.url;if(!url)return;if(!providers[url])providers[url]={};const val=input.value.trim();if(val)providers[url].proxy=val;else delete providers[url].proxy});await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({providers})});await json("/__bili/config/reload",{method:"POST"});toast("\u6309 URL \u8986\u76D6\u5DF2\u70ED\u66F4\u65B0");await loadOverrides()}catch(error){toast(String(error),true)}finally{busy(button,false)}}
51050
- async function loadSessions(){try{const data=await json("/__bili/stats");const rows=(data.sessions||[]).map((item)=>"<tr><td>"+escapeHtml(item.title||"\u2014")+"</td><td>"+escapeHtml(item.protocol||"\u2014")+"</td><td class=mono>"+escapeHtml(item.label||"\u2014")+"</td><td>"+escapeHtml(item.requests)+"</td><td>"+escapeHtml(item.contextTokens)+"</td><td>"+escapeHtml(new Date(item.lastSeen).toLocaleString())+(item.restored?" <span class=muted>(\u6062\u590D\uFF0C\u5F00\u673A\u540E\u672A\u6D3B\u52A8)</span>":"")+"</td></tr>").join("");byId("sessions-body").innerHTML=rows||'<tr><td colspan="6">\u6682\u65E0\u4F1A\u8BDD</td></tr>'}catch(error){toast(String(error),true);throw error}}
51113
+ async function loadSessions(){try{const data=await json("/__bili/stats");const rows=(data.sessions||[]).map((item)=>"<tr><td>"+escapeHtml(item.title||"\u2014")+"</td><td>"+escapeHtml(item.protocol||"\u2014")+"</td><td class=mono>"+escapeHtml(item.label||"\u2014")+"</td><td>"+escapeHtml(item.requests)+"</td><td>"+escapeHtml(item.contextTokens)+"</td><td>"+escapeHtml(new Date(item.lastSeen).toLocaleString())+"</td></tr>").join("");byId("sessions-body").innerHTML=rows||'<tr><td colspan="6">\u6682\u65E0\u4F1A\u8BDD</td></tr>'}catch(error){toast(String(error),true);throw error}}
51051
51114
  async function refreshSessions(){const button=byId("refresh-sessions");busy(button,true,"\u5237\u65B0\u4E2D\u2026");try{await loadSessions();toast("\u4F1A\u8BDD\u5217\u8868\u5DF2\u5237\u65B0")}catch{}finally{busy(button,false)}}
51052
51115
  document.querySelectorAll(".copy-btn").forEach((btn)=>btn.addEventListener("click",async()=>{busy(btn,true,"\u590D\u5236\u4E2D\u2026");try{await navigator.clipboard.writeText(btn.dataset.copy||"");toast("\u5DF2\u590D\u5236")}catch(e){toast(String(e),true)}finally{busy(btn,false)}}));byId("save-upstream").addEventListener("click",saveUpstream);byId("test-upstream").addEventListener("click",testUpstream);byId("save-providers").addEventListener("click",saveProviders);byId("save-compress").addEventListener("click",saveCompress);byId("save-overrides").addEventListener("click",saveOverrides);byId("refresh-sessions").addEventListener("click",refreshSessions);
51053
51116
  Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),true));setInterval(()=>{if(byId("page-sessions").classList.contains("active"))loadSessions().catch(()=>{})},5000);
@@ -51057,7 +51120,7 @@ Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),tr
51057
51120
  var WEB_STYLES = `
51058
51121
  :root{--bg:#0f1115;--panel:#171a21;--panel2:#1e222c;--line:#2b313d;--text:#e7eaf0;--muted:#8f98a8;--blue:#6ea8fe;--green:#55c98b;--yellow:#e9b949;--red:#ef6b73;--radius:10px}
51059
51122
  *{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;min-height:100vh}.app{display:grid;grid-template-columns:220px 1fr;min-height:100vh}.sidebar{border-right:1px solid var(--line);padding:22px 14px;background:#12151b;position:sticky;top:0;height:100vh}.brand{font-size:18px;font-weight:700;padding:0 10px 22px}.brand span{color:var(--blue)}.version{display:block;color:var(--muted);font-size:11px;font-weight:400;margin-top:2px}.nav{display:grid;gap:4px}.nav button{appearance:none;border:0;background:transparent;color:var(--muted);text-align:left;padding:10px 12px;border-radius:7px;cursor:pointer;font:inherit}.nav button:hover,.nav button.active{background:var(--panel2);color:var(--text)}.main{padding:32px;max-width:1050px;width:100%}.page{display:none}.page.active{display:block}h1{font-size:23px;margin:0 0 4px}h2{font-size:15px;margin:0}.lead{color:var(--muted);margin:0 0 24px}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px;margin-bottom:14px}.card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.badge{border-radius:99px;padding:3px 9px;font-size:12px;background:var(--panel2);color:var(--muted)}.badge.ok{color:var(--green)}.badge.warn{color:var(--yellow)}.badge.err{color:var(--red)}.kv{display:grid;grid-template-columns:135px 1fr;gap:10px 14px;margin:0}.kv dt{color:var(--muted)}.kv dd{margin:0;word-break:break-all}.mono{font-family:"Cascadia Code",Consolas,monospace;font-size:12px}.actions{display:flex;gap:9px;flex-wrap:wrap;margin-top:18px}.btn{border:1px solid var(--line);background:var(--panel2);color:var(--text);border-radius:7px;padding:8px 13px;cursor:pointer;font:inherit}.btn:hover{border-color:#4b5668}.btn.primary{background:var(--blue);border-color:var(--blue);color:#0b1220;font-weight:600}.btn.danger{color:var(--red)}.btn:disabled{opacity:.55;cursor:wait}.field{display:grid;gap:6px;margin:12px 0}.field label{color:var(--muted);font-size:12px}input,textarea,select{width:100%;background:#101319;color:var(--text);border:1px solid var(--line);border-radius:7px;padding:9px 10px;font:inherit}textarea{min-height:250px;font-family:"Cascadia Code",Consolas,monospace;font-size:12px;resize:vertical}.modes{display:flex;gap:18px;margin:12px 0}.modes label{display:flex;gap:7px;align-items:center;color:var(--muted)}.modes input{width:auto}.notice{border-left:3px solid var(--yellow);padding:10px 12px;background:rgba(233,185,73,.08);color:#d8c185;margin-top:14px}.status{color:var(--muted);white-space:pre-wrap}.status.ok{color:var(--green)}.status.err{color:var(--red)}table{width:100%;border-collapse:collapse}th,td{text-align:left;border-bottom:1px solid var(--line);padding:9px 8px;font-size:12px}th{color:var(--muted);font-weight:500}.toast{position:fixed;right:24px;bottom:24px;background:var(--green);color:#07140d;padding:10px 15px;border-radius:8px;opacity:0;transform:translateY(8px);transition:.2s;pointer-events:none}.toast.show{opacity:1;transform:none}.toast.err{background:var(--red);color:#1b0608}
51060
- .section-title{font-size:17px;margin:28px 0 4px}.hint{color:var(--muted);margin:0 0 14px;font-size:13px}.muted{color:var(--muted);font-size:11px}.btn.small{padding:4px 10px;font-size:12px}.config-block{background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:10px 14px;margin:8px 0 12px;overflow-x:auto;font-size:13px}.config-block code{font-family:"Cascadia Code",Consolas,monospace;color:var(--text)}.fork-ribbon{position:fixed;top:0;right:0;background:#1a1a2e;color:#fff;padding:6px 16px;font-size:12px;text-decoration:none;border-radius:0 0 0 8px;z-index:100;opacity:.8;transition:.2s}.fork-ribbon:hover{opacity:1}
51123
+ .section-title{font-size:17px;margin:28px 0 4px}.hint{color:var(--muted);margin:0 0 14px;font-size:13px}.btn.small{padding:4px 10px;font-size:12px}.config-block{background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:10px 14px;margin:8px 0 12px;overflow-x:auto;font-size:13px}.config-block code{font-family:"Cascadia Code",Consolas,monospace;color:var(--text)}.fork-ribbon{position:fixed;top:0;right:0;background:#1a1a2e;color:#fff;padding:6px 16px;font-size:12px;text-decoration:none;border-radius:0 0 0 8px;z-index:100;opacity:.8;transition:.2s}.fork-ribbon:hover{opacity:1}
51061
51124
  @media(max-width:760px){.app{grid-template-columns:1fr}.sidebar{height:auto;position:static;border-right:0;border-bottom:1px solid var(--line)}.nav{display:flex;overflow:auto}.main{padding:20px}.grid{grid-template-columns:1fr}.kv{grid-template-columns:110px 1fr}}
51062
51125
  `;
51063
51126
 
@@ -54373,14 +54436,10 @@ function handlePluginStatus(conversationId2, res, fallbackLatest = false) {
54373
54436
  let session = entry ? peekSession(entry.sessionId) : void 0;
54374
54437
  let viaFallback = false;
54375
54438
  if ((!entry || !session) && fallbackLatest) {
54376
- const latest = listSessions().filter((s3) => s3.restored !== true).sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
54439
+ const latest = listSessions().filter((s3) => typeof s3.lastSeen === "number").sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
54377
54440
  if (latest) {
54378
54441
  session = latest;
54379
54442
  viaFallback = true;
54380
- } else {
54381
- res.writeHead(404, { "content-type": "application/json" });
54382
- res.end(JSON.stringify({ ok: false, error: "no session with activity since boot \u2014 issue a model request or pass the conversation id" }));
54383
- return;
54384
54443
  }
54385
54444
  }
54386
54445
  if (!session) {
@@ -57643,11 +57702,13 @@ function isPreflightFailFast(outcome) {
57643
57702
  async function preflightCompressIfNeeded(prepared, runPrepare, req, res, opts, core, config, model, route, affinity, log2, instanceId) {
57644
57703
  const session = prepared.session;
57645
57704
  const limit = config.modelContextLimit;
57646
- const payloadEstimate = estimateCoreMessages(prepared.processedMessages);
57705
+ const imageTokens = imageTokensInRawBody(prepared.protocol, prepared.body);
57706
+ const payloadEstimate = estimateCoreMessages(prepared.processedMessages) + imageTokens;
57647
57707
  const tokenCount = Math.max(session.stats.lastInputTokens, payloadEstimate);
57648
57708
  if (limit <= 0 || !model || tokenCount < limit) return prepared;
57649
57709
  const failFast = (status2, detail, retryable) => {
57650
- const message = `context ~${tokenCount} tokens exceeds the model window ${limit} (model=${model}) and preflight compression could not bring it under: ${detail}. The over-window payload was NOT forwarded.`;
57710
+ const imageNote = imageTokens >= limit ? ` Images alone account for ~${imageTokens} tokens (\u2265 window ${limit}); compression cannot remove them \u2014 shrink or remove the images, or raise the window.` : "";
57711
+ const message = `context ~${tokenCount} tokens exceeds the model window ${limit} (model=${model}) and preflight compression could not bring it under: ${detail}.` + imageNote + ` The over-window payload was NOT forwarded.`;
57651
57712
  log2("error", `[${session.id}] preflight fail-fast ${status2} (retryable=${retryable}): ${message}`);
57652
57713
  return { failFast: true, status: status2, message, retryable, respond: !res.writableEnded };
57653
57714
  };
@@ -57677,7 +57738,8 @@ async function preflightCompressIfNeeded(prepared, runPrepare, req, res, opts, c
57677
57738
  model,
57678
57739
  proxyUrl,
57679
57740
  signal: clientAbort.signal,
57680
- log: log2
57741
+ log: log2,
57742
+ imageFloor: imageTokens
57681
57743
  },
57682
57744
  prepared.originalMessages
57683
57745
  );
@@ -57846,9 +57908,12 @@ ${hdrText}
57846
57908
  const info = inspectContextOverflow(upstream.status, errBody.toString("utf8"));
57847
57909
  if (info.isOverflow) {
57848
57910
  let reqModel;
57911
+ let rejectedImageTokens = 0;
57849
57912
  try {
57850
57913
  const rawBody = typeof prepared.body === "string" ? prepared.body : prepared.body.toString("utf8");
57851
- reqModel = JSON.parse(rawBody).model;
57914
+ const parsedBody = JSON.parse(rawBody);
57915
+ reqModel = typeof parsedBody.model === "string" ? parsedBody.model : void 0;
57916
+ rejectedImageTokens = imageTokensInParsedBody(prepared.protocol, parsedBody);
57852
57917
  } catch {
57853
57918
  reqModel = void 0;
57854
57919
  }
@@ -57860,7 +57925,7 @@ ${hdrText}
57860
57925
  s3.metadata.learnedContextLimits = learnedMap;
57861
57926
  log2("warn", `[${s3.id}] upstream context overflow \u2014 learned real window ${info.window} for ${reqModel ?? "(unknown model)"} (was ${prev ?? "unset"}); arming emergency shrink`);
57862
57927
  } else {
57863
- const payloadEstimate = estimateCoreMessages(prepared.processedMessages);
57928
+ const payloadEstimate = estimateCoreMessages(prepared.processedMessages) + rejectedImageTokens;
57864
57929
  const prev = (reqModel ? learnedMap[reqModel] : void 0) ?? s3.metadata.learnedContextLimit;
57865
57930
  if (payloadEstimate >= 1e3 && (prev === void 0 || payloadEstimate < prev)) {
57866
57931
  if (reqModel) learnedMap[reqModel] = payloadEstimate;
@@ -58245,8 +58310,7 @@ function sendStats(res) {
58245
58310
  outputTokens: s3.stats.outputTokens,
58246
58311
  cacheSamples: s3.stats.cacheSamples,
58247
58312
  cacheHitPct: s3.stats.cacheSamples > 0 && s3.stats.inputTokens > 0 ? Math.round(s3.stats.cachedTokens / s3.stats.inputTokens * 100) : null,
58248
- lastSeen: new Date(s3.lastSeen).toISOString(),
58249
- restored: s3.restored === true
58313
+ lastSeen: new Date(s3.lastSeen).toISOString()
58250
58314
  }));
58251
58315
  res.writeHead(200, { "content-type": "application/json" });
58252
58316
  res.end(JSON.stringify({ sessions: sessions2 }, null, 2));