@jeffreycao/copilot-api 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/README.zh-CN.md +7 -0
- package/dist/main.js +1 -1
- package/dist/{server-BDdqK9ps.js → server-DcL9pgmS.js} +68 -7
- package/dist/server-DcL9pgmS.js.map +1 -0
- package/dist/{start-BZqWghY0.js → start-D3oRc7UM.js} +2 -2
- package/dist/{start-BZqWghY0.js.map → start-D3oRc7UM.js.map} +1 -1
- package/package.json +1 -1
- package/dist/server-BDdqK9ps.js.map +0 -1
package/README.md
CHANGED
|
@@ -401,6 +401,11 @@ request_max_retries = 3
|
|
|
401
401
|
stream_max_retries = 1
|
|
402
402
|
stream_idle_timeout_ms = 300000
|
|
403
403
|
|
|
404
|
+
[features.code_mode]
|
|
405
|
+
excluded_tool_namespaces = [
|
|
406
|
+
"mcp__codex_apps__sites"
|
|
407
|
+
]
|
|
408
|
+
|
|
404
409
|
[features]
|
|
405
410
|
remote_compaction_v2 = true
|
|
406
411
|
|
|
@@ -410,6 +415,8 @@ enabled = false
|
|
|
410
415
|
|
|
411
416
|
> [!NOTE]
|
|
412
417
|
> `name` must be set to `"OpenAI"`.
|
|
418
|
+
>
|
|
419
|
+
> For models that do not support `tool_search`, we recommend disabling `mcp__codex_apps__sites` by adding it to `features.code_mode.excluded_tool_namespaces` as shown above. Otherwise, each prompt may consume more than 10,000 additional tokens.
|
|
413
420
|
|
|
414
421
|
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`: `/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.
|
|
415
422
|
|
package/README.zh-CN.md
CHANGED
|
@@ -429,6 +429,11 @@ request_max_retries = 3
|
|
|
429
429
|
stream_max_retries = 1
|
|
430
430
|
stream_idle_timeout_ms = 300000
|
|
431
431
|
|
|
432
|
+
[features.code_mode]
|
|
433
|
+
excluded_tool_namespaces = [
|
|
434
|
+
"mcp__codex_apps__sites"
|
|
435
|
+
]
|
|
436
|
+
|
|
432
437
|
[features]
|
|
433
438
|
remote_compaction_v2 = true
|
|
434
439
|
|
|
@@ -438,6 +443,8 @@ enabled = false
|
|
|
438
443
|
|
|
439
444
|
> [!NOTE]
|
|
440
445
|
> `name` 一定要配置为 `"OpenAI"`。
|
|
446
|
+
>
|
|
447
|
+
> 对于不支持 `tool_search` 的模型,建议按上面的配置将 `mcp__codex_apps__sites` 添加到 `features.code_mode.excluded_tool_namespaces` 中。否则每次提问可能会额外消耗 1 万多个 tokens。
|
|
441
448
|
|
|
442
449
|
Codex 客户端(`User-Agent` 以 `codex` 开头)请求顶层 `GET /v1/models` 时,网关会把原生 Codex 模型与可通过 Messages 适配的模型合并返回。后者会声明 `use_responses_lite: true`:调用 `/v1/responses` 后,Anthropic provider 走 **Responses → Messages**,OpenAI 兼容 provider 以及只支持 Chat 的 Copilot 模型则复用现有 Messages 路由继续走 **Responses → Messages → Chat Completions**,最终统一翻译回 Responses(包括流式事件)。
|
|
443
450
|
|
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-
|
|
28
|
+
const { start } = await import("./start-D3oRc7UM.js");
|
|
29
29
|
await runMain(defineCommand({
|
|
30
30
|
meta: {
|
|
31
31
|
name: "copilot-api",
|
|
@@ -2562,9 +2562,11 @@ async function forwardCodexAlphaSearchRequest(request) {
|
|
|
2562
2562
|
return createProviderProxyResponse(upstreamResponse);
|
|
2563
2563
|
}
|
|
2564
2564
|
function createAlphaSearchRequest(request, payload) {
|
|
2565
|
-
return new Request(request, {
|
|
2565
|
+
return new Request(request.url, {
|
|
2566
2566
|
body: JSON.stringify(payload),
|
|
2567
|
-
|
|
2567
|
+
headers: request.headers,
|
|
2568
|
+
method: request.method,
|
|
2569
|
+
signal: request.signal
|
|
2568
2570
|
});
|
|
2569
2571
|
}
|
|
2570
2572
|
async function handleCodexRequest(c, request, resolvedProviderConfig) {
|
|
@@ -2609,7 +2611,10 @@ async function handleAlphaSearchRequest(c, resolvedProviderConfig) {
|
|
|
2609
2611
|
if (providerModelAlias.provider === "codex") return await handleCodexRequest(c, createAlphaSearchRequest(c.req.raw, payload));
|
|
2610
2612
|
}
|
|
2611
2613
|
if (isAlphaSearchCodexPriorityEnabled()) {
|
|
2612
|
-
if (await resolveProviderConfig("codex"))
|
|
2614
|
+
if (await resolveProviderConfig("codex")) {
|
|
2615
|
+
if (!payload.model.startsWith("gpt")) payload.model = "gpt-5.6-luna";
|
|
2616
|
+
return await forwardCodexAlphaSearchRequest(createAlphaSearchRequest(c.req.raw, payload));
|
|
2617
|
+
}
|
|
2613
2618
|
}
|
|
2614
2619
|
const messagesBackedModel = await isMessagesBackedModel(resolvedRequestedModel);
|
|
2615
2620
|
if (messagesBackedModel) {
|
|
@@ -8134,6 +8139,7 @@ function translateResponsesToMessages(payload, options) {
|
|
|
8134
8139
|
content: MESSAGES_COMPACTION_PROMPT
|
|
8135
8140
|
});
|
|
8136
8141
|
if (messages.length === 0) throw new ResponsesMessagesTranslationError("Responses input must contain at least one translatable message");
|
|
8142
|
+
applyEphemeralCacheControl(messages, system);
|
|
8137
8143
|
const reasoningEffort = translateReasoningEffort(payload.reasoning?.effort);
|
|
8138
8144
|
const messagesPayload = {
|
|
8139
8145
|
model: options.model,
|
|
@@ -8660,6 +8666,24 @@ function resolveMetadataUserId(payload) {
|
|
|
8660
8666
|
if (payload.safety_identifier?.trim()) return payload.safety_identifier;
|
|
8661
8667
|
if (payload.prompt_cache_key?.trim()) return payload.prompt_cache_key;
|
|
8662
8668
|
}
|
|
8669
|
+
const EPHEMERAL_CACHE_CONTROL = { type: "ephemeral" };
|
|
8670
|
+
function applyEphemeralCacheControl(messages, system) {
|
|
8671
|
+
const lastSystemBlock = system.at(-1);
|
|
8672
|
+
if (lastSystemBlock) lastSystemBlock.cache_control = { ...EPHEMERAL_CACHE_CONTROL };
|
|
8673
|
+
const lastMessage = messages.at(-1);
|
|
8674
|
+
if (!lastMessage) return;
|
|
8675
|
+
if (typeof lastMessage.content === "string") {
|
|
8676
|
+
lastMessage.content = [{
|
|
8677
|
+
type: "text",
|
|
8678
|
+
text: lastMessage.content,
|
|
8679
|
+
cache_control: { ...EPHEMERAL_CACHE_CONTROL }
|
|
8680
|
+
}];
|
|
8681
|
+
return;
|
|
8682
|
+
}
|
|
8683
|
+
const lastBlock = lastMessage.content.at(-1);
|
|
8684
|
+
if (!lastBlock || lastBlock.type === "thinking") return;
|
|
8685
|
+
lastBlock.cache_control = { ...EPHEMERAL_CACHE_CONTROL };
|
|
8686
|
+
}
|
|
8663
8687
|
function appendAssistantBlock(messages, block) {
|
|
8664
8688
|
const last = messages.at(-1);
|
|
8665
8689
|
if (last?.role === "assistant" && Array.isArray(last.content)) {
|
|
@@ -8772,6 +8796,9 @@ var CustomToolInputStreamDecoder = class {
|
|
|
8772
8796
|
prefixTokenOffset = 0;
|
|
8773
8797
|
safeInputLength = 0;
|
|
8774
8798
|
state = "prefix";
|
|
8799
|
+
trailingDepth = 0;
|
|
8800
|
+
trailingEscaped = false;
|
|
8801
|
+
trailingInString = false;
|
|
8775
8802
|
unicodeDigitsRemaining = 0;
|
|
8776
8803
|
append(partialJson) {
|
|
8777
8804
|
if (this.failed) return this.fail("decoder is already in a failed state");
|
|
@@ -8807,8 +8834,42 @@ var CustomToolInputStreamDecoder = class {
|
|
|
8807
8834
|
}
|
|
8808
8835
|
if (this.state === "suffix") {
|
|
8809
8836
|
if (isJsonWhitespace(char)) return;
|
|
8810
|
-
if (char
|
|
8811
|
-
|
|
8837
|
+
if (char === "}") {
|
|
8838
|
+
this.state = "done";
|
|
8839
|
+
return;
|
|
8840
|
+
}
|
|
8841
|
+
if (char === ",") {
|
|
8842
|
+
this.state = "trailing";
|
|
8843
|
+
this.trailingDepth = 1;
|
|
8844
|
+
return;
|
|
8845
|
+
}
|
|
8846
|
+
return this.fail("expected \"}\" or \",\" after the input string");
|
|
8847
|
+
}
|
|
8848
|
+
if (this.state === "trailing") {
|
|
8849
|
+
if (this.trailingInString) {
|
|
8850
|
+
if (this.trailingEscaped) {
|
|
8851
|
+
this.trailingEscaped = false;
|
|
8852
|
+
return;
|
|
8853
|
+
}
|
|
8854
|
+
if (char === "\\") {
|
|
8855
|
+
this.trailingEscaped = true;
|
|
8856
|
+
return;
|
|
8857
|
+
}
|
|
8858
|
+
if (char === "\"") this.trailingInString = false;
|
|
8859
|
+
return;
|
|
8860
|
+
}
|
|
8861
|
+
if (char === "\"") {
|
|
8862
|
+
this.trailingInString = true;
|
|
8863
|
+
return;
|
|
8864
|
+
}
|
|
8865
|
+
if (char === "{" || char === "[") {
|
|
8866
|
+
this.trailingDepth += 1;
|
|
8867
|
+
return;
|
|
8868
|
+
}
|
|
8869
|
+
if (char === "}" || char === "]") {
|
|
8870
|
+
this.trailingDepth -= 1;
|
|
8871
|
+
if (this.trailingDepth === 0) this.state = "done";
|
|
8872
|
+
}
|
|
8812
8873
|
return;
|
|
8813
8874
|
}
|
|
8814
8875
|
if (this.state === "done") {
|
|
@@ -8869,7 +8930,7 @@ function isJsonWhitespace(char) {
|
|
|
8869
8930
|
}
|
|
8870
8931
|
//#endregion
|
|
8871
8932
|
//#region src/routes/responses/messages-stream-translation.ts
|
|
8872
|
-
const EMPTY_SIGNATURE_ENCRYPTED_CONTENT = "
|
|
8933
|
+
const EMPTY_SIGNATURE_ENCRYPTED_CONTENT = "";
|
|
8873
8934
|
async function* translateMessagesStream(chunks, context) {
|
|
8874
8935
|
const state = createTranslationState(context);
|
|
8875
8936
|
try {
|
|
@@ -10062,4 +10123,4 @@ server.route("/:provider/images", providerImageRoutes);
|
|
|
10062
10123
|
//#endregion
|
|
10063
10124
|
export { server };
|
|
10064
10125
|
|
|
10065
|
-
//# sourceMappingURL=server-
|
|
10126
|
+
//# sourceMappingURL=server-DcL9pgmS.js.map
|