@jeffreycao/copilot-api 2.6.16 → 2.6.17

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
@@ -232,18 +232,27 @@ Recommended Codex version: `0.155.1`.
232
232
 
233
233
  ### Codex `config.toml` Reference
234
234
 
235
- Add the following `[model_providers.copilot_api]` section to your Codex `~/.codex/config.toml`:
235
+ Add the following configuration to your Codex `~/.codex/config.toml`:
236
236
 
237
237
  ```toml
238
+ model = "gpt-6-sol"
239
+ model_reasoning_effort = "max"
238
240
  model_provider = "copilot_api"
239
241
  model_reasoning_summary = "auto"
242
+ plan_mode_reasoning_effort = "max"
240
243
  model_context_window = 272000
241
- model_auto_compact_token_limit = 244800
244
+ model_auto_compact_token_limit = 254800
245
+ sandbox_mode = "danger-full-access"
246
+ approvals_reviewer = "auto_review"
247
+ suppress_unstable_features_warning = true
242
248
  web_search = "live"
249
+ # Codex 0.156.0 and later: generate the catalog, then uncomment this line.
250
+ # model_catalog_json = "model_catalog.json"
243
251
 
244
252
  [model_providers.copilot_api]
245
253
  name = "OpenAI"
246
254
  base_url = "http://localhost:4141"
255
+ model_catalog_url = "http://localhost:4141/models"
247
256
  env_key = "GITHUB_COPILOT_API_KEY"
248
257
  requires_openai_auth = true
249
258
  supports_websockets = false
@@ -255,9 +264,11 @@ stream_idle_timeout_ms = 300000
255
264
 
256
265
  [features]
257
266
  remote_compaction_v2 = true
258
- # optional: set false only when the model does not support tool_search
259
- apps = false
267
+ api_key_model_discovery = true
268
+ default_mode_request_user_input = true
260
269
  standalone_web_search = true
270
+ daemon_auto_start = false
271
+ apps = false
261
272
 
262
273
  [analytics]
263
274
  enabled = false
@@ -265,50 +276,26 @@ enabled = false
265
276
 
266
277
  > [!NOTE]
267
278
  > `name` must be set to `"OpenAI"`.
268
- >
269
- > For third-party models that do not support `tool_search`, we recommend disabling features.apps. Otherwise, each prompt may consume an additional 20,000 or more tokens.
270
- >
271
- > `supports_standalone_web_search` and `[features] standalone_web_search` must both be enabled to expose the standalone `web.run` search tool.
272
279
 
273
- ### If Codex Is Not Signed In to a GPT Account
280
+ ### Generate `model_catalog.json`
274
281
 
275
- ```toml
276
- [model_providers.copilot_api]
277
- name = "OpenAI"
278
- base_url = "http://localhost:4141"
279
- requires_openai_auth = false
280
- supports_websockets = false
281
- supports_standalone_web_search = true
282
- wire_api = "responses"
283
- request_max_retries = 3
284
- stream_max_retries = 3
285
- stream_idle_timeout_ms = 300000
282
+ Codex `0.156.0` and later currently have a bug that prevents loading models through `api_key_model_discovery`. The example leaves `model_catalog_json` commented out by default: generate the file first, then uncomment `model_catalog_json = "model_catalog.json"` to load a local catalog as a workaround. This also works when Codex is not signed in to a GPT account. Versions earlier than `0.156.0` do not need this setting. The [official configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference) describes `model_catalog_json` as a path to a JSON model catalog loaded on startup.
286
283
 
287
- [features]
288
- standalone_web_search = true
284
+ With the gateway running and `curl` and either Bun or Node.js installed, run [the generator](./docs/generate-model-catalog.sh) from the repository root. The script prefers Bun and falls back to Node.js; `jq` is not required:
289
285
 
290
- [model_providers.copilot_api.auth]
291
- command = "powershell.exe"
292
- args = [
293
- "-NoProfile",
294
- "-NonInteractive",
295
- "-Command",
296
- "[Console]::Out.Write($env:GITHUB_COPILOT_API_KEY)"
297
- ]
286
+ ```sh
287
+ sh docs/generate-model-catalog.sh
298
288
  ```
299
289
 
300
- macOS, replace the `auth` block with:
290
+ By default, this writes `$HOME/.codex/model_catalog.json` and creates the directory if needed. With the default gateway URL, the command above is equivalent to specifying the URL and output path explicitly:
301
291
 
302
- ```toml
303
- [model_providers.copilot_api.auth]
304
- command = "/bin/zsh"
305
- args = [
306
- "-c",
307
- "printf '%s' \"$GITHUB_COPILOT_API_KEY\""
308
- ]
292
+ ```sh
293
+ sh docs/generate-model-catalog.sh http://localhost:4141 "$HOME/.codex/model_catalog.json"
309
294
  ```
310
295
 
311
- Without this configuration, Codex cannot fetch `/v1/models` while not signed in to a GPT account, so custom models are unavailable in the model picker.
296
+ If gateway authentication is enabled, export `GITHUB_COPILOT_API_KEY` before running the script. Set `model_catalog_json` to the generated file's absolute path to avoid ambiguity with relative paths. The script sends a Codex `User-Agent`, validates the returned catalog, and replaces the destination only after a successful download and validation. Run it again after changing gateway models or providers, then restart Codex to load the updated catalog.
297
+
298
+ ### Codex Model Catalog and Protocol Adapters
312
299
 
313
300
  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.
314
301
 
package/README.zh-CN.md CHANGED
@@ -248,18 +248,27 @@ npx @jeffreycao/copilot-api@latest start
248
248
 
249
249
  ### Codex `config.toml` 参考配置
250
250
 
251
- 把以下 `[model_providers.copilot_api]` 段加入你的 Codex `~/.codex/config.toml`:
251
+ 把以下配置加入你的 Codex `~/.codex/config.toml`:
252
252
 
253
253
  ```toml
254
+ model = "gpt-6-sol"
255
+ model_reasoning_effort = "max"
254
256
  model_provider = "copilot_api"
255
257
  model_reasoning_summary = "auto"
258
+ plan_mode_reasoning_effort = "max"
256
259
  model_context_window = 272000
257
- model_auto_compact_token_limit = 244800
260
+ model_auto_compact_token_limit = 254800
261
+ sandbox_mode = "danger-full-access"
262
+ approvals_reviewer = "auto_review"
263
+ suppress_unstable_features_warning = true
258
264
  web_search = "live"
265
+ # Codex 0.156.0 及以上版本:先生成模型目录文件,再取消下一行的注释。
266
+ # model_catalog_json = "model_catalog.json"
259
267
 
260
268
  [model_providers.copilot_api]
261
269
  name = "OpenAI"
262
270
  base_url = "http://localhost:4141"
271
+ model_catalog_url = "http://localhost:4141/models"
263
272
  env_key = "GITHUB_COPILOT_API_KEY"
264
273
  requires_openai_auth = true
265
274
  supports_websockets = false
@@ -271,9 +280,11 @@ stream_idle_timeout_ms = 300000
271
280
 
272
281
  [features]
273
282
  remote_compaction_v2 = true
274
- # optional: set false only when the model does not support tool_search
275
- apps = false
283
+ api_key_model_discovery = true
284
+ default_mode_request_user_input = true
276
285
  standalone_web_search = true
286
+ daemon_auto_start = false
287
+ apps = false
277
288
 
278
289
  [analytics]
279
290
  enabled = false
@@ -281,50 +292,26 @@ enabled = false
281
292
 
282
293
  > [!NOTE]
283
294
  > `name` 一定要配置为 `"OpenAI"`。
284
- >
285
- > 对于不支持 `tool_search` 的第三方模型,我们建议禁用 features.apps。否则,每个提示可能会额外消耗 20,000 多个 token。
286
- >
287
- > 必须同时启用 `supports_standalone_web_search` 和 `[features] standalone_web_search`,Codex 才会暴露独立的 `web.run` 搜索工具。
288
295
 
289
- ### Codex 未登录 GPT 账号时
296
+ ### 一键生成 `model_catalog.json`
290
297
 
291
- ```toml
292
- [model_providers.copilot_api]
293
- name = "OpenAI"
294
- base_url = "http://localhost:4141"
295
- requires_openai_auth = false
296
- supports_websockets = false
297
- supports_standalone_web_search = true
298
- wire_api = "responses"
299
- request_max_retries = 3
300
- stream_max_retries = 3
301
- stream_idle_timeout_ms = 300000
298
+ Codex `0.156.0` 及以上版本目前存在无法加载 `api_key_model_discovery` 模型列表的 bug。示例默认注释了 `model_catalog_json`,请先生成文件,再取消 `model_catalog_json = "model_catalog.json"` 的注释,通过本地模型目录临时解决。未登录 GPT 账号时也可以使用此方式加载模型目录;低于 `0.156.0` 的版本不需要增加此项。[官方配置参考](https://learn.chatgpt.com/docs/config-file/config-reference)将 `model_catalog_json` 定义为启动时加载的 JSON 模型目录路径。
302
299
 
303
- [features]
304
- standalone_web_search = true
300
+ 启动网关并安装 `curl` 及 Bun 或 Node.js 后,在仓库根目录运行[生成脚本](./docs/generate-model-catalog.sh)。脚本优先使用 Bun,没有 Bun 时使用 Node.js,无需安装 `jq`:
305
301
 
306
- [model_providers.copilot_api.auth]
307
- command = "powershell.exe"
308
- args = [
309
- "-NoProfile",
310
- "-NonInteractive",
311
- "-Command",
312
- "[Console]::Out.Write($env:GITHUB_COPILOT_API_KEY)"
313
- ]
302
+ ```sh
303
+ sh docs/generate-model-catalog.sh
314
304
  ```
315
305
 
316
- macOS 将 `auth` 段替换为:
306
+ 默认写入 `$HOME/.codex/model_catalog.json`,目录不存在时会自动创建。使用默认网关地址时,上面的命令等价于显式指定网关地址和输出路径:
317
307
 
318
- ```toml
319
- [model_providers.copilot_api.auth]
320
- command = "/bin/zsh"
321
- args = [
322
- "-c",
323
- "printf '%s' \"$GITHUB_COPILOT_API_KEY\""
324
- ]
308
+ ```sh
309
+ sh docs/generate-model-catalog.sh http://localhost:4141 "$HOME/.codex/model_catalog.json"
325
310
  ```
326
311
 
327
- 未按上述方式配置时,Codex 未登录 GPT 账号拉不到 `/v1/models`,无法选择自定义模型。
312
+ 如果网关启用了鉴权,请先设置环境变量 `GITHUB_COPILOT_API_KEY`。建议把配置中的 `model_catalog_json` 改成生成文件的绝对路径,避免相对路径歧义。脚本会携带 Codex `User-Agent`,校验返回的模型目录,并仅在下载和校验成功后替换目标文件。网关模型或 provider 发生变化后,重新运行脚本并重启 Codex,即可加载更新后的目录。
313
+
314
+ ### Codex 模型目录与协议适配
328
315
 
329
316
  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(包括流式事件)。
330
317
 
package/dist/main.js CHANGED
@@ -30,7 +30,7 @@ if (isMcpFastPath(process.argv)) {
30
30
  const { auth } = await import("./auth-ZoN2_BLX.js");
31
31
  const { debug } = await import("./debug-C4rsL806.js");
32
32
  const { mcp } = await import("./mcp-Byz9h_xz.js");
33
- const { start } = await import("./start-CmHlGpmG.js");
33
+ const { start } = await import("./start-CRE6W4OF.js");
34
34
  await runMain(defineCommand({
35
35
  meta: {
36
36
  name: "copilot-api",
@@ -4062,20 +4062,22 @@ function translateToOpenAI(payload, options = {}) {
4062
4062
  const { sessionId: metadataPromptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
4063
4063
  const sessionAffinity = requestContext.getStore()?.sessionAffinity?.trim() || null;
4064
4064
  const promptCacheKey = metadataPromptCacheKey ?? sessionAffinity;
4065
+ const capabilities = {
4066
+ supportPdf: options.supportPdf ?? false,
4067
+ toolContentSupportType: options.toolContentSupportType ?? []
4068
+ };
4069
+ const tools = translateAnthropicToolsToOpenAI(payload.tools);
4065
4070
  return {
4066
4071
  model: modelId,
4067
- messages: translateAnthropicMessagesToOpenAI(payload, modelId, {
4068
- supportPdf: options.supportPdf ?? false,
4069
- toolContentSupportType: options.toolContentSupportType ?? []
4070
- }),
4072
+ messages: translateAnthropicMessagesToOpenAI(payload, modelId, capabilities),
4071
4073
  max_completion_tokens: payload.max_tokens,
4072
4074
  stop: payload.stop_sequences,
4073
4075
  stream: payload.stream,
4074
4076
  temperature: payload.temperature,
4075
4077
  top_p: payload.top_p,
4076
4078
  user: payload.metadata?.user_id,
4077
- tools: translateAnthropicToolsToOpenAI(payload.tools),
4078
- tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),
4079
+ tools,
4080
+ tool_choice: tools && tools.length > 0 ? translateAnthropicToolChoiceToOpenAI(payload.tool_choice) : void 0,
4079
4081
  thinking_budget: thinkingBudget,
4080
4082
  ...reasoningEffort ? { reasoning_effort: reasoningEffort } : {},
4081
4083
  ...promptCacheKey ? { prompt_cache_key: promptCacheKey } : {}
@@ -6943,7 +6945,7 @@ function translateFilePart(part, path) {
6943
6945
  };
6944
6946
  }
6945
6947
  function translateToolChoice(toolChoice, registry) {
6946
- if (!toolChoice) return void 0;
6948
+ if (!toolChoice || registry.tools.length === 0) return void 0;
6947
6949
  if (typeof toolChoice === "string") {
6948
6950
  if (toolChoice === "required") return { type: "any" };
6949
6951
  return { type: toolChoice };
@@ -12515,4 +12517,4 @@ createServer();
12515
12517
  //#endregion
12516
12518
  export { createServer };
12517
12519
 
12518
- //# sourceMappingURL=server-DQy_3eXx.js.map
12520
+ //# sourceMappingURL=server-B0LTZeZf.js.map