@jeffreycao/copilot-api 1.10.23 → 1.10.24

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
@@ -16,9 +16,7 @@ English | [简体中文](./README.zh-CN.md)
16
16
  >
17
17
  > 3. **Built-in `codex` provider:** Run `npx @jeffreycao/copilot-api@latest auth login --provider codex` once and the gateway will persist and refresh Codex OAuth credentials automatically.
18
18
  >
19
- > 4. **Disable multi agent when using codex:** If you're using codex via GitHub Copilot, disable multi agent. Copilot currently charges codex traffic based on whether the last message is a user role, and that billing logic has not been adjusted.
20
- >
21
- > 5. **Note:** See [GitHub Copilot Security Notice](./NOTICE.md#github-copilot-security-notice) for the warning removed from the README header.
19
+ > 4. **Note:** See [GitHub Copilot Security Notice](./NOTICE.md#github-copilot-security-notice) for the warning removed from the README header.
22
20
 
23
21
  ---
24
22
 
@@ -94,7 +92,7 @@ https://github.com/caozhiyuan/copilot-api/releases
94
92
 
95
93
  Download the installer for your platform, sign in inside the app, choose a port, start the server, then point your client at the local endpoint shown in the app. Packaged desktop builds use the bundled Electron runtime, so normal desktop usage does not require installing Node.js separately. Token usage history is enabled when that bundled runtime supports SQLite.
96
94
 
97
- The desktop app's Advanced Config page reads and writes model mappings through `GET/POST /admin/config/model-mappings`. It uses `auth.adminApiKey` instead of the regular `auth.apiKeys`, and the app reads that key directly from `config.json` after the server has generated it on startup.
95
+ The desktop app's Advanced Config page reads and writes the shared model mappings through `GET/POST /admin/config/model-mappings`. The same mappings apply across `POST /v1/messages`, `POST /v1/messages/count_tokens`, `POST /v1/responses`, and `POST /v1/chat/completions` instead of being split per interface. It uses `auth.adminApiKey` instead of the regular `auth.apiKeys`, and the app reads that key directly from `config.json` after the server has generated it on startup.
98
96
 
99
97
  ### Desktop App Screenshots
100
98
 
@@ -195,14 +193,7 @@ The following command line options are available for the `start` command:
195
193
  "enabled": true,
196
194
  "baseUrl": "your-base-url",
197
195
  "apiKey": "sk-your-provider-key",
198
- "authType": "x-api-key",
199
- "adjustInputTokens": false,
200
- "models": {
201
- "kimi-k2.5": {
202
- "temperature": 1,
203
- "topP": 0.95
204
- }
205
- }
196
+ "authType": "x-api-key"
206
197
  },
207
198
  "dashscope": {
208
199
  "type": "openai-compatible",
@@ -216,8 +207,7 @@ The following command line options are available for the `start` command:
216
207
  "topK": 20,
217
208
  "extraBody": {
218
209
  "preserve_thinking": true
219
- },
220
- "contextCache": true
210
+ }
221
211
  },
222
212
  "glm-5.1": {
223
213
  "temperature": 0.7,
@@ -252,7 +242,7 @@ The following command line options are available for the `start` command:
252
242
  ```
253
243
  - **auth.apiKeys:** API keys used for request authentication on non-admin routes. Supports multiple keys for rotation. Requests can authenticate with either `x-api-key: <key>` or `Authorization: Bearer <key>`. If empty or omitted, authentication for non-admin routes is disabled.
254
244
  - **auth.adminApiKey:** Single admin key used only for `/admin/*` routes. If missing, the server generates a random key at startup and writes it back to `config.json`. Requests use the same `x-api-key` or `Authorization: Bearer` headers, but regular `auth.apiKeys` never grant access to `/admin/*`.
255
- - **modelMappings:** Exact `sourceModel -> targetModel` rewrites for top-level `POST /v1/messages` and `POST /v1/messages/count_tokens` requests. Omit it or leave it as `{}` to disable rewrites. Both the source and target must be non-empty strings. Targets can be regular model IDs or `provider/model` aliases such as `dashscope/qwen3.6-plus`, and the rewrite happens before provider alias parsing. The admin endpoints `GET/POST /admin/config/model-mappings` read and update only this field.
245
+ - **modelMappings:** Exact `sourceModel -> targetModel` rewrites shared by top-level `POST /v1/messages`, `POST /v1/messages/count_tokens`, `POST /v1/responses`, and `POST /v1/chat/completions` requests. Omit it or leave it as `{}` to disable rewrites. Both the source and target must be non-empty strings. Targets can be regular model IDs or `provider/model` aliases such as `dashscope/qwen3.6-plus`, and the rewrite happens before provider alias parsing. These mappings are not split per interface. The admin endpoints `GET/POST /admin/config/model-mappings` read and update only this field.
256
246
  - **extraPrompts:** Map of `model -> prompt` appended to the first system prompt when translating Anthropic-style requests to Copilot. Use this to inject guardrails or guidance per model. Missing default entries are auto-added without overwriting your custom prompts. The built-in prompts for `gpt-5.3-codex` and `gpt-5.4` enable phase-aware commentary, which lets the model emit a short user-facing progress update before tools or deeper reasoning.
257
247
  - **providers:** Global upstream provider map. Each provider key (for example `dashscope`) becomes a route prefix (`/dashscope/v1/messages`). Supports `type: "anthropic"`, `type: "openai-compatible"`, and `type: "openai-responses"`. Top-level clients can also use `model: "dashscope/model-id"` with `/v1/messages`, `/v1/messages/count_tokens`, and `/v1/responses`; the gateway strips the `dashscope/` prefix before forwarding upstream. `GET /v1/models` does not aggregate provider models; use `GET /dashscope/v1/models` for provider model lists.
258
248
  - `enabled` defaults to `true` if omitted.
@@ -520,14 +510,14 @@ Example `~/.config/opencode/opencode.json`:
520
510
  "output": ["text"]
521
511
  },
522
512
  "limit": {
523
- "context": 272000,
513
+ "context": 300000,
524
514
  "output": 128000
525
515
  }
526
516
  },
527
517
  "gpt-5-mini": {
528
518
  "name": "gpt-5-mini",
529
519
  "limit": {
530
- "context": 128000,
520
+ "context": 200000,
531
521
  "output": 64000
532
522
  }
533
523
  },
@@ -539,7 +529,7 @@ Example `~/.config/opencode/opencode.json`:
539
529
  "output": ["text"]
540
530
  },
541
531
  "limit": {
542
- "context": 128000,
532
+ "context": 200000,
543
533
  "output": 32000
544
534
  },
545
535
  "options": {
package/README.zh-CN.md CHANGED
@@ -16,9 +16,7 @@
16
16
  >
17
17
  > 3. **内置 `codex` provider:** 执行一次 `npx @jeffreycao/copilot-api@latest auth login --provider codex` 后,AI gateway 会自动持久化并刷新 Codex OAuth 凭据。
18
18
  >
19
- > 4. **通过 codex 使用时请关闭 multi agent:** 如果你是通过 GitHub Copilot 使用 codex,请关闭 multi agent。当前 Copilot 会按最后一条消息是否为 user role 对 codex 流量计费,而这部分逻辑尚未调整。
20
- >
21
- > 5. **注意事项:** README 顶部移除的 GitHub Copilot warning 见 [GitHub Copilot 安全提示](./NOTICE.md#github-copilot-security-notice)。
19
+ > 4. **注意事项:** README 顶部移除的 GitHub Copilot warning [GitHub Copilot 安全提示](./NOTICE.md#github-copilot-security-notice)。
22
20
 
23
21
  ---
24
22
 
@@ -94,7 +92,7 @@ https://github.com/caozhiyuan/copilot-api/releases
94
92
 
95
93
  下载对应平台的安装包后,在应用内登录、选择端口并启动服务,再把你的客户端指向应用里显示的本地端点即可。发布版桌面应用使用随包内置的 Electron 运行时,正常使用不需要额外安装 Node.js;token usage 历史记录会在该内置运行时支持 SQLite 时启用。
96
94
 
97
- 桌面应用里的高级配置页会通过 `GET/POST /admin/config/model-mappings` 读写模型映射。它使用的是 `auth.adminApiKey`,不是普通的 `auth.apiKeys`;应用会在服务启动并自动生成该 key 后,直接从 `config.json` 读取它来发起请求。
95
+ 桌面应用里的高级配置页会通过 `GET/POST /admin/config/model-mappings` 读写这份共享的模型映射。同一份映射会统一作用于 `POST /v1/messages`、`POST /v1/messages/count_tokens`、`POST /v1/responses` 和 `POST /v1/chat/completions`,不再按接口区分。它使用的是 `auth.adminApiKey`,不是普通的 `auth.apiKeys`;应用会在服务启动并自动生成该 key 后,直接从 `config.json` 读取它来发起请求。
98
96
 
99
97
  ### 桌面应用截图
100
98
 
@@ -197,14 +195,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
197
195
  "enabled": true,
198
196
  "baseUrl": "your-base-url",
199
197
  "apiKey": "sk-your-provider-key",
200
- "authType": "x-api-key",
201
- "adjustInputTokens": false,
202
- "models": {
203
- "kimi-k2.5": {
204
- "temperature": 1,
205
- "topP": 0.95
206
- }
207
- }
198
+ "authType": "x-api-key"
208
199
  },
209
200
  "dashscope": {
210
201
  "type": "openai-compatible",
@@ -218,8 +209,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
218
209
  "topK": 20,
219
210
  "extraBody": {
220
211
  "preserve_thinking": true
221
- },
222
- "contextCache": true
212
+ }
223
213
  },
224
214
  "glm-5.1": {
225
215
  "temperature": 0.7,
@@ -254,7 +244,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
254
244
  ```
255
245
  - **auth.apiKeys:** 用于普通非 admin 路由的 API key。支持多个 key 轮换使用。请求可通过 `x-api-key: <key>` 或 `Authorization: Bearer <key>` 进行认证。若为空或省略,则普通路由的认证会被禁用。
256
246
  - **auth.adminApiKey:** 仅用于 `/admin/*` 路由的单个 admin key。若未配置,服务会在启动时自动生成一个随机 key,并回写到 `config.json`。它同样使用 `x-api-key` 或 `Authorization: Bearer` 这两种头,但普通 `auth.apiKeys` 不能访问 `/admin/*`。
257
- - **modelMappings:** 用于顶层 `POST /v1/messages` 和 `POST /v1/messages/count_tokens` 请求的精确 `sourceModel -> targetModel` 重写映射。省略该字段或保留为 `{}` 时,不会做模型重写。`source` 和 `target` 都必须是非空字符串。`target` 可以是普通模型 ID,也可以是 `provider/model` 形式的别名,例如 `dashscope/qwen3.6-plus`;重写发生在 provider alias 解析之前。`GET/POST /admin/config/model-mappings` 管理接口读写的也只有这个字段。
247
+ - **modelMappings:** 用于顶层 `POST /v1/messages`、`POST /v1/messages/count_tokens`、`POST /v1/responses` 和 `POST /v1/chat/completions` 请求的精确 `sourceModel -> targetModel` 重写映射,这几类接口共用同一份规则。省略该字段或保留为 `{}` 时,不会做模型重写。`source` 和 `target` 都必须是非空字符串。`target` 可以是普通模型 ID,也可以是 `provider/model` 形式的别名,例如 `dashscope/qwen3.6-plus`;重写发生在 provider alias 解析之前。这些映射不再按接口区分。`GET/POST /admin/config/model-mappings` 管理接口读写的也只有这个字段。
258
248
  - **extraPrompts:** `model -> prompt` 的映射。把 Anthropic 风格请求翻译给 Copilot 时,会将其附加到第一条 system prompt 后面。你可以借此为不同模型注入护栏或指引。缺失的默认项会自动补齐,但不会覆盖你自定义的 prompt。内置的 `gpt-5.3-codex` 和 `gpt-5.4` prompt 会启用带阶段感知的 commentary,让模型在工具调用或更深层推理前先发出简短的用户可见进度说明。
259
249
  - **providers:** 全局上游 provider 映射。每个 provider key(例如 `dashscope`)都会变成一个路由前缀(`/dashscope/v1/messages`)。支持 `type: "anthropic"`、`type: "openai-compatible"` 和 `type: "openai-responses"`。顶层客户端也可以在 `/v1/messages`、`/v1/messages/count_tokens` 和 `/v1/responses` 中使用 `model: "dashscope/model-id"`;AI gateway 会在转发上游前移除 `dashscope/` 前缀。`GET /v1/models` 不聚合 provider 模型;provider 模型列表请使用 `GET /dashscope/v1/models`。
260
250
  - `enabled`:可选,若省略则默认为 `true`。
@@ -524,14 +514,14 @@ npx @jeffreycao/copilot-api@latest --oauth-app=opencode start
524
514
  "output": ["text"]
525
515
  },
526
516
  "limit": {
527
- "context": 272000,
517
+ "context": 300000,
528
518
  "output": 128000
529
519
  }
530
520
  },
531
521
  "gpt-5-mini": {
532
522
  "name": "gpt-5-mini",
533
523
  "limit": {
534
- "context": 128000,
524
+ "context": 200000,
535
525
  "output": 64000
536
526
  }
537
527
  },
@@ -543,7 +533,7 @@ npx @jeffreycao/copilot-api@latest --oauth-app=opencode start
543
533
  "output": ["text"]
544
534
  },
545
535
  "limit": {
546
- "context": 128000,
536
+ "context": 200000,
547
537
  "output": 32000
548
538
  },
549
539
  "options": {
package/dist/main.js CHANGED
@@ -43,7 +43,7 @@ const { auth } = await import("./auth-Qy0uU2yI.js");
43
43
  const { checkUsage } = await import("./check-usage-DDfnCA0c.js");
44
44
  const { debug } = await import("./debug-Cc-hdADF.js");
45
45
  const { mcp } = await import("./mcp-DZgcvqQY.js");
46
- const { start } = await import("./start-B9cpzVBW.js");
46
+ const { start } = await import("./start-BUezzq53.js");
47
47
  await runMain(defineCommand({
48
48
  meta: {
49
49
  name: "copilot-api",
@@ -1026,8 +1026,11 @@ const createChatCompletions = async (payload, options) => {
1026
1026
  //#region src/routes/chat-completions/handler.ts
1027
1027
  const logger$7 = createHandlerLogger("chat-completions-handler");
1028
1028
  async function handleCompletion$1(c) {
1029
- await checkRateLimit(state);
1030
1029
  let payload = await c.req.json();
1030
+ const requestedModel = payload.model;
1031
+ payload.model = resolveMappedModel(payload.model);
1032
+ if (payload.model !== requestedModel) logger$7.debug(`Resolved model mapping: ${requestedModel} -> ${payload.model}`);
1033
+ await checkRateLimit(state);
1031
1034
  debugJsonTail(logger$7, "Request payload:", {
1032
1035
  value: payload,
1033
1036
  tailLength: 400
@@ -3773,6 +3776,7 @@ const stringifyToolSearchArguments = (argumentsValue) => {
3773
3776
  return;
3774
3777
  }
3775
3778
  };
3779
+ const DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO = .9;
3776
3780
  const responsesUtilsDependencies = {
3777
3781
  isResponsesApiContextManagementModel,
3778
3782
  isResponsesApiWebSocketEnabled
@@ -3873,18 +3877,18 @@ const isResponseFunctionCallOutputItem = (item) => {
3873
3877
  const isResponseInputImage = (content) => {
3874
3878
  return typeof content === "object" && content !== null && "type" in content && content.type === "input_image";
3875
3879
  };
3876
- const resolveResponsesCompactThreshold = (maxPromptTokens) => {
3877
- if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
3878
- return 272e3 * .9;
3880
+ const resolveResponsesCompactThreshold = (maxPromptTokens, compactThresholdRatio = DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO) => {
3881
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * compactThresholdRatio);
3882
+ return 2e5 * compactThresholdRatio;
3879
3883
  };
3880
3884
  const createCompactionContextManagement = (compactThreshold) => [{
3881
3885
  type: "compaction",
3882
3886
  compact_threshold: compactThreshold
3883
3887
  }];
3884
- const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
3888
+ const applyResponsesApiContextManagement = (payload, maxPromptTokens, compactThresholdRatio = DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO) => {
3885
3889
  if (payload.context_management !== void 0) return;
3886
3890
  if (!responsesUtilsDependencies.isResponsesApiContextManagementModel(payload.model)) return;
3887
- payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
3891
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens, compactThresholdRatio));
3888
3892
  };
3889
3893
  const compactInputByLatestCompaction = (payload) => {
3890
3894
  if (!Array.isArray(payload.input) || payload.input.length === 0) return;
@@ -5020,7 +5024,7 @@ async function handleProviderResponsesForProvider(c, options) {
5020
5024
  message: `Provider '${provider}' does not support the /v1/responses endpoint`,
5021
5025
  type: "invalid_request_error"
5022
5026
  } }, 400);
5023
- applyResponsesApiContextManagement(payload, (providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0)?.capabilities.limits.max_prompt_tokens ?? 0);
5027
+ applyResponsesApiContextManagement(payload, (providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0)?.capabilities.limits.max_prompt_tokens ?? 0, .8);
5024
5028
  const contextManagement = payload.context_management;
5025
5029
  debugJson(logger$2, "Translated Responses request payload:", {
5026
5030
  contextManagement,
@@ -5159,6 +5163,9 @@ const responsesHandlerDependencies = {
5159
5163
  };
5160
5164
  const handleResponses = async (c) => {
5161
5165
  const payload = await c.req.json();
5166
+ const requestedModel = payload.model;
5167
+ payload.model = resolveMappedModel(payload.model);
5168
+ if (payload.model !== requestedModel) logger$1.debug(`Resolved model mapping: ${requestedModel} -> ${payload.model}`);
5162
5169
  const providerModelAlias = parseProviderModelAlias(payload.model);
5163
5170
  if (providerModelAlias) {
5164
5171
  payload.model = providerModelAlias.model;
@@ -5399,4 +5406,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
5399
5406
  //#endregion
5400
5407
  export { server };
5401
5408
 
5402
- //# sourceMappingURL=server-G5PWGqkb.js.map
5409
+ //# sourceMappingURL=server-BA2464Db.js.map