xiaodcs-copilot-api 2.4.1-public.1 → 2.5.1-public.2
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 +33 -9
- package/README.zh-CN.md +33 -9
- package/dist/{auth-CZhugmTr.js → auth-D-M3qCeV.js} +24 -6
- package/dist/auth-DIGdDJx3.js +2 -0
- package/dist/{config-A1SyzmBJ.js → config-DnMKoKrg.js} +37 -27
- package/dist/{debug-Dnic5hxU.js → debug-CuLfQpTq.js} +3 -3
- package/dist/main.js +6 -6
- package/dist/{mcp-fpSlKZxK.js → mcp-DqslOG3W.js} +1 -1
- package/dist/{mcp-server-BeNu_Edl.js → mcp-server-B-_dWuXe.js} +1 -1
- package/dist/mcp-server-Byq5DomJ.js +2 -0
- package/dist/protocol-BTFLbI8m.js +257 -0
- package/dist/provider-proxy-BbLwvtD_.js +263 -0
- package/dist/runtime-CWU5BNBf.js +442 -0
- package/dist/{server-wD8xXlqc.js → server-DmKNMBLd.js} +660 -478
- package/dist/{start-DCKDnLr6.js → start-WdcRgBSL.js} +110 -11
- package/dist/{token-CQyKjtuM.js → token-CQftvMU4.js} +37 -24
- package/dist/transport-DE8Q0wU-.js +252 -0
- package/dist/transport-HOWgkXsv.js +2 -0
- package/package.json +18 -8
- package/qoder-bridge/README.md +112 -0
- package/dist/auth-D-Wpolvg.js +0 -2
- package/dist/mcp-server-DQ4r-fAy.js +0 -2
- package/dist/models-CmzVpYlg.js +0 -88
- /package/dist/{electron-fetch-BRX-ug5E.js → electron-fetch-D5uOld7F.js} +0 -0
- /package/dist/{tls-Aq1Dd8E2.js → tls-B5VJAJJM.js} +0 -0
- /package/dist/{tool-search-Ds1vbmGG.js → tool-search-DCb3HbWj.js} +0 -0
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
|
|
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
|
|
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`.
|
|
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:**
|
|
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
|
|
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,7 @@ 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.
|
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
|
|
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
|
|
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
|
|
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:**
|
|
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
|
|
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 {
|
|
2
|
-
import { A as getConfiguredApiKeys, K as state, M as loginCodex, a as setupGitHubToken, n as persistCodexCredentials } from "./token-
|
|
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 = [
|
|
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-
|
|
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-
|
|
417
|
+
(await import("./tls-B5VJAJJM.js")).enableSystemCACompat();
|
|
400
418
|
await ensurePaths();
|
|
401
419
|
const operations = [
|
|
402
420
|
...options.add !== void 0 ? ["add"] : [],
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
|
68
|
+
await fs.access(filePath, fs.constants.W_OK);
|
|
69
69
|
} catch {
|
|
70
|
-
await fs
|
|
71
|
-
await fs
|
|
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 {
|
|
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 {
|
|
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-
|
|
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-
|
|
28
|
+
const { bindElectronFetch } = await import("./electron-fetch-D5uOld7F.js");
|
|
29
29
|
bindElectronFetch();
|
|
30
|
-
const { auth } = await import("./auth-
|
|
31
|
-
const { debug } = await import("./debug-
|
|
32
|
-
const { mcp } = await import("./mcp-
|
|
33
|
-
const { start } = await import("./start-
|
|
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-WdcRgBSL.js");
|
|
34
34
|
await runMain(defineCommand({
|
|
35
35
|
meta: {
|
|
36
36
|
name: "copilot-api",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createMcpToolSearchSentinel } from "./tool-search-
|
|
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";
|