ghc-proxy 0.5.6 → 0.5.7
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 +17 -0
- package/dist/main.mjs +130 -52
- package/dist/main.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -489,3 +489,20 @@ bun run matrix:live --stateful-only --json --model=gpt-5.2-codex
|
|
|
489
489
|
> - `--stateful-only`: run follow-up/resource probes such as `previous_response_id`, `input_tokens`, and `input_items`
|
|
490
490
|
> - `--all-responses-models`: scan every model that advertises `/responses`
|
|
491
491
|
> - `--model=<id>`: pin the Responses scan to one specific model
|
|
492
|
+
|
|
493
|
+
### Tool Support Probe
|
|
494
|
+
|
|
495
|
+
Tests which server-side tool types (bash, text_editor, web_search, memory, etc.) each Copilot model actually accepts. Useful for tracking backend changes over time.
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
bun scripts/probe-all-copilot-tools.ts # human-readable table
|
|
499
|
+
bun scripts/probe-all-copilot-tools.ts --json # JSON snapshot to stdout
|
|
500
|
+
bun scripts/probe-all-copilot-tools.ts --model=claude-opus-4.6 # single model
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
The JSON output is designed for weekly diffing — `generatedAt` is the only volatile field:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
# Compare two weekly snapshots
|
|
507
|
+
diff <(jq -S 'del(.generatedAt)' week1.json) <(jq -S 'del(.generatedAt)' week2.json)
|
|
508
|
+
```
|
package/dist/main.mjs
CHANGED
|
@@ -6340,6 +6340,33 @@ async function cacheVSCodeVersion() {
|
|
|
6340
6340
|
consola.debug(`Using VSCode version: ${response}`);
|
|
6341
6341
|
}
|
|
6342
6342
|
|
|
6343
|
+
//#endregion
|
|
6344
|
+
//#region src/lib/retry.ts
|
|
6345
|
+
/**
|
|
6346
|
+
* Retry an async operation with exponential backoff.
|
|
6347
|
+
* Delay schedule: baseDelayMs * 2^attempt (0-indexed), e.g. 5s, 10s, 20s, 40s.
|
|
6348
|
+
*/
|
|
6349
|
+
async function retryWithBackoff(fn, options) {
|
|
6350
|
+
const maxRetries = options?.maxRetries ?? 4;
|
|
6351
|
+
const baseDelayMs = options?.baseDelayMs ?? 5e3;
|
|
6352
|
+
const shouldRetry = options?.shouldRetry ?? (() => true);
|
|
6353
|
+
const onRetry = options?.onRetry;
|
|
6354
|
+
let lastError;
|
|
6355
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
6356
|
+
return await fn();
|
|
6357
|
+
} catch (error) {
|
|
6358
|
+
lastError = error;
|
|
6359
|
+
if (!shouldRetry(error) || attempt >= maxRetries) throw error;
|
|
6360
|
+
const delay = baseDelayMs * 2 ** attempt;
|
|
6361
|
+
onRetry?.(error, attempt, delay);
|
|
6362
|
+
await sleep(delay);
|
|
6363
|
+
}
|
|
6364
|
+
throw lastError;
|
|
6365
|
+
}
|
|
6366
|
+
function formatErrorMessage(error) {
|
|
6367
|
+
return error instanceof Error ? error.message : String(error);
|
|
6368
|
+
}
|
|
6369
|
+
|
|
6343
6370
|
//#endregion
|
|
6344
6371
|
//#region src/lib/token.ts
|
|
6345
6372
|
const TRAILING_SLASHES_RE = /\/+$/;
|
|
@@ -6354,20 +6381,28 @@ async function setupCopilotToken() {
|
|
|
6354
6381
|
consola.debug("GitHub Copilot Token fetched successfully!");
|
|
6355
6382
|
if (state.config.showToken) consola.info("Copilot token:", response.token);
|
|
6356
6383
|
const refreshInterval = (response.refresh_in - 60) * 1e3;
|
|
6357
|
-
const
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
applyCopilotTokenState(refreshed);
|
|
6362
|
-
consola.debug("Copilot token refreshed");
|
|
6363
|
-
if (state.config.showToken) consola.info("Refreshed Copilot token:", refreshed.token);
|
|
6364
|
-
} catch (error) {
|
|
6365
|
-
consola.error("Failed to refresh Copilot token:", error);
|
|
6366
|
-
}
|
|
6384
|
+
const scheduleRefresh = () => {
|
|
6385
|
+
setTimeout(() => {
|
|
6386
|
+
refreshCopilotToken(githubClient).then(scheduleRefresh);
|
|
6387
|
+
}, refreshInterval);
|
|
6367
6388
|
};
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6389
|
+
scheduleRefresh();
|
|
6390
|
+
}
|
|
6391
|
+
async function refreshCopilotToken(githubClient) {
|
|
6392
|
+
consola.debug("Refreshing Copilot token");
|
|
6393
|
+
try {
|
|
6394
|
+
const refreshed = await retryWithBackoff(() => githubClient.getCopilotToken(), {
|
|
6395
|
+
shouldRetry: (error) => !(error instanceof HTTPError) || isTransientHttpError(error),
|
|
6396
|
+
onRetry: (error, attempt, delayMs) => {
|
|
6397
|
+
consola.warn(`Token refresh failed (attempt ${attempt + 1}), retrying in ${delayMs / 1e3}s:`, formatErrorMessage(error));
|
|
6398
|
+
}
|
|
6399
|
+
});
|
|
6400
|
+
applyCopilotTokenState(refreshed);
|
|
6401
|
+
consola.debug("Copilot token refreshed");
|
|
6402
|
+
if (state.config.showToken) consola.info("Refreshed Copilot token:", refreshed.token);
|
|
6403
|
+
} catch (error) {
|
|
6404
|
+
consola.error("Failed to refresh Copilot token:", error);
|
|
6405
|
+
}
|
|
6371
6406
|
}
|
|
6372
6407
|
async function setupGitHubToken(options) {
|
|
6373
6408
|
try {
|
|
@@ -6416,6 +6451,17 @@ async function setupGitHubToken(options) {
|
|
|
6416
6451
|
function isAuthError(error) {
|
|
6417
6452
|
return error instanceof HTTPError && (error.status === 401 || error.status === 403);
|
|
6418
6453
|
}
|
|
6454
|
+
const TRANSIENT_HTTP_STATUSES = new Set([
|
|
6455
|
+
408,
|
|
6456
|
+
429,
|
|
6457
|
+
500,
|
|
6458
|
+
502,
|
|
6459
|
+
503,
|
|
6460
|
+
504
|
|
6461
|
+
]);
|
|
6462
|
+
function isTransientHttpError(error) {
|
|
6463
|
+
return TRANSIENT_HTTP_STATUSES.has(error.status);
|
|
6464
|
+
}
|
|
6419
6465
|
async function logUser() {
|
|
6420
6466
|
const user = await createGitHubClient().getGitHubUser();
|
|
6421
6467
|
state.cache.githubLogin = user.login;
|
|
@@ -6533,7 +6579,7 @@ const checkUsage = defineCommand({
|
|
|
6533
6579
|
|
|
6534
6580
|
//#endregion
|
|
6535
6581
|
//#region src/lib/version.ts
|
|
6536
|
-
const VERSION = "0.5.
|
|
6582
|
+
const VERSION = "0.5.7";
|
|
6537
6583
|
|
|
6538
6584
|
//#endregion
|
|
6539
6585
|
//#region src/debug.ts
|
|
@@ -46879,20 +46925,29 @@ const methodColors = {
|
|
|
46879
46925
|
function colorizeMethod(method) {
|
|
46880
46926
|
return colorize(methodColors[method] ?? "white", method);
|
|
46881
46927
|
}
|
|
46928
|
+
function getEffectiveModel(info) {
|
|
46929
|
+
return info.steps.length > 0 ? info.steps.at(-1).result : info.originalModel ?? "-";
|
|
46930
|
+
}
|
|
46931
|
+
function appendModelStep(info, tag, newModel) {
|
|
46932
|
+
if (newModel === getEffectiveModel(info)) return info;
|
|
46933
|
+
return {
|
|
46934
|
+
originalModel: info.originalModel,
|
|
46935
|
+
steps: [...info.steps, {
|
|
46936
|
+
tag,
|
|
46937
|
+
result: newModel
|
|
46938
|
+
}]
|
|
46939
|
+
};
|
|
46940
|
+
}
|
|
46882
46941
|
function formatModelMapping(info) {
|
|
46883
46942
|
if (!info) return "";
|
|
46884
|
-
const { originalModel,
|
|
46885
|
-
if (!originalModel &&
|
|
46886
|
-
const parts = [];
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
parts.push(colorize("dim",
|
|
46891
|
-
parts.push(colorize("cyanBright",
|
|
46892
|
-
}
|
|
46893
|
-
if (mappedModel && mappedModel !== (rewrittenModel ?? displayOriginal)) {
|
|
46894
|
-
parts.push(colorize("dim", "→"));
|
|
46895
|
-
parts.push(colorize("greenBright", mappedModel));
|
|
46943
|
+
const { originalModel, steps } = info;
|
|
46944
|
+
if (!originalModel && steps.length === 0) return "";
|
|
46945
|
+
const parts = [colorize("blueBright", originalModel ?? "-")];
|
|
46946
|
+
for (let i = 0; i < steps.length; i++) {
|
|
46947
|
+
const step = steps[i];
|
|
46948
|
+
const isLast = i === steps.length - 1;
|
|
46949
|
+
parts.push(colorize("dim", `-[${step.tag}]->`));
|
|
46950
|
+
parts.push(colorize(isLast ? "greenBright" : "cyanBright", step.result));
|
|
46896
46951
|
}
|
|
46897
46952
|
return ` ${colorize("dim", "model=")}${parts.join(" ")}`;
|
|
46898
46953
|
}
|
|
@@ -48569,13 +48624,15 @@ function rewriteModel(modelId) {
|
|
|
48569
48624
|
if (userRules) {
|
|
48570
48625
|
for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
|
|
48571
48626
|
originalModel: modelId,
|
|
48572
|
-
model: normalizeToKnownModel(rule.to) ?? rule.to
|
|
48627
|
+
model: normalizeToKnownModel(rule.to) ?? rule.to,
|
|
48628
|
+
reason: "CONFIG_REWRITE"
|
|
48573
48629
|
};
|
|
48574
48630
|
}
|
|
48575
48631
|
const normalized = normalizeToKnownModel(modelId);
|
|
48576
48632
|
if (normalized && normalized !== modelId) return {
|
|
48577
48633
|
originalModel: modelId,
|
|
48578
|
-
model: normalized
|
|
48634
|
+
model: normalized,
|
|
48635
|
+
reason: "AUTO_CORRECT"
|
|
48579
48636
|
};
|
|
48580
48637
|
return {
|
|
48581
48638
|
originalModel: modelId,
|
|
@@ -49279,8 +49336,13 @@ const responsesReasoningSummarySchema = object({
|
|
|
49279
49336
|
const responsesReasoningInputSchema = object({
|
|
49280
49337
|
id: string().optional(),
|
|
49281
49338
|
type: literal("reasoning"),
|
|
49282
|
-
summary: array(responsesReasoningSummarySchema),
|
|
49283
|
-
encrypted_content: string().
|
|
49339
|
+
summary: array(responsesReasoningSummarySchema).optional(),
|
|
49340
|
+
encrypted_content: string().nullable().optional(),
|
|
49341
|
+
status: _enum([
|
|
49342
|
+
"in_progress",
|
|
49343
|
+
"completed",
|
|
49344
|
+
"incomplete"
|
|
49345
|
+
]).optional()
|
|
49284
49346
|
}).loose();
|
|
49285
49347
|
const responsesCompactionInputSchema = object({
|
|
49286
49348
|
id: string().min(1),
|
|
@@ -49513,7 +49575,11 @@ async function handleCompletionCore({ body, signal, headers }) {
|
|
|
49513
49575
|
const requestContext = normalizeChatRequestContext(payload, headers);
|
|
49514
49576
|
consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
|
|
49515
49577
|
const rewrite = applyModelRewrite(payload);
|
|
49516
|
-
const
|
|
49578
|
+
const steps = [];
|
|
49579
|
+
if (rewrite.reason) steps.push({
|
|
49580
|
+
tag: rewrite.reason,
|
|
49581
|
+
result: rewrite.model
|
|
49582
|
+
});
|
|
49517
49583
|
const selectedModel = findModelById(payload.model);
|
|
49518
49584
|
try {
|
|
49519
49585
|
if (selectedModel) {
|
|
@@ -49532,11 +49598,10 @@ async function handleCompletionCore({ body, signal, headers }) {
|
|
|
49532
49598
|
}
|
|
49533
49599
|
const upstreamSignal = createUpstreamSignalFromConfig(signal);
|
|
49534
49600
|
const plan = adapter.toCapiPlan(payload, { requestContext });
|
|
49535
|
-
const modelMapping = {
|
|
49536
|
-
originalModel,
|
|
49537
|
-
|
|
49538
|
-
|
|
49539
|
-
};
|
|
49601
|
+
const modelMapping = appendModelStep({
|
|
49602
|
+
originalModel: rewrite.originalModel,
|
|
49603
|
+
steps
|
|
49604
|
+
}, "MODEL_RESOLVE", plan.resolvedModel);
|
|
49540
49605
|
const transport = new CopilotTransport(createCopilotClient());
|
|
49541
49606
|
consola.debug("Streaming response");
|
|
49542
49607
|
return {
|
|
@@ -50913,10 +50978,6 @@ const responsesApiEntry = {
|
|
|
50913
50978
|
if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
|
|
50914
50979
|
throw error;
|
|
50915
50980
|
}
|
|
50916
|
-
const modelMapping = {
|
|
50917
|
-
originalModel: ctx.modelMapping.originalModel,
|
|
50918
|
-
mappedModel: responsesPayload.model
|
|
50919
|
-
};
|
|
50920
50981
|
applyContextManagement(responsesPayload, ctx.selectedModel?.capabilities.limits.max_prompt_tokens);
|
|
50921
50982
|
compactInputByLatestCompaction(responsesPayload);
|
|
50922
50983
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
@@ -50927,7 +50988,7 @@ const responsesApiEntry = {
|
|
|
50927
50988
|
signal: ctx.upstreamSignal.signal,
|
|
50928
50989
|
requestContext: ctx.requestContext
|
|
50929
50990
|
}), ctx.upstreamSignal),
|
|
50930
|
-
modelMapping
|
|
50991
|
+
modelMapping: ctx.modelMapping
|
|
50931
50992
|
};
|
|
50932
50993
|
}
|
|
50933
50994
|
};
|
|
@@ -50943,10 +51004,7 @@ const chatCompletionsEntry = {
|
|
|
50943
51004
|
if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
|
|
50944
51005
|
throw error;
|
|
50945
51006
|
}
|
|
50946
|
-
const modelMapping =
|
|
50947
|
-
originalModel: ctx.modelMapping.originalModel,
|
|
50948
|
-
mappedModel: plan.resolvedModel
|
|
50949
|
-
};
|
|
51007
|
+
const modelMapping = appendModelStep(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
|
|
50950
51008
|
consola.debug("Claude Code requested model:", ctx.anthropicPayload.model, "-> Copilot model:", plan.resolvedModel);
|
|
50951
51009
|
if (consola.level >= 4) consola.debug("Planned Copilot request payload:", JSON.stringify(plan.payload));
|
|
50952
51010
|
return {
|
|
@@ -50996,17 +51054,33 @@ async function handleMessagesCore({ body, signal, headers }) {
|
|
|
50996
51054
|
const requestContext = normalizeAnthropicRequestContext(anthropicPayload, headers);
|
|
50997
51055
|
if (consola.level >= 4) consola.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
|
|
50998
51056
|
const rewrite = applyModelRewrite(anthropicPayload);
|
|
51057
|
+
const steps = [];
|
|
51058
|
+
if (rewrite.reason) steps.push({
|
|
51059
|
+
tag: rewrite.reason,
|
|
51060
|
+
result: rewrite.model
|
|
51061
|
+
});
|
|
50999
51062
|
const betaResult = processAnthropicBetaHeader(headers.get("anthropic-beta"), anthropicPayload.model);
|
|
51000
51063
|
if (betaResult.upgradeTarget) {
|
|
51001
51064
|
consola.debug(`Beta header context upgrade: ${anthropicPayload.model} → ${betaResult.upgradeTarget}`);
|
|
51002
51065
|
anthropicPayload.model = betaResult.upgradeTarget;
|
|
51066
|
+
steps.push({
|
|
51067
|
+
tag: "BETA_UPGRADE",
|
|
51068
|
+
result: betaResult.upgradeTarget
|
|
51069
|
+
});
|
|
51003
51070
|
}
|
|
51004
51071
|
const anthropicBetaHeader = betaResult.header;
|
|
51005
51072
|
const modelRouting = applyMessagesModelPolicy(anthropicPayload, { betaUpgraded: !!betaResult.upgradeTarget });
|
|
51073
|
+
if (modelRouting.reason === "context-upgrade") steps.push({
|
|
51074
|
+
tag: "CONTEXT_UPGRADE",
|
|
51075
|
+
result: modelRouting.routedModel
|
|
51076
|
+
});
|
|
51077
|
+
else if (modelRouting.reason === "compact") steps.push({
|
|
51078
|
+
tag: "COMPACT",
|
|
51079
|
+
result: modelRouting.routedModel
|
|
51080
|
+
});
|
|
51006
51081
|
const modelMapping = {
|
|
51007
51082
|
originalModel: rewrite.originalModel,
|
|
51008
|
-
|
|
51009
|
-
mappedModel: modelRouting.routedModel
|
|
51083
|
+
steps
|
|
51010
51084
|
};
|
|
51011
51085
|
if (modelRouting.reason) consola.debug(`Routed anthropic request via ${modelRouting.reason}:`, `${modelRouting.originalModel} -> ${modelRouting.routedModel}`);
|
|
51012
51086
|
const selectedModel = findModelById(anthropicPayload.model);
|
|
@@ -51040,8 +51114,10 @@ async function handleMessagesCore({ body, signal, headers }) {
|
|
|
51040
51114
|
upstreamSignal: retrySignal,
|
|
51041
51115
|
modelMapping: {
|
|
51042
51116
|
originalModel: rewrite.originalModel,
|
|
51043
|
-
|
|
51044
|
-
|
|
51117
|
+
steps: [...steps, {
|
|
51118
|
+
tag: "RETRY_UPGRADE",
|
|
51119
|
+
result: upgradeTarget
|
|
51120
|
+
}]
|
|
51045
51121
|
}
|
|
51046
51122
|
});
|
|
51047
51123
|
}
|
|
@@ -51458,8 +51534,10 @@ async function handleResponsesCore({ body, signal, headers }) {
|
|
|
51458
51534
|
result,
|
|
51459
51535
|
modelMapping: {
|
|
51460
51536
|
originalModel: rewrite.originalModel,
|
|
51461
|
-
|
|
51462
|
-
|
|
51537
|
+
steps: rewrite.reason ? [{
|
|
51538
|
+
tag: rewrite.reason,
|
|
51539
|
+
result: rewrite.model
|
|
51540
|
+
}] : []
|
|
51463
51541
|
}
|
|
51464
51542
|
};
|
|
51465
51543
|
}
|
|
@@ -51705,7 +51783,7 @@ function createServer(options) {
|
|
|
51705
51783
|
const model = body && typeof body === "object" && "model" in body ? body.model : void 0;
|
|
51706
51784
|
if (typeof model === "string") setRequestModelMapping(request, {
|
|
51707
51785
|
originalModel: model,
|
|
51708
|
-
|
|
51786
|
+
steps: []
|
|
51709
51787
|
});
|
|
51710
51788
|
}).onAfterResponse(({ request, requestStart, set }) => {
|
|
51711
51789
|
const elapsed = formatElapsed(requestStart);
|