xiaodcs-copilot-api 2.4.1-public.1 → 2.5.1-public.4

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
@@ -65,7 +65,8 @@ From here, jump to the guide for your client: [Claude Code](#using-with-claude-c
65
65
  - **Unified API Gateway**: Serve OpenAI-compatible Chat Completions (`/v1/chat/completions`), the OpenAI Responses API (`/v1/responses`), and Anthropic-compatible Messages (`/v1/messages`) from one local endpoint.
66
66
  - **Multi-Provider**: Route GitHub Copilot, the built-in `codex` provider, and third-party providers (Kimi, DeepSeek, DashScope, OpenRouter, OpenCode Go, or a custom provider) behind the same gateway. GitHub Copilot is optional — with at least one enabled provider, the server starts in provider-only mode without a GitHub token.
67
67
  - **Coding Agent Ready**: First-class setups for Claude Code, OpenCode, and Codex, including the interactive `--claude-code` launcher and a merged model catalog for Codex.
68
- - **Streaming & WebSocket**: SSE streaming on all three client-facing protocols. Upstream Copilot Responses traffic selects WebSocket or HTTP from each model's advertised endpoints; streamed Responses traffic for the built-in `codex` provider uses WebSocket by default and uses HTTP when `useResponsesApiWebSocket` is disabled.
68
+ - **Streaming & WebSocket**: SSE streaming on all three client-facing protocols. Upstream Copilot Responses traffic selects WebSocket or HTTP from each model's advertised endpoints. The built-in `codex` provider can independently select WebSocket with `useCodexResponsesApiWebSocket`; when omitted, it inherits `useResponsesApiWebSocket`.
69
+ - **Codex quota logs**: Healthy quota snapshots are debug-only (visible with `--verbose`). Warnings remain visible when a window reaches 90% used, `allowed=false`, or `limit_reached=true`. This changes console verbosity only; quota events, usage recording, and request handling are unchanged.
69
70
  - **Desktop App**: Electron GUI with GitHub Copilot sign-in, Codex OAuth, provider configuration, token usage, logs, and one-click start/stop.
70
71
 
71
72
  ## Compatibility
@@ -431,9 +432,12 @@ npx xiaodcs-copilot-api-edge@latest start
431
432
  With options:
432
433
 
433
434
  ```sh
434
- npx xiaodcs-copilot-api-edge@latest start --port 8080
435
+ npx xiaodcs-copilot-api-edge@latest auth keys --add your-gateway-api-key
436
+ npx xiaodcs-copilot-api-edge@latest start --host 0.0.0.0 --port 8080
435
437
  ```
436
438
 
439
+ Binding to `0.0.0.0` exposes the gateway to the network, so the server requires at least one gateway API key and restricts CORS to same-origin requests.
440
+
437
441
  For authentication or provider configuration only:
438
442
 
439
443
  ```sh
@@ -459,15 +463,17 @@ Run the container with a bind mount so auth data survives restarts:
459
463
 
460
464
  ```sh
461
465
  mkdir -p ./copilot-data
466
+ docker run --rm -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api --auth keys --add your-gateway-api-key
462
467
  docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api
463
468
  ```
464
469
 
465
470
  This stores GitHub auth data, provider config, and other gateway state in `./copilot-data` on the host, mapped to `/root/.local/share/copilot-api` in the container.
471
+ The image explicitly listens on `0.0.0.0` so Docker port publishing works and refuses to start until at least one gateway API key is configured. Non-loopback listeners also restrict CORS to the request's own origin.
466
472
 
467
473
  Or pass a GitHub token directly:
468
474
 
469
475
  ```sh
470
- docker run -p 4141:4141 -e GH_TOKEN=your_github_token_here copilot-api
476
+ docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api -e GH_TOKEN=your_github_token_here copilot-api
471
477
  ```
472
478
 
473
479
  ## Electron Desktop App
@@ -653,6 +659,7 @@ The following command line options are available for the `start` command:
653
659
 
654
660
  | Option | Description | Default | Alias |
655
661
  | -------------- | ----------------------------------------------------------------------------- | ---------- | ----- |
662
+ | --host | Host to listen on; non-loopback hosts require a configured gateway API key | 127.0.0.1 | none |
656
663
  | --port | Port to listen on | 4141 | -p |
657
664
  | --verbose | Enable verbose logging | false | -v |
658
665
  | --github-token | Provide GitHub token directly (must be generated using the `auth` subcommand) | none | -g |
@@ -674,7 +681,7 @@ Use `copilot-api auth login --provider deepseek`, `--provider dashscope`, `--pro
674
681
 
675
682
  Use `copilot-api auth login --provider custom` to add or update another third-party provider from the CLI. The command prompts for the provider name, supported type (`anthropic`, `openai-compatible`, or `openai-responses`), `baseUrl`, masked `apiKey`, and `authType`; `authType` may be left as the type default or set to `x-api-key` / `authorization`.
676
683
 
677
- Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `copilot-api auth keys` (one operation per invocation): add a key with `--add <key>`, remove one with `--remove <key>`, list all with `--list`, or clear them all with `--clear`. Clients authenticate with any configured key via `x-api-key` or `Authorization: Bearer`. When no keys are configured, `copilot-api start` starts with authentication bypassed and prints a startup info message.
684
+ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `copilot-api auth keys` (one operation per invocation): add a key with `--add <key>`, remove one with `--remove <key>`, list all with `--list`, or clear them all with `--clear`. Clients authenticate with any configured key via `x-api-key` or `Authorization: Bearer`. Without keys, loopback listeners start with authentication bypassed and print an info message; non-loopback listeners refuse to start.
678
685
 
679
686
  ### Debug Command Options
680
687
 
@@ -727,7 +734,7 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
727
734
  "messageApiWebSearchModel": "gpt-5-mini"
728
735
  }
729
736
  ```
730
- - **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.
737
+ - **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 only on loopback listeners; non-loopback listeners refuse to start.
731
738
  - **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/*`.
732
739
  - **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.
733
740
  - **extraPrompts:** Map of `model -> prompt` appended to the first system prompt when translating Anthropic-style requests to Responses API. Use this to inject guardrails or guidance per model. Missing default entries are auto-added without overwriting your custom prompts. For GPT-5.3+ models (e.g. `gpt-5.3-codex`, `gpt-5.4`, `gpt-5.5`), a built-in commentary prompt is used as fallback when not explicitly configured. The built-in prompts enable phase-aware commentary, which lets the model emit a short user-facing progress update before tools or deeper reasoning.
@@ -762,7 +769,19 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
762
769
  - **Configuration values:** `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`.
763
770
  - **useMessagesApi:** When `true`, models that advertise Copilot's native `/v1/messages` endpoint use the Messages API. If Messages is disabled or unavailable for the selected model, the gateway uses Responses when that model advertises a Responses endpoint, then falls back to Chat Completions when supported. Set this to `false` to skip native Messages routing. Defaults to `true`.
764
771
  - **useResponsesApiCompactionRecovery (experimental):** When `true`, successful remote Responses compactions enqueue a non-blocking, low-reasoning shadow-summary request and store only that summary under a hash of the opaque compaction item in the private `~/.local/share/copilot-api/compaction-recovery/cache.sqlite` directory. If Copilot later rejects that compaction or connection-bound history, HTTP requests progressively rebuild the request from cached summaries and visible messages. This option defaults to `false` because shadow summaries add one background model request and recovery is lossy. WebSocket errors are recovered on the client's next retry; automatic same-request recovery is HTTP-only.
765
- - **useResponsesApiWebSocket:** When `true`, Copilot Responses requests use WebSocket for models that advertise `ws:/responses`; models that advertise only `/responses` use HTTP. Streamed Responses requests for the built-in `codex` provider use WebSocket whenever this setting is enabled, while non-streaming Codex requests always use HTTP. Set this to `false` to make Copilot use HTTP `/responses` where the selected model advertises it and to send streamed Codex Responses requests over HTTP. WebSocket failures are not retried automatically over HTTP. Defaults to `true`. If a proxy, VPN, or network blocks or destabilizes WebSocket traffic, disable this setting or switch networks.
772
+ - **useResponsesApiWebSocket:** Controls upstream Copilot Responses WebSocket use for models that advertise `ws:/responses`; HTTP is used where the model advertises `/responses` and WebSocket is disabled or unavailable in its endpoint metadata. Defaults to `true`. Also supplies the legacy default for `codex` when its independent override is omitted. Copilot WebSocket failures are not retried automatically over HTTP.
773
+ - **useCodexResponsesApiWebSocket (optional):** Overrides WebSocket use only for streamed Responses requests to the built-in `codex` (ChatGPT OAuth) provider, including requests translated from Messages. A boolean `false` forces HTTP and `true` selects WebSocket; omission inherits `useResponsesApiWebSocket` for backward compatibility. Non-streaming requests remain HTTP. A Codex WebSocket connection failure **before any send attempt** falls back to HTTP once, unless cancelled or carrying `previous_response_id`/`conversation` state. After send is attempted, no automatic replay occurs—even before the first event—because the upstream may already be executing the request. HTTP fallback failure is surfaced normally. This does not add a client-facing WebSocket endpoint, guarantee uninterrupted streams, or change third-party providers.
774
+
775
+ To enable WebSocket only between the gateway and ChatGPT while keeping Copilot on HTTP:
776
+
777
+ ```json
778
+ {
779
+ "useResponsesApiWebSocket": false,
780
+ "useCodexResponsesApiWebSocket": true
781
+ }
782
+ ```
783
+
784
+ Merge these keys into the intended API Home's existing `config.json`; do not replace the entire file. These are gateway-to-upstream settings. Keep the Codex client's gateway provider at `supports_websockets = false`, since client-facing Responses traffic still uses HTTP/SSE. Configuration is cached; restart the intended gateway instance after changing the file. To disable the Codex override explicitly, set it to `false`; to restore legacy inheritance, remove that key.
766
785
  - **useCopilotFastTier:** Controls whether a client request with `service_tier: "fast"` or `"priority"` may route to a paired Copilot `*-fast` model. Defaults to `true`. Set it to `false` to force the standard model even when a Codex task retains a hidden Fast speed-tier selection. When enabled, an explicit upstream Fast 429 falls back once to the paired standard model and temporarily cools Fast routing according to `Retry-After` (30 seconds by default, capped at 5 minutes).
767
786
  - **responsesTransport:** Positive integer lifecycle and buffering limits for every upstream Responses transport. Invalid, zero, or negative values fall back to the defaults shown above. `headersTimeoutMsV2` covers connection setup through receipt of HTTP response headers; it is not a total generation deadline. `streamInactivityTimeoutMs` is reset by every HTTP body chunk or WebSocket message, allowing long generations to continue while they remain active. `websocketOpenTimeoutMs` limits the WebSocket handshake, while `websocketPoolIdleTimeoutMs` controls only completed, reusable pooled sockets. The byte and message limits bound queued WebSocket events; exceeding either limit fails that stream and invalidates its socket rather than dropping or reordering events.
768
787
  - **useResponsesApiWebSearch:** When `true`, the server keeps Responses API tools with `type: "web_search"` and forwards them upstream. Set to `false` to strip those tools from `/responses` payloads. Defaults to `true`.
@@ -777,7 +796,7 @@ Edit this file to customize prompts or swap in your own fast model. Restart the
777
796
 
778
797
  ## API Authentication
779
798
 
780
- - **Protected non-admin routes:** All routes except `/`, `/usage-viewer`, and `/usage-viewer/` require authentication when `auth.apiKeys` is configured and non-empty.
799
+ - **Protected non-admin routes:** All routes except `/`, `/usage-viewer`, and `/usage-viewer/` require authentication when `auth.apiKeys` is configured and non-empty. Non-loopback listeners require a non-empty `auth.apiKeys` configuration at startup and continue failing closed if the keys are later cleared.
781
800
  - **Admin routes:** All `/admin/*` routes require `auth.adminApiKey`. If it is missing, the server generates one at startup and persists it to `config.json` before serving requests.
782
801
  - **Allowed auth headers:**
783
802
  - `x-api-key: <your_key>`
@@ -809,7 +828,7 @@ These endpoints mimic the OpenAI API structure.
809
828
 
810
829
  | Endpoint | Method | Description |
811
830
  | --------------------------- | ------ | ---------------------------------------------------------------- |
812
- | `POST /v1/responses` | `POST` | OpenAI Most advanced interface for generating model responses. Supports `provider/model` aliases for `openai-responses` providers. |
831
+ | `POST /v1/responses` | `POST` | OpenAI Most advanced interface for generating model responses. Supports `Content-Encoding: zstd` request bodies and `provider/model` aliases for `openai-responses` providers. Zstd request decompression is limited to Responses routes, including provider-scoped aliases. |
813
832
  | `POST /v1/chat/completions` | `POST` | Creates a model response for the given chat conversation. Supports `provider/model` aliases for `openai-compatible` providers and can be used without Copilot when the target provider is configured. |
814
833
  | `GET /v1/models` | `GET` | Lists Copilot models plus enabled provider models using `provider/model-id` IDs. Requests from Codex clients (`User-Agent` beginning with `codex`) are forwarded to the Codex Models upstream. |
815
834
  | `POST /v1/embeddings` | `POST` | Creates an embedding vector representing the input text. |
@@ -861,7 +880,8 @@ Common `npx` commands:
861
880
  npx xiaodcs-copilot-api-edge@latest start
862
881
 
863
882
  # Start on a custom port with verbose logging
864
- npx xiaodcs-copilot-api-edge@latest start --port 8080 --verbose
883
+ npx xiaodcs-copilot-api-edge@latest auth keys --add your-gateway-api-key
884
+ npx xiaodcs-copilot-api-edge@latest start --host 0.0.0.0 --port 8080 --verbose
865
885
 
866
886
  # Run the auth flow
867
887
  npx xiaodcs-copilot-api-edge@latest auth login
@@ -899,3 +919,15 @@ Same reminders as `CLAUDE_PLUGIN_ENABLE_QUESTION_RULES=1` in the `agent-inject`
899
919
  - Prohibited from directly asking questions to users, MUST use question tool.
900
920
  - Once you can confirm that the task is complete, MUST use question tool to make user confirm. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again, after try again, MUST use question tool to make user confirm again.
901
921
  ```
922
+
923
+ ## Builtin Qoder SDK provider
924
+
925
+ Run `copilot-api auth login --provider qoder` (Edge: `copilot-api-edge`), enter your Qoder PAT, then start the gateway normally. Credentials use the existing protected `config.json`; no separate sidecar or bridge key is needed. Supports text/image Chat Completions, SSE, model discovery and Credits. See [setup and capability limits](qoder-bridge/README.md). This integration is included in source and awaits npm release.
926
+
927
+ ### Generate a Codex model list on startup
928
+
929
+ Opt in with `copilot-api start --sync-model-list` (or `copilot-api-edge` for the Edge package). The catalog is written to `model-list.json` beside the active API Home's `config.json`, defaulting to `~/.local/share/copilot-api/`. Use `--model-list-file codex-models.json` to choose a filename, or `--no-sync-model-list` to skip synchronization for one launch.
930
+
931
+ To enable it persistently, add `"modelList": { "enabled": true, "file": "model-list.json", "providers": ["*"], "exclude": [], "overrides": {} }` to your existing configuration. CLI options take precedence. Select only Qoder with `"providers": ["qoder"]`.
932
+
933
+ Configure Codex yourself to read the resulting absolute path through `model_catalog_json`. The gateway does not edit or restart Codex. Compatible models and context budgets are refreshed on startup; failed sources retain their previous entries. Files with manual edits are protected, and a `.bak` plus `.state.json` sidecar support safe updates. Put display/order/window preferences in `overrides`, not in generated JSON. See [model list synchronization](docs/model-list-sync.md) for metadata rules and recovery details.
package/README.zh-CN.md CHANGED
@@ -68,7 +68,8 @@ curl http://localhost:4141/v1/models
68
68
  - **统一 API 网关**:在同一个本地端点上提供 OpenAI 兼容的 Chat Completions(`/v1/chat/completions`)、OpenAI Responses API(`/v1/responses`)和 Anthropic 兼容的 Messages(`/v1/messages`)。
69
69
  - **多 Provider 接入**:在同一个网关后面统一路由 GitHub Copilot、内置 `codex` provider 和第三方 provider(Kimi、DeepSeek、DashScope、OpenRouter、OpenCode Go 或自定义 provider)。GitHub Copilot 是可选能力——只要至少有一个启用中的 provider,无需 GitHub token 也能按 provider-only 模式启动。
70
70
  - **为 Coding Agent 而生**:为 Claude Code、OpenCode 和 Codex 提供完整的配置指南,包括交互式 `--claude-code` 启动器和面向 Codex 的合并模型目录。
71
- - **Streaming 与 WebSocket**:三种面向客户端的协议都支持 SSE 流式输出。上游 Copilot Responses 流量会根据每个模型声明的端点选择 WebSocket 或 HTTP;内置 `codex` provider 的流式 Responses 请求默认走 WebSocket,关闭 `useResponsesApiWebSocket` 后改走 HTTP。
71
+ - **Streaming 与 WebSocket**:三种面向客户端的协议都支持 SSE 流式输出。上游 Copilot Responses 流量根据模型声明的端点选择 WebSocket 或 HTTP;内置 `codex` provider 可用 `useCodexResponsesApiWebSocket` 独立选择传输,未设置时继承 `useResponsesApiWebSocket`。
72
+ - **Codex 额度日志**:正常额度快照仅在 debug / `--verbose` 模式显示;窗口已用额度达到 90%、`allowed=false` 或 `limit_reached=true` 时保留警告。只降低控制台噪声,不改变额度事件转发、用量记录或请求处理。
72
73
  - **桌面应用**:Electron 图形界面,支持 GitHub Copilot 登录、Codex OAuth、provider 配置、token 用量、日志查看和一键启动 / 停止。
73
74
 
74
75
  <a id="compatibility"></a>
@@ -457,9 +458,12 @@ npx xiaodcs-copilot-api-edge@latest start
457
458
  带参数示例:
458
459
 
459
460
  ```sh
460
- npx xiaodcs-copilot-api-edge@latest start --port 8080
461
+ npx xiaodcs-copilot-api-edge@latest auth keys --add your-gateway-api-key
462
+ npx xiaodcs-copilot-api-edge@latest start --host 0.0.0.0 --port 8080
461
463
  ```
462
464
 
465
+ 绑定到 `0.0.0.0` 会将网关暴露到网络,因此服务要求至少配置一个网关 API Key,并将 CORS 限制为同源请求。
466
+
463
467
  如果只想做认证或 provider 配置:
464
468
 
465
469
  ```sh
@@ -487,15 +491,17 @@ docker build -t copilot-api .
487
491
 
488
492
  ```sh
489
493
  mkdir -p ./copilot-data
494
+ docker run --rm -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api --auth keys --add your-gateway-api-key
490
495
  docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api
491
496
  ```
492
497
 
493
498
  这会把宿主机上的 `./copilot-data` 映射到容器内的 `/root/.local/share/copilot-api`,用于持久化 GitHub 认证数据、provider 配置和其他 gateway 状态。
499
+ 镜像会显式监听 `0.0.0.0` 以支持 Docker 端口映射,并在未配置网关 API Key 时拒绝启动。非回环监听还会将 CORS 限制为请求自身的同源地址。
494
500
 
495
501
  也可以直接通过环境变量传入 GitHub token:
496
502
 
497
503
  ```sh
498
- docker run -p 4141:4141 -e GH_TOKEN=your_github_token_here copilot-api
504
+ docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api -e GH_TOKEN=your_github_token_here copilot-api
499
505
  ```
500
506
 
501
507
  <a id="electron-desktop-app"></a>
@@ -693,6 +699,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
693
699
 
694
700
  | 选项 | 说明 | 默认值 | 别名 |
695
701
  | --- | --- | --- | --- |
702
+ | --host | 监听主机;非回环地址要求已配置网关 API Key | 127.0.0.1 | 无 |
696
703
  | --port | 监听端口 | 4141 | -p |
697
704
  | --verbose | 启用详细日志 | false | -v |
698
705
  | --github-token | 直接提供 GitHub token(必须通过 `auth` 子命令生成) | 无 | -g |
@@ -714,7 +721,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
714
721
 
715
722
  使用 `copilot-api auth login --provider custom` 可以通过 CLI 新增或更新其他第三方 provider。命令会依次提示输入 provider name、项目支持的 type(`anthropic`、`openai-compatible` 或 `openai-responses`)、`baseUrl`、掩码显示的 `apiKey` 和 `authType`;`authType` 可保持 type 默认值,也可选择 `x-api-key` / `authorization`。
716
723
 
717
- 网关 API Key 存放在 `config.json` 的 `auth.apiKeys` 中,可通过 `copilot-api auth keys` 管理(每次只执行一种操作):`--add <key>` 添加、`--remove <key>` 删除、`--list` 列出全部、`--clear` 清空。客户端通过 `x-api-key` 或 `Authorization: Bearer` 使用任意已配置的 Key 认证。未配置任何 Key 时,`copilot-api start` 会以“不校验认证”的方式启动并输出一条 info 级别的启动提示。
724
+ 网关 API Key 存放在 `config.json` 的 `auth.apiKeys` 中,可通过 `copilot-api auth keys` 管理(每次只执行一种操作):`--add <key>` 添加、`--remove <key>` 删除、`--list` 列出全部、`--clear` 清空。客户端通过 `x-api-key` 或 `Authorization: Bearer` 使用任意已配置的 Key 认证。未配置任何 Key 时,回环监听会以“不校验认证”的方式启动并输出一条 info 级别提示;非回环监听则拒绝启动。
718
725
 
719
726
  ### Debug 命令选项
720
727
 
@@ -769,7 +776,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
769
776
  "messageApiWebSearchModel": "gpt-5-mini"
770
777
  }
771
778
  ```
772
- - **auth.apiKeys:** 用于普通非 admin 路由的 API key。支持多个 key 轮换使用。请求可通过 `x-api-key: <key>` 或 `Authorization: Bearer <key>` 进行认证。若为空或省略,则普通路由的认证会被禁用。
779
+ - **auth.apiKeys:** 用于普通非 admin 路由的 API key。支持多个 key 轮换使用。请求可通过 `x-api-key: <key>` 或 `Authorization: Bearer <key>` 进行认证。若为空或省略,仅回环监听会禁用普通路由认证;非回环监听会拒绝启动。
773
780
  - **auth.adminApiKey:** 仅用于 `/admin/*` 路由的单个 admin key。若未配置,服务会在启动时自动生成一个随机 key,并回写到 `config.json`。它同样使用 `x-api-key` 或 `Authorization: Bearer` 这两种头,但普通 `auth.apiKeys` 不能访问 `/admin/*`。
774
781
  - **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` 管理接口读写的也只有这个字段。
775
782
  - **extraPrompts:** `model -> prompt` 的映射。把 Anthropic 风格请求翻译为 Responses API 时,会将其附加到第一条 system prompt 后面。你可以借此为不同模型注入护栏或指引。缺失的默认项会自动补齐,但不会覆盖你自定义的 prompt。对于 GPT-5.3+ 模型(如 `gpt-5.3-codex`、`gpt-5.4`、`gpt-5.5`),未显式配置时会自动使用内置的 commentary prompt。内置 prompt 会启用带阶段感知的 commentary,让模型在工具调用或更深层推理前先发出简短的用户可见进度说明。
@@ -804,7 +811,19 @@ Copilot API 现在使用子命令结构,主要命令包括:
804
811
  - **配置可选值:** `none`、`minimal`、`low`、`medium`、`high`、`xhigh`、`max`。
805
812
  - **useMessagesApi:** 当为 `true` 时,声明了 Copilot 原生 `/v1/messages` 端点的模型会使用 Messages API。如果所选模型未声明 Messages 端点或关闭了该配置,网关会在模型声明了 Responses 端点时使用 Responses,否则在模型支持时回退到 Chat Completions。设为 `false` 可跳过原生 Messages 路由。默认值为 `true`。
806
813
  - **useResponsesApiCompactionRecovery(实验性):** 设为 `true` 后,成功的远程 Responses 压缩会异步生成低推理强度的影子摘要,并仅以 opaque compaction 哈希为键保存摘要。当 Copilot 后续拒绝该压缩内容或连接绑定历史时,HTTP 请求会逐步使用缓存摘要与可见消息重建请求。默认关闭,因为影子摘要会增加一次后台模型请求,且恢复过程存在信息损失。WebSocket 错误会在客户端下一次重试时恢复;同一次请求内的自动恢复仅支持 HTTP。
807
- - **useResponsesApiWebSocket:** 当为 `true` 时,Copilot Responses 请求会对声明了 `ws:/responses` 的模型使用 WebSocket;仅声明 `/responses` 的模型使用 HTTP。内置 `codex` provider 的流式 Responses 请求只要启用了该配置就会使用 WebSocket,非流式 Codex 请求始终使用 HTTP。设为 `false` 后,Copilot 会在所选模型声明了 `/responses` 时使用 HTTP,Codex 的流式 Responses 请求也会改走 HTTP。WebSocket 失败后不会自动通过 HTTP 重试。默认值为 `true`。如果代理、VPN 或网络会阻断或干扰 WebSocket 流量,请关闭该配置或切换网络。
814
+ - **useResponsesApiWebSocket:** 控制上游 Copilot Responses 是否对声明了 `ws:/responses` 的模型使用 WebSocket;关闭或端点元数据不支持 WebSocket 时,在模型声明了 `/responses` 的情况下使用 HTTP。默认 `true`。内置 `codex` 未设置独立开关时也继承此值。Copilot WebSocket 失败后不会自动通过 HTTP 重试。
815
+ - **useCodexResponsesApiWebSocket(可选):** 仅覆盖内置 `codex`(ChatGPT OAuth)provider 的流式 Responses 传输,包括从 Messages 转换的请求。布尔值 `false` 使用 HTTP,`true` 选择 WebSocket;不填时继承 `useResponsesApiWebSocket`,兼容旧配置。非流式请求仍走 HTTP。Codex WebSocket 在**尚未尝试发送请求**时建连失败,会降级 HTTP 一次;已取消或带有 `previous_response_id` / `conversation` 续接状态时不降级。一旦尝试发送,即使尚未收到首个事件,也不会自动重放,因为上游可能已经开始执行。HTTP 降级也失败时正常返回错误。此功能不增加面向客户端的 WebSocket 接口、不保证永不断流,也不改变第三方 provider。
816
+
817
+ 只让网关到 ChatGPT 使用 WebSocket、Copilot 保持 HTTP 的配置:
818
+
819
+ ```json
820
+ {
821
+ "useResponsesApiWebSocket": false,
822
+ "useCodexResponsesApiWebSocket": true
823
+ }
824
+ ```
825
+
826
+ 把这两个键合并到目标 API Home 的现有 `config.json`,不要覆盖整份文件。这是网关连接上游的配置;Codex 客户端连接网关的 provider 仍保留 `supports_websockets = false`,使用 HTTP/SSE。配置会缓存,改文件后需重启对应网关实例。要明确关闭 Codex WebSocket,把独立开关设为 `false`;要恢复旧版继承行为,移除该键。
808
827
  - **useCopilotFastTier:** 控制客户端请求中的 `service_tier: "fast"` 或 `"priority"` 是否可以路由到配对的 Copilot `*-fast` 模型,默认值为 `true`。设为 `false` 后,即使 Codex 任务保留了界面中不明显的 Fast 速度档位,也会强制使用标准模型。开启时,若 Fast 上游明确返回 429,会自动回退一次到配对标准模型,并按 `Retry-After` 暂停 Fast 路由(默认 30 秒,最长 5 分钟)。
809
828
  - **responsesTransport:** 所有上游 Responses transport 共用的生命周期与缓冲区正整数限制。无效值、零或负数会回退到上面列出的默认值。`headersTimeoutMsV2` 从连接建立开始计算,到收到 HTTP 响应头为止,并不是整个生成过程的总时限。每收到一个 HTTP body chunk 或 WebSocket message 都会重置 `streamInactivityTimeoutMs`,因此持续活跃的长推理任务不会被短总时限中断。`websocketOpenTimeoutMs` 限制 WebSocket 握手时间;`websocketPoolIdleTimeoutMs` 只控制已正常完成且可复用的空闲连接。WebSocket 队列同时受字节数和消息数上限约束;超过任一上限时会终止该 stream 并使 socket 失效,而不会丢弃或重排事件。
810
829
  - **useResponsesApiWebSearch:** 当为 `true` 时,服务端会保留 Responses API 中 `type: "web_search"` 的工具并透传到上游。设为 `false` 则会从 `/responses` payload 中移除这些工具。默认值为 `true`。
@@ -821,7 +840,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
821
840
 
822
841
  ## API 认证
823
842
 
824
- - **受保护的普通路由:** 当配置了 `auth.apiKeys` 且非空时,除 `/`、`/usage-viewer` 和 `/usage-viewer/` 以外的普通路由都需要认证。
843
+ - **受保护的普通路由:** 当配置了 `auth.apiKeys` 且非空时,除 `/`、`/usage-viewer` 和 `/usage-viewer/` 以外的普通路由都需要认证。非回环监听要求启动时存在非空的 `auth.apiKeys`,即使运行期间 Key 被清空也会继续以拒绝请求的方式安全失败。
825
844
  - **Admin 路由:** 所有 `/admin/*` 路由都要求 `auth.adminApiKey`。如果缺失,服务会在启动时自动生成并在开始提供服务前写回 `config.json`。
826
845
  - **允许的认证头:**
827
846
  - `x-api-key: <your_key>`
@@ -855,7 +874,7 @@ curl http://localhost:4141/admin/config/model-mappings \
855
874
 
856
875
  | 端点 | 方法 | 说明 |
857
876
  | --------------------------- | ---- | -------------------------------------------------------------------------------------------------------- |
858
- | `POST /v1/responses` | `POST` | OpenAI 中用于生成模型响应的高级接口。支持 `openai-responses` provider 的 `provider/model` 别名。 |
877
+ | `POST /v1/responses` | `POST` | OpenAI 中用于生成模型响应的高级接口。支持 `Content-Encoding: zstd` 请求体和 `openai-responses` provider 的 `provider/model` 别名。zstd 请求解压仅作用于 Responses 路由,包括 provider-scoped 别名路由。 |
859
878
  | `POST /v1/chat/completions` | `POST` | 为给定聊天对话创建模型响应。支持 `openai-compatible` provider 的 `provider/model` 别名;目标 provider 已配置时可在没有 Copilot 的情况下使用。 |
860
879
  | `GET /v1/models` | `GET` | 列出 Copilot 模型以及已启用 provider 的 `provider/model-id` 模型。来自 Codex 客户端(`User-Agent` 以 `codex` 开头)的请求会转发到 Codex Models 上游。 |
861
880
  | `POST /v1/embeddings` | `POST` | 创建表示输入文本的向量嵌入。 |
@@ -909,7 +928,8 @@ curl http://localhost:4141/admin/config/model-mappings \
909
928
  npx xiaodcs-copilot-api-edge@latest start
910
929
 
911
930
  # 自定义端口并开启详细日志
912
- npx xiaodcs-copilot-api-edge@latest start --port 8080 --verbose
931
+ npx xiaodcs-copilot-api-edge@latest auth keys --add your-gateway-api-key
932
+ npx xiaodcs-copilot-api-edge@latest start --host 0.0.0.0 --port 8080 --verbose
913
933
 
914
934
  # 执行认证流程
915
935
  npx xiaodcs-copilot-api-edge@latest auth login
@@ -951,3 +971,7 @@ curl http://localhost:4141/dashscope/v1/messages \
951
971
  - Prohibited from directly asking questions to users, MUST use question tool.
952
972
  - Once you can confirm that the task is complete, MUST use question tool to make user confirm. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again, after try again, MUST use question tool to make user confirm again.
953
973
  ```
974
+
975
+ ## 内置 Qoder SDK provider
976
+
977
+ 运行 `copilot-api auth login --provider qoder`(Edge 包使用 `copilot-api-edge`),输入 Qoder PAT 后正常启动网关即可。凭证沿用受保护的 `config.json`,无需单独运行 bridge 或配置 bridge key。支持文本和图片输入、SSE、模型目录与 Credits 查询,详见 [Qoder 配置说明](qoder-bridge/README.md)。本次适配已进入源码,尚待 npm 发布。
@@ -1,5 +1,5 @@
1
- import { F as PATHS, I as ensurePaths, P as setConfiguredApiKeys, a as normalizeProviderBaseUrl, c as setProviderConfig, n as getRawProviderConfig, r as isSupportedProviderType, y as SUPPORTED_PROVIDER_TYPES } from "./config-A1SyzmBJ.js";
2
- import { A as getConfiguredApiKeys, K as state, M as loginCodex, a as setupGitHubToken, n as persistCodexCredentials } from "./token-CQyKjtuM.js";
1
+ import { L as setConfiguredApiKeys, R as PATHS, a as normalizeProviderBaseUrl, c as setProviderConfig, l as QODER_SDK_BASE_URL, n as getRawProviderConfig, r as isSupportedProviderType, x as SUPPORTED_PROVIDER_TYPES, z as ensurePaths } from "./config-DnMKoKrg.js";
2
+ import { A as getConfiguredApiKeys, K as state, M as loginCodex, a as setupGitHubToken, n as persistCodexCredentials } from "./token-CQftvMU4.js";
3
3
  import { defineCommand } from "citty";
4
4
  import consola from "consola";
5
5
  //#region src/lib/quick-providers.ts
@@ -86,7 +86,7 @@ async function prompt(message, options) {
86
86
  const authArgs = {
87
87
  provider: {
88
88
  type: "string",
89
- description: "Provider to log in with or configure (copilot, codex, opencode-go, kimi, deepseek, dashscope, openrouter, custom)"
89
+ description: "Provider to log in with or configure (copilot, codex, qoder, opencode-go, kimi, deepseek, dashscope, openrouter, custom)"
90
90
  },
91
91
  verbose: {
92
92
  alias: "v",
@@ -100,7 +100,11 @@ const authArgs = {
100
100
  description: "Show provider access token on auth"
101
101
  }
102
102
  };
103
- const BUILTIN_PROVIDER_NAMES = ["copilot", "codex"];
103
+ const BUILTIN_PROVIDER_NAMES = [
104
+ "copilot",
105
+ "codex",
106
+ "qoder"
107
+ ];
104
108
  const QUICK_PROVIDER_NAMES = Object.keys(QUICK_PROVIDER_CONFIGS);
105
109
  const AUTH_PROVIDER_NAMES = [
106
110
  ...BUILTIN_PROVIDER_NAMES,
@@ -113,6 +117,7 @@ const CUSTOM_PROVIDER_AUTH_TYPES = ["x-api-key", "authorization"];
113
117
  const AUTH_PROVIDER_LABELS = {
114
118
  copilot: "GitHub Copilot",
115
119
  codex: "OpenAI Codex",
120
+ qoder: "Qoder (Personal Access Token)",
116
121
  "opencode-go": "OpenCode Go",
117
122
  kimi: "Kimi",
118
123
  deepseek: "DeepSeek",
@@ -344,6 +349,19 @@ async function loginWithProvider(provider) {
344
349
  await loginWithCodex();
345
350
  return;
346
351
  }
352
+ if (provider === "qoder") {
353
+ const apiKey = await promptRequiredSecret("Enter Qoder Personal Access Token", "PAT");
354
+ const existing = getRawProviderConfig("qoder");
355
+ setProviderConfig("qoder", {
356
+ type: "openai-compatible",
357
+ enabled: true,
358
+ baseUrl: QODER_SDK_BASE_URL,
359
+ apiKey,
360
+ ...existing?.models ? { models: existing.models } : {}
361
+ });
362
+ consola.success(`Qoder PAT written to ${PATHS.CONFIG_PATH}. Start the gateway normally to use qoder/<model>.`);
363
+ return;
364
+ }
347
365
  if (isQuickProviderName(provider)) {
348
366
  await configureQuickProvider(provider);
349
367
  return;
@@ -356,7 +374,7 @@ async function runProviderSetup() {
356
374
  await loginWithProvider(provider);
357
375
  }
358
376
  async function runAuthLogin(options) {
359
- (await import("./tls-Aq1Dd8E2.js")).enableSystemCACompat();
377
+ (await import("./tls-B5VJAJJM.js")).enableSystemCACompat();
360
378
  if (options.verbose) {
361
379
  consola.level = 5;
362
380
  consola.info("Verbose logging enabled");
@@ -396,7 +414,7 @@ function normalizeAuthKeyValue(value) {
396
414
  return normalizedKey;
397
415
  }
398
416
  async function runAuthKeys(options) {
399
- (await import("./tls-Aq1Dd8E2.js")).enableSystemCACompat();
417
+ (await import("./tls-B5VJAJJM.js")).enableSystemCACompat();
400
418
  await ensurePaths();
401
419
  const operations = [
402
420
  ...options.add !== void 0 ? ["add"] : [],
@@ -0,0 +1,2 @@
1
+ import { t as auth } from "./auth-D-M3qCeV.js";
2
+ export { auth };
@@ -1,47 +1,47 @@
1
- import consola from "consola";
2
- import { randomBytes } from "node:crypto";
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import fs$1 from "node:fs/promises";
1
+ import fs from "node:fs/promises";
6
2
  import os from "node:os";
3
+ import path from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ import consola from "consola";
6
+ import fs$1 from "node:fs";
7
7
  //#region src/lib/atomic-file.ts
8
8
  const TEMP_FILE_RANDOM_BYTES = 8;
9
9
  const fsyncDirectory = (directory) => {
10
10
  if (process.platform === "win32") return;
11
11
  let directoryFd;
12
12
  try {
13
- directoryFd = fs.openSync(directory, "r");
14
- fs.fsyncSync(directoryFd);
13
+ directoryFd = fs$1.openSync(directory, "r");
14
+ fs$1.fsyncSync(directoryFd);
15
15
  } catch (error) {
16
16
  console.warn(`Failed to fsync directory: ${directory}`, error);
17
17
  } finally {
18
18
  if (directoryFd !== void 0) try {
19
- fs.closeSync(directoryFd);
19
+ fs$1.closeSync(directoryFd);
20
20
  } catch {}
21
21
  }
22
22
  };
23
23
  function writeFileAtomically(filePath, content) {
24
24
  const directory = path.dirname(filePath);
25
25
  const tempPath = path.join(directory, `.${path.basename(filePath)}.${process.pid}.${randomBytes(TEMP_FILE_RANDOM_BYTES).toString("hex")}.tmp`);
26
- fs.mkdirSync(directory, { recursive: true });
26
+ fs$1.mkdirSync(directory, { recursive: true });
27
27
  let fileDescriptor;
28
28
  let tempFileCreated = false;
29
29
  try {
30
- fileDescriptor = fs.openSync(tempPath, "wx", 384);
30
+ fileDescriptor = fs$1.openSync(tempPath, "wx", 384);
31
31
  tempFileCreated = true;
32
- fs.writeFileSync(fileDescriptor, content, "utf8");
33
- fs.fsyncSync(fileDescriptor);
34
- fs.closeSync(fileDescriptor);
32
+ fs$1.writeFileSync(fileDescriptor, content, "utf8");
33
+ fs$1.fsyncSync(fileDescriptor);
34
+ fs$1.closeSync(fileDescriptor);
35
35
  fileDescriptor = void 0;
36
- fs.renameSync(tempPath, filePath);
36
+ fs$1.renameSync(tempPath, filePath);
37
37
  tempFileCreated = false;
38
38
  fsyncDirectory(directory);
39
39
  } catch (error) {
40
40
  if (fileDescriptor !== void 0) try {
41
- fs.closeSync(fileDescriptor);
41
+ fs$1.closeSync(fileDescriptor);
42
42
  } catch {}
43
43
  if (tempFileCreated) try {
44
- fs.rmSync(tempPath, { force: true });
44
+ fs$1.rmSync(tempPath, { force: true });
45
45
  } catch {}
46
46
  throw error;
47
47
  }
@@ -59,16 +59,16 @@ const PATHS = {
59
59
  CONFIG_PATH: path.join(APP_DIR, "config.json")
60
60
  };
61
61
  async function ensurePaths() {
62
- await fs$1.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true });
62
+ await fs.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true });
63
63
  await ensureFile(PATHS.GITHUB_TOKEN_PATH);
64
64
  await ensureFile(PATHS.CONFIG_PATH);
65
65
  }
66
66
  async function ensureFile(filePath) {
67
67
  try {
68
- await fs$1.access(filePath, fs$1.constants.W_OK);
68
+ await fs.access(filePath, fs.constants.W_OK);
69
69
  } catch {
70
- await fs$1.writeFile(filePath, "");
71
- await fs$1.chmod(filePath, 384);
70
+ await fs.writeFile(filePath, "");
71
+ await fs.chmod(filePath, 384);
72
72
  }
73
73
  }
74
74
  //#endregion
@@ -140,11 +140,11 @@ function isNodeError(error) {
140
140
  }
141
141
  function ensureConfigFile() {
142
142
  try {
143
- fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK | fs.constants.W_OK);
143
+ fs$1.accessSync(PATHS.CONFIG_PATH, fs$1.constants.R_OK | fs$1.constants.W_OK);
144
144
  } catch {
145
145
  writeFileAtomically(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`);
146
146
  try {
147
- fs.chmodSync(PATHS.CONFIG_PATH, 384);
147
+ fs$1.chmodSync(PATHS.CONFIG_PATH, 384);
148
148
  } catch {
149
149
  return;
150
150
  }
@@ -152,7 +152,7 @@ function ensureConfigFile() {
152
152
  }
153
153
  function readConfigFromDisk() {
154
154
  ensureConfigFile();
155
- const raw = fs.readFileSync(PATHS.CONFIG_PATH, "utf8");
155
+ const raw = fs$1.readFileSync(PATHS.CONFIG_PATH, "utf8");
156
156
  if (!raw.trim()) {
157
157
  writeFileAtomically(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`);
158
158
  return defaultConfig;
@@ -167,7 +167,7 @@ function readConfigFromDisk() {
167
167
  }
168
168
  function readEditableConfigFromDisk() {
169
169
  try {
170
- const raw = fs.readFileSync(PATHS.CONFIG_PATH, "utf8");
170
+ const raw = fs$1.readFileSync(PATHS.CONFIG_PATH, "utf8");
171
171
  if (!raw.trim()) return {};
172
172
  return JSON.parse(raw);
173
173
  } catch (error) {
@@ -303,6 +303,10 @@ function isMessagesApiEnabled() {
303
303
  function isResponsesApiWebSocketEnabled() {
304
304
  return getConfig().useResponsesApiWebSocket ?? true;
305
305
  }
306
+ function isCodexResponsesApiWebSocketEnabled() {
307
+ const config = getConfig();
308
+ return typeof config.useCodexResponsesApiWebSocket === "boolean" ? config.useCodexResponsesApiWebSocket : isResponsesApiWebSocketEnabled();
309
+ }
306
310
  function isCopilotFastTierEnabled() {
307
311
  return getConfig().useCopilotFastTier ?? true;
308
312
  }
@@ -444,6 +448,12 @@ function getReasoningEffortForModel(model) {
444
448
  return isGpt53OrAbove(model) ? "xhigh" : "high";
445
449
  }
446
450
  //#endregion
451
+ //#region src/lib/qoder-config.ts
452
+ const QODER_SDK_BASE_URL = "qoder://sdk";
453
+ function isQoderSdkProvider(provider) {
454
+ return provider.name === "qoder" && provider.baseUrl === "qoder://sdk";
455
+ }
456
+ //#endregion
447
457
  //#region src/lib/provider-config.ts
448
458
  const OPENCODE_ANTHROPIC_MODEL_PATTERN = /^(?:qwen|minimax)/iu;
449
459
  const OPENCODE_RESPONSES_MODEL_PATTERN = /^(?:gpt|grok|muse-spark)(?:[-_.]|$)/iu;
@@ -502,12 +512,12 @@ function getProviderConfig(name) {
502
512
  const provider = getRawProviderConfig(providerName);
503
513
  if (!provider) return null;
504
514
  if (provider.enabled === false) return null;
505
- const type = provider.type ?? "anthropic";
515
+ const type = provider.type ?? (providerName === "qoder" ? "openai-compatible" : "anthropic");
506
516
  if (!isSupportedProviderType(type)) {
507
517
  consola.warn(`Provider ${providerName} is ignored because type '${type}' is not supported`);
508
518
  return null;
509
519
  }
510
- const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? "");
520
+ const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? (providerName === "qoder" ? "qoder://sdk" : ""));
511
521
  const authType = resolveProviderAuthType(providerName, provider.authType, type);
512
522
  const apiKey = (provider.apiKey ?? "").trim();
513
523
  const missingFields = [...baseUrl ? [] : ["baseUrl"], ...isProviderApiKeyRequired(providerName, authType) && !apiKey ? ["apiKey"] : []];
@@ -545,4 +555,4 @@ function isReservedProviderName(name) {
545
555
  return name.trim() === "copilot";
546
556
  }
547
557
  //#endregion
548
- export { isResponsesApiCompactionRecoveryEnabled as A, getClaudeTokenMultiplier as C, isAlphaSearchCodexPriorityEnabled as D, getResponsesTransportConfig as E, PATHS as F, ensurePaths as I, isResponsesApiWebSocketEnabled as M, mergeConfigWithDefaults as N, isCopilotFastTierEnabled as O, setConfiguredApiKeys as P, getClaudeAutoModel as S, getMessageApiWebSearchModel as T, resolveMappedModel as _, normalizeProviderBaseUrl as a, getAlphaSearchModel as b, setProviderConfig as c, getModelResponsesApiCompactThreshold as d, getReasoningEffortForModel as f, isGpt56OrAbove as g, isContextManagementEnabledForResponses as h, listEnabledProviders as i, isResponsesApiWebSearchEnabled as j, isMessagesApiEnabled as k, getExtraPromptForModel as l, isContextManagementEnabledForMessages as m, getRawProviderConfig as n, resolveEffectiveProviderType as o, getSmallModel as p, isSupportedProviderType as r, resolveProviderAuthType as s, getProviderConfig as t, getModelMappings as u, setModelMappings as v, getConfig as w, getAnthropicApiKey as x, SUPPORTED_PROVIDER_TYPES as y };
558
+ export { isCodexResponsesApiWebSocketEnabled as A, writeFileAtomically as B, getAnthropicApiKey as C, getMessageApiWebSearchModel as D, getConfig as E, isResponsesApiWebSocketEnabled as F, mergeConfigWithDefaults as I, setConfiguredApiKeys as L, isMessagesApiEnabled as M, isResponsesApiCompactionRecoveryEnabled as N, getResponsesTransportConfig as O, isResponsesApiWebSearchEnabled as P, PATHS as R, getAlphaSearchModel as S, getClaudeTokenMultiplier as T, isContextManagementEnabledForResponses as _, normalizeProviderBaseUrl as a, setModelMappings as b, setProviderConfig as c, getExtraPromptForModel as d, getModelMappings as f, isContextManagementEnabledForMessages as g, getSmallModel as h, listEnabledProviders as i, isCopilotFastTierEnabled as j, isAlphaSearchCodexPriorityEnabled as k, QODER_SDK_BASE_URL as l, getReasoningEffortForModel as m, getRawProviderConfig as n, resolveEffectiveProviderType as o, getModelResponsesApiCompactThreshold as p, isSupportedProviderType as r, resolveProviderAuthType as s, getProviderConfig as t, isQoderSdkProvider as u, isGpt56OrAbove as v, getClaudeAutoModel as w, SUPPORTED_PROVIDER_TYPES as x, resolveMappedModel as y, ensurePaths as z };
@@ -1,8 +1,8 @@
1
- import { F as PATHS, i as listEnabledProviders, n as getRawProviderConfig } from "./config-A1SyzmBJ.js";
2
- import { defineCommand } from "citty";
3
- import consola from "consola";
1
+ import { R as PATHS, i as listEnabledProviders, n as getRawProviderConfig } from "./config-DnMKoKrg.js";
4
2
  import fs from "node:fs/promises";
5
3
  import os from "node:os";
4
+ import { defineCommand } from "citty";
5
+ import consola from "consola";
6
6
  import { fileURLToPath } from "node:url";
7
7
  //#region src/debug.ts
8
8
  async function getPackageVersion() {
package/dist/main.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { t as isMcpFastPath } from "./fast-path-BoMnZCVC.js";
3
3
  //#region src/main.ts
4
4
  if (isMcpFastPath(process.argv)) {
5
- const { runMcpServer } = await import("./mcp-server-DQ4r-fAy.js");
5
+ const { runMcpServer } = await import("./mcp-server-Byq5DomJ.js");
6
6
  await runMcpServer();
7
7
  } else {
8
8
  const { defineCommand, runMain, parseArgs } = await import("citty");
@@ -25,12 +25,12 @@ if (isMcpFastPath(process.argv)) {
25
25
  if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
26
26
  if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
27
27
  if (process.platform === "win32" && process.stdout.isTTY && !process.env.WT_SESSION) process.env.WT_SESSION = "copilot-api";
28
- const { bindElectronFetch } = await import("./electron-fetch-BRX-ug5E.js");
28
+ const { bindElectronFetch } = await import("./electron-fetch-D5uOld7F.js");
29
29
  bindElectronFetch();
30
- const { auth } = await import("./auth-D-Wpolvg.js");
31
- const { debug } = await import("./debug-Dnic5hxU.js");
32
- const { mcp } = await import("./mcp-fpSlKZxK.js");
33
- const { start } = await import("./start-DCKDnLr6.js");
30
+ const { auth } = await import("./auth-DIGdDJx3.js");
31
+ const { debug } = await import("./debug-CuLfQpTq.js");
32
+ const { mcp } = await import("./mcp-DqslOG3W.js");
33
+ const { start } = await import("./start-BRXpCbKi.js");
34
34
  await runMain(defineCommand({
35
35
  meta: {
36
36
  name: "copilot-api",
@@ -1,4 +1,4 @@
1
- import { t as runMcpServer } from "./mcp-server-BeNu_Edl.js";
1
+ import { t as runMcpServer } from "./mcp-server-B-_dWuXe.js";
2
2
  import { defineCommand } from "citty";
3
3
  //#region src/mcp.ts
4
4
  const mcp = defineCommand({
@@ -1,4 +1,4 @@
1
- import { n as createMcpToolSearchSentinel } from "./tool-search-Ds1vbmGG.js";
1
+ import { n as createMcpToolSearchSentinel } from "./tool-search-DCb3HbWj.js";
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
@@ -0,0 +1,2 @@
1
+ import { t as runMcpServer } from "./mcp-server-B-_dWuXe.js";
2
+ export { runMcpServer };