@jeffreycao/copilot-api 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -25,7 +25,7 @@ bindElectronFetch();
25
25
  const { auth } = await import("./auth-DH-ThnhJ.js");
26
26
  const { debug } = await import("./debug-D2giR-Kj.js");
27
27
  const { mcp } = await import("./mcp-BG6fpi6q.js");
28
- const { start } = await import("./start-ObdI9ph2.js");
28
+ const { start } = await import("./start-CfqpNRSH.js");
29
29
  await runMain(defineCommand({
30
30
  meta: {
31
31
  name: "copilot-api",
@@ -2999,7 +2999,8 @@ async function handleCompletion$1(c) {
2999
2999
  });
3000
3000
  }
3001
3001
  debugJson(logger$13, "Request payload:", payload);
3002
- const selectedModel = state.models?.data.find((model) => model.id === payload.model);
3002
+ const selectedModel = findEndpointModel(payload.model);
3003
+ payload.model = selectedModel?.id ?? payload.model;
3003
3004
  if (isNullish(payload.max_tokens) && isNullish(payload.max_completion_tokens)) {
3004
3005
  payload = {
3005
3006
  ...payload,
@@ -7338,9 +7339,9 @@ async function handleCompletionPayload(c, anthropicPayload, dispatchOptions = {}
7338
7339
  debugJson(logger$9, "Anthropic request payload:", anthropicPayload);
7339
7340
  normalizeSystemMessages(anthropicPayload);
7340
7341
  sanitizeIdeTools(anthropicPayload);
7341
- const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
7342
+ const subagentMarker = dispatchOptions.subagentMarker ?? parseSubagentMarkerFromFirstUser(anthropicPayload);
7342
7343
  if (subagentMarker) debugJson(logger$9, "Detected Subagent marker:", subagentMarker);
7343
- let sessionId = getRootSessionId(anthropicPayload, c);
7344
+ let sessionId = dispatchOptions.sessionId ?? getRootSessionId(anthropicPayload, c);
7344
7345
  const compactType = dispatchOptions.compactType ?? getCompactType(anthropicPayload);
7345
7346
  const anthropicBeta = c.req.header("anthropic-beta");
7346
7347
  logger$9.debug("Anthropic Beta header:", anthropicBeta);
@@ -7356,7 +7357,7 @@ async function handleCompletionPayload(c, anthropicPayload, dispatchOptions = {}
7356
7357
  mergeToolResultForClaude(anthropicPayload, { skipLastMessage: compactType === 1 });
7357
7358
  applyLastMessageCacheControl(anthropicPayload, lastMessageCacheControl);
7358
7359
  }
7359
- const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
7360
+ const requestId = dispatchOptions.requestId ?? generateRequestIdFromPayload(anthropicPayload, sessionId);
7360
7361
  logger$9.debug("Generated request ID:", requestId);
7361
7362
  if (!sessionId) sessionId = getUUID(requestId);
7362
7363
  logger$9.debug("Extracted session ID:", sessionId);
@@ -7449,6 +7450,10 @@ const DEFAULT_REASONING_EFFORTS = [
7449
7450
  "max",
7450
7451
  "ultra"
7451
7452
  ];
7453
+ const CODEX_ALIAS_PRIORITY_BASE = 1e3;
7454
+ const COPILOT_PRIORITY_BASE = 2e3;
7455
+ const OPENCODE_GO_PRIORITY_BASE = 3e3;
7456
+ const PROVIDER_PRIORITY_BASE = 4e3;
7452
7457
  const DEFAULT_CODEX_TEMPLATE = {
7453
7458
  slug: "gpt-5.6-sol",
7454
7459
  display_name: "GPT-5.6-Sol",
@@ -7702,25 +7707,33 @@ async function handleMergedCodexModels(c, candidatesRequest, options = {}) {
7702
7707
  const template = selectTemplate(upstreamModels);
7703
7708
  const catalogModelsBySlug = new Map(upstreamModels.map((model) => [model.slug, model]));
7704
7709
  const seenSlugs = new Set(upstreamModels.map((model) => model.slug));
7705
- const codexProviderAliases = options.includeCodexProviderAliases ? upstreamModels.flatMap((model) => {
7710
+ const codexProviderAliases = options.includeCodexProviderAliases ? upstreamModels.flatMap((model, index) => {
7706
7711
  const slug = `codex/${model.slug}`;
7707
7712
  if (seenSlugs.has(slug)) return [];
7708
7713
  seenSlugs.add(slug);
7709
- return [createCatalogAlias(model, slug, options.codexProviderName)];
7714
+ return [{
7715
+ ...createCatalogAlias(model, slug, options.codexProviderName),
7716
+ priority: CODEX_ALIAS_PRIORITY_BASE + index
7717
+ }];
7710
7718
  }) : [];
7711
7719
  const syntheticModels = candidates.filter((candidate) => !seenSlugs.has(candidate.slug)).flatMap((candidate, index) => {
7720
+ const priorityBase = getCandidatePriorityBase(candidate);
7712
7721
  const catalogModel = candidate.catalogSlug ? catalogModelsBySlug.get(candidate.catalogSlug) : void 0;
7713
- if (catalogModel) return [createCatalogAlias(catalogModel, candidate.slug, candidate.providerName)];
7722
+ if (catalogModel) return [{
7723
+ ...createCatalogAlias(catalogModel, candidate.slug, candidate.providerName),
7724
+ priority: priorityBase + index
7725
+ }];
7714
7726
  if (candidate.catalogMatchRequired) return [];
7715
- return [createSyntheticCodexModel(candidate, template, upstreamModels.length + index)];
7727
+ return [createSyntheticCodexModel(candidate, template, priorityBase + index)];
7716
7728
  });
7729
+ const models = [
7730
+ ...upstreamModels,
7731
+ ...codexProviderAliases,
7732
+ ...syntheticModels
7733
+ ].sort((a, b) => getModelPriority(a) - getModelPriority(b));
7717
7734
  const response = {
7718
7735
  ...upstreamCatalog ?? {},
7719
- models: [
7720
- ...upstreamModels,
7721
- ...codexProviderAliases,
7722
- ...syntheticModels
7723
- ]
7736
+ models
7724
7737
  };
7725
7738
  debugJson(logger$8, "models.codex.merged_response", {
7726
7739
  upstreamCount: upstreamModels.length,
@@ -7823,6 +7836,14 @@ async function tryGetCodexCatalog(c) {
7823
7836
  function selectTemplate(models) {
7824
7837
  return models.find((model) => model.visibility === "list" && model.supported_in_api !== false) ?? models[0] ?? DEFAULT_CODEX_TEMPLATE;
7825
7838
  }
7839
+ function getModelPriority(model) {
7840
+ return typeof model.priority === "number" && Number.isFinite(model.priority) ? model.priority : 0;
7841
+ }
7842
+ function getCandidatePriorityBase(candidate) {
7843
+ if (!candidate.providerName) return COPILOT_PRIORITY_BASE;
7844
+ if (candidate.providerName === "opencode-go") return OPENCODE_GO_PRIORITY_BASE;
7845
+ return PROVIDER_PRIORITY_BASE;
7846
+ }
7826
7847
  function isCodexModelsResponse(value) {
7827
7848
  if (!isRecord$2(value) || !Array.isArray(value.models)) return false;
7828
7849
  return value.models.every((model) => isRecord$2(model) && typeof model.slug === "string");
@@ -7960,7 +7981,7 @@ async function getSyntheticCodexModels(requestHeaders, providers) {
7960
7981
  function getCopilotCodexCandidates() {
7961
7982
  const candidates = [];
7962
7983
  for (const model of state.models?.data ?? []) try {
7963
- if (isCopilotMessagesFallbackModel(model)) candidates.push(createCopilotCodexCandidate(model));
7984
+ if (isCopilotCodexCandidate(model)) candidates.push(createCopilotCodexCandidate(model));
7964
7985
  } catch (error) {
7965
7986
  logger$7.warn("models.codex.copilot_skip_error", {
7966
7987
  modelId: model.id,
@@ -7969,17 +7990,17 @@ function getCopilotCodexCandidates() {
7969
7990
  }
7970
7991
  return candidates;
7971
7992
  }
7972
- function isCopilotMessagesFallbackModel(model) {
7973
- const endpoints = model.supported_endpoints ?? [];
7974
- return endpoints.some((endpoint) => endpoint === MESSAGES_ENDPOINT || endpoint === CHAT_COMPLETIONS_ENDPOINT) && !endpoints.some((endpoint) => RESPONSES_ENDPOINTS.has(endpoint)) && model.capabilities.supports.tool_calls !== false;
7993
+ function isCopilotCodexCandidate(model) {
7994
+ return (model.supported_endpoints ?? []).some((endpoint) => endpoint === MESSAGES_ENDPOINT || endpoint === CHAT_COMPLETIONS_ENDPOINT || RESPONSES_ENDPOINTS.has(endpoint)) && model.capabilities.supports.tool_calls !== false;
7975
7995
  }
7976
7996
  function createCopilotCodexCandidate(model) {
7977
7997
  const reasoningEfforts = normalizeReasoningEfforts(model.capabilities.supports.reasoning_effort);
7998
+ const usesNativeResponses = model.supported_endpoints?.some((endpoint) => RESPONSES_ENDPOINTS.has(endpoint));
7978
7999
  const usesNativeMessages = model.supported_endpoints?.includes(MESSAGES_ENDPOINT);
7979
8000
  return {
7980
8001
  slug: toClientModelId(model.id),
7981
8002
  displayName: model.name,
7982
- description: usesNativeMessages ? `${model.name} through the Copilot Messages adapter.` : `${model.name} through the Copilot Messages-to-Chat adapter.`,
8003
+ description: usesNativeResponses ? `${model.name} through the Copilot Responses API.` : usesNativeMessages ? `${model.name} through the Copilot Messages adapter.` : `${model.name} through the Copilot Messages-to-Chat adapter.`,
7983
8004
  contextWindow: positiveNumber(model.capabilities.limits.max_context_window_tokens, 256e3),
7984
8005
  maxOutputTokens: positiveNumber(model.capabilities.limits.max_output_tokens, 32e3),
7985
8006
  inputModalities: model.capabilities.supports.vision ? ["text", "image"] : ["text"],
@@ -9743,7 +9764,10 @@ async function handleResponsesViaMessages(c, options) {
9743
9764
  skipClaudeAutoModel: true,
9744
9765
  skipModelMapping: true,
9745
9766
  skipWebSearch: true,
9746
- usageEndpoint: "responses"
9767
+ usageEndpoint: "responses",
9768
+ subagentMarker: options.subagentMarker,
9769
+ requestId: options.requestId,
9770
+ sessionId: options.sessionId
9747
9771
  });
9748
9772
  if (!messagesResponse.ok) return messagesResponse;
9749
9773
  if ((messagesResponse.headers.get("content-type") ?? "").includes("text/event-stream")) {
@@ -10007,24 +10031,25 @@ const handleResponses = async (c) => {
10007
10031
  const selectedModel = responsesHandlerDependencies.findEndpointModel(payload.model);
10008
10032
  payload.model = selectedModel?.id ?? payload.model;
10009
10033
  const responsesTransport = getResponsesTransportForModel(selectedModel);
10010
- if (!responsesTransport) {
10011
- const supportedEndpoints = selectedModel?.supported_endpoints ?? [];
10012
- if (supportedEndpoints.includes("/v1/messages") || supportedEndpoints.includes("/chat/completions")) return await handleResponsesViaMessages(c, {
10013
- payload,
10014
- publicModel: requestedModel,
10015
- targetModel: payload.model
10016
- });
10017
- return c.json({ error: {
10018
- message: "This model does not support the responses endpoint. Please choose a different model.",
10019
- type: "invalid_request_error"
10020
- } }, 400);
10021
- }
10034
+ if (shouldFallbackToMessages(c, payload.model, selectedModel, responsesTransport)) return await handleResponsesViaMessages(c, {
10035
+ payload,
10036
+ publicModel: requestedModel,
10037
+ targetModel: payload.model,
10038
+ subagentMarker,
10039
+ requestId,
10040
+ sessionId: fallbackSessionId
10041
+ });
10042
+ if (!responsesTransport) return c.json({ error: {
10043
+ message: "This model does not support the responses endpoint. Please choose a different model.",
10044
+ type: "invalid_request_error"
10045
+ } }, 400);
10022
10046
  const recordUsage = createCopilotTokenUsageRecorder({
10023
10047
  endpoint: "responses",
10024
10048
  fallbackSessionId,
10025
10049
  model: payload.model
10026
10050
  });
10027
10051
  removeUnsupportedTools(payload);
10052
+ fillEmptyNamespaceToolDescriptions(payload);
10028
10053
  if (!responsesHandlerDependencies.isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
10029
10054
  const sanitizedImageCount = sanitizeOversizedInputImages(payload, selectedModel?.capabilities.limits.vision?.max_prompt_image_size);
10030
10055
  if (sanitizedImageCount > 0) logger$1.warn(`Omitted ${sanitizedImageCount} oversized input image(s) before forwarding to Copilot Responses`);
@@ -10078,6 +10103,12 @@ const handleResponses = async (c) => {
10078
10103
  return c.json(result);
10079
10104
  };
10080
10105
  const isStreamingRequested = (payload) => Boolean(payload.stream);
10106
+ const shouldFallbackToMessages = (c, modelId, selectedModel, responsesTransport) => {
10107
+ if (isCodexUserAgent(c.req.header("user-agent"))) return !modelId.startsWith("gpt");
10108
+ if (responsesTransport) return false;
10109
+ const supportedEndpoints = selectedModel?.supported_endpoints ?? [];
10110
+ return supportedEndpoints.includes("/v1/messages") || supportedEndpoints.includes("/chat/completions");
10111
+ };
10081
10112
  const parseResponsesStreamEvent = (chunk) => {
10082
10113
  const data = chunk.data;
10083
10114
  if (!data || data === "[DONE]") return null;
@@ -10110,6 +10141,22 @@ const removeUnsupportedTools = (payload) => {
10110
10141
  });
10111
10142
  if (dropped.length > 0) logger$1.debug("Removed unsupported tools:", dropped);
10112
10143
  };
10144
+ const fillEmptyNamespaceToolDescriptions = (payload) => {
10145
+ fillEmptyNamespaceDescriptions(payload.tools);
10146
+ if (!Array.isArray(payload.input)) return;
10147
+ for (const item of payload.input) {
10148
+ if (!item || typeof item !== "object") continue;
10149
+ fillEmptyNamespaceDescriptions(item.tools);
10150
+ }
10151
+ };
10152
+ const fillEmptyNamespaceDescriptions = (tools) => {
10153
+ if (!Array.isArray(tools)) return;
10154
+ for (const tool of tools) {
10155
+ if (!tool || typeof tool !== "object") continue;
10156
+ const namespaceTool = tool;
10157
+ if (namespaceTool.type === "namespace" && namespaceTool.description === "" && typeof namespaceTool.name === "string") namespaceTool.description = namespaceTool.name;
10158
+ }
10159
+ };
10113
10160
  const getIncomingResponsesSessionId = (c) => getTrimmedHeader(c, "session-id") ?? getTrimmedHeader(c, "x-session-id");
10114
10161
  const codexSubagentHeaderValues = new Set([
10115
10162
  "collab_spawn",
@@ -10258,4 +10305,4 @@ server.route("/:provider/images", providerImageRoutes);
10258
10305
  //#endregion
10259
10306
  export { server };
10260
10307
 
10261
- //# sourceMappingURL=server---R3M8xj.js.map
10308
+ //# sourceMappingURL=server-CF6ryUB1.js.map