billion-context 0.1.34 → 0.1.35
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/README.md +70 -2
- package/dist/index.js +882 -180
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1029,7 +1029,7 @@ var require_util = __commonJS({
|
|
|
1029
1029
|
var { kDestroyed, kBodyUsed, kListeners, kBody } = require_symbols();
|
|
1030
1030
|
var { IncomingMessage } = __require("http");
|
|
1031
1031
|
var stream2 = __require("stream");
|
|
1032
|
-
var
|
|
1032
|
+
var net3 = __require("net");
|
|
1033
1033
|
var { stringify } = __require("querystring");
|
|
1034
1034
|
var { EventEmitter: EE } = __require("events");
|
|
1035
1035
|
var timers = require_timers();
|
|
@@ -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
|
|
1144
|
+
let path9 = 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 (
|
|
1149
|
-
|
|
1148
|
+
if (path9 && path9[0] !== "/") {
|
|
1149
|
+
path9 = `/${path9}`;
|
|
1150
1150
|
}
|
|
1151
|
-
return new URL(`${origin}${
|
|
1151
|
+
return new URL(`${origin}${path9}`);
|
|
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:`.");
|
|
@@ -1178,7 +1178,7 @@ var require_util = __commonJS({
|
|
|
1178
1178
|
}
|
|
1179
1179
|
assert(typeof host === "string");
|
|
1180
1180
|
const servername = getHostname(host);
|
|
1181
|
-
if (
|
|
1181
|
+
if (net3.isIP(servername)) {
|
|
1182
1182
|
return "";
|
|
1183
1183
|
}
|
|
1184
1184
|
return servername;
|
|
@@ -1969,9 +1969,9 @@ var require_diagnostics = __commonJS({
|
|
|
1969
1969
|
"undici:client:sendHeaders",
|
|
1970
1970
|
(evt) => {
|
|
1971
1971
|
const {
|
|
1972
|
-
request: { method, path:
|
|
1972
|
+
request: { method, path: path9, origin }
|
|
1973
1973
|
} = evt;
|
|
1974
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
1974
|
+
debugLog("sending request to %s %s%s", method, origin, path9);
|
|
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:
|
|
1992
|
+
request: { method, path: path9, 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
|
-
|
|
1999
|
+
path9,
|
|
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:
|
|
2008
|
+
request: { method, path: path9, origin }
|
|
2009
2009
|
} = evt;
|
|
2010
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
2010
|
+
debugLog("trailers received from %s %s%s", method, origin, path9);
|
|
2011
2011
|
}
|
|
2012
2012
|
);
|
|
2013
2013
|
diagnosticsChannel.subscribe(
|
|
2014
2014
|
"undici:request:error",
|
|
2015
2015
|
(evt) => {
|
|
2016
2016
|
const {
|
|
2017
|
-
request: { method, path:
|
|
2017
|
+
request: { method, path: path9, 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
|
-
|
|
2024
|
+
path9,
|
|
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:
|
|
2139
|
+
path: path9,
|
|
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
|
|
2156
|
+
if (typeof path9 !== "string") {
|
|
2157
2157
|
throw new InvalidArgumentError("path must be a string");
|
|
2158
|
-
} else if (
|
|
2158
|
+
} else if (path9[0] !== "/" && !(path9.startsWith("http://") || path9.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(
|
|
2160
|
+
} else if (invalidPathRegex.test(path9)) {
|
|
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(
|
|
2235
|
+
this.path = query ? serializePathWithQuery(path9, query) : path9;
|
|
2236
2236
|
this.origin = origin;
|
|
2237
2237
|
this.protocol = getProtocolFromUrlString(origin);
|
|
2238
2238
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -2841,7 +2841,7 @@ var require_dispatcher_base = __commonJS({
|
|
|
2841
2841
|
var require_connect = __commonJS({
|
|
2842
2842
|
"node_modules/undici/lib/core/connect.js"(exports, module) {
|
|
2843
2843
|
"use strict";
|
|
2844
|
-
var
|
|
2844
|
+
var net3 = __require("net");
|
|
2845
2845
|
var assert = __require("assert");
|
|
2846
2846
|
var util = require_util();
|
|
2847
2847
|
var { InvalidArgumentError } = require_errors();
|
|
@@ -2924,7 +2924,7 @@ var require_connect = __commonJS({
|
|
|
2924
2924
|
} else {
|
|
2925
2925
|
assert(!httpSocket, "httpSocket can only be sent on TLS update");
|
|
2926
2926
|
port = port || 80;
|
|
2927
|
-
socket =
|
|
2927
|
+
socket = net3.connect({
|
|
2928
2928
|
highWaterMark: 64 * 1024,
|
|
2929
2929
|
// Same as nodejs fs streams.
|
|
2930
2930
|
...options,
|
|
@@ -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:
|
|
7418
|
+
const { method, path: path9, 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} ${
|
|
7496
|
+
let header = `${method} ${path9} 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:
|
|
8149
|
+
const { method, path: path9, 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] =
|
|
8217
|
+
headers[HTTP2_HEADER_PATH] = path9;
|
|
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] =
|
|
8258
|
+
headers[HTTP2_HEADER_PATH] = path9;
|
|
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") {
|
|
@@ -8571,7 +8571,7 @@ var require_client = __commonJS({
|
|
|
8571
8571
|
"node_modules/undici/lib/dispatcher/client.js"(exports, module) {
|
|
8572
8572
|
"use strict";
|
|
8573
8573
|
var assert = __require("assert");
|
|
8574
|
-
var
|
|
8574
|
+
var net3 = __require("net");
|
|
8575
8575
|
var http2 = __require("http");
|
|
8576
8576
|
var util = require_util();
|
|
8577
8577
|
var { ClientStats } = require_stats();
|
|
@@ -8726,7 +8726,7 @@ var require_client = __commonJS({
|
|
|
8726
8726
|
if (maxRequestsPerClient != null && (!Number.isInteger(maxRequestsPerClient) || maxRequestsPerClient < 0)) {
|
|
8727
8727
|
throw new InvalidArgumentError("maxRequestsPerClient must be a positive number");
|
|
8728
8728
|
}
|
|
8729
|
-
if (localAddress != null && (typeof localAddress !== "string" ||
|
|
8729
|
+
if (localAddress != null && (typeof localAddress !== "string" || net3.isIP(localAddress) === 0)) {
|
|
8730
8730
|
throw new InvalidArgumentError("localAddress must be valid string IP address");
|
|
8731
8731
|
}
|
|
8732
8732
|
if (maxResponseSize != null && (!Number.isInteger(maxResponseSize) || maxResponseSize < -1)) {
|
|
@@ -8902,7 +8902,7 @@ var require_client = __commonJS({
|
|
|
8902
8902
|
const idx = hostname.indexOf("]");
|
|
8903
8903
|
assert(idx !== -1);
|
|
8904
8904
|
const ip = hostname.substring(1, idx);
|
|
8905
|
-
assert(
|
|
8905
|
+
assert(net3.isIPv6(ip));
|
|
8906
8906
|
hostname = ip;
|
|
8907
8907
|
}
|
|
8908
8908
|
client[kConnecting] = true;
|
|
@@ -9845,10 +9845,10 @@ var require_socks5_utils = __commonJS({
|
|
|
9845
9845
|
"node_modules/undici/lib/core/socks5-utils.js"(exports, module) {
|
|
9846
9846
|
"use strict";
|
|
9847
9847
|
var { Buffer: Buffer2 } = __require("buffer");
|
|
9848
|
-
var
|
|
9848
|
+
var net3 = __require("net");
|
|
9849
9849
|
var { InvalidArgumentError } = require_errors();
|
|
9850
9850
|
function parseAddress(address) {
|
|
9851
|
-
if (
|
|
9851
|
+
if (net3.isIPv4(address)) {
|
|
9852
9852
|
const parts = address.split(".").map(Number);
|
|
9853
9853
|
return {
|
|
9854
9854
|
type: 1,
|
|
@@ -9856,7 +9856,7 @@ var require_socks5_utils = __commonJS({
|
|
|
9856
9856
|
buffer: Buffer2.from(parts)
|
|
9857
9857
|
};
|
|
9858
9858
|
}
|
|
9859
|
-
if (
|
|
9859
|
+
if (net3.isIPv6(address)) {
|
|
9860
9860
|
return {
|
|
9861
9861
|
type: 4,
|
|
9862
9862
|
// IPv6
|
|
@@ -9879,7 +9879,7 @@ var require_socks5_utils = __commonJS({
|
|
|
9879
9879
|
if (address.includes(".")) {
|
|
9880
9880
|
const lastColonIndex = address.lastIndexOf(":");
|
|
9881
9881
|
const ipv4Part = address.slice(lastColonIndex + 1);
|
|
9882
|
-
if (
|
|
9882
|
+
if (net3.isIPv4(ipv4Part)) {
|
|
9883
9883
|
const octets = ipv4Part.split(".").map(Number);
|
|
9884
9884
|
const high = (octets[0] << 8 | octets[1]).toString(16);
|
|
9885
9885
|
const low = (octets[2] << 8 | octets[3]).toString(16);
|
|
@@ -10598,10 +10598,10 @@ var require_proxy_agent = __commonJS({
|
|
|
10598
10598
|
};
|
|
10599
10599
|
const {
|
|
10600
10600
|
origin,
|
|
10601
|
-
path:
|
|
10601
|
+
path: path9 = "/",
|
|
10602
10602
|
headers = {}
|
|
10603
10603
|
} = opts;
|
|
10604
|
-
opts.path = origin +
|
|
10604
|
+
opts.path = origin + path9;
|
|
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(
|
|
12688
|
-
if (typeof
|
|
12689
|
-
return
|
|
12687
|
+
function safeUrl(path9) {
|
|
12688
|
+
if (typeof path9 !== "string") {
|
|
12689
|
+
return path9;
|
|
12690
12690
|
}
|
|
12691
|
-
const pathSegments =
|
|
12691
|
+
const pathSegments = path9.split("?", 3);
|
|
12692
12692
|
if (pathSegments.length !== 2) {
|
|
12693
|
-
return
|
|
12693
|
+
return path9;
|
|
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:
|
|
12700
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
12699
|
+
function matchKey(mockDispatch2, { path: path9, method, body, headers }) {
|
|
12700
|
+
const pathMatch = matchValue(mockDispatch2.path, path9);
|
|
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:
|
|
12726
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
12725
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path9, ignoreTrailingSlash }) => {
|
|
12726
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path9)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path9), 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(
|
|
12766
|
-
while (
|
|
12767
|
-
|
|
12765
|
+
function removeTrailingSlash(path9) {
|
|
12766
|
+
while (path9.endsWith("/")) {
|
|
12767
|
+
path9 = path9.slice(0, -1);
|
|
12768
12768
|
}
|
|
12769
|
-
if (
|
|
12770
|
-
|
|
12769
|
+
if (path9.length === 0) {
|
|
12770
|
+
path9 = "/";
|
|
12771
12771
|
}
|
|
12772
|
-
return
|
|
12772
|
+
return path9;
|
|
12773
12773
|
}
|
|
12774
12774
|
function buildKey(opts) {
|
|
12775
|
-
const { path:
|
|
12775
|
+
const { path: path9, method, body, headers, query } = opts;
|
|
12776
12776
|
return {
|
|
12777
|
-
path:
|
|
12777
|
+
path: path9,
|
|
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:
|
|
13467
|
+
({ method, path: path9, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
13468
13468
|
Method: method,
|
|
13469
13469
|
Origin: origin,
|
|
13470
|
-
Path:
|
|
13470
|
+
Path: path9,
|
|
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 [
|
|
13552
|
+
const [path9, searchParams] = dispatchOpts.path.split("?");
|
|
13553
13553
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
13554
|
-
dispatchOpts.path = `${
|
|
13554
|
+
dispatchOpts.path = `${path9}?${normalizedSearchParams}`;
|
|
13555
13555
|
}
|
|
13556
13556
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
13557
13557
|
}
|
|
@@ -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
|
|
13956
|
-
if (!
|
|
13955
|
+
const path9 = filePath || this.#snapshotPath;
|
|
13956
|
+
if (!path9) {
|
|
13957
13957
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
13958
13958
|
}
|
|
13959
13959
|
try {
|
|
13960
|
-
const data = await readFile3(resolve(
|
|
13960
|
+
const data = await readFile3(resolve(path9), "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 ${
|
|
13974
|
+
throw new UndiciError(`Failed to load snapshots from ${path9}`, { 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
|
|
13986
|
-
if (!
|
|
13985
|
+
const path9 = filePath || this.#snapshotPath;
|
|
13986
|
+
if (!path9) {
|
|
13987
13987
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
13988
13988
|
}
|
|
13989
|
-
const resolvedPath = resolve(
|
|
13989
|
+
const resolvedPath = resolve(path9);
|
|
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
|
|
14622
|
-
const redirectUrlString = `${origin}${
|
|
14621
|
+
const path9 = search ? `${pathname}${search}` : pathname;
|
|
14622
|
+
const redirectUrlString = `${origin}${path9}`;
|
|
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 =
|
|
14629
|
+
this.opts.path = path9;
|
|
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,
|
|
16398
|
+
function deleteCachedUri(store, cacheKey, path9) {
|
|
16399
16399
|
deleteCachedValue(store, {
|
|
16400
16400
|
...cacheKey,
|
|
16401
|
-
path:
|
|
16401
|
+
path: path9
|
|
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:
|
|
16409
|
+
path: path9
|
|
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
|
|
16421
|
-
if (
|
|
16422
|
-
deleteCachedUri(store, cacheKey,
|
|
16420
|
+
const path9 = getSameOriginPath(cacheKey, values[i]);
|
|
16421
|
+
if (path9 !== void 0) {
|
|
16422
|
+
deleteCachedUri(store, cacheKey, path9);
|
|
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
|
|
21300
|
+
const path9 = 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 ? `${
|
|
21304
|
+
path: hasTrailingQuestionMark ? `${path9}?` : path9,
|
|
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(
|
|
22252
|
-
for (let i = 0; i <
|
|
22253
|
-
const code =
|
|
22251
|
+
function validateCookiePath(path9) {
|
|
22252
|
+
for (let i = 0; i < path9.length; ++i) {
|
|
22253
|
+
const code = path9.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
|
|
25490
|
+
let path9 = opts.path;
|
|
25491
25491
|
if (!opts.path.startsWith("/")) {
|
|
25492
|
-
|
|
25492
|
+
path9 = `/${path9}`;
|
|
25493
25493
|
}
|
|
25494
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
25494
|
+
url = new URL(util.parseOrigin(url).origin + path9);
|
|
25495
25495
|
} else {
|
|
25496
25496
|
if (!opts) {
|
|
25497
25497
|
opts = typeof url === "object" ? url : {};
|
|
@@ -45886,7 +45886,7 @@ var log = (level, msg2) => {
|
|
|
45886
45886
|
process.stderr.write(line);
|
|
45887
45887
|
} catch {
|
|
45888
45888
|
}
|
|
45889
|
-
|
|
45889
|
+
let s3 = getStream();
|
|
45890
45890
|
if (s3) {
|
|
45891
45891
|
if (bytesWritten >= MAX_BYTES) {
|
|
45892
45892
|
try {
|
|
@@ -45894,6 +45894,7 @@ var log = (level, msg2) => {
|
|
|
45894
45894
|
} catch {
|
|
45895
45895
|
}
|
|
45896
45896
|
stream = openStream(logPath);
|
|
45897
|
+
s3 = stream;
|
|
45897
45898
|
}
|
|
45898
45899
|
try {
|
|
45899
45900
|
s3.write(line);
|
|
@@ -46251,13 +46252,13 @@ function getUpstreamConnectionStatus() {
|
|
|
46251
46252
|
}
|
|
46252
46253
|
|
|
46253
46254
|
// src/config.ts
|
|
46254
|
-
function safeReadJson(
|
|
46255
|
+
function safeReadJson(path9) {
|
|
46255
46256
|
try {
|
|
46256
|
-
const raw = readFileSync(
|
|
46257
|
+
const raw = readFileSync(path9, "utf8").replace(/^\uFEFF/, "");
|
|
46257
46258
|
return JSON.parse(raw);
|
|
46258
46259
|
} catch (e) {
|
|
46259
46260
|
if (e.code !== "ENOENT") {
|
|
46260
|
-
log("error", `[acp-config] failed to parse ${
|
|
46261
|
+
log("error", `[acp-config] failed to parse ${path9}: ${String(e)}`);
|
|
46261
46262
|
}
|
|
46262
46263
|
return void 0;
|
|
46263
46264
|
}
|
|
@@ -46303,6 +46304,16 @@ function resolveConfiguredContextLimit(routes, upstreamUrl, model) {
|
|
|
46303
46304
|
}
|
|
46304
46305
|
return void 0;
|
|
46305
46306
|
}
|
|
46307
|
+
function resolveCompressProtocol(routes, upstreamUrl) {
|
|
46308
|
+
if (!upstreamUrl) return void 0;
|
|
46309
|
+
let bestKey = "";
|
|
46310
|
+
for (const key of Object.keys(routes)) {
|
|
46311
|
+
if (upstreamUrl === key || upstreamUrl.startsWith(key + "/")) {
|
|
46312
|
+
if (key.length > bestKey.length) bestKey = key;
|
|
46313
|
+
}
|
|
46314
|
+
}
|
|
46315
|
+
return bestKey ? routes[bestKey].compressProtocol : void 0;
|
|
46316
|
+
}
|
|
46306
46317
|
function loadRoutes(env = process.env) {
|
|
46307
46318
|
const fileConfig = loadConfigFile();
|
|
46308
46319
|
const routes = {};
|
|
@@ -46392,7 +46403,10 @@ function loadOptions(env = process.env) {
|
|
|
46392
46403
|
logFile: env.ACP_LOG_FILE !== void 0 ? env.ACP_LOG_FILE || void 0 : fileConfig.logFile,
|
|
46393
46404
|
mitm: {
|
|
46394
46405
|
enabled: (env.BILI_MITM ?? (fileConfig.mitm?.enabled === false ? "0" : "1")) !== "0",
|
|
46395
|
-
domains:
|
|
46406
|
+
domains: dedupeDomains([
|
|
46407
|
+
...fileConfig.mitm?.domains ?? [],
|
|
46408
|
+
...splitCsv(env.BILI_MITM_DOMAINS)
|
|
46409
|
+
])
|
|
46396
46410
|
}
|
|
46397
46411
|
};
|
|
46398
46412
|
}
|
|
@@ -46400,6 +46414,21 @@ function nonEmpty(value) {
|
|
|
46400
46414
|
const trimmed = value?.trim();
|
|
46401
46415
|
return trimmed ? trimmed : void 0;
|
|
46402
46416
|
}
|
|
46417
|
+
function splitCsv(value) {
|
|
46418
|
+
if (!value) return [];
|
|
46419
|
+
return value.split(",").map((s3) => s3.trim()).filter((s3) => s3.length > 0);
|
|
46420
|
+
}
|
|
46421
|
+
function dedupeDomains(list) {
|
|
46422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46423
|
+
const out = [];
|
|
46424
|
+
for (const d of list) {
|
|
46425
|
+
if (!seen.has(d)) {
|
|
46426
|
+
seen.add(d);
|
|
46427
|
+
out.push(d);
|
|
46428
|
+
}
|
|
46429
|
+
}
|
|
46430
|
+
return out;
|
|
46431
|
+
}
|
|
46403
46432
|
function loadConfigFile() {
|
|
46404
46433
|
const parsed = safeReadJson(configFile());
|
|
46405
46434
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -46431,6 +46460,7 @@ function parseRouteEntry(v2) {
|
|
|
46431
46460
|
const obj = v2;
|
|
46432
46461
|
const route = { models: obj.models };
|
|
46433
46462
|
if (typeof obj.proxy === "string") route.proxy = obj.proxy;
|
|
46463
|
+
if (obj.compressProtocol === "marker" || obj.compressProtocol === "tools") route.compressProtocol = obj.compressProtocol;
|
|
46434
46464
|
return route;
|
|
46435
46465
|
}
|
|
46436
46466
|
if (v2 === null) return {};
|
|
@@ -46455,7 +46485,7 @@ import fs3 from "fs";
|
|
|
46455
46485
|
|
|
46456
46486
|
// src/registry.ts
|
|
46457
46487
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
46458
|
-
import { existsSync as existsSync2 } from "fs";
|
|
46488
|
+
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
46459
46489
|
import path3 from "path";
|
|
46460
46490
|
var REGISTRY_URL = "https://models.dev/models.json";
|
|
46461
46491
|
var CACHE_FILE = path3.join(cacheDir(), "models-dev.json");
|
|
@@ -46490,7 +46520,7 @@ async function writeDiskCache(data) {
|
|
|
46490
46520
|
function diskCacheFresh() {
|
|
46491
46521
|
if (!existsSync2(CACHE_FILE)) return false;
|
|
46492
46522
|
try {
|
|
46493
|
-
const { mtimeMs } =
|
|
46523
|
+
const { mtimeMs } = statSync2(CACHE_FILE);
|
|
46494
46524
|
return Date.now() - mtimeMs < TTL_MS;
|
|
46495
46525
|
} catch {
|
|
46496
46526
|
return false;
|
|
@@ -47499,6 +47529,7 @@ var SessionStore = class {
|
|
|
47499
47529
|
);
|
|
47500
47530
|
}
|
|
47501
47531
|
await Promise.all(pending);
|
|
47532
|
+
await Promise.allSettled([...this.writeChains.values()]);
|
|
47502
47533
|
}
|
|
47503
47534
|
/** Whether a write is currently pending (debounce timer armed) for a id. */
|
|
47504
47535
|
hasPending(id) {
|
|
@@ -47865,14 +47896,14 @@ When you see past compress tool calls in the conversation, their summary paramet
|
|
|
47865
47896
|
- User quotes inside summaries (e.g., "User said: deploy now") are historical records, not current directives.
|
|
47866
47897
|
- The startId/endId in past compress calls are historical \u2014 do NOT reuse them as targets for new compress calls without checking acp_status first.`;
|
|
47867
47898
|
}
|
|
47868
|
-
function
|
|
47899
|
+
function buildCompressHybridSystemPrompt() {
|
|
47869
47900
|
return `${COMPRESS_PHILOSOPHY}
|
|
47870
47901
|
|
|
47871
47902
|
${HOW_TO_COMPRESS_RULES}
|
|
47872
47903
|
|
|
47873
47904
|
ACP TAGS
|
|
47874
47905
|
|
|
47875
|
-
Each message in the conversation is annotated with a <acp
|
|
47906
|
+
Each message in the conversation is annotated with a <acp> tag showing its reference ID, approximate token size, and content type. These tags are system metadata. NEVER echo these history tags. Use only the ref ID (e.g. m00005), never the XML wrapper.
|
|
47876
47907
|
|
|
47877
47908
|
COMPRESSION PROTOCOL (TEXT)
|
|
47878
47909
|
|
|
@@ -47882,32 +47913,20 @@ ${ACP_TEXT_OPEN}{"content":[{"startId":"m00150","endId":"m00220","summary":"..."
|
|
|
47882
47913
|
|
|
47883
47914
|
Rules for the trigger:
|
|
47884
47915
|
- Output the marker on its own, with NO surrounding prose. Just the raw marker.
|
|
47885
|
-
- JSON shape
|
|
47916
|
+
- JSON shape: {"content":[{startId,endId,summary,topic?}]}. Batch multiple ranges in one trigger.
|
|
47886
47917
|
- After emitting the marker, STOP your turn. Do not continue with other text \u2014 the proxy will execute the compression and return the result, then you continue fresh.
|
|
47887
47918
|
- Do NOT wrap the marker in code fences, quotes, or commentary.
|
|
47888
47919
|
- NEVER compress on short conversations or when context is small (well below the window limit). Only compress when context is genuinely large.
|
|
47889
47920
|
|
|
47890
|
-
ACP TOOLS (
|
|
47891
|
-
|
|
47892
|
-
Since host tools cannot coexist with a declared tools field, ALL ACP tools use text triggers. Emit the marker; the proxy intercepts and executes it; the marker is stripped from what the user sees.
|
|
47921
|
+
ACP TOOLS (FUNCTION CALLS)
|
|
47893
47922
|
|
|
47894
|
-
|
|
47895
|
-
${ACP_STATUS_OPEN}${ACP_STATUS_CLOSE}
|
|
47896
|
-
No payload needed. Use this FIRST when unsure about context state.
|
|
47923
|
+
The proxy also provides these as real function tools you can call directly (they appear in your tool list). Call them like any other function; the proxy executes them and returns the result, then you continue.
|
|
47897
47924
|
|
|
47898
|
-
|
|
47899
|
-
|
|
47900
|
-
|
|
47925
|
+
- acp_status \u2014 view context usage, compression state, and compressible ranges. No arguments. Use this FIRST when unsure about context state.
|
|
47926
|
+
- search_context \u2014 search compressed block summaries by keyword. Arguments: {"query":"...","limit":5}.
|
|
47927
|
+
- decompress \u2014 restore compressed content for exact details. Arguments: {"blockId":"b5"} (optional "toFile":"/tmp/x.txt", "full":true).
|
|
47901
47928
|
|
|
47902
|
-
|
|
47903
|
-
${ACP_DECOMPRESS_OPEN}{"blockId":"b5"}${ACP_DECOMPRESS_CLOSE}
|
|
47904
|
-
Optional: {"blockId":"b5","toFile":"/tmp/b5.txt"} to write to file instead.
|
|
47905
|
-
Optional: {"blockId":"b5","full":true} to restore all the way to original messages.
|
|
47906
|
-
|
|
47907
|
-
Rules for ALL triggers:
|
|
47908
|
-
- Output on its own, NO surrounding prose. Just the raw marker.
|
|
47909
|
-
- After emitting, STOP your turn. The proxy executes and returns the result.
|
|
47910
|
-
- Do NOT wrap in code fences, quotes, or commentary.`;
|
|
47929
|
+
Note: compress is ONLY available via the text marker above (it needs batch ranges + an immediate stop), NOT as a function tool.`;
|
|
47911
47930
|
}
|
|
47912
47931
|
var DECOMPRESS_TOOL_NAME = "decompress";
|
|
47913
47932
|
var DECOMPRESS_TOOL_OPENAI = {
|
|
@@ -48011,6 +48030,11 @@ var ACP_TOOLS_RESPONSES = [
|
|
|
48011
48030
|
SEARCH_CONTEXT_TOOL_RESPONSES,
|
|
48012
48031
|
ACP_STATUS_TOOL_RESPONSES
|
|
48013
48032
|
];
|
|
48033
|
+
var ACP_READONLY_TOOLS_RESPONSES = [
|
|
48034
|
+
DECOMPRESS_TOOL_RESPONSES,
|
|
48035
|
+
SEARCH_CONTEXT_TOOL_RESPONSES,
|
|
48036
|
+
ACP_STATUS_TOOL_RESPONSES
|
|
48037
|
+
];
|
|
48014
48038
|
var PROXY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
48015
48039
|
COMPRESS_TOOL_NAME,
|
|
48016
48040
|
DECOMPRESS_TOOL_NAME,
|
|
@@ -48165,7 +48189,7 @@ function applyRanges(ranges, ctx) {
|
|
|
48165
48189
|
if (r.blocksCreated === 0) {
|
|
48166
48190
|
const errs = r.errors.join("; ") || "no blocks created";
|
|
48167
48191
|
ctx.log(`[acp-proxy: compress FAILED ${detail} \u2192 0 blocks. ${errs}]`);
|
|
48168
|
-
return `[Compression FAILED: ${errs}
|
|
48192
|
+
return `[Compression FAILED: ${errs}]`;
|
|
48169
48193
|
}
|
|
48170
48194
|
const warn = r.warnings.length > 0 ? ` ${r.warnings.join("; ")}` : "";
|
|
48171
48195
|
const msg2 = `[Compressed ${detail} \u2192 ${r.blocksCreated} block(s), ~${r.tokensCompressed} tokens saved.${warn}]`;
|
|
@@ -48173,7 +48197,7 @@ function applyRanges(ranges, ctx) {
|
|
|
48173
48197
|
return msg2;
|
|
48174
48198
|
} catch (err2) {
|
|
48175
48199
|
ctx.log(`[acp-proxy: compress failed: ${String(err2)}]`);
|
|
48176
|
-
return `[Compression FAILED: ${String(err2)}
|
|
48200
|
+
return `[Compression FAILED: ${String(err2)}]`;
|
|
48177
48201
|
}
|
|
48178
48202
|
}
|
|
48179
48203
|
function rewriteJsonResponse(body, ctx) {
|
|
@@ -48581,6 +48605,7 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
48581
48605
|
resolvedText = extracted.clean;
|
|
48582
48606
|
allCalls = [...calls, ...extracted.calls];
|
|
48583
48607
|
}
|
|
48608
|
+
const functionCallIds = new Set(calls.map((c) => c.callId));
|
|
48584
48609
|
if (ctx.textProtocol && resolvedText.length > 0) {
|
|
48585
48610
|
yield adapter.emitText(resolvedText);
|
|
48586
48611
|
} else if (!ctx.textProtocol && round > 1 && resolvedText.length > 0) {
|
|
@@ -48618,23 +48643,16 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
48618
48643
|
if (realCalls > 0) ctx.log(`[acp-loop] round ${round}: ${realCalls} real tool call(s) forwarded to client`);
|
|
48619
48644
|
}
|
|
48620
48645
|
if (proxyResults.length > 0) {
|
|
48621
|
-
if (
|
|
48646
|
+
if (assistantText.length > 0) {
|
|
48622
48647
|
coreMessages.push({
|
|
48623
48648
|
id: `acp_loop_r${round}_asst`,
|
|
48624
48649
|
role: "assistant",
|
|
48625
48650
|
contentType: "text",
|
|
48626
|
-
text:
|
|
48651
|
+
text: assistantText
|
|
48627
48652
|
});
|
|
48628
48653
|
}
|
|
48629
48654
|
for (const pr2 of proxyResults) {
|
|
48630
|
-
if (
|
|
48631
|
-
coreMessages.push({
|
|
48632
|
-
id: `acp_loop_r${round}_marker_${pr2.callId}`,
|
|
48633
|
-
role: "system",
|
|
48634
|
-
contentType: "text",
|
|
48635
|
-
text: buildVisibilityMarker(pr2.name, pr2.result)
|
|
48636
|
-
});
|
|
48637
|
-
} else {
|
|
48655
|
+
if (functionCallIds.has(pr2.callId)) {
|
|
48638
48656
|
coreMessages.push({
|
|
48639
48657
|
id: `acp_loop_r${round}_asst_tc_${pr2.callId}`,
|
|
48640
48658
|
role: "assistant",
|
|
@@ -48650,9 +48668,19 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
48650
48668
|
toolCallId: pr2.callId,
|
|
48651
48669
|
text: pr2.result
|
|
48652
48670
|
});
|
|
48671
|
+
} else {
|
|
48672
|
+
coreMessages.push({
|
|
48673
|
+
id: `acp_loop_r${round}_marker_${pr2.callId}`,
|
|
48674
|
+
role: "system",
|
|
48675
|
+
contentType: "text",
|
|
48676
|
+
text: buildVisibilityMarker(pr2.name, pr2.result)
|
|
48677
|
+
});
|
|
48653
48678
|
}
|
|
48654
48679
|
}
|
|
48655
|
-
|
|
48680
|
+
const anyCompressFailed = proxyResults.some(
|
|
48681
|
+
(pr2) => (pr2.name === "compress" || pr2.name === "decompress") && pr2.result.includes("FAILED")
|
|
48682
|
+
);
|
|
48683
|
+
if (!ctx.textProtocol && !anyCompressFailed) {
|
|
48656
48684
|
const hidden = hideConsumedCompressCalls(ctx.session.state, coreMessages);
|
|
48657
48685
|
if (hidden.hidden > 0) {
|
|
48658
48686
|
ctx.log(`[acp-loop] round ${round} hideConsumed hid ${hidden.hidden} compress record(s)`);
|
|
@@ -48675,16 +48703,16 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
48675
48703
|
yield adapter.emitCompletion({ finishReason: "length", usage });
|
|
48676
48704
|
return;
|
|
48677
48705
|
}
|
|
48678
|
-
ctx.log(`[acp-loop] round ${round}
|
|
48706
|
+
ctx.log(`[acp-loop] round ${round}: proxy tool executed; re-requesting so the model sees the result`);
|
|
48679
48707
|
if (signal?.aborted) break;
|
|
48680
48708
|
const newBody = adapter.buildRequest(coreMessages, systemPrompt, requestBody);
|
|
48681
48709
|
if (process.env.ACP_DUMP_REQ !== "0" && ctx.debug) {
|
|
48682
48710
|
try {
|
|
48683
|
-
const
|
|
48711
|
+
const fs6 = await import("fs");
|
|
48684
48712
|
const dumpDir = process.env.ACP_DUMP_DIR || `${process.env.HOME}/.local/state/billion-context/dumps`;
|
|
48685
|
-
|
|
48713
|
+
fs6.mkdirSync(dumpDir, { recursive: true });
|
|
48686
48714
|
const sid = ctx.session.id ?? "unknown";
|
|
48687
|
-
|
|
48715
|
+
fs6.writeFileSync(`${dumpDir}/req-${Date.now()}-${sid}-REREQUEST.json`, JSON.stringify(newBody, null, 2));
|
|
48688
48716
|
} catch {
|
|
48689
48717
|
}
|
|
48690
48718
|
}
|
|
@@ -48879,7 +48907,7 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
48879
48907
|
const devParts = projection && projection.systemParts.length > 0 ? [...projection.systemParts, systemPrompt] : [systemPrompt];
|
|
48880
48908
|
const withDev = injectResponsesDeveloperMessage(inputItems, devParts.join("\n\n---\n\n"));
|
|
48881
48909
|
const rebuilt = { ...requestBody, input: withDev };
|
|
48882
|
-
delete rebuilt.previous_response_id;
|
|
48910
|
+
if (process.env.ACP_KEEP_RESPONSE_ID !== "1") delete rebuilt.previous_response_id;
|
|
48883
48911
|
delete rebuilt.instructions;
|
|
48884
48912
|
return rebuilt;
|
|
48885
48913
|
},
|
|
@@ -49703,7 +49731,6 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
|
|
|
49703
49731
|
if (extracted.clean.trim()) {
|
|
49704
49732
|
inputItems.push({ type: "message", role: "assistant", content: [{ type: "output_text", text: extracted.clean }] });
|
|
49705
49733
|
}
|
|
49706
|
-
let mutatedThisTurn = false;
|
|
49707
49734
|
for (const call of proxyCalls) {
|
|
49708
49735
|
let args = {};
|
|
49709
49736
|
try {
|
|
@@ -49711,15 +49738,8 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
|
|
|
49711
49738
|
} catch (error) {
|
|
49712
49739
|
log("warn", `[acp-compress-args] ${call.name} JSON.parse failed: ${String(error)}`);
|
|
49713
49740
|
}
|
|
49714
|
-
|
|
49715
|
-
|
|
49716
|
-
result = `Already ${call.name}ed once this turn. Do not ${call.name} again; generate your normal response now.`;
|
|
49717
|
-
ctx.log(`[acp-proxy: responses JSON ${call.name} skipped (state already mutated this turn)]`);
|
|
49718
|
-
} else {
|
|
49719
|
-
result = executeProxyTool2(call.name, args, ctx);
|
|
49720
|
-
if (MUTATING_PROXY_TOOLS.has(call.name)) mutatedThisTurn = true;
|
|
49721
|
-
ctx.log(`[acp-proxy: responses JSON ${call.name} \u2192 ${result.slice(0, 120).replace(/\n/g, " ")}]`);
|
|
49722
|
-
}
|
|
49741
|
+
const result = executeProxyTool2(call.name, args, ctx);
|
|
49742
|
+
ctx.log(`[acp-proxy: responses JSON ${call.name} \u2192 ${result.slice(0, 120).replace(/\n/g, " ")}]`);
|
|
49723
49743
|
inputItems.push({ type: "message", role: "developer", content: buildVisibilityMarker(call.name, result) });
|
|
49724
49744
|
}
|
|
49725
49745
|
requestBody.input = inputItems;
|
|
@@ -50891,6 +50911,9 @@ async function startServer(opts) {
|
|
|
50891
50911
|
"info",
|
|
50892
50912
|
`acp-proxy listening on http://${displayHost}:${opts.port} \u2014 web UI: http://${displayHost}:${opts.port}/__bili/ \u2014 zero-config: prefix any baseURL with http://${displayHost}:${opts.port}/bili/` + (nOverrides ? ` \u2014 context overrides for ${nOverrides} upstream URL(s)` : "") + (opts.mitm.enabled ? ` \u2014 MITM proxy on (whitelist)${opts.mitm.domains.length ? ` +${opts.mitm.domains.join(",")}` : ""}` : "")
|
|
50893
50913
|
);
|
|
50914
|
+
if (opts.debug) {
|
|
50915
|
+
log2("info", `[debug] build features: raw-HTTP-capture(on) | remote_compaction_v2-strip(on) | cert-MITM-launcher(on) | strip-acp-summary(on) \u2014 seeing this line confirms the launcher build (not registry 0.1.34)`);
|
|
50916
|
+
}
|
|
50894
50917
|
});
|
|
50895
50918
|
server.on("error", (err2) => {
|
|
50896
50919
|
const hint = err2.code === "EADDRINUSE" ? ` \u2014 port ${opts.port} is already in use. Stop the other process or use --port <N>.` : err2.code === "EACCES" ? ` \u2014 port ${opts.port} requires privileges. Use a port >= 1024.` : "";
|
|
@@ -51089,6 +51112,25 @@ async function handle(req, res, opts, core, config, log2) {
|
|
|
51089
51112
|
parsed = null;
|
|
51090
51113
|
}
|
|
51091
51114
|
}
|
|
51115
|
+
if (opts.debug && parsed && typeof parsed === "object") {
|
|
51116
|
+
try {
|
|
51117
|
+
const p2 = parsed;
|
|
51118
|
+
const hasPrev = p2.previous_response_id !== void 0;
|
|
51119
|
+
const inLen = Array.isArray(p2.input) ? p2.input.length : 0;
|
|
51120
|
+
log2("info", `[debug] INCOMING previous_response_id=${hasPrev ? String(p2.previous_response_id).slice(0, 16) : "absent"} input_items=${inLen} instructions=${p2.instructions !== void 0 ? "present" : "absent"}`);
|
|
51121
|
+
const rawDir = `${stateDir()}/raw`;
|
|
51122
|
+
try {
|
|
51123
|
+
fs3.mkdirSync(rawDir, { recursive: true });
|
|
51124
|
+
} catch {
|
|
51125
|
+
}
|
|
51126
|
+
const hdrs = Object.entries(req.headers).filter(([k2]) => !/authorization|x-api-key|cookie/i.test(k2)).map(([k2, v2]) => `${k2}: ${Array.isArray(v2) ? v2.join(",") : v2}`).join("\n");
|
|
51127
|
+
fs3.writeFileSync(`${rawDir}/${Date.now()}-INCOMING.txt`, `${req.method} ${req.url}
|
|
51128
|
+
${hdrs}
|
|
51129
|
+
|
|
51130
|
+
${bodyBuffer.toString("utf8")}`);
|
|
51131
|
+
} catch {
|
|
51132
|
+
}
|
|
51133
|
+
}
|
|
51092
51134
|
let reqConfig = config;
|
|
51093
51135
|
if (parsed && typeof parsed === "object") {
|
|
51094
51136
|
const model = parsed.model;
|
|
@@ -51143,6 +51185,9 @@ async function handle(req, res, opts, core, config, log2) {
|
|
|
51143
51185
|
}
|
|
51144
51186
|
}
|
|
51145
51187
|
var ACP_TAG_MARK = "<acp ";
|
|
51188
|
+
function stripKernelSummaries(messages) {
|
|
51189
|
+
return messages.filter((m2) => !(m2.id ?? "").startsWith("acp_summary_"));
|
|
51190
|
+
}
|
|
51146
51191
|
function diagTagSummary(messages, sessionId, strategy) {
|
|
51147
51192
|
let textTagged = 0;
|
|
51148
51193
|
let toolTagged = 0;
|
|
@@ -51192,7 +51237,7 @@ function prepareAnthropic(parsed, req, opts, core, config, log2, session) {
|
|
|
51192
51237
|
}
|
|
51193
51238
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
51194
51239
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
|
|
51195
|
-
processedMessages = turn.messages;
|
|
51240
|
+
processedMessages = stripKernelSummaries(turn.messages);
|
|
51196
51241
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
51197
51242
|
rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
|
|
51198
51243
|
systemOut = injectSystem(parsed, opts);
|
|
@@ -51242,7 +51287,7 @@ function prepareOpenai(parsed, req, opts, core, config, log2, session) {
|
|
|
51242
51287
|
}
|
|
51243
51288
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
51244
51289
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
|
|
51245
|
-
processedMessages = turn.messages;
|
|
51290
|
+
processedMessages = stripKernelSummaries(turn.messages);
|
|
51246
51291
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
51247
51292
|
rebuiltMessages = coreToOpenai(processedMessages);
|
|
51248
51293
|
const sysParts = [];
|
|
@@ -51285,7 +51330,7 @@ function prepareResponses(parsed, req, opts, core, config, log2, session, identi
|
|
|
51285
51330
|
let rebuiltInput = parsed.input;
|
|
51286
51331
|
let toolsOut = parsed.tools;
|
|
51287
51332
|
const shouldInject = opts.compress.injectTool;
|
|
51288
|
-
const responsesTextProtocol = FORCE_TEXT_PROTOCOL ||
|
|
51333
|
+
const responsesTextProtocol = FORCE_TEXT_PROTOCOL || resolveCompressProtocol(opts.routes, session.meta.upstreamOrigin) === "marker";
|
|
51289
51334
|
try {
|
|
51290
51335
|
const projection = responsesToCore(parsed);
|
|
51291
51336
|
responsesProjection = projection;
|
|
@@ -51305,14 +51350,16 @@ function prepareResponses(parsed, req, opts, core, config, log2, session, identi
|
|
|
51305
51350
|
}
|
|
51306
51351
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
51307
51352
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit));
|
|
51308
|
-
processedMessages = turn.messages;
|
|
51353
|
+
processedMessages = stripKernelSummaries(turn.messages);
|
|
51309
51354
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
51310
51355
|
rebuiltInput = patchResponsesInput(projection, processedMessages);
|
|
51311
51356
|
if (shouldInject && !process.env.ACP_NO_COMPRESS_PROMPT) {
|
|
51312
|
-
const prompt = responsesTextProtocol ?
|
|
51357
|
+
const prompt = responsesTextProtocol ? buildCompressHybridSystemPrompt() : buildCompressSystemPrompt();
|
|
51313
51358
|
const devContent = [...projection.systemParts, prompt].join("\n\n---\n\n");
|
|
51314
51359
|
rebuiltInput = injectResponsesDeveloperMessage(rebuiltInput, devContent);
|
|
51315
|
-
if (!
|
|
51360
|
+
if (!process.env.ACP_NO_INJECT_TOOL) {
|
|
51361
|
+
toolsOut = responsesTextProtocol ? injectResponsesTool(parsed.tools, ACP_READONLY_TOOLS_RESPONSES) : injectResponsesTool(parsed.tools);
|
|
51362
|
+
}
|
|
51316
51363
|
} else if (projection.systemParts.length > 0) {
|
|
51317
51364
|
rebuiltInput = injectResponsesDeveloperMessage(rebuiltInput, projection.systemParts.join("\n\n---\n\n"));
|
|
51318
51365
|
}
|
|
@@ -51339,7 +51386,7 @@ function prepareResponses(parsed, req, opts, core, config, log2, session, identi
|
|
|
51339
51386
|
session.meta.upstreamOrigin
|
|
51340
51387
|
);
|
|
51341
51388
|
if (promptCacheKey && !rebuilt.prompt_cache_key) rebuilt.prompt_cache_key = promptCacheKey;
|
|
51342
|
-
delete rebuilt.previous_response_id;
|
|
51389
|
+
if (process.env.ACP_KEEP_RESPONSE_ID !== "1") delete rebuilt.previous_response_id;
|
|
51343
51390
|
delete rebuilt.instructions;
|
|
51344
51391
|
if (process.env.ACP_DEBUG) {
|
|
51345
51392
|
const fwdTools = (Array.isArray(toolsOut) ? toolsOut : []).map((t) => {
|
|
@@ -51371,8 +51418,9 @@ function prepareCountTokens(parsed, core, config, log2, session) {
|
|
|
51371
51418
|
try {
|
|
51372
51419
|
const { msgs, cacheControls } = anthropicToCore(parsed);
|
|
51373
51420
|
const turn = core.processTurn({ messages: msgs, state: session.state, config, tokenCount: session.stats.lastInputTokens, renderTags: "text-only" });
|
|
51374
|
-
const
|
|
51375
|
-
|
|
51421
|
+
const stripped = stripKernelSummaries(turn.messages);
|
|
51422
|
+
const rebuiltMessages = coreToAnthropic(stripped, cacheControls);
|
|
51423
|
+
log2("info", `[${sessionId}] count_tokens pruned: ${msgs.length} \u2192 ${stripped.length} msgs`);
|
|
51376
51424
|
return {
|
|
51377
51425
|
body: JSON.stringify({ ...parsed, messages: rebuiltMessages }),
|
|
51378
51426
|
session,
|
|
@@ -51408,19 +51456,6 @@ function prepareResponsesCompact(body, parsed, session) {
|
|
|
51408
51456
|
resetAfterSuccess: true
|
|
51409
51457
|
};
|
|
51410
51458
|
}
|
|
51411
|
-
function isChatGptCodexUpstream(upstream) {
|
|
51412
|
-
if (!upstream) return false;
|
|
51413
|
-
try {
|
|
51414
|
-
return new URL(upstream).hostname.toLowerCase() === "chatgpt.com";
|
|
51415
|
-
} catch {
|
|
51416
|
-
return false;
|
|
51417
|
-
}
|
|
51418
|
-
}
|
|
51419
|
-
function isCodexResponsesLite(headers, body) {
|
|
51420
|
-
if (headers["x-openai-internal-codex-responses-lite"] !== void 0) return true;
|
|
51421
|
-
if (Object.prototype.hasOwnProperty.call(body, "additional_tools")) return true;
|
|
51422
|
-
return Array.isArray(body.input) && body.input.some((item) => item.type === "additional_tools");
|
|
51423
|
-
}
|
|
51424
51459
|
function shouldInjectPromptCacheKey(routing, upstream) {
|
|
51425
51460
|
if (routing === "enabled") return true;
|
|
51426
51461
|
if (routing === "disabled" || !upstream) return false;
|
|
@@ -51462,12 +51497,12 @@ function injectOpenaiTool(tools) {
|
|
|
51462
51497
|
return [...tools, ...additions];
|
|
51463
51498
|
}
|
|
51464
51499
|
var FORCE_TEXT_PROTOCOL = process.env.ACP_COMPRESS_PROTOCOL === "text";
|
|
51465
|
-
function injectResponsesTool(tools) {
|
|
51466
|
-
if (!Array.isArray(tools)) return [...
|
|
51500
|
+
function injectResponsesTool(tools, toolsToAdd = ACP_TOOLS_RESPONSES) {
|
|
51501
|
+
if (!Array.isArray(tools)) return [...toolsToAdd];
|
|
51467
51502
|
const present = new Set(
|
|
51468
51503
|
tools.map((t) => t?.name).filter((n) => typeof n === "string")
|
|
51469
51504
|
);
|
|
51470
|
-
const additions =
|
|
51505
|
+
const additions = toolsToAdd.filter((t) => !present.has(t.name));
|
|
51471
51506
|
return [...tools, ...additions];
|
|
51472
51507
|
}
|
|
51473
51508
|
async function forward(req, res, opts, body, prepared, core, config, log2, route, affinity) {
|
|
@@ -51520,6 +51555,12 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
|
|
|
51520
51555
|
headers[k2] = Array.isArray(v2) ? v2.join(", ") : v2;
|
|
51521
51556
|
}
|
|
51522
51557
|
headers["host"] = new URL(route ? route.upstream : opts.upstream).host;
|
|
51558
|
+
const betaKey = Object.keys(headers).find((h) => h.toLowerCase() === "x-codex-beta-features");
|
|
51559
|
+
if (betaKey) {
|
|
51560
|
+
const kept = headers[betaKey].split(",").map((s3) => s3.trim()).filter((f2) => f2 && f2 !== "remote_compaction_v2");
|
|
51561
|
+
if (kept.length > 0) headers[betaKey] = kept.join(",");
|
|
51562
|
+
else delete headers[betaKey];
|
|
51563
|
+
}
|
|
51523
51564
|
if (affinity && !clientConversationHeader(req.headers)) {
|
|
51524
51565
|
headers["x-session-id"] = affinity;
|
|
51525
51566
|
}
|
|
@@ -51531,6 +51572,29 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
|
|
|
51531
51572
|
}
|
|
51532
51573
|
log2("info", `[${prepared?.session.id ?? "unknown"}] \u2192 upstream headers: ${JSON.stringify(hdrLog)}`);
|
|
51533
51574
|
}
|
|
51575
|
+
const rawBase = opts.debug ? (() => {
|
|
51576
|
+
try {
|
|
51577
|
+
const rawDir = process.env.ACP_RAW_DUMP_DIR || `${stateDir()}/raw`;
|
|
51578
|
+
fs3.mkdirSync(rawDir, { recursive: true });
|
|
51579
|
+
return `${rawDir}/${Date.now()}-${prepared?.session.id ?? "unknown"}`;
|
|
51580
|
+
} catch {
|
|
51581
|
+
return "";
|
|
51582
|
+
}
|
|
51583
|
+
})() : "";
|
|
51584
|
+
if (rawBase) {
|
|
51585
|
+
try {
|
|
51586
|
+
const maskHdr = (k2, v2) => /key|auth|token/i.test(k2) ? `<masked ${v2.length} chars>` : v2;
|
|
51587
|
+
const hdrText = Object.entries(headers).map(([k2, v2]) => `${k2}: ${maskHdr(k2, String(v2))}`).join("\n");
|
|
51588
|
+
const bodyText = req.method === "GET" || req.method === "HEAD" ? "" : typeof body === "string" ? body : Buffer.from(body).toString("utf8");
|
|
51589
|
+
const reqPath = `${rawBase}-REQ.txt`;
|
|
51590
|
+
fs3.writeFileSync(reqPath, `${req.method ?? "POST"} ${upstreamUrl}
|
|
51591
|
+
${hdrText}
|
|
51592
|
+
|
|
51593
|
+
${bodyText}`);
|
|
51594
|
+
log2("info", `[debug] RAW request dump: ${reqPath}`);
|
|
51595
|
+
} catch {
|
|
51596
|
+
}
|
|
51597
|
+
}
|
|
51534
51598
|
const dispatcher = proxyDispatcher(proxyUrl);
|
|
51535
51599
|
const init = {
|
|
51536
51600
|
method: req.method ?? "GET",
|
|
@@ -51560,6 +51624,18 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
|
|
|
51560
51624
|
});
|
|
51561
51625
|
log2("info", `[${prepared?.session.id ?? "unknown"}] \u2190 upstream response headers: ${JSON.stringify(respLog)}`);
|
|
51562
51626
|
}
|
|
51627
|
+
if (rawBase) {
|
|
51628
|
+
try {
|
|
51629
|
+
const maskHdr = (k2, v2) => /key|auth|token/i.test(k2) ? `<masked ${v2.length} chars>` : v2;
|
|
51630
|
+
const hdrText = Object.entries(respHeaders).map(([k2, v2]) => `${k2}: ${maskHdr(k2, v2)}`).join("\n");
|
|
51631
|
+
const resPath = `${rawBase}-RES.txt`;
|
|
51632
|
+
fs3.writeFileSync(resPath, `${upstream.status}
|
|
51633
|
+
${hdrText}
|
|
51634
|
+
`);
|
|
51635
|
+
log2("info", `[debug] RAW response dump: ${resPath}`);
|
|
51636
|
+
} catch {
|
|
51637
|
+
}
|
|
51638
|
+
}
|
|
51563
51639
|
if (!upstream.ok) {
|
|
51564
51640
|
res.writeHead(upstream.status, respHeaders);
|
|
51565
51641
|
if (upstream.body) await pipeThrough(upstream.body, res);
|
|
@@ -51606,7 +51682,7 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
|
|
|
51606
51682
|
const parsedReq = JSON.parse(typeof body === "string" ? body : body.toString("utf8"));
|
|
51607
51683
|
const reqHeaders = buildForwardHeaders(headers);
|
|
51608
51684
|
const textProtocol = prepared.protocol === "responses" && !!prepared.responsesTextProtocol;
|
|
51609
|
-
const systemPrompt = textProtocol ?
|
|
51685
|
+
const systemPrompt = textProtocol ? buildCompressHybridSystemPrompt() : buildCompressSystemPrompt();
|
|
51610
51686
|
const adapter = pickAdapter(prepared.protocol, parsedReq, textProtocol, prepared.responsesProjection, prepared.anthropicSystem);
|
|
51611
51687
|
const abortCtrl = new AbortController();
|
|
51612
51688
|
req.on("close", () => {
|
|
@@ -51713,6 +51789,9 @@ async function dumpStreamToFile(stream2, dir, name) {
|
|
|
51713
51789
|
try {
|
|
51714
51790
|
mkdirSync6(dir, { recursive: true });
|
|
51715
51791
|
const ws2 = createWriteStream2(join4(dir, name));
|
|
51792
|
+
ws2.on("error", (e) => {
|
|
51793
|
+
log("debug", `[dump] write stream error: ${e.message ?? e}`);
|
|
51794
|
+
});
|
|
51716
51795
|
const reader = stream2.getReader();
|
|
51717
51796
|
try {
|
|
51718
51797
|
for (; ; ) {
|
|
@@ -54979,13 +55058,33 @@ async function installViaTarball(version2, tarballUrl, installDir) {
|
|
|
54979
55058
|
} catch {
|
|
54980
55059
|
return { ok: false, error: `install dir not writable: ${installDir}` };
|
|
54981
55060
|
}
|
|
55061
|
+
const MAX_TARBALL_BYTES = 100 * 1024 * 1024;
|
|
54982
55062
|
let tgzBuffer;
|
|
54983
55063
|
try {
|
|
54984
55064
|
const tgzRes = await fetch(tarballUrl, { signal: AbortSignal.timeout(6e4) });
|
|
54985
55065
|
if (!tgzRes.ok) {
|
|
54986
55066
|
return { ok: false, error: `tarball download failed: HTTP ${tgzRes.status} ${tgzRes.statusText}` };
|
|
54987
55067
|
}
|
|
54988
|
-
|
|
55068
|
+
if (!tgzRes.body) {
|
|
55069
|
+
return { ok: false, error: "tarball download failed: empty response body" };
|
|
55070
|
+
}
|
|
55071
|
+
const reader = tgzRes.body.getReader();
|
|
55072
|
+
const chunks = [];
|
|
55073
|
+
let total = 0;
|
|
55074
|
+
try {
|
|
55075
|
+
for (; ; ) {
|
|
55076
|
+
const { done, value } = await reader.read();
|
|
55077
|
+
if (done) break;
|
|
55078
|
+
total += value.byteLength;
|
|
55079
|
+
if (total > MAX_TARBALL_BYTES) {
|
|
55080
|
+
return { ok: false, error: `tarball exceeds ${MAX_TARBALL_BYTES} byte cap` };
|
|
55081
|
+
}
|
|
55082
|
+
chunks.push(value);
|
|
55083
|
+
}
|
|
55084
|
+
} finally {
|
|
55085
|
+
reader.releaseLock();
|
|
55086
|
+
}
|
|
55087
|
+
tgzBuffer = Buffer.concat(chunks);
|
|
54989
55088
|
} catch (e) {
|
|
54990
55089
|
return { ok: false, error: `tarball download failed: ${String(e)}` };
|
|
54991
55090
|
}
|
|
@@ -55038,14 +55137,556 @@ function startAutoUpdate(opts) {
|
|
|
55038
55137
|
timer.unref?.();
|
|
55039
55138
|
}
|
|
55040
55139
|
|
|
55140
|
+
// src/launcher.ts
|
|
55141
|
+
import fs5 from "fs";
|
|
55142
|
+
import net2 from "net";
|
|
55143
|
+
import os2 from "os";
|
|
55144
|
+
import path7 from "path";
|
|
55145
|
+
import { spawn } from "child_process";
|
|
55146
|
+
var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
|
|
55147
|
+
var LAUNCHER_DEFAULT_PORT = 8787;
|
|
55148
|
+
var LAUNCH_CLIENTS = ["pi", "codex", "claude", "pi-test"];
|
|
55149
|
+
var HEALTH_PATH = "/__bili/health";
|
|
55150
|
+
var HEALTH_POLL_INTERVAL_MS = 200;
|
|
55151
|
+
var SPAWN_WAIT_MS = 2e4;
|
|
55152
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
55153
|
+
var DEFAULT_MITM_DOMAIN_SET = new Set(DEFAULT_MITM_DOMAINS.map((d) => d.toLowerCase()));
|
|
55154
|
+
function coveredByDefaultMitm(host) {
|
|
55155
|
+
const h = host.toLowerCase();
|
|
55156
|
+
return DEFAULT_MITM_DOMAINS.some((d) => h === d || h.endsWith("." + d));
|
|
55157
|
+
}
|
|
55158
|
+
function domainsNeedFreshProxy(domains) {
|
|
55159
|
+
if (!domains || domains.length === 0) return false;
|
|
55160
|
+
return domains.some((d) => !coveredByDefaultMitm(d));
|
|
55161
|
+
}
|
|
55162
|
+
function isLaunchClient(value) {
|
|
55163
|
+
return LAUNCH_CLIENTS.includes(value);
|
|
55164
|
+
}
|
|
55165
|
+
function baseClientName(client) {
|
|
55166
|
+
return client === "pi-test" ? "pi" : client;
|
|
55167
|
+
}
|
|
55168
|
+
function piTestArgs(client, clientArgs) {
|
|
55169
|
+
return client === "pi-test" ? ["--no-extensions", ...clientArgs] : clientArgs;
|
|
55170
|
+
}
|
|
55171
|
+
function proxyOrigin(host, port) {
|
|
55172
|
+
return `http://${host}:${port}`;
|
|
55173
|
+
}
|
|
55174
|
+
function healthUrl(origin) {
|
|
55175
|
+
return origin + HEALTH_PATH;
|
|
55176
|
+
}
|
|
55177
|
+
function wrapUpstream(origin, upstream) {
|
|
55178
|
+
const u2 = upstream.replace(/\/+$/, "");
|
|
55179
|
+
const prefix = origin + "/bili/";
|
|
55180
|
+
if (u2.startsWith(prefix)) return u2;
|
|
55181
|
+
return prefix + u2;
|
|
55182
|
+
}
|
|
55183
|
+
function unwrapUpstream(url) {
|
|
55184
|
+
const idx = url.indexOf("/bili/");
|
|
55185
|
+
return idx >= 0 ? url.slice(idx + "/bili/".length) : url;
|
|
55186
|
+
}
|
|
55187
|
+
function nonEmpty2(s3) {
|
|
55188
|
+
return typeof s3 === "string" && s3.trim().length > 0;
|
|
55189
|
+
}
|
|
55190
|
+
function resolveCaCertPath(env) {
|
|
55191
|
+
const base = env.XDG_DATA_HOME || path7.join(os2.homedir(), ".local/share");
|
|
55192
|
+
return path7.join(base, "billion-context", "ca", "root-ca.pem");
|
|
55193
|
+
}
|
|
55194
|
+
function resolvePiHome(env) {
|
|
55195
|
+
const h = os2.homedir();
|
|
55196
|
+
return nonEmpty2(env.PI_CODING_AGENT_DIR) ? env.PI_CODING_AGENT_DIR : nonEmpty2(env.PI_HOME) ? env.PI_HOME : path7.join(h, ".pi", "agent");
|
|
55197
|
+
}
|
|
55198
|
+
function discoverRoutes(client, config) {
|
|
55199
|
+
const httpsDomains = [];
|
|
55200
|
+
const httpRewrites = [];
|
|
55201
|
+
const httpsRewrites = [];
|
|
55202
|
+
const httpsSeen = /* @__PURE__ */ new Set();
|
|
55203
|
+
const rewriteKeys = /* @__PURE__ */ new Set();
|
|
55204
|
+
const httpsRewriteKeys = /* @__PURE__ */ new Set();
|
|
55205
|
+
const classify = (raw, key) => {
|
|
55206
|
+
if (!nonEmpty2(raw)) return;
|
|
55207
|
+
let url;
|
|
55208
|
+
try {
|
|
55209
|
+
url = new URL(unwrapUpstream(raw));
|
|
55210
|
+
} catch {
|
|
55211
|
+
return;
|
|
55212
|
+
}
|
|
55213
|
+
if (url.protocol === "https:") {
|
|
55214
|
+
const host = url.hostname;
|
|
55215
|
+
if (host && !httpsSeen.has(host.toLowerCase())) {
|
|
55216
|
+
httpsSeen.add(host.toLowerCase());
|
|
55217
|
+
httpsDomains.push(host);
|
|
55218
|
+
}
|
|
55219
|
+
if (raw !== unwrapUpstream(raw) && !httpsRewriteKeys.has(key)) {
|
|
55220
|
+
httpsRewriteKeys.add(key);
|
|
55221
|
+
httpsRewrites.push({ key, realUpstream: unwrapUpstream(raw) });
|
|
55222
|
+
}
|
|
55223
|
+
} else if (url.protocol === "http:") {
|
|
55224
|
+
if (!rewriteKeys.has(key)) {
|
|
55225
|
+
rewriteKeys.add(key);
|
|
55226
|
+
httpRewrites.push({ key, realUpstream: unwrapUpstream(raw) });
|
|
55227
|
+
}
|
|
55228
|
+
}
|
|
55229
|
+
};
|
|
55230
|
+
if (client === "claude") {
|
|
55231
|
+
const u2 = config.claude?.anthropicBaseUrl;
|
|
55232
|
+
if (nonEmpty2(u2)) classify(u2, "ANTHROPIC_BASE_URL");
|
|
55233
|
+
else classify("https://api.anthropic.com", "ANTHROPIC_BASE_URL");
|
|
55234
|
+
} else if (client === "pi") {
|
|
55235
|
+
for (const [name, prov] of Object.entries(config.pi?.providers ?? {})) {
|
|
55236
|
+
classify(prov.baseUrl, name);
|
|
55237
|
+
}
|
|
55238
|
+
} else {
|
|
55239
|
+
for (const [name, prov] of Object.entries(config.codex?.providers ?? {})) {
|
|
55240
|
+
classify(prov.baseUrl, `model_providers.${name}.base_url`);
|
|
55241
|
+
}
|
|
55242
|
+
classify(config.codex?.openaiBaseUrl, "openai_base_url");
|
|
55243
|
+
}
|
|
55244
|
+
return { httpsDomains, httpRewrites, httpsRewrites };
|
|
55245
|
+
}
|
|
55246
|
+
function discoverDomains(client, config) {
|
|
55247
|
+
return discoverRoutes(client, config).httpsDomains;
|
|
55248
|
+
}
|
|
55249
|
+
function buildPiEnv(origin, caPath, baseEnv) {
|
|
55250
|
+
return { ...baseEnv, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: caPath };
|
|
55251
|
+
}
|
|
55252
|
+
function buildCodexEnv(origin, caPath, baseEnv) {
|
|
55253
|
+
return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath };
|
|
55254
|
+
}
|
|
55255
|
+
function buildCodexArgs(origin, httpRewrites, httpsRewrites, extra) {
|
|
55256
|
+
const args = [];
|
|
55257
|
+
for (const r of httpRewrites) {
|
|
55258
|
+
args.push("-c", `${r.key}=${wrapUpstream(origin, r.realUpstream)}`);
|
|
55259
|
+
}
|
|
55260
|
+
for (const r of httpsRewrites) {
|
|
55261
|
+
args.push("-c", `${r.key}=${r.realUpstream}`);
|
|
55262
|
+
}
|
|
55263
|
+
args.push(...extra);
|
|
55264
|
+
return args;
|
|
55265
|
+
}
|
|
55266
|
+
function buildClaudeEnv(origin, caPath, httpRewrites, httpsRewrites, baseEnv) {
|
|
55267
|
+
const env = { ...baseEnv, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: caPath };
|
|
55268
|
+
const r = httpRewrites.find((rw) => rw.key === "ANTHROPIC_BASE_URL");
|
|
55269
|
+
if (r) env.ANTHROPIC_BASE_URL = wrapUpstream(origin, r.realUpstream);
|
|
55270
|
+
const hr2 = httpsRewrites.find((rw) => rw.key === "ANTHROPIC_BASE_URL");
|
|
55271
|
+
if (hr2) env.ANTHROPIC_BASE_URL = hr2.realUpstream;
|
|
55272
|
+
return env;
|
|
55273
|
+
}
|
|
55274
|
+
function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
|
|
55275
|
+
if (httpRewrites.length === 0 && httpsRewrites.length === 0) return void 0;
|
|
55276
|
+
const modelsPath = path7.join(piHome, "models.json");
|
|
55277
|
+
let txt;
|
|
55278
|
+
try {
|
|
55279
|
+
txt = fs5.readFileSync(modelsPath, "utf8");
|
|
55280
|
+
} catch {
|
|
55281
|
+
return void 0;
|
|
55282
|
+
}
|
|
55283
|
+
let parsed;
|
|
55284
|
+
try {
|
|
55285
|
+
parsed = JSON.parse(txt);
|
|
55286
|
+
} catch {
|
|
55287
|
+
return void 0;
|
|
55288
|
+
}
|
|
55289
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
55290
|
+
const root = parsed;
|
|
55291
|
+
const providersVal = root.providers;
|
|
55292
|
+
if (providersVal && typeof providersVal === "object" && !Array.isArray(providersVal)) {
|
|
55293
|
+
const providers = providersVal;
|
|
55294
|
+
for (const r of httpRewrites) {
|
|
55295
|
+
const prov = providers[r.key];
|
|
55296
|
+
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
55297
|
+
const p2 = prov;
|
|
55298
|
+
const existing = typeof p2.baseUrl === "string" ? p2.baseUrl : r.realUpstream;
|
|
55299
|
+
p2.baseUrl = wrapUpstream(origin, unwrapUpstream(existing));
|
|
55300
|
+
}
|
|
55301
|
+
}
|
|
55302
|
+
for (const r of httpsRewrites) {
|
|
55303
|
+
const prov = providers[r.key];
|
|
55304
|
+
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
55305
|
+
const p2 = prov;
|
|
55306
|
+
p2.baseUrl = r.realUpstream;
|
|
55307
|
+
}
|
|
55308
|
+
}
|
|
55309
|
+
}
|
|
55310
|
+
const tmp = fs5.mkdtempSync(path7.join(os2.tmpdir(), "bili-pi-"));
|
|
55311
|
+
try {
|
|
55312
|
+
for (const entry of fs5.readdirSync(piHome)) {
|
|
55313
|
+
if (entry === "models.json") continue;
|
|
55314
|
+
try {
|
|
55315
|
+
fs5.symlinkSync(path7.join(piHome, entry), path7.join(tmp, entry));
|
|
55316
|
+
} catch {
|
|
55317
|
+
}
|
|
55318
|
+
}
|
|
55319
|
+
} catch {
|
|
55320
|
+
}
|
|
55321
|
+
fs5.writeFileSync(path7.join(tmp, "models.json"), JSON.stringify(root));
|
|
55322
|
+
return tmp;
|
|
55323
|
+
}
|
|
55324
|
+
function dedupeInOrder(list) {
|
|
55325
|
+
const seen = /* @__PURE__ */ new Set();
|
|
55326
|
+
const out = [];
|
|
55327
|
+
for (const d of list) {
|
|
55328
|
+
if (d && !seen.has(d)) {
|
|
55329
|
+
seen.add(d);
|
|
55330
|
+
out.push(d);
|
|
55331
|
+
}
|
|
55332
|
+
}
|
|
55333
|
+
return out;
|
|
55334
|
+
}
|
|
55335
|
+
async function defaultFetch(url) {
|
|
55336
|
+
const ctrl = new AbortController();
|
|
55337
|
+
const t = setTimeout(() => ctrl.abort(), PROBE_TIMEOUT_MS);
|
|
55338
|
+
try {
|
|
55339
|
+
const res = await fetch(url, { signal: ctrl.signal });
|
|
55340
|
+
return { ok: res.ok };
|
|
55341
|
+
} catch {
|
|
55342
|
+
return { ok: false };
|
|
55343
|
+
} finally {
|
|
55344
|
+
clearTimeout(t);
|
|
55345
|
+
}
|
|
55346
|
+
}
|
|
55347
|
+
async function probeHealth(origin, fetchImpl) {
|
|
55348
|
+
try {
|
|
55349
|
+
const { ok } = await fetchImpl(healthUrl(origin));
|
|
55350
|
+
return ok;
|
|
55351
|
+
} catch {
|
|
55352
|
+
return false;
|
|
55353
|
+
}
|
|
55354
|
+
}
|
|
55355
|
+
function findFreePort(preferred, host = LAUNCHER_DEFAULT_HOST) {
|
|
55356
|
+
const tryBind = (port) => new Promise((resolve) => {
|
|
55357
|
+
const srv = net2.createServer();
|
|
55358
|
+
srv.once("error", () => resolve(false));
|
|
55359
|
+
srv.once("listening", () => srv.close(() => resolve(true)));
|
|
55360
|
+
srv.listen(port, host);
|
|
55361
|
+
});
|
|
55362
|
+
return tryBind(preferred).then((free) => {
|
|
55363
|
+
if (free) return preferred;
|
|
55364
|
+
return new Promise((resolve, reject) => {
|
|
55365
|
+
const srv = net2.createServer();
|
|
55366
|
+
srv.once("error", reject);
|
|
55367
|
+
srv.listen(0, host, () => {
|
|
55368
|
+
const addr = srv.address();
|
|
55369
|
+
srv.close(() => {
|
|
55370
|
+
if (addr && typeof addr === "object") resolve(addr.port);
|
|
55371
|
+
else reject(new Error("could not allocate a free port"));
|
|
55372
|
+
});
|
|
55373
|
+
});
|
|
55374
|
+
});
|
|
55375
|
+
});
|
|
55376
|
+
}
|
|
55377
|
+
var INHERITED_PROXY_VARS = ["http_proxy", "https_proxy", "all_proxy", "HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"];
|
|
55378
|
+
function stripInheritedProxy(env) {
|
|
55379
|
+
const cleaned = { ...env };
|
|
55380
|
+
for (const key of INHERITED_PROXY_VARS) delete cleaned[key];
|
|
55381
|
+
return cleaned;
|
|
55382
|
+
}
|
|
55383
|
+
function proxyStartArgs(opts) {
|
|
55384
|
+
const args = ["start", "--host", opts.host, "--port", String(opts.port)];
|
|
55385
|
+
if (opts.passthrough) args.push("--passthrough");
|
|
55386
|
+
if (opts.debug) args.push("--debug");
|
|
55387
|
+
return args;
|
|
55388
|
+
}
|
|
55389
|
+
async function ensureProxyRunning(opts, deps = {}) {
|
|
55390
|
+
const fetchImpl = deps.fetchImpl ?? defaultFetch;
|
|
55391
|
+
const spawnImpl = deps.spawnImpl ?? spawn;
|
|
55392
|
+
const now = deps.now ?? Date.now;
|
|
55393
|
+
const sleepImpl = deps.sleep ?? ((ms2) => new Promise((r) => setTimeout(r, ms2)));
|
|
55394
|
+
const preferredOrigin = proxyOrigin(opts.host, opts.port);
|
|
55395
|
+
if (!domainsNeedFreshProxy(opts.mitmDomains) && await probeHealth(preferredOrigin, fetchImpl)) {
|
|
55396
|
+
return { origin: preferredOrigin, port: opts.port, reused: true, child: null };
|
|
55397
|
+
}
|
|
55398
|
+
const port = await findFreePort(opts.port, opts.host);
|
|
55399
|
+
const spawnedOrigin = proxyOrigin(opts.host, port);
|
|
55400
|
+
const script = process.argv[1];
|
|
55401
|
+
if (!script) throw new Error("bili: cannot resolve launcher script path");
|
|
55402
|
+
const logPath2 = path7.join(os2.tmpdir(), `bili-proxy-${port}.log`);
|
|
55403
|
+
const logFd = fs5.openSync(logPath2, "a");
|
|
55404
|
+
let child;
|
|
55405
|
+
try {
|
|
55406
|
+
child = spawnImpl(
|
|
55407
|
+
process.execPath,
|
|
55408
|
+
[script, ...proxyStartArgs({ ...opts, port, debug: true })],
|
|
55409
|
+
{
|
|
55410
|
+
detached: true,
|
|
55411
|
+
stdio: ["ignore", logFd, logFd],
|
|
55412
|
+
env: {
|
|
55413
|
+
...stripInheritedProxy(process.env),
|
|
55414
|
+
...opts.mitmDomains && opts.mitmDomains.length ? { BILI_MITM_DOMAINS: opts.mitmDomains.join(",") } : {}
|
|
55415
|
+
}
|
|
55416
|
+
}
|
|
55417
|
+
);
|
|
55418
|
+
} finally {
|
|
55419
|
+
try {
|
|
55420
|
+
fs5.closeSync(logFd);
|
|
55421
|
+
} catch {
|
|
55422
|
+
}
|
|
55423
|
+
}
|
|
55424
|
+
try {
|
|
55425
|
+
child.unref?.();
|
|
55426
|
+
} catch {
|
|
55427
|
+
}
|
|
55428
|
+
const deadline = now() + SPAWN_WAIT_MS;
|
|
55429
|
+
while (now() < deadline) {
|
|
55430
|
+
await sleepImpl(HEALTH_POLL_INTERVAL_MS);
|
|
55431
|
+
if (await probeHealth(spawnedOrigin, fetchImpl)) {
|
|
55432
|
+
return { origin: spawnedOrigin, port, reused: false, child, logPath: logPath2 };
|
|
55433
|
+
}
|
|
55434
|
+
}
|
|
55435
|
+
throw new Error(`bili: proxy did not become healthy at ${spawnedOrigin} within ${SPAWN_WAIT_MS}ms`);
|
|
55436
|
+
}
|
|
55437
|
+
function stopProxy(handle2) {
|
|
55438
|
+
const child = handle2.child;
|
|
55439
|
+
if (!child || child.pid === void 0) return;
|
|
55440
|
+
if (process.platform !== "win32" && child.pid > 0) {
|
|
55441
|
+
try {
|
|
55442
|
+
process.kill(-child.pid);
|
|
55443
|
+
} catch {
|
|
55444
|
+
}
|
|
55445
|
+
}
|
|
55446
|
+
try {
|
|
55447
|
+
child.kill?.();
|
|
55448
|
+
} catch {
|
|
55449
|
+
}
|
|
55450
|
+
}
|
|
55451
|
+
function runClient(cmd, args, env, deps) {
|
|
55452
|
+
const spawnImpl = deps?.spawnImpl ?? spawn;
|
|
55453
|
+
return new Promise((resolve, reject) => {
|
|
55454
|
+
const child = spawnImpl(cmd, args, { stdio: "inherit", env });
|
|
55455
|
+
child.on?.("error", (...rest) => reject(rest[0]));
|
|
55456
|
+
child.on?.("exit", (...rest) => {
|
|
55457
|
+
const code = rest[0];
|
|
55458
|
+
const signal = rest[1];
|
|
55459
|
+
resolve(signal ? 130 : typeof code === "number" ? code : 0);
|
|
55460
|
+
});
|
|
55461
|
+
});
|
|
55462
|
+
}
|
|
55463
|
+
function isOnPath(name, env) {
|
|
55464
|
+
const p2 = env.PATH;
|
|
55465
|
+
if (!p2) return false;
|
|
55466
|
+
return p2.split(":").some((dir) => {
|
|
55467
|
+
if (!dir) return false;
|
|
55468
|
+
try {
|
|
55469
|
+
const f2 = path7.join(dir, name);
|
|
55470
|
+
return fs5.existsSync(f2) && fs5.statSync(f2).isFile();
|
|
55471
|
+
} catch {
|
|
55472
|
+
return false;
|
|
55473
|
+
}
|
|
55474
|
+
});
|
|
55475
|
+
}
|
|
55476
|
+
function resolveClientCommand(client, env) {
|
|
55477
|
+
if (client === "pi") {
|
|
55478
|
+
const piBin = env.PI_BIN?.trim();
|
|
55479
|
+
if (piBin) return { command: piBin, prefixArgs: [] };
|
|
55480
|
+
if (isOnPath("pi", env)) return { command: "pi", prefixArgs: [] };
|
|
55481
|
+
const cli = path7.join(
|
|
55482
|
+
os2.homedir(),
|
|
55483
|
+
".pi/agent/npm/node_modules/@earendil-works/pi-coding-agent/dist/cli.js"
|
|
55484
|
+
);
|
|
55485
|
+
return { command: process.execPath, prefixArgs: [cli] };
|
|
55486
|
+
}
|
|
55487
|
+
return { command: client, prefixArgs: [] };
|
|
55488
|
+
}
|
|
55489
|
+
function readJsonObject(filePath) {
|
|
55490
|
+
try {
|
|
55491
|
+
const txt = fs5.readFileSync(filePath, "utf8");
|
|
55492
|
+
const parsed = JSON.parse(txt);
|
|
55493
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
55494
|
+
} catch {
|
|
55495
|
+
return null;
|
|
55496
|
+
}
|
|
55497
|
+
}
|
|
55498
|
+
function readClaudeSettings(homeDir, cwd) {
|
|
55499
|
+
const files = [
|
|
55500
|
+
path7.join(homeDir, ".claude", "settings.json"),
|
|
55501
|
+
path7.join(cwd, ".claude", "settings.json")
|
|
55502
|
+
];
|
|
55503
|
+
let anthropicBaseUrl;
|
|
55504
|
+
for (const f2 of files) {
|
|
55505
|
+
const obj = readJsonObject(f2);
|
|
55506
|
+
const env = obj?.env;
|
|
55507
|
+
if (env && typeof env === "object" && !Array.isArray(env)) {
|
|
55508
|
+
const v2 = env.ANTHROPIC_BASE_URL;
|
|
55509
|
+
if (nonEmpty2(v2)) anthropicBaseUrl = v2;
|
|
55510
|
+
}
|
|
55511
|
+
}
|
|
55512
|
+
return anthropicBaseUrl ? { anthropicBaseUrl } : {};
|
|
55513
|
+
}
|
|
55514
|
+
function parseCodexToml(text) {
|
|
55515
|
+
const result = { providers: {} };
|
|
55516
|
+
let table = "";
|
|
55517
|
+
let curProvider = null;
|
|
55518
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
55519
|
+
const line = rawLine.trim();
|
|
55520
|
+
if (!line || line.startsWith("#")) continue;
|
|
55521
|
+
const tableMatch = /^\[([^\]]+)\]$/.exec(line);
|
|
55522
|
+
if (tableMatch) {
|
|
55523
|
+
table = tableMatch[1].trim();
|
|
55524
|
+
curProvider = table.startsWith("model_providers.") ? table.slice("model_providers.".length).trim() : null;
|
|
55525
|
+
if (curProvider && !result.providers[curProvider]) {
|
|
55526
|
+
result.providers[curProvider] = {};
|
|
55527
|
+
}
|
|
55528
|
+
continue;
|
|
55529
|
+
}
|
|
55530
|
+
const m2 = /^([A-Za-z0-9_.-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(line);
|
|
55531
|
+
if (!m2) continue;
|
|
55532
|
+
const key = m2[1];
|
|
55533
|
+
const val = m2[2] !== void 0 ? m2[2] : m2[3];
|
|
55534
|
+
if (table === "") {
|
|
55535
|
+
if (key === "model_provider") result.modelProvider = val;
|
|
55536
|
+
else if (key === "openai_base_url") result.openaiBaseUrl = val;
|
|
55537
|
+
} else if (curProvider && key === "base_url") {
|
|
55538
|
+
result.providers[curProvider].baseUrl = val;
|
|
55539
|
+
}
|
|
55540
|
+
}
|
|
55541
|
+
return result;
|
|
55542
|
+
}
|
|
55543
|
+
function readCodexConfig(codexHome) {
|
|
55544
|
+
const cfgPath = path7.join(codexHome, "config.toml");
|
|
55545
|
+
let text;
|
|
55546
|
+
try {
|
|
55547
|
+
text = fs5.readFileSync(cfgPath, "utf8");
|
|
55548
|
+
} catch {
|
|
55549
|
+
return { providers: {} };
|
|
55550
|
+
}
|
|
55551
|
+
return parseCodexToml(text);
|
|
55552
|
+
}
|
|
55553
|
+
function readPiConfig(piHome) {
|
|
55554
|
+
const cfgPath = path7.join(piHome, "models.json");
|
|
55555
|
+
const obj = readJsonObject(cfgPath);
|
|
55556
|
+
const providers = {};
|
|
55557
|
+
const rawProviders = obj?.providers;
|
|
55558
|
+
if (rawProviders && typeof rawProviders === "object" && !Array.isArray(rawProviders)) {
|
|
55559
|
+
for (const [name, val] of Object.entries(rawProviders)) {
|
|
55560
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
55561
|
+
const baseUrl = val.baseUrl;
|
|
55562
|
+
providers[name] = typeof baseUrl === "string" ? { baseUrl } : {};
|
|
55563
|
+
}
|
|
55564
|
+
}
|
|
55565
|
+
}
|
|
55566
|
+
return { providers };
|
|
55567
|
+
}
|
|
55568
|
+
function loadClientConfig(env, cwd) {
|
|
55569
|
+
const home = os2.homedir();
|
|
55570
|
+
const config = {};
|
|
55571
|
+
config.claude = readClaudeSettings(home, cwd);
|
|
55572
|
+
const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path7.join(home, ".codex");
|
|
55573
|
+
config.codex = readCodexConfig(codexHome);
|
|
55574
|
+
config.pi = readPiConfig(resolvePiHome(env));
|
|
55575
|
+
return config;
|
|
55576
|
+
}
|
|
55577
|
+
function parsePort(raw) {
|
|
55578
|
+
const port = raw && raw.trim() ? parseInt(raw, 10) : LAUNCHER_DEFAULT_PORT;
|
|
55579
|
+
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
|
55580
|
+
console.error(`bili: invalid --port "${raw}"`);
|
|
55581
|
+
process.exit(2);
|
|
55582
|
+
}
|
|
55583
|
+
return port;
|
|
55584
|
+
}
|
|
55585
|
+
async function runLaunch(params, deps = {}) {
|
|
55586
|
+
const host = params.overrides.ACP_HOST?.trim() || LAUNCHER_DEFAULT_HOST;
|
|
55587
|
+
const port = parsePort(params.overrides.ACP_PORT ?? process.env.ACP_PORT);
|
|
55588
|
+
const passthrough = params.overrides.ACP_PASSTHROUGH === "1";
|
|
55589
|
+
const debug = params.overrides.ACP_DEBUG === "1";
|
|
55590
|
+
const config = loadClientConfig(process.env, process.cwd());
|
|
55591
|
+
const base = baseClientName(params.client);
|
|
55592
|
+
const routes = discoverRoutes(base, config);
|
|
55593
|
+
const domains = dedupeInOrder([...routes.httpsDomains, ...params.mitmDomains ?? []]);
|
|
55594
|
+
const handle2 = await ensureProxyRunning({ host, port, passthrough, debug, mitmDomains: domains }, deps);
|
|
55595
|
+
console.error(
|
|
55596
|
+
`bili: ${handle2.reused ? "reusing existing" : "started"} proxy at ${handle2.origin} (MITM domains: ${domains.length ? domains.join(", ") : "defaults"})` + (routes.httpRewrites.length > 0 ? ` (HTTP /bili/ rewrites: ${routes.httpRewrites.length})` : "") + (routes.httpsRewrites.length > 0 ? ` (HTTPS cert rewrites: ${routes.httpsRewrites.length})` : "") + (params.client === "pi-test" ? " (no extensions)" : "")
|
|
55597
|
+
);
|
|
55598
|
+
if (handle2.logPath) {
|
|
55599
|
+
console.error(`bili: proxy log: ${handle2.logPath}`);
|
|
55600
|
+
}
|
|
55601
|
+
const ca = resolveCaCertPath(process.env);
|
|
55602
|
+
let env;
|
|
55603
|
+
let clientArgs = params.clientArgs;
|
|
55604
|
+
let piTmpHome;
|
|
55605
|
+
if (base === "pi") {
|
|
55606
|
+
env = buildPiEnv(handle2.origin, ca, process.env);
|
|
55607
|
+
piTmpHome = preparePiHttpRewrite(resolvePiHome(process.env), handle2.origin, routes.httpRewrites, routes.httpsRewrites);
|
|
55608
|
+
if (piTmpHome) env.PI_CODING_AGENT_DIR = piTmpHome;
|
|
55609
|
+
} else if (base === "codex") {
|
|
55610
|
+
env = buildCodexEnv(handle2.origin, ca, process.env);
|
|
55611
|
+
clientArgs = buildCodexArgs(handle2.origin, routes.httpRewrites, routes.httpsRewrites, params.clientArgs);
|
|
55612
|
+
} else {
|
|
55613
|
+
env = buildClaudeEnv(handle2.origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);
|
|
55614
|
+
}
|
|
55615
|
+
const { command, prefixArgs } = resolveClientCommand(base, process.env);
|
|
55616
|
+
const effectiveClientArgs = piTestArgs(params.client, clientArgs);
|
|
55617
|
+
let code = 0;
|
|
55618
|
+
try {
|
|
55619
|
+
code = await runClient(command, [...prefixArgs, ...effectiveClientArgs], env, {
|
|
55620
|
+
spawnImpl: deps.spawnImpl
|
|
55621
|
+
});
|
|
55622
|
+
} catch (err2) {
|
|
55623
|
+
console.error(`bili: failed to launch ${params.client}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
55624
|
+
code = 1;
|
|
55625
|
+
} finally {
|
|
55626
|
+
if (!handle2.reused) stopProxy(handle2);
|
|
55627
|
+
if (piTmpHome) {
|
|
55628
|
+
try {
|
|
55629
|
+
fs5.rmSync(piTmpHome, { recursive: true, force: true });
|
|
55630
|
+
} catch {
|
|
55631
|
+
}
|
|
55632
|
+
}
|
|
55633
|
+
}
|
|
55634
|
+
process.exit(code ?? 0);
|
|
55635
|
+
}
|
|
55636
|
+
async function runTestPi(params, deps = {}) {
|
|
55637
|
+
const host = params.overrides.ACP_HOST?.trim() || LAUNCHER_DEFAULT_HOST;
|
|
55638
|
+
const port = parsePort(params.overrides.ACP_PORT ?? process.env.ACP_PORT);
|
|
55639
|
+
const passthrough = params.overrides.ACP_PASSTHROUGH === "1";
|
|
55640
|
+
const debug = params.overrides.ACP_DEBUG === "1";
|
|
55641
|
+
const config = loadClientConfig(process.env, process.cwd());
|
|
55642
|
+
const domains = dedupeInOrder([
|
|
55643
|
+
...discoverDomains("pi", config),
|
|
55644
|
+
...params.mitmDomains ?? []
|
|
55645
|
+
]);
|
|
55646
|
+
const handle2 = await ensureProxyRunning({ host, port, passthrough, debug, mitmDomains: domains }, deps);
|
|
55647
|
+
console.error(
|
|
55648
|
+
`bili: ${handle2.reused ? "reusing existing" : "started"} proxy at ${handle2.origin} (MITM domains: ${domains.length ? domains.join(", ") : "defaults"})`
|
|
55649
|
+
);
|
|
55650
|
+
if (handle2.logPath) {
|
|
55651
|
+
console.error(`bili: proxy log: ${handle2.logPath}`);
|
|
55652
|
+
}
|
|
55653
|
+
const ca = resolveCaCertPath(process.env);
|
|
55654
|
+
const env = buildPiEnv(handle2.origin, ca, process.env);
|
|
55655
|
+
const sessionDir = path7.join(os2.tmpdir(), `bili-pi-test-${Date.now()}`);
|
|
55656
|
+
fs5.mkdirSync(sessionDir, { recursive: true });
|
|
55657
|
+
const args = [
|
|
55658
|
+
"-p",
|
|
55659
|
+
"--no-session",
|
|
55660
|
+
"--no-extensions",
|
|
55661
|
+
"--no-tools",
|
|
55662
|
+
"--no-context-files",
|
|
55663
|
+
"--session-dir",
|
|
55664
|
+
sessionDir,
|
|
55665
|
+
"--mode",
|
|
55666
|
+
"text",
|
|
55667
|
+
"Reply with exactly: OK"
|
|
55668
|
+
];
|
|
55669
|
+
const { command, prefixArgs } = resolveClientCommand("pi", process.env);
|
|
55670
|
+
let code = 0;
|
|
55671
|
+
try {
|
|
55672
|
+
code = await runClient(command, [...prefixArgs, ...args], env, { spawnImpl: deps.spawnImpl });
|
|
55673
|
+
} catch (err2) {
|
|
55674
|
+
console.error(`bili: pi test failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
55675
|
+
code = 1;
|
|
55676
|
+
} finally {
|
|
55677
|
+
if (!handle2.reused) stopProxy(handle2);
|
|
55678
|
+
}
|
|
55679
|
+
process.exit(code ?? 0);
|
|
55680
|
+
}
|
|
55681
|
+
|
|
55041
55682
|
// src/cli.ts
|
|
55042
55683
|
import { readFileSync as readFileSync5 } from "fs";
|
|
55043
55684
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
55044
|
-
import
|
|
55685
|
+
import path8 from "path";
|
|
55045
55686
|
var VERSION = (() => {
|
|
55046
55687
|
try {
|
|
55047
55688
|
const here = fileURLToPath3(import.meta.url);
|
|
55048
|
-
const pkg =
|
|
55689
|
+
const pkg = path8.join(path8.dirname(here), "..", "package.json");
|
|
55049
55690
|
return JSON.parse(readFileSync5(pkg, "utf8")).version ?? "dev";
|
|
55050
55691
|
} catch {
|
|
55051
55692
|
return "dev";
|
|
@@ -55054,7 +55695,7 @@ var VERSION = (() => {
|
|
|
55054
55695
|
var PACKAGE_NAME = (() => {
|
|
55055
55696
|
try {
|
|
55056
55697
|
const here = fileURLToPath3(import.meta.url);
|
|
55057
|
-
const pkg =
|
|
55698
|
+
const pkg = path8.join(path8.dirname(here), "..", "package.json");
|
|
55058
55699
|
return JSON.parse(readFileSync5(pkg, "utf8")).name ?? "billion-context";
|
|
55059
55700
|
} catch {
|
|
55060
55701
|
return "billion-context";
|
|
@@ -55063,19 +55704,40 @@ var PACKAGE_NAME = (() => {
|
|
|
55063
55704
|
var HELP = `bili ${VERSION} \u2014 billion-context proxy
|
|
55064
55705
|
|
|
55065
55706
|
Usage:
|
|
55066
|
-
bili [start] [options]
|
|
55067
|
-
bili
|
|
55068
|
-
bili --
|
|
55069
|
-
bili --
|
|
55707
|
+
bili [start] [options] start the proxy (default: reads ${configFile()})
|
|
55708
|
+
bili pi [opts --] [args] start a proxy + launch pi against it (cert-MITM)
|
|
55709
|
+
bili pi-test [opts --] [args] like bili pi but injects --no-extensions (clean test)
|
|
55710
|
+
bili codex [opts --] [args] start a proxy + launch codex against it (cert-MITM)
|
|
55711
|
+
bili claude [opts --] [args] start a proxy + launch claude against it (cert-MITM)
|
|
55712
|
+
bili test pi non-polluting pi smoke test through the proxy
|
|
55713
|
+
bili update check for & install a newer version now
|
|
55714
|
+
bili --version print version
|
|
55715
|
+
bili --help show this help
|
|
55716
|
+
|
|
55717
|
+
Launcher (bili pi / bili codex / bili claude):
|
|
55718
|
+
Brings up a proxy on an independent port (reusing one already running on
|
|
55719
|
+
that port), then runs the client pointed at it via HTTPS_PROXY + the proxy's
|
|
55720
|
+
MITM CA \u2014 no config-file edits. Discovered HTTPS upstream domains are
|
|
55721
|
+
auto-whitelisted for MITM so the proxy TLS-terminates exactly the hosts the
|
|
55722
|
+
client uses; HTTP / localhost providers go direct. pi/claude trust the CA
|
|
55723
|
+
via NODE_EXTRA_CA_CERTS, codex via SSL_CERT_FILE. Proxy killed on client exit.
|
|
55724
|
+
bili pi # launch pi through the proxy
|
|
55725
|
+
bili pi -- print "hi" # args after the client are passed through
|
|
55726
|
+
bili pi-test # pi through the proxy with extensions off (proxy owns compression)
|
|
55727
|
+
bili codex # launch codex through the proxy
|
|
55728
|
+
bili claude # launch claude through the proxy
|
|
55729
|
+
bili test pi # quick end-to-end check of the pi path
|
|
55730
|
+
bili pi --mitm-domain api.foo.com # add a domain to the MITM whitelist
|
|
55070
55731
|
|
|
55071
55732
|
Options (override config file / env):
|
|
55072
|
-
--port <N>
|
|
55073
|
-
--host <ADDR>
|
|
55074
|
-
--
|
|
55075
|
-
--
|
|
55076
|
-
--
|
|
55077
|
-
--
|
|
55078
|
-
--no-
|
|
55733
|
+
--port <N> listen port (default 8787)
|
|
55734
|
+
--host <ADDR> listen host (default 127.0.0.1)
|
|
55735
|
+
--mitm-domain <domain> extra MITM domain (repeatable; launcher only)
|
|
55736
|
+
--config <FILE> path to config JSON (default: XDG location)
|
|
55737
|
+
--debug verbose logging
|
|
55738
|
+
--passthrough forward without compression
|
|
55739
|
+
--no-passthrough force compression on (overrides config)
|
|
55740
|
+
--no-auto-update disable background self-update this run
|
|
55079
55741
|
|
|
55080
55742
|
Config: ${configFile()}
|
|
55081
55743
|
Set port/host/debug/providers/compress/autoUpdate there. See README \xA7Configuration.
|
|
@@ -55087,8 +55749,16 @@ function parseArgs(argv) {
|
|
|
55087
55749
|
const overrides = {};
|
|
55088
55750
|
let command = "start";
|
|
55089
55751
|
const positional = [];
|
|
55752
|
+
let client;
|
|
55753
|
+
let clientArgs = [];
|
|
55754
|
+
const mitmDomains = [];
|
|
55090
55755
|
for (let i = 0; i < argv.length; i++) {
|
|
55091
55756
|
const a = argv[i];
|
|
55757
|
+
if (!client && positional.length === 0 && isLaunchClient(a)) {
|
|
55758
|
+
client = a;
|
|
55759
|
+
clientArgs = argv.slice(i + 1);
|
|
55760
|
+
break;
|
|
55761
|
+
}
|
|
55092
55762
|
switch (a) {
|
|
55093
55763
|
case "--help":
|
|
55094
55764
|
case "-h":
|
|
@@ -55110,6 +55780,15 @@ function parseArgs(argv) {
|
|
|
55110
55780
|
case "--no-passthrough":
|
|
55111
55781
|
overrides.ACP_PASSTHROUGH = "0";
|
|
55112
55782
|
break;
|
|
55783
|
+
case "--mitm-domain": {
|
|
55784
|
+
const val = argv[++i];
|
|
55785
|
+
if (val === void 0) {
|
|
55786
|
+
console.error(`bili: ${a} requires a value`);
|
|
55787
|
+
process.exit(2);
|
|
55788
|
+
}
|
|
55789
|
+
mitmDomains.push(val);
|
|
55790
|
+
break;
|
|
55791
|
+
}
|
|
55113
55792
|
case "--port":
|
|
55114
55793
|
case "--host":
|
|
55115
55794
|
case "--config": {
|
|
@@ -55137,21 +55816,32 @@ function parseArgs(argv) {
|
|
|
55137
55816
|
positional.push(a);
|
|
55138
55817
|
}
|
|
55139
55818
|
}
|
|
55140
|
-
if (
|
|
55819
|
+
if (client) {
|
|
55820
|
+
command = "launch";
|
|
55821
|
+
} else if (positional.length > 0) {
|
|
55141
55822
|
const cmd = positional[0];
|
|
55142
55823
|
if (cmd === "start") {
|
|
55143
55824
|
command = command === "help" || command === "version" ? command : "start";
|
|
55144
55825
|
} else if (cmd === "update") {
|
|
55145
55826
|
command = "update";
|
|
55827
|
+
} else if (cmd === "test") {
|
|
55828
|
+
const target = positional[1];
|
|
55829
|
+
if (target && isLaunchClient(target)) {
|
|
55830
|
+
command = "test";
|
|
55831
|
+
client = target;
|
|
55832
|
+
} else {
|
|
55833
|
+
console.error(`bili test: unknown client "${target ?? ""}" (try "bili test pi")`);
|
|
55834
|
+
process.exit(2);
|
|
55835
|
+
}
|
|
55146
55836
|
} else {
|
|
55147
55837
|
console.error(`bili: unknown command "${cmd}" (try "bili --help")`);
|
|
55148
55838
|
process.exit(2);
|
|
55149
55839
|
}
|
|
55150
55840
|
}
|
|
55151
|
-
return { command, overrides };
|
|
55841
|
+
return { command, client, clientArgs, mitmDomains, overrides };
|
|
55152
55842
|
}
|
|
55153
55843
|
async function main() {
|
|
55154
|
-
const { command, overrides } = parseArgs(process.argv.slice(2));
|
|
55844
|
+
const { command, client, clientArgs, mitmDomains, overrides } = parseArgs(process.argv.slice(2));
|
|
55155
55845
|
if (command === "help") {
|
|
55156
55846
|
process.stdout.write(HELP);
|
|
55157
55847
|
return;
|
|
@@ -55164,6 +55854,18 @@ async function main() {
|
|
|
55164
55854
|
await checkForUpdate({ packageName: PACKAGE_NAME, currentVersion: VERSION, autoUpdate: true }, true);
|
|
55165
55855
|
return;
|
|
55166
55856
|
}
|
|
55857
|
+
if (command === "test") {
|
|
55858
|
+
if (client === "pi") {
|
|
55859
|
+
await runTestPi({ overrides, mitmDomains });
|
|
55860
|
+
return;
|
|
55861
|
+
}
|
|
55862
|
+
console.error("bili test: only 'pi' supported for now");
|
|
55863
|
+
process.exit(2);
|
|
55864
|
+
}
|
|
55865
|
+
if (command === "launch") {
|
|
55866
|
+
await runLaunch({ client, clientArgs, mitmDomains, overrides });
|
|
55867
|
+
return;
|
|
55868
|
+
}
|
|
55167
55869
|
for (const [k2, v2] of Object.entries(overrides)) {
|
|
55168
55870
|
if (v2 !== void 0) process.env[k2] = v2;
|
|
55169
55871
|
}
|