@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 +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/main.js +1 -1
- package/dist/{server-m80zRYma.js → server-fiF0jU-7.js} +29 -13
- package/dist/{server-m80zRYma.js.map → server-fiF0jU-7.js.map} +1 -1
- package/dist/{start-D1lA7Gjm.js → start-BaYrtsEL.js} +2 -2
- package/dist/{start-D1lA7Gjm.js.map → start-BaYrtsEL.js.map} +1 -1
- package/package.json +1 -1
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-
|
|
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))
|
|
10527
|
-
payload,
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
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-
|
|
10811
|
+
//# sourceMappingURL=server-fiF0jU-7.js.map
|