copilot-relay 0.3.9 → 0.4.0

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
@@ -1,271 +1,65 @@
1
1
  # copilot-relay
2
2
 
3
+ **Use Claude Code with the models available through your GitHub Copilot subscription.**
4
+
3
5
  [![CI](https://github.com/D0n9X1n/copilot-relay/actions/workflows/ci.yml/badge.svg)](https://github.com/D0n9X1n/copilot-relay/actions/workflows/ci.yml)
4
6
  [![npm version](https://img.shields.io/npm/v/copilot-relay.svg?logo=npm)](https://www.npmjs.com/package/copilot-relay)
5
- [![npm downloads](https://img.shields.io/npm/dm/copilot-relay.svg?logo=npm)](https://www.npmjs.com/package/copilot-relay)
6
- [![GitHub Packages](https://img.shields.io/badge/GitHub%20Packages-ready-24292f?logo=github)](https://github.com/D0n9X1n/copilot-relay/pkgs/npm/copilot-relay)
7
7
  [![Node.js](https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
8
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
- [![Claude Code](https://img.shields.io/badge/Claude%20Code-supported-d97757)](https://docs.anthropic.com/en/docs/claude-code/overview)
10
8
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
9
 
12
- Yet, just another relay for Claude Code to use a GitHub Copilot subscription.
13
-
14
- ## Disclaimer
15
-
16
- This is a research-oriented project and is not affiliated with GitHub, GitHub
17
- Copilot, Anthropic, or Claude Code. It depends on upstream GitHub Copilot
18
- services and undocumented compatibility behavior, so Copilot availability, model
19
- access, API behavior, and runtime stability are not guaranteed.
20
-
21
- Public API:
22
-
23
- - `POST /v1/messages`
24
- - `POST /v1/messages/count_tokens`
25
- - `GET /v1/models`
26
- - `GET /healthz`
27
- - `GET|HEAD /api/hello`
28
-
29
- `/api/hello` is a static reachability probe Claude Code sends on startup and
30
- around real traffic. Like `/healthz` it never contacts Copilot, so it proves the
31
- relay is listening and nothing more.
32
-
33
- Claude WebSearch is bridge-managed: when the model selects the WebSearch tool,
34
- the relay executes Copilot `/responses` with `web_search_preview`, then sends the
35
- retrieved context through a final model pass and returns Claude
36
- `server_tool_use` / `web_search_tool_result` blocks. The final pass keeps your
37
- other tools available, so the model can act on what it found in the same turn.
38
-
39
- Advertising WebSearch no longer costs streaming. The relay reads the model's
40
- response only as far as it takes to tell whether a search is coming, so a turn
41
- that never searches streams normally — which is most of them, since Claude Code
42
- offers the tool on every request.
43
-
44
- Unknown API routes return `500` and log method, path, selected headers, and
45
- request payload to help implement compatible endpoints later.
46
-
47
- Routing:
48
-
49
- | Requested model | Upstream model |
50
- | --- | --- |
51
- | contains `opus` | `claude-opus-5` |
52
- | `gpt-6-astra[1m]`, plain `gpt-6-astra`, or another non-Opus alias | `gpt-6-astra` |
53
-
54
- The fresh-install default is `gpt-6-astra`, exposed to Claude Code as
55
- `gpt-6-astra[1m]`. The selector changes Claude Code's client-side context budgeting
56
- only; Copilot receives the canonical `gpt-6-astra` ID. It does not enlarge
57
- upstream capacity. Existing `config.yaml` model choices are never migrated.
58
- If your account cannot use Astra, startup fails explicitly; choose a model your
59
- account supports rather than relying on an automatic fallback.
60
-
61
- Claude Code can still show its built-in Haiku and Sonnet picker entries. The
62
- managed `model` field sets the startup default but does not restrict
63
- `availableModels`; selecting any non-Opus alias still follows the GPT route.
64
-
65
- ## Install & run
66
-
67
- ```sh
68
- npx copilot-relay@latest auth
69
- npx copilot-relay@latest start
70
- npx copilot-relay@latest restart
71
- npx copilot-relay@latest stop
72
- ```
73
-
74
- With `claudeSetup: true`, `start` manages `ANTHROPIC_BASE_URL`, a dummy
75
- `ANTHROPIC_AUTH_TOKEN` when auth is absent, and the configured GPT default via
76
- the top-level `model` field in `~/.claude/settings.json`. Exact
77
- `gpt-6-astra` and `gpt-5.6-sol` overrides are normalized to Claude-facing
78
- `[1m]` identities when discovery reports exactly 1M; other reported windows use
79
- plain GPT IDs with Claude's numeric context setting. Unrelated model choices and
80
- existing token-budget overrides are preserved.
81
-
82
- Startup retains Copilot's actual context, prompt, and output limits and exposes
83
- them on `GET /v1/models`. Managed Claude setup seeds
84
- `CLAUDE_CODE_MAX_CONTEXT_TOKENS` and `CLAUDE_CODE_MAX_OUTPUT_TOKENS` when absent.
85
- The default models support 1M total context, with up to 128K output tokens for
86
- Astra and 64K for Opus. Input text is never shortened; smaller explicit output
87
- budgets remain respected. See [full-context configuration](wiki/EN-Configuration.md)
88
- for existing/manual Claude setups and the limits on input plus output.
89
-
90
- ## Config
91
-
92
- Config lives at `~/.copilot-relay/config.yaml` and is hot-reloaded:
93
-
94
- ```yaml
95
- host: 127.0.0.1
96
- port: 4142
97
- copilotBaseUrl: https://api.githubcopilot.com
98
- claudeSetup: true
99
- logLevel: info
100
- logRetentionDays: 3
101
- thinkEffort: max
102
- upstreamTimeoutSeconds: 180
103
- webSearchBackend:
104
- gptModel: gpt-6-astra
105
- opusModel: claude-opus-5
106
- ```
107
-
108
- copilot-relay writes the resolved config back to this file, so every key is
109
- present after the first start. Shipped defaults therefore apply to fresh
110
- installs only — once a value is in your `config.yaml` it is never rewritten by
111
- an upgrade. To pick up a changed default, edit the key yourself. See
112
- [Configuration](wiki/EN-Configuration.md) / [配置说明](wiki/ZH-Configuration.md)
113
- for live model discovery, compatible thinking efforts, and copy-paste updates.
114
-
115
- `logLevel` controls verbosity:
116
-
117
- | Level | Logs |
118
- | --- | --- |
119
- | `error` | Startup, preflight, and request failures |
120
- | `info` | Errors plus startup/preflight status, request IDs, model/effort summaries, upstream lifecycle, and local HTTP status codes |
121
- | `debug` | Info plus detailed Copilot timings and request payloads |
122
-
123
- Any other `logLevel` value is invalid and stops startup.
124
-
125
- Valid `thinkEffort` defaults: `low`, `medium`, `high`, `xhigh`, `max`.
126
- It is a fallback, not a forced override: Claude Code's `output_config.effort`
127
- wins, followed by the legacy `reasoning_effort` field, then `thinkEffort` when
128
- neither request field supplies a value. The selected effort is preserved through
129
- all model and WebSearch passes; existing config values are not rewritten.
130
- `none` and other invalid explicit defaults fail startup before authentication or
131
- config write-back, with a clear list of valid choices. They are not silently
132
- replaced with `max`. Explicit request-level `none` remains model-dependent.
133
-
134
- `upstreamTimeoutSeconds` controls the maximum time a single Claude request can
135
- spend waiting on upstream Copilot calls, including chat, Responses, preflight,
136
- and bridge-managed WebSearch calls. The default is `180`. Set `0` to disable the
137
- relay deadline for very long requests; client cancellation and provider/transport
138
- timeouts still apply. Existing saved timeouts are never changed by an upgrade.
10
+ ## Features
139
11
 
140
- `webSearchBackend` controls bridge-managed Claude WebSearch. Leave it empty to
141
- use `gptModel`, or set a Copilot Responses model ID such as `gpt-5.5`.
12
+ - **Claude Code, familiar workflow** — Messages API compatibility, streaming responses, and tool calls.
13
+ - **WebSearch that fits the conversation** — relay-managed search, followed by an answer that can still use your tools.
14
+ - **Your models, your settings** — configurable GPT/Opus routes and reasoning effort; existing selections survive upgrades.
15
+ - **Use the advertised capacity** — discovered context/output limits, without silently shortening your input.
16
+ - **Know what works** — model discovery and opt-in per-model deep checks with clear results.
17
+ - **Choose Claude's upstream protocol** — `claudeUpstreamApi: chat-completions` stays the default; opt into `auto` or `messages` for native Claude transport.
18
+ - **Diagnose offline** — debug mode captures full observed bodies for `copilot-relay replay`; captures contain unredacted prompts and must never be shared wholesale.
19
+ - **Run it your way** — foreground CLI or background service on macOS, Windows, and Linux.
142
20
 
143
- The same folder stores `copilot_token.json` for the cached Copilot bearer token, `github_token` for refresh/login, and `logs/` for runtime logs.
21
+ ## Quick start
144
22
 
145
- ## CLI
23
+ You need **Node.js 22+**, **Claude Code**, and a GitHub account with Copilot access
24
+ to the models you select.
146
25
 
147
26
  ```sh
27
+ npm install -g copilot-relay
148
28
  copilot-relay auth
149
29
  copilot-relay start
150
- copilot-relay restart
151
- copilot-relay status
152
- copilot-relay stop
153
30
  ```
154
31
 
155
- `status` reports whether a relay is running, where it is listening, and whether
156
- it is reachable:
32
+ Follow the device-login prompt. Keep the relay running in this terminal; by default,
33
+ startup configures Claude Code's connection in `~/.claude/settings.json`.
34
+ Open a **second terminal** and run:
157
35
 
158
- ```text
159
- copilot-relay 0.2.5
160
- process running (pid 93744, up 1h 16m)
161
- version 0.2.5
162
- listening http://127.0.0.1:4142
163
- health ok (9ms)
164
- models gpt-6-astra[1m], claude-opus-5
165
- upstream not checked (use --deep)
166
- log ~/.copilot-relay/logs/copilot-relay.2026-07-25.log
167
- config ~/.copilot-relay/config.yaml
168
- host 127.0.0.1
169
- port 4142
170
- copilotBaseUrl https://api.githubcopilot.com
171
- claudeSetup true
172
- logLevel info
173
- logRetentionDays 3
174
- thinkEffort max
175
- upstreamTimeoutSeconds 180
176
- webSearchBackend (unset — uses gptModel)
177
- gptModel gpt-6-astra
178
- opusModel claude-opus-5
179
- host, port and claudeSetup take effect on restart; the rest hot-reload.
180
- ```
181
-
182
- The `config` block is every key `readAppConfig()` resolved, in
183
- `config.default.yaml` order. These are the values on disk: eight of them reload
184
- while the relay runs, while `host`, `port` and `claudeSetup` are read once at
185
- startup — the block says so rather than leaving you to discover it after an
186
- edit. `--json` emits the same values under `config`, with `webSearchBackend` as
187
- `null` when unset so the key set stays the same shape either way.
188
-
189
- The first line is the CLI you invoked; the `version` row is the build the
190
- running daemon reports about itself. They differ after an upgrade that has not
191
- been restarted yet — the new CLI is installed, the old process is still
192
- serving — and `status` says so rather than letting the header imply the upgrade
193
- took effect:
194
-
195
- ```text
196
- version 0.2.6 — MISMATCH, 0.3.0 is installed
197
- ...
198
- The running relay is 0.2.6; 0.3.0 is installed.
199
- Restart it to serve the installed version: copilot-relay restart
36
+ ```sh
37
+ claude
200
38
  ```
201
39
 
202
- A mismatch does not change the exit code: the relay works, it is just not the
203
- build you installed. A daemon older than v0.3.1 does not report a version at
204
- all, which shows as `unknown`.
205
-
206
- `--deep` additionally sends a real request through Copilot. That is the only
207
- check that proves the relay can actually serve Claude Code — a relay whose
208
- Copilot token expired an hour ago still answers `/healthz` and `/v1/models`,
209
- because neither contacts upstream. It is opt-in because it spends a few tokens.
40
+ Configuration lives in `~/.copilot-relay/config.yaml`. Model access depends on your
41
+ account and organization policy; if startup rejects a model, choose an available
42
+ one using the [configuration guide](wiki/EN-Configuration.md).
210
43
 
211
- `--json` emits machine-readable output. Exit codes: `0` running and reachable,
212
- `1` not running, `2` running but not usable — the health probe failed, or
213
- `--deep` was requested and failed. `0` requires a live process *and* a passing
214
- health probe, so a relay that cannot answer `/healthz` never reports success.
215
-
216
- ## Logging
217
-
218
- At `info`, every model request logs the requested model, upstream model, requested
219
- think effort, requested thinking, and effective think effort. Missing request
220
- effort is shown as `unset`, distinct from explicit `none`; full normal request
221
- payloads remain at `debug`.
222
-
223
- Upstream failures are logged at `error` with full request and response context in the same log file.
224
-
225
- Unsupported Claude API requests are logged at `error` with the local method/path
226
- and detailed request payload.
227
-
228
- Logs are written to `~/.copilot-relay/logs/copilot-relay.<local-date>.log`. The
229
- active file rotates at local midnight, and files older than `logRetentionDays`
230
- local calendar days are deleted. Rotation is what makes retention take effect:
231
- without it the single log file's mtime was refreshed by every append, so nothing
232
- ever aged out.
233
-
234
- Quick inspection:
44
+ Discover models and optionally test one:
235
45
 
236
46
  ```sh
237
- tail -f ~/.copilot-relay/logs/copilot-relay.$(date +%F).log
238
- grep -n "Failed to create\\|Startup preflight failed" ~/.copilot-relay/logs/copilot-relay.*.log
47
+ copilot-relay models
48
+ copilot-relay models --deep --model claude-opus-5.5
239
49
  ```
240
50
 
241
- See [Logs and troubleshooting](wiki/EN-Logging-Troubleshooting.md)
242
- ([中文](wiki/ZH-Logging-Troubleshooting.md)) for common debugging workflows.
51
+ Deep checks **consume Copilot usage** and test an isolated relay pipeline, not the
52
+ running daemon. Use `copilot-relay status --deep` for daemon health, and
53
+ `copilot-relay stop` when finished.
243
54
 
244
- ## Running it as a service
55
+ ## Go further
245
56
 
246
- To keep the relay running across reboots, see [`wiki/`](wiki/) — per-platform
247
- setup for macOS, Windows, and Linux, in English and 中文, each covering
248
- registration, how to verify it is *actually* working rather than merely
249
- listening, and how to stop it.
57
+ **[Open the Wiki](https://github.com/D0n9X1n/copilot-relay/wiki)** · **[English / 中文](wiki/README.md)**
250
58
 
251
- The same pages are published to the [wiki tab](https://github.com/D0n9X1n/copilot-relay/wiki),
252
- which is generated from `wiki/` on every merge. Edit the folder, not the tab.
59
+ - [Configure models and deep checks](wiki/EN-Configuration.md) · [中文](wiki/ZH-Configuration.md)
60
+ - Run at login: [macOS](wiki/EN-macOS-LaunchAgent.md) · [Windows](wiki/EN-Windows-Service.md) · [Linux](wiki/EN-Linux-systemd.md)
61
+ - [Troubleshoot](wiki/EN-Logging-Troubleshooting.md) · [Understand the architecture](wiki/EN-Architecture.md) · [Contribute](wiki/EN-Development.md)
253
62
 
254
- ## Development
255
-
256
- All documentation lives in [`wiki/`](wiki/), in English and 中文:
257
-
258
- | Page | Covers |
259
- | --- | --- |
260
- | [Architecture](wiki/EN-Architecture.md) ([中文](wiki/ZH-Architecture.md)) | Modules, request and startup flow, public API, runtime files |
261
- | [Internals](wiki/EN-Internals.md) ([中文](wiki/ZH-Internals.md)) | Translation, streaming, prompt caching, lifecycle, logging invariants |
262
- | [Development](wiki/EN-Development.md) ([中文](wiki/ZH-Development.md)) | Setup, tests, CI matrix, workflow, releasing |
263
- | [Configuration](wiki/EN-Configuration.md) ([中文](wiki/ZH-Configuration.md)) | Every config key, hot reload vs restart |
264
- | [Logs and troubleshooting](wiki/EN-Logging-Troubleshooting.md) ([中文](wiki/ZH-Logging-Troubleshooting.md)) | Log format, grep recipes, failure modes |
265
-
266
- ```sh
267
- npm install
268
- npm run typecheck
269
- npm run build
270
- npm test
271
- ```
63
+ Unofficial research project; not affiliated with GitHub or Anthropic. Upstream
64
+ services and compatibility can change. Model and tool support are not guaranteed;
65
+ see the Wiki for known limitations. [MIT licensed](LICENSE).
@@ -2,8 +2,8 @@
2
2
  #
3
3
  # This file is copied to ~/.copilot-relay/config.yaml on first start.
4
4
  # Edit the user config file, not this template, for local changes.
5
- # Most values hot-reload while the service is running. host and port still
6
- # require restart because the listening socket is already bound.
5
+ # Valid complete edits hot-reload without rewriting this file.
6
+ # host, port, and claudeSetup require restart.
7
7
  #
8
8
  # Values here apply to a fresh install only. copilot-relay writes the resolved
9
9
  # config back to disk, so once a key exists in your config.yaml it is yours:
@@ -26,13 +26,12 @@ claudeSetup: true
26
26
 
27
27
  # Log verbosity:
28
28
  # error - startup/preflight/request failures only
29
- # info - error logs plus startup/preflight status, model/effort summaries,
30
- # and local HTTP status codes
31
- # debug - info logs plus detailed Copilot timings and request payloads
29
+ # info - errors plus status, model/effort and semantic completion summaries
30
+ # debug - info plus full private bodies in ~/.copilot-relay/captures; may contain secrets
32
31
  # Any other value is invalid and stops startup.
33
32
  logLevel: info
34
33
 
35
- # Number of days to keep files in ~/.copilot-relay/logs.
34
+ # Number of days to keep relay logs and settled debug captures.
36
35
  # Counted in local calendar days: 3 keeps today plus the previous two days.
37
36
  # The active log file is copilot-relay.<local-date>.log and rotates at local
38
37
  # midnight, which is what makes this setting take effect at all.
@@ -52,10 +51,15 @@ upstreamTimeoutSeconds: 180
52
51
  # Leave empty to use gptModel.
53
52
  webSearchBackend:
54
53
 
54
+ # Claude upstream protocol: auto selects advertised native Messages support.
55
+ # Keep the proven chat route until native cache non-regression is measured.
56
+ # Explicit alternatives: auto, messages.
57
+ claudeUpstreamApi: chat-completions
58
+
55
59
  # Model routing: requests containing "opus" use opusModel; all others use gptModel.
56
60
  #
57
61
  # Upstream Copilot model used for non-Opus requests.
58
62
  gptModel: gpt-6-astra
59
63
 
60
64
  # Upstream Copilot model used for requests containing "opus".
61
- opusModel: claude-opus-5
65
+ opusModel: claude-opus-5.5