ghc-proxy 0.6.2 → 0.7.1

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
@@ -5754,6 +5754,11 @@ const configFileSchema = object({
5754
5754
  responsesApiAutoCompactInput: boolean().optional(),
5755
5755
  responsesApiAutoContextManagement: boolean().optional(),
5756
5756
  responsesApiContextManagementModels: array(string()).optional(),
5757
+ responsesApiParameterFilters: array(object({
5758
+ models: array(string()).min(1),
5759
+ params: array(string()).min(1)
5760
+ })).optional(),
5761
+ responsesApiParameterFiltersReplaceDefault: boolean().optional(),
5757
5762
  responsesOfficialEmulator: boolean().optional(),
5758
5763
  responsesOfficialEmulatorTtlSeconds: number().int().positive().optional(),
5759
5764
  modelReasoningEfforts: record(string(), reasoningEffortSchema).optional(),
@@ -5761,12 +5766,6 @@ const configFileSchema = object({
5761
5766
  from: string(),
5762
5767
  to: string()
5763
5768
  })).optional(),
5764
- contextUpgradeRules: array(object({
5765
- from: string(),
5766
- to: string()
5767
- })).optional(),
5768
- contextUpgrade: boolean().optional(),
5769
- contextUpgradeTokenThreshold: number().int().positive().optional(),
5770
5769
  upstreamQueueConcurrency: number().int().positive().optional(),
5771
5770
  upstreamQueueMaxRetries: number().int().nonnegative().optional(),
5772
5771
  upstreamQueueBaseDelaySeconds: number().int().nonnegative().optional(),
@@ -5855,12 +5854,6 @@ var ConfigStore = class {
5855
5854
  getEmulatorTtlSeconds() {
5856
5855
  return getCachedConfig().responsesOfficialEmulatorTtlSeconds ?? 14400;
5857
5856
  }
5858
- isContextUpgradeEnabled() {
5859
- return getCachedConfig().contextUpgrade !== false;
5860
- }
5861
- getContextUpgradeThreshold() {
5862
- return getCachedConfig().contextUpgradeTokenThreshold ?? 16e4;
5863
- }
5864
5857
  isCompactSmallModelEnabled() {
5865
5858
  return getCachedConfig().compactUseSmallModel ?? false;
5866
5859
  }
@@ -5883,36 +5876,233 @@ var ConfigStore = class {
5883
5876
  getReasoningEffort(model) {
5884
5877
  return getCachedConfig().modelReasoningEfforts?.[model] ?? "high";
5885
5878
  }
5879
+ getResponsesParameterFilters() {
5880
+ return getCachedConfig().responsesApiParameterFilters ?? [];
5881
+ }
5882
+ shouldReplaceDefaultParameterFilters() {
5883
+ return getCachedConfig().responsesApiParameterFiltersReplaceDefault ?? false;
5884
+ }
5886
5885
  getModelRewrites() {
5887
5886
  return getCachedConfig().modelRewrites ?? [];
5888
5887
  }
5889
- getContextUpgradeRules() {
5890
- return getCachedConfig().contextUpgradeRules ?? [];
5891
- }
5892
5888
  getModelFallback() {
5893
5889
  return getCachedConfig().modelFallback;
5894
5890
  }
5895
- getUpstreamQueueConcurrency() {
5896
- return getCachedConfig().upstreamQueueConcurrency;
5891
+ };
5892
+ const configStore = new ConfigStore();
5893
+ //#endregion
5894
+ //#region src/state/model-cache.ts
5895
+ const RESPONSES_ENDPOINT = "/responses";
5896
+ /**
5897
+ * Models whose upstream `/v1/messages` endpoint rejects the `output_config`
5898
+ * field with "Extra inputs are not permitted".
5899
+ *
5900
+ * Verified via `scripts/probes/messages/output-config.ts` (2026-03-14).
5901
+ * When new models appear, re-run the probe and update this list.
5902
+ */
5903
+ const MODELS_REJECTING_OUTPUT_CONFIG = new Set([
5904
+ "claude-sonnet-4",
5905
+ "claude-sonnet-4.5",
5906
+ "claude-haiku-4.5"
5907
+ ]);
5908
+ var ModelCache = class {
5909
+ models;
5910
+ vsCodeVersion;
5911
+ cacheModels(models) {
5912
+ this.models = models;
5913
+ }
5914
+ clearModels() {
5915
+ this.models = void 0;
5897
5916
  }
5898
- getUpstreamQueueMaxRetries() {
5899
- return getCachedConfig().upstreamQueueMaxRetries;
5917
+ getModels() {
5918
+ return this.models;
5900
5919
  }
5901
- getUpstreamQueueBaseDelaySeconds() {
5902
- return getCachedConfig().upstreamQueueBaseDelaySeconds;
5920
+ setVSCodeVersion(version) {
5921
+ this.vsCodeVersion = version;
5903
5922
  }
5904
- getUpstreamQueueMaxDelaySeconds() {
5905
- return getCachedConfig().upstreamQueueMaxDelaySeconds;
5923
+ clearVSCodeVersion() {
5924
+ this.vsCodeVersion = void 0;
5925
+ }
5926
+ getVSCodeVersion() {
5927
+ return this.vsCodeVersion;
5928
+ }
5929
+ findById(modelId) {
5930
+ return this.models?.data.find((model) => model.id === modelId);
5931
+ }
5932
+ getModelIds() {
5933
+ return this.models?.data.map((model) => model.id) ?? [];
5934
+ }
5935
+ supportsEndpoint(model, endpoint) {
5936
+ return model?.supported_endpoints?.includes(endpoint) ?? false;
5937
+ }
5938
+ supportsToolCalls(model) {
5939
+ return model?.capabilities.supports.tool_calls ?? false;
5940
+ }
5941
+ supportsAdaptiveThinking(model) {
5942
+ return model?.capabilities.supports.adaptive_thinking ?? false;
5943
+ }
5944
+ supportsVision(model) {
5945
+ return model?.capabilities.supports.vision ?? false;
5946
+ }
5947
+ supportsReasoningEffort(model) {
5948
+ return (model?.capabilities.supports.reasoning_effort?.length ?? 0) > 0;
5949
+ }
5950
+ supportsOutputConfig(model) {
5951
+ if (!model) return true;
5952
+ return !MODELS_REJECTING_OUTPUT_CONFIG.has(model.id);
5953
+ }
5954
+ };
5955
+ const modelCache = new ModelCache();
5956
+ //#endregion
5957
+ //#region src/translator/anthropic/translation-issue.ts
5958
+ var TranslationFailure = class extends Error {
5959
+ status;
5960
+ kind;
5961
+ constructor(message, options) {
5962
+ super(message);
5963
+ this.name = "TranslationFailure";
5964
+ this.status = options.status;
5965
+ this.kind = options.kind;
5906
5966
  }
5907
5967
  };
5908
- const configStore = new ConfigStore();
5909
5968
  //#endregion
5910
- //#region src/lib/responses-emulator-state.ts
5969
+ //#region src/lib/error.ts
5970
+ var HTTPError = class extends Error {
5971
+ status;
5972
+ body;
5973
+ constructor(status, body) {
5974
+ super(body.error.message);
5975
+ this.name = "HTTPError";
5976
+ this.status = status;
5977
+ this.body = body;
5978
+ }
5979
+ toResponse() {
5980
+ return Response.json(this.body, { status: this.status });
5981
+ }
5982
+ };
5983
+ function throwInvalidRequestError(message, param, code) {
5984
+ throw new HTTPError(400, { error: {
5985
+ message,
5986
+ type: "invalid_request_error",
5987
+ param,
5988
+ ...code ? { code } : {}
5989
+ } });
5990
+ }
5991
+ function fromTranslationFailure(failure) {
5992
+ return new HTTPError(failure.status, { error: {
5993
+ message: failure.message,
5994
+ type: "translation_error"
5995
+ } });
5996
+ }
5997
+ function resolveModelOrThrow(modelId) {
5998
+ const model = modelCache.findById(modelId);
5999
+ if (!model) throwInvalidRequestError("The selected model could not be resolved.", "model");
6000
+ return model;
6001
+ }
6002
+ function withTranslationErrors(fn) {
6003
+ try {
6004
+ return fn();
6005
+ } catch (error) {
6006
+ if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
6007
+ throw error;
6008
+ }
6009
+ }
6010
+ function previewBody(text, maxLength = 500) {
6011
+ return text.length > maxLength ? `${text.slice(0, maxLength)}…` : text;
6012
+ }
6013
+ function isStructuredErrorPayload(value) {
6014
+ return typeof value === "object" && value !== null && "error" in value && typeof value.error === "object" && value.error !== null;
6015
+ }
6016
+ function upstreamErrorType(status) {
6017
+ return status === 429 ? "rate_limit_error" : "upstream_error";
6018
+ }
6019
+ function createFallbackUpstreamError(message, response, rawText) {
6020
+ return { error: {
6021
+ message: rawText.trim() || message,
6022
+ type: upstreamErrorType(response.status)
6023
+ } };
6024
+ }
6025
+ function getDiagnosticHeaders(response) {
6026
+ const headerNames = [
6027
+ "retry-after",
6028
+ "x-ratelimit-limit",
6029
+ "x-ratelimit-remaining",
6030
+ "x-ratelimit-reset",
6031
+ "x-github-request-id",
6032
+ "x-request-id"
6033
+ ];
6034
+ const headers = {};
6035
+ for (const name of headerNames) {
6036
+ const value = response.headers.get(name);
6037
+ if (value) headers[name] = value;
6038
+ }
6039
+ return Object.keys(headers).length > 0 ? headers : void 0;
6040
+ }
6041
+ async function throwUpstreamError(message, response) {
6042
+ let rawText = "";
6043
+ let body;
6044
+ try {
6045
+ rawText = await response.text();
6046
+ const json = JSON.parse(rawText);
6047
+ body = isStructuredErrorPayload(json) ? json : createFallbackUpstreamError(message, response, rawText);
6048
+ } catch {
6049
+ body = createFallbackUpstreamError(message, response, rawText);
6050
+ }
6051
+ consola.error("Upstream error:", {
6052
+ status: response.status,
6053
+ statusText: response.statusText,
6054
+ url: response.url,
6055
+ body,
6056
+ rawBody: rawText ? previewBody(rawText) : "<empty>",
6057
+ headers: getDiagnosticHeaders(response)
6058
+ });
6059
+ throw new HTTPError(response.status, body);
6060
+ }
6061
+ //#endregion
6062
+ //#region src/util/sleep.ts
6063
+ function sleep(ms) {
6064
+ return new Promise((resolve) => {
6065
+ setTimeout(resolve, ms);
6066
+ });
6067
+ }
6068
+ //#endregion
6069
+ //#region src/state/rate-limiter.ts
6070
+ var RateLimiter = class {
6071
+ nextAvailableAt = 0;
6072
+ reset() {
6073
+ this.nextAvailableAt = 0;
6074
+ }
6075
+ async acquire(intervalSeconds, waitMode) {
6076
+ if (intervalSeconds === void 0) return;
6077
+ const now = Date.now();
6078
+ const intervalMs = intervalSeconds * 1e3;
6079
+ if (!this.nextAvailableAt || now >= this.nextAvailableAt) {
6080
+ this.nextAvailableAt = now + intervalMs;
6081
+ return;
6082
+ }
6083
+ const waitMs = this.nextAvailableAt - now;
6084
+ const waitTimeSeconds = Math.ceil(waitMs / 1e3);
6085
+ if (!waitMode) {
6086
+ consola.warn(`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`);
6087
+ throw new HTTPError(429, { error: {
6088
+ message: "Rate limit exceeded",
6089
+ type: "rate_limit_error"
6090
+ } });
6091
+ }
6092
+ const claimedSlot = this.nextAvailableAt;
6093
+ this.nextAvailableAt = claimedSlot + intervalMs;
6094
+ consola.warn(`Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`);
6095
+ await sleep(waitMs);
6096
+ consola.info("Rate limit wait completed, proceeding with request");
6097
+ }
6098
+ };
6099
+ const rateLimiter = new RateLimiter();
6100
+ //#endregion
6101
+ //#region src/state/responses-emulator-state.ts
5911
6102
  const DEFAULT_MAX_TOTAL_ENTRIES = 1e4;
5912
6103
  const BACKGROUND_PRUNE_INTERVAL_MS = 6e4;
5913
6104
  function cloneValue$1(value) {
5914
- if (typeof globalThis.structuredClone === "function") return globalThis.structuredClone(value);
5915
- return JSON.parse(JSON.stringify(value));
6105
+ return structuredClone(value);
5916
6106
  }
5917
6107
  function currentTime() {
5918
6108
  return Date.now();
@@ -5958,7 +6148,6 @@ function createResponsesEmulatorState(opts) {
5958
6148
  pruneIntervalId = void 0;
5959
6149
  }
5960
6150
  }
5961
- startBackgroundPrune();
5962
6151
  function totalEntries() {
5963
6152
  let sum = 0;
5964
6153
  for (const map of allMaps) sum += map.size;
@@ -5977,6 +6166,7 @@ function createResponsesEmulatorState(opts) {
5977
6166
  return cloneValue$1(entry.value);
5978
6167
  }
5979
6168
  function writeMap(map, key, value, ttlSeconds, at = currentTime()) {
6169
+ startBackgroundPrune();
5980
6170
  if (!map.has(key)) enforceCapOnWrite();
5981
6171
  const cloned = cloneValue$1(value);
5982
6172
  map.set(key, {
@@ -5989,6 +6179,7 @@ function createResponsesEmulatorState(opts) {
5989
6179
  return map.delete(key);
5990
6180
  }
5991
6181
  function putDeletionFlag(map, id, ttlSeconds, at = currentTime()) {
6182
+ startBackgroundPrune();
5992
6183
  if (!map.has(id)) enforceCapOnWrite();
5993
6184
  const flag = {
5994
6185
  deleted: true,
@@ -6136,9 +6327,6 @@ function createResponsesEmulatorState(opts) {
6136
6327
  getConversationHead(conversationId) {
6137
6328
  return readMap(conversationHeadRecords, conversationId);
6138
6329
  },
6139
- clearConversationHead(conversationId) {
6140
- deleteMapEntry(conversationHeadRecords, conversationId);
6141
- },
6142
6330
  setInputItems(responseId, inputItems, options) {
6143
6331
  removeDeletionFlag(inputItemDeletionFlags, responseId);
6144
6332
  return writeMap(inputItemRecords, responseId, inputItems, options?.ttlSeconds);
@@ -6157,329 +6345,19 @@ function createResponsesEmulatorState(opts) {
6157
6345
  deleted: true
6158
6346
  };
6159
6347
  },
6160
- setDeletionFlag(kind, id, options) {
6161
- return putDeletionFlag(deletionMap(kind), id, options?.ttlSeconds);
6162
- },
6163
6348
  getDeletionFlag(kind, id) {
6164
6349
  return readDeletionFlag(deletionMap(kind), id);
6165
- },
6166
- clearDeletionFlag(kind, id) {
6167
- removeDeletionFlag(deletionMap(kind), id);
6168
6350
  }
6169
6351
  };
6170
6352
  }
6171
6353
  const responsesEmulatorState = createResponsesEmulatorState();
6172
6354
  //#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
6355
  //#region src/state/runtime.ts
6381
6356
  var RuntimeStore = class {
6382
6357
  dumpFailedPayloads = false;
6383
6358
  };
6384
6359
  const runtimeStore = new RuntimeStore();
6385
6360
  //#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
6361
  //#region node_modules/fetch-event-stream/esm/deps/jsr.io/@std/streams/0.221.0/text_line_stream.js
6484
6362
  /**
6485
6363
  * Transform a stream into a stream where each chunk is divided by a newline,
@@ -6602,6 +6480,64 @@ async function* events(res, signal) {
6602
6480
  }
6603
6481
  }
6604
6482
  //#endregion
6483
+ //#region src/clients/api-config.ts
6484
+ function standardHeaders() {
6485
+ return {
6486
+ "content-type": "application/json",
6487
+ "accept": "application/json"
6488
+ };
6489
+ }
6490
+ const COPILOT_VERSION = "0.26.7";
6491
+ const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
6492
+ const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
6493
+ const API_VERSION = "2025-04-01";
6494
+ const TRAILING_SLASHES_RE$1 = /\/+$/;
6495
+ /** Headers shared by both Copilot and GitHub API requests (editor identity + versioning) */
6496
+ function editorHeaders(config) {
6497
+ return {
6498
+ "editor-version": `vscode/${config.vsCodeVersion ?? "unknown"}`,
6499
+ "editor-plugin-version": EDITOR_PLUGIN_VERSION,
6500
+ "user-agent": USER_AGENT,
6501
+ "x-github-api-version": API_VERSION,
6502
+ "x-vscode-user-agent-library-version": "electron-fetch"
6503
+ };
6504
+ }
6505
+ function copilotBaseUrl(config) {
6506
+ if (config.copilotApiBase) return config.copilotApiBase.replace(TRAILING_SLASHES_RE$1, "");
6507
+ return config.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${config.accountType}.githubcopilot.com`;
6508
+ }
6509
+ function copilotHeaders(auth, config, options = {}) {
6510
+ const requestContext = options.requestContext;
6511
+ const headers = {
6512
+ "Authorization": `Bearer ${auth.copilotToken}`,
6513
+ "content-type": standardHeaders()["content-type"],
6514
+ "copilot-integration-id": "vscode-chat",
6515
+ ...editorHeaders(config),
6516
+ "openai-intent": "conversation-panel",
6517
+ "x-request-id": randomUUID()
6518
+ };
6519
+ if (options.vision) headers["copilot-vision-request"] = "true";
6520
+ if (options.initiator) headers["X-Initiator"] = options.initiator;
6521
+ if (requestContext?.interactionType) headers["X-Interaction-Type"] = requestContext.interactionType;
6522
+ if (requestContext?.agentTaskId) headers["X-Agent-Task-Id"] = requestContext.agentTaskId;
6523
+ if (requestContext?.parentAgentTaskId) headers["X-Parent-Agent-Id"] = requestContext.parentAgentTaskId;
6524
+ if (requestContext?.clientSessionId) headers["X-Client-Session-Id"] = requestContext.clientSessionId;
6525
+ if (requestContext?.interactionId) headers["X-Interaction-Id"] = requestContext.interactionId;
6526
+ if (requestContext?.clientMachineId) headers["X-Client-Machine-Id"] = requestContext.clientMachineId;
6527
+ return headers;
6528
+ }
6529
+ const GITHUB_API_BASE_URL = "https://api.github.com";
6530
+ function githubHeaders(auth, config) {
6531
+ return {
6532
+ ...standardHeaders(),
6533
+ authorization: `token ${auth.githubToken}`,
6534
+ ...editorHeaders(config)
6535
+ };
6536
+ }
6537
+ const GITHUB_BASE_URL = "https://github.com";
6538
+ const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
6539
+ const GITHUB_APP_SCOPES = ["read:user"].join(" ");
6540
+ //#endregion
6605
6541
  //#region src/clients/copilot-client.ts
6606
6542
  var CopilotClient = class {
6607
6543
  auth;
@@ -6930,7 +6866,55 @@ async function getVSCodeVersion() {
6930
6866
  return remoteVersion ?? localVersion ?? FALLBACK;
6931
6867
  }
6932
6868
  //#endregion
6933
- //#region src/lib/upstream-request-queue.ts
6869
+ //#region src/clients/ghe-domain.ts
6870
+ const GHE_SUFFIX = ".ghe.com";
6871
+ /**
6872
+ * Normalize a GHE domain input to a lowercase bare domain.
6873
+ *
6874
+ * Accepted inputs: `company.ghe.com`, `https://company.ghe.com`,
6875
+ * `https://Company.GHE.com/`, etc.
6876
+ *
6877
+ * @returns Bare lowercase domain, e.g. `company.ghe.com`
6878
+ * @throws {Error} If the input is empty or does not end with `.ghe.com`
6879
+ */
6880
+ function normalizeGheDomain(input) {
6881
+ const trimmed = input.trim();
6882
+ if (!trimmed) throw new Error("GHE domain must not be empty");
6883
+ let domain;
6884
+ try {
6885
+ domain = (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname.toLowerCase();
6886
+ } catch {
6887
+ throw new Error(`Invalid GHE domain: ${trimmed}`);
6888
+ }
6889
+ if (!domain.endsWith(GHE_SUFFIX) || domain === GHE_SUFFIX.slice(1)) throw new Error(`GHE domain must end with ${GHE_SUFFIX} (got "${domain}")`);
6890
+ return domain;
6891
+ }
6892
+ /**
6893
+ * Build GitHub base URL and API base URL for a given GHE domain,
6894
+ * or return the public GitHub defaults when no domain is provided.
6895
+ */
6896
+ function buildGitHubUrls(gheDomain) {
6897
+ if (!gheDomain) return {
6898
+ baseUrl: GITHUB_BASE_URL,
6899
+ apiBaseUrl: GITHUB_API_BASE_URL
6900
+ };
6901
+ const domain = normalizeGheDomain(gheDomain);
6902
+ return {
6903
+ baseUrl: `https://${domain}`,
6904
+ apiBaseUrl: `https://api.${domain}`
6905
+ };
6906
+ }
6907
+ //#endregion
6908
+ //#region src/util/duration.ts
6909
+ /**
6910
+ * Formats a millisecond duration as a compact human-readable string:
6911
+ * `<n>ms` under one second, otherwise `<n>s` rounded to whole seconds.
6912
+ */
6913
+ function formatDurationMs(ms) {
6914
+ return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
6915
+ }
6916
+ //#endregion
6917
+ //#region src/clients/upstream-queue.ts
6934
6918
  const DEFAULT_UPSTREAM_QUEUE_OPTIONS = {
6935
6919
  concurrency: 10,
6936
6920
  maxRetries: 5,
@@ -6987,7 +6971,7 @@ var UpstreamRequestQueue = class {
6987
6971
  this.logger.warn([
6988
6972
  "Upstream rate limited;",
6989
6973
  `retrying ${formatRequestContext(context)}`,
6990
- `in ${formatDelay(delayMs)}`,
6974
+ `in ${formatDurationMs(delayMs)}`,
6991
6975
  `(attempt ${attempt + 1}/${this.options.maxRetries})`
6992
6976
  ].join(" "));
6993
6977
  await abortableSleep(this.sleep, delayMs, signal);
@@ -7097,9 +7081,6 @@ function formatRequestContext(context) {
7097
7081
  return `${context.method ?? "GET"} ${context.url}`;
7098
7082
  }
7099
7083
  }
7100
- function formatDelay(delayMs) {
7101
- return delayMs < 1e3 ? `${delayMs}ms` : `${Math.round(delayMs / 1e3)}s`;
7102
- }
7103
7084
  function abortableSleep(sleep, ms, signal) {
7104
7085
  if (!signal) return sleep(ms);
7105
7086
  signal.throwIfAborted();
@@ -7118,7 +7099,7 @@ function abortableSleep(sleep, ms, signal) {
7118
7099
  });
7119
7100
  }
7120
7101
  //#endregion
7121
- //#region src/lib/state.ts
7102
+ //#region src/clients/factory.ts
7122
7103
  const upstreamRequestQueue = createDefaultUpstreamRequestQueue();
7123
7104
  function configureUpstreamRequestQueue(options) {
7124
7105
  upstreamRequestQueue.updateOptions(options);
@@ -7363,11 +7344,6 @@ const checkUsage = defineCommand({
7363
7344
  await setupGitHubToken();
7364
7345
  try {
7365
7346
  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
7347
  function summarizeQuota(name, snap) {
7372
7348
  if (!snap) return `${name}: N/A`;
7373
7349
  const total = snap.entitlement;
@@ -7376,7 +7352,7 @@ const checkUsage = defineCommand({
7376
7352
  const percentRemaining = snap.percent_remaining;
7377
7353
  return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
7378
7354
  }
7379
- const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
7355
+ const premiumLine = summarizeQuota("Premium", usage.quota_snapshots.premium_interactions);
7380
7356
  const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
7381
7357
  const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
7382
7358
  consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
@@ -7387,8 +7363,8 @@ const checkUsage = defineCommand({
7387
7363
  }
7388
7364
  });
7389
7365
  //#endregion
7390
- //#region src/lib/version.ts
7391
- const VERSION = "0.6.2";
7366
+ //#region src/util/version.ts
7367
+ const VERSION = "0.7.1";
7392
7368
  //#endregion
7393
7369
  //#region src/debug.ts
7394
7370
  function getRuntimeInfo() {
@@ -7656,59 +7632,6 @@ async function getTokenCount(payload, model) {
7656
7632
  async function estimateResponsesInputTokens(inputItems, model) {
7657
7633
  return (await getEncoder(getTokenizerFromModel(model))).encode(JSON.stringify(inputItems)).length;
7658
7634
  }
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
7635
  //#endregion
7713
7636
  //#region src/selfcheck.ts
7714
7637
  const PROBE_ENCODINGS = [
@@ -29208,7 +29131,7 @@ var require_eventsource = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
29208
29131
  };
29209
29132
  }));
29210
29133
  //#endregion
29211
- //#region src/lib/proxy.ts
29134
+ //#region src/cli/proxy.ts
29212
29135
  var import_undici = (/* @__PURE__ */ __commonJSMin$1(((exports, module) => {
29213
29136
  const Client = require_client();
29214
29137
  const Dispatcher = require_dispatcher();
@@ -29419,7 +29342,7 @@ function initProxyFromEnv() {
29419
29342
  }
29420
29343
  }
29421
29344
  //#endregion
29422
- //#region src/lib/shell.ts
29345
+ //#region src/cli/shell.ts
29423
29346
  const EXE_EXTENSION_RE = /\.exe$/i;
29424
29347
  function normalizeShellName(raw) {
29425
29348
  if (!raw) return;
@@ -29508,7 +29431,7 @@ function generateEnvScript(envVars, commandToRun = "") {
29508
29431
  //#endregion
29509
29432
  //#region src/lib/model-resolver.ts
29510
29433
  const DEFAULT_FALLBACKS = {
29511
- claudeOpus: "claude-opus-4.6",
29434
+ claudeOpus: "claude-opus-4.8",
29512
29435
  claudeSonnet: "claude-sonnet-4.6",
29513
29436
  claudeHaiku: "claude-haiku-4.5"
29514
29437
  };
@@ -29528,7 +29451,7 @@ function resolveModel(modelId, knownModelIds, config) {
29528
29451
  return modelId;
29529
29452
  }
29530
29453
  //#endregion
29531
- //#region src/lib/startup-banner.ts
29454
+ //#region src/cli/startup-banner.ts
29532
29455
  function printStartupBanner(serverUrl) {
29533
29456
  const lines = [];
29534
29457
  lines.push(`ghc-proxy v${VERSION}`);
@@ -47817,8 +47740,7 @@ function getRequestModelMapping(request) {
47817
47740
  return requestModelMapping.get(request);
47818
47741
  }
47819
47742
  function formatElapsed(start) {
47820
- const delta = Date.now() - start;
47821
- return delta < 1e3 ? `${delta}ms` : `${Math.round(delta / 1e3)}s`;
47743
+ return formatDurationMs(Date.now() - start);
47822
47744
  }
47823
47745
  function formatPath(rawUrl) {
47824
47746
  try {
@@ -47849,8 +47771,8 @@ function getEffectiveModel(info) {
47849
47771
  }
47850
47772
  /**
47851
47773
  * 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.
47774
+ * Strategy contexts hold a reference to the same `modelMapping`,
47775
+ * so steps are pushed directly rather than returning a new object.
47854
47776
  */
47855
47777
  function appendModelStepInPlace(info, tag, newModel) {
47856
47778
  const current = getEffectiveModel(info);
@@ -47893,6 +47815,16 @@ function logRequest(method, url, status, elapsed, modelInfo, requestId) {
47893
47815
  //#endregion
47894
47816
  //#region src/lib/sse-adapter.ts
47895
47817
  /**
47818
+ * Serializes Anthropic stream events into SSE output items
47819
+ * (one `{ event, data }` per event, with `data` as the JSON-encoded event).
47820
+ */
47821
+ function serializeAnthropicSSE(events) {
47822
+ return events.map((event) => ({
47823
+ event: event.type,
47824
+ data: JSON.stringify(event)
47825
+ }));
47826
+ }
47827
+ /**
47896
47828
  * Bridges an AsyncGenerator<SSEOutput> to Elysia's SSE response format.
47897
47829
  * Returns an async generator that yields sse() calls for each SSE output item.
47898
47830
  */
@@ -47906,7 +47838,7 @@ async function* sseAdapter(generator) {
47906
47838
  //#endregion
47907
47839
  //#region src/deliver/index.ts
47908
47840
  function deliverResult(request, result, modelMapping) {
47909
- if (modelMapping) setRequestModelMapping(request, modelMapping);
47841
+ setRequestModelMapping(request, modelMapping);
47910
47842
  if (result.kind === "json") return {
47911
47843
  streaming: false,
47912
47844
  data: result.data
@@ -47929,7 +47861,7 @@ function hasStreamingResponsesQuery(request) {
47929
47861
  return new URL(request.url).searchParams.get("stream") === "true";
47930
47862
  }
47931
47863
  //#endregion
47932
- //#region src/lib/approval.ts
47864
+ //#region src/guard/approval.ts
47933
47865
  async function awaitApproval() {
47934
47866
  if (!await consola.prompt(`Accept incoming request?`, { type: "confirm" })) throw new HTTPError(403, { error: {
47935
47867
  message: "Request rejected",
@@ -47937,7 +47869,7 @@ async function awaitApproval() {
47937
47869
  } });
47938
47870
  }
47939
47871
  //#endregion
47940
- //#region src/guard/auth.ts
47872
+ //#region src/guard/gate.ts
47941
47873
  async function runGuard() {
47942
47874
  await rateLimiter.acquire(authStore.rateLimitSeconds, authStore.rateLimitWait);
47943
47875
  if (authStore.manualApprove) await awaitApproval();
@@ -47949,118 +47881,7 @@ const requestGuardPlugin = new Elysia({ name: "request-guard" }).macro({ guarded
47949
47881
  await runGuard();
47950
47882
  } }) });
47951
47883
  //#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
47884
+ //#region src/util/assert-never.ts
48064
47885
  /**
48065
47886
  * Compile-time exhaustiveness check for switch/if-else chains on
48066
47887
  * discriminated unions. At runtime, throws with a descriptive message.
@@ -48111,54 +47932,20 @@ function selectCapiProfile(model) {
48111
47932
  return inferModelFamily(model) === "claude" ? claudeProfile : baseProfile;
48112
47933
  }
48113
47934
  //#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>";
47935
+ //#region src/core/capi/headers.ts
47936
+ /**
47937
+ * Leaf helper for reading optional request headers. Lives in its own module so
47938
+ * both request-context.ts and subagent-marker.ts can depend on it without
47939
+ * importing each other (which would form a cycle).
47940
+ */
48118
47941
  function readHeader(headers, name) {
48119
47942
  return headers.get(name) ?? void 0;
48120
47943
  }
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
- }
47944
+ //#endregion
47945
+ //#region src/core/capi/subagent-marker.ts
47946
+ const SUBAGENT_MARKER_PREFIX = "__SUBAGENT_MARKER__";
47947
+ const SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
47948
+ const SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
48162
47949
  function withSubagentMarker(baseContext, headers, marker) {
48163
47950
  if (!marker) return baseContext;
48164
47951
  const rootSessionId = readHeader(headers, "x-session-id") ?? baseContext.clientSessionId;
@@ -48433,6 +48220,49 @@ function findJsonObjectEnd(text, start) {
48433
48220
  return -1;
48434
48221
  }
48435
48222
  //#endregion
48223
+ //#region src/core/capi/request-context.ts
48224
+ function inferInitiator(turns) {
48225
+ return turns.some((turn) => turn.role === "assistant" || turn.role === "tool") ? "agent" : "user";
48226
+ }
48227
+ function readCapiRequestContext(headers) {
48228
+ return {
48229
+ interactionType: readHeader(headers, "x-interaction-type"),
48230
+ agentTaskId: readHeader(headers, "x-agent-task-id"),
48231
+ parentAgentTaskId: readHeader(headers, "x-parent-agent-id"),
48232
+ clientSessionId: readHeader(headers, "x-client-session-id") ?? readHeader(headers, "x-session-id"),
48233
+ interactionId: readHeader(headers, "x-interaction-id"),
48234
+ clientMachineId: readHeader(headers, "x-client-machine-id")
48235
+ };
48236
+ }
48237
+ function resolveInitiator(defaultInitiator, requestContext) {
48238
+ switch (requestContext?.interactionType) {
48239
+ case "conversation-agent":
48240
+ case "conversation-subagent":
48241
+ case "conversation-background": return "agent";
48242
+ case "conversation-user": return "user";
48243
+ default: return defaultInitiator;
48244
+ }
48245
+ }
48246
+ function buildCapiRequestContext(initiator, overrides = {}) {
48247
+ return {
48248
+ interactionType: overrides.interactionType ?? (initiator === "agent" ? "conversation-agent" : "conversation-user"),
48249
+ agentTaskId: overrides.agentTaskId,
48250
+ parentAgentTaskId: overrides.parentAgentTaskId,
48251
+ clientSessionId: overrides.clientSessionId,
48252
+ interactionId: overrides.interactionId ?? randomUUID(),
48253
+ clientMachineId: overrides.clientMachineId
48254
+ };
48255
+ }
48256
+ function normalizeAnthropicRequestContext(payload, headers) {
48257
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromAnthropicPayload(payload));
48258
+ }
48259
+ function normalizeChatRequestContext(payload, headers) {
48260
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromChatPayload(payload));
48261
+ }
48262
+ function normalizeResponsesRequestContext(payload, headers) {
48263
+ return withSubagentMarker(readCapiRequestContext(headers), headers, stripSubagentMarkerFromResponsesPayload(payload));
48264
+ }
48265
+ //#endregion
48436
48266
  //#region src/core/capi/plan-builder.ts
48437
48267
  const EPHEMERAL_CACHE_CONTROL = { type: "ephemeral" };
48438
48268
  function asContentPart(block) {
@@ -48636,7 +48466,7 @@ function buildCapiExecutionPlan(request, options = {}) {
48636
48466
  };
48637
48467
  }
48638
48468
  //#endregion
48639
- //#region src/lib/validation/shared.ts
48469
+ //#region src/ingest/validation/shared.ts
48640
48470
  const jsonObjectSchema = object({}).catchall(unknown());
48641
48471
  const finiteNumberSchema = number().finite();
48642
48472
  const nonNegativeIntegerSchema = number().int().nonnegative();
@@ -48733,7 +48563,7 @@ function parsePayload(schema, context, payload) {
48733
48563
  return result.data;
48734
48564
  }
48735
48565
  //#endregion
48736
- //#region src/lib/validation/anthropic-messages.ts
48566
+ //#region src/ingest/validation/anthropic-messages.ts
48737
48567
  const anthropicTextBlockSchema = object({
48738
48568
  type: literal("text"),
48739
48569
  text: string()
@@ -48923,7 +48753,7 @@ function parseAnthropicCountTokensPayload(payload) {
48923
48753
  return parsePayload(anthropicCountTokensPayloadSchema, "anthropic.messages.count_tokens", payload);
48924
48754
  }
48925
48755
  //#endregion
48926
- //#region src/lib/validation/embeddings.ts
48756
+ //#region src/ingest/validation/embeddings.ts
48927
48757
  const embeddingRequestSchema = object({
48928
48758
  input: union([string(), array(string())]),
48929
48759
  model: string().min(1),
@@ -48943,7 +48773,7 @@ const REASONING_EFFORT_VALUES = [
48943
48773
  "high"
48944
48774
  ];
48945
48775
  //#endregion
48946
- //#region src/lib/validation/openai-chat.ts
48776
+ //#region src/ingest/validation/openai-chat.ts
48947
48777
  const openAIPenaltySchema = finiteNumberSchema.min(-2).max(2);
48948
48778
  const openAILogitBiasKeySchema = string().regex(/^\d+$/);
48949
48779
  const openAILogitBiasValueSchema = finiteNumberSchema.min(-100).max(100);
@@ -49052,53 +48882,77 @@ const openAIChatPayloadSchema = object({
49052
48882
  function parseOpenAIChatPayload(payload) {
49053
48883
  return parsePayload(openAIChatPayloadSchema, "openai.chat", payload);
49054
48884
  }
48885
+ //#endregion
48886
+ //#region src/ingest/validation/responses.ts
48887
+ const responsesInputTextSchema = object({
48888
+ type: _enum(["input_text", "output_text"]),
48889
+ text: string()
48890
+ }).loose();
48891
+ const responsesInputImageSchema = object({
48892
+ type: literal("input_image"),
48893
+ image_url: string().nullable().optional(),
48894
+ file_id: string().nullable().optional(),
48895
+ detail: _enum([
48896
+ "low",
48897
+ "high",
48898
+ "auto",
48899
+ "original"
48900
+ ]).optional()
48901
+ }).loose().superRefine((item, ctx) => {
48902
+ if (!item.image_url && !item.file_id) ctx.addIssue({
48903
+ code: "custom",
48904
+ message: "input_image requires image_url or file_id"
48905
+ });
48906
+ });
48907
+ const responsesFunctionCallOutputImageSchema = object({
48908
+ type: literal("input_image"),
48909
+ image_url: string().nullable().optional(),
48910
+ file_id: string().nullable().optional(),
48911
+ detail: _enum([
48912
+ "low",
48913
+ "high",
48914
+ "auto",
48915
+ "original"
48916
+ ]).optional()
48917
+ }).loose();
48918
+ const responsesInputFileSchema = object({
48919
+ type: literal("input_file"),
48920
+ file_id: string().nullable().optional(),
48921
+ file_url: string().nullable().optional(),
48922
+ file_data: string().nullable().optional(),
48923
+ filename: string().nullable().optional()
48924
+ }).loose().superRefine((item, ctx) => {
48925
+ if (!item.file_id && !item.file_url && !item.file_data) ctx.addIssue({
48926
+ code: "custom",
48927
+ message: "input_file requires file_id, file_url, or file_data"
48928
+ });
48929
+ if (item.file_data && !item.filename) ctx.addIssue({
48930
+ code: "custom",
48931
+ message: "input_file with file_data requires filename"
48932
+ });
48933
+ });
48934
+ const responsesUnknownContentSchema = object({ type: string().min(1) }).catchall(unknown()).superRefine((item, ctx) => {
48935
+ if ([
48936
+ "input_text",
48937
+ "output_text",
48938
+ "input_image",
48939
+ "input_file"
48940
+ ].includes(item.type)) ctx.addIssue({
48941
+ code: "custom",
48942
+ message: `content item type ${item.type} must match the explicit schema`
48943
+ });
48944
+ });
49055
48945
  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
- })
48946
+ responsesInputTextSchema,
48947
+ responsesInputImageSchema,
48948
+ responsesInputFileSchema,
48949
+ responsesUnknownContentSchema
48950
+ ]);
48951
+ const responsesFunctionCallOutputContentSchema = union([
48952
+ responsesInputTextSchema,
48953
+ responsesFunctionCallOutputImageSchema,
48954
+ responsesInputFileSchema,
48955
+ responsesUnknownContentSchema
49102
48956
  ]);
49103
48957
  const responsesMessageSchema = object({
49104
48958
  type: literal("message").optional(),
@@ -49126,7 +48980,7 @@ const responsesFunctionCallSchema = object({
49126
48980
  const responsesFunctionCallOutputSchema = object({
49127
48981
  type: literal("function_call_output"),
49128
48982
  call_id: string().min(1),
49129
- output: union([string(), array(responsesInputContentSchema)]),
48983
+ output: union([string(), array(responsesFunctionCallOutputContentSchema)]),
49130
48984
  status: _enum([
49131
48985
  "in_progress",
49132
48986
  "completed",
@@ -49464,16 +49318,16 @@ function createUpstreamSignalFromConfig(clientSignal) {
49464
49318
  //#endregion
49465
49319
  //#region src/pipeline/runner.ts
49466
49320
  async function runPipeline(params, config) {
49467
- const { payload, meta } = protocolRegistry.ingest(config.protocol, params.body, params.headers);
49468
- config.afterIngest?.({
49469
- payload,
49321
+ const ingested = protocolRegistry.ingest(config.protocol, params.body, params.headers);
49322
+ const meta = ingested.meta;
49323
+ const payload = config.afterIngest ? config.afterIngest({
49324
+ payload: ingested.payload,
49470
49325
  meta,
49471
49326
  headers: params.headers
49472
- });
49327
+ }) : ingested.payload;
49473
49328
  const transformResult = config.transformChain.apply({
49474
49329
  model: payload.model,
49475
49330
  payload,
49476
- headers: params.headers,
49477
49331
  meta: { betaHeaders: meta.betaHeaders }
49478
49332
  });
49479
49333
  payload.model = transformResult.model;
@@ -49495,7 +49349,7 @@ async function runPipeline(params, config) {
49495
49349
  });
49496
49350
  const upstreamSignal = createUpstreamSignalFromConfig(params.signal);
49497
49351
  const copilotClient = createCopilotClient();
49498
- const buildCtx = () => config.buildStrategyContext({
49352
+ const ctx = config.buildStrategyContext({
49499
49353
  payload,
49500
49354
  meta,
49501
49355
  headers: params.headers,
@@ -49504,93 +49358,12 @@ async function runPipeline(params, config) {
49504
49358
  upstreamSignal,
49505
49359
  modelMapping
49506
49360
  });
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
49361
  return {
49543
49362
  result: await config.strategyRegistry.select(selectedModel, ctx).execute(ctx),
49544
49363
  modelMapping
49545
49364
  };
49546
49365
  }
49547
49366
  //#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
49367
  //#region src/transform/chain.ts
49595
49368
  function composeModelTransforms(...steps) {
49596
49369
  return { apply(input) {
@@ -49626,18 +49399,10 @@ function composeModelTransforms(...steps) {
49626
49399
  } };
49627
49400
  }
49628
49401
  //#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
- }
49402
+ //#region src/transform/constants.ts
49403
+ const CONTEXT_BETA_RE = /^context-\d+[km]-/;
49639
49404
  //#endregion
49640
- //#region src/lib/request-model-policy.ts
49405
+ //#region src/transform/request-model-policy.ts
49641
49406
  const COMPACT_SYSTEM_PROMPT_START = "You are a helpful AI assistant tasked with summarizing conversations";
49642
49407
  function applyMessagesModelPolicy(payload, options) {
49643
49408
  const originalModel = payload.model;
@@ -49645,17 +49410,6 @@ function applyMessagesModelPolicy(payload, options) {
49645
49410
  originalModel,
49646
49411
  routedModel: originalModel
49647
49412
  };
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
49413
  const smallModel = configStore.getSmallModel();
49660
49414
  if (!smallModel || !configStore.isCompactSmallModelEnabled() || !isCompactRequest(payload)) return {
49661
49415
  originalModel,
@@ -49684,9 +49438,9 @@ function canRouteToSmallModel(payload, originalModel, smallModel) {
49684
49438
  const originalEndpoints = new Set(originalModel.supported_endpoints ?? []);
49685
49439
  const smallEndpoints = new Set(smallModel.supported_endpoints ?? []);
49686
49440
  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;
49441
+ if (payload.tools?.length && !(smallModel.capabilities.supports.tool_calls ?? false)) return false;
49442
+ if (payload.thinking && !(smallModel.capabilities.supports.adaptive_thinking ?? false)) return false;
49443
+ if (hasVisionInput$1(payload) && !(smallModel.capabilities.supports.vision ?? false)) return false;
49690
49444
  return true;
49691
49445
  }
49692
49446
  function hasVisionInput$1(payload) {
@@ -49700,17 +49454,72 @@ function containsVisionContent$1(content) {
49700
49454
  //#region src/transform/policy.ts
49701
49455
  const modelPolicyStep = {
49702
49456
  tag: "POLICY",
49703
- apply({ model, payload, meta, resolvedModel }) {
49457
+ apply({ payload, meta }) {
49704
49458
  const routing = applyMessagesModelPolicy(payload, { betaUpgraded: meta?.betaHeaders?.some((b) => CONTEXT_BETA_RE.test(b)) ?? false });
49705
49459
  if (!routing.reason) return null;
49706
49460
  return {
49707
49461
  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
49462
+ tag: "COMPACT"
49710
49463
  };
49711
49464
  }
49712
49465
  };
49713
49466
  //#endregion
49467
+ //#region src/transform/model-rewrite.ts
49468
+ /**
49469
+ * Unified model rewrite: user rules → built-in normalization → pass-through.
49470
+ * Call once at handler entry, before any model lookup or policy.
49471
+ */
49472
+ function rewriteModel(modelId) {
49473
+ const userRules = configStore.getModelRewrites();
49474
+ if (userRules.length > 0) {
49475
+ for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
49476
+ originalModel: modelId,
49477
+ model: normalizeToKnownModel(rule.to) ?? rule.to,
49478
+ reason: "CONFIG_REWRITE"
49479
+ };
49480
+ }
49481
+ const normalized = normalizeToKnownModel(modelId);
49482
+ if (normalized && normalized !== modelId) return {
49483
+ originalModel: modelId,
49484
+ model: normalized,
49485
+ reason: "AUTO_CORRECT"
49486
+ };
49487
+ return {
49488
+ originalModel: modelId,
49489
+ model: modelId
49490
+ };
49491
+ }
49492
+ /**
49493
+ * Apply model rewrite to a mutable model field and log if changed.
49494
+ * Returns the rewrite result for downstream use.
49495
+ */
49496
+ function applyModelRewrite(payload) {
49497
+ const result = rewriteModel(payload.model);
49498
+ if (result.model !== result.originalModel) {
49499
+ consola.debug(`Model rewritten: ${result.originalModel} ~> ${result.model}`);
49500
+ payload.model = result.model;
49501
+ }
49502
+ return result;
49503
+ }
49504
+ const DOT_RE = /\./g;
49505
+ /**
49506
+ * Resolve a model ID against Copilot's cached model list using
49507
+ * dash/dot equivalence. Returns the canonical ID if found.
49508
+ */
49509
+ function normalizeToKnownModel(modelId) {
49510
+ const models = modelCache.getModels()?.data;
49511
+ if (!models) return void 0;
49512
+ if (models.some((m) => m.id === modelId)) return modelId;
49513
+ const normalized = modelId.replace(DOT_RE, "-");
49514
+ for (const model of models) if (model.id.replace(DOT_RE, "-") === normalized) return model.id;
49515
+ }
49516
+ const GLOB_SPECIAL_RE = /[.+^${}()|[\]\\]/g;
49517
+ const GLOB_STAR_RE = /\*/g;
49518
+ function matchesGlob(pattern, value) {
49519
+ if (!pattern.includes("*")) return pattern === value;
49520
+ return new RegExp(`^${pattern.replace(GLOB_SPECIAL_RE, "\\$&").replace(GLOB_STAR_RE, ".*")}$`).test(value);
49521
+ }
49522
+ //#endregion
49714
49523
  //#region src/transform/rewrite.ts
49715
49524
  const rewriteStep = {
49716
49525
  tag: "rewrite",
@@ -49735,6 +49544,20 @@ const rewriteStep = {
49735
49544
  }
49736
49545
  };
49737
49546
  //#endregion
49547
+ //#region src/transform/beta-headers.ts
49548
+ const COPILOT_UNSUPPORTED_BETA_RE = /^mid-conversation-system-\d{4}-\d{2}-\d{2}$/;
49549
+ function processAnthropicBetaHeader(rawHeader) {
49550
+ if (!rawHeader) return void 0;
49551
+ const values = rawHeader.split(",").map((v) => v.trim()).filter(Boolean);
49552
+ const filtered = [];
49553
+ for (const value of values) {
49554
+ if (CONTEXT_BETA_RE.test(value)) continue;
49555
+ if (COPILOT_UNSUPPORTED_BETA_RE.test(value)) continue;
49556
+ filtered.push(value);
49557
+ }
49558
+ return filtered.length > 0 ? filtered.join(",") : void 0;
49559
+ }
49560
+ //#endregion
49738
49561
  //#region src/translator/responses/signature-codec.ts
49739
49562
  const COMPACTION_PREFIX = "cm1#";
49740
49563
  const SEPARATOR = "@";
@@ -49797,8 +49620,8 @@ const OUTPUT_CONFIG_EFFORT_RANK = new Map([
49797
49620
  "low",
49798
49621
  "medium",
49799
49622
  "high",
49800
- "max",
49801
- "xhigh"
49623
+ "xhigh",
49624
+ "max"
49802
49625
  ].map((effort, index) => [effort, index]));
49803
49626
  function isOutputConfigEffort(value) {
49804
49627
  return OUTPUT_CONFIG_EFFORT_RANK.has(value);
@@ -49841,7 +49664,7 @@ function sanitizeCacheControl(payload) {
49841
49664
  }
49842
49665
  //#endregion
49843
49666
  //#region src/transform/index.ts
49844
- const messagesModelChain = composeModelTransforms(rewriteStep, betaHeaderStep, modelPolicyStep);
49667
+ const messagesModelChain = composeModelTransforms(rewriteStep, modelPolicyStep);
49845
49668
  const chatCompletionsModelChain = composeModelTransforms(rewriteStep);
49846
49669
  const responsesModelChain = composeModelTransforms(rewriteStep);
49847
49670
  //#endregion
@@ -49881,9 +49704,6 @@ function normalizeSystemBlocks(system) {
49881
49704
  blocks: system.map((block) => textBlock(block.text))
49882
49705
  }];
49883
49706
  }
49884
- function normalizeToolResultContent(block) {
49885
- return normalizeToolResultContentValue(block.content);
49886
- }
49887
49707
  function normalizeToolResultContentValue(content) {
49888
49708
  if (typeof content === "string") return [textBlock(content)];
49889
49709
  return content.map((contentBlock) => {
@@ -49895,9 +49715,6 @@ function normalizeToolResultContentValue(content) {
49895
49715
  }
49896
49716
  });
49897
49717
  }
49898
- function normalizeMcpToolResultContent(block) {
49899
- return normalizeToolResultContentValue(block.content);
49900
- }
49901
49718
  function normalizeServerToolResultContent(block) {
49902
49719
  return [textBlock(typeof block.content === "string" ? block.content : JSON.stringify(block.content) ?? "")];
49903
49720
  }
@@ -49937,13 +49754,13 @@ function normalizeMessage(message) {
49937
49754
  case "tool_result": return {
49938
49755
  kind: "tool_result",
49939
49756
  toolUseId: block.tool_use_id,
49940
- content: normalizeToolResultContent(block),
49757
+ content: normalizeToolResultContentValue(block.content),
49941
49758
  isError: block.is_error
49942
49759
  };
49943
49760
  case "mcp_tool_result": return {
49944
49761
  kind: "tool_result",
49945
49762
  toolUseId: block.tool_use_id,
49946
- content: normalizeMcpToolResultContent(block),
49763
+ content: normalizeToolResultContentValue(block.content),
49947
49764
  isError: block.is_error
49948
49765
  };
49949
49766
  case "server_tool_result":
@@ -50169,10 +49986,6 @@ var AnthropicStreamTranslator = class {
50169
49986
  for (const delta of deltas) switch (delta.kind) {
50170
49987
  case "message_start": break;
50171
49988
  case "thinking_delta":
50172
- this.state.lastMetadata = {
50173
- ...this.state.lastMetadata,
50174
- ...delta.metadata
50175
- };
50176
49989
  this.textWriter.close(events);
50177
49990
  this.thinkingWriter.append(events, delta.text);
50178
49991
  break;
@@ -50193,10 +50006,6 @@ var AnthropicStreamTranslator = class {
50193
50006
  });
50194
50007
  break;
50195
50008
  case "message_stop":
50196
- this.state.lastMetadata = {
50197
- ...this.state.lastMetadata,
50198
- ...delta.metadata
50199
- };
50200
50009
  this.state.pendingStopReason = delta.stopReason;
50201
50010
  this.closeAllBlocks(events);
50202
50011
  break;
@@ -50273,13 +50082,7 @@ var AnthropicStreamTranslator = class {
50273
50082
  });
50274
50083
  if (choice.delta.reasoning_text) deltas.push({
50275
50084
  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
- }
50085
+ text: choice.delta.reasoning_text
50283
50086
  });
50284
50087
  if (choice.delta.content) deltas.push({
50285
50088
  kind: "text_delta",
@@ -50295,13 +50098,7 @@ var AnthropicStreamTranslator = class {
50295
50098
  if (choice.finish_reason) deltas.push({
50296
50099
  kind: "message_stop",
50297
50100
  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
- }
50101
+ usage: chunk.usage
50305
50102
  });
50306
50103
  return deltas;
50307
50104
  }
@@ -50417,13 +50214,7 @@ function normalizeAssistantTurn(message) {
50417
50214
  }] : [],
50418
50215
  ...contentBlocks,
50419
50216
  ...toolBlocks
50420
- ],
50421
- meta: {
50422
- reasoningOpaque: message.reasoning_opaque,
50423
- encryptedContent: message.encrypted_content,
50424
- phase: message.phase,
50425
- copilotAnnotations: message.copilot_annotations
50426
- }
50217
+ ]
50427
50218
  };
50428
50219
  }
50429
50220
  function normalizeOpenAIResponse(response, context) {
@@ -50597,7 +50388,7 @@ var AnthropicMessagesAdapter = class {
50597
50388
  constructor(options = {}) {
50598
50389
  this.options = {
50599
50390
  modelResolver: options.modelResolver ?? ((model) => model),
50600
- getModelCapabilities: options.getModelCapabilities ?? ((model) => ({ supportsThinkingBudget: model.startsWith("claude") })),
50391
+ getModelCapabilities: options.getModelCapabilities ?? ((model) => ({ supportsThinkingBudget: inferModelFamily(model) === "claude" })),
50601
50392
  policy: options.policy ?? defaultTranslationPolicy
50602
50393
  };
50603
50394
  }
@@ -50633,21 +50424,6 @@ var AnthropicMessagesAdapter = class {
50633
50424
  }
50634
50425
  };
50635
50426
  //#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
50427
  //#region src/adapters/openai-chat-adapter.ts
50652
50428
  function toConversationBlocks(content) {
50653
50429
  if (content === null) return [];
@@ -50796,280 +50572,6 @@ var OpenAIChatAdapter = class {
50796
50572
  }
50797
50573
  };
50798
50574
  //#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
50575
  //#region src/dispatch/strategy-registry.ts
51074
50576
  var StrategyRegistry = class {
51075
50577
  entries = [];
@@ -51141,19 +50643,21 @@ function normalizeOutputs(value) {
51141
50643
  */
51142
50644
  function passthroughSSEChunk(chunk, data) {
51143
50645
  return {
51144
- ...chunk.comment ? { comment: chunk.comment } : {},
51145
50646
  ...chunk.event ? { event: chunk.event } : {},
51146
50647
  ...chunk.id !== void 0 ? { id: String(chunk.id) } : {},
51147
- ...chunk.retry !== void 0 ? { retry: chunk.retry } : {},
51148
50648
  data
51149
50649
  };
51150
50650
  }
51151
50651
  //#endregion
51152
50652
  //#region src/routes/chat-completions/strategy.ts
51153
- function createChatCompletionsStrategy(transport, adapter, plan, signal) {
50653
+ function createChatCompletionsStrategy(client, adapter, plan, signal) {
51154
50654
  return {
51155
50655
  execute() {
51156
- return transport.execute(plan, { signal });
50656
+ return client.createChatCompletions(plan.payload, {
50657
+ signal,
50658
+ initiator: plan.initiator,
50659
+ requestContext: plan.requestContext
50660
+ });
51157
50661
  },
51158
50662
  isStream(result) {
51159
50663
  return !isNonStreamingResponse(result);
@@ -51180,9 +50684,8 @@ const chatCompletionsEntry$1 = {
51180
50684
  const adapter = new OpenAIChatAdapter();
51181
50685
  const plan = adapter.toCapiPlan(ctx.payload, { requestContext: ctx.requestContext });
51182
50686
  appendModelStepInPlace(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
51183
- const transport = new CopilotTransport(ctx.copilotClient);
51184
50687
  consola.debug("Streaming response");
51185
- return await runStrategy(createChatCompletionsStrategy(transport, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
50688
+ return await runStrategy(createChatCompletionsStrategy(ctx.copilotClient, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
51186
50689
  }
51187
50690
  };
51188
50691
  const chatCompletionsStrategyRegistry = new StrategyRegistry();
@@ -51200,6 +50703,7 @@ async function handleCompletionCore({ body, signal, headers }) {
51200
50703
  strategyRegistry: chatCompletionsStrategyRegistry,
51201
50704
  afterIngest({ payload }) {
51202
50705
  consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
50706
+ return payload;
51203
50707
  },
51204
50708
  async afterTransform({ payload, selectedModel }) {
51205
50709
  try {
@@ -51275,7 +50779,7 @@ function createAnthropicAdapter() {
51275
50779
  const fallbackConfig = getModelFallbackConfig();
51276
50780
  return new AnthropicMessagesAdapter({
51277
50781
  modelResolver: (model) => resolveModel(model, knownModelIds, fallbackConfig),
51278
- getModelCapabilities: (model) => ({ supportsThinkingBudget: model.startsWith("claude") })
50782
+ getModelCapabilities: (model) => ({ supportsThinkingBudget: inferModelFamily(model) === "claude" })
51279
50783
  });
51280
50784
  }
51281
50785
  //#endregion
@@ -51314,7 +50818,123 @@ async function handleCountTokensCore({ body, headers }) {
51314
50818
  return { input_tokens: finalTokenCount };
51315
50819
  }
51316
50820
  //#endregion
51317
- //#region src/lib/function-schema.ts
50821
+ //#region src/transform/context-management.ts
50822
+ /** Default token threshold when model limits are unknown. */
50823
+ const DEFAULT_COMPACT_THRESHOLD = 5e4;
50824
+ /** Fraction of max prompt tokens to use as compact threshold. */
50825
+ const COMPACT_THRESHOLD_RATIO = .9;
50826
+ function getResponsesRequestOptions(payload) {
50827
+ return {
50828
+ vision: hasVisionInput(payload),
50829
+ initiator: hasAgentInitiator(payload) ? "agent" : "user"
50830
+ };
50831
+ }
50832
+ function hasAgentInitiator(payload) {
50833
+ const lastItem = getPayloadItems(payload).at(-1);
50834
+ if (!lastItem) return false;
50835
+ if (!("role" in lastItem) || !lastItem.role) return true;
50836
+ return String(lastItem.role).toLowerCase() === "assistant";
50837
+ }
50838
+ function hasVisionInput(payload) {
50839
+ return getPayloadItems(payload).some((item) => containsVisionContent(item));
50840
+ }
50841
+ function resolveResponsesCompactThreshold(maxPromptTokens) {
50842
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * COMPACT_THRESHOLD_RATIO);
50843
+ return DEFAULT_COMPACT_THRESHOLD;
50844
+ }
50845
+ function createCompactionContextManagement(compactThreshold) {
50846
+ return [{
50847
+ type: "compaction",
50848
+ compact_threshold: compactThreshold
50849
+ }];
50850
+ }
50851
+ function applyContextManagement(payload, maxPromptTokens) {
50852
+ if (payload.context_management !== void 0) return;
50853
+ if (!configStore.isContextManagementModel(payload.model)) return;
50854
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
50855
+ }
50856
+ function compactInputByLatestCompaction(payload) {
50857
+ if (!configStore.isAutoCompactResponsesInputEnabled()) return;
50858
+ if (!Array.isArray(payload.input) || payload.input.length === 0) return;
50859
+ const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
50860
+ if (latestCompactionMessageIndex === void 0) return;
50861
+ payload.input = payload.input.slice(latestCompactionMessageIndex);
50862
+ }
50863
+ function getLatestCompactionMessageIndex(input) {
50864
+ for (let index = input.length - 1; index >= 0; index--) if (isCompactionInputItem(input[index])) return index;
50865
+ }
50866
+ function isCompactionInputItem(value) {
50867
+ return "type" in value && value.type === "compaction";
50868
+ }
50869
+ function getPayloadItems(payload) {
50870
+ return Array.isArray(payload.input) ? payload.input : [];
50871
+ }
50872
+ function containsVisionContent(value) {
50873
+ if (!value) return false;
50874
+ if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
50875
+ if (typeof value !== "object") return false;
50876
+ const record = value;
50877
+ if (record.type === "input_image") return true;
50878
+ if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
50879
+ return false;
50880
+ }
50881
+ //#endregion
50882
+ //#region src/transform/parameter-filter.ts
50883
+ /**
50884
+ * Parameters the default rule strips for reasoning models on the Responses
50885
+ * boundary. Reasoning models (gpt-5 family, o-series, codex) reject sampling
50886
+ * parameters upstream with a 400 "Unsupported parameter" error, so the proxy
50887
+ * drops them instead of leaking the incompatibility to the client.
50888
+ */
50889
+ const DEFAULT_REASONING_UNSUPPORTED_PARAMS = ["temperature", "top_p"];
50890
+ /**
50891
+ * A reasoning model is any model that advertises one or more
50892
+ * `reasoning_effort` levels. This dynamically covers the full reasoning
50893
+ * family (mini, codex, future point releases) without a hardcoded ID list.
50894
+ */
50895
+ function isReasoningModel(model) {
50896
+ return modelCache.supportsReasoningEffort(model);
50897
+ }
50898
+ /**
50899
+ * Resolve the set of request parameters to strip for a given model on the
50900
+ * Responses boundary.
50901
+ *
50902
+ * Rule composition:
50903
+ * 1. Built-in default: reasoning models strip {@link DEFAULT_REASONING_UNSUPPORTED_PARAMS}.
50904
+ * Disabled entirely when `responsesApiParameterFiltersReplaceDefault` is true.
50905
+ * 2. User rules (`responsesApiParameterFilters`): every rule whose `models`
50906
+ * glob matches the resolved model id contributes its `params`.
50907
+ *
50908
+ * The result is the union of all matching rules, so user rules ADD to the
50909
+ * default. Setting `responsesApiParameterFiltersReplaceDefault: true` disables
50910
+ * the default so user rules fully OVERWRITE it.
50911
+ */
50912
+ function resolveStrippedResponsesParams(model) {
50913
+ const params = /* @__PURE__ */ new Set();
50914
+ if (!configStore.shouldReplaceDefaultParameterFilters() && isReasoningModel(model)) for (const param of DEFAULT_REASONING_UNSUPPORTED_PARAMS) params.add(param);
50915
+ const modelId = model?.id;
50916
+ if (modelId) {
50917
+ for (const rule of configStore.getResponsesParameterFilters()) if (rule.models.some((pattern) => matchesGlob(pattern, modelId))) for (const param of rule.params) params.add(param);
50918
+ }
50919
+ return params;
50920
+ }
50921
+ /**
50922
+ * Strip unsupported parameters from a Responses payload before dispatch.
50923
+ * Keys are deleted entirely (never set to null) because upstream rejects the
50924
+ * mere presence of the key, not just non-null values.
50925
+ */
50926
+ function applyResponsesParameterFilters(payload, model) {
50927
+ const strip = resolveStrippedResponsesParams(model);
50928
+ if (strip.size === 0) return;
50929
+ const removed = [];
50930
+ for (const key of strip) if (key in payload) {
50931
+ delete payload[key];
50932
+ removed.push(key);
50933
+ }
50934
+ if (removed.length > 0) consola.debug(`Stripped unsupported responses params for model ${model?.id}: ${removed.join(", ")}`);
50935
+ }
50936
+ //#endregion
50937
+ //#region src/translator/responses/function-schema.ts
51318
50938
  function isRecord$2(value) {
51319
50939
  return typeof value === "object" && value !== null && !Array.isArray(value);
51320
50940
  }
@@ -51356,147 +50976,9 @@ function normalizeFunctionParametersSchemaForCopilot(schema) {
51356
50976
  return normalizeSchemaNode(schema);
51357
50977
  }
51358
50978
  //#endregion
51359
- //#region src/translator/responses/anthropic-to-responses.ts
50979
+ //#region src/translator/responses/response-items.ts
51360
50980
  const MESSAGE_TYPE = "message";
51361
- const USER_ID_ACCOUNT_RE = /user_([^_]+)_account/;
51362
- const USER_ID_SESSION_RE = /_session_(.+)$/;
51363
50981
  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
50982
  function translateUserContentBlock(block) {
51501
50983
  switch (block.type) {
51502
50984
  case "text": return createTextContent(block.text);
@@ -51595,7 +51077,7 @@ function createRedactedReasoningContent(block) {
51595
51077
  };
51596
51078
  }
51597
51079
  function createCompactionContent(block) {
51598
- const compaction = decodeCompactionCarrierSignature(block.signature ?? "");
51080
+ const compaction = SignatureCodec.decodeCompaction(block.signature ?? "");
51599
51081
  if (!compaction) return;
51600
51082
  return {
51601
51083
  id: compaction.id,
@@ -51631,6 +51113,160 @@ function createServerFunctionCallOutput(block) {
51631
51113
  function isServerToolResultBlock(block) {
51632
51114
  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
51115
  }
51116
+ function convertToolResultContent(content) {
51117
+ if (typeof content === "string") return content;
51118
+ const result = [];
51119
+ for (const block of content) switch (block.type) {
51120
+ case "text":
51121
+ result.push(createTextContent(block.text));
51122
+ break;
51123
+ case "image":
51124
+ result.push(createImageContent(block));
51125
+ break;
51126
+ case "search_result":
51127
+ result.push(createTextContent(formatSearchResultBlock(block)));
51128
+ break;
51129
+ default: break;
51130
+ }
51131
+ return result;
51132
+ }
51133
+ //#endregion
51134
+ //#region src/translator/responses/anthropic-to-responses.ts
51135
+ const USER_ID_ACCOUNT_RE = /user_([^_]+)_account/;
51136
+ const USER_ID_SESSION_RE = /_session_(.+)$/;
51137
+ function translateAnthropicToResponsesPayload(payload, options) {
51138
+ assertResponsesCompatibleRequest(payload);
51139
+ const input = [];
51140
+ for (const message of payload.messages) input.push(...translateMessage(message));
51141
+ const { safetyIdentifier, promptCacheKey } = parseUserId(payload.metadata?.user_id);
51142
+ const reasoning = resolveResponsesReasoningConfig(payload, options);
51143
+ const text = resolveResponsesTextConfig(payload);
51144
+ return {
51145
+ model: payload.model,
51146
+ input,
51147
+ instructions: translateSystemPrompt(payload.system),
51148
+ temperature: payload.temperature ?? null,
51149
+ top_p: payload.top_p ?? null,
51150
+ max_output_tokens: payload.max_tokens,
51151
+ tools: convertAnthropicTools(payload.tools),
51152
+ tool_choice: convertAnthropicToolChoice(payload.tool_choice),
51153
+ metadata: payload.metadata ? { ...payload.metadata } : null,
51154
+ safety_identifier: safetyIdentifier,
51155
+ prompt_cache_key: promptCacheKey,
51156
+ stream: payload.stream ?? null,
51157
+ store: false,
51158
+ parallel_tool_calls: true,
51159
+ ...text ? { text } : {},
51160
+ ...reasoning ? {
51161
+ reasoning,
51162
+ include: ["reasoning.encrypted_content"]
51163
+ } : {}
51164
+ };
51165
+ }
51166
+ function translateMessage(message) {
51167
+ switch (message.role) {
51168
+ case "user": return translateUserMessage(message);
51169
+ case "assistant": return translateAssistantMessage(message);
51170
+ case "system": return translateSystemMessage(message);
51171
+ }
51172
+ }
51173
+ function translateSystemMessage(message) {
51174
+ if (typeof message.content === "string") return [createMessage("system", message.content)];
51175
+ if (!Array.isArray(message.content)) return [];
51176
+ return [createMessage("system", message.content.map((block) => createTextContent(block.text)))];
51177
+ }
51178
+ function translateUserMessage(message) {
51179
+ if (typeof message.content === "string") return [createMessage("user", message.content)];
51180
+ if (!Array.isArray(message.content)) return [];
51181
+ const items = [];
51182
+ const pendingContent = [];
51183
+ for (const block of message.content) {
51184
+ if (block.type === "tool_result" || block.type === "mcp_tool_result") {
51185
+ flushPendingContent(pendingContent, items, { role: "user" });
51186
+ items.push(createFunctionCallOutput(block));
51187
+ continue;
51188
+ }
51189
+ if (isServerToolResultBlock(block)) {
51190
+ flushPendingContent(pendingContent, items, { role: "user" });
51191
+ items.push(createServerFunctionCallOutput(block));
51192
+ continue;
51193
+ }
51194
+ const converted = translateUserContentBlock(block);
51195
+ if (converted) pendingContent.push(converted);
51196
+ }
51197
+ flushPendingContent(pendingContent, items, { role: "user" });
51198
+ return items;
51199
+ }
51200
+ function translateAssistantMessage(message) {
51201
+ const assistantPhase = resolveAssistantPhase(message.content);
51202
+ if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
51203
+ if (!Array.isArray(message.content)) return [];
51204
+ const items = [];
51205
+ const pendingContent = [];
51206
+ for (const block of message.content) {
51207
+ if (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use") {
51208
+ flushPendingContent(pendingContent, items, {
51209
+ role: "assistant",
51210
+ phase: assistantPhase
51211
+ });
51212
+ items.push(createFunctionToolCall(block));
51213
+ continue;
51214
+ }
51215
+ if (block.type === "redacted_thinking") {
51216
+ flushPendingContent(pendingContent, items, {
51217
+ role: "assistant",
51218
+ phase: assistantPhase
51219
+ });
51220
+ items.push(createRedactedReasoningContent(block));
51221
+ continue;
51222
+ }
51223
+ if (block.type === "mcp_tool_result") {
51224
+ flushPendingContent(pendingContent, items, {
51225
+ role: "assistant",
51226
+ phase: assistantPhase
51227
+ });
51228
+ items.push(createFunctionCallOutput(block));
51229
+ continue;
51230
+ }
51231
+ if (isServerToolResultBlock(block)) {
51232
+ flushPendingContent(pendingContent, items, {
51233
+ role: "assistant",
51234
+ phase: assistantPhase
51235
+ });
51236
+ items.push(createServerFunctionCallOutput(block));
51237
+ continue;
51238
+ }
51239
+ if (block.type === "thinking" && block.signature) {
51240
+ const compaction = createCompactionContent(block);
51241
+ if (compaction) {
51242
+ flushPendingContent(pendingContent, items, {
51243
+ role: "assistant",
51244
+ phase: assistantPhase
51245
+ });
51246
+ items.push(compaction);
51247
+ continue;
51248
+ }
51249
+ if (SignatureCodec.isReasoningSignature(block.signature)) {
51250
+ const { id } = SignatureCodec.decodeReasoning(block.signature);
51251
+ if (id) {
51252
+ flushPendingContent(pendingContent, items, {
51253
+ role: "assistant",
51254
+ phase: assistantPhase
51255
+ });
51256
+ items.push(createReasoningContent(block));
51257
+ continue;
51258
+ }
51259
+ }
51260
+ }
51261
+ const converted = translateAssistantContentBlock(block);
51262
+ if (converted) pendingContent.push(converted);
51263
+ }
51264
+ flushPendingContent(pendingContent, items, {
51265
+ role: "assistant",
51266
+ phase: assistantPhase
51267
+ });
51268
+ return items;
51269
+ }
51634
51270
  function translateSystemPrompt(system) {
51635
51271
  if (!system) return null;
51636
51272
  if (typeof system === "string") return system;
@@ -51716,92 +51352,18 @@ function parseUserId(userId) {
51716
51352
  promptCacheKey: sessionMatch ? sessionMatch[1] : null
51717
51353
  };
51718
51354
  }
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
51355
  //#endregion
51798
51356
  //#region src/routes/messages/strategies/chat-completions.ts
51799
- function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, signal) {
51357
+ function createMessagesViaChatCompletionsStrategy(client, adapter, plan, signal) {
51800
51358
  let streamTranslator;
51801
51359
  let done = false;
51802
51360
  return {
51803
51361
  execute() {
51804
- return transport.execute(plan, { signal });
51362
+ return client.createChatCompletions(plan.payload, {
51363
+ signal,
51364
+ initiator: plan.initiator,
51365
+ requestContext: plan.requestContext
51366
+ });
51805
51367
  },
51806
51368
  isStream(result) {
51807
51369
  return !isNonStreamingResponse(result);
@@ -51818,24 +51380,15 @@ function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, sign
51818
51380
  if (chunk.data === "[DONE]") {
51819
51381
  const finalEvents = streamTranslator.onDone();
51820
51382
  done = true;
51821
- return finalEvents.map((event) => ({
51822
- event: event.type,
51823
- data: JSON.stringify(event)
51824
- }));
51383
+ return serializeAnthropicSSE(finalEvents);
51825
51384
  }
51826
51385
  if (!chunk.data) return null;
51827
51386
  const parsed = JSON.parse(chunk.data);
51828
- return streamTranslator.onChunk(parsed).map((event) => ({
51829
- event: event.type,
51830
- data: JSON.stringify(event)
51831
- }));
51387
+ return serializeAnthropicSSE(streamTranslator.onChunk(parsed));
51832
51388
  },
51833
51389
  onStreamDone() {
51834
51390
  if (!streamTranslator) return null;
51835
- return streamTranslator.onDone().map((event) => ({
51836
- event: event.type,
51837
- data: JSON.stringify(event)
51838
- }));
51391
+ return serializeAnthropicSSE(streamTranslator.onDone());
51839
51392
  },
51840
51393
  shouldBreakStream() {
51841
51394
  return done;
@@ -51843,15 +51396,12 @@ function createMessagesViaChatCompletionsStrategy(transport, adapter, plan, sign
51843
51396
  onStreamError(error) {
51844
51397
  consola.error("Error streaming Anthropic response:", error);
51845
51398
  if (!streamTranslator) streamTranslator = adapter.createStreamSerializer();
51846
- return streamTranslator.onError(error).map((event) => ({
51847
- event: event.type,
51848
- data: JSON.stringify(event)
51849
- }));
51399
+ return serializeAnthropicSSE(streamTranslator.onError(error));
51850
51400
  }
51851
51401
  };
51852
51402
  }
51853
51403
  //#endregion
51854
- //#region src/lib/async-iterable.ts
51404
+ //#region src/util/async-iterable.ts
51855
51405
  function isAsyncIterable(value) {
51856
51406
  return Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
51857
51407
  }
@@ -51924,6 +51474,30 @@ function createNativeMessagesStrategy(copilotClient, payload, anthropicBetaHeade
51924
51474
  }
51925
51475
  };
51926
51476
  }
51477
+ var FunctionCallArgumentsValidationError = class extends Error {
51478
+ constructor(message) {
51479
+ super(message);
51480
+ this.name = "FunctionCallArgumentsValidationError";
51481
+ }
51482
+ };
51483
+ function updateWhitespaceRunState(previousCount, chunk) {
51484
+ let count = previousCount;
51485
+ for (const char of chunk) {
51486
+ if (char === " " || char === "\r" || char === "\n" || char === " ") {
51487
+ count += 1;
51488
+ if (count > 20) return {
51489
+ nextCount: count,
51490
+ exceeded: true
51491
+ };
51492
+ continue;
51493
+ }
51494
+ count = 0;
51495
+ }
51496
+ return {
51497
+ nextCount: count,
51498
+ exceeded: false
51499
+ };
51500
+ }
51927
51501
  //#endregion
51928
51502
  //#region src/translator/responses/responses-to-anthropic.ts
51929
51503
  function translateResponsesToAnthropic(response) {
@@ -51996,12 +51570,9 @@ function combineMessageTextContent(content) {
51996
51570
  function extractReasoningText(item) {
51997
51571
  if (!item.summary || item.summary.length === 0) return THINKING_TEXT;
51998
51572
  const segments = [];
51999
- collectReasoningSegments(item.summary, segments);
51573
+ for (const block of item.summary) if (typeof block.text === "string") segments.push(block.text);
52000
51574
  return segments.join("").trim();
52001
51575
  }
52002
- function collectReasoningSegments(blocks, segments) {
52003
- for (const block of blocks) if (typeof block.text === "string") segments.push(block.text);
52004
- }
52005
51576
  function createToolUseContentBlock(call) {
52006
51577
  if (!call.name || !call.call_id) return null;
52007
51578
  return {
@@ -52061,31 +51632,6 @@ function isResponseOutputRefusal(block) {
52061
51632
  }
52062
51633
  //#endregion
52063
51634
  //#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
51635
  var ResponsesStreamTranslator = class {
52090
51636
  state = {
52091
51637
  messageStartSent: false,
@@ -52345,6 +51891,7 @@ var ResponsesStreamTranslator = class {
52345
51891
  return events;
52346
51892
  }
52347
51893
  handleResponseCompleted(rawEvent) {
51894
+ if (this.state.messageCompleted) return [];
52348
51895
  const events = [];
52349
51896
  this.closeAllOpenBlocks(events);
52350
51897
  const anthropic = translateResponsesToAnthropic(rawEvent.response);
@@ -52505,27 +52052,18 @@ function createMessagesViaResponsesStrategy(copilotClient, responsesPayload, opt
52505
52052
  data: "{\"type\":\"ping\"}"
52506
52053
  };
52507
52054
  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
- }));
52055
+ return serializeAnthropicSSE(translator.onEvent(JSON.parse(chunk.data)));
52512
52056
  },
52513
52057
  shouldBreakStream() {
52514
52058
  return translator.isCompleted;
52515
52059
  },
52516
52060
  onStreamDone() {
52517
52061
  if (translator.isCompleted) return null;
52518
- return translator.onDone().map((event) => ({
52519
- event: event.type,
52520
- data: JSON.stringify(event)
52521
- }));
52062
+ return serializeAnthropicSSE(translator.onDone());
52522
52063
  },
52523
52064
  onStreamError(error) {
52524
52065
  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
- }));
52066
+ return serializeAnthropicSSE(translator.onError(error));
52529
52067
  }
52530
52068
  };
52531
52069
  }
@@ -52551,6 +52089,7 @@ const responsesApiEntry = {
52551
52089
  const responsesPayload = withTranslationErrors(() => translateAnthropicToResponsesPayload(ctx.anthropicPayload, { reasoningEffortResolver: (model) => configStore.getReasoningEffort(model) }));
52552
52090
  applyContextManagement(responsesPayload, ctx.selectedModel?.capabilities.limits.max_prompt_tokens);
52553
52091
  compactInputByLatestCompaction(responsesPayload);
52092
+ applyResponsesParameterFilters(responsesPayload, ctx.selectedModel);
52554
52093
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
52555
52094
  return await runStrategy(createMessagesViaResponsesStrategy(ctx.copilotClient, responsesPayload, {
52556
52095
  vision,
@@ -52570,7 +52109,7 @@ const chatCompletionsEntry = {
52570
52109
  appendModelStepInPlace(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
52571
52110
  consola.debug("Claude Code requested model:", ctx.anthropicPayload.model, "-> Copilot model:", plan.resolvedModel);
52572
52111
  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);
52112
+ return await runStrategy(createMessagesViaChatCompletionsStrategy(ctx.copilotClient, adapter, plan, ctx.upstreamSignal.signal), ctx.upstreamSignal);
52574
52113
  }
52575
52114
  };
52576
52115
  const defaultStrategyRegistry = new StrategyRegistry();
@@ -52589,10 +52128,10 @@ async function handleMessagesCore({ body, signal, headers }) {
52589
52128
  protocol: "anthropic-messages",
52590
52129
  transformChain: messagesModelChain,
52591
52130
  strategyRegistry: defaultStrategyRegistry,
52592
- contextRetry: true,
52593
52131
  afterIngest({ payload, headers: reqHeaders }) {
52594
52132
  if (consola.level >= 4) consola.debug("Anthropic request payload:", JSON.stringify(payload));
52595
- anthropicBetaHeader = processAnthropicBetaHeader(reqHeaders.get("anthropic-beta"), payload.model).header;
52133
+ anthropicBetaHeader = processAnthropicBetaHeader(reqHeaders.get("anthropic-beta"));
52134
+ return payload;
52596
52135
  },
52597
52136
  buildStrategyContext({ payload, meta, headers: reqHeaders, selectedModel, copilotClient, upstreamSignal, modelMapping }) {
52598
52137
  return {
@@ -52657,13 +52196,243 @@ function createModelRoutes() {
52657
52196
  });
52658
52197
  }
52659
52198
  //#endregion
52199
+ //#region src/routes/responses/emulator.ts
52200
+ function cloneValue(value) {
52201
+ return structuredClone(value);
52202
+ }
52203
+ function rejectUnsupportedBackground(payload) {
52204
+ if (payload.background) throwInvalidRequestError("background mode is not supported by the responses official emulator.", "background", "unsupported_background_mode");
52205
+ }
52206
+ function prepareEmulatorRequest(payload) {
52207
+ rejectUnsupportedBackground(payload);
52208
+ const normalizedCurrentInput = normalizeResponsesInput(payload.input);
52209
+ const { continuationSourceResponseId, conversation: resolvedConversation, previousResponse } = resolveContinuation(payload);
52210
+ const conversation = resolvedConversation ?? createConversationRef();
52211
+ const effectiveInputItems = [...continuationSourceResponseId ? buildContinuationHistory(continuationSourceResponseId) : [], ...normalizedCurrentInput];
52212
+ const shouldStore = payload.store ?? true;
52213
+ return {
52214
+ upstreamPayload: {
52215
+ ...payload,
52216
+ background: void 0,
52217
+ conversation: void 0,
52218
+ previous_response_id: void 0,
52219
+ store: void 0,
52220
+ input: effectiveInputItems
52221
+ },
52222
+ effectiveInputItems,
52223
+ previousResponseId: previousResponse?.id,
52224
+ conversation,
52225
+ shouldStore
52226
+ };
52227
+ }
52228
+ function decorateStoredResponse(upstreamResponse, requestPayload, prepared) {
52229
+ return {
52230
+ ...cloneValue(upstreamResponse),
52231
+ previous_response_id: prepared.previousResponseId ?? null,
52232
+ conversation: prepared.conversation,
52233
+ truncation: requestPayload.truncation ?? null,
52234
+ store: prepared.shouldStore,
52235
+ user: normalizeNullableString(requestPayload.user),
52236
+ service_tier: normalizeServiceTier(requestPayload.service_tier)
52237
+ };
52238
+ }
52239
+ function persistEmulatorResponse(response, effectiveInputItems) {
52240
+ responsesEmulatorState.setResponse(response);
52241
+ if (response.conversation) {
52242
+ responsesEmulatorState.setConversation(response.conversation);
52243
+ responsesEmulatorState.setConversationHead(getConversationId(response.conversation), response.id);
52244
+ }
52245
+ responsesEmulatorState.setInputItems(response.id, effectiveInputItems);
52246
+ }
52247
+ function getStoredResponseOrThrow(responseId) {
52248
+ const response = responsesEmulatorState.getResponse(responseId);
52249
+ if (!response) throw new HTTPError(404, { error: {
52250
+ message: `No response found with id '${responseId}'.`,
52251
+ type: "invalid_request_error"
52252
+ } });
52253
+ return response;
52254
+ }
52255
+ function listStoredInputItemsOrThrow(responseId, params) {
52256
+ const items = responsesEmulatorState.getInputItems(responseId);
52257
+ if (!items) throw new HTTPError(404, { error: {
52258
+ message: `No response input items found for id '${responseId}'.`,
52259
+ type: "invalid_request_error"
52260
+ } });
52261
+ let orderedItems = cloneValue(items);
52262
+ if (params?.order === "desc") orderedItems.reverse();
52263
+ if (params?.after) {
52264
+ const afterIndex = orderedItems.findIndex((item) => getInputItemId(item) === params.after);
52265
+ if (afterIndex >= 0) orderedItems = orderedItems.slice(afterIndex + 1);
52266
+ }
52267
+ const limitedItems = orderedItems.slice(0, params?.limit ?? orderedItems.length);
52268
+ return {
52269
+ object: "list",
52270
+ data: limitedItems,
52271
+ first_id: getInputItemId(limitedItems[0]) ?? null,
52272
+ last_id: getInputItemId(limitedItems.at(-1)) ?? null,
52273
+ has_more: limitedItems.length < orderedItems.length
52274
+ };
52275
+ }
52276
+ function deleteStoredResponseOrThrow(responseId) {
52277
+ getStoredResponseOrThrow(responseId);
52278
+ return responsesEmulatorState.deleteResponse(responseId);
52279
+ }
52280
+ async function estimateEmulatorInputTokens(payload, selectedModel) {
52281
+ return {
52282
+ object: "response.input_tokens",
52283
+ input_tokens: await estimateResponsesInputTokens(resolveEffectiveInputForInputTokens(payload), selectedModel)
52284
+ };
52285
+ }
52286
+ function resolveEffectiveInputForInputTokens(payload) {
52287
+ const normalizedInput = normalizeResponsesInput(payload.input);
52288
+ const background = payload.background === null || typeof payload.background === "boolean" ? payload.background : void 0;
52289
+ const conversation = isConversationReference(payload.conversation) ? payload.conversation : void 0;
52290
+ const previousResponseId = typeof payload.previous_response_id === "string" ? payload.previous_response_id : void 0;
52291
+ rejectUnsupportedBackground({ background });
52292
+ const { continuationSourceResponseId } = resolveContinuation({
52293
+ conversation,
52294
+ previous_response_id: previousResponseId
52295
+ });
52296
+ if (continuationSourceResponseId) return [...buildContinuationHistory(continuationSourceResponseId), ...normalizedInput];
52297
+ return normalizedInput;
52298
+ }
52299
+ function resolveContinuation(payload) {
52300
+ const previousResponse = resolvePreviousResponse(payload.previous_response_id);
52301
+ const conversation = resolveConversation(payload.conversation, previousResponse);
52302
+ return {
52303
+ previousResponse,
52304
+ conversation,
52305
+ continuationSourceResponseId: resolveContinuationSourceResponseId(previousResponse, conversation)
52306
+ };
52307
+ }
52308
+ function resolvePreviousResponse(previousResponseId) {
52309
+ if (typeof previousResponseId !== "string" || previousResponseId.length === 0) return;
52310
+ const previousResponse = responsesEmulatorState.getResponse(previousResponseId);
52311
+ if (!previousResponse) throwInvalidRequestError("The selected previous_response_id could not be resolved.", "previous_response_id");
52312
+ return previousResponse;
52313
+ }
52314
+ function resolveConversation(conversation, previousResponse) {
52315
+ if (isConversationReference(conversation)) {
52316
+ const conversationId = getConversationId(conversation);
52317
+ const existingConversation = responsesEmulatorState.getConversation(conversationId);
52318
+ if (!existingConversation) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
52319
+ if (previousResponse?.conversation && getConversationId(previousResponse.conversation) !== conversationId) throwInvalidRequestError("The selected previous_response_id does not belong to the selected conversation.", "previous_response_id");
52320
+ return existingConversation;
52321
+ }
52322
+ return previousResponse?.conversation ?? void 0;
52323
+ }
52324
+ function resolveContinuationSourceResponseId(previousResponse, conversation) {
52325
+ if (previousResponse) return previousResponse.id;
52326
+ if (!conversation) return;
52327
+ const head = responsesEmulatorState.getConversationHead(getConversationId(conversation));
52328
+ if (!head) throwInvalidRequestError("The selected conversation could not be resolved.", "conversation");
52329
+ return head;
52330
+ }
52331
+ function buildContinuationHistory(responseId) {
52332
+ const previousResponse = getStoredResponseOrThrow(responseId);
52333
+ const previousInput = responsesEmulatorState.getInputItems(responseId);
52334
+ if (!previousInput) throwInvalidRequestError("The selected previous_response_id is missing stored input items.", "previous_response_id");
52335
+ return [...cloneValue(previousInput), ...convertOutputItemsToInputItems(previousResponse.output)];
52336
+ }
52337
+ function normalizeResponsesInput(input) {
52338
+ if (!input) return [];
52339
+ if (typeof input === "string") return [{
52340
+ type: "message",
52341
+ role: "user",
52342
+ content: input
52343
+ }];
52344
+ if (Array.isArray(input)) return cloneValue(input);
52345
+ return [];
52346
+ }
52347
+ function convertOutputItemsToInputItems(output) {
52348
+ const items = [];
52349
+ for (const item of output) switch (item.type) {
52350
+ case "message":
52351
+ items.push(convertMessageOutputToInput(item));
52352
+ break;
52353
+ case "function_call":
52354
+ items.push(convertFunctionCallOutputToInput(item));
52355
+ break;
52356
+ case "reasoning": {
52357
+ const reasoningInput = convertReasoningOutputToInput(item);
52358
+ if (reasoningInput) items.push(reasoningInput);
52359
+ break;
52360
+ }
52361
+ case "compaction":
52362
+ items.push(convertCompactionOutputToInput(item));
52363
+ break;
52364
+ }
52365
+ return items;
52366
+ }
52367
+ function convertMessageOutputToInput(item) {
52368
+ return {
52369
+ type: "message",
52370
+ role: item.role,
52371
+ status: item.status,
52372
+ content: item.content?.map((content) => {
52373
+ if (content.type === "output_text" && typeof content.text === "string") return {
52374
+ type: "output_text",
52375
+ text: content.text
52376
+ };
52377
+ return cloneValue(content);
52378
+ }) ?? []
52379
+ };
52380
+ }
52381
+ function convertFunctionCallOutputToInput(item) {
52382
+ return {
52383
+ type: "function_call",
52384
+ call_id: item.call_id,
52385
+ name: item.name,
52386
+ arguments: item.arguments,
52387
+ status: item.status
52388
+ };
52389
+ }
52390
+ function convertReasoningOutputToInput(item) {
52391
+ if (!item.encrypted_content) return;
52392
+ return {
52393
+ id: item.id,
52394
+ type: "reasoning",
52395
+ summary: (item.summary ?? []).filter((summary) => typeof summary.text === "string").map((summary) => ({
52396
+ type: "summary_text",
52397
+ text: summary.text
52398
+ })),
52399
+ encrypted_content: item.encrypted_content
52400
+ };
52401
+ }
52402
+ function convertCompactionOutputToInput(item) {
52403
+ return {
52404
+ id: item.id,
52405
+ type: "compaction",
52406
+ encrypted_content: item.encrypted_content
52407
+ };
52408
+ }
52409
+ function normalizeNullableString(value) {
52410
+ return typeof value === "string" ? value : null;
52411
+ }
52412
+ function normalizeServiceTier(value) {
52413
+ if (value === "auto" || value === "default" || value === "flex" || value === "scale" || value === "priority") return value;
52414
+ return null;
52415
+ }
52416
+ function createConversationRef() {
52417
+ return { id: `conv_${randomUUID().replaceAll("-", "")}` };
52418
+ }
52419
+ function isConversationReference(value) {
52420
+ if (typeof value === "string") return value.length > 0;
52421
+ return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string" && value.id.length > 0;
52422
+ }
52423
+ function getConversationId(conversation) {
52424
+ return typeof conversation === "string" ? conversation : conversation.id;
52425
+ }
52426
+ function getInputItemId(item) {
52427
+ if (!item || typeof item !== "object") return;
52428
+ if ("id" in item && typeof item.id === "string") return item.id;
52429
+ if ("call_id" in item && typeof item.call_id === "string") return item.call_id;
52430
+ }
52431
+ //#endregion
52660
52432
  //#region src/routes/responses/strategy.ts
52661
52433
  function isRecord(value) {
52662
52434
  return typeof value === "object" && value !== null;
52663
52435
  }
52664
- function createStreamIdTracker() {
52665
- return { itemIdsByOutputIndex: /* @__PURE__ */ new Map() };
52666
- }
52667
52436
  function fixStreamIds(rawData, eventName, state) {
52668
52437
  if (!rawData) return rawData;
52669
52438
  let parsed;
@@ -52693,7 +52462,7 @@ function fixStreamIds(rawData, eventName, state) {
52693
52462
  return JSON.stringify(parsed);
52694
52463
  }
52695
52464
  function createResponsesPassthroughStrategy(copilotClient, payload, options) {
52696
- const tracker = createStreamIdTracker();
52465
+ const tracker = { itemIdsByOutputIndex: /* @__PURE__ */ new Map() };
52697
52466
  return {
52698
52467
  async execute() {
52699
52468
  try {
@@ -52707,7 +52476,10 @@ function createResponsesPassthroughStrategy(copilotClient, payload, options) {
52707
52476
  return Boolean(payload.stream) && isAsyncIterable(result);
52708
52477
  },
52709
52478
  translateResult(result) {
52710
- return result;
52479
+ const response = result;
52480
+ const mapped = options.mapResponse ? options.mapResponse(response) : response;
52481
+ if (options.mapResponse) options.onTerminalResponse?.(mapped);
52482
+ return mapped;
52711
52483
  },
52712
52484
  translateStreamChunk(chunk) {
52713
52485
  const fixedData = fixStreamIds(chunk.data ?? "", chunk.event, tracker);
@@ -52786,59 +52558,56 @@ responsesStrategyRegistry.register(responsesPassthroughEntry);
52786
52558
  //#region src/routes/responses/handler.ts
52787
52559
  const HTTP_URL_RE = /^https?:\/\//i;
52788
52560
  /**
52789
- * Core handler for responses endpoint.
52561
+ * Core handler for responses endpoint. Orchestrates the standard pipeline
52562
+ * (ingest → transform → dispatch) via runPipeline, with the responses-specific
52563
+ * emulator request prep, tool/input policies, and context management applied
52564
+ * through the afterIngest / afterTransform lifecycle hooks.
52790
52565
  */
52791
52566
  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,
52567
+ const emulatorMode = configStore.isEmulatorEnabled();
52568
+ let originalPayload;
52569
+ let emulatorPrepared;
52570
+ return await runPipeline({
52571
+ body,
52572
+ signal,
52799
52573
  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
- }))
52574
+ }, {
52575
+ protocol: "responses",
52576
+ transformChain: responsesModelChain,
52577
+ strategyRegistry: responsesStrategyRegistry,
52578
+ afterIngest({ payload }) {
52579
+ originalPayload = payload;
52580
+ emulatorPrepared = emulatorMode ? prepareEmulatorRequest(payload) : void 0;
52581
+ return emulatorPrepared?.upstreamPayload ?? payload;
52582
+ },
52583
+ afterTransform({ payload, selectedModel }) {
52584
+ applyResponsesToolTransforms(payload);
52585
+ applyResponsesInputPolicies(payload);
52586
+ compactInputByLatestCompaction(payload);
52587
+ if (!selectedModel) throwInvalidRequestError("The selected model could not be resolved.", "model");
52588
+ if (!modelCache.supportsEndpoint(selectedModel, "/responses")) throwInvalidRequestError("The selected model does not support the responses endpoint.", "model");
52589
+ applyContextManagement(payload, selectedModel.capabilities.limits.max_prompt_tokens);
52590
+ applyResponsesParameterFilters(payload, selectedModel);
52591
+ },
52592
+ buildStrategyContext({ payload, meta, copilotClient, upstreamSignal }) {
52593
+ const { vision, initiator } = getResponsesRequestOptions(payload);
52594
+ const prepared = emulatorPrepared;
52595
+ const requestPayload = originalPayload ?? payload;
52596
+ return {
52597
+ copilotClient,
52598
+ payload,
52599
+ upstreamSignal,
52600
+ requestContext: meta.requestContext ?? {},
52601
+ vision,
52602
+ initiator,
52603
+ decorateResponse: prepared ? (response) => decorateStoredResponse(response, requestPayload, prepared) : void 0,
52604
+ onTerminalResponse: prepared ? (terminalResponse) => {
52605
+ if (!prepared.shouldStore) return;
52606
+ persistEmulatorResponse(terminalResponse, prepared.effectiveInputItems);
52607
+ } : void 0
52608
+ };
52840
52609
  }
52841
- };
52610
+ });
52842
52611
  }
52843
52612
  function applyResponsesToolTransforms(payload) {
52844
52613
  applyFunctionApplyPatch(payload);
@@ -52944,6 +52713,46 @@ function containsRemoteImageUrl(value) {
52944
52713
  return Object.values(record).some((entry) => containsRemoteImageUrl(entry));
52945
52714
  }
52946
52715
  //#endregion
52716
+ //#region src/routes/responses/resource-dispatcher.ts
52717
+ var EmulatorResourceDispatcher = class {
52718
+ retrieve(responseId) {
52719
+ return Promise.resolve(getStoredResponseOrThrow(responseId));
52720
+ }
52721
+ listInputItems(responseId, params) {
52722
+ return Promise.resolve(listStoredInputItemsOrThrow(responseId, params));
52723
+ }
52724
+ async createInputTokens(payload) {
52725
+ return estimateEmulatorInputTokens(payload, resolveModelOrThrow(payload.model ?? ""));
52726
+ }
52727
+ delete(responseId) {
52728
+ return Promise.resolve(deleteStoredResponseOrThrow(responseId));
52729
+ }
52730
+ };
52731
+ var UpstreamResourceDispatcher = class {
52732
+ client;
52733
+ constructor(client) {
52734
+ this.client = client;
52735
+ }
52736
+ retrieve(responseId, params, options) {
52737
+ return this.client.getResponse(responseId, {
52738
+ params,
52739
+ ...options
52740
+ });
52741
+ }
52742
+ listInputItems(responseId, params, options) {
52743
+ return this.client.getResponseInputItems(responseId, params, options);
52744
+ }
52745
+ createInputTokens(payload, options) {
52746
+ return this.client.createResponseInputTokens(payload, options);
52747
+ }
52748
+ delete(responseId, options) {
52749
+ return this.client.deleteResponse(responseId, options);
52750
+ }
52751
+ };
52752
+ function createResourceDispatcher() {
52753
+ return configStore.isEmulatorEnabled() ? new EmulatorResourceDispatcher() : new UpstreamResourceDispatcher(createCopilotClient());
52754
+ }
52755
+ //#endregion
52947
52756
  //#region src/routes/responses/resource-handler.ts
52948
52757
  async function handleRetrieveResponseCore({ params, url, headers, signal }) {
52949
52758
  const responseId = requireResponseId(params.responseId);
@@ -53312,7 +53121,7 @@ const start = defineCommand({
53312
53121
  },
53313
53122
  "upstream-queue-retries": {
53314
53123
  type: "string",
53315
- description: "Maximum retries for upstream 429 responses (default: 6)"
53124
+ description: "Maximum retries for upstream 429 responses (default: 5)"
53316
53125
  },
53317
53126
  "upstream-queue-base-delay": {
53318
53127
  type: "string",