ghc-proxy 0.6.2 → 0.7.0

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
@@ -5761,12 +5761,6 @@ const configFileSchema = object({
5761
5761
  from: string(),
5762
5762
  to: string()
5763
5763
  })).optional(),
5764
- contextUpgradeRules: array(object({
5765
- from: string(),
5766
- to: string()
5767
- })).optional(),
5768
- contextUpgrade: boolean().optional(),
5769
- contextUpgradeTokenThreshold: number().int().positive().optional(),
5770
5764
  upstreamQueueConcurrency: number().int().positive().optional(),
5771
5765
  upstreamQueueMaxRetries: number().int().nonnegative().optional(),
5772
5766
  upstreamQueueBaseDelaySeconds: number().int().nonnegative().optional(),
@@ -5855,12 +5849,6 @@ var ConfigStore = class {
5855
5849
  getEmulatorTtlSeconds() {
5856
5850
  return getCachedConfig().responsesOfficialEmulatorTtlSeconds ?? 14400;
5857
5851
  }
5858
- isContextUpgradeEnabled() {
5859
- return getCachedConfig().contextUpgrade !== false;
5860
- }
5861
- getContextUpgradeThreshold() {
5862
- return getCachedConfig().contextUpgradeTokenThreshold ?? 16e4;
5863
- }
5864
5852
  isCompactSmallModelEnabled() {
5865
5853
  return getCachedConfig().compactUseSmallModel ?? false;
5866
5854
  }
@@ -5886,33 +5874,221 @@ var ConfigStore = class {
5886
5874
  getModelRewrites() {
5887
5875
  return getCachedConfig().modelRewrites ?? [];
5888
5876
  }
5889
- getContextUpgradeRules() {
5890
- return getCachedConfig().contextUpgradeRules ?? [];
5891
- }
5892
5877
  getModelFallback() {
5893
5878
  return getCachedConfig().modelFallback;
5894
5879
  }
5895
- getUpstreamQueueConcurrency() {
5896
- return getCachedConfig().upstreamQueueConcurrency;
5880
+ };
5881
+ const configStore = new ConfigStore();
5882
+ //#endregion
5883
+ //#region src/state/model-cache.ts
5884
+ const RESPONSES_ENDPOINT = "/responses";
5885
+ /**
5886
+ * Models whose upstream `/v1/messages` endpoint rejects the `output_config`
5887
+ * field with "Extra inputs are not permitted".
5888
+ *
5889
+ * Verified via `scripts/probes/messages/output-config.ts` (2026-03-14).
5890
+ * When new models appear, re-run the probe and update this list.
5891
+ */
5892
+ const MODELS_REJECTING_OUTPUT_CONFIG = new Set([
5893
+ "claude-sonnet-4",
5894
+ "claude-sonnet-4.5",
5895
+ "claude-haiku-4.5"
5896
+ ]);
5897
+ var ModelCache = class {
5898
+ models;
5899
+ vsCodeVersion;
5900
+ cacheModels(models) {
5901
+ this.models = models;
5902
+ }
5903
+ clearModels() {
5904
+ this.models = void 0;
5905
+ }
5906
+ getModels() {
5907
+ return this.models;
5897
5908
  }
5898
- getUpstreamQueueMaxRetries() {
5899
- return getCachedConfig().upstreamQueueMaxRetries;
5909
+ setVSCodeVersion(version) {
5910
+ this.vsCodeVersion = version;
5900
5911
  }
5901
- getUpstreamQueueBaseDelaySeconds() {
5902
- return getCachedConfig().upstreamQueueBaseDelaySeconds;
5912
+ clearVSCodeVersion() {
5913
+ this.vsCodeVersion = void 0;
5903
5914
  }
5904
- getUpstreamQueueMaxDelaySeconds() {
5905
- return getCachedConfig().upstreamQueueMaxDelaySeconds;
5915
+ getVSCodeVersion() {
5916
+ return this.vsCodeVersion;
5917
+ }
5918
+ findById(modelId) {
5919
+ return this.models?.data.find((model) => model.id === modelId);
5920
+ }
5921
+ getModelIds() {
5922
+ return this.models?.data.map((model) => model.id) ?? [];
5923
+ }
5924
+ supportsEndpoint(model, endpoint) {
5925
+ return model?.supported_endpoints?.includes(endpoint) ?? false;
5926
+ }
5927
+ supportsToolCalls(model) {
5928
+ return model?.capabilities.supports.tool_calls ?? false;
5929
+ }
5930
+ supportsAdaptiveThinking(model) {
5931
+ return model?.capabilities.supports.adaptive_thinking ?? false;
5932
+ }
5933
+ supportsVision(model) {
5934
+ return model?.capabilities.supports.vision ?? false;
5935
+ }
5936
+ supportsOutputConfig(model) {
5937
+ if (!model) return true;
5938
+ return !MODELS_REJECTING_OUTPUT_CONFIG.has(model.id);
5906
5939
  }
5907
5940
  };
5908
- const configStore = new ConfigStore();
5941
+ const modelCache = new ModelCache();
5909
5942
  //#endregion
5910
- //#region src/lib/responses-emulator-state.ts
5943
+ //#region src/translator/anthropic/translation-issue.ts
5944
+ var TranslationFailure = class extends Error {
5945
+ status;
5946
+ kind;
5947
+ constructor(message, options) {
5948
+ super(message);
5949
+ this.name = "TranslationFailure";
5950
+ this.status = options.status;
5951
+ this.kind = options.kind;
5952
+ }
5953
+ };
5954
+ //#endregion
5955
+ //#region src/lib/error.ts
5956
+ var HTTPError = class extends Error {
5957
+ status;
5958
+ body;
5959
+ constructor(status, body) {
5960
+ super(body.error.message);
5961
+ this.name = "HTTPError";
5962
+ this.status = status;
5963
+ this.body = body;
5964
+ }
5965
+ toResponse() {
5966
+ return Response.json(this.body, { status: this.status });
5967
+ }
5968
+ };
5969
+ function throwInvalidRequestError(message, param, code) {
5970
+ throw new HTTPError(400, { error: {
5971
+ message,
5972
+ type: "invalid_request_error",
5973
+ param,
5974
+ ...code ? { code } : {}
5975
+ } });
5976
+ }
5977
+ function fromTranslationFailure(failure) {
5978
+ return new HTTPError(failure.status, { error: {
5979
+ message: failure.message,
5980
+ type: "translation_error"
5981
+ } });
5982
+ }
5983
+ function resolveModelOrThrow(modelId) {
5984
+ const model = modelCache.findById(modelId);
5985
+ if (!model) throwInvalidRequestError("The selected model could not be resolved.", "model");
5986
+ return model;
5987
+ }
5988
+ function withTranslationErrors(fn) {
5989
+ try {
5990
+ return fn();
5991
+ } catch (error) {
5992
+ if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
5993
+ throw error;
5994
+ }
5995
+ }
5996
+ function previewBody(text, maxLength = 500) {
5997
+ return text.length > maxLength ? `${text.slice(0, maxLength)}…` : text;
5998
+ }
5999
+ function isStructuredErrorPayload(value) {
6000
+ return typeof value === "object" && value !== null && "error" in value && typeof value.error === "object" && value.error !== null;
6001
+ }
6002
+ function upstreamErrorType(status) {
6003
+ return status === 429 ? "rate_limit_error" : "upstream_error";
6004
+ }
6005
+ function createFallbackUpstreamError(message, response, rawText) {
6006
+ return { error: {
6007
+ message: rawText.trim() || message,
6008
+ type: upstreamErrorType(response.status)
6009
+ } };
6010
+ }
6011
+ function getDiagnosticHeaders(response) {
6012
+ const headerNames = [
6013
+ "retry-after",
6014
+ "x-ratelimit-limit",
6015
+ "x-ratelimit-remaining",
6016
+ "x-ratelimit-reset",
6017
+ "x-github-request-id",
6018
+ "x-request-id"
6019
+ ];
6020
+ const headers = {};
6021
+ for (const name of headerNames) {
6022
+ const value = response.headers.get(name);
6023
+ if (value) headers[name] = value;
6024
+ }
6025
+ return Object.keys(headers).length > 0 ? headers : void 0;
6026
+ }
6027
+ async function throwUpstreamError(message, response) {
6028
+ let rawText = "";
6029
+ let body;
6030
+ try {
6031
+ rawText = await response.text();
6032
+ const json = JSON.parse(rawText);
6033
+ body = isStructuredErrorPayload(json) ? json : createFallbackUpstreamError(message, response, rawText);
6034
+ } catch {
6035
+ body = createFallbackUpstreamError(message, response, rawText);
6036
+ }
6037
+ consola.error("Upstream error:", {
6038
+ status: response.status,
6039
+ statusText: response.statusText,
6040
+ url: response.url,
6041
+ body,
6042
+ rawBody: rawText ? previewBody(rawText) : "<empty>",
6043
+ headers: getDiagnosticHeaders(response)
6044
+ });
6045
+ throw new HTTPError(response.status, body);
6046
+ }
6047
+ //#endregion
6048
+ //#region src/util/sleep.ts
6049
+ function sleep(ms) {
6050
+ return new Promise((resolve) => {
6051
+ setTimeout(resolve, ms);
6052
+ });
6053
+ }
6054
+ //#endregion
6055
+ //#region src/state/rate-limiter.ts
6056
+ var RateLimiter = class {
6057
+ nextAvailableAt = 0;
6058
+ reset() {
6059
+ this.nextAvailableAt = 0;
6060
+ }
6061
+ async acquire(intervalSeconds, waitMode) {
6062
+ if (intervalSeconds === void 0) return;
6063
+ const now = Date.now();
6064
+ const intervalMs = intervalSeconds * 1e3;
6065
+ if (!this.nextAvailableAt || now >= this.nextAvailableAt) {
6066
+ this.nextAvailableAt = now + intervalMs;
6067
+ return;
6068
+ }
6069
+ const waitMs = this.nextAvailableAt - now;
6070
+ const waitTimeSeconds = Math.ceil(waitMs / 1e3);
6071
+ if (!waitMode) {
6072
+ consola.warn(`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`);
6073
+ throw new HTTPError(429, { error: {
6074
+ message: "Rate limit exceeded",
6075
+ type: "rate_limit_error"
6076
+ } });
6077
+ }
6078
+ const claimedSlot = this.nextAvailableAt;
6079
+ this.nextAvailableAt = claimedSlot + intervalMs;
6080
+ consola.warn(`Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`);
6081
+ await sleep(waitMs);
6082
+ consola.info("Rate limit wait completed, proceeding with request");
6083
+ }
6084
+ };
6085
+ const rateLimiter = new RateLimiter();
6086
+ //#endregion
6087
+ //#region src/state/responses-emulator-state.ts
5911
6088
  const DEFAULT_MAX_TOTAL_ENTRIES = 1e4;
5912
6089
  const BACKGROUND_PRUNE_INTERVAL_MS = 6e4;
5913
6090
  function cloneValue$1(value) {
5914
- if (typeof globalThis.structuredClone === "function") return globalThis.structuredClone(value);
5915
- return JSON.parse(JSON.stringify(value));
6091
+ return structuredClone(value);
5916
6092
  }
5917
6093
  function currentTime() {
5918
6094
  return Date.now();
@@ -5958,7 +6134,6 @@ function createResponsesEmulatorState(opts) {
5958
6134
  pruneIntervalId = void 0;
5959
6135
  }
5960
6136
  }
5961
- startBackgroundPrune();
5962
6137
  function totalEntries() {
5963
6138
  let sum = 0;
5964
6139
  for (const map of allMaps) sum += map.size;
@@ -5977,6 +6152,7 @@ function createResponsesEmulatorState(opts) {
5977
6152
  return cloneValue$1(entry.value);
5978
6153
  }
5979
6154
  function writeMap(map, key, value, ttlSeconds, at = currentTime()) {
6155
+ startBackgroundPrune();
5980
6156
  if (!map.has(key)) enforceCapOnWrite();
5981
6157
  const cloned = cloneValue$1(value);
5982
6158
  map.set(key, {
@@ -5989,6 +6165,7 @@ function createResponsesEmulatorState(opts) {
5989
6165
  return map.delete(key);
5990
6166
  }
5991
6167
  function putDeletionFlag(map, id, ttlSeconds, at = currentTime()) {
6168
+ startBackgroundPrune();
5992
6169
  if (!map.has(id)) enforceCapOnWrite();
5993
6170
  const flag = {
5994
6171
  deleted: true,
@@ -6136,9 +6313,6 @@ function createResponsesEmulatorState(opts) {
6136
6313
  getConversationHead(conversationId) {
6137
6314
  return readMap(conversationHeadRecords, conversationId);
6138
6315
  },
6139
- clearConversationHead(conversationId) {
6140
- deleteMapEntry(conversationHeadRecords, conversationId);
6141
- },
6142
6316
  setInputItems(responseId, inputItems, options) {
6143
6317
  removeDeletionFlag(inputItemDeletionFlags, responseId);
6144
6318
  return writeMap(inputItemRecords, responseId, inputItems, options?.ttlSeconds);
@@ -6157,329 +6331,19 @@ function createResponsesEmulatorState(opts) {
6157
6331
  deleted: true
6158
6332
  };
6159
6333
  },
6160
- setDeletionFlag(kind, id, options) {
6161
- return putDeletionFlag(deletionMap(kind), id, options?.ttlSeconds);
6162
- },
6163
6334
  getDeletionFlag(kind, id) {
6164
6335
  return readDeletionFlag(deletionMap(kind), id);
6165
- },
6166
- clearDeletionFlag(kind, id) {
6167
- removeDeletionFlag(deletionMap(kind), id);
6168
6336
  }
6169
6337
  };
6170
6338
  }
6171
6339
  const responsesEmulatorState = createResponsesEmulatorState();
6172
6340
  //#endregion
6173
- //#region src/state/model-cache.ts
6174
- const RESPONSES_ENDPOINT = "/responses";
6175
- /**
6176
- * Models whose upstream `/v1/messages` endpoint rejects the `output_config`
6177
- * field with "Extra inputs are not permitted".
6178
- *
6179
- * Verified via `scripts/probe-all-models-output-config.ts` (2026-03-14).
6180
- * When new models appear, re-run the probe and update this list.
6181
- */
6182
- const MODELS_REJECTING_OUTPUT_CONFIG = new Set([
6183
- "claude-sonnet-4",
6184
- "claude-sonnet-4.5",
6185
- "claude-haiku-4.5"
6186
- ]);
6187
- var ModelCache = class {
6188
- models;
6189
- vsCodeVersion;
6190
- cacheModels(models) {
6191
- this.models = models;
6192
- }
6193
- clearModels() {
6194
- this.models = void 0;
6195
- }
6196
- getModels() {
6197
- return this.models;
6198
- }
6199
- setVSCodeVersion(version) {
6200
- this.vsCodeVersion = version;
6201
- }
6202
- clearVSCodeVersion() {
6203
- this.vsCodeVersion = void 0;
6204
- }
6205
- getVSCodeVersion() {
6206
- return this.vsCodeVersion;
6207
- }
6208
- findById(modelId) {
6209
- return this.models?.data.find((model) => model.id === modelId);
6210
- }
6211
- getModelIds() {
6212
- return this.models?.data.map((model) => model.id) ?? [];
6213
- }
6214
- supportsEndpoint(model, endpoint) {
6215
- return model?.supported_endpoints?.includes(endpoint) ?? false;
6216
- }
6217
- supportsToolCalls(model) {
6218
- return model?.capabilities.supports.tool_calls ?? false;
6219
- }
6220
- supportsAdaptiveThinking(model) {
6221
- return model?.capabilities.supports.adaptive_thinking ?? false;
6222
- }
6223
- supportsVision(model) {
6224
- return model?.capabilities.supports.vision ?? false;
6225
- }
6226
- supportsOutputConfig(model) {
6227
- if (!model) return true;
6228
- return !MODELS_REJECTING_OUTPUT_CONFIG.has(model.id);
6229
- }
6230
- getVisionLimits(model) {
6231
- return model?.capabilities.limits.vision;
6232
- }
6233
- };
6234
- const modelCache = new ModelCache();
6235
- //#endregion
6236
- //#region src/translator/anthropic/translation-issue.ts
6237
- var TranslationFailure = class extends Error {
6238
- status;
6239
- kind;
6240
- constructor(message, options) {
6241
- super(message);
6242
- this.name = "TranslationFailure";
6243
- this.status = options.status;
6244
- this.kind = options.kind;
6245
- }
6246
- };
6247
- //#endregion
6248
- //#region src/lib/error.ts
6249
- var HTTPError = class extends Error {
6250
- status;
6251
- body;
6252
- constructor(status, body) {
6253
- super(body.error.message);
6254
- this.name = "HTTPError";
6255
- this.status = status;
6256
- this.body = body;
6257
- }
6258
- toResponse() {
6259
- return Response.json(this.body, { status: this.status });
6260
- }
6261
- };
6262
- function throwInvalidRequestError(message, param, code) {
6263
- throw new HTTPError(400, { error: {
6264
- message,
6265
- type: "invalid_request_error",
6266
- param,
6267
- ...code ? { code } : {}
6268
- } });
6269
- }
6270
- function fromTranslationFailure(failure) {
6271
- return new HTTPError(failure.status, { error: {
6272
- message: failure.message,
6273
- type: "translation_error"
6274
- } });
6275
- }
6276
- function resolveModelOrThrow(modelId) {
6277
- const model = modelCache.findById(modelId);
6278
- if (!model) throwInvalidRequestError("The selected model could not be resolved.", "model");
6279
- return model;
6280
- }
6281
- function withTranslationErrors(fn) {
6282
- try {
6283
- return fn();
6284
- } catch (error) {
6285
- if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
6286
- throw error;
6287
- }
6288
- }
6289
- function previewBody(text, maxLength = 500) {
6290
- return text.length > maxLength ? `${text.slice(0, maxLength)}…` : text;
6291
- }
6292
- function isStructuredErrorPayload(value) {
6293
- return typeof value === "object" && value !== null && "error" in value && typeof value.error === "object" && value.error !== null;
6294
- }
6295
- function upstreamErrorType(status) {
6296
- return status === 429 ? "rate_limit_error" : "upstream_error";
6297
- }
6298
- function createFallbackUpstreamError(message, response, rawText) {
6299
- return { error: {
6300
- message: rawText.trim() || message,
6301
- type: upstreamErrorType(response.status)
6302
- } };
6303
- }
6304
- function getDiagnosticHeaders(response) {
6305
- const headerNames = [
6306
- "retry-after",
6307
- "x-ratelimit-limit",
6308
- "x-ratelimit-remaining",
6309
- "x-ratelimit-reset",
6310
- "x-github-request-id",
6311
- "x-request-id"
6312
- ];
6313
- const headers = {};
6314
- for (const name of headerNames) {
6315
- const value = response.headers.get(name);
6316
- if (value) headers[name] = value;
6317
- }
6318
- return Object.keys(headers).length > 0 ? headers : void 0;
6319
- }
6320
- async function throwUpstreamError(message, response) {
6321
- let rawText = "";
6322
- let body;
6323
- try {
6324
- rawText = await response.text();
6325
- const json = JSON.parse(rawText);
6326
- body = isStructuredErrorPayload(json) ? json : createFallbackUpstreamError(message, response, rawText);
6327
- } catch {
6328
- body = createFallbackUpstreamError(message, response, rawText);
6329
- }
6330
- consola.error("Upstream error:", {
6331
- status: response.status,
6332
- statusText: response.statusText,
6333
- url: response.url,
6334
- body,
6335
- rawBody: rawText ? previewBody(rawText) : "<empty>",
6336
- headers: getDiagnosticHeaders(response)
6337
- });
6338
- throw new HTTPError(response.status, body);
6339
- }
6340
- //#endregion
6341
- //#region src/lib/sleep.ts
6342
- function sleep(ms) {
6343
- return new Promise((resolve) => {
6344
- setTimeout(resolve, ms);
6345
- });
6346
- }
6347
- //#endregion
6348
- //#region src/state/rate-limiter.ts
6349
- var RateLimiter = class {
6350
- nextAvailableAt = 0;
6351
- reset() {
6352
- this.nextAvailableAt = 0;
6353
- }
6354
- async acquire(intervalSeconds, waitMode) {
6355
- if (intervalSeconds === void 0) return;
6356
- const now = Date.now();
6357
- const intervalMs = intervalSeconds * 1e3;
6358
- if (!this.nextAvailableAt || now >= this.nextAvailableAt) {
6359
- this.nextAvailableAt = now + intervalMs;
6360
- return;
6361
- }
6362
- const waitMs = this.nextAvailableAt - now;
6363
- const waitTimeSeconds = Math.ceil(waitMs / 1e3);
6364
- if (!waitMode) {
6365
- consola.warn(`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`);
6366
- throw new HTTPError(429, { error: {
6367
- message: "Rate limit exceeded",
6368
- type: "rate_limit_error"
6369
- } });
6370
- }
6371
- const claimedSlot = this.nextAvailableAt;
6372
- this.nextAvailableAt = claimedSlot + intervalMs;
6373
- consola.warn(`Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`);
6374
- await sleep(waitMs);
6375
- consola.info("Rate limit wait completed, proceeding with request");
6376
- }
6377
- };
6378
- const rateLimiter = new RateLimiter();
6379
- //#endregion
6380
6341
  //#region src/state/runtime.ts
6381
6342
  var RuntimeStore = class {
6382
6343
  dumpFailedPayloads = false;
6383
6344
  };
6384
6345
  const runtimeStore = new RuntimeStore();
6385
6346
  //#endregion
6386
- //#region src/lib/api-config.ts
6387
- function standardHeaders() {
6388
- return {
6389
- "content-type": "application/json",
6390
- "accept": "application/json"
6391
- };
6392
- }
6393
- const COPILOT_VERSION = "0.26.7";
6394
- const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
6395
- const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
6396
- const API_VERSION = "2025-04-01";
6397
- const TRAILING_SLASHES_RE$1 = /\/+$/;
6398
- /** Headers shared by both Copilot and GitHub API requests (editor identity + versioning) */
6399
- function editorHeaders(config) {
6400
- return {
6401
- "editor-version": `vscode/${config.vsCodeVersion ?? "unknown"}`,
6402
- "editor-plugin-version": EDITOR_PLUGIN_VERSION,
6403
- "user-agent": USER_AGENT,
6404
- "x-github-api-version": API_VERSION,
6405
- "x-vscode-user-agent-library-version": "electron-fetch"
6406
- };
6407
- }
6408
- function copilotBaseUrl(config) {
6409
- if (config.copilotApiBase) return config.copilotApiBase.replace(TRAILING_SLASHES_RE$1, "");
6410
- return config.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${config.accountType}.githubcopilot.com`;
6411
- }
6412
- function copilotHeaders(auth, config, options = {}) {
6413
- const requestContext = options.requestContext;
6414
- const headers = {
6415
- "Authorization": `Bearer ${auth.copilotToken}`,
6416
- "content-type": standardHeaders()["content-type"],
6417
- "copilot-integration-id": "vscode-chat",
6418
- ...editorHeaders(config),
6419
- "openai-intent": "conversation-panel",
6420
- "x-request-id": randomUUID()
6421
- };
6422
- if (options.vision) headers["copilot-vision-request"] = "true";
6423
- if (options.initiator) headers["X-Initiator"] = options.initiator;
6424
- if (requestContext?.interactionType) headers["X-Interaction-Type"] = requestContext.interactionType;
6425
- if (requestContext?.agentTaskId) headers["X-Agent-Task-Id"] = requestContext.agentTaskId;
6426
- if (requestContext?.parentAgentTaskId) headers["X-Parent-Agent-Id"] = requestContext.parentAgentTaskId;
6427
- if (requestContext?.clientSessionId) headers["X-Client-Session-Id"] = requestContext.clientSessionId;
6428
- if (requestContext?.interactionId) headers["X-Interaction-Id"] = requestContext.interactionId;
6429
- if (requestContext?.clientMachineId) headers["X-Client-Machine-Id"] = requestContext.clientMachineId;
6430
- return headers;
6431
- }
6432
- const GITHUB_API_BASE_URL = "https://api.github.com";
6433
- function githubHeaders(auth, config) {
6434
- return {
6435
- ...standardHeaders(),
6436
- authorization: `token ${auth.githubToken}`,
6437
- ...editorHeaders(config)
6438
- };
6439
- }
6440
- const GITHUB_BASE_URL = "https://github.com";
6441
- const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
6442
- const GITHUB_APP_SCOPES = ["read:user"].join(" ");
6443
- //#endregion
6444
- //#region src/lib/ghe-domain.ts
6445
- const GHE_SUFFIX = ".ghe.com";
6446
- /**
6447
- * Normalize a GHE domain input to a lowercase bare domain.
6448
- *
6449
- * Accepted inputs: `company.ghe.com`, `https://company.ghe.com`,
6450
- * `https://Company.GHE.com/`, etc.
6451
- *
6452
- * @returns Bare lowercase domain, e.g. `company.ghe.com`
6453
- * @throws {Error} If the input is empty or does not end with `.ghe.com`
6454
- */
6455
- function normalizeGheDomain(input) {
6456
- const trimmed = input.trim();
6457
- if (!trimmed) throw new Error("GHE domain must not be empty");
6458
- let domain;
6459
- try {
6460
- domain = (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname.toLowerCase();
6461
- } catch {
6462
- throw new Error(`Invalid GHE domain: ${trimmed}`);
6463
- }
6464
- if (!domain.endsWith(GHE_SUFFIX) || domain === GHE_SUFFIX.slice(1)) throw new Error(`GHE domain must end with ${GHE_SUFFIX} (got "${domain}")`);
6465
- return domain;
6466
- }
6467
- /**
6468
- * Build GitHub base URL and API base URL for a given GHE domain,
6469
- * or return the public GitHub defaults when no domain is provided.
6470
- */
6471
- function buildGitHubUrls(gheDomain) {
6472
- if (!gheDomain) return {
6473
- baseUrl: GITHUB_BASE_URL,
6474
- apiBaseUrl: GITHUB_API_BASE_URL
6475
- };
6476
- const domain = normalizeGheDomain(gheDomain);
6477
- return {
6478
- baseUrl: `https://${domain}`,
6479
- apiBaseUrl: `https://api.${domain}`
6480
- };
6481
- }
6482
- //#endregion
6483
6347
  //#region node_modules/fetch-event-stream/esm/deps/jsr.io/@std/streams/0.221.0/text_line_stream.js
6484
6348
  /**
6485
6349
  * Transform a stream into a stream where each chunk is divided by a newline,
@@ -6602,6 +6466,64 @@ async function* events(res, signal) {
6602
6466
  }
6603
6467
  }
6604
6468
  //#endregion
6469
+ //#region src/clients/api-config.ts
6470
+ function standardHeaders() {
6471
+ return {
6472
+ "content-type": "application/json",
6473
+ "accept": "application/json"
6474
+ };
6475
+ }
6476
+ const COPILOT_VERSION = "0.26.7";
6477
+ const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
6478
+ const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
6479
+ const API_VERSION = "2025-04-01";
6480
+ const TRAILING_SLASHES_RE$1 = /\/+$/;
6481
+ /** Headers shared by both Copilot and GitHub API requests (editor identity + versioning) */
6482
+ function editorHeaders(config) {
6483
+ return {
6484
+ "editor-version": `vscode/${config.vsCodeVersion ?? "unknown"}`,
6485
+ "editor-plugin-version": EDITOR_PLUGIN_VERSION,
6486
+ "user-agent": USER_AGENT,
6487
+ "x-github-api-version": API_VERSION,
6488
+ "x-vscode-user-agent-library-version": "electron-fetch"
6489
+ };
6490
+ }
6491
+ function copilotBaseUrl(config) {
6492
+ if (config.copilotApiBase) return config.copilotApiBase.replace(TRAILING_SLASHES_RE$1, "");
6493
+ return config.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${config.accountType}.githubcopilot.com`;
6494
+ }
6495
+ function copilotHeaders(auth, config, options = {}) {
6496
+ const requestContext = options.requestContext;
6497
+ const headers = {
6498
+ "Authorization": `Bearer ${auth.copilotToken}`,
6499
+ "content-type": standardHeaders()["content-type"],
6500
+ "copilot-integration-id": "vscode-chat",
6501
+ ...editorHeaders(config),
6502
+ "openai-intent": "conversation-panel",
6503
+ "x-request-id": randomUUID()
6504
+ };
6505
+ if (options.vision) headers["copilot-vision-request"] = "true";
6506
+ if (options.initiator) headers["X-Initiator"] = options.initiator;
6507
+ if (requestContext?.interactionType) headers["X-Interaction-Type"] = requestContext.interactionType;
6508
+ if (requestContext?.agentTaskId) headers["X-Agent-Task-Id"] = requestContext.agentTaskId;
6509
+ if (requestContext?.parentAgentTaskId) headers["X-Parent-Agent-Id"] = requestContext.parentAgentTaskId;
6510
+ if (requestContext?.clientSessionId) headers["X-Client-Session-Id"] = requestContext.clientSessionId;
6511
+ if (requestContext?.interactionId) headers["X-Interaction-Id"] = requestContext.interactionId;
6512
+ if (requestContext?.clientMachineId) headers["X-Client-Machine-Id"] = requestContext.clientMachineId;
6513
+ return headers;
6514
+ }
6515
+ const GITHUB_API_BASE_URL = "https://api.github.com";
6516
+ function githubHeaders(auth, config) {
6517
+ return {
6518
+ ...standardHeaders(),
6519
+ authorization: `token ${auth.githubToken}`,
6520
+ ...editorHeaders(config)
6521
+ };
6522
+ }
6523
+ const GITHUB_BASE_URL = "https://github.com";
6524
+ const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
6525
+ const GITHUB_APP_SCOPES = ["read:user"].join(" ");
6526
+ //#endregion
6605
6527
  //#region src/clients/copilot-client.ts
6606
6528
  var CopilotClient = class {
6607
6529
  auth;
@@ -6930,7 +6852,55 @@ async function getVSCodeVersion() {
6930
6852
  return remoteVersion ?? localVersion ?? FALLBACK;
6931
6853
  }
6932
6854
  //#endregion
6933
- //#region src/lib/upstream-request-queue.ts
6855
+ //#region src/clients/ghe-domain.ts
6856
+ const GHE_SUFFIX = ".ghe.com";
6857
+ /**
6858
+ * Normalize a GHE domain input to a lowercase bare domain.
6859
+ *
6860
+ * Accepted inputs: `company.ghe.com`, `https://company.ghe.com`,
6861
+ * `https://Company.GHE.com/`, etc.
6862
+ *
6863
+ * @returns Bare lowercase domain, e.g. `company.ghe.com`
6864
+ * @throws {Error} If the input is empty or does not end with `.ghe.com`
6865
+ */
6866
+ function normalizeGheDomain(input) {
6867
+ const trimmed = input.trim();
6868
+ if (!trimmed) throw new Error("GHE domain must not be empty");
6869
+ let domain;
6870
+ try {
6871
+ domain = (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname.toLowerCase();
6872
+ } catch {
6873
+ throw new Error(`Invalid GHE domain: ${trimmed}`);
6874
+ }
6875
+ if (!domain.endsWith(GHE_SUFFIX) || domain === GHE_SUFFIX.slice(1)) throw new Error(`GHE domain must end with ${GHE_SUFFIX} (got "${domain}")`);
6876
+ return domain;
6877
+ }
6878
+ /**
6879
+ * Build GitHub base URL and API base URL for a given GHE domain,
6880
+ * or return the public GitHub defaults when no domain is provided.
6881
+ */
6882
+ function buildGitHubUrls(gheDomain) {
6883
+ if (!gheDomain) return {
6884
+ baseUrl: GITHUB_BASE_URL,
6885
+ apiBaseUrl: GITHUB_API_BASE_URL
6886
+ };
6887
+ const domain = normalizeGheDomain(gheDomain);
6888
+ return {
6889
+ baseUrl: `https://${domain}`,
6890
+ apiBaseUrl: `https://api.${domain}`
6891
+ };
6892
+ }
6893
+ //#endregion
6894
+ //#region src/util/duration.ts
6895
+ /**
6896
+ * Formats a millisecond duration as a compact human-readable string:
6897
+ * `<n>ms` under one second, otherwise `<n>s` rounded to whole seconds.
6898
+ */
6899
+ function formatDurationMs(ms) {
6900
+ return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
6901
+ }
6902
+ //#endregion
6903
+ //#region src/clients/upstream-queue.ts
6934
6904
  const DEFAULT_UPSTREAM_QUEUE_OPTIONS = {
6935
6905
  concurrency: 10,
6936
6906
  maxRetries: 5,
@@ -6987,7 +6957,7 @@ var UpstreamRequestQueue = class {
6987
6957
  this.logger.warn([
6988
6958
  "Upstream rate limited;",
6989
6959
  `retrying ${formatRequestContext(context)}`,
6990
- `in ${formatDelay(delayMs)}`,
6960
+ `in ${formatDurationMs(delayMs)}`,
6991
6961
  `(attempt ${attempt + 1}/${this.options.maxRetries})`
6992
6962
  ].join(" "));
6993
6963
  await abortableSleep(this.sleep, delayMs, signal);
@@ -7097,9 +7067,6 @@ function formatRequestContext(context) {
7097
7067
  return `${context.method ?? "GET"} ${context.url}`;
7098
7068
  }
7099
7069
  }
7100
- function formatDelay(delayMs) {
7101
- return delayMs < 1e3 ? `${delayMs}ms` : `${Math.round(delayMs / 1e3)}s`;
7102
- }
7103
7070
  function abortableSleep(sleep, ms, signal) {
7104
7071
  if (!signal) return sleep(ms);
7105
7072
  signal.throwIfAborted();
@@ -7118,7 +7085,7 @@ function abortableSleep(sleep, ms, signal) {
7118
7085
  });
7119
7086
  }
7120
7087
  //#endregion
7121
- //#region src/lib/state.ts
7088
+ //#region src/clients/factory.ts
7122
7089
  const upstreamRequestQueue = createDefaultUpstreamRequestQueue();
7123
7090
  function configureUpstreamRequestQueue(options) {
7124
7091
  upstreamRequestQueue.updateOptions(options);
@@ -7363,11 +7330,6 @@ const checkUsage = defineCommand({
7363
7330
  await setupGitHubToken();
7364
7331
  try {
7365
7332
  const usage = await new GitHubClient(authStore, getClientConfig()).getCopilotUsage();
7366
- const premium = usage.quota_snapshots.premium_interactions;
7367
- const premiumTotal = premium.entitlement;
7368
- const premiumUsed = premiumTotal - premium.remaining;
7369
- const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
7370
- const premiumPercentRemaining = premium.percent_remaining;
7371
7333
  function summarizeQuota(name, snap) {
7372
7334
  if (!snap) return `${name}: N/A`;
7373
7335
  const total = snap.entitlement;
@@ -7376,7 +7338,7 @@ const checkUsage = defineCommand({
7376
7338
  const percentRemaining = snap.percent_remaining;
7377
7339
  return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
7378
7340
  }
7379
- const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
7341
+ const premiumLine = summarizeQuota("Premium", usage.quota_snapshots.premium_interactions);
7380
7342
  const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
7381
7343
  const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
7382
7344
  consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
@@ -7387,8 +7349,8 @@ const checkUsage = defineCommand({
7387
7349
  }
7388
7350
  });
7389
7351
  //#endregion
7390
- //#region src/lib/version.ts
7391
- const VERSION = "0.6.2";
7352
+ //#region src/util/version.ts
7353
+ const VERSION = "0.7.0";
7392
7354
  //#endregion
7393
7355
  //#region src/debug.ts
7394
7356
  function getRuntimeInfo() {
@@ -7656,59 +7618,6 @@ async function getTokenCount(payload, model) {
7656
7618
  async function estimateResponsesInputTokens(inputItems, model) {
7657
7619
  return (await getEncoder(getTokenizerFromModel(model))).encode(JSON.stringify(inputItems)).length;
7658
7620
  }
7659
- /**
7660
- * Fast character-based token estimate for Anthropic payloads.
7661
- * Uses ~3.5 chars/token ratio (conservative for Claude's tokenizer).
7662
- * Intentionally over-estimates to favor proactive routing.
7663
- */
7664
- function estimateAnthropicInputTokens(payload) {
7665
- let chars = 0;
7666
- if (typeof payload.system === "string") chars += payload.system.length;
7667
- else if (Array.isArray(payload.system)) for (const block of payload.system) chars += block.text?.length ?? 0;
7668
- for (const msg of payload.messages) if (typeof msg.content === "string") chars += msg.content.length;
7669
- else if (Array.isArray(msg.content)) chars += estimateContentBlockChars(msg.content);
7670
- if (payload.tools?.length) chars += JSON.stringify(payload.tools).length;
7671
- return Math.ceil(chars / 3.5);
7672
- }
7673
- function estimateContentBlockChars(blocks) {
7674
- let chars = 0;
7675
- for (const block of blocks) switch (block.type) {
7676
- case "text":
7677
- chars += block.text.length;
7678
- break;
7679
- case "thinking":
7680
- chars += block.thinking.length;
7681
- break;
7682
- case "redacted_thinking":
7683
- chars += block.data.length;
7684
- break;
7685
- case "tool_use":
7686
- case "server_tool_use":
7687
- case "mcp_tool_use":
7688
- chars += JSON.stringify(block.input).length;
7689
- break;
7690
- case "tool_result":
7691
- case "mcp_tool_result":
7692
- chars += typeof block.content === "string" ? block.content.length : JSON.stringify(block.content ?? "").length;
7693
- break;
7694
- case "server_tool_result":
7695
- case "web_search_tool_result":
7696
- case "web_fetch_tool_result":
7697
- case "code_execution_tool_result":
7698
- case "bash_code_execution_tool_result":
7699
- case "text_editor_code_execution_tool_result":
7700
- case "tool_search_tool_result":
7701
- chars += JSON.stringify(block.content ?? "").length;
7702
- break;
7703
- case "document":
7704
- chars += JSON.stringify(block).length;
7705
- break;
7706
- case "image":
7707
- chars += 1e3;
7708
- break;
7709
- }
7710
- return chars;
7711
- }
7712
7621
  //#endregion
7713
7622
  //#region src/selfcheck.ts
7714
7623
  const PROBE_ENCODINGS = [
@@ -29208,7 +29117,7 @@ var require_eventsource = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
29208
29117
  };
29209
29118
  }));
29210
29119
  //#endregion
29211
- //#region src/lib/proxy.ts
29120
+ //#region src/cli/proxy.ts
29212
29121
  var import_undici = (/* @__PURE__ */ __commonJSMin$1(((exports, module) => {
29213
29122
  const Client = require_client();
29214
29123
  const Dispatcher = require_dispatcher();
@@ -29419,7 +29328,7 @@ function initProxyFromEnv() {
29419
29328
  }
29420
29329
  }
29421
29330
  //#endregion
29422
- //#region src/lib/shell.ts
29331
+ //#region src/cli/shell.ts
29423
29332
  const EXE_EXTENSION_RE = /\.exe$/i;
29424
29333
  function normalizeShellName(raw) {
29425
29334
  if (!raw) return;
@@ -29508,7 +29417,7 @@ function generateEnvScript(envVars, commandToRun = "") {
29508
29417
  //#endregion
29509
29418
  //#region src/lib/model-resolver.ts
29510
29419
  const DEFAULT_FALLBACKS = {
29511
- claudeOpus: "claude-opus-4.6",
29420
+ claudeOpus: "claude-opus-4.8",
29512
29421
  claudeSonnet: "claude-sonnet-4.6",
29513
29422
  claudeHaiku: "claude-haiku-4.5"
29514
29423
  };
@@ -29528,7 +29437,7 @@ function resolveModel(modelId, knownModelIds, config) {
29528
29437
  return modelId;
29529
29438
  }
29530
29439
  //#endregion
29531
- //#region src/lib/startup-banner.ts
29440
+ //#region src/cli/startup-banner.ts
29532
29441
  function printStartupBanner(serverUrl) {
29533
29442
  const lines = [];
29534
29443
  lines.push(`ghc-proxy v${VERSION}`);
@@ -47817,8 +47726,7 @@ function getRequestModelMapping(request) {
47817
47726
  return requestModelMapping.get(request);
47818
47727
  }
47819
47728
  function formatElapsed(start) {
47820
- const delta = Date.now() - start;
47821
- return delta < 1e3 ? `${delta}ms` : `${Math.round(delta / 1e3)}s`;
47729
+ return formatDurationMs(Date.now() - start);
47822
47730
  }
47823
47731
  function formatPath(rawUrl) {
47824
47732
  try {
@@ -47849,8 +47757,8 @@ function getEffectiveModel(info) {
47849
47757
  }
47850
47758
  /**
47851
47759
  * Mutate `modelMapping` in place by appending a transform step.
47852
- * `appendModelStep` returns a new object, but strategy contexts
47853
- * hold a reference to the same `modelMapping`, so we push directly.
47760
+ * Strategy contexts hold a reference to the same `modelMapping`,
47761
+ * so steps are pushed directly rather than returning a new object.
47854
47762
  */
47855
47763
  function appendModelStepInPlace(info, tag, newModel) {
47856
47764
  const current = getEffectiveModel(info);
@@ -47893,6 +47801,16 @@ function logRequest(method, url, status, elapsed, modelInfo, requestId) {
47893
47801
  //#endregion
47894
47802
  //#region src/lib/sse-adapter.ts
47895
47803
  /**
47804
+ * Serializes Anthropic stream events into SSE output items
47805
+ * (one `{ event, data }` per event, with `data` as the JSON-encoded event).
47806
+ */
47807
+ function serializeAnthropicSSE(events) {
47808
+ return events.map((event) => ({
47809
+ event: event.type,
47810
+ data: JSON.stringify(event)
47811
+ }));
47812
+ }
47813
+ /**
47896
47814
  * Bridges an AsyncGenerator<SSEOutput> to Elysia's SSE response format.
47897
47815
  * Returns an async generator that yields sse() calls for each SSE output item.
47898
47816
  */
@@ -47906,7 +47824,7 @@ async function* sseAdapter(generator) {
47906
47824
  //#endregion
47907
47825
  //#region src/deliver/index.ts
47908
47826
  function deliverResult(request, result, modelMapping) {
47909
- if (modelMapping) setRequestModelMapping(request, modelMapping);
47827
+ setRequestModelMapping(request, modelMapping);
47910
47828
  if (result.kind === "json") return {
47911
47829
  streaming: false,
47912
47830
  data: result.data
@@ -47929,7 +47847,7 @@ function hasStreamingResponsesQuery(request) {
47929
47847
  return new URL(request.url).searchParams.get("stream") === "true";
47930
47848
  }
47931
47849
  //#endregion
47932
- //#region src/lib/approval.ts
47850
+ //#region src/guard/approval.ts
47933
47851
  async function awaitApproval() {
47934
47852
  if (!await consola.prompt(`Accept incoming request?`, { type: "confirm" })) throw new HTTPError(403, { error: {
47935
47853
  message: "Request rejected",
@@ -47937,7 +47855,7 @@ async function awaitApproval() {
47937
47855
  } });
47938
47856
  }
47939
47857
  //#endregion
47940
- //#region src/guard/auth.ts
47858
+ //#region src/guard/gate.ts
47941
47859
  async function runGuard() {
47942
47860
  await rateLimiter.acquire(authStore.rateLimitSeconds, authStore.rateLimitWait);
47943
47861
  if (authStore.manualApprove) await awaitApproval();
@@ -47949,118 +47867,7 @@ const requestGuardPlugin = new Elysia({ name: "request-guard" }).macro({ guarded
47949
47867
  await runGuard();
47950
47868
  } }) });
47951
47869
  //#endregion
47952
- //#region src/lib/model-rewrite.ts
47953
- /**
47954
- * Unified model rewrite: user rules → built-in normalization → pass-through.
47955
- * Call once at handler entry, before any model lookup or policy.
47956
- */
47957
- function rewriteModel(modelId) {
47958
- const userRules = configStore.getModelRewrites();
47959
- if (userRules.length > 0) {
47960
- for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
47961
- originalModel: modelId,
47962
- model: normalizeToKnownModel(rule.to) ?? rule.to,
47963
- reason: "CONFIG_REWRITE"
47964
- };
47965
- }
47966
- const normalized = normalizeToKnownModel(modelId);
47967
- if (normalized && normalized !== modelId) return {
47968
- originalModel: modelId,
47969
- model: normalized,
47970
- reason: "AUTO_CORRECT"
47971
- };
47972
- return {
47973
- originalModel: modelId,
47974
- model: modelId
47975
- };
47976
- }
47977
- /**
47978
- * Apply model rewrite to a mutable model field and log if changed.
47979
- * Returns the rewrite result for downstream use.
47980
- */
47981
- function applyModelRewrite(payload) {
47982
- const result = rewriteModel(payload.model);
47983
- if (result.model !== result.originalModel) {
47984
- consola.debug(`Model rewritten: ${result.originalModel} ~> ${result.model}`);
47985
- payload.model = result.model;
47986
- }
47987
- return result;
47988
- }
47989
- const DOT_RE = /\./g;
47990
- /**
47991
- * Resolve a model ID against Copilot's cached model list using
47992
- * dash/dot equivalence. Returns the canonical ID if found.
47993
- */
47994
- function normalizeToKnownModel(modelId) {
47995
- const models = modelCache.getModels()?.data;
47996
- if (!models) return void 0;
47997
- if (models.some((m) => m.id === modelId)) return modelId;
47998
- const normalized = modelId.replace(DOT_RE, "-");
47999
- for (const model of models) if (model.id.replace(DOT_RE, "-") === normalized) return model.id;
48000
- }
48001
- const GLOB_SPECIAL_RE = /[.+^${}()|[\]\\]/g;
48002
- const GLOB_STAR_RE = /\*/g;
48003
- function matchesGlob(pattern, value) {
48004
- if (!pattern.includes("*")) return pattern === value;
48005
- return new RegExp(`^${pattern.replace(GLOB_SPECIAL_RE, "\\$&").replace(GLOB_STAR_RE, ".*")}$`).test(value);
48006
- }
48007
- /**
48008
- * Quick check: does this model have any configured context-upgrade rules?
48009
- * Use to skip expensive token estimation for ineligible models.
48010
- */
48011
- function hasContextUpgradeRule(model) {
48012
- return configStore.getContextUpgradeRules().some((rule) => matchesGlob(rule.from, model));
48013
- }
48014
- /** Find the first configured upgrade rule for a model. */
48015
- function findUpgradeRule(model) {
48016
- for (const rule of configStore.getContextUpgradeRules()) if (matchesGlob(rule.from, model)) return {
48017
- from: rule.from,
48018
- to: normalizeToKnownModel(rule.to) ?? rule.to
48019
- };
48020
- }
48021
- /**
48022
- * Proactive: resolve the upgrade target model for a given model + token count.
48023
- * Returns the target model ID, or undefined if no upgrade applies.
48024
- */
48025
- function resolveContextUpgrade(model, estimatedTokens) {
48026
- const rule = findUpgradeRule(model);
48027
- if (rule && estimatedTokens > configStore.getContextUpgradeThreshold()) return rule.to;
48028
- }
48029
- /**
48030
- * Reactive: get the upgrade target for a model on context-length error.
48031
- * Returns the target model ID, or undefined if no fallback applies.
48032
- */
48033
- function getContextUpgradeTarget(model) {
48034
- return findUpgradeRule(model)?.to;
48035
- }
48036
- /** Context-length error detection with pattern matching */
48037
- const CONTEXT_ERROR_PATTERNS = [
48038
- /context.length/i,
48039
- /too.long/i,
48040
- /token.*(limit|maximum|exceed)/i,
48041
- /(limit|maximum|exceed).*token/i
48042
- ];
48043
- function isContextLengthError(error) {
48044
- if (!(error instanceof HTTPError) || error.status !== 400) return false;
48045
- const message = error.body?.error?.message;
48046
- return message ? CONTEXT_ERROR_PATTERNS.some((pattern) => pattern.test(message)) : false;
48047
- }
48048
- //#endregion
48049
- //#region src/dispatch/error-recovery.ts
48050
- async function executeWithContextRetry(executeFn, modelInfo) {
48051
- try {
48052
- return await executeFn(modelInfo.model);
48053
- } catch (error) {
48054
- if (!isContextLengthError(error)) throw error;
48055
- if (!configStore.isContextUpgradeEnabled()) throw error;
48056
- const upgradeTarget = getContextUpgradeTarget(modelInfo.model);
48057
- if (!upgradeTarget) throw error;
48058
- consola.info(`Context length error → retrying with ${upgradeTarget}`);
48059
- return await executeFn(upgradeTarget);
48060
- }
48061
- }
48062
- //#endregion
48063
- //#region src/lib/assert-never.ts
47870
+ //#region src/util/assert-never.ts
48064
47871
  /**
48065
47872
  * Compile-time exhaustiveness check for switch/if-else chains on
48066
47873
  * discriminated unions. At runtime, throws with a descriptive message.
@@ -48111,54 +47918,20 @@ function selectCapiProfile(model) {
48111
47918
  return inferModelFamily(model) === "claude" ? claudeProfile : baseProfile;
48112
47919
  }
48113
47920
  //#endregion
48114
- //#region src/core/capi/request-context.ts
48115
- const SUBAGENT_MARKER_PREFIX = "__SUBAGENT_MARKER__";
48116
- const SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
48117
- const SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
47921
+ //#region src/core/capi/headers.ts
47922
+ /**
47923
+ * Leaf helper for reading optional request headers. Lives in its own module so
47924
+ * both request-context.ts and subagent-marker.ts can depend on it without
47925
+ * importing each other (which would form a cycle).
47926
+ */
48118
47927
  function readHeader(headers, name) {
48119
47928
  return headers.get(name) ?? void 0;
48120
47929
  }
48121
- function inferInitiator(turns) {
48122
- return turns.some((turn) => turn.role === "assistant" || turn.role === "tool") ? "agent" : "user";
48123
- }
48124
- function readCapiRequestContext(headers) {
48125
- return {
48126
- interactionType: readHeader(headers, "x-interaction-type"),
48127
- agentTaskId: readHeader(headers, "x-agent-task-id"),
48128
- parentAgentTaskId: readHeader(headers, "x-parent-agent-id"),
48129
- clientSessionId: readHeader(headers, "x-client-session-id") ?? readHeader(headers, "x-session-id"),
48130
- interactionId: readHeader(headers, "x-interaction-id"),
48131
- clientMachineId: readHeader(headers, "x-client-machine-id")
48132
- };
48133
- }
48134
- function resolveInitiator(defaultInitiator, requestContext) {
48135
- switch (requestContext?.interactionType) {
48136
- case "conversation-agent":
48137
- case "conversation-subagent":
48138
- case "conversation-background": return "agent";
48139
- case "conversation-user": return "user";
48140
- default: return defaultInitiator;
48141
- }
48142
- }
48143
- function buildCapiRequestContext(initiator, overrides = {}) {
48144
- return {
48145
- interactionType: overrides.interactionType ?? (initiator === "agent" ? "conversation-agent" : "conversation-user"),
48146
- agentTaskId: overrides.agentTaskId,
48147
- parentAgentTaskId: overrides.parentAgentTaskId,
48148
- clientSessionId: overrides.clientSessionId,
48149
- interactionId: overrides.interactionId ?? randomUUID(),
48150
- clientMachineId: overrides.clientMachineId
48151
- };
48152
- }
48153
- function normalizeAnthropicRequestContext(payload, headers) {
48154
- return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromAnthropicPayload(payload));
48155
- }
48156
- function normalizeChatRequestContext(payload, headers) {
48157
- return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromChatPayload(payload));
48158
- }
48159
- function normalizeResponsesRequestContext(payload, headers) {
48160
- return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromResponsesPayload(payload));
48161
- }
47930
+ //#endregion
47931
+ //#region src/core/capi/subagent-marker.ts
47932
+ const SUBAGENT_MARKER_PREFIX = "__SUBAGENT_MARKER__";
47933
+ const SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
47934
+ const SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
48162
47935
  function withSubagentMarker(baseContext, headers, marker) {
48163
47936
  if (!marker) return baseContext;
48164
47937
  const rootSessionId = readHeader(headers, "x-session-id") ?? baseContext.clientSessionId;
@@ -48433,6 +48206,49 @@ function findJsonObjectEnd(text, start) {
48433
48206
  return -1;
48434
48207
  }
48435
48208
  //#endregion
48209
+ //#region src/core/capi/request-context.ts
48210
+ function inferInitiator(turns) {
48211
+ return turns.some((turn) => turn.role === "assistant" || turn.role === "tool") ? "agent" : "user";
48212
+ }
48213
+ function readCapiRequestContext(headers) {
48214
+ return {
48215
+ interactionType: readHeader(headers, "x-interaction-type"),
48216
+ agentTaskId: readHeader(headers, "x-agent-task-id"),
48217
+ parentAgentTaskId: readHeader(headers, "x-parent-agent-id"),
48218
+ clientSessionId: readHeader(headers, "x-client-session-id") ?? readHeader(headers, "x-session-id"),
48219
+ interactionId: readHeader(headers, "x-interaction-id"),
48220
+ clientMachineId: readHeader(headers, "x-client-machine-id")
48221
+ };
48222
+ }
48223
+ function resolveInitiator(defaultInitiator, requestContext) {
48224
+ switch (requestContext?.interactionType) {
48225
+ case "conversation-agent":
48226
+ case "conversation-subagent":
48227
+ case "conversation-background": return "agent";
48228
+ case "conversation-user": return "user";
48229
+ default: return defaultInitiator;
48230
+ }
48231
+ }
48232
+ function buildCapiRequestContext(initiator, overrides = {}) {
48233
+ return {
48234
+ interactionType: overrides.interactionType ?? (initiator === "agent" ? "conversation-agent" : "conversation-user"),
48235
+ agentTaskId: overrides.agentTaskId,
48236
+ parentAgentTaskId: overrides.parentAgentTaskId,
48237
+ clientSessionId: overrides.clientSessionId,
48238
+ interactionId: overrides.interactionId ?? randomUUID(),
48239
+ clientMachineId: overrides.clientMachineId
48240
+ };
48241
+ }
48242
+ function normalizeAnthropicRequestContext(payload, headers) {
48243
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromAnthropicPayload(payload));
48244
+ }
48245
+ function normalizeChatRequestContext(payload, headers) {
48246
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromChatPayload(payload));
48247
+ }
48248
+ function normalizeResponsesRequestContext(payload, headers) {
48249
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromResponsesPayload(payload));
48250
+ }
48251
+ //#endregion
48436
48252
  //#region src/core/capi/plan-builder.ts
48437
48253
  const EPHEMERAL_CACHE_CONTROL = { type: "ephemeral" };
48438
48254
  function asContentPart(block) {
@@ -48636,7 +48452,7 @@ function buildCapiExecutionPlan(request, options = {}) {
48636
48452
  };
48637
48453
  }
48638
48454
  //#endregion
48639
- //#region src/lib/validation/shared.ts
48455
+ //#region src/ingest/validation/shared.ts
48640
48456
  const jsonObjectSchema = object({}).catchall(unknown());
48641
48457
  const finiteNumberSchema = number().finite();
48642
48458
  const nonNegativeIntegerSchema = number().int().nonnegative();
@@ -48733,7 +48549,7 @@ function parsePayload(schema, context, payload) {
48733
48549
  return result.data;
48734
48550
  }
48735
48551
  //#endregion
48736
- //#region src/lib/validation/anthropic-messages.ts
48552
+ //#region src/ingest/validation/anthropic-messages.ts
48737
48553
  const anthropicTextBlockSchema = object({
48738
48554
  type: literal("text"),
48739
48555
  text: string()
@@ -48923,7 +48739,7 @@ function parseAnthropicCountTokensPayload(payload) {
48923
48739
  return parsePayload(anthropicCountTokensPayloadSchema, "anthropic.messages.count_tokens", payload);
48924
48740
  }
48925
48741
  //#endregion
48926
- //#region src/lib/validation/embeddings.ts
48742
+ //#region src/ingest/validation/embeddings.ts
48927
48743
  const embeddingRequestSchema = object({
48928
48744
  input: union([string(), array(string())]),
48929
48745
  model: string().min(1),
@@ -48943,7 +48759,7 @@ const REASONING_EFFORT_VALUES = [
48943
48759
  "high"
48944
48760
  ];
48945
48761
  //#endregion
48946
- //#region src/lib/validation/openai-chat.ts
48762
+ //#region src/ingest/validation/openai-chat.ts
48947
48763
  const openAIPenaltySchema = finiteNumberSchema.min(-2).max(2);
48948
48764
  const openAILogitBiasKeySchema = string().regex(/^\d+$/);
48949
48765
  const openAILogitBiasValueSchema = finiteNumberSchema.min(-100).max(100);
@@ -49052,53 +48868,77 @@ const openAIChatPayloadSchema = object({
49052
48868
  function parseOpenAIChatPayload(payload) {
49053
48869
  return parsePayload(openAIChatPayloadSchema, "openai.chat", payload);
49054
48870
  }
48871
+ //#endregion
48872
+ //#region src/ingest/validation/responses.ts
48873
+ const responsesInputTextSchema = object({
48874
+ type: _enum(["input_text", "output_text"]),
48875
+ text: string()
48876
+ }).loose();
48877
+ const responsesInputImageSchema = object({
48878
+ type: literal("input_image"),
48879
+ image_url: string().nullable().optional(),
48880
+ file_id: string().nullable().optional(),
48881
+ detail: _enum([
48882
+ "low",
48883
+ "high",
48884
+ "auto",
48885
+ "original"
48886
+ ]).optional()
48887
+ }).loose().superRefine((item, ctx) => {
48888
+ if (!item.image_url && !item.file_id) ctx.addIssue({
48889
+ code: "custom",
48890
+ message: "input_image requires image_url or file_id"
48891
+ });
48892
+ });
48893
+ const responsesFunctionCallOutputImageSchema = object({
48894
+ type: literal("input_image"),
48895
+ image_url: string().nullable().optional(),
48896
+ file_id: string().nullable().optional(),
48897
+ detail: _enum([
48898
+ "low",
48899
+ "high",
48900
+ "auto",
48901
+ "original"
48902
+ ]).optional()
48903
+ }).loose();
48904
+ const responsesInputFileSchema = object({
48905
+ type: literal("input_file"),
48906
+ file_id: string().nullable().optional(),
48907
+ file_url: string().nullable().optional(),
48908
+ file_data: string().nullable().optional(),
48909
+ filename: string().nullable().optional()
48910
+ }).loose().superRefine((item, ctx) => {
48911
+ if (!item.file_id && !item.file_url && !item.file_data) ctx.addIssue({
48912
+ code: "custom",
48913
+ message: "input_file requires file_id, file_url, or file_data"
48914
+ });
48915
+ if (item.file_data && !item.filename) ctx.addIssue({
48916
+ code: "custom",
48917
+ message: "input_file with file_data requires filename"
48918
+ });
48919
+ });
48920
+ const responsesUnknownContentSchema = object({ type: string().min(1) }).catchall(unknown()).superRefine((item, ctx) => {
48921
+ if ([
48922
+ "input_text",
48923
+ "output_text",
48924
+ "input_image",
48925
+ "input_file"
48926
+ ].includes(item.type)) ctx.addIssue({
48927
+ code: "custom",
48928
+ message: `content item type ${item.type} must match the explicit schema`
48929
+ });
48930
+ });
49055
48931
  const responsesInputContentSchema = union([
49056
- object({
49057
- type: _enum(["input_text", "output_text"]),
49058
- text: string()
49059
- }).loose(),
49060
- object({
49061
- type: literal("input_image"),
49062
- image_url: string().nullable().optional(),
49063
- file_id: string().nullable().optional(),
49064
- detail: _enum([
49065
- "low",
49066
- "high",
49067
- "auto"
49068
- ]).optional()
49069
- }).loose().superRefine((item, ctx) => {
49070
- if (!item.image_url && !item.file_id) ctx.addIssue({
49071
- code: "custom",
49072
- message: "input_image requires image_url or file_id"
49073
- });
49074
- }),
49075
- object({
49076
- type: literal("input_file"),
49077
- file_id: string().nullable().optional(),
49078
- file_url: string().nullable().optional(),
49079
- file_data: string().nullable().optional(),
49080
- filename: string().nullable().optional()
49081
- }).loose().superRefine((item, ctx) => {
49082
- if (!item.file_id && !item.file_url && !item.file_data) ctx.addIssue({
49083
- code: "custom",
49084
- message: "input_file requires file_id, file_url, or file_data"
49085
- });
49086
- if (item.file_data && !item.filename) ctx.addIssue({
49087
- code: "custom",
49088
- message: "input_file with file_data requires filename"
49089
- });
49090
- }),
49091
- object({ type: string().min(1) }).catchall(unknown()).superRefine((item, ctx) => {
49092
- if ([
49093
- "input_text",
49094
- "output_text",
49095
- "input_image",
49096
- "input_file"
49097
- ].includes(item.type)) ctx.addIssue({
49098
- code: "custom",
49099
- message: `content item type ${item.type} must match the explicit schema`
49100
- });
49101
- })
48932
+ responsesInputTextSchema,
48933
+ responsesInputImageSchema,
48934
+ responsesInputFileSchema,
48935
+ responsesUnknownContentSchema
48936
+ ]);
48937
+ const responsesFunctionCallOutputContentSchema = union([
48938
+ responsesInputTextSchema,
48939
+ responsesFunctionCallOutputImageSchema,
48940
+ responsesInputFileSchema,
48941
+ responsesUnknownContentSchema
49102
48942
  ]);
49103
48943
  const responsesMessageSchema = object({
49104
48944
  type: literal("message").optional(),
@@ -49126,7 +48966,7 @@ const responsesFunctionCallSchema = object({
49126
48966
  const responsesFunctionCallOutputSchema = object({
49127
48967
  type: literal("function_call_output"),
49128
48968
  call_id: string().min(1),
49129
- output: union([string(), array(responsesInputContentSchema)]),
48969
+ output: union([string(), array(responsesFunctionCallOutputContentSchema)]),
49130
48970
  status: _enum([
49131
48971
  "in_progress",
49132
48972
  "completed",
@@ -49464,16 +49304,16 @@ function createUpstreamSignalFromConfig(clientSignal) {
49464
49304
  //#endregion
49465
49305
  //#region src/pipeline/runner.ts
49466
49306
  async function runPipeline(params, config) {
49467
- const { payload, meta } = protocolRegistry.ingest(config.protocol, params.body, params.headers);
49468
- config.afterIngest?.({
49469
- payload,
49307
+ const ingested = protocolRegistry.ingest(config.protocol, params.body, params.headers);
49308
+ const meta = ingested.meta;
49309
+ const payload = config.afterIngest ? config.afterIngest({
49310
+ payload: ingested.payload,
49470
49311
  meta,
49471
49312
  headers: params.headers
49472
- });
49313
+ }) : ingested.payload;
49473
49314
  const transformResult = config.transformChain.apply({
49474
49315
  model: payload.model,
49475
49316
  payload,
49476
- headers: params.headers,
49477
49317
  meta: { betaHeaders: meta.betaHeaders }
49478
49318
  });
49479
49319
  payload.model = transformResult.model;
@@ -49495,7 +49335,7 @@ async function runPipeline(params, config) {
49495
49335
  });
49496
49336
  const upstreamSignal = createUpstreamSignalFromConfig(params.signal);
49497
49337
  const copilotClient = createCopilotClient();
49498
- const buildCtx = () => config.buildStrategyContext({
49338
+ const ctx = config.buildStrategyContext({
49499
49339
  payload,
49500
49340
  meta,
49501
49341
  headers: params.headers,
@@ -49504,93 +49344,12 @@ async function runPipeline(params, config) {
49504
49344
  upstreamSignal,
49505
49345
  modelMapping
49506
49346
  });
49507
- if (config.contextRetry) return {
49508
- result: await executeWithContextRetry(async (model) => {
49509
- const isRetry = model !== payload.model;
49510
- const currentMapping = isRetry ? {
49511
- originalModel: modelMapping.originalModel,
49512
- steps: [...modelMapping.steps]
49513
- } : modelMapping;
49514
- const effectivePayload = isRetry ? {
49515
- ...payload,
49516
- model
49517
- } : payload;
49518
- const currentModel = isRetry ? modelCache.findById(model) ?? selectedModel : selectedModel;
49519
- const ctx = config.buildStrategyContext({
49520
- payload: effectivePayload,
49521
- meta,
49522
- headers: params.headers,
49523
- selectedModel: currentModel,
49524
- copilotClient,
49525
- upstreamSignal: isRetry ? createUpstreamSignalFromConfig(params.signal) : upstreamSignal,
49526
- modelMapping: currentMapping
49527
- });
49528
- const entryResult = await config.strategyRegistry.select(currentModel, ctx).execute(ctx);
49529
- if (isRetry) modelMapping.steps = currentMapping.steps;
49530
- return entryResult;
49531
- }, {
49532
- model: payload.model,
49533
- trace: modelMapping.steps.map((s) => ({
49534
- tag: s.tag,
49535
- from: s.from,
49536
- to: s.to
49537
- }))
49538
- }),
49539
- modelMapping
49540
- };
49541
- const ctx = buildCtx();
49542
49347
  return {
49543
49348
  result: await config.strategyRegistry.select(selectedModel, ctx).execute(ctx),
49544
49349
  modelMapping
49545
49350
  };
49546
49351
  }
49547
49352
  //#endregion
49548
- //#region src/transform/constants.ts
49549
- const CONTEXT_BETA_RE = /^context-\d+[km]-/;
49550
- //#endregion
49551
- //#region src/transform/beta-headers.ts
49552
- const COPILOT_UNSUPPORTED_BETA_RE = /^mid-conversation-system-\d{4}-\d{2}-\d{2}$/;
49553
- function processAnthropicBetaHeader(rawHeader, model) {
49554
- if (!rawHeader) return {
49555
- header: void 0,
49556
- upgradeTarget: void 0
49557
- };
49558
- const values = rawHeader.split(",").map((v) => v.trim()).filter(Boolean);
49559
- let upgradeTarget;
49560
- const filtered = [];
49561
- for (const value of values) {
49562
- if (CONTEXT_BETA_RE.test(value)) {
49563
- if (!upgradeTarget && configStore.isContextUpgradeEnabled()) {
49564
- const target = getContextUpgradeTarget(model);
49565
- if (target) upgradeTarget = target;
49566
- }
49567
- continue;
49568
- }
49569
- if (COPILOT_UNSUPPORTED_BETA_RE.test(value)) continue;
49570
- filtered.push(value);
49571
- }
49572
- return {
49573
- header: filtered.length > 0 ? filtered.join(",") : void 0,
49574
- upgradeTarget
49575
- };
49576
- }
49577
- const betaHeaderStep = {
49578
- tag: "BETA_UPGRADE",
49579
- apply({ model, headers, resolvedModel }) {
49580
- if (!headers) return null;
49581
- const result = processAnthropicBetaHeader(headers.get("anthropic-beta"), model);
49582
- if (!result.upgradeTarget) return null;
49583
- return {
49584
- model: result.upgradeTarget,
49585
- tag: "BETA_UPGRADE",
49586
- resolvedModel: modelCache.findById(result.upgradeTarget) ?? resolvedModel ?? modelCache.findById(model),
49587
- mutatePayload(payload) {
49588
- if (payload && typeof payload === "object" && "model" in payload) payload.model = result.upgradeTarget;
49589
- }
49590
- };
49591
- }
49592
- };
49593
- //#endregion
49594
49353
  //#region src/transform/chain.ts
49595
49354
  function composeModelTransforms(...steps) {
49596
49355
  return { apply(input) {
@@ -49626,18 +49385,10 @@ function composeModelTransforms(...steps) {
49626
49385
  } };
49627
49386
  }
49628
49387
  //#endregion
49629
- //#region src/lib/model-capabilities.ts
49630
- function modelSupportsToolCalls(model) {
49631
- return model?.capabilities.supports.tool_calls ?? false;
49632
- }
49633
- function modelSupportsAdaptiveThinking(model) {
49634
- return model?.capabilities.supports.adaptive_thinking ?? false;
49635
- }
49636
- function modelSupportsVision(model) {
49637
- return model?.capabilities.supports.vision ?? false;
49638
- }
49388
+ //#region src/transform/constants.ts
49389
+ const CONTEXT_BETA_RE = /^context-\d+[km]-/;
49639
49390
  //#endregion
49640
- //#region src/lib/request-model-policy.ts
49391
+ //#region src/transform/request-model-policy.ts
49641
49392
  const COMPACT_SYSTEM_PROMPT_START = "You are a helpful AI assistant tasked with summarizing conversations";
49642
49393
  function applyMessagesModelPolicy(payload, options) {
49643
49394
  const originalModel = payload.model;
@@ -49645,17 +49396,6 @@ function applyMessagesModelPolicy(payload, options) {
49645
49396
  originalModel,
49646
49397
  routedModel: originalModel
49647
49398
  };
49648
- if (configStore.isContextUpgradeEnabled() && hasContextUpgradeRule(payload.model)) {
49649
- const contextUpgradeTarget = resolveContextUpgrade(payload.model, estimateAnthropicInputTokens(payload));
49650
- if (contextUpgradeTarget) {
49651
- payload.model = contextUpgradeTarget;
49652
- return {
49653
- originalModel,
49654
- routedModel: contextUpgradeTarget,
49655
- reason: "context-upgrade"
49656
- };
49657
- }
49658
- }
49659
49399
  const smallModel = configStore.getSmallModel();
49660
49400
  if (!smallModel || !configStore.isCompactSmallModelEnabled() || !isCompactRequest(payload)) return {
49661
49401
  originalModel,
@@ -49684,9 +49424,9 @@ function canRouteToSmallModel(payload, originalModel, smallModel) {
49684
49424
  const originalEndpoints = new Set(originalModel.supported_endpoints ?? []);
49685
49425
  const smallEndpoints = new Set(smallModel.supported_endpoints ?? []);
49686
49426
  for (const endpoint of originalEndpoints) if (!smallEndpoints.has(endpoint)) return false;
49687
- if (payload.tools?.length && !modelSupportsToolCalls(smallModel)) return false;
49688
- if (payload.thinking && !modelSupportsAdaptiveThinking(smallModel)) return false;
49689
- if (hasVisionInput$1(payload) && !modelSupportsVision(smallModel)) return false;
49427
+ if (payload.tools?.length && !(smallModel.capabilities.supports.tool_calls ?? false)) return false;
49428
+ if (payload.thinking && !(smallModel.capabilities.supports.adaptive_thinking ?? false)) return false;
49429
+ if (hasVisionInput$1(payload) && !(smallModel.capabilities.supports.vision ?? false)) return false;
49690
49430
  return true;
49691
49431
  }
49692
49432
  function hasVisionInput$1(payload) {
@@ -49700,17 +49440,72 @@ function containsVisionContent$1(content) {
49700
49440
  //#region src/transform/policy.ts
49701
49441
  const modelPolicyStep = {
49702
49442
  tag: "POLICY",
49703
- apply({ model, payload, meta, resolvedModel }) {
49443
+ apply({ payload, meta }) {
49704
49444
  const routing = applyMessagesModelPolicy(payload, { betaUpgraded: meta?.betaHeaders?.some((b) => CONTEXT_BETA_RE.test(b)) ?? false });
49705
49445
  if (!routing.reason) return null;
49706
49446
  return {
49707
49447
  model: routing.routedModel,
49708
- tag: routing.reason === "context-upgrade" ? "CONTEXT_UPGRADE" : "COMPACT",
49709
- resolvedModel: routing.reason === "context-upgrade" ? modelCache.findById(routing.routedModel) ?? resolvedModel ?? modelCache.findById(model) : void 0
49448
+ tag: "COMPACT"
49710
49449
  };
49711
49450
  }
49712
49451
  };
49713
49452
  //#endregion
49453
+ //#region src/transform/model-rewrite.ts
49454
+ /**
49455
+ * Unified model rewrite: user rules → built-in normalization → pass-through.
49456
+ * Call once at handler entry, before any model lookup or policy.
49457
+ */
49458
+ function rewriteModel(modelId) {
49459
+ const userRules = configStore.getModelRewrites();
49460
+ if (userRules.length > 0) {
49461
+ for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
49462
+ originalModel: modelId,
49463
+ model: normalizeToKnownModel(rule.to) ?? rule.to,
49464
+ reason: "CONFIG_REWRITE"
49465
+ };
49466
+ }
49467
+ const normalized = normalizeToKnownModel(modelId);
49468
+ if (normalized && normalized !== modelId) return {
49469
+ originalModel: modelId,
49470
+ model: normalized,
49471
+ reason: "AUTO_CORRECT"
49472
+ };
49473
+ return {
49474
+ originalModel: modelId,
49475
+ model: modelId
49476
+ };
49477
+ }
49478
+ /**
49479
+ * Apply model rewrite to a mutable model field and log if changed.
49480
+ * Returns the rewrite result for downstream use.
49481
+ */
49482
+ function applyModelRewrite(payload) {
49483
+ const result = rewriteModel(payload.model);
49484
+ if (result.model !== result.originalModel) {
49485
+ consola.debug(`Model rewritten: ${result.originalModel} ~> ${result.model}`);
49486
+ payload.model = result.model;
49487
+ }
49488
+ return result;
49489
+ }
49490
+ const DOT_RE = /\./g;
49491
+ /**
49492
+ * Resolve a model ID against Copilot's cached model list using
49493
+ * dash/dot equivalence. Returns the canonical ID if found.
49494
+ */
49495
+ function normalizeToKnownModel(modelId) {
49496
+ const models = modelCache.getModels()?.data;
49497
+ if (!models) return void 0;
49498
+ if (models.some((m) => m.id === modelId)) return modelId;
49499
+ const normalized = modelId.replace(DOT_RE, "-");
49500
+ for (const model of models) if (model.id.replace(DOT_RE, "-") === normalized) return model.id;
49501
+ }
49502
+ const GLOB_SPECIAL_RE = /[.+^${}()|[\]\\]/g;
49503
+ const GLOB_STAR_RE = /\*/g;
49504
+ function matchesGlob(pattern, value) {
49505
+ if (!pattern.includes("*")) return pattern === value;
49506
+ return new RegExp(`^${pattern.replace(GLOB_SPECIAL_RE, "\\$&").replace(GLOB_STAR_RE, ".*")}$`).test(value);
49507
+ }
49508
+ //#endregion
49714
49509
  //#region src/transform/rewrite.ts
49715
49510
  const rewriteStep = {
49716
49511
  tag: "rewrite",
@@ -49735,6 +49530,20 @@ const rewriteStep = {
49735
49530
  }
49736
49531
  };
49737
49532
  //#endregion
49533
+ //#region src/transform/beta-headers.ts
49534
+ const COPILOT_UNSUPPORTED_BETA_RE = /^mid-conversation-system-\d{4}-\d{2}-\d{2}$/;
49535
+ function processAnthropicBetaHeader(rawHeader) {
49536
+ if (!rawHeader) return void 0;
49537
+ const values = rawHeader.split(",").map((v) => v.trim()).filter(Boolean);
49538
+ const filtered = [];
49539
+ for (const value of values) {
49540
+ if (CONTEXT_BETA_RE.test(value)) continue;
49541
+ if (COPILOT_UNSUPPORTED_BETA_RE.test(value)) continue;
49542
+ filtered.push(value);
49543
+ }
49544
+ return filtered.length > 0 ? filtered.join(",") : void 0;
49545
+ }
49546
+ //#endregion
49738
49547
  //#region src/translator/responses/signature-codec.ts
49739
49548
  const COMPACTION_PREFIX = "cm1#";
49740
49549
  const SEPARATOR = "@";
@@ -49797,8 +49606,8 @@ const OUTPUT_CONFIG_EFFORT_RANK = new Map([
49797
49606
  "low",
49798
49607
  "medium",
49799
49608
  "high",
49800
- "max",
49801
- "xhigh"
49609
+ "xhigh",
49610
+ "max"
49802
49611
  ].map((effort, index) => [effort, index]));
49803
49612
  function isOutputConfigEffort(value) {
49804
49613
  return OUTPUT_CONFIG_EFFORT_RANK.has(value);
@@ -49841,7 +49650,7 @@ function sanitizeCacheControl(payload) {
49841
49650
  }
49842
49651
  //#endregion
49843
49652
  //#region src/transform/index.ts
49844
- const messagesModelChain = composeModelTransforms(rewriteStep, betaHeaderStep, modelPolicyStep);
49653
+ const messagesModelChain = composeModelTransforms(rewriteStep, modelPolicyStep);
49845
49654
  const chatCompletionsModelChain = composeModelTransforms(rewriteStep);
49846
49655
  const responsesModelChain = composeModelTransforms(rewriteStep);
49847
49656
  //#endregion
@@ -49881,9 +49690,6 @@ function normalizeSystemBlocks(system) {
49881
49690
  blocks: system.map((block) => textBlock(block.text))
49882
49691
  }];
49883
49692
  }
49884
- function normalizeToolResultContent(block) {
49885
- return normalizeToolResultContentValue(block.content);
49886
- }
49887
49693
  function normalizeToolResultContentValue(content) {
49888
49694
  if (typeof content === "string") return [textBlock(content)];
49889
49695
  return content.map((contentBlock) => {
@@ -49895,9 +49701,6 @@ function normalizeToolResultContentValue(content) {
49895
49701
  }
49896
49702
  });
49897
49703
  }
49898
- function normalizeMcpToolResultContent(block) {
49899
- return normalizeToolResultContentValue(block.content);
49900
- }
49901
49704
  function normalizeServerToolResultContent(block) {
49902
49705
  return [textBlock(typeof block.content === "string" ? block.content : JSON.stringify(block.content) ?? "")];
49903
49706
  }
@@ -49937,13 +49740,13 @@ function normalizeMessage(message) {
49937
49740
  case "tool_result": return {
49938
49741
  kind: "tool_result",
49939
49742
  toolUseId: block.tool_use_id,
49940
- content: normalizeToolResultContent(block),
49743
+ content: normalizeToolResultContentValue(block.content),
49941
49744
  isError: block.is_error
49942
49745
  };
49943
49746
  case "mcp_tool_result": return {
49944
49747
  kind: "tool_result",
49945
49748
  toolUseId: block.tool_use_id,
49946
- content: normalizeMcpToolResultContent(block),
49749
+ content: normalizeToolResultContentValue(block.content),
49947
49750
  isError: block.is_error
49948
49751
  };
49949
49752
  case "server_tool_result":
@@ -50169,10 +49972,6 @@ var AnthropicStreamTranslator = class {
50169
49972
  for (const delta of deltas) switch (delta.kind) {
50170
49973
  case "message_start": break;
50171
49974
  case "thinking_delta":
50172
- this.state.lastMetadata = {
50173
- ...this.state.lastMetadata,
50174
- ...delta.metadata
50175
- };
50176
49975
  this.textWriter.close(events);
50177
49976
  this.thinkingWriter.append(events, delta.text);
50178
49977
  break;
@@ -50193,10 +49992,6 @@ var AnthropicStreamTranslator = class {
50193
49992
  });
50194
49993
  break;
50195
49994
  case "message_stop":
50196
- this.state.lastMetadata = {
50197
- ...this.state.lastMetadata,
50198
- ...delta.metadata
50199
- };
50200
49995
  this.state.pendingStopReason = delta.stopReason;
50201
49996
  this.closeAllBlocks(events);
50202
49997
  break;
@@ -50273,13 +50068,7 @@ var AnthropicStreamTranslator = class {
50273
50068
  });
50274
50069
  if (choice.delta.reasoning_text) deltas.push({
50275
50070
  kind: "thinking_delta",
50276
- text: choice.delta.reasoning_text,
50277
- metadata: {
50278
- reasoningOpaque: choice.delta.reasoning_opaque,
50279
- encryptedContent: choice.delta.encrypted_content,
50280
- phase: choice.delta.phase,
50281
- copilotAnnotations: choice.delta.copilot_annotations
50282
- }
50071
+ text: choice.delta.reasoning_text
50283
50072
  });
50284
50073
  if (choice.delta.content) deltas.push({
50285
50074
  kind: "text_delta",
@@ -50295,13 +50084,7 @@ var AnthropicStreamTranslator = class {
50295
50084
  if (choice.finish_reason) deltas.push({
50296
50085
  kind: "message_stop",
50297
50086
  stopReason: choice.finish_reason,
50298
- usage: chunk.usage,
50299
- metadata: {
50300
- reasoningOpaque: choice.delta.reasoning_opaque,
50301
- encryptedContent: choice.delta.encrypted_content,
50302
- phase: choice.delta.phase,
50303
- copilotAnnotations: choice.delta.copilot_annotations
50304
- }
50087
+ usage: chunk.usage
50305
50088
  });
50306
50089
  return deltas;
50307
50090
  }
@@ -50417,13 +50200,7 @@ function normalizeAssistantTurn(message) {
50417
50200
  }] : [],
50418
50201
  ...contentBlocks,
50419
50202
  ...toolBlocks
50420
- ],
50421
- meta: {
50422
- reasoningOpaque: message.reasoning_opaque,
50423
- encryptedContent: message.encrypted_content,
50424
- phase: message.phase,
50425
- copilotAnnotations: message.copilot_annotations
50426
- }
50203
+ ]
50427
50204
  };
50428
50205
  }
50429
50206
  function normalizeOpenAIResponse(response, context) {
@@ -50597,7 +50374,7 @@ var AnthropicMessagesAdapter = class {
50597
50374
  constructor(options = {}) {
50598
50375
  this.options = {
50599
50376
  modelResolver: options.modelResolver ?? ((model) => model),
50600
- getModelCapabilities: options.getModelCapabilities ?? ((model) => ({ supportsThinkingBudget: model.startsWith("claude") })),
50377
+ getModelCapabilities: options.getModelCapabilities ?? ((model) => ({ supportsThinkingBudget: inferModelFamily(model) === "claude" })),
50601
50378
  policy: options.policy ?? defaultTranslationPolicy
50602
50379
  };
50603
50380
  }
@@ -50633,21 +50410,6 @@ var AnthropicMessagesAdapter = class {
50633
50410
  }
50634
50411
  };
50635
50412
  //#endregion
50636
- //#region src/adapters/copilot-transport.ts
50637
- var CopilotTransport = class {
50638
- client;
50639
- constructor(client) {
50640
- this.client = client;
50641
- }
50642
- execute(plan, options) {
50643
- return this.client.createChatCompletions(plan.payload, {
50644
- signal: options?.signal,
50645
- initiator: plan.initiator,
50646
- requestContext: plan.requestContext
50647
- });
50648
- }
50649
- };
50650
- //#endregion
50651
50413
  //#region src/adapters/openai-chat-adapter.ts
50652
50414
  function toConversationBlocks(content) {
50653
50415
  if (content === null) return [];
@@ -50796,280 +50558,6 @@ var OpenAIChatAdapter = class {
50796
50558
  }
50797
50559
  };
50798
50560
  //#endregion
50799
- //#region src/routes/responses/emulator.ts
50800
- function cloneValue(value) {
50801
- if (typeof globalThis.structuredClone === "function") return globalThis.structuredClone(value);
50802
- return JSON.parse(JSON.stringify(value));
50803
- }
50804
- function rejectUnsupportedBackground(payload) {
50805
- if (payload.background) throwInvalidRequestError("background mode is not supported by the responses official emulator.", "background", "unsupported_background_mode");
50806
- }
50807
- function prepareEmulatorRequest(payload) {
50808
- rejectUnsupportedBackground(payload);
50809
- const normalizedCurrentInput = normalizeResponsesInput(payload.input);
50810
- const { continuationSourceResponseId, conversation: resolvedConversation, previousResponse } = resolveContinuation(payload);
50811
- const conversation = resolvedConversation ?? createConversationRef();
50812
- const effectiveInputItems = [...continuationSourceResponseId ? buildContinuationHistory(continuationSourceResponseId) : [], ...normalizedCurrentInput];
50813
- const shouldStore = payload.store ?? true;
50814
- return {
50815
- upstreamPayload: {
50816
- ...payload,
50817
- background: void 0,
50818
- conversation: void 0,
50819
- previous_response_id: void 0,
50820
- store: void 0,
50821
- input: effectiveInputItems
50822
- },
50823
- effectiveInputItems,
50824
- previousResponseId: previousResponse?.id,
50825
- conversation,
50826
- shouldStore
50827
- };
50828
- }
50829
- function decorateStoredResponse(upstreamResponse, requestPayload, prepared) {
50830
- return {
50831
- ...cloneValue(upstreamResponse),
50832
- previous_response_id: prepared.previousResponseId ?? null,
50833
- conversation: prepared.conversation,
50834
- truncation: requestPayload.truncation ?? null,
50835
- store: prepared.shouldStore,
50836
- user: normalizeNullableString(requestPayload.user),
50837
- service_tier: normalizeServiceTier(requestPayload.service_tier)
50838
- };
50839
- }
50840
- function persistEmulatorResponse(response, effectiveInputItems) {
50841
- responsesEmulatorState.setResponse(response);
50842
- if (response.conversation) {
50843
- responsesEmulatorState.setConversation(response.conversation);
50844
- responsesEmulatorState.setConversationHead(getConversationId(response.conversation), response.id);
50845
- }
50846
- responsesEmulatorState.setInputItems(response.id, effectiveInputItems);
50847
- }
50848
- function getStoredResponseOrThrow(responseId) {
50849
- const response = responsesEmulatorState.getResponse(responseId);
50850
- if (!response) throw new HTTPError(404, { error: {
50851
- message: `No response found with id '${responseId}'.`,
50852
- type: "invalid_request_error"
50853
- } });
50854
- return response;
50855
- }
50856
- function listStoredInputItemsOrThrow(responseId, params) {
50857
- const items = responsesEmulatorState.getInputItems(responseId);
50858
- if (!items) throw new HTTPError(404, { error: {
50859
- message: `No response input items found for id '${responseId}'.`,
50860
- type: "invalid_request_error"
50861
- } });
50862
- let orderedItems = cloneValue(items);
50863
- if (params?.order === "desc") orderedItems.reverse();
50864
- if (params?.after) {
50865
- const afterIndex = orderedItems.findIndex((item) => getInputItemId(item) === params.after);
50866
- if (afterIndex >= 0) orderedItems = orderedItems.slice(afterIndex + 1);
50867
- }
50868
- const limitedItems = orderedItems.slice(0, params?.limit ?? orderedItems.length);
50869
- return {
50870
- object: "list",
50871
- data: limitedItems,
50872
- first_id: getInputItemId(limitedItems[0]) ?? null,
50873
- last_id: getInputItemId(limitedItems.at(-1)) ?? null,
50874
- has_more: limitedItems.length < orderedItems.length
50875
- };
50876
- }
50877
- function deleteStoredResponseOrThrow(responseId) {
50878
- getStoredResponseOrThrow(responseId);
50879
- return responsesEmulatorState.deleteResponse(responseId);
50880
- }
50881
- async function estimateEmulatorInputTokens(payload, selectedModel) {
50882
- return {
50883
- object: "response.input_tokens",
50884
- input_tokens: await estimateResponsesInputTokens(resolveEffectiveInputForInputTokens(payload), selectedModel)
50885
- };
50886
- }
50887
- function resolveEffectiveInputForInputTokens(payload) {
50888
- const normalizedInput = normalizeResponsesInput(payload.input);
50889
- const background = payload.background === null || typeof payload.background === "boolean" ? payload.background : void 0;
50890
- const conversation = isConversationReference(payload.conversation) ? payload.conversation : void 0;
50891
- const previousResponseId = typeof payload.previous_response_id === "string" ? payload.previous_response_id : void 0;
50892
- rejectUnsupportedBackground({ background });
50893
- const { continuationSourceResponseId } = resolveContinuation({
50894
- conversation,
50895
- previous_response_id: previousResponseId
50896
- });
50897
- if (continuationSourceResponseId) return [...buildContinuationHistory(continuationSourceResponseId), ...normalizedInput];
50898
- return normalizedInput;
50899
- }
50900
- function resolveContinuation(payload) {
50901
- const previousResponse = resolvePreviousResponse(payload.previous_response_id);
50902
- const conversation = resolveConversation(payload.conversation, previousResponse);
50903
- return {
50904
- previousResponse,
50905
- conversation,
50906
- continuationSourceResponseId: resolveContinuationSourceResponseId(previousResponse, conversation)
50907
- };
50908
- }
50909
- function resolvePreviousResponse(previousResponseId) {
50910
- if (typeof previousResponseId !== "string" || previousResponseId.length === 0) return;
50911
- const previousResponse = responsesEmulatorState.getResponse(previousResponseId);
50912
- if (!previousResponse) throwInvalidRequestError("The selected previous_response_id could not be resolved.", "previous_response_id");
50913
- return previousResponse;
50914
- }
50915
- function resolveConversation(conversation, previousResponse) {
50916
- if (isConversationReference(conversation)) {
50917
- const conversationId = getConversationId(conversation);
50918
- const existingConversation = responsesEmulatorState.getConversation(conversationId);
50919
- if (!existingConversation) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
50920
- if (previousResponse?.conversation && getConversationId(previousResponse.conversation) !== conversationId) throwInvalidRequestError("The selected previous_response_id does not belong to the selected conversation.", "previous_response_id");
50921
- return existingConversation;
50922
- }
50923
- return previousResponse?.conversation ?? void 0;
50924
- }
50925
- function resolveContinuationSourceResponseId(previousResponse, conversation) {
50926
- if (previousResponse) return previousResponse.id;
50927
- if (!conversation) return;
50928
- const head = responsesEmulatorState.getConversationHead(getConversationId(conversation));
50929
- if (!head) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
50930
- return head;
50931
- }
50932
- function buildContinuationHistory(responseId) {
50933
- const previousResponse = getStoredResponseOrThrow(responseId);
50934
- const previousInput = responsesEmulatorState.getInputItems(responseId);
50935
- if (!previousInput) throwInvalidRequestError("The selected previous_response_id is missing stored input items.", "previous_response_id");
50936
- return [...cloneValue(previousInput), ...convertOutputItemsToInputItems(previousResponse.output)];
50937
- }
50938
- function normalizeResponsesInput(input) {
50939
- if (!input) return [];
50940
- if (typeof input === "string") return [{
50941
- type: "message",
50942
- role: "user",
50943
- content: input
50944
- }];
50945
- if (Array.isArray(input)) return cloneValue(input);
50946
- return [];
50947
- }
50948
- function convertOutputItemsToInputItems(output) {
50949
- const items = [];
50950
- for (const item of output) switch (item.type) {
50951
- case "message":
50952
- items.push(convertMessageOutputToInput(item));
50953
- break;
50954
- case "function_call":
50955
- items.push(convertFunctionCallOutputToInput(item));
50956
- break;
50957
- case "reasoning": {
50958
- const reasoningInput = convertReasoningOutputToInput(item);
50959
- if (reasoningInput) items.push(reasoningInput);
50960
- break;
50961
- }
50962
- case "compaction":
50963
- items.push(convertCompactionOutputToInput(item));
50964
- break;
50965
- }
50966
- return items;
50967
- }
50968
- function convertMessageOutputToInput(item) {
50969
- return {
50970
- type: "message",
50971
- role: item.role,
50972
- status: item.status,
50973
- content: item.content?.map((content) => {
50974
- if (content.type === "output_text" && typeof content.text === "string") return {
50975
- type: "output_text",
50976
- text: content.text
50977
- };
50978
- return cloneValue(content);
50979
- }) ?? []
50980
- };
50981
- }
50982
- function convertFunctionCallOutputToInput(item) {
50983
- return {
50984
- type: "function_call",
50985
- call_id: item.call_id,
50986
- name: item.name,
50987
- arguments: item.arguments,
50988
- status: item.status
50989
- };
50990
- }
50991
- function convertReasoningOutputToInput(item) {
50992
- if (!item.encrypted_content) return;
50993
- return {
50994
- id: item.id,
50995
- type: "reasoning",
50996
- summary: (item.summary ?? []).filter((summary) => typeof summary.text === "string").map((summary) => ({
50997
- type: "summary_text",
50998
- text: summary.text
50999
- })),
51000
- encrypted_content: item.encrypted_content
51001
- };
51002
- }
51003
- function convertCompactionOutputToInput(item) {
51004
- return {
51005
- id: item.id,
51006
- type: "compaction",
51007
- encrypted_content: item.encrypted_content
51008
- };
51009
- }
51010
- function normalizeNullableString(value) {
51011
- return typeof value === "string" ? value : null;
51012
- }
51013
- function normalizeServiceTier(value) {
51014
- if (value === "auto" || value === "default" || value === "flex" || value === "scale" || value === "priority") return value;
51015
- return null;
51016
- }
51017
- function createConversationRef() {
51018
- return { id: `conv_${randomUUID().replaceAll("-", "")}` };
51019
- }
51020
- function isConversationReference(value) {
51021
- if (typeof value === "string") return value.length > 0;
51022
- return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string" && value.id.length > 0;
51023
- }
51024
- function getConversationId(conversation) {
51025
- return typeof conversation === "string" ? conversation : conversation.id;
51026
- }
51027
- function getInputItemId(item) {
51028
- if (!item || typeof item !== "object") return;
51029
- if ("id" in item && typeof item.id === "string") return item.id;
51030
- if ("call_id" in item && typeof item.call_id === "string") return item.call_id;
51031
- }
51032
- //#endregion
51033
- //#region src/dispatch/resource-dispatcher.ts
51034
- var EmulatorResourceDispatcher = class {
51035
- retrieve(responseId) {
51036
- return Promise.resolve(getStoredResponseOrThrow(responseId));
51037
- }
51038
- listInputItems(responseId, params) {
51039
- return Promise.resolve(listStoredInputItemsOrThrow(responseId, params));
51040
- }
51041
- async createInputTokens(payload) {
51042
- return estimateEmulatorInputTokens(payload, resolveModelOrThrow(payload.model ?? ""));
51043
- }
51044
- delete(responseId) {
51045
- return Promise.resolve(deleteStoredResponseOrThrow(responseId));
51046
- }
51047
- };
51048
- var UpstreamResourceDispatcher = class {
51049
- client;
51050
- constructor(client) {
51051
- this.client = client;
51052
- }
51053
- retrieve(responseId, params, options) {
51054
- return this.client.getResponse(responseId, {
51055
- params,
51056
- ...options
51057
- });
51058
- }
51059
- listInputItems(responseId, params, options) {
51060
- return this.client.getResponseInputItems(responseId, params, options);
51061
- }
51062
- createInputTokens(payload, options) {
51063
- return this.client.createResponseInputTokens(payload, options);
51064
- }
51065
- delete(responseId, options) {
51066
- return this.client.deleteResponse(responseId, options);
51067
- }
51068
- };
51069
- function createResourceDispatcher() {
51070
- return configStore.isEmulatorEnabled() ? new EmulatorResourceDispatcher() : new UpstreamResourceDispatcher(createCopilotClient());
51071
- }
51072
- //#endregion
51073
50561
  //#region src/dispatch/strategy-registry.ts
51074
50562
  var StrategyRegistry = class {
51075
50563
  entries = [];
@@ -51141,19 +50629,21 @@ function normalizeOutputs(value) {
51141
50629
  */
51142
50630
  function passthroughSSEChunk(chunk, data) {
51143
50631
  return {
51144
- ...chunk.comment ? { comment: chunk.comment } : {},
51145
50632
  ...chunk.event ? { event: chunk.event } : {},
51146
50633
  ...chunk.id !== void 0 ? { id: String(chunk.id) } : {},
51147
- ...chunk.retry !== void 0 ? { retry: chunk.retry } : {},
51148
50634
  data
51149
50635
  };
51150
50636
  }
51151
50637
  //#endregion
51152
50638
  //#region src/routes/chat-completions/strategy.ts
51153
- function createChatCompletionsStrategy(transport, adapter, plan, signal) {
50639
+ function createChatCompletionsStrategy(client, adapter, plan, signal) {
51154
50640
  return {
51155
50641
  execute() {
51156
- return transport.execute(plan, { signal });
50642
+ return client.createChatCompletions(plan.payload, {
50643
+ signal,
50644
+ initiator: plan.initiator,
50645
+ requestContext: plan.requestContext
50646
+ });
51157
50647
  },
51158
50648
  isStream(result) {
51159
50649
  return !isNonStreamingResponse(result);
@@ -51180,9 +50670,8 @@ const chatCompletionsEntry$1 = {
51180
50670
  const adapter = new OpenAIChatAdapter();
51181
50671
  const plan = adapter.toCapiPlan(ctx.payload, { requestContext: ctx.requestContext });
51182
50672
  appendModelStepInPlace(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
51183
- const transport = new CopilotTransport(ctx.copilotClient);
51184
50673
  consola.debug("Streaming response");
51185
- return await runStrategy(createChatCompletionsStrategy(transport, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
50674
+ return await runStrategy(createChatCompletionsStrategy(ctx.copilotClient, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
51186
50675
  }
51187
50676
  };
51188
50677
  const chatCompletionsStrategyRegistry = new StrategyRegistry();
@@ -51200,6 +50689,7 @@ async function handleCompletionCore({ body, signal, headers }) {
51200
50689
  strategyRegistry: chatCompletionsStrategyRegistry,
51201
50690
  afterIngest({ payload }) {
51202
50691
  consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
50692
+ return payload;
51203
50693
  },
51204
50694
  async afterTransform({ payload, selectedModel }) {
51205
50695
  try {
@@ -51275,7 +50765,7 @@ function createAnthropicAdapter() {
51275
50765
  const fallbackConfig = getModelFallbackConfig();
51276
50766
  return new AnthropicMessagesAdapter({
51277
50767
  modelResolver: (model) => resolveModel(model, knownModelIds, fallbackConfig),
51278
- getModelCapabilities: (model) => ({ supportsThinkingBudget: model.startsWith("claude") })
50768
+ getModelCapabilities: (model) => ({ supportsThinkingBudget: inferModelFamily(model) === "claude" })
51279
50769
  });
51280
50770
  }
51281
50771
  //#endregion
@@ -51314,7 +50804,68 @@ async function handleCountTokensCore({ body, headers }) {
51314
50804
  return { input_tokens: finalTokenCount };
51315
50805
  }
51316
50806
  //#endregion
51317
- //#region src/lib/function-schema.ts
50807
+ //#region src/transform/context-management.ts
50808
+ /** Default token threshold when model limits are unknown. */
50809
+ const DEFAULT_COMPACT_THRESHOLD = 5e4;
50810
+ /** Fraction of max prompt tokens to use as compact threshold. */
50811
+ const COMPACT_THRESHOLD_RATIO = .9;
50812
+ function getResponsesRequestOptions(payload) {
50813
+ return {
50814
+ vision: hasVisionInput(payload),
50815
+ initiator: hasAgentInitiator(payload) ? "agent" : "user"
50816
+ };
50817
+ }
50818
+ function hasAgentInitiator(payload) {
50819
+ const lastItem = getPayloadItems(payload).at(-1);
50820
+ if (!lastItem) return false;
50821
+ if (!("role" in lastItem) || !lastItem.role) return true;
50822
+ return String(lastItem.role).toLowerCase() === "assistant";
50823
+ }
50824
+ function hasVisionInput(payload) {
50825
+ return getPayloadItems(payload).some((item) => containsVisionContent(item));
50826
+ }
50827
+ function resolveResponsesCompactThreshold(maxPromptTokens) {
50828
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * COMPACT_THRESHOLD_RATIO);
50829
+ return DEFAULT_COMPACT_THRESHOLD;
50830
+ }
50831
+ function createCompactionContextManagement(compactThreshold) {
50832
+ return [{
50833
+ type: "compaction",
50834
+ compact_threshold: compactThreshold
50835
+ }];
50836
+ }
50837
+ function applyContextManagement(payload, maxPromptTokens) {
50838
+ if (payload.context_management !== void 0) return;
50839
+ if (!configStore.isContextManagementModel(payload.model)) return;
50840
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
50841
+ }
50842
+ function compactInputByLatestCompaction(payload) {
50843
+ if (!configStore.isAutoCompactResponsesInputEnabled()) return;
50844
+ if (!Array.isArray(payload.input) || payload.input.length === 0) return;
50845
+ const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
50846
+ if (latestCompactionMessageIndex === void 0) return;
50847
+ payload.input = payload.input.slice(latestCompactionMessageIndex);
50848
+ }
50849
+ function getLatestCompactionMessageIndex(input) {
50850
+ for (let index = input.length - 1; index >= 0; index--) if (isCompactionInputItem(input[index])) return index;
50851
+ }
50852
+ function isCompactionInputItem(value) {
50853
+ return "type" in value && value.type === "compaction";
50854
+ }
50855
+ function getPayloadItems(payload) {
50856
+ return Array.isArray(payload.input) ? payload.input : [];
50857
+ }
50858
+ function containsVisionContent(value) {
50859
+ if (!value) return false;
50860
+ if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
50861
+ if (typeof value !== "object") return false;
50862
+ const record = value;
50863
+ if (record.type === "input_image") return true;
50864
+ if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
50865
+ return false;
50866
+ }
50867
+ //#endregion
50868
+ //#region src/translator/responses/function-schema.ts
51318
50869
  function isRecord$2(value) {
51319
50870
  return typeof value === "object" && value !== null && !Array.isArray(value);
51320
50871
  }
@@ -51356,147 +50907,9 @@ function normalizeFunctionParametersSchemaForCopilot(schema) {
51356
50907
  return normalizeSchemaNode(schema);
51357
50908
  }
51358
50909
  //#endregion
51359
- //#region src/translator/responses/anthropic-to-responses.ts
50910
+ //#region src/translator/responses/response-items.ts
51360
50911
  const MESSAGE_TYPE = "message";
51361
- const USER_ID_ACCOUNT_RE = /user_([^_]+)_account/;
51362
- const USER_ID_SESSION_RE = /_session_(.+)$/;
51363
50912
  const THINKING_TEXT = "Thinking...";
51364
- function translateAnthropicToResponsesPayload(payload, options) {
51365
- assertResponsesCompatibleRequest(payload);
51366
- const input = [];
51367
- for (const message of payload.messages) input.push(...translateMessage(message));
51368
- const { safetyIdentifier, promptCacheKey } = parseUserId(payload.metadata?.user_id);
51369
- const reasoning = resolveResponsesReasoningConfig(payload, options);
51370
- const text = resolveResponsesTextConfig(payload);
51371
- return {
51372
- model: payload.model,
51373
- input,
51374
- instructions: translateSystemPrompt(payload.system),
51375
- temperature: payload.temperature ?? null,
51376
- top_p: payload.top_p ?? null,
51377
- max_output_tokens: payload.max_tokens,
51378
- tools: convertAnthropicTools(payload.tools),
51379
- tool_choice: convertAnthropicToolChoice(payload.tool_choice),
51380
- metadata: payload.metadata ? { ...payload.metadata } : null,
51381
- safety_identifier: safetyIdentifier,
51382
- prompt_cache_key: promptCacheKey,
51383
- stream: payload.stream ?? null,
51384
- store: false,
51385
- parallel_tool_calls: true,
51386
- ...text ? { text } : {},
51387
- ...reasoning ? {
51388
- reasoning,
51389
- include: ["reasoning.encrypted_content"]
51390
- } : {}
51391
- };
51392
- }
51393
- function decodeCompactionCarrierSignature(signature) {
51394
- return SignatureCodec.decodeCompaction(signature);
51395
- }
51396
- function translateMessage(message) {
51397
- switch (message.role) {
51398
- case "user": return translateUserMessage(message);
51399
- case "assistant": return translateAssistantMessage(message);
51400
- case "system": return translateSystemMessage(message);
51401
- }
51402
- }
51403
- function translateSystemMessage(message) {
51404
- if (typeof message.content === "string") return [createMessage("system", message.content)];
51405
- if (!Array.isArray(message.content)) return [];
51406
- return [createMessage("system", message.content.map((block) => createTextContent(block.text)))];
51407
- }
51408
- function translateUserMessage(message) {
51409
- if (typeof message.content === "string") return [createMessage("user", message.content)];
51410
- if (!Array.isArray(message.content)) return [];
51411
- const items = [];
51412
- const pendingContent = [];
51413
- for (const block of message.content) {
51414
- if (block.type === "tool_result" || block.type === "mcp_tool_result") {
51415
- flushPendingContent(pendingContent, items, { role: "user" });
51416
- items.push(createFunctionCallOutput(block));
51417
- continue;
51418
- }
51419
- if (isServerToolResultBlock(block)) {
51420
- flushPendingContent(pendingContent, items, { role: "user" });
51421
- items.push(createServerFunctionCallOutput(block));
51422
- continue;
51423
- }
51424
- const converted = translateUserContentBlock(block);
51425
- if (converted) pendingContent.push(converted);
51426
- }
51427
- flushPendingContent(pendingContent, items, { role: "user" });
51428
- return items;
51429
- }
51430
- function translateAssistantMessage(message) {
51431
- const assistantPhase = resolveAssistantPhase(message.content);
51432
- if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
51433
- if (!Array.isArray(message.content)) return [];
51434
- const items = [];
51435
- const pendingContent = [];
51436
- for (const block of message.content) {
51437
- if (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use") {
51438
- flushPendingContent(pendingContent, items, {
51439
- role: "assistant",
51440
- phase: assistantPhase
51441
- });
51442
- items.push(createFunctionToolCall(block));
51443
- continue;
51444
- }
51445
- if (block.type === "redacted_thinking") {
51446
- flushPendingContent(pendingContent, items, {
51447
- role: "assistant",
51448
- phase: assistantPhase
51449
- });
51450
- items.push(createRedactedReasoningContent(block));
51451
- continue;
51452
- }
51453
- if (block.type === "mcp_tool_result") {
51454
- flushPendingContent(pendingContent, items, {
51455
- role: "assistant",
51456
- phase: assistantPhase
51457
- });
51458
- items.push(createFunctionCallOutput(block));
51459
- continue;
51460
- }
51461
- if (isServerToolResultBlock(block)) {
51462
- flushPendingContent(pendingContent, items, {
51463
- role: "assistant",
51464
- phase: assistantPhase
51465
- });
51466
- items.push(createServerFunctionCallOutput(block));
51467
- continue;
51468
- }
51469
- if (block.type === "thinking" && block.signature) {
51470
- const compaction = createCompactionContent(block);
51471
- if (compaction) {
51472
- flushPendingContent(pendingContent, items, {
51473
- role: "assistant",
51474
- phase: assistantPhase
51475
- });
51476
- items.push(compaction);
51477
- continue;
51478
- }
51479
- if (SignatureCodec.isReasoningSignature(block.signature)) {
51480
- const { id } = SignatureCodec.decodeReasoning(block.signature);
51481
- if (id) {
51482
- flushPendingContent(pendingContent, items, {
51483
- role: "assistant",
51484
- phase: assistantPhase
51485
- });
51486
- items.push(createReasoningContent(block));
51487
- continue;
51488
- }
51489
- }
51490
- }
51491
- const converted = translateAssistantContentBlock(block);
51492
- if (converted) pendingContent.push(converted);
51493
- }
51494
- flushPendingContent(pendingContent, items, {
51495
- role: "assistant",
51496
- phase: assistantPhase
51497
- });
51498
- return items;
51499
- }
51500
50913
  function translateUserContentBlock(block) {
51501
50914
  switch (block.type) {
51502
50915
  case "text": return createTextContent(block.text);
@@ -51595,7 +51008,7 @@ function createRedactedReasoningContent(block) {
51595
51008
  };
51596
51009
  }
51597
51010
  function createCompactionContent(block) {
51598
- const compaction = decodeCompactionCarrierSignature(block.signature ?? "");
51011
+ const compaction = SignatureCodec.decodeCompaction(block.signature ?? "");
51599
51012
  if (!compaction) return;
51600
51013
  return {
51601
51014
  id: compaction.id,
@@ -51631,6 +51044,160 @@ function createServerFunctionCallOutput(block) {
51631
51044
  function isServerToolResultBlock(block) {
51632
51045
  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";
51633
51046
  }
51047
+ function convertToolResultContent(content) {
51048
+ if (typeof content === "string") return content;
51049
+ const result = [];
51050
+ for (const block of content) switch (block.type) {
51051
+ case "text":
51052
+ result.push(createTextContent(block.text));
51053
+ break;
51054
+ case "image":
51055
+ result.push(createImageContent(block));
51056
+ break;
51057
+ case "search_result":
51058
+ result.push(createTextContent(formatSearchResultBlock(block)));
51059
+ break;
51060
+ default: break;
51061
+ }
51062
+ return result;
51063
+ }
51064
+ //#endregion
51065
+ //#region src/translator/responses/anthropic-to-responses.ts
51066
+ const USER_ID_ACCOUNT_RE = /user_([^_]+)_account/;
51067
+ const USER_ID_SESSION_RE = /_session_(.+)$/;
51068
+ function translateAnthropicToResponsesPayload(payload, options) {
51069
+ assertResponsesCompatibleRequest(payload);
51070
+ const input = [];
51071
+ for (const message of payload.messages) input.push(...translateMessage(message));
51072
+ const { safetyIdentifier, promptCacheKey } = parseUserId(payload.metadata?.user_id);
51073
+ const reasoning = resolveResponsesReasoningConfig(payload, options);
51074
+ const text = resolveResponsesTextConfig(payload);
51075
+ return {
51076
+ model: payload.model,
51077
+ input,
51078
+ instructions: translateSystemPrompt(payload.system),
51079
+ temperature: payload.temperature ?? null,
51080
+ top_p: payload.top_p ?? null,
51081
+ max_output_tokens: payload.max_tokens,
51082
+ tools: convertAnthropicTools(payload.tools),
51083
+ tool_choice: convertAnthropicToolChoice(payload.tool_choice),
51084
+ metadata: payload.metadata ? { ...payload.metadata } : null,
51085
+ safety_identifier: safetyIdentifier,
51086
+ prompt_cache_key: promptCacheKey,
51087
+ stream: payload.stream ?? null,
51088
+ store: false,
51089
+ parallel_tool_calls: true,
51090
+ ...text ? { text } : {},
51091
+ ...reasoning ? {
51092
+ reasoning,
51093
+ include: ["reasoning.encrypted_content"]
51094
+ } : {}
51095
+ };
51096
+ }
51097
+ function translateMessage(message) {
51098
+ switch (message.role) {
51099
+ case "user": return translateUserMessage(message);
51100
+ case "assistant": return translateAssistantMessage(message);
51101
+ case "system": return translateSystemMessage(message);
51102
+ }
51103
+ }
51104
+ function translateSystemMessage(message) {
51105
+ if (typeof message.content === "string") return [createMessage("system", message.content)];
51106
+ if (!Array.isArray(message.content)) return [];
51107
+ return [createMessage("system", message.content.map((block) => createTextContent(block.text)))];
51108
+ }
51109
+ function translateUserMessage(message) {
51110
+ if (typeof message.content === "string") return [createMessage("user", message.content)];
51111
+ if (!Array.isArray(message.content)) return [];
51112
+ const items = [];
51113
+ const pendingContent = [];
51114
+ for (const block of message.content) {
51115
+ if (block.type === "tool_result" || block.type === "mcp_tool_result") {
51116
+ flushPendingContent(pendingContent, items, { role: "user" });
51117
+ items.push(createFunctionCallOutput(block));
51118
+ continue;
51119
+ }
51120
+ if (isServerToolResultBlock(block)) {
51121
+ flushPendingContent(pendingContent, items, { role: "user" });
51122
+ items.push(createServerFunctionCallOutput(block));
51123
+ continue;
51124
+ }
51125
+ const converted = translateUserContentBlock(block);
51126
+ if (converted) pendingContent.push(converted);
51127
+ }
51128
+ flushPendingContent(pendingContent, items, { role: "user" });
51129
+ return items;
51130
+ }
51131
+ function translateAssistantMessage(message) {
51132
+ const assistantPhase = resolveAssistantPhase(message.content);
51133
+ if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
51134
+ if (!Array.isArray(message.content)) return [];
51135
+ const items = [];
51136
+ const pendingContent = [];
51137
+ for (const block of message.content) {
51138
+ if (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use") {
51139
+ flushPendingContent(pendingContent, items, {
51140
+ role: "assistant",
51141
+ phase: assistantPhase
51142
+ });
51143
+ items.push(createFunctionToolCall(block));
51144
+ continue;
51145
+ }
51146
+ if (block.type === "redacted_thinking") {
51147
+ flushPendingContent(pendingContent, items, {
51148
+ role: "assistant",
51149
+ phase: assistantPhase
51150
+ });
51151
+ items.push(createRedactedReasoningContent(block));
51152
+ continue;
51153
+ }
51154
+ if (block.type === "mcp_tool_result") {
51155
+ flushPendingContent(pendingContent, items, {
51156
+ role: "assistant",
51157
+ phase: assistantPhase
51158
+ });
51159
+ items.push(createFunctionCallOutput(block));
51160
+ continue;
51161
+ }
51162
+ if (isServerToolResultBlock(block)) {
51163
+ flushPendingContent(pendingContent, items, {
51164
+ role: "assistant",
51165
+ phase: assistantPhase
51166
+ });
51167
+ items.push(createServerFunctionCallOutput(block));
51168
+ continue;
51169
+ }
51170
+ if (block.type === "thinking" && block.signature) {
51171
+ const compaction = createCompactionContent(block);
51172
+ if (compaction) {
51173
+ flushPendingContent(pendingContent, items, {
51174
+ role: "assistant",
51175
+ phase: assistantPhase
51176
+ });
51177
+ items.push(compaction);
51178
+ continue;
51179
+ }
51180
+ if (SignatureCodec.isReasoningSignature(block.signature)) {
51181
+ const { id } = SignatureCodec.decodeReasoning(block.signature);
51182
+ if (id) {
51183
+ flushPendingContent(pendingContent, items, {
51184
+ role: "assistant",
51185
+ phase: assistantPhase
51186
+ });
51187
+ items.push(createReasoningContent(block));
51188
+ continue;
51189
+ }
51190
+ }
51191
+ }
51192
+ const converted = translateAssistantContentBlock(block);
51193
+ if (converted) pendingContent.push(converted);
51194
+ }
51195
+ flushPendingContent(pendingContent, items, {
51196
+ role: "assistant",
51197
+ phase: assistantPhase
51198
+ });
51199
+ return items;
51200
+ }
51634
51201
  function translateSystemPrompt(system) {
51635
51202
  if (!system) return null;
51636
51203
  if (typeof system === "string") return system;
@@ -51716,92 +51283,18 @@ function parseUserId(userId) {
51716
51283
  promptCacheKey: sessionMatch ? sessionMatch[1] : null
51717
51284
  };
51718
51285
  }
51719
- function convertToolResultContent(content) {
51720
- if (typeof content === "string") return content;
51721
- const result = [];
51722
- for (const block of content) switch (block.type) {
51723
- case "text":
51724
- result.push(createTextContent(block.text));
51725
- break;
51726
- case "image":
51727
- result.push(createImageContent(block));
51728
- break;
51729
- case "search_result":
51730
- result.push(createTextContent(formatSearchResultBlock(block)));
51731
- break;
51732
- default: break;
51733
- }
51734
- return result;
51735
- }
51736
- //#endregion
51737
- //#region src/routes/responses/context-management.ts
51738
- /** Default token threshold when model limits are unknown. */
51739
- const DEFAULT_COMPACT_THRESHOLD = 5e4;
51740
- /** Fraction of max prompt tokens to use as compact threshold. */
51741
- const COMPACT_THRESHOLD_RATIO = .9;
51742
- function getResponsesRequestOptions(payload) {
51743
- return {
51744
- vision: hasVisionInput(payload),
51745
- initiator: hasAgentInitiator(payload) ? "agent" : "user"
51746
- };
51747
- }
51748
- function hasAgentInitiator(payload) {
51749
- const lastItem = getPayloadItems(payload).at(-1);
51750
- if (!lastItem) return false;
51751
- if (!("role" in lastItem) || !lastItem.role) return true;
51752
- return String(lastItem.role).toLowerCase() === "assistant";
51753
- }
51754
- function hasVisionInput(payload) {
51755
- return getPayloadItems(payload).some((item) => containsVisionContent(item));
51756
- }
51757
- function resolveResponsesCompactThreshold(maxPromptTokens) {
51758
- if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * COMPACT_THRESHOLD_RATIO);
51759
- return DEFAULT_COMPACT_THRESHOLD;
51760
- }
51761
- function createCompactionContextManagement(compactThreshold) {
51762
- return [{
51763
- type: "compaction",
51764
- compact_threshold: compactThreshold
51765
- }];
51766
- }
51767
- function applyContextManagement(payload, maxPromptTokens) {
51768
- if (payload.context_management !== void 0) return;
51769
- if (!configStore.isContextManagementModel(payload.model)) return;
51770
- payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
51771
- }
51772
- function compactInputByLatestCompaction(payload) {
51773
- if (!configStore.isAutoCompactResponsesInputEnabled()) return;
51774
- if (!Array.isArray(payload.input) || payload.input.length === 0) return;
51775
- const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
51776
- if (latestCompactionMessageIndex === void 0) return;
51777
- payload.input = payload.input.slice(latestCompactionMessageIndex);
51778
- }
51779
- function getLatestCompactionMessageIndex(input) {
51780
- for (let index = input.length - 1; index >= 0; index--) if (isCompactionInputItem(input[index])) return index;
51781
- }
51782
- function isCompactionInputItem(value) {
51783
- return "type" in value && value.type === "compaction";
51784
- }
51785
- function getPayloadItems(payload) {
51786
- return Array.isArray(payload.input) ? payload.input : [];
51787
- }
51788
- function containsVisionContent(value) {
51789
- if (!value) return false;
51790
- if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
51791
- if (typeof value !== "object") return false;
51792
- const record = value;
51793
- if (record.type === "input_image") return true;
51794
- if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
51795
- return false;
51796
- }
51797
51286
  //#endregion
51798
51287
  //#region src/routes/messages/strategies/chat-completions.ts
51799
- function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, signal) {
51288
+ function createMessagesViaChatCompletionsStrategy(client, adapter, plan, signal) {
51800
51289
  let streamTranslator;
51801
51290
  let done = false;
51802
51291
  return {
51803
51292
  execute() {
51804
- return transport.execute(plan, { signal });
51293
+ return client.createChatCompletions(plan.payload, {
51294
+ signal,
51295
+ initiator: plan.initiator,
51296
+ requestContext: plan.requestContext
51297
+ });
51805
51298
  },
51806
51299
  isStream(result) {
51807
51300
  return !isNonStreamingResponse(result);
@@ -51818,24 +51311,15 @@ function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, sign
51818
51311
  if (chunk.data === "[DONE]") {
51819
51312
  const finalEvents = streamTranslator.onDone();
51820
51313
  done = true;
51821
- return finalEvents.map((event) => ({
51822
- event: event.type,
51823
- data: JSON.stringify(event)
51824
- }));
51314
+ return serializeAnthropicSSE(finalEvents);
51825
51315
  }
51826
51316
  if (!chunk.data) return null;
51827
51317
  const parsed = JSON.parse(chunk.data);
51828
- return streamTranslator.onChunk(parsed).map((event) => ({
51829
- event: event.type,
51830
- data: JSON.stringify(event)
51831
- }));
51318
+ return serializeAnthropicSSE(streamTranslator.onChunk(parsed));
51832
51319
  },
51833
51320
  onStreamDone() {
51834
51321
  if (!streamTranslator) return null;
51835
- return streamTranslator.onDone().map((event) => ({
51836
- event: event.type,
51837
- data: JSON.stringify(event)
51838
- }));
51322
+ return serializeAnthropicSSE(streamTranslator.onDone());
51839
51323
  },
51840
51324
  shouldBreakStream() {
51841
51325
  return done;
@@ -51843,15 +51327,12 @@ function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, sign
51843
51327
  onStreamError(error) {
51844
51328
  consola.error("Error streaming Anthropic response:", error);
51845
51329
  if (!streamTranslator) streamTranslator = adapter.createStreamSerializer();
51846
- return streamTranslator.onError(error).map((event) => ({
51847
- event: event.type,
51848
- data: JSON.stringify(event)
51849
- }));
51330
+ return serializeAnthropicSSE(streamTranslator.onError(error));
51850
51331
  }
51851
51332
  };
51852
51333
  }
51853
51334
  //#endregion
51854
- //#region src/lib/async-iterable.ts
51335
+ //#region src/util/async-iterable.ts
51855
51336
  function isAsyncIterable(value) {
51856
51337
  return Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
51857
51338
  }
@@ -51924,6 +51405,30 @@ function createNativeMessagesStrategy(copilotClient, payload, anthropicBetaHeade
51924
51405
  }
51925
51406
  };
51926
51407
  }
51408
+ var FunctionCallArgumentsValidationError = class extends Error {
51409
+ constructor(message) {
51410
+ super(message);
51411
+ this.name = "FunctionCallArgumentsValidationError";
51412
+ }
51413
+ };
51414
+ function updateWhitespaceRunState(previousCount, chunk) {
51415
+ let count = previousCount;
51416
+ for (const char of chunk) {
51417
+ if (char === " " || char === "\r" || char === "\n" || char === " ") {
51418
+ count += 1;
51419
+ if (count > 20) return {
51420
+ nextCount: count,
51421
+ exceeded: true
51422
+ };
51423
+ continue;
51424
+ }
51425
+ count = 0;
51426
+ }
51427
+ return {
51428
+ nextCount: count,
51429
+ exceeded: false
51430
+ };
51431
+ }
51927
51432
  //#endregion
51928
51433
  //#region src/translator/responses/responses-to-anthropic.ts
51929
51434
  function translateResponsesToAnthropic(response) {
@@ -51996,12 +51501,9 @@ function combineMessageTextContent(content) {
51996
51501
  function extractReasoningText(item) {
51997
51502
  if (!item.summary || item.summary.length === 0) return THINKING_TEXT;
51998
51503
  const segments = [];
51999
- collectReasoningSegments(item.summary, segments);
51504
+ for (const block of item.summary) if (typeof block.text === "string") segments.push(block.text);
52000
51505
  return segments.join("").trim();
52001
51506
  }
52002
- function collectReasoningSegments(blocks, segments) {
52003
- for (const block of blocks) if (typeof block.text === "string") segments.push(block.text);
52004
- }
52005
51507
  function createToolUseContentBlock(call) {
52006
51508
  if (!call.name || !call.call_id) return null;
52007
51509
  return {
@@ -52061,31 +51563,6 @@ function isResponseOutputRefusal(block) {
52061
51563
  }
52062
51564
  //#endregion
52063
51565
  //#region src/translator/responses/responses-stream-translator.ts
52064
- const MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE = 20;
52065
- var FunctionCallArgumentsValidationError = class extends Error {
52066
- constructor(message) {
52067
- super(message);
52068
- this.name = "FunctionCallArgumentsValidationError";
52069
- }
52070
- };
52071
- function updateWhitespaceRunState(previousCount, chunk) {
52072
- let count = previousCount;
52073
- for (const char of chunk) {
52074
- if (char === " " || char === "\r" || char === "\n" || char === " ") {
52075
- count += 1;
52076
- if (count > MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE) return {
52077
- nextCount: count,
52078
- exceeded: true
52079
- };
52080
- continue;
52081
- }
52082
- count = 0;
52083
- }
52084
- return {
52085
- nextCount: count,
52086
- exceeded: false
52087
- };
52088
- }
52089
51566
  var ResponsesStreamTranslator = class {
52090
51567
  state = {
52091
51568
  messageStartSent: false,
@@ -52345,6 +51822,7 @@ var ResponsesStreamTranslator = class {
52345
51822
  return events;
52346
51823
  }
52347
51824
  handleResponseCompleted(rawEvent) {
51825
+ if (this.state.messageCompleted) return [];
52348
51826
  const events = [];
52349
51827
  this.closeAllOpenBlocks(events);
52350
51828
  const anthropic = translateResponsesToAnthropic(rawEvent.response);
@@ -52505,27 +51983,18 @@ function createMessagesViaResponsesStrategy(copilotClient, responsesPayload, opt
52505
51983
  data: "{\"type\":\"ping\"}"
52506
51984
  };
52507
51985
  if (!chunk.data) return null;
52508
- return translator.onEvent(JSON.parse(chunk.data)).map((event) => ({
52509
- event: event.type,
52510
- data: JSON.stringify(event)
52511
- }));
51986
+ return serializeAnthropicSSE(translator.onEvent(JSON.parse(chunk.data)));
52512
51987
  },
52513
51988
  shouldBreakStream() {
52514
51989
  return translator.isCompleted;
52515
51990
  },
52516
51991
  onStreamDone() {
52517
51992
  if (translator.isCompleted) return null;
52518
- return translator.onDone().map((event) => ({
52519
- event: event.type,
52520
- data: JSON.stringify(event)
52521
- }));
51993
+ return serializeAnthropicSSE(translator.onDone());
52522
51994
  },
52523
51995
  onStreamError(error) {
52524
51996
  consola.error("Error streaming Anthropic response via Responses API:", error);
52525
- return translator.onError(error).map((event) => ({
52526
- event: event.type,
52527
- data: JSON.stringify(event)
52528
- }));
51997
+ return serializeAnthropicSSE(translator.onError(error));
52529
51998
  }
52530
51999
  };
52531
52000
  }
@@ -52570,7 +52039,7 @@ const chatCompletionsEntry = {
52570
52039
  appendModelStepInPlace(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
52571
52040
  consola.debug("Claude Code requested model:", ctx.anthropicPayload.model, "-> Copilot model:", plan.resolvedModel);
52572
52041
  if (consola.level >= 4) consola.debug("Planned Copilot request payload:", JSON.stringify(plan.payload));
52573
- return await runStrategy(createMessagesViaChatCompletionsStrategy(new CopilotTransport(ctx.copilotClient), adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
52042
+ return await runStrategy(createMessagesViaChatCompletionsStrategy(ctx.copilotClient, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
52574
52043
  }
52575
52044
  };
52576
52045
  const defaultStrategyRegistry = new StrategyRegistry();
@@ -52589,10 +52058,10 @@ async function handleMessagesCore({ body, signal, headers }) {
52589
52058
  protocol: "anthropic-messages",
52590
52059
  transformChain: messagesModelChain,
52591
52060
  strategyRegistry: defaultStrategyRegistry,
52592
- contextRetry: true,
52593
52061
  afterIngest({ payload, headers: reqHeaders }) {
52594
52062
  if (consola.level >= 4) consola.debug("Anthropic request payload:", JSON.stringify(payload));
52595
- anthropicBetaHeader = processAnthropicBetaHeader(reqHeaders.get("anthropic-beta"), payload.model).header;
52063
+ anthropicBetaHeader = processAnthropicBetaHeader(reqHeaders.get("anthropic-beta"));
52064
+ return payload;
52596
52065
  },
52597
52066
  buildStrategyContext({ payload, meta, headers: reqHeaders, selectedModel, copilotClient, upstreamSignal, modelMapping }) {
52598
52067
  return {
@@ -52657,13 +52126,243 @@ function createModelRoutes() {
52657
52126
  });
52658
52127
  }
52659
52128
  //#endregion
52129
+ //#region src/routes/responses/emulator.ts
52130
+ function cloneValue(value) {
52131
+ return structuredClone(value);
52132
+ }
52133
+ function rejectUnsupportedBackground(payload) {
52134
+ if (payload.background) throwInvalidRequestError("background mode is not supported by the responses official emulator.", "background", "unsupported_background_mode");
52135
+ }
52136
+ function prepareEmulatorRequest(payload) {
52137
+ rejectUnsupportedBackground(payload);
52138
+ const normalizedCurrentInput = normalizeResponsesInput(payload.input);
52139
+ const { continuationSourceResponseId, conversation: resolvedConversation, previousResponse } = resolveContinuation(payload);
52140
+ const conversation = resolvedConversation ?? createConversationRef();
52141
+ const effectiveInputItems = [...continuationSourceResponseId ? buildContinuationHistory(continuationSourceResponseId) : [], ...normalizedCurrentInput];
52142
+ const shouldStore = payload.store ?? true;
52143
+ return {
52144
+ upstreamPayload: {
52145
+ ...payload,
52146
+ background: void 0,
52147
+ conversation: void 0,
52148
+ previous_response_id: void 0,
52149
+ store: void 0,
52150
+ input: effectiveInputItems
52151
+ },
52152
+ effectiveInputItems,
52153
+ previousResponseId: previousResponse?.id,
52154
+ conversation,
52155
+ shouldStore
52156
+ };
52157
+ }
52158
+ function decorateStoredResponse(upstreamResponse, requestPayload, prepared) {
52159
+ return {
52160
+ ...cloneValue(upstreamResponse),
52161
+ previous_response_id: prepared.previousResponseId ?? null,
52162
+ conversation: prepared.conversation,
52163
+ truncation: requestPayload.truncation ?? null,
52164
+ store: prepared.shouldStore,
52165
+ user: normalizeNullableString(requestPayload.user),
52166
+ service_tier: normalizeServiceTier(requestPayload.service_tier)
52167
+ };
52168
+ }
52169
+ function persistEmulatorResponse(response, effectiveInputItems) {
52170
+ responsesEmulatorState.setResponse(response);
52171
+ if (response.conversation) {
52172
+ responsesEmulatorState.setConversation(response.conversation);
52173
+ responsesEmulatorState.setConversationHead(getConversationId(response.conversation), response.id);
52174
+ }
52175
+ responsesEmulatorState.setInputItems(response.id, effectiveInputItems);
52176
+ }
52177
+ function getStoredResponseOrThrow(responseId) {
52178
+ const response = responsesEmulatorState.getResponse(responseId);
52179
+ if (!response) throw new HTTPError(404, { error: {
52180
+ message: `No response found with id '${responseId}'.`,
52181
+ type: "invalid_request_error"
52182
+ } });
52183
+ return response;
52184
+ }
52185
+ function listStoredInputItemsOrThrow(responseId, params) {
52186
+ const items = responsesEmulatorState.getInputItems(responseId);
52187
+ if (!items) throw new HTTPError(404, { error: {
52188
+ message: `No response input items found for id '${responseId}'.`,
52189
+ type: "invalid_request_error"
52190
+ } });
52191
+ let orderedItems = cloneValue(items);
52192
+ if (params?.order === "desc") orderedItems.reverse();
52193
+ if (params?.after) {
52194
+ const afterIndex = orderedItems.findIndex((item) => getInputItemId(item) === params.after);
52195
+ if (afterIndex >= 0) orderedItems = orderedItems.slice(afterIndex + 1);
52196
+ }
52197
+ const limitedItems = orderedItems.slice(0, params?.limit ?? orderedItems.length);
52198
+ return {
52199
+ object: "list",
52200
+ data: limitedItems,
52201
+ first_id: getInputItemId(limitedItems[0]) ?? null,
52202
+ last_id: getInputItemId(limitedItems.at(-1)) ?? null,
52203
+ has_more: limitedItems.length < orderedItems.length
52204
+ };
52205
+ }
52206
+ function deleteStoredResponseOrThrow(responseId) {
52207
+ getStoredResponseOrThrow(responseId);
52208
+ return responsesEmulatorState.deleteResponse(responseId);
52209
+ }
52210
+ async function estimateEmulatorInputTokens(payload, selectedModel) {
52211
+ return {
52212
+ object: "response.input_tokens",
52213
+ input_tokens: await estimateResponsesInputTokens(resolveEffectiveInputForInputTokens(payload), selectedModel)
52214
+ };
52215
+ }
52216
+ function resolveEffectiveInputForInputTokens(payload) {
52217
+ const normalizedInput = normalizeResponsesInput(payload.input);
52218
+ const background = payload.background === null || typeof payload.background === "boolean" ? payload.background : void 0;
52219
+ const conversation = isConversationReference(payload.conversation) ? payload.conversation : void 0;
52220
+ const previousResponseId = typeof payload.previous_response_id === "string" ? payload.previous_response_id : void 0;
52221
+ rejectUnsupportedBackground({ background });
52222
+ const { continuationSourceResponseId } = resolveContinuation({
52223
+ conversation,
52224
+ previous_response_id: previousResponseId
52225
+ });
52226
+ if (continuationSourceResponseId) return [...buildContinuationHistory(continuationSourceResponseId), ...normalizedInput];
52227
+ return normalizedInput;
52228
+ }
52229
+ function resolveContinuation(payload) {
52230
+ const previousResponse = resolvePreviousResponse(payload.previous_response_id);
52231
+ const conversation = resolveConversation(payload.conversation, previousResponse);
52232
+ return {
52233
+ previousResponse,
52234
+ conversation,
52235
+ continuationSourceResponseId: resolveContinuationSourceResponseId(previousResponse, conversation)
52236
+ };
52237
+ }
52238
+ function resolvePreviousResponse(previousResponseId) {
52239
+ if (typeof previousResponseId !== "string" || previousResponseId.length === 0) return;
52240
+ const previousResponse = responsesEmulatorState.getResponse(previousResponseId);
52241
+ if (!previousResponse) throwInvalidRequestError("The selected previous_response_id could not be resolved.", "previous_response_id");
52242
+ return previousResponse;
52243
+ }
52244
+ function resolveConversation(conversation, previousResponse) {
52245
+ if (isConversationReference(conversation)) {
52246
+ const conversationId = getConversationId(conversation);
52247
+ const existingConversation = responsesEmulatorState.getConversation(conversationId);
52248
+ if (!existingConversation) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
52249
+ if (previousResponse?.conversation && getConversationId(previousResponse.conversation) !== conversationId) throwInvalidRequestError("The selected previous_response_id does not belong to the selected conversation.", "previous_response_id");
52250
+ return existingConversation;
52251
+ }
52252
+ return previousResponse?.conversation ?? void 0;
52253
+ }
52254
+ function resolveContinuationSourceResponseId(previousResponse, conversation) {
52255
+ if (previousResponse) return previousResponse.id;
52256
+ if (!conversation) return;
52257
+ const head = responsesEmulatorState.getConversationHead(getConversationId(conversation));
52258
+ if (!head) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
52259
+ return head;
52260
+ }
52261
+ function buildContinuationHistory(responseId) {
52262
+ const previousResponse = getStoredResponseOrThrow(responseId);
52263
+ const previousInput = responsesEmulatorState.getInputItems(responseId);
52264
+ if (!previousInput) throwInvalidRequestError("The selected previous_response_id is missing stored input items.", "previous_response_id");
52265
+ return [...cloneValue(previousInput), ...convertOutputItemsToInputItems(previousResponse.output)];
52266
+ }
52267
+ function normalizeResponsesInput(input) {
52268
+ if (!input) return [];
52269
+ if (typeof input === "string") return [{
52270
+ type: "message",
52271
+ role: "user",
52272
+ content: input
52273
+ }];
52274
+ if (Array.isArray(input)) return cloneValue(input);
52275
+ return [];
52276
+ }
52277
+ function convertOutputItemsToInputItems(output) {
52278
+ const items = [];
52279
+ for (const item of output) switch (item.type) {
52280
+ case "message":
52281
+ items.push(convertMessageOutputToInput(item));
52282
+ break;
52283
+ case "function_call":
52284
+ items.push(convertFunctionCallOutputToInput(item));
52285
+ break;
52286
+ case "reasoning": {
52287
+ const reasoningInput = convertReasoningOutputToInput(item);
52288
+ if (reasoningInput) items.push(reasoningInput);
52289
+ break;
52290
+ }
52291
+ case "compaction":
52292
+ items.push(convertCompactionOutputToInput(item));
52293
+ break;
52294
+ }
52295
+ return items;
52296
+ }
52297
+ function convertMessageOutputToInput(item) {
52298
+ return {
52299
+ type: "message",
52300
+ role: item.role,
52301
+ status: item.status,
52302
+ content: item.content?.map((content) => {
52303
+ if (content.type === "output_text" && typeof content.text === "string") return {
52304
+ type: "output_text",
52305
+ text: content.text
52306
+ };
52307
+ return cloneValue(content);
52308
+ }) ?? []
52309
+ };
52310
+ }
52311
+ function convertFunctionCallOutputToInput(item) {
52312
+ return {
52313
+ type: "function_call",
52314
+ call_id: item.call_id,
52315
+ name: item.name,
52316
+ arguments: item.arguments,
52317
+ status: item.status
52318
+ };
52319
+ }
52320
+ function convertReasoningOutputToInput(item) {
52321
+ if (!item.encrypted_content) return;
52322
+ return {
52323
+ id: item.id,
52324
+ type: "reasoning",
52325
+ summary: (item.summary ?? []).filter((summary) => typeof summary.text === "string").map((summary) => ({
52326
+ type: "summary_text",
52327
+ text: summary.text
52328
+ })),
52329
+ encrypted_content: item.encrypted_content
52330
+ };
52331
+ }
52332
+ function convertCompactionOutputToInput(item) {
52333
+ return {
52334
+ id: item.id,
52335
+ type: "compaction",
52336
+ encrypted_content: item.encrypted_content
52337
+ };
52338
+ }
52339
+ function normalizeNullableString(value) {
52340
+ return typeof value === "string" ? value : null;
52341
+ }
52342
+ function normalizeServiceTier(value) {
52343
+ if (value === "auto" || value === "default" || value === "flex" || value === "scale" || value === "priority") return value;
52344
+ return null;
52345
+ }
52346
+ function createConversationRef() {
52347
+ return { id: `conv_${randomUUID().replaceAll("-", "")}` };
52348
+ }
52349
+ function isConversationReference(value) {
52350
+ if (typeof value === "string") return value.length > 0;
52351
+ return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string" && value.id.length > 0;
52352
+ }
52353
+ function getConversationId(conversation) {
52354
+ return typeof conversation === "string" ? conversation : conversation.id;
52355
+ }
52356
+ function getInputItemId(item) {
52357
+ if (!item || typeof item !== "object") return;
52358
+ if ("id" in item && typeof item.id === "string") return item.id;
52359
+ if ("call_id" in item && typeof item.call_id === "string") return item.call_id;
52360
+ }
52361
+ //#endregion
52660
52362
  //#region src/routes/responses/strategy.ts
52661
52363
  function isRecord(value) {
52662
52364
  return typeof value === "object" && value !== null;
52663
52365
  }
52664
- function createStreamIdTracker() {
52665
- return { itemIdsByOutputIndex: /* @__PURE__ */ new Map() };
52666
- }
52667
52366
  function fixStreamIds(rawData, eventName, state) {
52668
52367
  if (!rawData) return rawData;
52669
52368
  let parsed;
@@ -52693,7 +52392,7 @@ function fixStreamIds(rawData, eventName, state) {
52693
52392
  return JSON.stringify(parsed);
52694
52393
  }
52695
52394
  function createResponsesPassthroughStrategy(copilotClient, payload, options) {
52696
- const tracker = createStreamIdTracker();
52395
+ const tracker = { itemIdsByOutputIndex: /* @__PURE__ */ new Map() };
52697
52396
  return {
52698
52397
  async execute() {
52699
52398
  try {
@@ -52707,7 +52406,10 @@ function createResponsesPassthroughStrategy(copilotClient, payload, options) {
52707
52406
  return Boolean(payload.stream) && isAsyncIterable(result);
52708
52407
  },
52709
52408
  translateResult(result) {
52710
- return result;
52409
+ const response = result;
52410
+ const mapped = options.mapResponse ? options.mapResponse(response) : response;
52411
+ if (options.mapResponse) options.onTerminalResponse?.(mapped);
52412
+ return mapped;
52711
52413
  },
52712
52414
  translateStreamChunk(chunk) {
52713
52415
  const fixedData = fixStreamIds(chunk.data ?? "", chunk.event, tracker);
@@ -52786,59 +52488,55 @@ responsesStrategyRegistry.register(responsesPassthroughEntry);
52786
52488
  //#region src/routes/responses/handler.ts
52787
52489
  const HTTP_URL_RE = /^https?:\/\//i;
52788
52490
  /**
52789
- * Core handler for responses endpoint.
52491
+ * Core handler for responses endpoint. Orchestrates the standard pipeline
52492
+ * (ingest → transform → dispatch) via runPipeline, with the responses-specific
52493
+ * emulator request prep, tool/input policies, and context management applied
52494
+ * through the afterIngest / afterTransform lifecycle hooks.
52790
52495
  */
52791
52496
  async function handleResponsesCore({ body, signal, headers }) {
52792
- const { payload, meta } = protocolRegistry.ingest("responses", body, headers);
52793
- const requestContext = meta.requestContext;
52794
- const emulatorPrepared = configStore.isEmulatorEnabled() ? prepareEmulatorRequest(payload) : void 0;
52795
- const effectivePayload = emulatorPrepared?.upstreamPayload ?? payload;
52796
- const transformResult = responsesModelChain.apply({
52797
- model: effectivePayload.model,
52798
- payload: effectivePayload,
52497
+ const emulatorMode = configStore.isEmulatorEnabled();
52498
+ let originalPayload;
52499
+ let emulatorPrepared;
52500
+ return await runPipeline({
52501
+ body,
52502
+ signal,
52799
52503
  headers
52800
- });
52801
- effectivePayload.model = transformResult.model;
52802
- applyResponsesToolTransforms(effectivePayload);
52803
- applyResponsesInputPolicies(effectivePayload);
52804
- compactInputByLatestCompaction(effectivePayload);
52805
- const selectedModel = modelCache.findById(effectivePayload.model);
52806
- if (!selectedModel) throwInvalidRequestError("The selected model could not be resolved.", "model");
52807
- if (!modelCache.supportsEndpoint(selectedModel, "/responses")) throwInvalidRequestError("The selected model does not support the responses endpoint.", "model");
52808
- applyContextManagement(effectivePayload, selectedModel.capabilities.limits.max_prompt_tokens);
52809
- const { vision, initiator } = getResponsesRequestOptions(effectivePayload);
52810
- const upstreamSignal = createUpstreamSignalFromConfig(signal);
52811
- const copilotClient = createCopilotClient();
52812
- const decorateResponse = emulatorPrepared ? (response) => decorateStoredResponse(response, payload, emulatorPrepared) : void 0;
52813
- const result = await responsesStrategyRegistry.select(selectedModel).execute({
52814
- copilotClient,
52815
- payload: effectivePayload,
52816
- upstreamSignal,
52817
- requestContext: requestContext ?? {},
52818
- vision,
52819
- initiator,
52820
- decorateResponse,
52821
- onTerminalResponse: emulatorPrepared ? (terminalResponse) => {
52822
- if (!emulatorPrepared?.shouldStore) return;
52823
- persistEmulatorResponse(terminalResponse, emulatorPrepared.effectiveInputItems);
52824
- } : void 0
52825
- });
52826
- if (emulatorPrepared && result.kind === "json") {
52827
- const emulatedResponse = decorateStoredResponse(result.data, payload, emulatorPrepared);
52828
- if (emulatorPrepared.shouldStore) persistEmulatorResponse(emulatedResponse, emulatorPrepared.effectiveInputItems);
52829
- result.data = emulatedResponse;
52830
- }
52831
- return {
52832
- result,
52833
- modelMapping: {
52834
- originalModel: transformResult.trace.length > 0 ? transformResult.trace[0].from : effectivePayload.model,
52835
- steps: transformResult.trace.map((r) => ({
52836
- tag: r.tag,
52837
- from: r.from,
52838
- to: r.to
52839
- }))
52504
+ }, {
52505
+ protocol: "responses",
52506
+ transformChain: responsesModelChain,
52507
+ strategyRegistry: responsesStrategyRegistry,
52508
+ afterIngest({ payload }) {
52509
+ originalPayload = payload;
52510
+ emulatorPrepared = emulatorMode ? prepareEmulatorRequest(payload) : void 0;
52511
+ return emulatorPrepared?.upstreamPayload ?? payload;
52512
+ },
52513
+ afterTransform({ payload, selectedModel }) {
52514
+ applyResponsesToolTransforms(payload);
52515
+ applyResponsesInputPolicies(payload);
52516
+ compactInputByLatestCompaction(payload);
52517
+ if (!selectedModel) throwInvalidRequestError("The selected model could not be resolved.", "model");
52518
+ if (!modelCache.supportsEndpoint(selectedModel, "/responses")) throwInvalidRequestError("The selected model does not support the responses endpoint.", "model");
52519
+ applyContextManagement(payload, selectedModel.capabilities.limits.max_prompt_tokens);
52520
+ },
52521
+ buildStrategyContext({ payload, meta, copilotClient, upstreamSignal }) {
52522
+ const { vision, initiator } = getResponsesRequestOptions(payload);
52523
+ const prepared = emulatorPrepared;
52524
+ const requestPayload = originalPayload ?? payload;
52525
+ return {
52526
+ copilotClient,
52527
+ payload,
52528
+ upstreamSignal,
52529
+ requestContext: meta.requestContext ?? {},
52530
+ vision,
52531
+ initiator,
52532
+ decorateResponse: prepared ? (response) => decorateStoredResponse(response, requestPayload, prepared) : void 0,
52533
+ onTerminalResponse: prepared ? (terminalResponse) => {
52534
+ if (!prepared.shouldStore) return;
52535
+ persistEmulatorResponse(terminalResponse, prepared.effectiveInputItems);
52536
+ } : void 0
52537
+ };
52840
52538
  }
52841
- };
52539
+ });
52842
52540
  }
52843
52541
  function applyResponsesToolTransforms(payload) {
52844
52542
  applyFunctionApplyPatch(payload);
@@ -52944,6 +52642,46 @@ function containsRemoteImageUrl(value) {
52944
52642
  return Object.values(record).some((entry) => containsRemoteImageUrl(entry));
52945
52643
  }
52946
52644
  //#endregion
52645
+ //#region src/routes/responses/resource-dispatcher.ts
52646
+ var EmulatorResourceDispatcher = class {
52647
+ retrieve(responseId) {
52648
+ return Promise.resolve(getStoredResponseOrThrow(responseId));
52649
+ }
52650
+ listInputItems(responseId, params) {
52651
+ return Promise.resolve(listStoredInputItemsOrThrow(responseId, params));
52652
+ }
52653
+ async createInputTokens(payload) {
52654
+ return estimateEmulatorInputTokens(payload, resolveModelOrThrow(payload.model ?? ""));
52655
+ }
52656
+ delete(responseId) {
52657
+ return Promise.resolve(deleteStoredResponseOrThrow(responseId));
52658
+ }
52659
+ };
52660
+ var UpstreamResourceDispatcher = class {
52661
+ client;
52662
+ constructor(client) {
52663
+ this.client = client;
52664
+ }
52665
+ retrieve(responseId, params, options) {
52666
+ return this.client.getResponse(responseId, {
52667
+ params,
52668
+ ...options
52669
+ });
52670
+ }
52671
+ listInputItems(responseId, params, options) {
52672
+ return this.client.getResponseInputItems(responseId, params, options);
52673
+ }
52674
+ createInputTokens(payload, options) {
52675
+ return this.client.createResponseInputTokens(payload, options);
52676
+ }
52677
+ delete(responseId, options) {
52678
+ return this.client.deleteResponse(responseId, options);
52679
+ }
52680
+ };
52681
+ function createResourceDispatcher() {
52682
+ return configStore.isEmulatorEnabled() ? new EmulatorResourceDispatcher() : new UpstreamResourceDispatcher(createCopilotClient());
52683
+ }
52684
+ //#endregion
52947
52685
  //#region src/routes/responses/resource-handler.ts
52948
52686
  async function handleRetrieveResponseCore({ params, url, headers, signal }) {
52949
52687
  const responseId = requireResponseId(params.responseId);
@@ -53312,7 +53050,7 @@ const start = defineCommand({
53312
53050
  },
53313
53051
  "upstream-queue-retries": {
53314
53052
  type: "string",
53315
- description: "Maximum retries for upstream 429 responses (default: 6)"
53053
+ description: "Maximum retries for upstream 429 responses (default: 5)"
53316
53054
  },
53317
53055
  "upstream-queue-base-delay": {
53318
53056
  type: "string",