Skip to content

Commit 546ca1f

Browse files
merge: integrate caozhiyuan dev updates into dev
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2 parents f4d91fb + 36b4931 commit 546ca1f

90 files changed

Lines changed: 17661 additions & 921 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
1-
name: CI
2-
3-
on:
4-
push:
5-
branches: [master]
6-
pull_request:
7-
types: [opened, synchronize, reopened]
8-
9-
jobs:
10-
test:
11-
runs-on: ubuntu-latest
12-
steps:
13-
- uses: actions/checkout@v4
14-
15-
- uses: oven-sh/setup-bun@v2
16-
with:
17-
bun-version: latest
18-
19-
- name: Install dependencies
20-
run: bun install
21-
22-
- name: Run linter
23-
run: bun run lint:all
24-
25-
- name: Run type check
26-
run: bun run typecheck
27-
28-
- name: Run tests
29-
run: bun test
30-
31-
- name: Build
32-
run: bun run build
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ "main", "dev" ]
6+
pull_request:
7+
types: [opened, synchronize, reopened]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: "22.13.0"
18+
19+
- name: Verify Node sqlite support
20+
run: node -e "import('node:sqlite').then(() => console.log('node:sqlite ok')).catch((error) => { console.error(error); process.exit(1) })"
21+
22+
- uses: oven-sh/setup-bun@v2
23+
with:
24+
bun-version: latest
25+
26+
- name: Install dependencies
27+
run: bun install
28+
29+
- name: Run linter
30+
run: bun run lint:all
31+
32+
- name: Run type check
33+
run: bun run typecheck
34+
35+
- name: Run tests
36+
run: bun test
37+
38+
- name: Build
39+
run: bun run build
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: Release Desktop
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
# ─── macOS Apple Silicon (arm64) ─────────────────────────────────────────
13+
build-mac-arm64:
14+
name: Build macOS (Apple Silicon)
15+
runs-on: macos-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- uses: oven-sh/setup-bun@v2
20+
with:
21+
bun-version: latest
22+
23+
- name: Install root dependencies
24+
run: bun install
25+
26+
- name: Build server
27+
run: bun run build
28+
29+
- uses: actions/setup-node@v4
30+
with:
31+
node-version: "22.13.0"
32+
33+
- name: Install desktop dependencies
34+
working-directory: desktop
35+
run: npm install
36+
37+
- name: Build macOS arm64 package
38+
working-directory: desktop
39+
run: npm run package:mac
40+
env:
41+
CSC_IDENTITY_AUTO_DISCOVERY: false
42+
43+
- uses: actions/upload-artifact@v4
44+
with:
45+
name: mac-arm64
46+
path: desktop/release/*.dmg
47+
if-no-files-found: warn
48+
49+
# ─── Windows ─────────────────────────────────────────────────────────────
50+
build-win:
51+
name: Build Windows
52+
runs-on: windows-latest
53+
steps:
54+
- uses: actions/checkout@v4
55+
56+
- uses: oven-sh/setup-bun@v2
57+
with:
58+
bun-version: latest
59+
60+
- name: Install root dependencies
61+
run: bun install
62+
63+
- name: Build server
64+
run: bun run build
65+
66+
- uses: actions/setup-node@v4
67+
with:
68+
node-version: "22.13.0"
69+
70+
- name: Install desktop dependencies
71+
working-directory: desktop
72+
run: npm install
73+
74+
- name: Build Windows package
75+
working-directory: desktop
76+
run: npm run package:win
77+
env:
78+
CSC_IDENTITY_AUTO_DISCOVERY: false
79+
80+
- uses: actions/upload-artifact@v4
81+
with:
82+
name: win
83+
path: |
84+
desktop/release/*.exe
85+
desktop/release/*.msi
86+
if-no-files-found: warn
87+
88+
# ─── Upload all artifacts to the GitHub Release ──────────────────────────
89+
release-upload:
90+
name: Upload to Release
91+
needs: [ build-mac-arm64, build-win ]
92+
runs-on: ubuntu-latest
93+
steps:
94+
- uses: actions/download-artifact@v4
95+
with:
96+
path: artifacts
97+
merge-multiple: true
98+
99+
- name: List artifacts
100+
run: find artifacts -type f | sort
101+
102+
- name: Wait for GitHub Release to be created
103+
run: |
104+
for i in {1..12}; do
105+
if gh release view "${{ github.ref_name }}" \
106+
--repo "${{ github.repository }}" > /dev/null 2>&1; then
107+
echo "Release exists, proceeding."
108+
break
109+
fi
110+
echo "Release not found yet, waiting 30s... ($i/12)"
111+
sleep 30
112+
done
113+
env:
114+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
115+
116+
- name: Upload artifacts to GitHub Release
117+
run: |
118+
find artifacts -type f -exec \
119+
gh release upload "${{ github.ref_name }}" {} --clobber \;
120+
env:
121+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122+
GH_REPO: ${{ github.repository }}

README.md

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ English | [简体中文](./README.zh-CN.md)
2121
2222
---
2323

24-
> [!NOTE]
25-
> [opencode](https://github.com/sst/opencode) already ships with a built-in GitHub Copilot provider, so you may not need this project for basic usage. This proxy is still useful if you want OpenCode to talk to Copilot through `@ai-sdk/anthropic`, preserve Anthropic Messages semantics for tool use, prefer the native Messages API over Chat Completions API for Claude-family models, use gpt phase-aware commentary, or optimize premium requests.
26-
27-
---
28-
2924
## Important Notes
3025

3126
> [!IMPORTANT]
@@ -67,7 +62,7 @@ Compared with routing everything through plain Chat Completions compatibility, t
6762
- **Opencode OAuth Support**: Use opencode GitHub Copilot authentication by setting `COPILOT_API_OAUTH_APP=opencode` environment variable or using `--oauth-app=opencode` command line option.
6863
- **GitHub Enterprise Support**: Connect to GHE.com by setting `COPILOT_API_ENTERPRISE_URL` environment variable (e.g., `company.ghe.com`) or using `--enterprise-url=company.ghe.com` command line option.
6964
- **Custom Data Directory**: Change the default data directory (where tokens and config are stored) by setting `COPILOT_API_HOME` environment variable or using `--api-home=/path/to/dir` command line option.
70-
- **Multi-Provider Anthropic Proxy Routes**: Add global provider configs and call external Anthropic-compatible APIs via `/:provider/v1/messages` and `/:provider/v1/models`.
65+
- **Multi-Provider Messages Proxy Routes**: Add global provider configs and call external Anthropic-compatible or OpenAI-compatible APIs via `/:provider/v1/messages` and `/:provider/v1/models`.
7166
- **Accurate Claude Token Counting**: Optionally forward `/v1/messages/count_tokens` requests for Claude models to Anthropic's free token counting endpoint for exact counts instead of GPT tokenizer estimation.
7267
- **GPT Context Management**: Configurable context compaction for long-running GPT conversations via `responsesApiContextManagementModels`, reducing unnecessary premium requests when approaching token limits. See [Configuration](#configuration-configjson) for details.
7368
@@ -129,6 +124,7 @@ When an Anthropic API key is configured, the proxy forwards Claude model token c
129124
## Prerequisites
130125
131126
- Bun (>= 1.2.x)
127+
- Node.js if you plan to run the published CLI with `npx`
132128
- GitHub account with Copilot subscription (individual, business, or enterprise)
133129
134130
## Installation
@@ -149,6 +145,11 @@ bun run start start
149145
150146
You can run the project directly using npx:
151147
148+
> [!IMPORTANT]
149+
> Token usage storage uses Node's built-in `node:sqlite` module when running with `npx`. It is enabled on Node.js >= 22.13.0. On Node.js < 22.13.0, the CLI still starts, but token usage storage is disabled.
150+
>
151+
> If you want token usage storage without upgrading Node.js, run the published CLI with Bun instead: `bunx --bun @jeffreycao/copilot-api@latest start`.
152+
152153
```sh
153154
npx @jeffreycao/copilot-api@latest start
154155
```
@@ -165,6 +166,16 @@ For authentication only:
165166
npx @jeffreycao/copilot-api@latest auth
166167
```
167168

169+
## Electron Desktop App
170+
171+
If you prefer a GUI, this repository also includes an Electron desktop app in `desktop/`. It supports GitHub Copilot sign-in or manual token entry, can start and stop the local proxy with one click, and shows the local endpoint, auth header, available models, usage, and logs in the app.
172+
173+
The settings screen also exposes `OAuth App`, `API Home`, `Enterprise URL`, verbose logging, and minimize-to-tray. Desktop packages are published in GitHub Releases:
174+
175+
https://github.com/caozhiyuan/copilot-api/releases
176+
177+
Download the installer for your platform, sign in inside the app, choose a port, start the server, then point your client at the local endpoint shown in the app. Packaged desktop builds use the bundled Electron runtime, so normal desktop usage does not require installing Node.js separately. Token usage history is enabled when that bundled runtime supports SQLite.
178+
168179
## Using with Docker
169180

170181
Build image
@@ -298,6 +309,31 @@ The following command line options are available for the `start` command:
298309
"topP": 0.95
299310
}
300311
}
312+
},
313+
"dashscope": {
314+
"type": "openai-compatible",
315+
"enabled": true,
316+
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode",
317+
"apiKey": "sk-your-dashscope-key",
318+
"models": {
319+
"qwen3.6-plus": {
320+
"temperature": 1,
321+
"topP": 0.95,
322+
"topK": 20,
323+
"extraBody": {
324+
"preserve_thinking": true
325+
},
326+
"contextCache": true
327+
},
328+
"glm-5.1": {
329+
"temperature": 0.7,
330+
"topP": 0.95,
331+
"contextCache": true,
332+
"extraBody": {
333+
"preserve_thinking": true
334+
}
335+
}
336+
}
301337
}
302338
},
303339
"extraPrompts": {
@@ -321,16 +357,20 @@ The following command line options are available for the `start` command:
321357
```
322358
- **auth.apiKeys:** API keys used for request authentication. Supports multiple keys for rotation. Requests can authenticate with either `x-api-key: <key>` or `Authorization: Bearer <key>`. If empty or omitted, authentication is disabled.
323359
- **extraPrompts:** Map of `model -> prompt` appended to the first system prompt when translating Anthropic-style requests to Copilot. Use this to inject guardrails or guidance per model. Missing default entries are auto-added without overwriting your custom prompts. The built-in prompts for `gpt-5.3-codex` and `gpt-5.4` enable phase-aware commentary, which lets the model emit a short user-facing progress update before tools or deeper reasoning.
324-
- **providers:** Global upstream provider map. Each provider key (for example `custom`) becomes a route prefix (`/custom/v1/messages`). Currently only `type: "anthropic"` is supported.
360+
- **providers:** Global upstream provider map. Each provider key (for example `custom`) becomes a route prefix (`/custom/v1/messages`). Supports `type: "anthropic"` and `type: "openai-compatible"`.
325361
- `enabled` defaults to `true` if omitted.
326-
- `baseUrl` should be provider API base URL without trailing `/v1/messages`.
362+
- `baseUrl` should be provider API base URL without the final endpoint. For Anthropic providers, omit `/v1/messages`; for OpenAI-compatible providers, omit `/v1/chat/completions`.
327363
- `apiKey` is used as the upstream credential value.
328-
- `authType` (optional): Controls how `apiKey` is sent upstream. Supports `x-api-key` (default) and `authorization`. When set to `authorization`, the proxy sends `Authorization: Bearer <apiKey>`.
364+
- `authType` (optional): Controls how `apiKey` is sent upstream. Supports `x-api-key` and `authorization`. Anthropic providers default to `x-api-key`; OpenAI-compatible providers default to `authorization`. When set to `authorization`, the proxy sends `Authorization: Bearer <apiKey>`.
329365
- `adjustInputTokens` (optional): When `true`, the proxy will adjust the `input_tokens` in the usage response by subtracting `cache_read_input_tokens` and `cache_creation_input_tokens`.
330366
- `models` (optional): Per-model configuration map. Each key is a model ID (matching the model name in requests), and the value is:
331367
- `temperature` (optional): Default temperature value used when the request does not specify one.
332368
- `topP` (optional): Default top_p value used when the request does not specify one.
333369
- `topK` (optional): Default top_k value used when the request does not specify one.
370+
- `extraBody` (optional): Dynamic fields merged into the upstream request body for that model. Request body fields with the same name take precedence. OpenAI-compatible providers can use this for fields such as `enable_thinking`, `preserve_thinking`, `reasoning_effort`.
371+
- `contextCache` (optional): Defaults to `true` for OpenAI-compatible providers. This enables Alibaba Cloud Model Studio/DashScope explicit context cache by injecting `cache_control: { "type": "ephemeral" }` on up to 4 content blocks using the Context Cache format. The cache breakpoint strategy matches opencode's main provider flow: the first 2 system messages plus the last 2 non-system messages. Marked string content is converted to text content part arrays for `system` / `user` / `assistant` / `tool` messages; existing array content is marked on the last part. Set this to `false` when the model already supports implicit caching, or when the upstream does not accept this explicit-cache extension field.
372+
- `supportPdf` (optional): Controls whether the model supports PDF/document content. Defaults to `false`; unsupported PDFs are converted to a text notice. Set it to `true` to send PDF/document blocks as OpenAI Chat Completions file parts.
373+
- `toolContentSupportType` (optional): Tool result content capabilities for that model, as an array of `array`, `image`, and `pdf`. Provider routes default to string-only tool content when omitted. If `supportPdf` is `true` but this list does not include `pdf`, file parts in tool results are moved to user role messages. This provider default does not change the Copilot main flow, which continues to support array + image and not PDF.
334374
- **smallModel:** Fallback model used for tool-less warmup messages (e.g., Claude Code probe requests) to avoid spending premium requests; defaults to gpt-5-mini.
335375
- **responsesApiContextManagementModels:** List of GPT model IDs that should receive Responses API `context_management` compaction instructions. This defaults to `[]`, so you need to opt in explicitly. A good starting point is `["gpt-5-mini", "gpt-5.3-codex", "gpt-5.4-mini", "gpt-5.4"]`. When enabled, the request includes `context_management` in the body and keeps only the latest compaction carrier on follow-up turns. The actual compaction is handled server-side and appears to begin when usage approaches roughly 90% of the model's `maxPromptTokens`, which makes it especially useful for long-running tasks without consuming additional premium requests. In practice, the effective `compact_threshold` also appears to be fixed on the server side, so changing it in this project does not currently alter compaction behavior. At the moment, this optimization is intended for GPT-family models only.
336376
- **modelReasoningEfforts:** Per-model `reasoning.effort` sent to the Copilot Responses API. Allowed values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. If a model isn’t listed, `high` is used by default.
@@ -381,8 +421,8 @@ These endpoints are designed to be compatible with the Anthropic Messages API.
381421
| -------------------------------- | ------ | ------------------------------------------------------------ |
382422
| `POST /v1/messages` | `POST` | Creates a model response for a given conversation. |
383423
| `POST /v1/messages/count_tokens` | `POST` | Calculates the number of tokens for a given set of messages. |
384-
| `POST /:provider/v1/messages` | `POST` | Proxies Anthropic Messages API to the configured provider. |
385-
| `GET /:provider/v1/models` | `GET` | Proxies Anthropic Models API to the configured provider. |
424+
| `POST /:provider/v1/messages` | `POST` | Proxies Anthropic Messages requests to the configured Anthropic or OpenAI-compatible provider. |
425+
| `GET /:provider/v1/models` | `GET` | Proxies model listing requests to the configured provider. |
386426
| `POST /:provider/v1/messages/count_tokens` | `POST` | Calculates tokens locally for provider route requests. |
387427

388428
### Usage Monitoring Endpoints
@@ -455,6 +495,9 @@ npx @jeffreycao/copilot-api@latest --oauth-app=opencode start
455495
456496
# Combine multiple global options
457497
npx @jeffreycao/copilot-api@latest --api-home=/custom/path --oauth-app=opencode --enterprise-url=company.ghe.com start
498+
499+
# Run the published CLI with Bun instead of Node.js
500+
bunx --bun @jeffreycao/copilot-api@latest start
458501
```
459502

460503
## Using with OpenCode
@@ -561,6 +604,8 @@ After starting the server, a URL to the Copilot Usage Dashboard will be displaye
561604

562605
The dashboard provides a user-friendly interface to view your Copilot usage data:
563606

607+
> Token usage history requires Bun or Node.js >= 22.13.0. On Node.js < 22.13.0, the server runs normally but token usage storage is disabled.
608+
564609
- **API Endpoint URL**: The dashboard is pre-configured to fetch data from your local server endpoint via the URL query parameter. You can change this URL to point to any other compatible API endpoint.
565610
- **Fetch Data**: Click the "Fetch" button to load or refresh the usage data. The dashboard will automatically fetch data on load.
566611
- **Usage Quotas**: View a summary of your usage quotas for different services like Chat and Completions, displayed with progress bars for a quick overview.

0 commit comments

Comments
 (0)