billion-context 0.1.42 → 0.1.43

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
@@ -1141,14 +1141,14 @@ var require_util = __commonJS({
1141
1141
  }
1142
1142
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
1143
1143
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
1144
- let path11 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
1144
+ let path12 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
1145
1145
  if (origin[origin.length - 1] === "/") {
1146
1146
  origin = origin.slice(0, origin.length - 1);
1147
1147
  }
1148
- if (path11 && path11[0] !== "/") {
1149
- path11 = `/${path11}`;
1148
+ if (path12 && path12[0] !== "/") {
1149
+ path12 = `/${path12}`;
1150
1150
  }
1151
- return new URL(`${origin}${path11}`);
1151
+ return new URL(`${origin}${path12}`);
1152
1152
  }
1153
1153
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
1154
1154
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -1969,9 +1969,9 @@ var require_diagnostics = __commonJS({
1969
1969
  "undici:client:sendHeaders",
1970
1970
  (evt) => {
1971
1971
  const {
1972
- request: { method, path: path11, origin }
1972
+ request: { method, path: path12, origin }
1973
1973
  } = evt;
1974
- debugLog("sending request to %s %s%s", method, origin, path11);
1974
+ debugLog("sending request to %s %s%s", method, origin, path12);
1975
1975
  }
1976
1976
  );
1977
1977
  }
@@ -1989,14 +1989,14 @@ var require_diagnostics = __commonJS({
1989
1989
  "undici:request:headers",
1990
1990
  (evt) => {
1991
1991
  const {
1992
- request: { method, path: path11, origin },
1992
+ request: { method, path: path12, origin },
1993
1993
  response: { statusCode }
1994
1994
  } = evt;
1995
1995
  debugLog(
1996
1996
  "received response to %s %s%s - HTTP %d",
1997
1997
  method,
1998
1998
  origin,
1999
- path11,
1999
+ path12,
2000
2000
  statusCode
2001
2001
  );
2002
2002
  }
@@ -2005,23 +2005,23 @@ var require_diagnostics = __commonJS({
2005
2005
  "undici:request:trailers",
2006
2006
  (evt) => {
2007
2007
  const {
2008
- request: { method, path: path11, origin }
2008
+ request: { method, path: path12, origin }
2009
2009
  } = evt;
2010
- debugLog("trailers received from %s %s%s", method, origin, path11);
2010
+ debugLog("trailers received from %s %s%s", method, origin, path12);
2011
2011
  }
2012
2012
  );
2013
2013
  diagnosticsChannel.subscribe(
2014
2014
  "undici:request:error",
2015
2015
  (evt) => {
2016
2016
  const {
2017
- request: { method, path: path11, origin },
2017
+ request: { method, path: path12, origin },
2018
2018
  error
2019
2019
  } = evt;
2020
2020
  debugLog(
2021
2021
  "request to %s %s%s errored - %s",
2022
2022
  method,
2023
2023
  origin,
2024
- path11,
2024
+ path12,
2025
2025
  error.message
2026
2026
  );
2027
2027
  }
@@ -2136,7 +2136,7 @@ var require_request = __commonJS({
2136
2136
  var kHandler = /* @__PURE__ */ Symbol("handler");
2137
2137
  var Request = class {
2138
2138
  constructor(origin, {
2139
- path: path11,
2139
+ path: path12,
2140
2140
  method,
2141
2141
  body,
2142
2142
  headers,
@@ -2153,11 +2153,11 @@ var require_request = __commonJS({
2153
2153
  maxRedirections,
2154
2154
  typeOfService
2155
2155
  }, handler) {
2156
- if (typeof path11 !== "string") {
2156
+ if (typeof path12 !== "string") {
2157
2157
  throw new InvalidArgumentError("path must be a string");
2158
- } else if (path11[0] !== "/" && !(path11.startsWith("http://") || path11.startsWith("https://")) && method !== "CONNECT") {
2158
+ } else if (path12[0] !== "/" && !(path12.startsWith("http://") || path12.startsWith("https://")) && method !== "CONNECT") {
2159
2159
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
2160
- } else if (invalidPathRegex.test(path11)) {
2160
+ } else if (invalidPathRegex.test(path12)) {
2161
2161
  throw new InvalidArgumentError("invalid request path");
2162
2162
  }
2163
2163
  if (typeof method !== "string") {
@@ -2232,7 +2232,7 @@ var require_request = __commonJS({
2232
2232
  this.completed = false;
2233
2233
  this.aborted = false;
2234
2234
  this.upgrade = upgrade || null;
2235
- this.path = query ? serializePathWithQuery(path11, query) : path11;
2235
+ this.path = query ? serializePathWithQuery(path12, query) : path12;
2236
2236
  this.origin = origin;
2237
2237
  this.protocol = getProtocolFromUrlString(origin);
2238
2238
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -7415,7 +7415,7 @@ var require_client_h1 = __commonJS({
7415
7415
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
7416
7416
  }
7417
7417
  function writeH1(client, request) {
7418
- const { method, path: path11, host, upgrade, blocking, reset } = request;
7418
+ const { method, path: path12, host, upgrade, blocking, reset } = request;
7419
7419
  let { body, headers, contentLength } = request;
7420
7420
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
7421
7421
  if (util.isFormDataLike(body)) {
@@ -7493,7 +7493,7 @@ var require_client_h1 = __commonJS({
7493
7493
  if (socket.setTypeOfService) {
7494
7494
  socket.setTypeOfService(request.typeOfService);
7495
7495
  }
7496
- let header = `${method} ${path11} HTTP/1.1\r
7496
+ let header = `${method} ${path12} HTTP/1.1\r
7497
7497
  `;
7498
7498
  if (typeof host === "string") {
7499
7499
  header += `host: ${host}\r
@@ -8146,7 +8146,7 @@ var require_client_h2 = __commonJS({
8146
8146
  function writeH2(client, request) {
8147
8147
  const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout];
8148
8148
  const session = client[kHTTP2Session];
8149
- const { method, path: path11, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
8149
+ const { method, path: path12, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
8150
8150
  let { body } = request;
8151
8151
  if (upgrade != null && upgrade !== "websocket") {
8152
8152
  util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -8214,7 +8214,7 @@ var require_client_h2 = __commonJS({
8214
8214
  }
8215
8215
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
8216
8216
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
8217
- headers[HTTP2_HEADER_PATH] = path11;
8217
+ headers[HTTP2_HEADER_PATH] = path12;
8218
8218
  if (protocol === "ws:" || protocol === "wss:") {
8219
8219
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
8220
8220
  } else {
@@ -8255,7 +8255,7 @@ var require_client_h2 = __commonJS({
8255
8255
  stream2.setTimeout(requestTimeout);
8256
8256
  return true;
8257
8257
  }
8258
- headers[HTTP2_HEADER_PATH] = path11;
8258
+ headers[HTTP2_HEADER_PATH] = path12;
8259
8259
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
8260
8260
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
8261
8261
  if (body && typeof body.read === "function") {
@@ -10598,10 +10598,10 @@ var require_proxy_agent = __commonJS({
10598
10598
  };
10599
10599
  const {
10600
10600
  origin,
10601
- path: path11 = "/",
10601
+ path: path12 = "/",
10602
10602
  headers = {}
10603
10603
  } = opts;
10604
- opts.path = origin + path11;
10604
+ opts.path = origin + path12;
10605
10605
  if (!("host" in headers) && !("Host" in headers)) {
10606
10606
  const { host } = new URL(origin);
10607
10607
  headers.host = host;
@@ -12684,20 +12684,20 @@ var require_mock_utils = __commonJS({
12684
12684
  }
12685
12685
  return normalizedQp;
12686
12686
  }
12687
- function safeUrl(path11) {
12688
- if (typeof path11 !== "string") {
12689
- return path11;
12687
+ function safeUrl(path12) {
12688
+ if (typeof path12 !== "string") {
12689
+ return path12;
12690
12690
  }
12691
- const pathSegments = path11.split("?", 3);
12691
+ const pathSegments = path12.split("?", 3);
12692
12692
  if (pathSegments.length !== 2) {
12693
- return path11;
12693
+ return path12;
12694
12694
  }
12695
12695
  const qp = new URLSearchParams(pathSegments.pop());
12696
12696
  qp.sort();
12697
12697
  return [...pathSegments, qp.toString()].join("?");
12698
12698
  }
12699
- function matchKey(mockDispatch2, { path: path11, method, body, headers }) {
12700
- const pathMatch = matchValue(mockDispatch2.path, path11);
12699
+ function matchKey(mockDispatch2, { path: path12, method, body, headers }) {
12700
+ const pathMatch = matchValue(mockDispatch2.path, path12);
12701
12701
  const methodMatch = matchValue(mockDispatch2.method, method);
12702
12702
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
12703
12703
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -12722,8 +12722,8 @@ var require_mock_utils = __commonJS({
12722
12722
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
12723
12723
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
12724
12724
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
12725
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path11, ignoreTrailingSlash }) => {
12726
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path11)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path11), resolvedPath);
12725
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path12, ignoreTrailingSlash }) => {
12726
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path12)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path12), resolvedPath);
12727
12727
  });
12728
12728
  if (matchedMockDispatches.length === 0) {
12729
12729
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -12762,19 +12762,19 @@ var require_mock_utils = __commonJS({
12762
12762
  mockDispatches.splice(index, 1);
12763
12763
  }
12764
12764
  }
12765
- function removeTrailingSlash(path11) {
12766
- while (path11.endsWith("/")) {
12767
- path11 = path11.slice(0, -1);
12765
+ function removeTrailingSlash(path12) {
12766
+ while (path12.endsWith("/")) {
12767
+ path12 = path12.slice(0, -1);
12768
12768
  }
12769
- if (path11.length === 0) {
12770
- path11 = "/";
12769
+ if (path12.length === 0) {
12770
+ path12 = "/";
12771
12771
  }
12772
- return path11;
12772
+ return path12;
12773
12773
  }
12774
12774
  function buildKey(opts) {
12775
- const { path: path11, method, body, headers, query } = opts;
12775
+ const { path: path12, method, body, headers, query } = opts;
12776
12776
  return {
12777
- path: path11,
12777
+ path: path12,
12778
12778
  method,
12779
12779
  body,
12780
12780
  headers,
@@ -13464,10 +13464,10 @@ var require_pending_interceptors_formatter = __commonJS({
13464
13464
  }
13465
13465
  format(pendingInterceptors) {
13466
13466
  const withPrettyHeaders = pendingInterceptors.map(
13467
- ({ method, path: path11, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13467
+ ({ method, path: path12, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13468
13468
  Method: method,
13469
13469
  Origin: origin,
13470
- Path: path11,
13470
+ Path: path12,
13471
13471
  "Status code": statusCode,
13472
13472
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
13473
13473
  Invocations: timesInvoked,
@@ -13549,9 +13549,9 @@ var require_mock_agent = __commonJS({
13549
13549
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
13550
13550
  const dispatchOpts = { ...opts };
13551
13551
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
13552
- const [path11, searchParams] = dispatchOpts.path.split("?");
13552
+ const [path12, searchParams] = dispatchOpts.path.split("?");
13553
13553
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
13554
- dispatchOpts.path = `${path11}?${normalizedSearchParams}`;
13554
+ dispatchOpts.path = `${path12}?${normalizedSearchParams}`;
13555
13555
  }
13556
13556
  return this[kAgent].dispatch(dispatchOpts, handler);
13557
13557
  }
@@ -13680,7 +13680,7 @@ var require_snapshot_utils = __commonJS({
13680
13680
  };
13681
13681
  }
13682
13682
  var crypto2 = runtimeFeatures.has("crypto") ? __require("crypto") : null;
13683
- var hashId2 = crypto2?.hash ? (value) => crypto2.hash("sha256", value, "base64url") : (value) => Buffer.from(value).toString("base64url");
13683
+ var hashId3 = crypto2?.hash ? (value) => crypto2.hash("sha256", value, "base64url") : (value) => Buffer.from(value).toString("base64url");
13684
13684
  function isUndiciHeaders(headers) {
13685
13685
  return Array.isArray(headers) && (headers.length & 1) === 0;
13686
13686
  }
@@ -13742,7 +13742,7 @@ var require_snapshot_utils = __commonJS({
13742
13742
  }
13743
13743
  module.exports = {
13744
13744
  createHeaderFilters,
13745
- hashId: hashId2,
13745
+ hashId: hashId3,
13746
13746
  isUndiciHeaders,
13747
13747
  normalizeHeaders,
13748
13748
  isUrlExcludedFactory,
@@ -13759,7 +13759,7 @@ var require_snapshot_recorder = __commonJS({
13759
13759
  var { dirname: dirname6, resolve } = __require("path");
13760
13760
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
13761
13761
  var { InvalidArgumentError, UndiciError } = require_errors();
13762
- var { hashId: hashId2, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
13762
+ var { hashId: hashId3, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
13763
13763
  function formatRequestKey(opts, headerFilters, matchOptions = {}) {
13764
13764
  const url = new URL(opts.path, opts.origin);
13765
13765
  const normalized = opts._normalizedHeaders || normalizeHeaders(opts.headers);
@@ -13822,7 +13822,7 @@ var require_snapshot_recorder = __commonJS({
13822
13822
  }
13823
13823
  parts.push(formattedRequest.body);
13824
13824
  const content = parts.join("|");
13825
- return hashId2(content);
13825
+ return hashId3(content);
13826
13826
  }
13827
13827
  var SnapshotRecorder = class {
13828
13828
  /** @type {NodeJS.Timeout | null} */
@@ -13952,12 +13952,12 @@ var require_snapshot_recorder = __commonJS({
13952
13952
  * @return {Promise<void>} - Resolves when snapshots are loaded
13953
13953
  */
13954
13954
  async loadSnapshots(filePath) {
13955
- const path11 = filePath || this.#snapshotPath;
13956
- if (!path11) {
13955
+ const path12 = filePath || this.#snapshotPath;
13956
+ if (!path12) {
13957
13957
  throw new InvalidArgumentError("Snapshot path is required");
13958
13958
  }
13959
13959
  try {
13960
- const data = await readFile3(resolve(path11), "utf8");
13960
+ const data = await readFile3(resolve(path12), "utf8");
13961
13961
  const parsed = JSON.parse(data);
13962
13962
  if (Array.isArray(parsed)) {
13963
13963
  this.#snapshots.clear();
@@ -13971,7 +13971,7 @@ var require_snapshot_recorder = __commonJS({
13971
13971
  if (error.code === "ENOENT") {
13972
13972
  this.#snapshots.clear();
13973
13973
  } else {
13974
- throw new UndiciError(`Failed to load snapshots from ${path11}`, { cause: error });
13974
+ throw new UndiciError(`Failed to load snapshots from ${path12}`, { cause: error });
13975
13975
  }
13976
13976
  }
13977
13977
  }
@@ -13982,11 +13982,11 @@ var require_snapshot_recorder = __commonJS({
13982
13982
  * @returns {Promise<void>} - Resolves when snapshots are saved
13983
13983
  */
13984
13984
  async saveSnapshots(filePath) {
13985
- const path11 = filePath || this.#snapshotPath;
13986
- if (!path11) {
13985
+ const path12 = filePath || this.#snapshotPath;
13986
+ if (!path12) {
13987
13987
  throw new InvalidArgumentError("Snapshot path is required");
13988
13988
  }
13989
- const resolvedPath = resolve(path11);
13989
+ const resolvedPath = resolve(path12);
13990
13990
  await mkdir3(dirname6(resolvedPath), { recursive: true });
13991
13991
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
13992
13992
  hash,
@@ -14618,15 +14618,15 @@ var require_redirect_handler = __commonJS({
14618
14618
  return;
14619
14619
  }
14620
14620
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
14621
- const path11 = search ? `${pathname}${search}` : pathname;
14622
- const redirectUrlString = `${origin}${path11}`;
14621
+ const path12 = search ? `${pathname}${search}` : pathname;
14622
+ const redirectUrlString = `${origin}${path12}`;
14623
14623
  for (const historyUrl of this.history) {
14624
14624
  if (historyUrl.toString() === redirectUrlString) {
14625
14625
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
14626
14626
  }
14627
14627
  }
14628
14628
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
14629
- this.opts.path = path11;
14629
+ this.opts.path = path12;
14630
14630
  this.opts.origin = origin;
14631
14631
  this.opts.query = null;
14632
14632
  }
@@ -16395,10 +16395,10 @@ var require_cache_handler = __commonJS({
16395
16395
  }
16396
16396
  return locationUrl.pathname + locationUrl.search;
16397
16397
  }
16398
- function deleteCachedUri(store, cacheKey, path11) {
16398
+ function deleteCachedUri(store, cacheKey, path12) {
16399
16399
  deleteCachedValue(store, {
16400
16400
  ...cacheKey,
16401
- path: path11
16401
+ path: path12
16402
16402
  });
16403
16403
  for (let i = 0; i < util.safeHTTPMethods.length; i++) {
16404
16404
  const method = util.safeHTTPMethods[i];
@@ -16406,7 +16406,7 @@ var require_cache_handler = __commonJS({
16406
16406
  deleteCachedValue(store, {
16407
16407
  ...cacheKey,
16408
16408
  method,
16409
- path: path11
16409
+ path: path12
16410
16410
  });
16411
16411
  }
16412
16412
  }
@@ -16417,9 +16417,9 @@ var require_cache_handler = __commonJS({
16417
16417
  }
16418
16418
  const values = Array.isArray(headerValue2) ? headerValue2 : [headerValue2];
16419
16419
  for (let i = 0; i < values.length; i++) {
16420
- const path11 = getSameOriginPath(cacheKey, values[i]);
16421
- if (path11 !== void 0) {
16422
- deleteCachedUri(store, cacheKey, path11);
16420
+ const path12 = getSameOriginPath(cacheKey, values[i]);
16421
+ if (path12 !== void 0) {
16422
+ deleteCachedUri(store, cacheKey, path12);
16423
16423
  }
16424
16424
  }
16425
16425
  }
@@ -21297,11 +21297,11 @@ var require_fetch = __commonJS({
21297
21297
  function dispatch({ body }) {
21298
21298
  const url = requestCurrentURL(request);
21299
21299
  const agent = fetchParams.controller.dispatcher;
21300
- const path11 = url.pathname + url.search;
21300
+ const path12 = url.pathname + url.search;
21301
21301
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
21302
21302
  return new Promise((resolve, reject) => agent.dispatch(
21303
21303
  {
21304
- path: hasTrailingQuestionMark ? `${path11}?` : path11,
21304
+ path: hasTrailingQuestionMark ? `${path12}?` : path12,
21305
21305
  origin: url.origin,
21306
21306
  method: request.method,
21307
21307
  body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
@@ -22248,9 +22248,9 @@ var require_util4 = __commonJS({
22248
22248
  }
22249
22249
  }
22250
22250
  }
22251
- function validateCookiePath(path11) {
22252
- for (let i = 0; i < path11.length; ++i) {
22253
- const code = path11.charCodeAt(i);
22251
+ function validateCookiePath(path12) {
22252
+ for (let i = 0; i < path12.length; ++i) {
22253
+ const code = path12.charCodeAt(i);
22254
22254
  if (code < 32 || // exclude CTLs (0-31)
22255
22255
  code > 126 || // exclude DEL and non-ascii
22256
22256
  code === 59) {
@@ -25487,11 +25487,11 @@ var require_undici = __commonJS({
25487
25487
  if (typeof opts.path !== "string") {
25488
25488
  throw new InvalidArgumentError("invalid opts.path");
25489
25489
  }
25490
- let path11 = opts.path;
25490
+ let path12 = opts.path;
25491
25491
  if (!opts.path.startsWith("/")) {
25492
- path11 = `/${path11}`;
25492
+ path12 = `/${path12}`;
25493
25493
  }
25494
- url = new URL(util.parseOrigin(url).origin + path11);
25494
+ url = new URL(util.parseOrigin(url).origin + path12);
25495
25495
  } else {
25496
25496
  if (!opts) {
25497
25497
  opts = typeof url === "object" ? url : {};
@@ -43539,6 +43539,7 @@ function createInitialState() {
43539
43539
  return {
43540
43540
  blocks: [],
43541
43541
  messageRefs: { byRaw: {}, byRef: {} },
43542
+ tokenSnapshot: {},
43542
43543
  nudge: {
43543
43544
  lastPerMessageNudgeTokens: 0,
43544
43545
  lastNudgeShownTokens: 0,
@@ -43708,11 +43709,23 @@ function syncBlocks(messages, state) {
43708
43709
  byRaw: { ...state.messageRefs.byRaw },
43709
43710
  byRef: { ...state.messageRefs.byRef }
43710
43711
  },
43712
+ // Snapshot is keyed by ref with primitive values — shallow copy suffices.
43713
+ tokenSnapshot: { ...state.tokenSnapshot ?? {} },
43711
43714
  nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
43712
43715
  stats: { ...state.stats },
43713
43716
  nextBlockId: state.nextBlockId,
43714
43717
  nextRunId: state.nextRunId
43715
43718
  };
43719
+ const liveRefs = new Set(
43720
+ messages.map((m2) => result.messageRefs.byRaw[m2.id]).filter((r) => typeof r === "string")
43721
+ );
43722
+ if (Object.keys(result.tokenSnapshot).length !== liveRefs.size) {
43723
+ const pruned = {};
43724
+ for (const [ref, n] of Object.entries(result.tokenSnapshot)) {
43725
+ if (liveRefs.has(ref)) pruned[ref] = n;
43726
+ }
43727
+ result.tokenSnapshot = pruned;
43728
+ }
43716
43729
  const consumedBlockIds = /* @__PURE__ */ new Set();
43717
43730
  for (const block of result.blocks) {
43718
43731
  for (const consumedId of block.directBlockIds) {
@@ -44191,7 +44204,7 @@ var TAG_CLOSE = LT + "/acp" + GT;
44191
44204
  function acpTag(ref, tokens, type) {
44192
44205
  return TAG_OPEN + 'tokens="' + formatTokens(tokens) + '" type="' + type + '"' + GT + ref + TAG_CLOSE;
44193
44206
  }
44194
- function renderMessage(message, map, countTokens, strategy) {
44207
+ function renderMessage(message, map, countTokens, strategy, snapshot = null) {
44195
44208
  const ref = refForRaw(map, message.id);
44196
44209
  if (!ref || ref === BLOCKED_REF) return message;
44197
44210
  if (strategy === "none") return message;
@@ -44202,26 +44215,33 @@ function renderMessage(message, map, countTokens, strategy) {
44202
44215
  "^" + escapeRegex(TAG_OPEN) + "[^>]*" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + "\\n?"
44203
44216
  );
44204
44217
  const cleanText = (message.text || "").replace(ownTagRe, "");
44205
- const tokens = countTokens(cleanText);
44218
+ const tokens = snapshot ? snapshot[ref] ?? (snapshot[ref] = countTokens(cleanText)) : countTokens(cleanText);
44206
44219
  const type = classifyType(message);
44207
44220
  const prefix = acpTag(ref, tokens, type) + "\n";
44208
44221
  if (!cleanText) return { ...message, text: prefix };
44209
44222
  return { ...message, text: prefix + cleanText };
44210
44223
  }
44211
- function renderVisibleRefs(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
44224
+ function renderWithSnapshot(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
44212
44225
  const map = state.messageRefs;
44213
- return messages.map(
44214
- (message) => renderMessage(message, map, countTokens, strategy)
44226
+ const snapshot = { ...state.tokenSnapshot ?? {} };
44227
+ const rendered = messages.map(
44228
+ (message) => renderMessage(message, map, countTokens, strategy, snapshot)
44215
44229
  );
44230
+ return { messages: rendered, tokenSnapshot: snapshot };
44216
44231
  }
44217
44232
  function createRenderRefsNode(strategy) {
44218
44233
  return {
44219
44234
  name: "render-refs",
44220
44235
  run(io2, ctx) {
44221
- return {
44222
- ...io2,
44223
- messages: renderVisibleRefs(io2.messages, io2.state, ctx.countTokens, strategy)
44224
- };
44236
+ const { messages, tokenSnapshot } = renderWithSnapshot(
44237
+ io2.messages,
44238
+ io2.state,
44239
+ ctx.countTokens,
44240
+ strategy
44241
+ );
44242
+ const prev = io2.state.tokenSnapshot;
44243
+ const changed = !prev || Object.keys(tokenSnapshot).length !== Object.keys(prev).length;
44244
+ return changed ? { ...io2, messages, state: { ...io2.state, tokenSnapshot } } : { ...io2, messages };
44225
44245
  }
44226
44246
  };
44227
44247
  }
@@ -44417,6 +44437,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
44417
44437
  ref,
44418
44438
  refNum: rn2,
44419
44439
  tokens: countTokens(msg2.text ?? ""),
44440
+ chars: (msg2.text ?? "").length,
44420
44441
  isTool: isToolMessage(msg2),
44421
44442
  isUser: msg2.role === "user"
44422
44443
  });
@@ -44437,6 +44458,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
44437
44458
  endRef: info.ref,
44438
44459
  count: 1,
44439
44460
  tokens: info.tokens,
44461
+ chars: info.chars,
44440
44462
  toolPct: info.isTool ? 100 : 0,
44441
44463
  textPct: info.isTool ? 0 : 100
44442
44464
  };
@@ -44444,6 +44466,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
44444
44466
  cur.endRef = info.ref;
44445
44467
  cur.count++;
44446
44468
  cur.tokens += info.tokens;
44469
+ cur.chars = (cur.chars ?? 0) + info.chars;
44447
44470
  if (info.isTool) {
44448
44471
  cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);
44449
44472
  } else {
@@ -44491,6 +44514,7 @@ function mergeBatch(batch) {
44491
44514
  const last = batch[batch.length - 1];
44492
44515
  const count = batch.reduce((s3, r) => s3 + r.count, 0);
44493
44516
  const tokens = batch.reduce((s3, r) => s3 + r.tokens, 0);
44517
+ const chars = batch.reduce((s3, r) => s3 + rangeChars(r), 0);
44494
44518
  const toolPct = Math.round(
44495
44519
  batch.reduce((s3, r) => s3 + r.toolPct * r.count, 0) / count
44496
44520
  );
@@ -44499,6 +44523,7 @@ function mergeBatch(batch) {
44499
44523
  endRef: last.endRef,
44500
44524
  count,
44501
44525
  tokens,
44526
+ chars,
44502
44527
  toolPct,
44503
44528
  textPct: 100 - toolPct
44504
44529
  };
@@ -44507,16 +44532,21 @@ function mergeBatch(batch) {
44507
44532
  }
44508
44533
  return merged;
44509
44534
  }
44535
+ function rangeChars(r) {
44536
+ return r.chars ?? r.tokens * 4;
44537
+ }
44510
44538
  function mergeRangesToThreshold(ranges, minChars) {
44511
44539
  if (minChars <= 0 || ranges.length === 0) return ranges;
44512
44540
  const result = [];
44513
44541
  let batch = [];
44542
+ let batchChars = 0;
44514
44543
  for (const r of ranges) {
44515
44544
  batch.push(r);
44516
- const batchTokens = batch.reduce((s3, x) => s3 + x.tokens, 0);
44517
- if (batchTokens * 4 >= minChars) {
44545
+ batchChars += rangeChars(r);
44546
+ if (batchChars >= minChars) {
44518
44547
  result.push(mergeBatch(batch));
44519
44548
  batch = [];
44549
+ batchChars = 0;
44520
44550
  }
44521
44551
  }
44522
44552
  if (batch.length > 0) {
@@ -45104,7 +45134,7 @@ function resolveAdaptiveGrowth(modelContextLimit, nudge) {
45104
45134
  function pendingByTier(state, recommendation, countTokens, minCompressRange) {
45105
45135
  const out = {};
45106
45136
  const merged = recommendation?.recommendedRanges ?? [];
45107
- const effective = minCompressRange > 0 ? merged.filter((r) => r.tokens * 4 >= minCompressRange) : merged;
45137
+ const effective = minCompressRange > 0 ? merged.filter((r) => (r.chars ?? r.tokens * 4) >= minCompressRange) : merged;
45108
45138
  out[1] = { pending: effective.reduce((s3, r) => s3 + r.tokens, 0), targetBlocks: [] };
45109
45139
  const active = activeBlocks(state);
45110
45140
  const t1 = active.filter((b2) => b2.tier === 1);
@@ -45266,6 +45296,7 @@ function cloneState(state) {
45266
45296
  byRaw: { ...state.messageRefs.byRaw },
45267
45297
  byRef: { ...state.messageRefs.byRef }
45268
45298
  },
45299
+ tokenSnapshot: { ...state.tokenSnapshot ?? {} },
45269
45300
  nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
45270
45301
  stats: { ...state.stats },
45271
45302
  nextBlockId: state.nextBlockId,
@@ -46507,13 +46538,13 @@ function getUpstreamConnectionStatus() {
46507
46538
  }
46508
46539
 
46509
46540
  // src/config.ts
46510
- function safeReadJson(path11) {
46541
+ function safeReadJson(path12) {
46511
46542
  try {
46512
- const raw = readFileSync(path11, "utf8").replace(/^\uFEFF/, "");
46543
+ const raw = readFileSync(path12, "utf8").replace(/^\uFEFF/, "");
46513
46544
  return JSON.parse(raw);
46514
46545
  } catch (e) {
46515
46546
  if (e.code !== "ENOENT") {
46516
- log("error", `[acp-config] failed to parse ${path11}: ${String(e)}`);
46547
+ log("error", `[acp-config] failed to parse ${path12}: ${String(e)}`);
46517
46548
  }
46518
46549
  return void 0;
46519
46550
  }
@@ -46724,6 +46755,65 @@ function parsePromptCacheRouting(value) {
46724
46755
  function parseUpstreamProxyMode(value) {
46725
46756
  return value === "manual" || value === "auto" ? value : "direct";
46726
46757
  }
46758
+ function parseCompressSettings(v2) {
46759
+ if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return void 0;
46760
+ const obj = v2;
46761
+ const out = {};
46762
+ const numberOrPercent = (value) => typeof value === "number" && Number.isFinite(value) || typeof value === "string" && /^\d+(\.\d+)?%$/.test(value.trim());
46763
+ let ok = true;
46764
+ const takeNumber = (key) => {
46765
+ if (!(key in obj)) return;
46766
+ if (typeof obj[key] !== "number" || !Number.isFinite(obj[key])) ok = false;
46767
+ else out[key] = obj[key];
46768
+ };
46769
+ for (const key of ["modelContextLimit", "maxContextLimit", "emergencyThresholdPercent"]) {
46770
+ if (!(key in obj)) continue;
46771
+ if (!numberOrPercent(obj[key])) {
46772
+ ok = false;
46773
+ continue;
46774
+ }
46775
+ out[key] = typeof obj[key] === "string" ? obj[key].trim() : obj[key];
46776
+ }
46777
+ for (const key of ["nudgeGrowthTokens", "preserveRecentMessages", "preserveRecentTokens", "minCompressRange"]) {
46778
+ takeNumber(key);
46779
+ }
46780
+ if ("tiers" in obj) {
46781
+ if (typeof obj.tiers !== "boolean") ok = false;
46782
+ else out.tiers = obj.tiers;
46783
+ }
46784
+ for (const key of ["injectTool", "injectNudge"]) {
46785
+ if (key in obj) {
46786
+ if (typeof obj[key] !== "boolean") ok = false;
46787
+ else out[key] = obj[key];
46788
+ }
46789
+ }
46790
+ if ("acknowledgePromptsRisk" in obj) {
46791
+ if (typeof obj.acknowledgePromptsRisk !== "boolean") ok = false;
46792
+ else out.acknowledgePromptsRisk = obj.acknowledgePromptsRisk;
46793
+ }
46794
+ if ("prompts" in obj && obj.prompts !== void 0) {
46795
+ const prompts = obj.prompts;
46796
+ if (!prompts || typeof prompts !== "object" || Array.isArray(prompts)) {
46797
+ ok = false;
46798
+ } else {
46799
+ const cleaned = {};
46800
+ for (const [key, value] of Object.entries(prompts)) {
46801
+ if (typeof value !== "string" || value.trim().length === 0) {
46802
+ ok = false;
46803
+ continue;
46804
+ }
46805
+ if (key !== "compressPhilosophy" && key !== "howToCompressRules" && key !== "tier2DistillRules" && key !== "tier3CondenseRules") {
46806
+ ok = false;
46807
+ continue;
46808
+ }
46809
+ cleaned[key] = value;
46810
+ }
46811
+ if (ok) out.prompts = cleaned;
46812
+ }
46813
+ }
46814
+ if (!ok) return void 0;
46815
+ return out;
46816
+ }
46727
46817
  function rejectLegacyRoute(key, value) {
46728
46818
  if (typeof value !== "string") return;
46729
46819
  throw new Error(
@@ -46978,23 +47068,11 @@ async function fetchWithTimeout(url, opts, timeoutMs = UPSTREAM_TIMEOUT_MS, exte
46978
47068
  }
46979
47069
  }
46980
47070
 
46981
- // src/util.ts
47071
+ // node_modules/acp-kernel/dist/wire/index.js
46982
47072
  import { createHash } from "crypto";
46983
47073
  function hashId(s3) {
46984
47074
  return createHash("sha256").update(s3, "utf8").digest("hex").slice(0, 16);
46985
47075
  }
46986
- function safeJsonParse(s3) {
46987
- try {
46988
- return s3 ? JSON.parse(s3) : {};
46989
- } catch {
46990
- return {};
46991
- }
46992
- }
46993
- function isLoopbackAddress(addr) {
46994
- return !!addr && (addr.startsWith("127.") || addr === "::1" || addr.startsWith("::ffff:127."));
46995
- }
46996
-
46997
- // src/message-id.ts
46998
47076
  function deriveMessageId(role, contentType, text, options = {}) {
46999
47077
  const seed = `${role}|${contentType}|${options.toolCallId ?? ""}|${options.toolName ?? ""}|${text}`;
47000
47078
  return "h_" + hashId(seed);
@@ -47007,8 +47085,6 @@ var ClusterCounter = class {
47007
47085
  return n === 0 ? baseId : `${baseId}_${n}`;
47008
47086
  }
47009
47087
  };
47010
-
47011
- // src/anthropic.ts
47012
47088
  function extractSystem(system) {
47013
47089
  if (!system) return "";
47014
47090
  if (typeof system === "string") return system;
@@ -47174,15 +47250,11 @@ function safeParse(s3) {
47174
47250
  return {};
47175
47251
  }
47176
47252
  }
47177
-
47178
- // src/bili-message.ts
47179
47253
  function parseDataUrl(url) {
47180
47254
  const m2 = /^data:([^;,]+)(?:;base64)?,(.+)$/i.exec(url);
47181
47255
  if (!m2) return void 0;
47182
47256
  return { mediaType: m2[1], base64: m2[2] };
47183
47257
  }
47184
-
47185
- // src/openai.ts
47186
47258
  function openaiToCore(body) {
47187
47259
  const msgs = [];
47188
47260
  const clusters = new ClusterCounter();
@@ -47361,8 +47433,6 @@ function firstImagePart(content) {
47361
47433
  }
47362
47434
  return void 0;
47363
47435
  }
47364
-
47365
- // src/responses.ts
47366
47436
  var OPAQUE_ITEM_TYPES = /* @__PURE__ */ new Set([
47367
47437
  "additional_tools",
47368
47438
  "mcp_list_tools"
@@ -47638,13 +47708,32 @@ function conversationIdentityResponses(body, headerValue2) {
47638
47708
  function conversationSignalResponses(body, headerValue2) {
47639
47709
  return conversationIdentityResponses(body, headerValue2).value;
47640
47710
  }
47711
+ function createSubagentNamespaces() {
47712
+ const anchors = /* @__PURE__ */ new Map();
47713
+ return {
47714
+ namespaceFor(identityValue, instructions) {
47715
+ if (typeof instructions !== "string" || instructions.trim().length === 0) return identityValue;
47716
+ const fp = hashId(instructions);
47717
+ const anchor = anchors.get(identityValue);
47718
+ if (anchor === void 0) {
47719
+ anchors.set(identityValue, fp);
47720
+ return identityValue;
47721
+ }
47722
+ return anchor === fp ? identityValue : `${identityValue}|sub:${fp}`;
47723
+ }
47724
+ };
47725
+ }
47726
+ var defaultNamespaces = createSubagentNamespaces();
47727
+ function subagentNamespace(identityValue, instructions) {
47728
+ return defaultNamespaces.namespaceFor(identityValue, instructions);
47729
+ }
47641
47730
 
47642
47731
  // src/persist.ts
47643
47732
  import { promises as fs } from "fs";
47644
47733
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
47645
47734
  import { createHash as createHash2 } from "crypto";
47646
47735
  import * as path4 from "path";
47647
- var PERSIST_VERSION = 2;
47736
+ var PERSIST_VERSION = 3;
47648
47737
  function mergeState(parsed) {
47649
47738
  const fresh = createInitialState();
47650
47739
  return {
@@ -47653,7 +47742,8 @@ function mergeState(parsed) {
47653
47742
  nudge: { ...fresh.nudge, ...parsed.nudge ?? {} },
47654
47743
  stats: { ...fresh.stats, ...parsed.stats ?? {} },
47655
47744
  nextBlockId: parsed.nextBlockId ?? fresh.nextBlockId,
47656
- nextRunId: parsed.nextRunId ?? fresh.nextRunId
47745
+ nextRunId: parsed.nextRunId ?? fresh.nextRunId,
47746
+ tokenSnapshot: parsed.tokenSnapshot ?? fresh.tokenSnapshot
47657
47747
  };
47658
47748
  }
47659
47749
  function hostLabel(upstreamOrigin) {
@@ -47913,6 +48003,7 @@ function buildRecord(session) {
47913
48003
  id: session.id,
47914
48004
  meta: { ...session.meta },
47915
48005
  stats: { ...session.stats },
48006
+ messages: session.lastMessages,
47916
48007
  metadata: { ...session.metadata },
47917
48008
  state: session.state,
47918
48009
  blockContents: Object.fromEntries(session.blockContents),
@@ -47949,6 +48040,7 @@ function buildSession(parsed) {
47949
48040
  createdAt: parsed.createdAt ?? Date.now(),
47950
48041
  lastSeen: Date.now(),
47951
48042
  blockContents,
48043
+ lastMessages: Array.isArray(parsed.messages) ? parsed.messages : void 0,
47952
48044
  inFlight: 0,
47953
48045
  persisted: true
47954
48046
  };
@@ -48084,6 +48176,9 @@ async function withSessionLock(session, fn) {
48084
48176
  function listSessions() {
48085
48177
  return [...sessions.values()].sort((a, b2) => b2.lastSeen - a.lastSeen);
48086
48178
  }
48179
+ function snapshotMessages(session, messages) {
48180
+ if (messages.length > 0) session.lastMessages = messages;
48181
+ }
48087
48182
  function markDirty(session) {
48088
48183
  getStore().scheduleSave(session);
48089
48184
  }
@@ -48608,16 +48703,17 @@ function busy(button,on,label){if(!button)return;if(on){button.dataset.label=but
48608
48703
  async function json(url,options){const response=await fetch(url,options);const data=await response.json().catch(()=>({}));if(!response.ok)throw new Error(data.error||data.detail||("HTTP "+response.status));return data}
48609
48704
  function showPage(name){document.querySelectorAll(".page").forEach((node)=>node.classList.toggle("active",node.id==="page-"+name));document.querySelectorAll(".nav button").forEach((node)=>node.classList.toggle("active",node.dataset.page===name));if(name==="sessions")loadSessions();if(name==="upstream"){loadUpstream();loadOverrides()}}
48610
48705
  document.querySelectorAll(".nav button").forEach((button)=>button.addEventListener("click",()=>showPage(button.dataset.page)));
48611
- async function loadConfig(){const data=await json("/__bili/config");byId("providers-json").value=JSON.stringify(data.providers||{},null,2);byId("proxy-url").value=data.upstreamProxy||"";document.querySelectorAll('input[name="proxy-mode"]').forEach((input)=>input.checked=input.value===(data.upstreamProxyMode||"direct"));return data}
48706
+ async function loadConfig(){const data=await json("/__bili/config");byId("providers-json").value=JSON.stringify(data.providers||{},null,2);byId("proxy-url").value=data.upstreamProxy||"";byId("compress-json").value=data.compress?JSON.stringify(data.compress,null,2):"";document.querySelectorAll('input[name="proxy-mode"]').forEach((input)=>input.checked=input.value===(data.upstreamProxyMode||"direct"));return data}
48612
48707
  async function loadUpstream(){try{const data=await json("/__bili/upstream");const labels={"provider":"Provider \u5355\u72EC\u4EE3\u7406","provider-direct":"Provider \u76F4\u8FDE","bili-env":"BILI_UPSTREAM_PROXY","web-manual":"Web \u624B\u52A8\u4EE3\u7406","config":"\u914D\u7F6E\u6587\u4EF6\u4EE3\u7406","HTTPS_PROXY":"HTTPS_PROXY","HTTP_PROXY":"HTTP_PROXY","ALL_PROXY":"ALL_PROXY","windows-system":"Windows \u7CFB\u7EDF\u4EE3\u7406","windows-bypass":"Windows \u7ED5\u8FC7\u5217\u8868","no-proxy":"NO_PROXY","direct":"\u76F4\u8FDE"};byId("upstream-source").textContent=labels[data.source]||data.source||"\u76F4\u8FDE";byId("upstream-effective").textContent=data.proxy||"direct";byId("upstream-pac").textContent=data.autoConfigUrl||"\u2014";const state=byId("upstream-state");state.className="status "+(data.connected===true?"ok":data.connected===false?"err":"");state.textContent=data.connected===true?"CONNECT \u6B63\u5E38":data.connected===false?(data.error||"\u8FDE\u63A5\u5931\u8D25"):"\u5C1A\u672A\u89C2\u5BDF\u5230\u4E0A\u6E38\u8FDE\u63A5"}catch(error){byId("upstream-state").textContent=String(error)}}
48613
48708
  async function saveUpstream(){const button=byId("save-upstream");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");const mode=document.querySelector('input[name="proxy-mode"]:checked').value;try{await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({upstreamProxyMode:mode,upstreamProxy:byId("proxy-url").value.trim()||null})});toast("\u4E0A\u6E38\u8BBE\u7F6E\u5DF2\u70ED\u66F4\u65B0");await loadUpstream()}catch(error){toast(String(error),true)}finally{busy(button,false)}}
48614
48709
  async function testUpstream(){const button=byId("test-upstream");busy(button,true,"\u6D4B\u8BD5\u4E2D\u2026");try{const data=await json("/__bili/upstream/test",{method:"POST"});toast("\u8FDE\u63A5\u6210\u529F\uFF0CHTTP "+data.status);await loadUpstream()}catch(error){toast(String(error),true);await loadUpstream()}finally{busy(button,false)}}
48615
48710
  async function saveProviders(){const button=byId("save-providers");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");try{const providers=JSON.parse(byId("providers-json").value);await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({providers})});await json("/__bili/config/reload",{method:"POST"});toast("Provider \u914D\u7F6E\u5DF2\u70ED\u66F4\u65B0")}catch(error){toast(String(error),true)}finally{busy(button,false)}}
48711
+ 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)}}
48616
48712
  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)}}
48617
48713
  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)}}
48618
48714
  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}}
48619
48715
  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)}}
48620
- 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-overrides").addEventListener("click",saveOverrides);byId("refresh-sessions").addEventListener("click",refreshSessions);
48716
+ 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);
48621
48717
  Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),true));setInterval(()=>{if(byId("page-sessions").classList.contains("active"))loadSessions().catch(()=>{})},5000);
48622
48718
  `;
48623
48719
 
@@ -48648,7 +48744,7 @@ function renderPage(origin, version2) {
48648
48744
  <div class="card"><div class="card-head"><h2>ZCode\uFF08\u7F16\u7A0B\u5957\u9910\uFF09</h2><span class="badge">MITM</span></div><dl class="kv"><dt>\u65B9\u5F0F</dt><dd>MITM \u900F\u660E\u4EE3\u7406</dd><dt>\u8BBE\u7F6E</dt><dd>Settings \u2192 Network \u2192 HTTP Proxy = <span class="mono">${origin}</span></dd><dt>CA \u8BC1\u4E66</dt><dd class="mono">~/.local/share/billion-context/ca/root-ca.pem</dd></dl></div></section>
48649
48745
  <section id="page-upstream" class="page"><h1>\u4E0A\u6E38\u7F51\u7EDC</h1><p class="lead">\u63A7\u5236 bili \u5982\u4F55\u8BBF\u95EE\u771F\u5B9E Provider\uFF0C\u4E0D\u4F1A\u6539\u53D8\u5BA2\u6237\u7AEF\u7684\u672C\u5730\u8DEF\u7531\u5730\u5740\u3002</p><div class="card"><div class="card-head"><h2>\u5168\u5C40\u4EE3\u7406</h2></div><div class="modes"><label><input type="radio" name="proxy-mode" value="direct" checked>\u76F4\u8FDE\uFF08\u9ED8\u8BA4\uFF09</label><label><input type="radio" name="proxy-mode" value="manual">\u624B\u52A8\u4EE3\u7406</label><label><input type="radio" name="proxy-mode" value="auto">\u81EA\u52A8\uFF08\u8DDF\u968F\u7CFB\u7EDF\uFF09</label></div><div class="field"><label>HTTP / HTTPS Proxy</label><input id="proxy-url" class="mono" placeholder="http://127.0.0.1:7897"></div><dl class="kv"><dt>\u5F53\u524D\u6765\u6E90</dt><dd id="upstream-source">\u76F4\u8FDE</dd><dt>\u6709\u6548\u4EE3\u7406</dt><dd id="upstream-effective" class="mono">direct</dd><dt>\u7CFB\u7EDF PAC</dt><dd id="upstream-pac" class="mono">\u2014</dd><dt>\u72B6\u6001</dt><dd id="upstream-state" class="status">\u5C1A\u672A\u6D4B\u8BD5</dd></dl><div class="actions"><button id="save-upstream" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button><button id="test-upstream" class="btn">\u6D4B\u8BD5\u8FDE\u63A5</button></div></div><div class="card"><div class="card-head"><h2>\u6309 URL \u8986\u76D6</h2></div><p class="status">\u4E3A\u7279\u5B9A Provider \u5355\u72EC\u8BBE\u7F6E\u4E0A\u6E38\u4EE3\u7406\uFF0C\u8986\u76D6\u5168\u5C40\u8BBE\u7F6E\u3002\u7559\u7A7A = \u7EE7\u627F\u5168\u5C40\u3002</p><div id="upstream-overrides" class="status">\u52A0\u8F7D\u4E2D</div><div class="actions"><button id="save-overrides" class="btn primary">\u4FDD\u5B58\u8986\u76D6\u5E76\u70ED\u66F4\u65B0</button></div></div></section>
48650
48746
  <section id="page-sessions" class="page"><div class="card-head"><div><h1>\u4F1A\u8BDD</h1><p class="lead">ACP \u538B\u7F29\u72B6\u6001\u4E0E\u4E0A\u6E38\u7528\u91CF\u3002</p></div><button id="refresh-sessions" class="btn">\u5237\u65B0</button></div><div class="card"><table><thead><tr><th>\u6807\u9898</th><th>\u534F\u8BAE</th><th>\u6807\u8BC6</th><th>\u8BF7\u6C42</th><th>\u4E0A\u4E0B\u6587</th><th>\u6700\u540E\u6D3B\u52A8</th></tr></thead><tbody id="sessions-body"></tbody></table></div></section>
48651
- <section id="page-settings" class="page"><h1>\u9AD8\u7EA7\u8BBE\u7F6E</h1><p class="lead">\u76F4\u63A5\u7F16\u8F91 providers JSON\uFF08\u6DFB\u52A0\u65B0 Provider\u3001\u914D\u7F6E\u6A21\u578B\u4E0A\u4E0B\u6587\u7A97\u53E3\u3001\u6309 URL \u4EE3\u7406\u7B49\uFF09\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u70ED\u66F4\u65B0\u3002</p><div class="card"><div class="field"><label>providers JSON</label><textarea id="providers-json">{}</textarea></div><div class="actions"><button id="save-providers" class="btn primary">\u4FDD\u5B58\u5E76\u5E94\u7528</button></div></div></section></main></div><div id="toast" class="toast"></div><script>${WEB_CLIENT}</script></body></html>`;
48747
+ <section id="page-settings" class="page"><h1>\u9AD8\u7EA7\u8BBE\u7F6E</h1><p class="lead">\u76F4\u63A5\u7F16\u8F91 providers JSON\uFF08\u6DFB\u52A0\u65B0 Provider\u3001\u914D\u7F6E\u6A21\u578B\u4E0A\u4E0B\u6587\u7A97\u53E3\u3001\u6309 URL \u4EE3\u7406\u7B49\uFF09\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u70ED\u66F4\u65B0\u3002</p><div class="card"><div class="field"><label>providers JSON</label><textarea id="providers-json">{}</textarea></div><div class="actions"><button id="save-providers" class="btn primary">\u4FDD\u5B58\u5E76\u5E94\u7528</button></div></div><div class="card"><div class="card-head"><h2>\u538B\u7F29\u53C2\u6570\uFF08\u5168\u5C40\uFF09</h2></div><p class="status">\u5168\u5C40 compress \u914D\u7F6E\uFF08modelContextLimit / maxContextLimit / emergencyThresholdPercent / nudgeGrowthTokens / preserveRecentMessages / preserveRecentTokens / minCompressRange / tiers / injectTool / injectNudge\uFF09\u3002\u4FDD\u5B58\u540E\u70ED\u66F4\u65B0\uFF0C\u65E0\u9700\u91CD\u542F\u3002\u7F6E\u7A7A = \u6062\u590D\u9ED8\u8BA4\u3002</p><div class="field"><label>compress JSON</label><textarea id="compress-json" placeholder='{"modelContextLimit": 200000}'></textarea></div><div class="actions"><button id="save-compress" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button></div></div></section></main></div><div id="toast" class="toast"></div><script>${WEB_CLIENT}</script></body></html>`;
48652
48748
  }
48653
48749
 
48654
48750
  // src/web/api.ts
@@ -48693,12 +48789,14 @@ function atomicWriteConfig(config) {
48693
48789
  }
48694
48790
  async function handleConfigGet(res) {
48695
48791
  const upstream = readUpstreamSettings();
48792
+ const config = readConfig();
48696
48793
  res.writeHead(200, { "content-type": "application/json" });
48697
48794
  res.end(JSON.stringify({
48698
48795
  path: configFile(),
48699
48796
  providers: readProviders(),
48700
48797
  upstreamProxy: upstream.proxy ?? null,
48701
- upstreamProxyMode: upstream.mode
48798
+ upstreamProxyMode: upstream.mode,
48799
+ compress: config.compress ?? null
48702
48800
  }, null, 2));
48703
48801
  }
48704
48802
  async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
@@ -48708,7 +48806,8 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
48708
48806
  const hasProviders = Object.prototype.hasOwnProperty.call(body, "providers");
48709
48807
  const hasProxy = Object.prototype.hasOwnProperty.call(body, "upstreamProxy");
48710
48808
  const hasMode = Object.prototype.hasOwnProperty.call(body, "upstreamProxyMode");
48711
- if (!hasProviders && !hasProxy && !hasMode) return sendError(res, 400, "expected providers or upstream proxy settings");
48809
+ const hasCompress = Object.prototype.hasOwnProperty.call(body, "compress");
48810
+ if (!hasProviders && !hasProxy && !hasMode && !hasCompress) return sendError(res, 400, "expected providers, upstream proxy, or compress settings");
48712
48811
  const routes = {};
48713
48812
  if (hasProviders) {
48714
48813
  if (!body.providers || typeof body.providers !== "object" || Array.isArray(body.providers)) {
@@ -48747,6 +48846,11 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
48747
48846
  if (mode === "manual" && !proxy && !readUpstreamSettings().proxy) {
48748
48847
  return sendError(res, 400, "manual mode requires an upstream proxy URL");
48749
48848
  }
48849
+ let compress;
48850
+ if (hasCompress) {
48851
+ compress = body.compress === null ? {} : parseCompressSettings(body.compress);
48852
+ if (compress === void 0) return sendError(res, 400, "invalid compress settings");
48853
+ }
48750
48854
  const config = readConfig();
48751
48855
  if (hasProviders) config.providers = routes;
48752
48856
  if (hasProxy) {
@@ -48754,13 +48858,21 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
48754
48858
  else delete config.upstreamProxy;
48755
48859
  }
48756
48860
  if (hasMode && mode) config.upstreamProxyMode = mode;
48861
+ if (hasCompress) {
48862
+ if (compress && Object.keys(compress).length > 0) config.compress = compress;
48863
+ else delete config.compress;
48864
+ }
48757
48865
  try {
48758
48866
  atomicWriteConfig(config);
48759
48867
  onChanged?.();
48760
48868
  } catch (error) {
48761
48869
  return sendError(res, 500, `failed to apply config: ${String(error)}`);
48762
48870
  }
48763
- log("info", `[acp-web] configuration updated (${hasProviders ? `${Object.keys(routes).length} routes` : "network only"})`);
48871
+ const changed = [];
48872
+ if (hasProviders) changed.push(`${Object.keys(routes).length} routes`);
48873
+ if (hasProxy || hasMode) changed.push("network");
48874
+ if (hasCompress) changed.push("compress");
48875
+ log("info", `[acp-web] configuration updated (${changed.join(", ") || "none"})`);
48764
48876
  res.writeHead(200, { "content-type": "application/json" });
48765
48877
  res.end(JSON.stringify({ ok: true, providers: hasProviders ? Object.keys(routes).length : void 0 }));
48766
48878
  }
@@ -50240,6 +50352,22 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
50240
50352
  return current;
50241
50353
  }
50242
50354
 
50355
+ // src/util.ts
50356
+ import { createHash as createHash3 } from "crypto";
50357
+ function hashId2(s3) {
50358
+ return createHash3("sha256").update(s3, "utf8").digest("hex").slice(0, 16);
50359
+ }
50360
+ function safeJsonParse(s3) {
50361
+ try {
50362
+ return s3 ? JSON.parse(s3) : {};
50363
+ } catch {
50364
+ return {};
50365
+ }
50366
+ }
50367
+ function isLoopbackAddress(addr) {
50368
+ return !!addr && (addr.startsWith("127.") || addr === "::1" || addr.startsWith("::ffff:127."));
50369
+ }
50370
+
50243
50371
  // src/stream-openai.ts
50244
50372
  function rewriteOpenaiJsonResponse(body, ctx) {
50245
50373
  if (!body || typeof body !== "object") return body;
@@ -50408,7 +50536,7 @@ function clientConversationHeader(headers) {
50408
50536
  function deriveSessionId(headers, protocol, upstream, conversation) {
50409
50537
  if (!conversation) throw new Error("deriveSessionId: conversation dimension is required (pass the conversationSignal* output)");
50410
50538
  const key = extractKey(headers);
50411
- return hashId(`${protocol}|${upstream}|${key}|${conversation}`);
50539
+ return hashId2(`${protocol}|${upstream}|${key}|${conversation}`);
50412
50540
  }
50413
50541
  function affinityToken(identity) {
50414
50542
  return identity.clientProvided ? identity.value : void 0;
@@ -50424,13 +50552,50 @@ import path5 from "path";
50424
50552
  import tls2 from "tls";
50425
50553
  var ROOT_CERT_FILE = "root-ca.pem";
50426
50554
  var ROOT_KEY_FILE = "root-ca-key.pem";
50555
+ var COMBINED_CA_FILE = "combined-ca.pem";
50427
50556
  var ROOT_CN = "billion-context MITM Root CA";
50557
+ var PLATFORM_CA_CANDIDATES = process.platform === "darwin" ? ["/etc/ssl/cert.pem", "/private/etc/ssl/cert.pem"] : [
50558
+ "/etc/ssl/certs/ca-certificates.crt",
50559
+ "/etc/pki/tls/certs/ca-bundle.crt",
50560
+ "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
50561
+ "/etc/ssl/ca-bundle.pem",
50562
+ "/etc/ssl/cert.pem"
50563
+ ];
50428
50564
  var rootCertPem;
50429
50565
  var rootKeyPem;
50430
50566
  var rootCert;
50431
50567
  var rootKey;
50432
50568
  var secureContextCache = /* @__PURE__ */ new Map();
50433
50569
  var SECURE_CONTEXT_CACHE_MAX = 64;
50570
+ function collectSystemCaPems(env = process.env) {
50571
+ const pems = [];
50572
+ const seen = /* @__PURE__ */ new Set();
50573
+ const pushFile = (file) => {
50574
+ try {
50575
+ const text = fs2.readFileSync(file, "utf8");
50576
+ if (!text.includes("BEGIN CERTIFICATE") || seen.has(text)) return false;
50577
+ seen.add(text);
50578
+ pems.push(text);
50579
+ return true;
50580
+ } catch {
50581
+ }
50582
+ return false;
50583
+ };
50584
+ const userBundle = env.SSL_CERT_FILE?.trim();
50585
+ if (userBundle && pushFile(userBundle)) return pems;
50586
+ for (const candidate of PLATFORM_CA_CANDIDATES) {
50587
+ if (pushFile(candidate)) break;
50588
+ }
50589
+ return pems;
50590
+ }
50591
+ function writeCombinedBundle() {
50592
+ const certs = /* @__PURE__ */ new Set();
50593
+ for (const pem of collectSystemCaPems()) certs.add(pem.trim());
50594
+ for (const pem of tls2.rootCertificates) certs.add(pem.trim());
50595
+ certs.add(rootCertPem.trim());
50596
+ const body = [...certs].map((pem) => pem.endsWith("\n") ? pem : pem + "\n").join("");
50597
+ fs2.writeFileSync(path5.join(caDir(), COMBINED_CA_FILE), body, { mode: 420 });
50598
+ }
50434
50599
  function generateRootCA() {
50435
50600
  const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
50436
50601
  const cert = import_node_forge.default.pki.createCertificate();
@@ -50457,7 +50622,10 @@ function generateRootCA() {
50457
50622
  };
50458
50623
  }
50459
50624
  function ensureRootCA() {
50460
- if (rootCertPem && rootKeyPem) return;
50625
+ if (rootCertPem && rootKeyPem) {
50626
+ writeCombinedBundle();
50627
+ return;
50628
+ }
50461
50629
  const dir = caDir();
50462
50630
  fs2.mkdirSync(dir, { recursive: true });
50463
50631
  const certPath = path5.join(dir, ROOT_CERT_FILE);
@@ -50467,6 +50635,7 @@ function ensureRootCA() {
50467
50635
  rootKeyPem = fs2.readFileSync(keyPath, "utf8");
50468
50636
  rootCert = import_node_forge.default.pki.certificateFromPem(rootCertPem);
50469
50637
  rootKey = import_node_forge.default.pki.privateKeyFromPem(rootKeyPem);
50638
+ writeCombinedBundle();
50470
50639
  return;
50471
50640
  }
50472
50641
  const { cert, key } = generateRootCA();
@@ -50476,6 +50645,7 @@ function ensureRootCA() {
50476
50645
  rootKeyPem = key;
50477
50646
  rootCert = import_node_forge.default.pki.certificateFromPem(cert);
50478
50647
  rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
50648
+ writeCombinedBundle();
50479
50649
  }
50480
50650
  function getSecureContext(host) {
50481
50651
  if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
@@ -51794,6 +51964,7 @@ async function handle(req, res, opts, core, config, log2) {
51794
51964
  opts.proxyMode = fresh.proxyMode;
51795
51965
  opts.proxySource = fresh.proxySource;
51796
51966
  opts.proxyFallback = fresh.proxyFallback;
51967
+ opts.compress = fresh.compress;
51797
51968
  resetProxyCache();
51798
51969
  for (const k2 of Object.keys(opts.routes)) delete opts.routes[k2];
51799
51970
  Object.assign(opts.routes, loadRoutes());
@@ -51938,7 +52109,10 @@ ${bodyBuffer.toString("utf8")}`);
51938
52109
  const clientConv = clientConversationHeader(req.headers);
51939
52110
  const convHeader = clientConv ?? sessionHeader;
51940
52111
  const responsesIdentity = protocol === "responses" ? conversationIdentityResponses(parsed, convHeader) : void 0;
51941
- const conversation = protocol === "anthropic" ? conversationSignalAnthropic(parsed, convHeader) : protocol === "openai" ? conversationSignalOpenai(parsed, convHeader) : responsesIdentity?.value ?? conversationSignalResponses(parsed, convHeader);
52112
+ const conversation = protocol === "anthropic" ? conversationSignalAnthropic(parsed, convHeader) : protocol === "openai" ? conversationSignalOpenai(parsed, convHeader) : subagentNamespace(
52113
+ responsesIdentity?.value ?? conversationSignalResponses(parsed, convHeader),
52114
+ parsed.instructions
52115
+ );
51942
52116
  const sessionId = deriveSessionId(req.headers, protocol, upstreamOrigin, conversation);
51943
52117
  const affinity = affinityToken(responsesIdentity ?? {
51944
52118
  value: clientConv ?? conversation,
@@ -51979,7 +52153,7 @@ function diagTagSummary(messages, sessionId, strategy) {
51979
52153
  }
51980
52154
  return `[${sessionId}] processTurn: ${messages.length} msgs, renderTags=${strategy}, ${textTagged} text tagged, ${toolTagged} tool tagged (should be 0 with text-only)`;
51981
52155
  }
51982
- function diagNudge(turn, sessionId, tokenCount, limit) {
52156
+ function diagNudge(turn, sessionId, tokenCount, limit, model) {
51983
52157
  const n = turn.nudge;
51984
52158
  if (!n) return `[${sessionId}] nudge: unavailable`;
51985
52159
  const b2 = n.breakdown ?? {};
@@ -51990,7 +52164,8 @@ function diagNudge(turn, sessionId, tokenCount, limit) {
51990
52164
  const pendingT1 = b2["pendingT1"] ?? 0;
51991
52165
  const ref = b2["growthReference"] ?? 0;
51992
52166
  const inject = n.shouldInject ? `INJECT T${n.tier ?? "?"}` : "idle";
51993
- return `[${sessionId}] nudge ${inject}: usage=${pct2} (${tokenCount}/${limit}), growth=${growth}/${floor} (ref=${ref}, interval=${interval}), pendingT1=${pendingT1}/${interval}, reason="${n.reason.slice(0, 120)}"`;
52167
+ const modelTag = model ? ` model=${model}` : "";
52168
+ 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)}"`;
51994
52169
  }
51995
52170
  function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session) {
51996
52171
  const sessionId = session.id;
@@ -52016,7 +52191,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
52016
52191
  if (t) session.meta.title = t;
52017
52192
  }
52018
52193
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
52019
- log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
52194
+ log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
52020
52195
  processedMessages = stripKernelSummaries(turn.messages);
52021
52196
  reapOrphanBlocks(session, msgs, deactivateBlock);
52022
52197
  rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
@@ -52037,6 +52212,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
52037
52212
  log2("warn", `[${sessionId}] kernel transform failed, forwarding unchanged: ${String(err2)}`);
52038
52213
  processedMessages = [];
52039
52214
  }
52215
+ snapshotMessages(session, originalMessages);
52040
52216
  markDirty(session);
52041
52217
  const rebuilt = { ...parsed, messages: rebuiltMessages, system: systemOut, tools: toolsOut };
52042
52218
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: opts.compress.injectTool, nudge, prompts };
@@ -52066,7 +52242,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session)
52066
52242
  if (t) session.meta.title = t;
52067
52243
  }
52068
52244
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
52069
- log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
52245
+ log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
52070
52246
  processedMessages = stripKernelSummaries(turn.messages);
52071
52247
  reapOrphanBlocks(session, msgs, deactivateBlock);
52072
52248
  rebuiltMessages = coreToOpenai(processedMessages);
@@ -52093,6 +52269,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session)
52093
52269
  if (stream2 && rebuilt.stream_options === void 0) {
52094
52270
  rebuilt.stream_options = { include_usage: true };
52095
52271
  }
52272
+ snapshotMessages(session, originalMessages);
52096
52273
  markDirty(session);
52097
52274
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, protocol: "openai", stream: stream2, compressInjected: shouldInject, nudge, prompts };
52098
52275
  }
@@ -52129,7 +52306,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
52129
52306
  if (t) session.meta.title = t;
52130
52307
  }
52131
52308
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
52132
- log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
52309
+ log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
52133
52310
  processedMessages = stripKernelSummaries(turn.messages);
52134
52311
  reapOrphanBlocks(session, msgs, deactivateBlock);
52135
52312
  rebuiltInput = patchResponsesInput(projection, processedMessages);
@@ -52176,6 +52353,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
52176
52353
  });
52177
52354
  log2("info", `[${sessionId}] responses forward tools=[${fwdTools.join(",")}] injectTool=${shouldInject} NO_INJECT_TOOL=${!!process.env.ACP_NO_INJECT_TOOL} NO_COMPRESS_PROMPT=${!!process.env.ACP_NO_COMPRESS_PROMPT}`);
52178
52355
  }
52356
+ snapshotMessages(session, originalMessages);
52179
52357
  markDirty(session);
52180
52358
  return {
52181
52359
  body: JSON.stringify(rebuilt),
@@ -52572,10 +52750,10 @@ async function pipeThrough(stream2, res) {
52572
52750
  }
52573
52751
  }
52574
52752
  async function dumpStreamToFile(stream2, dir, name) {
52575
- const { mkdirSync: mkdirSync6, createWriteStream: createWriteStream2 } = await import("fs");
52753
+ const { mkdirSync: mkdirSync7, createWriteStream: createWriteStream2 } = await import("fs");
52576
52754
  const { join: join4 } = await import("path");
52577
52755
  try {
52578
- mkdirSync6(dir, { recursive: true });
52756
+ mkdirSync7(dir, { recursive: true });
52579
52757
  const ws2 = createWriteStream2(join4(dir, name));
52580
52758
  ws2.on("error", (e) => {
52581
52759
  log("debug", `[dump] write stream error: ${e.message ?? e}`);
@@ -52606,6 +52784,7 @@ function handleConfigReload(opts, res, log2) {
52606
52784
  const fresh = loadRoutes();
52607
52785
  for (const k2 of Object.keys(opts.routes)) delete opts.routes[k2];
52608
52786
  Object.assign(opts.routes, fresh);
52787
+ opts.compress = loadOptions().compress;
52609
52788
  resetProxyCache();
52610
52789
  const names = Object.keys(fresh);
52611
52790
  log2("info", `[acp-web] routes hot-reloaded (${names.length} providers): ${names.join(", ") || "(none)"}`);
@@ -56008,6 +56187,10 @@ function resolveCaCertPath(env) {
56008
56187
  const base = env.XDG_DATA_HOME || path9.join(os4.homedir(), ".local/share");
56009
56188
  return path9.join(base, "billion-context", "ca", "root-ca.pem");
56010
56189
  }
56190
+ function resolveCombinedCaPath(env) {
56191
+ const base = env.XDG_DATA_HOME || path9.join(os4.homedir(), ".local/share");
56192
+ return path9.join(base, "billion-context", "ca", "combined-ca.pem");
56193
+ }
56011
56194
  function discoverRoutes(client, config) {
56012
56195
  const httpsDomains = [];
56013
56196
  const httpRewrites = [];
@@ -56337,7 +56520,7 @@ async function runLaunch(params, deps = {}) {
56337
56520
  piTmpHome = preparePiHttpRewrite(resolvePiHome(process.env), handle2.origin, routes.httpRewrites, routes.httpsRewrites);
56338
56521
  if (piTmpHome) env.PI_CODING_AGENT_DIR = piTmpHome;
56339
56522
  } else if (base === "codex") {
56340
- env = buildCodexEnv(handle2.origin, ca, process.env);
56523
+ env = buildCodexEnv(handle2.origin, resolveCombinedCaPath(process.env), process.env);
56341
56524
  clientArgs = buildCodexArgs(handle2.origin, routes.httpRewrites, routes.httpsRewrites, params.clientArgs);
56342
56525
  } else {
56343
56526
  env = buildClaudeEnv(handle2.origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);
@@ -56409,14 +56592,155 @@ async function runTestPi(params, deps = {}) {
56409
56592
  process.exit(code ?? 0);
56410
56593
  }
56411
56594
 
56595
+ // src/export.ts
56596
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
56597
+ import path10 from "path";
56598
+ function fmtDate(ms2) {
56599
+ return ms2 ? new Date(ms2).toISOString().replace("T", " ").slice(0, 19) + " UTC" : "\u2014";
56600
+ }
56601
+ async function listSessions2(opts = {}) {
56602
+ const store = new SessionStore({ dir: opts.dir, enabled: true });
56603
+ const sessions2 = [...(await store.loadAll()).values()];
56604
+ sessions2.sort((a, b2) => latestBlockTime(b2) - latestBlockTime(a));
56605
+ return sessions2.map((s3) => ({
56606
+ id: s3.id,
56607
+ title: s3.meta.title,
56608
+ label: s3.meta.label,
56609
+ protocol: s3.meta.protocol,
56610
+ upstreamOrigin: s3.meta.upstreamOrigin,
56611
+ savedAt: latestBlockTime(s3) || void 0,
56612
+ contextTokens: s3.stats.contextTokens,
56613
+ blocks: s3.state.blocks.length
56614
+ }));
56615
+ }
56616
+ function latestBlockTime(s3) {
56617
+ let latest = 0;
56618
+ for (const b2 of s3.state.blocks) if (b2.createdAt > latest) latest = b2.createdAt;
56619
+ return latest;
56620
+ }
56621
+ function renderHandoff(s3, full) {
56622
+ const lines = [];
56623
+ lines.push(`# billion-context session handoff`);
56624
+ lines.push("");
56625
+ lines.push(`- title: ${s3.meta.title ?? "(untitled)"}`);
56626
+ if (s3.meta.label) lines.push(`- label: ${s3.meta.label}`);
56627
+ lines.push(`- session id: ${s3.id}`);
56628
+ if (s3.meta.protocol) lines.push(`- protocol: ${s3.meta.protocol}`);
56629
+ if (s3.meta.upstreamOrigin) lines.push(`- upstream: ${s3.meta.upstreamOrigin}`);
56630
+ lines.push(`- requests: ${s3.stats.requests}`);
56631
+ if (s3.stats.contextTokens) lines.push(`- last context tokens: ~${s3.stats.contextTokens}`);
56632
+ lines.push(`- compression blocks: ${s3.state.blocks.length} (active ${s3.state.blocks.filter((b2) => b2.active).length})`);
56633
+ lines.push("");
56634
+ const messages = s3.lastMessages;
56635
+ if (messages && messages.length > 0) {
56636
+ lines.push(full ? `## Full conversation (${messages.length} messages)` : `## Conversation (folded view as the model saw it, ${messages.length} client messages)`);
56637
+ lines.push("");
56638
+ let lastRole = "";
56639
+ const view = full ? messages : prune(messages, s3.state);
56640
+ for (const m2 of view) {
56641
+ if (m2.role !== lastRole) {
56642
+ lines.push(`### ${m2.role}`);
56643
+ lines.push("");
56644
+ lastRole = m2.role;
56645
+ }
56646
+ lines.push(renderMessage2(m2));
56647
+ }
56648
+ lines.push("");
56649
+ return lines.join("\n");
56650
+ }
56651
+ const active = s3.state.blocks.filter((b2) => b2.active);
56652
+ if (active.length === 0) {
56653
+ lines.push("No active compression blocks and no persisted conversation snapshot (v2 session file). Original messages are only persisted when they are compressed into a block, so this session's conversation content is not available for export.");
56654
+ lines.push("");
56655
+ }
56656
+ for (const b2 of active) {
56657
+ lines.push(`## Block ${b2.blockId}${b2.topic ? ` \u2014 ${b2.topic}` : ""}`);
56658
+ lines.push("");
56659
+ lines.push(`tier ${b2.tier} \xB7 ~${b2.compressedTokens} tokens compressed \xB7 ${fmtDate(b2.createdAt)}`);
56660
+ lines.push("");
56661
+ lines.push(b2.summary.trim());
56662
+ lines.push("");
56663
+ const content = s3.blockContents.get(b2.blockId);
56664
+ if (full && content) {
56665
+ lines.push(`### Original messages (${content.full.count})`);
56666
+ lines.push("");
56667
+ lines.push(content.full.text.trim());
56668
+ lines.push("");
56669
+ }
56670
+ }
56671
+ if (active.length > 0) {
56672
+ lines.push("---");
56673
+ lines.push("");
56674
+ lines.push("Paste the block summaries above into a new session to continue without the proxy.");
56675
+ lines.push("");
56676
+ }
56677
+ return lines.join("\n");
56678
+ }
56679
+ function renderMessage2(m2) {
56680
+ const parts = [];
56681
+ switch (m2.contentType) {
56682
+ case "text":
56683
+ parts.push(m2.text ?? "");
56684
+ break;
56685
+ case "tool-call":
56686
+ parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` args: ${m2.text ?? ""}`);
56687
+ break;
56688
+ case "tool-result":
56689
+ parts.push(`\`${m2.toolName ?? "?"}(${m2.toolCallId ?? ""})\` \u2192 ${m2.text ?? ""}`);
56690
+ break;
56691
+ case "reasoning":
56692
+ parts.push(`_reasoning_: ${m2.text ?? ""}`);
56693
+ break;
56694
+ }
56695
+ const body = parts.join("\n").trim();
56696
+ return body === "" ? "_(empty)_" : body + "\n";
56697
+ }
56698
+ function matchSession(sessions2, selector) {
56699
+ const exact = sessions2.filter((s3) => s3.id === selector);
56700
+ if (exact.length > 0) return exact;
56701
+ const byLabel = sessions2.filter((s3) => s3.meta.label === selector);
56702
+ if (byLabel.length > 0) return byLabel;
56703
+ const byPrefix = sessions2.filter((s3) => s3.id.startsWith(selector) || (s3.meta.label ?? "").startsWith(selector));
56704
+ return byPrefix;
56705
+ }
56706
+ async function exportSession(selector, opts = {}) {
56707
+ const store = new SessionStore({ dir: opts.dir, enabled: true });
56708
+ const all = [...(await store.loadAll()).values()];
56709
+ if (all.length === 0) {
56710
+ return "No persisted sessions found. Sessions are written under the sessions directory once the proxy has served a request (compression state and compressed originals only \u2014 uncompressed conversation text is not persisted).";
56711
+ }
56712
+ if (!selector) {
56713
+ const list = await listSessions2(opts);
56714
+ const rows = list.map(
56715
+ (s3) => `${s3.id}${s3.label ? ` label=${s3.label}` : ""}${s3.protocol ? ` [${s3.protocol}]` : ""} blocks=${s3.blocks}${s3.contextTokens ? ` ctx~${s3.contextTokens}` : ""} ${s3.title ?? ""}`
56716
+ );
56717
+ return ["Persisted sessions:", "", ...rows.map((r) => ` ${r}`), "", "Usage: bili export <session-id|label> [--output handoff.md] [--full]"].join("\n");
56718
+ }
56719
+ const matches = matchSession(all, selector);
56720
+ if (matches.length === 0) {
56721
+ throw new Error(`no session matches "${selector}" (run "bili export" to list sessions)`);
56722
+ }
56723
+ if (matches.length > 1) {
56724
+ const ids = matches.map((s3) => s3.id).join(", ");
56725
+ throw new Error(`selector "${selector}" matches ${matches.length} sessions (${ids}); use the full session id`);
56726
+ }
56727
+ const markdown = renderHandoff(matches[0], opts.full ?? false);
56728
+ if (opts.output) {
56729
+ mkdirSync6(path10.dirname(path10.resolve(opts.output)), { recursive: true });
56730
+ writeFileSync5(opts.output, markdown, "utf8");
56731
+ return `written to ${opts.output}`;
56732
+ }
56733
+ return markdown;
56734
+ }
56735
+
56412
56736
  // src/cli.ts
56413
56737
  import { readFileSync as readFileSync5 } from "fs";
56414
56738
  import { fileURLToPath as fileURLToPath3 } from "url";
56415
- import path10 from "path";
56739
+ import path11 from "path";
56416
56740
  var VERSION = (() => {
56417
56741
  try {
56418
56742
  const here = fileURLToPath3(import.meta.url);
56419
- const pkg = path10.join(path10.dirname(here), "..", "package.json");
56743
+ const pkg = path11.join(path11.dirname(here), "..", "package.json");
56420
56744
  return JSON.parse(readFileSync5(pkg, "utf8")).version ?? "dev";
56421
56745
  } catch {
56422
56746
  return "dev";
@@ -56425,7 +56749,7 @@ var VERSION = (() => {
56425
56749
  var PACKAGE_NAME = (() => {
56426
56750
  try {
56427
56751
  const here = fileURLToPath3(import.meta.url);
56428
- const pkg = path10.join(path10.dirname(here), "..", "package.json");
56752
+ const pkg = path11.join(path11.dirname(here), "..", "package.json");
56429
56753
  return JSON.parse(readFileSync5(pkg, "utf8")).name ?? "billion-context";
56430
56754
  } catch {
56431
56755
  return "billion-context";
@@ -56440,6 +56764,8 @@ Usage:
56440
56764
  bili codex [opts --] [args] start a proxy + launch codex against it (cert-MITM)
56441
56765
  bili claude [opts --] [args] start a proxy + launch claude against it (cert-MITM)
56442
56766
  bili test pi non-polluting pi smoke test through the proxy
56767
+ bili export [session] [--full] list sessions / export one as a Markdown handoff
56768
+ (--full includes original messages; --output FILE)
56443
56769
  bili update check for & install a newer version now
56444
56770
  bili --version print version
56445
56771
  bili --help show this help
@@ -56482,6 +56808,9 @@ function parseArgs(argv) {
56482
56808
  let client;
56483
56809
  let clientArgs = [];
56484
56810
  const mitmDomains = [];
56811
+ let exportSelector;
56812
+ let exportOutput;
56813
+ let exportFull = false;
56485
56814
  for (let i = 0; i < argv.length; i++) {
56486
56815
  const a = argv[i];
56487
56816
  if (!client && positional.length === 0 && isLaunchClient(a)) {
@@ -56519,6 +56848,18 @@ function parseArgs(argv) {
56519
56848
  mitmDomains.push(val);
56520
56849
  break;
56521
56850
  }
56851
+ case "--full":
56852
+ exportFull = true;
56853
+ break;
56854
+ case "--output": {
56855
+ const val = argv[++i];
56856
+ if (val === void 0) {
56857
+ console.error(`bili: ${a} requires a value`);
56858
+ process.exit(2);
56859
+ }
56860
+ exportOutput = val;
56861
+ break;
56862
+ }
56522
56863
  case "--port":
56523
56864
  case "--host":
56524
56865
  case "--config": {
@@ -56554,6 +56895,9 @@ function parseArgs(argv) {
56554
56895
  command = command === "help" || command === "version" ? command : "start";
56555
56896
  } else if (cmd === "update") {
56556
56897
  command = "update";
56898
+ } else if (cmd === "export") {
56899
+ command = "export";
56900
+ exportSelector = positional[1];
56557
56901
  } else if (cmd === "test") {
56558
56902
  const target = positional[1];
56559
56903
  if (target && isLaunchClient(target)) {
@@ -56568,10 +56912,10 @@ function parseArgs(argv) {
56568
56912
  process.exit(2);
56569
56913
  }
56570
56914
  }
56571
- return { command, client, clientArgs, mitmDomains, overrides };
56915
+ return { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull };
56572
56916
  }
56573
56917
  async function main() {
56574
- const { command, client, clientArgs, mitmDomains, overrides } = parseArgs(process.argv.slice(2));
56918
+ const { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull } = parseArgs(process.argv.slice(2));
56575
56919
  if (command === "help") {
56576
56920
  process.stdout.write(HELP);
56577
56921
  return;
@@ -56580,6 +56924,16 @@ async function main() {
56580
56924
  process.stdout.write(VERSION + "\n");
56581
56925
  return;
56582
56926
  }
56927
+ if (command === "export") {
56928
+ try {
56929
+ const text = await exportSession(exportSelector, { output: exportOutput, full: exportFull });
56930
+ process.stdout.write(text + "\n");
56931
+ } catch (error) {
56932
+ console.error(`bili export: ${error instanceof Error ? error.message : String(error)}`);
56933
+ process.exit(1);
56934
+ }
56935
+ return;
56936
+ }
56583
56937
  if (command === "update") {
56584
56938
  await checkForUpdate({ packageName: PACKAGE_NAME, currentVersion: VERSION, autoUpdate: true }, true);
56585
56939
  return;