@jeffreycao/copilot-api 2.3.11 → 2.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -310,6 +310,8 @@ Without this configuration, Codex cannot fetch `/v1/models` while not signed in
310
310
 
311
311
  When a Codex client (`User-Agent` starts with `codex`) requests the top-level `GET /v1/models`, the gateway merges native Codex models with models available through the Messages adapter. The latter advertise `use_responses_lite: true`, except DeepSeek models, which use `use_responses_lite: false` and `tool_mode: null`. For other models, `/v1/responses` uses **Responses → Messages** for Anthropic providers, while OpenAI-compatible providers and Chat-only Copilot models reuse the existing Messages route for **Responses → Messages → Chat Completions**, then translate streaming or JSON results back to Responses.
312
312
 
313
+ > **Note:** DeepSeek models do not use Responses Lite (`use_responses_lite: false`, `tool_mode: null`), so the tool set they advertise to Codex differs from other models, which use `tool_mode: "code_mode_only"`. Switching between a DeepSeek model and a Responses Lite model mid-session is not compatible, because tool calls and conversation history produced under one tool set do not translate to the other. Start a new Codex session when switching between them.
314
+
313
315
  The merged catalog is what Codex shows in its model picker, including the models exposed by your configured providers:
314
316
 
315
317
  <img src="./docs/screenshots/codex-models.png" alt="Codex model picker showing models provided by the gateway" width="900" />
package/README.zh-CN.md CHANGED
@@ -326,6 +326,8 @@ args = [
326
326
 
327
327
  Codex 客户端(`User-Agent` 以 `codex` 开头)请求顶层 `GET /v1/models` 时,网关会把原生 Codex 模型与可通过 Messages 适配的模型合并返回。除 DeepSeek 模型外,后者会声明 `use_responses_lite: true`;DeepSeek 模型使用 `use_responses_lite: false` 和 `tool_mode: null`。调用 `/v1/responses` 后,Anthropic provider 走 **Responses → Messages**,OpenAI 兼容 provider 以及只支持 Chat 的 Copilot 模型则复用现有 Messages 路由继续走 **Responses → Messages → Chat Completions**,最终统一翻译回 Responses(包括流式事件)。
328
328
 
329
+ > **注意:** DeepSeek 模型不使用 Responses Lite(`use_responses_lite: false`、`tool_mode: null`),因此向 Codex 暴露的工具集合与其他模型(`tool_mode: "code_mode_only"`)不一致。在会话中途切换 DeepSeek 模型与 Responses Lite 模型并不兼容——一套工具集合下产生的工具调用和会话历史无法直接沿用到另一套。切换模型时请新建 Codex 会话。
330
+
329
331
  合并后的模型列表会直接展示在 Codex 的模型选择界面中,包含各 provider 暴露的模型:
330
332
 
331
333
  <img src="./docs/screenshots/codex-models.png" alt="Codex 模型选择界面展示网关提供的模型列表" width="900" />
package/dist/main.js CHANGED
@@ -30,7 +30,7 @@ if (isMcpFastPath(process.argv)) {
30
30
  const { auth } = await import("./auth-DgKX2oyO.js");
31
31
  const { debug } = await import("./debug-BHOitPm3.js");
32
32
  const { mcp } = await import("./mcp-fpSlKZxK.js");
33
- const { start } = await import("./start-D1lA7Gjm.js");
33
+ const { start } = await import("./start-BaYrtsEL.js");
34
34
  await runMain(defineCommand({
35
35
  meta: {
36
36
  name: "copilot-api",
@@ -8697,6 +8697,9 @@ providerModelRoutes.get("/", async (c) => {
8697
8697
  //#endregion
8698
8698
  //#region src/routes/responses/messages-translation.ts
8699
8699
  const MESSAGES_COMPACTION_PREFIX = "copilot-api:messages-compaction:v1:";
8700
+ const MESSAGES_REASONING_ID_SUFFIX = "__a1";
8701
+ const markMessagesReasoningId = (id) => `${id}${MESSAGES_REASONING_ID_SUFFIX}`;
8702
+ const isMessagesReasoningId = (id) => typeof id === "string" && id.endsWith(MESSAGES_REASONING_ID_SUFFIX);
8700
8703
  const MESSAGES_COMPACTION_PROMPT = [
8701
8704
  "You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.",
8702
8705
  "Do NOT continue the task, make changes, or call any tools. Your only output must be the handoff summary.",
@@ -9206,7 +9209,7 @@ function translateAssistantOutput(response, registry) {
9206
9209
  for (const [index, block] of response.content.entries()) {
9207
9210
  if (block.type === "thinking") {
9208
9211
  output.push({
9209
- id: `rs_${createStableHash(`${response.id}:${index}:reasoning`)}`,
9212
+ id: markMessagesReasoningId(`rs_${createStableHash(`${response.id}:${index}:reasoning`)}`),
9210
9213
  type: "reasoning",
9211
9214
  status: "completed",
9212
9215
  ...block.thinking && block.thinking !== "Thinking..." ? { summary: [{
@@ -9238,7 +9241,6 @@ function translateAssistantOutput(response, registry) {
9238
9241
  function translateToolUseOutput(block, registry, idSeed) {
9239
9242
  const descriptor = resolveToolDescriptor(registry, block.name);
9240
9243
  const common = {
9241
- id: `fc_${createStableHash(idSeed)}`,
9242
9244
  call_id: block.id,
9243
9245
  name: descriptor.name,
9244
9246
  status: "completed",
@@ -9246,11 +9248,13 @@ function translateToolUseOutput(block, registry, idSeed) {
9246
9248
  };
9247
9249
  if (descriptor.kind === "custom") return {
9248
9250
  ...common,
9251
+ id: `ctc_${createStableHash(idSeed)}`,
9249
9252
  type: "custom_tool_call",
9250
9253
  input: decodeCustomToolInput(block.input)
9251
9254
  };
9252
9255
  return {
9253
9256
  ...common,
9257
+ id: `fc_${createStableHash(idSeed)}`,
9254
9258
  type: "function_call",
9255
9259
  arguments: JSON.stringify(block.input)
9256
9260
  };
@@ -9845,7 +9849,7 @@ function* startContentBlock(state, event) {
9845
9849
  }
9846
9850
  if (block.type === "thinking") {
9847
9851
  const item = {
9848
- id: `rs_${state.responseId.slice(-18)}_${event.index}`,
9852
+ id: markMessagesReasoningId(`rs_${state.responseId.slice(-18)}_${event.index}`),
9849
9853
  type: "reasoning",
9850
9854
  status: "in_progress",
9851
9855
  summary: [],
@@ -9872,7 +9876,6 @@ function* startContentBlock(state, event) {
9872
9876
  if (block.type === "tool_use") {
9873
9877
  const descriptor = resolveToolDescriptor(state.context.registry, block.name);
9874
9878
  const common = {
9875
- id: `fc_${state.responseId.slice(-18)}_${event.index}`,
9876
9879
  call_id: block.id,
9877
9880
  name: descriptor.name,
9878
9881
  status: "in_progress",
@@ -9881,6 +9884,7 @@ function* startContentBlock(state, event) {
9881
9884
  if (descriptor.kind === "custom") {
9882
9885
  const item = {
9883
9886
  ...common,
9887
+ id: `ctc_${state.responseId.slice(-18)}_${event.index}`,
9884
9888
  type: "custom_tool_call",
9885
9889
  input: ""
9886
9890
  };
@@ -9910,6 +9914,7 @@ function* startContentBlock(state, event) {
9910
9914
  }
9911
9915
  const item = {
9912
9916
  ...common,
9917
+ id: `fc_${state.responseId.slice(-18)}_${event.index}`,
9913
9918
  type: "function_call",
9914
9919
  arguments: ""
9915
9920
  };
@@ -10523,18 +10528,22 @@ const handleResponses = async (c) => {
10523
10528
  const normalizedReasoningEffort = normalizeResponsesReasoningEffort(payload, selectedModel?.capabilities?.supports?.reasoning_effort);
10524
10529
  if (normalizedReasoningEffort) logger$1.debug(`Normalized reasoning effort from ${normalizedReasoningEffort.from} to ${normalizedReasoningEffort.to} based on the selected model capabilities`);
10525
10530
  const responsesTransport = getResponsesTransportForModel(selectedModel);
10526
- if (shouldFallbackToMessages(c, payload.model, selectedModel, responsesTransport)) return await handleResponsesViaMessages(c, {
10527
- payload,
10528
- publicModel: requestedModel,
10529
- targetModel: payload.model,
10530
- subagentMarker,
10531
- requestId,
10532
- sessionId: fallbackSessionId
10533
- });
10531
+ if (shouldFallbackToMessages(c, payload.model, selectedModel, responsesTransport)) {
10532
+ filterReasoningForTransport(payload, true);
10533
+ return await handleResponsesViaMessages(c, {
10534
+ payload,
10535
+ publicModel: requestedModel,
10536
+ targetModel: payload.model,
10537
+ subagentMarker,
10538
+ requestId,
10539
+ sessionId: fallbackSessionId
10540
+ });
10541
+ }
10534
10542
  if (!responsesTransport) return c.json({ error: {
10535
10543
  message: "This model does not support the responses endpoint. Please choose a different model.",
10536
10544
  type: "invalid_request_error"
10537
10545
  } }, 400);
10546
+ filterReasoningForTransport(payload, false);
10538
10547
  const recordUsage = createCopilotTokenUsageRecorder({
10539
10548
  endpoint: "responses",
10540
10549
  fallbackSessionId,
@@ -10605,6 +10614,13 @@ const handleResponses = async (c) => {
10605
10614
  return c.json(result);
10606
10615
  };
10607
10616
  const isStreamingRequested = (payload) => Boolean(payload.stream);
10617
+ const filterReasoningForTransport = (payload, useMessagesFallback) => {
10618
+ if (!Array.isArray(payload.input)) return;
10619
+ payload.input = payload.input.filter((item) => {
10620
+ if (item.type !== "reasoning") return true;
10621
+ return isMessagesReasoningId(item.id) === useMessagesFallback;
10622
+ });
10623
+ };
10608
10624
  const shouldFallbackToMessages = (c, modelId, selectedModel, responsesTransport) => {
10609
10625
  if (isCodexUserAgent(c.req.header("user-agent"))) return !(modelId.startsWith("gpt") || modelId.startsWith("codex"));
10610
10626
  if (responsesTransport) return false;
@@ -10792,4 +10808,4 @@ server.route("/:provider/images", providerImageRoutes);
10792
10808
  //#endregion
10793
10809
  export { server };
10794
10810
 
10795
- //# sourceMappingURL=server-m80zRYma.js.map
10811
+ //# sourceMappingURL=server-fiF0jU-7.js.map