github-router 0.3.21 → 0.3.22
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/main.js +86 -3
- package/dist/main.js.map +1 -1
- package/package.json +3 -1
package/dist/main.js
CHANGED
|
@@ -2344,7 +2344,7 @@ function initProxyFromEnv() {
|
|
|
2344
2344
|
//#endregion
|
|
2345
2345
|
//#region package.json
|
|
2346
2346
|
var name = "github-router";
|
|
2347
|
-
var version = "0.3.
|
|
2347
|
+
var version = "0.3.22";
|
|
2348
2348
|
|
|
2349
2349
|
//#endregion
|
|
2350
2350
|
//#region src/lib/approval.ts
|
|
@@ -2455,6 +2455,50 @@ function detectCapabilityMismatch(info, model) {
|
|
|
2455
2455
|
const err = info.errorBody.toLowerCase();
|
|
2456
2456
|
return err.includes("token") || err.includes("context") || err.includes("too long") || err.includes("max_tokens") || err.includes("prompt is too long");
|
|
2457
2457
|
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Opt-in instrumentation for the discovery loop (Phase 0.5 of the
|
|
2460
|
+
* long-horizon plan). When `GH_ROUTER_LOG_FIELDS=1` is set in the
|
|
2461
|
+
* environment, emits a single structured `[fields]` log line per request
|
|
2462
|
+
* recording the top-level body keys, per-tool field keys, and
|
|
2463
|
+
* anthropic-beta header values seen.
|
|
2464
|
+
*
|
|
2465
|
+
* Default-off (zero overhead). The companion
|
|
2466
|
+
* `scripts/discover-new-fields.sh` greps these lines, aggregates unique
|
|
2467
|
+
* field names per request shape, and diffs against the known-fields
|
|
2468
|
+
* list in `docs/copilot-compat-matrix.md` — surfacing anything new
|
|
2469
|
+
* that should get a probe row added.
|
|
2470
|
+
*
|
|
2471
|
+
* Format (single line, deterministic-ish key order):
|
|
2472
|
+
* [fields] path=<P> body_keys=<csv> tool_field_keys=<csv> beta_values=<csv>
|
|
2473
|
+
*
|
|
2474
|
+
* Where:
|
|
2475
|
+
* - `body_keys` is the alphabetical union of top-level keys in the
|
|
2476
|
+
* request body
|
|
2477
|
+
* - `tool_field_keys` is the alphabetical union of all keys appearing
|
|
2478
|
+
* across every entry of `body.tools[]` (or empty)
|
|
2479
|
+
* - `beta_values` is the comma-split anthropic-beta header value as
|
|
2480
|
+
* received (NOT filtered) — captures what the client sends, not
|
|
2481
|
+
* what we forward
|
|
2482
|
+
*/
|
|
2483
|
+
function logRequestFields(opts) {
|
|
2484
|
+
if (process.env.GH_ROUTER_LOG_FIELDS !== "1") return;
|
|
2485
|
+
const bodyKeys = collectTopLevelKeys(opts.body);
|
|
2486
|
+
const toolFieldKeys = collectToolFieldKeys(opts.body);
|
|
2487
|
+
const betaValues = (opts.betaHeader ?? "").split(",").map((v) => v.trim()).filter(Boolean);
|
|
2488
|
+
consola.info(`[fields] path=${opts.path} body_keys=${bodyKeys.join(",")} tool_field_keys=${toolFieldKeys.join(",")} beta_values=${betaValues.join(",")}`);
|
|
2489
|
+
}
|
|
2490
|
+
function collectTopLevelKeys(body) {
|
|
2491
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return [];
|
|
2492
|
+
return Object.keys(body).sort();
|
|
2493
|
+
}
|
|
2494
|
+
function collectToolFieldKeys(body) {
|
|
2495
|
+
if (!body || typeof body !== "object") return [];
|
|
2496
|
+
const tools = body.tools;
|
|
2497
|
+
if (!Array.isArray(tools)) return [];
|
|
2498
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2499
|
+
for (const tool of tools) if (tool && typeof tool === "object" && !Array.isArray(tool)) for (const k of Object.keys(tool)) seen.add(k);
|
|
2500
|
+
return [...seen].sort();
|
|
2501
|
+
}
|
|
2458
2502
|
|
|
2459
2503
|
//#endregion
|
|
2460
2504
|
//#region src/lib/stream-relay.ts
|
|
@@ -4747,7 +4791,7 @@ function resolveModelInBody$1(rawBody) {
|
|
|
4747
4791
|
}
|
|
4748
4792
|
}
|
|
4749
4793
|
if (rawBody.includes("\"scope\"") && sanitizeCacheControl$1(parsed)) modified = true;
|
|
4750
|
-
if ((rawBody.includes("\"budget\"") || rawBody.includes("\"output_config\"") || rawBody.includes("\"betas\"")) && stripAnthropicOnlyFields$1(parsed)) modified = true;
|
|
4794
|
+
if ((rawBody.includes("\"budget\"") || rawBody.includes("\"output_config\"") || rawBody.includes("\"betas\"") || rawBody.includes("\"eager_input_streaming\"")) && stripAnthropicOnlyFields$1(parsed)) modified = true;
|
|
4751
4795
|
const resolvedModel = typeof parsed.model === "string" ? parsed.model : originalModel;
|
|
4752
4796
|
return {
|
|
4753
4797
|
body: modified ? JSON.stringify(parsed) : rawBody,
|
|
@@ -4809,6 +4853,20 @@ function stripAnthropicOnlyFields$1(body) {
|
|
|
4809
4853
|
delete body.betas;
|
|
4810
4854
|
stripped = true;
|
|
4811
4855
|
}
|
|
4856
|
+
if (Array.isArray(body.tools)) {
|
|
4857
|
+
let warnedFGTS = false;
|
|
4858
|
+
for (const tool of body.tools) if (typeof tool === "object" && tool !== null) {
|
|
4859
|
+
const t = tool;
|
|
4860
|
+
if (t.eager_input_streaming !== void 0) {
|
|
4861
|
+
delete t.eager_input_streaming;
|
|
4862
|
+
stripped = true;
|
|
4863
|
+
if (!warnedFGTS) {
|
|
4864
|
+
consola.warn("[count_tokens] Stripping per-tool `eager_input_streaming` (Copilot 400s on `tools.*.custom.eager_input_streaming`)");
|
|
4865
|
+
warnedFGTS = true;
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4812
4870
|
return stripped;
|
|
4813
4871
|
}
|
|
4814
4872
|
|
|
@@ -4919,6 +4977,17 @@ async function handleCompletion(c) {
|
|
|
4919
4977
|
const rawBody = await c.req.text();
|
|
4920
4978
|
const debugEnabled = consola.level >= 4;
|
|
4921
4979
|
if (debugEnabled) consola.debug("Anthropic request body:", rawBody.slice(0, 2e3));
|
|
4980
|
+
if (process.env.GH_ROUTER_LOG_FIELDS === "1") {
|
|
4981
|
+
let parsedForLog = void 0;
|
|
4982
|
+
try {
|
|
4983
|
+
parsedForLog = JSON.parse(rawBody);
|
|
4984
|
+
} catch {}
|
|
4985
|
+
logRequestFields({
|
|
4986
|
+
path: c.req.path,
|
|
4987
|
+
body: parsedForLog,
|
|
4988
|
+
betaHeader: c.req.header("anthropic-beta")
|
|
4989
|
+
});
|
|
4990
|
+
}
|
|
4922
4991
|
if (state.manualApprove) await awaitApproval();
|
|
4923
4992
|
const betaHeaders = extractBetaHeaders(c);
|
|
4924
4993
|
const advisorEnabled = isAdvisorRequested(c.req.header("anthropic-beta"));
|
|
@@ -5061,7 +5130,7 @@ function resolveModelInBody(rawBody) {
|
|
|
5061
5130
|
const selectedModel = resolvedModel ? state.models?.data.find((m) => m.id === resolvedModel) : void 0;
|
|
5062
5131
|
if (translateThinking(parsed, selectedModel)) modified = true;
|
|
5063
5132
|
if (rawBody.includes("\"scope\"") && sanitizeCacheControl(parsed)) modified = true;
|
|
5064
|
-
if ((rawBody.includes("\"budget\"") || rawBody.includes("\"output_config\"") || rawBody.includes("\"betas\"")) && stripAnthropicOnlyFields(parsed)) modified = true;
|
|
5133
|
+
if ((rawBody.includes("\"budget\"") || rawBody.includes("\"output_config\"") || rawBody.includes("\"betas\"") || rawBody.includes("\"eager_input_streaming\"")) && stripAnthropicOnlyFields(parsed)) modified = true;
|
|
5065
5134
|
return {
|
|
5066
5135
|
body: modified ? JSON.stringify(parsed) : rawBody,
|
|
5067
5136
|
originalModel,
|
|
@@ -5230,6 +5299,20 @@ function stripAnthropicOnlyFields(body) {
|
|
|
5230
5299
|
delete body.betas;
|
|
5231
5300
|
stripped = true;
|
|
5232
5301
|
}
|
|
5302
|
+
if (Array.isArray(body.tools)) {
|
|
5303
|
+
let warnedFGTS = false;
|
|
5304
|
+
for (const tool of body.tools) if (typeof tool === "object" && tool !== null) {
|
|
5305
|
+
const t = tool;
|
|
5306
|
+
if (t.eager_input_streaming !== void 0) {
|
|
5307
|
+
delete t.eager_input_streaming;
|
|
5308
|
+
stripped = true;
|
|
5309
|
+
if (!warnedFGTS) {
|
|
5310
|
+
consola.warn("Stripping per-tool `eager_input_streaming` field (Copilot 400s on `tools.*.custom.eager_input_streaming`; FGTS chunk-size optimization disabled, but streaming correctness is unaffected — `input_json_delta` events still flow normally)");
|
|
5311
|
+
warnedFGTS = true;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5233
5316
|
return stripped;
|
|
5234
5317
|
}
|
|
5235
5318
|
/**
|