Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 88 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ tower = { version = "0.5", features = ["util"] }
tower-http = { version = "0.6", features = ["fs"] }
reqwest = { version = "0.13", default-features = false, features = ["json", "rustls", "stream", "form"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_json = { version = "1", features = ["preserve_order"] }
serde_norway = "0.9"
futures-util = "0.3"
async-stream = "0.3"
Expand All @@ -33,5 +33,6 @@ chrono = { version = "0.4", features = ["clock"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tiktoken-rs = "0.7"
dialoguer = { version = "0.11", default-features = false, features = ["fuzzy-select"] }

[dev-dependencies]
83 changes: 61 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ This is a Rust backend port of the
# Build
cargo build --release

# Run (first run starts GitHub Device Flow auth if no token is configured)
# Run — on first launch in a terminal this opens the interactive setup wizard
./target/release/ghc-proxy

# Generate the default config file and exit
# Re-run the setup wizard at any time
./target/release/ghc-proxy --setup

# Generate the default config file non-interactively and exit
./target/release/ghc-proxy --config
```

On first run the proxy initiates **GitHub Device Flow** authentication if no
`GITHUB_TOKEN` environment variable is set and no saved token is found.
On a first run with no config file, when launched from a terminal, the proxy
opens an **interactive setup wizard** that signs you in to GitHub (Device Flow),
fetches the live model catalog, and helps you configure model mappings. In
headless or piped contexts the wizard is skipped: the proxy falls back to GitHub
Device Flow auth (or a `*_TOKEN` environment variable) and a default config
file.

## Features

Expand All @@ -39,18 +46,23 @@ On first run the proxy initiates **GitHub Device Flow** authentication if no
- **Orphaned `tool_use_id` recovery** — retries with offending tool results
stripped when the upstream returns the corresponding 400 error.
- **Request analytics dashboard** at `/` and a request browser at `/requests`.
- **Interactive setup wizard** (`--setup`, or first launch in a terminal):
GitHub sign-in, live model catalog, and model-mapping configuration.
- **1M-context support** — forwards the `anthropic-beta: context-1m-2025-08-07`
header for models whose catalog advertises an extended context window.

## CLI Options

```
ghc-proxy [options]

-s, --setup Show the setup guide and write/update the config file
--claudecode Include Claude Code setup instructions (use with --setup)
-s, --setup Launch the interactive setup wizard (sign in + map models)
--claudecode Configure Claude Code (~/.claude/settings.json) to use this proxy (with --setup)
-d, --default Reset config to defaults during setup
-p, --port <port> Port to listen on (default: 8314)
-a, --address <addr> Address to listen on (default: 127.0.0.1)
-c, --config Generate default config file
--account-type <t> Account tier: individual | business | enterprise
-c, --config Generate the default config file (non-interactive)
-v, --version Show version
-h, --help Show help
```
Expand All @@ -59,14 +71,32 @@ ghc-proxy [options]

A GitHub token is resolved in this order:

1. `GITHUB_TOKEN` environment variable.
1. `COPILOT_GITHUB_TOKEN`, then `GH_TOKEN`, then `GITHUB_TOKEN` environment
variables (matching the GitHub Copilot SDK precedence).
2. Saved token file at `<config-dir>/github_token.txt`.
3. Interactive GitHub Device Flow (the resulting token is saved for reuse).
3. Interactive GitHub Device Flow (the resulting token is saved for reuse, with
`0600` permissions on Unix).

The GitHub token is exchanged for a short-lived **Copilot token** via
`https://api.github.com/copilot_internal/v2/token`, which is refreshed
automatically before it expires.

## Setup Wizard

Running `ghc-proxy --setup` — or launching the proxy for the first time from a
terminal with no config file — opens an interactive wizard that:

1. Prompts for the **server settings** (listen address, port, account tier).
2. Signs in to GitHub via **Device Flow** and saves the token.
3. Fetches the **live model catalog** and lets you map the `opus` / `sonnet` /
`haiku` aliases to specific models (or keep the recommended defaults).
4. Optionally configures **Claude Code** to route through the proxy.

The wizard only runs when attached to a terminal, so headless and CI launches
are unaffected (they fall back to environment/file tokens and a default config).
Pass `--default` to start the wizard from built-in defaults, or `--claudecode`
to include the Claude Code step automatically.

## Configuration

Config file: `~/.ghc-tunnel/config.yaml` (`%APPDATA%/ghc-tunnel/config.yaml`
Expand All @@ -77,7 +107,7 @@ address: 127.0.0.1
port: 8314
debug: false
account_type: individual # individual | business | enterprise
vscode_version: "1.115.0"
vscode_version: "1.123.0"
api_version: "2025-05-01"
copilot_version: "0.44.0"
model_mappings:
Expand Down Expand Up @@ -153,6 +183,7 @@ cargo clippy # lint
| File | Responsibility |
|------|----------------|
| `src/main.rs` | CLI parsing and server startup |
| `src/setup.rs` | Interactive first-run setup wizard |
| `src/config.rs` | Config dir, YAML config, defaults, model-mapping defaults |
| `src/auth.rs` | GitHub token resolution (env/file/Device Flow), Copilot token exchange |
| `src/state.rs` | Shared state, token refresh, upstream header construction |
Expand All @@ -171,19 +202,25 @@ The proxy authenticates to GitHub Copilot by impersonating the official
identity headers that the real client sends to `api.githubcopilot.com`
(`Editor-Version`, `Editor-Plugin-Version`, `User-Agent`,
`Copilot-Integration-Id`, `OpenAI-Intent`, `X-Interaction-Type`,
`X-GitHub-Api-Version`, etc.). These are built in
`AppState::copilot_headers` / `github_headers` (`src/state.rs`) from the
`X-GitHub-Api-Version`, `openai-organization`, plus a persisted
`vscode-machineid` and a per-session `vscode-sessionid`, etc.). These are built
in `AppState::copilot_headers` / `github_headers` (`src/state.rs`) from the
version strings in `src/config.rs`.

For Anthropic-native `/v1/messages` requests, the proxy also forwards the
`anthropic-beta: context-1m-2025-08-07` header for models whose catalog
advertises a context window larger than 200K tokens, unlocking the 1M-token
tier the same way the official client does.

GitHub may reject requests that report stale client versions, so these values
occasionally need refreshing. The source of truth is the now open-source
[`microsoft/vscode-copilot-chat`](https://github.com/microsoft/vscode-copilot-chat)
repository:
extension and the VS Code Marketplace:

| Config value | Where to read it |
|--------------|------------------|
| `copilot_version` | `version` field in the extension's `package.json` |
| `vscode_version` | `engines.vscode` baseline in `package.json` |
| `copilot_version` | latest `GitHub.copilot-chat` version on the VS Code Marketplace (or the `version` field in the extension's `package.json`) |
| `vscode_version` | latest VS Code stable release (`https://update.code.visualstudio.com/api/releases/stable`) |
| `api_version` | `X-GitHub-Api-Version` constant in `src/platform/networking/common/networking.ts` |

After updating the constants in `src/config.rs`, run the test suite (the header
Expand All @@ -195,13 +232,15 @@ example values in this README.
This Rust port focuses on the **core proxy behavior**: authentication, token
management, model translation, all four API surfaces with streaming, content
filtering, retry, the CLI, and the dashboard. The following `ghc-tunnel`
auxiliary features are intentionally **not** ported: the fully interactive
setup wizard, OneDrive config sync, the ACP code agent, Codex config
auto-repair, and the persistent on-disk analytics database. `--setup` prints a
setup guide and writes/updates the config file (re-rendering it with the current
values, applying any CLI overrides, or resetting to defaults with `--default`),
even when a config file already exists; `--claudecode` adds Claude Code
integration guidance. The dashboard lists all supported models alongside the
auxiliary features are intentionally **not** ported: OneDrive config sync, the
ACP code agent, Codex config auto-repair, and the persistent on-disk analytics
database. `--setup` launches an interactive wizard (GitHub sign-in, live model
catalog, model-mapping configuration) and writes/updates the config file; in
headless or piped contexts it instead re-renders the config non-interactively,
applying any CLI overrides or resetting to defaults with `--default`.
`--claudecode` patches `~/.claude/settings.json`, merging
`env.ANTHROPIC_BASE_URL` so Claude Code routes through this proxy (existing
settings are preserved). The dashboard lists all supported models alongside the
request statistics.

## License
Expand Down
9 changes: 5 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ use std::path::PathBuf;
/// Kept in sync with the `engines.vscode` baseline of the latest
/// `microsoft/vscode-copilot-chat` release (see "Mimicking the Copilot client"
/// in the README for how to refresh these values).
pub const VSCODE_VERSION: &str = "1.115.0";
pub const VSCODE_VERSION: &str = "1.123.0";
/// Default GitHub Copilot API version header value (`X-GitHub-Api-Version`),
/// matching the latest documented Copilot REST API version.
pub const API_VERSION: &str = "2026-03-10";
/// matching the `X-GitHub-Api-Version` constant in the Copilot Chat client
/// source (`src/platform/networking/common/networking.ts`).
pub const API_VERSION: &str = "2025-05-01";
/// Default Copilot Chat plugin version string, matching the `version` field of
/// the latest `microsoft/vscode-copilot-chat` release.
pub const COPILOT_VERSION: &str = "0.44.0";
pub const COPILOT_VERSION: &str = "0.48.1";

/// Default model name that Claude "opus"/"sonnet" requests are mapped to.
pub const DEFAULT_OPUS: &str = "claude-opus-4.7-1m";
Expand Down
Loading
Loading