ghc-proxy 0.5.6 → 0.5.8

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.mjs CHANGED
@@ -2,9 +2,9 @@
2
2
  import { createRequire } from "node:module";
3
3
  import process$1 from "node:process";
4
4
  import { formatWithOptions, parseArgs, promisify } from "node:util";
5
- import path, { sep } from "node:path";
5
+ import path, { join, sep } from "node:path";
6
6
  import * as tty from "node:tty";
7
- import fs from "node:fs/promises";
7
+ import fs, { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
8
8
  import os from "node:os";
9
9
  import { randomUUID } from "node:crypto";
10
10
  import { execFile, execFileSync } from "node:child_process";
@@ -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 refreshCopilotToken = async () => {
6358
- consola.debug("Refreshing Copilot token");
6359
- try {
6360
- const refreshed = await githubClient.getCopilotToken();
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
- setInterval(() => {
6369
- refreshCopilotToken();
6370
- }, refreshInterval);
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.6";
6582
+ const VERSION = "0.5.8";
6537
6583
 
6538
6584
  //#endregion
6539
6585
  //#region src/debug.ts
@@ -18492,7 +18538,7 @@ var require_snapshot_utils = /* @__PURE__ */ __commonJSMin$1(((exports, module)
18492
18538
  //#endregion
18493
18539
  //#region node_modules/undici/lib/mock/snapshot-recorder.js
18494
18540
  var require_snapshot_recorder = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
18495
- const { writeFile, readFile, mkdir } = __require$1("node:fs/promises");
18541
+ const { writeFile: writeFile$1, readFile, mkdir: mkdir$1 } = __require$1("node:fs/promises");
18496
18542
  const { dirname, resolve } = __require$1("node:path");
18497
18543
  const { setTimeout: setTimeout$1, clearTimeout: clearTimeout$1 } = __require$1("node:timers");
18498
18544
  const { InvalidArgumentError, UndiciError } = require_errors();
@@ -18779,12 +18825,12 @@ var require_snapshot_recorder = /* @__PURE__ */ __commonJSMin$1(((exports, modul
18779
18825
  const path = filePath || this.#snapshotPath;
18780
18826
  if (!path) throw new InvalidArgumentError("Snapshot path is required");
18781
18827
  const resolvedPath = resolve(path);
18782
- await mkdir(dirname(resolvedPath), { recursive: true });
18828
+ await mkdir$1(dirname(resolvedPath), { recursive: true });
18783
18829
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
18784
18830
  hash,
18785
18831
  snapshot
18786
18832
  }));
18787
- await writeFile(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
18833
+ await writeFile$1(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
18788
18834
  }
18789
18835
  /**
18790
18836
  * Clears all recorded snapshots
@@ -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, rewrittenModel, mappedModel } = info;
46885
- if (!originalModel && !rewrittenModel && !mappedModel) return "";
46886
- const parts = [];
46887
- const displayOriginal = originalModel ?? "-";
46888
- parts.push(colorize("blueBright", displayOriginal));
46889
- if (rewrittenModel && rewrittenModel !== displayOriginal) {
46890
- parts.push(colorize("dim", "~>"));
46891
- parts.push(colorize("cyanBright", rewrittenModel));
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
  }
@@ -47584,8 +47639,11 @@ function normalizeSystemBlocks(system) {
47584
47639
  }];
47585
47640
  }
47586
47641
  function normalizeToolResultContent(block) {
47587
- if (typeof block.content === "string") return [textBlock(block.content)];
47588
- return block.content.map((contentBlock) => {
47642
+ return normalizeToolResultContentValue(block.content);
47643
+ }
47644
+ function normalizeToolResultContentValue(content) {
47645
+ if (typeof content === "string") return [textBlock(content)];
47646
+ return content.map((contentBlock) => {
47589
47647
  switch (contentBlock.type) {
47590
47648
  case "text": return textBlock(contentBlock.text);
47591
47649
  case "image": return imageBlock(contentBlock.source.media_type, contentBlock.source.data);
@@ -47593,6 +47651,15 @@ function normalizeToolResultContent(block) {
47593
47651
  }
47594
47652
  });
47595
47653
  }
47654
+ function normalizeMcpToolResultContent(block) {
47655
+ return normalizeToolResultContentValue(block.content);
47656
+ }
47657
+ function normalizeServerToolResultContent(block) {
47658
+ return [textBlock(typeof block.content === "string" ? block.content : JSON.stringify(block.content) ?? "")];
47659
+ }
47660
+ function describeDocumentBlock(block) {
47661
+ return `[document attachment omitted: ${typeof block.source.type === "string" ? block.source.type : "unknown"}]`;
47662
+ }
47596
47663
  function normalizeMessage(message) {
47597
47664
  if (typeof message.content === "string") return {
47598
47665
  role: message.role,
@@ -47607,7 +47674,13 @@ function normalizeMessage(message) {
47607
47674
  thinking: block.thinking,
47608
47675
  signature: block.signature
47609
47676
  };
47610
- case "tool_use": return {
47677
+ case "redacted_thinking": return {
47678
+ kind: "redacted_thinking",
47679
+ data: block.data
47680
+ };
47681
+ case "tool_use":
47682
+ case "server_tool_use":
47683
+ case "mcp_tool_use": return {
47611
47684
  kind: "tool_use",
47612
47685
  id: block.id,
47613
47686
  name: block.name,
@@ -47619,6 +47692,25 @@ function normalizeMessage(message) {
47619
47692
  content: normalizeToolResultContent(block),
47620
47693
  isError: block.is_error
47621
47694
  };
47695
+ case "mcp_tool_result": return {
47696
+ kind: "tool_result",
47697
+ toolUseId: block.tool_use_id,
47698
+ content: normalizeMcpToolResultContent(block),
47699
+ isError: block.is_error
47700
+ };
47701
+ case "server_tool_result":
47702
+ case "web_search_tool_result":
47703
+ case "web_fetch_tool_result":
47704
+ case "code_execution_tool_result":
47705
+ case "bash_code_execution_tool_result":
47706
+ case "text_editor_code_execution_tool_result":
47707
+ case "tool_search_tool_result": return {
47708
+ kind: "tool_result",
47709
+ toolUseId: block.tool_use_id,
47710
+ content: normalizeServerToolResultContent(block),
47711
+ isError: block.is_error
47712
+ };
47713
+ case "document": return textBlock(describeDocumentBlock(block));
47622
47714
  default: return assertNever(block);
47623
47715
  }
47624
47716
  });
@@ -47983,6 +48075,10 @@ function mapBlocks(response) {
47983
48075
  thinking: block.thinking,
47984
48076
  signature: block.signature
47985
48077
  };
48078
+ case "redacted_thinking": return {
48079
+ type: "redacted_thinking",
48080
+ data: block.data
48081
+ };
47986
48082
  case "tool_use": return {
47987
48083
  type: "tool_use",
47988
48084
  id: block.id,
@@ -48157,6 +48253,10 @@ function toConversationBlock(block) {
48157
48253
  text: block.thinking,
48158
48254
  signature: block.signature
48159
48255
  };
48256
+ case "redacted_thinking": return {
48257
+ kind: "redacted_thinking",
48258
+ data: block.data
48259
+ };
48160
48260
  case "tool_use": return {
48161
48261
  kind: "tool_use",
48162
48262
  id: block.id,
@@ -48205,6 +48305,9 @@ function recordAnthropicRequestIssues(request, context) {
48205
48305
  for (const block of turn.blocks) if (block.kind === "thinking") {
48206
48306
  sawThinking = true;
48207
48307
  if (sawToolUse) sawTextOrThinkingAfterTool = true;
48308
+ } else if (block.kind === "redacted_thinking") {
48309
+ sawThinking = true;
48310
+ if (sawToolUse) sawTextOrThinkingAfterTool = true;
48208
48311
  } else if (block.kind === "text") {
48209
48312
  if (sawToolUse) sawTextOrThinkingAfterTool = true;
48210
48313
  } else if (block.kind === "tool_use") sawToolUse = true;
@@ -48569,13 +48672,15 @@ function rewriteModel(modelId) {
48569
48672
  if (userRules) {
48570
48673
  for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
48571
48674
  originalModel: modelId,
48572
- model: normalizeToKnownModel(rule.to) ?? rule.to
48675
+ model: normalizeToKnownModel(rule.to) ?? rule.to,
48676
+ reason: "CONFIG_REWRITE"
48573
48677
  };
48574
48678
  }
48575
48679
  const normalized = normalizeToKnownModel(modelId);
48576
48680
  if (normalized && normalized !== modelId) return {
48577
48681
  originalModel: modelId,
48578
- model: normalized
48682
+ model: normalized,
48683
+ reason: "AUTO_CORRECT"
48579
48684
  };
48580
48685
  return {
48581
48686
  originalModel: modelId,
@@ -48874,12 +48979,30 @@ function estimateContentBlockChars(blocks) {
48874
48979
  case "thinking":
48875
48980
  chars += block.thinking.length;
48876
48981
  break;
48982
+ case "redacted_thinking":
48983
+ chars += block.data.length;
48984
+ break;
48877
48985
  case "tool_use":
48986
+ case "server_tool_use":
48987
+ case "mcp_tool_use":
48878
48988
  chars += JSON.stringify(block.input).length;
48879
48989
  break;
48880
48990
  case "tool_result":
48991
+ case "mcp_tool_result":
48881
48992
  chars += typeof block.content === "string" ? block.content.length : JSON.stringify(block.content ?? "").length;
48882
48993
  break;
48994
+ case "server_tool_result":
48995
+ case "web_search_tool_result":
48996
+ case "web_fetch_tool_result":
48997
+ case "code_execution_tool_result":
48998
+ case "bash_code_execution_tool_result":
48999
+ case "text_editor_code_execution_tool_result":
49000
+ case "tool_search_tool_result":
49001
+ chars += JSON.stringify(block.content ?? "").length;
49002
+ break;
49003
+ case "document":
49004
+ chars += JSON.stringify(block).length;
49005
+ break;
48883
49006
  case "image":
48884
49007
  chars += 1e3;
48885
49008
  break;
@@ -48970,12 +49093,29 @@ const anthropicThinkingBlockSchema = object({
48970
49093
  thinking: string(),
48971
49094
  signature: string().optional()
48972
49095
  }).loose();
49096
+ const anthropicRedactedThinkingBlockSchema = object({
49097
+ type: literal("redacted_thinking"),
49098
+ data: string()
49099
+ }).loose();
48973
49100
  const anthropicToolUseBlockSchema = object({
48974
49101
  type: literal("tool_use"),
48975
49102
  id: string().min(1),
48976
49103
  name: string().min(1),
48977
49104
  input: jsonObjectSchema
48978
49105
  }).loose();
49106
+ const anthropicServerToolUseBlockSchema = object({
49107
+ type: literal("server_tool_use"),
49108
+ id: string().min(1),
49109
+ name: string().min(1),
49110
+ input: jsonObjectSchema
49111
+ }).loose();
49112
+ const anthropicMcpToolUseBlockSchema = object({
49113
+ type: literal("mcp_tool_use"),
49114
+ id: string().min(1),
49115
+ name: string().min(1),
49116
+ input: jsonObjectSchema,
49117
+ server_name: string().min(1)
49118
+ }).loose();
48979
49119
  const anthropicToolResultContentBlockSchema = union([anthropicTextBlockSchema, anthropicImageBlockSchema]);
48980
49120
  const anthropicToolResultBlockSchema = object({
48981
49121
  type: literal("tool_result"),
@@ -48983,12 +49123,39 @@ const anthropicToolResultBlockSchema = object({
48983
49123
  content: union([string(), array(anthropicToolResultContentBlockSchema)]),
48984
49124
  is_error: boolean().optional()
48985
49125
  }).loose();
49126
+ const anthropicMcpToolResultBlockSchema = object({
49127
+ type: literal("mcp_tool_result"),
49128
+ tool_use_id: string().min(1),
49129
+ content: union([string(), array(anthropicToolResultContentBlockSchema)]),
49130
+ is_error: boolean().optional()
49131
+ }).loose();
49132
+ const anthropicServerToolResultBlockSchema = object({
49133
+ type: _enum([
49134
+ "server_tool_result",
49135
+ "web_search_tool_result",
49136
+ "web_fetch_tool_result",
49137
+ "code_execution_tool_result",
49138
+ "bash_code_execution_tool_result",
49139
+ "text_editor_code_execution_tool_result",
49140
+ "tool_search_tool_result"
49141
+ ]),
49142
+ tool_use_id: string().min(1),
49143
+ content: unknown(),
49144
+ is_error: boolean().optional()
49145
+ }).loose();
49146
+ const anthropicDocumentBlockSchema = object({
49147
+ type: literal("document"),
49148
+ source: jsonObjectSchema
49149
+ }).loose();
48986
49150
  const anthropicUserMessageSchema = object({
48987
49151
  role: literal("user"),
48988
49152
  content: union([string(), array(union([
48989
49153
  anthropicTextBlockSchema,
48990
49154
  anthropicImageBlockSchema,
48991
- anthropicToolResultBlockSchema
49155
+ anthropicToolResultBlockSchema,
49156
+ anthropicMcpToolResultBlockSchema,
49157
+ anthropicServerToolResultBlockSchema,
49158
+ anthropicDocumentBlockSchema
48992
49159
  ]))])
48993
49160
  }).loose();
48994
49161
  const anthropicAssistantMessageSchema = object({
@@ -48996,7 +49163,12 @@ const anthropicAssistantMessageSchema = object({
48996
49163
  content: union([string(), array(union([
48997
49164
  anthropicTextBlockSchema,
48998
49165
  anthropicThinkingBlockSchema,
48999
- anthropicToolUseBlockSchema
49166
+ anthropicRedactedThinkingBlockSchema,
49167
+ anthropicToolUseBlockSchema,
49168
+ anthropicServerToolUseBlockSchema,
49169
+ anthropicMcpToolUseBlockSchema,
49170
+ anthropicMcpToolResultBlockSchema,
49171
+ anthropicServerToolResultBlockSchema
49000
49172
  ]))])
49001
49173
  }).loose();
49002
49174
  const anthropicMessageSchema = union([anthropicUserMessageSchema, anthropicAssistantMessageSchema]);
@@ -49279,8 +49451,13 @@ const responsesReasoningSummarySchema = object({
49279
49451
  const responsesReasoningInputSchema = object({
49280
49452
  id: string().optional(),
49281
49453
  type: literal("reasoning"),
49282
- summary: array(responsesReasoningSummarySchema),
49283
- encrypted_content: string().min(1)
49454
+ summary: array(responsesReasoningSummarySchema).optional(),
49455
+ encrypted_content: string().nullable().optional(),
49456
+ status: _enum([
49457
+ "in_progress",
49458
+ "completed",
49459
+ "incomplete"
49460
+ ]).optional()
49284
49461
  }).loose();
49285
49462
  const responsesCompactionInputSchema = object({
49286
49463
  id: string().min(1),
@@ -49513,7 +49690,11 @@ async function handleCompletionCore({ body, signal, headers }) {
49513
49690
  const requestContext = normalizeChatRequestContext(payload, headers);
49514
49691
  consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
49515
49692
  const rewrite = applyModelRewrite(payload);
49516
- const originalModel = rewrite.originalModel;
49693
+ const steps = [];
49694
+ if (rewrite.reason) steps.push({
49695
+ tag: rewrite.reason,
49696
+ result: rewrite.model
49697
+ });
49517
49698
  const selectedModel = findModelById(payload.model);
49518
49699
  try {
49519
49700
  if (selectedModel) {
@@ -49532,11 +49713,10 @@ async function handleCompletionCore({ body, signal, headers }) {
49532
49713
  }
49533
49714
  const upstreamSignal = createUpstreamSignalFromConfig(signal);
49534
49715
  const plan = adapter.toCapiPlan(payload, { requestContext });
49535
- const modelMapping = {
49536
- originalModel,
49537
- rewrittenModel: rewrite.model,
49538
- mappedModel: plan.resolvedModel
49539
- };
49716
+ const modelMapping = appendModelStep({
49717
+ originalModel: rewrite.originalModel,
49718
+ steps
49719
+ }, "MODEL_RESOLVE", plan.resolvedModel);
49540
49720
  const transport = new CopilotTransport(createCopilotClient());
49541
49721
  consola.debug("Streaming response");
49542
49722
  return {
@@ -49847,11 +50027,16 @@ function translateUserMessage(message) {
49847
50027
  const items = [];
49848
50028
  const pendingContent = [];
49849
50029
  for (const block of message.content) {
49850
- if (block.type === "tool_result") {
50030
+ if (block.type === "tool_result" || block.type === "mcp_tool_result") {
49851
50031
  flushPendingContent(pendingContent, items, { role: "user" });
49852
50032
  items.push(createFunctionCallOutput(block));
49853
50033
  continue;
49854
50034
  }
50035
+ if (isServerToolResultBlock(block)) {
50036
+ flushPendingContent(pendingContent, items, { role: "user" });
50037
+ items.push(createServerFunctionCallOutput(block));
50038
+ continue;
50039
+ }
49855
50040
  const converted = translateUserContentBlock(block);
49856
50041
  if (converted) pendingContent.push(converted);
49857
50042
  }
@@ -49865,7 +50050,7 @@ function translateAssistantMessage(message) {
49865
50050
  const items = [];
49866
50051
  const pendingContent = [];
49867
50052
  for (const block of message.content) {
49868
- if (block.type === "tool_use") {
50053
+ if (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use") {
49869
50054
  flushPendingContent(pendingContent, items, {
49870
50055
  role: "assistant",
49871
50056
  phase: assistantPhase
@@ -49873,6 +50058,30 @@ function translateAssistantMessage(message) {
49873
50058
  items.push(createFunctionToolCall(block));
49874
50059
  continue;
49875
50060
  }
50061
+ if (block.type === "redacted_thinking") {
50062
+ flushPendingContent(pendingContent, items, {
50063
+ role: "assistant",
50064
+ phase: assistantPhase
50065
+ });
50066
+ items.push(createRedactedReasoningContent(block));
50067
+ continue;
50068
+ }
50069
+ if (block.type === "mcp_tool_result") {
50070
+ flushPendingContent(pendingContent, items, {
50071
+ role: "assistant",
50072
+ phase: assistantPhase
50073
+ });
50074
+ items.push(createFunctionCallOutput(block));
50075
+ continue;
50076
+ }
50077
+ if (isServerToolResultBlock(block)) {
50078
+ flushPendingContent(pendingContent, items, {
50079
+ role: "assistant",
50080
+ phase: assistantPhase
50081
+ });
50082
+ items.push(createServerFunctionCallOutput(block));
50083
+ continue;
50084
+ }
49876
50085
  if (block.type === "thinking" && block.signature) {
49877
50086
  const compaction = createCompactionContent(block);
49878
50087
  if (compaction) {
@@ -49908,6 +50117,7 @@ function translateUserContentBlock(block) {
49908
50117
  switch (block.type) {
49909
50118
  case "text": return createTextContent(block.text);
49910
50119
  case "image": return createImageContent(block);
50120
+ case "document": return createDocumentContent(block);
49911
50121
  default: return;
49912
50122
  }
49913
50123
  }
@@ -49937,7 +50147,7 @@ function resolveAssistantPhase(content) {
49937
50147
  let hasToolUse = false;
49938
50148
  for (const block of content) {
49939
50149
  if (block.type === "text") hasText = true;
49940
- else if (block.type === "tool_use") hasToolUse = true;
50150
+ else if (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use") hasToolUse = true;
49941
50151
  if (hasText && hasToolUse) break;
49942
50152
  }
49943
50153
  if (!hasText) return;
@@ -49962,6 +50172,23 @@ function createImageContent(block) {
49962
50172
  detail: "auto"
49963
50173
  };
49964
50174
  }
50175
+ function createDocumentContent(block) {
50176
+ const source = block.source;
50177
+ if (source.type === "file" && typeof source.file_id === "string") return {
50178
+ type: "input_file",
50179
+ file_id: source.file_id
50180
+ };
50181
+ if (source.type === "url" && typeof source.url === "string") return {
50182
+ type: "input_file",
50183
+ file_url: source.url
50184
+ };
50185
+ if (source.type === "base64" && typeof source.media_type === "string" && typeof source.data === "string") return {
50186
+ type: "input_file",
50187
+ file_data: `data:${source.media_type};base64,${source.data}`
50188
+ };
50189
+ if (source.type === "text" && typeof source.data === "string") return createTextContent(source.data);
50190
+ return createTextContent("[document attachment omitted]");
50191
+ }
49965
50192
  function createReasoningContent(block) {
49966
50193
  const { encryptedContent, id } = SignatureCodec.decodeReasoning(block.signature ?? "");
49967
50194
  const thinking = block.thinking === THINKING_TEXT ? "" : block.thinking;
@@ -49975,6 +50202,13 @@ function createReasoningContent(block) {
49975
50202
  encrypted_content: encryptedContent
49976
50203
  };
49977
50204
  }
50205
+ function createRedactedReasoningContent(block) {
50206
+ return {
50207
+ type: "reasoning",
50208
+ summary: [],
50209
+ encrypted_content: block.data
50210
+ };
50211
+ }
49978
50212
  function createCompactionContent(block) {
49979
50213
  const compaction = decodeCompactionCarrierSignature(block.signature ?? "");
49980
50214
  if (!compaction) return;
@@ -50001,6 +50235,17 @@ function createFunctionCallOutput(block) {
50001
50235
  status: block.is_error ? "incomplete" : "completed"
50002
50236
  };
50003
50237
  }
50238
+ function createServerFunctionCallOutput(block) {
50239
+ return {
50240
+ type: "function_call_output",
50241
+ call_id: block.tool_use_id,
50242
+ output: typeof block.content === "string" ? block.content : JSON.stringify(block.content) ?? "",
50243
+ status: block.is_error ? "incomplete" : "completed"
50244
+ };
50245
+ }
50246
+ function isServerToolResultBlock(block) {
50247
+ return block.type === "server_tool_result" || block.type === "web_search_tool_result" || block.type === "web_fetch_tool_result" || block.type === "code_execution_tool_result" || block.type === "bash_code_execution_tool_result" || block.type === "text_editor_code_execution_tool_result" || block.type === "tool_search_tool_result";
50248
+ }
50004
50249
  function translateSystemPrompt(system) {
50005
50250
  if (!system) return null;
50006
50251
  if (typeof system === "string") return system;
@@ -50913,10 +51158,6 @@ const responsesApiEntry = {
50913
51158
  if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
50914
51159
  throw error;
50915
51160
  }
50916
- const modelMapping = {
50917
- originalModel: ctx.modelMapping.originalModel,
50918
- mappedModel: responsesPayload.model
50919
- };
50920
51161
  applyContextManagement(responsesPayload, ctx.selectedModel?.capabilities.limits.max_prompt_tokens);
50921
51162
  compactInputByLatestCompaction(responsesPayload);
50922
51163
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
@@ -50927,7 +51168,7 @@ const responsesApiEntry = {
50927
51168
  signal: ctx.upstreamSignal.signal,
50928
51169
  requestContext: ctx.requestContext
50929
51170
  }), ctx.upstreamSignal),
50930
- modelMapping
51171
+ modelMapping: ctx.modelMapping
50931
51172
  };
50932
51173
  }
50933
51174
  };
@@ -50943,10 +51184,7 @@ const chatCompletionsEntry = {
50943
51184
  if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
50944
51185
  throw error;
50945
51186
  }
50946
- const modelMapping = {
50947
- originalModel: ctx.modelMapping.originalModel,
50948
- mappedModel: plan.resolvedModel
50949
- };
51187
+ const modelMapping = appendModelStep(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
50950
51188
  consola.debug("Claude Code requested model:", ctx.anthropicPayload.model, "-> Copilot model:", plan.resolvedModel);
50951
51189
  if (consola.level >= 4) consola.debug("Planned Copilot request payload:", JSON.stringify(plan.payload));
50952
51190
  return {
@@ -50996,17 +51234,33 @@ async function handleMessagesCore({ body, signal, headers }) {
50996
51234
  const requestContext = normalizeAnthropicRequestContext(anthropicPayload, headers);
50997
51235
  if (consola.level >= 4) consola.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
50998
51236
  const rewrite = applyModelRewrite(anthropicPayload);
51237
+ const steps = [];
51238
+ if (rewrite.reason) steps.push({
51239
+ tag: rewrite.reason,
51240
+ result: rewrite.model
51241
+ });
50999
51242
  const betaResult = processAnthropicBetaHeader(headers.get("anthropic-beta"), anthropicPayload.model);
51000
51243
  if (betaResult.upgradeTarget) {
51001
51244
  consola.debug(`Beta header context upgrade: ${anthropicPayload.model} → ${betaResult.upgradeTarget}`);
51002
51245
  anthropicPayload.model = betaResult.upgradeTarget;
51246
+ steps.push({
51247
+ tag: "BETA_UPGRADE",
51248
+ result: betaResult.upgradeTarget
51249
+ });
51003
51250
  }
51004
51251
  const anthropicBetaHeader = betaResult.header;
51005
51252
  const modelRouting = applyMessagesModelPolicy(anthropicPayload, { betaUpgraded: !!betaResult.upgradeTarget });
51253
+ if (modelRouting.reason === "context-upgrade") steps.push({
51254
+ tag: "CONTEXT_UPGRADE",
51255
+ result: modelRouting.routedModel
51256
+ });
51257
+ else if (modelRouting.reason === "compact") steps.push({
51258
+ tag: "COMPACT",
51259
+ result: modelRouting.routedModel
51260
+ });
51006
51261
  const modelMapping = {
51007
51262
  originalModel: rewrite.originalModel,
51008
- rewrittenModel: rewrite.model,
51009
- mappedModel: modelRouting.routedModel
51263
+ steps
51010
51264
  };
51011
51265
  if (modelRouting.reason) consola.debug(`Routed anthropic request via ${modelRouting.reason}:`, `${modelRouting.originalModel} -> ${modelRouting.routedModel}`);
51012
51266
  const selectedModel = findModelById(anthropicPayload.model);
@@ -51040,8 +51294,10 @@ async function handleMessagesCore({ body, signal, headers }) {
51040
51294
  upstreamSignal: retrySignal,
51041
51295
  modelMapping: {
51042
51296
  originalModel: rewrite.originalModel,
51043
- rewrittenModel: rewrite.model,
51044
- mappedModel: upgradeTarget
51297
+ steps: [...steps, {
51298
+ tag: "RETRY_UPGRADE",
51299
+ result: upgradeTarget
51300
+ }]
51045
51301
  }
51046
51302
  });
51047
51303
  }
@@ -51376,8 +51632,13 @@ function fixStreamIds(rawData, eventName, state) {
51376
51632
  function createResponsesPassthroughStrategy(copilotClient, payload, options) {
51377
51633
  const tracker = createStreamIdTracker();
51378
51634
  return {
51379
- execute() {
51380
- return copilotClient.createResponses(payload, options);
51635
+ async execute() {
51636
+ try {
51637
+ return await copilotClient.createResponses(payload, options);
51638
+ } catch (error) {
51639
+ if (error instanceof HTTPError && error.status === 400) dumpFailedPayload(payload, error).catch(() => {});
51640
+ throw error;
51641
+ }
51381
51642
  },
51382
51643
  isStream(result) {
51383
51644
  return Boolean(payload.stream) && isAsyncIterable(result);
@@ -51414,6 +51675,29 @@ function tryExtractTerminalResponse(rawData) {
51414
51675
  if (response && typeof response === "object") return response;
51415
51676
  } catch {}
51416
51677
  }
51678
+ const DUMP_DIR = join(PATHS.APP_DIR, "dumps");
51679
+ const MAX_DUMPS = 20;
51680
+ const TIMESTAMP_CHARS_RE = /[:.]/g;
51681
+ const DUMP_FILE_RE = /^\d{3}-/;
51682
+ async function dumpFailedPayload(payload, error) {
51683
+ try {
51684
+ await mkdir(DUMP_DIR, { recursive: true });
51685
+ const now = (/* @__PURE__ */ new Date()).toISOString();
51686
+ const ts = now.replace(TIMESTAMP_CHARS_RE, "-");
51687
+ const file = join(DUMP_DIR, `${error.status}-${ts}.json`);
51688
+ await writeFile(file, JSON.stringify({
51689
+ timestamp: now,
51690
+ error: {
51691
+ status: error.status,
51692
+ message: error.message
51693
+ },
51694
+ payload
51695
+ }, null, 2));
51696
+ consola.warn(`Dumped failed /responses payload → ${file}`);
51697
+ const dumps = (await readdir(DUMP_DIR)).filter((f) => DUMP_FILE_RE.test(f) && f.endsWith(".json")).sort();
51698
+ if (dumps.length > MAX_DUMPS) await Promise.all(dumps.slice(0, dumps.length - MAX_DUMPS).map((f) => unlink(join(DUMP_DIR, f)).catch(() => {})));
51699
+ } catch {}
51700
+ }
51417
51701
 
51418
51702
  //#endregion
51419
51703
  //#region src/routes/responses/handler.ts
@@ -51458,8 +51742,10 @@ async function handleResponsesCore({ body, signal, headers }) {
51458
51742
  result,
51459
51743
  modelMapping: {
51460
51744
  originalModel: rewrite.originalModel,
51461
- rewrittenModel: rewrite.model,
51462
- mappedModel: effectivePayload.model
51745
+ steps: rewrite.reason ? [{
51746
+ tag: rewrite.reason,
51747
+ result: rewrite.model
51748
+ }] : []
51463
51749
  }
51464
51750
  };
51465
51751
  }
@@ -51508,8 +51794,52 @@ function rejectUnsupportedBuiltinTools(payload) {
51508
51794
  for (const tool of payload.tools) if (tool.type === "web_search") throwInvalidRequestError("The selected Copilot endpoint does not support the Responses web_search tool.", "tools", "unsupported_tool_web_search");
51509
51795
  }
51510
51796
  function applyResponsesInputPolicies(payload) {
51797
+ payload.store = false;
51798
+ stripUnresolvableInputItems(payload);
51799
+ stripPhaseFromInputMessages(payload);
51511
51800
  rejectUnsupportedRemoteImageUrls(payload);
51512
51801
  }
51802
+ /**
51803
+ * Strip `phase` from input message items. The `phase` field is an output
51804
+ * annotation that some models may reject when sent back as input.
51805
+ */
51806
+ function stripPhaseFromInputMessages(payload) {
51807
+ if (!Array.isArray(payload.input)) return;
51808
+ let stripped = 0;
51809
+ for (const item of payload.input) {
51810
+ if (typeof item !== "object" || item === null) continue;
51811
+ const rec = item;
51812
+ if ((!("type" in rec) || rec.type === "message") && "phase" in rec) {
51813
+ delete rec.phase;
51814
+ stripped++;
51815
+ }
51816
+ }
51817
+ if (stripped > 0) consola.debug(`Stripped phase from ${stripped} input message item(s)`);
51818
+ }
51819
+ /**
51820
+ * Remove input items that Copilot cannot resolve and would trigger 404:
51821
+ * - `item_reference` items (opaque IDs from store=true sessions)
51822
+ * - `function_call_output` items whose `call_id` has no matching prior
51823
+ * `function_call` in the same input array (orphaned outputs)
51824
+ */
51825
+ function stripUnresolvableInputItems(payload) {
51826
+ if (!Array.isArray(payload.input)) return;
51827
+ const functionCallIds = /* @__PURE__ */ new Set();
51828
+ for (const item of payload.input) {
51829
+ if (typeof item !== "object" || item === null) continue;
51830
+ const rec = item;
51831
+ if (rec.type === "function_call" && typeof rec.call_id === "string") functionCallIds.add(rec.call_id);
51832
+ }
51833
+ const originalLength = payload.input.length;
51834
+ payload.input = payload.input.filter((item) => {
51835
+ if (typeof item !== "object" || item === null) return true;
51836
+ const rec = item;
51837
+ if (rec.type === "item_reference") return false;
51838
+ if (rec.type === "function_call_output" && typeof rec.call_id === "string" && !functionCallIds.has(rec.call_id)) return false;
51839
+ return true;
51840
+ });
51841
+ if (payload.input.length !== originalLength) consola.debug(`Stripped ${originalLength - payload.input.length} unresolvable input items (item_reference / orphaned function_call_output)`);
51842
+ }
51513
51843
  function rejectUnsupportedRemoteImageUrls(payload) {
51514
51844
  if (!Array.isArray(payload.input) || !containsRemoteImageUrl(payload.input)) return;
51515
51845
  throwInvalidRequestError("The selected Copilot endpoint does not support external image URLs on the Responses API. Use file_id or data URL image input instead.", "input", "unsupported_input_image_remote_url");
@@ -51624,7 +51954,7 @@ function parseBooleanParam(value) {
51624
51954
  //#region src/routes/responses/route.ts
51625
51955
  function createResponsesRoutes() {
51626
51956
  return new Elysia().use(requestGuardPlugin).post("/responses", async function* ({ body, request, server }) {
51627
- if (hasStreamingFlag(body)) disableIdleTimeout(server, request);
51957
+ disableIdleTimeout(server, request);
51628
51958
  const { result, modelMapping } = await handleResponsesCore({
51629
51959
  body,
51630
51960
  signal: request.signal,
@@ -51633,7 +51963,8 @@ function createResponsesRoutes() {
51633
51963
  if (modelMapping) setRequestModelMapping(request, modelMapping);
51634
51964
  if (result.kind === "json") return result.data;
51635
51965
  yield* sseAdapter(result.generator);
51636
- }, { guarded: true }).post("/responses/input_tokens", async ({ body, request }) => {
51966
+ }, { guarded: true }).post("/responses/input_tokens", async ({ body, request, server }) => {
51967
+ disableIdleTimeout(server, request);
51637
51968
  return handleCreateResponseInputTokensCore({
51638
51969
  body,
51639
51970
  headers: request.headers,
@@ -51705,7 +52036,7 @@ function createServer(options) {
51705
52036
  const model = body && typeof body === "object" && "model" in body ? body.model : void 0;
51706
52037
  if (typeof model === "string") setRequestModelMapping(request, {
51707
52038
  originalModel: model,
51708
- mappedModel: model
52039
+ steps: []
51709
52040
  });
51710
52041
  }).onAfterResponse(({ request, requestStart, set }) => {
51711
52042
  const elapsed = formatElapsed(requestStart);