ghc-proxy 0.10.1 → 0.10.3
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 +226 -82
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/{GptEncoding-DdY2evDX.mjs → GptEncoding-DGbju5p-.mjs} +11 -9
- package/dist/{cl100k_base-ChJqEXhP.mjs → cl100k_base-CR_-ZzWY.mjs} +2 -2
- package/dist/main.mjs +8912 -7222
- package/dist/{o200k_base-DXNwToXP.mjs → o200k_base-8n5G7cJ5.mjs} +2 -2
- package/dist/{p50k_base-Cab7w92R.mjs → p50k_base-Coo3riw5.mjs} +2 -2
- package/dist/{p50k_edit-DkrRw_em.mjs → p50k_edit-Df1WiLDq.mjs} +2 -2
- package/dist/{prompt-DsMdjS4d.mjs → prompt-B9CExZli.mjs} +66 -28
- package/dist/{r50k_base-1vVxWqTY.mjs → r50k_base-CrlP1QVX.mjs} +2 -2
- package/dist/{file-type-BwbWtW7C.mjs → source-BpNO27ea.mjs} +1417 -1248
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -9,32 +9,44 @@ A proxy that turns your GitHub Copilot subscription into an OpenAI and Anthropic
|
|
|
9
9
|
> [!WARNING]
|
|
10
10
|
> Reverse-engineered, unofficial, may break at any time. Excessive use can trigger GitHub abuse detection. **Use at your own risk.**
|
|
11
11
|
|
|
12
|
-
**TL;DR** —
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
**TL;DR** — Choose either supported runtime:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Bun >= 1.4
|
|
16
|
+
bunx --bun ghc-proxy@latest start
|
|
17
|
+
|
|
18
|
+
# Node.js >= 24
|
|
19
|
+
npx ghc-proxy@latest start
|
|
20
|
+
```
|
|
17
21
|
|
|
18
22
|
## Prerequisites
|
|
19
23
|
|
|
20
24
|
Before you start, make sure you have:
|
|
21
25
|
|
|
22
|
-
1. **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
2. **A GitHub Copilot subscription** -- individual, business, or enterprise
|
|
26
|
+
1. **One supported JavaScript runtime:**
|
|
27
|
+
- **Bun >= 1.4:** `winget install --id Oven-sh.Bun` on Windows, or see the [official installation guide](https://bun.com/docs/installation)
|
|
28
|
+
- **Node.js >= 24:** install the latest LTS release from the [official Node.js download page](https://nodejs.org/en/download)
|
|
29
|
+
2. **A GitHub Copilot subscription** -- individual, business, or enterprise
|
|
26
30
|
|
|
27
31
|
## Quick Start
|
|
28
32
|
|
|
29
|
-
1. Start the proxy:
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
1. Start the proxy with your chosen runtime:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Bun
|
|
37
|
+
bunx --bun ghc-proxy@latest start
|
|
38
|
+
|
|
39
|
+
# Node.js
|
|
40
|
+
npx ghc-proxy@latest start
|
|
41
|
+
```
|
|
32
42
|
|
|
33
43
|
2. On the first run, you will be guided through GitHub's device-code authentication flow. Follow the prompts to authorize the proxy.
|
|
34
44
|
|
|
35
45
|
3. Once authenticated, the proxy starts on **`http://localhost:4141`** and is ready to accept requests.
|
|
36
46
|
|
|
37
|
-
That's it. Any tool that supports the OpenAI or Anthropic API can now point to `http://localhost:4141`.
|
|
47
|
+
That's it. Any tool that supports the OpenAI or Anthropic API can now point to `http://localhost:4141`.
|
|
48
|
+
|
|
49
|
+
The examples below use `bunx --bun`. If you chose Node.js, replace `bunx --bun` with `npx`; the published CLI and commands are the same.
|
|
38
50
|
|
|
39
51
|
> **Tip:** If you set `--rate-limit`, add `--wait` to queue requests instead of rejecting them with 429 when the cooldown has not elapsed yet. See [Rate Limiting](#rate-limiting) for details.
|
|
40
52
|
|
|
@@ -45,7 +57,7 @@ This is the most common use case. There are two ways to set it up:
|
|
|
45
57
|
### Option A: One-command launch
|
|
46
58
|
|
|
47
59
|
```bash
|
|
48
|
-
bunx ghc-proxy@latest start --claude-code
|
|
60
|
+
bunx --bun ghc-proxy@latest start --claude-code
|
|
49
61
|
```
|
|
50
62
|
|
|
51
63
|
This starts the proxy, opens an interactive model picker, and prints a ready-to-paste environment command. Run that command in another terminal to launch Claude Code with the correct configuration.
|
|
@@ -73,7 +85,7 @@ Create or edit `~/.claude/settings.json` (this applies globally to all projects)
|
|
|
73
85
|
Then simply start the proxy and use Claude Code as usual:
|
|
74
86
|
|
|
75
87
|
```bash
|
|
76
|
-
bunx ghc-proxy@latest start
|
|
88
|
+
bunx --bun ghc-proxy@latest start
|
|
77
89
|
```
|
|
78
90
|
|
|
79
91
|
**What each environment variable does:**
|
|
@@ -96,11 +108,12 @@ See the [Claude Code settings docs](https://docs.anthropic.com/en/docs/claude-co
|
|
|
96
108
|
ghc-proxy uses a subcommand structure:
|
|
97
109
|
|
|
98
110
|
```bash
|
|
99
|
-
bunx ghc-proxy@latest start # Start the proxy server
|
|
100
|
-
bunx ghc-proxy@latest auth # Run GitHub auth flow without starting the server
|
|
101
|
-
bunx ghc-proxy@latest
|
|
102
|
-
bunx ghc-proxy@latest
|
|
103
|
-
bunx ghc-proxy@latest
|
|
111
|
+
bunx --bun ghc-proxy@latest start # Start the proxy server
|
|
112
|
+
bunx --bun ghc-proxy@latest auth # Run GitHub auth flow without starting the server
|
|
113
|
+
bunx --bun ghc-proxy@latest auth --account work # Create or replace a named account
|
|
114
|
+
bunx --bun ghc-proxy@latest check-usage # Show your Copilot usage/quota in the terminal
|
|
115
|
+
bunx --bun ghc-proxy@latest debug # Print diagnostic info (version, paths, token status)
|
|
116
|
+
bunx --bun ghc-proxy@latest selfcheck # Probe tokenizer chunks and Bun/Node runtime contracts in the packaged bundle
|
|
104
117
|
```
|
|
105
118
|
|
|
106
119
|
### `start` Options
|
|
@@ -133,13 +146,13 @@ If you want to throttle how often the proxy forwards requests:
|
|
|
133
146
|
|
|
134
147
|
```bash
|
|
135
148
|
# Enforce a 30-second cooldown between requests
|
|
136
|
-
bunx ghc-proxy@latest start --rate-limit 30
|
|
149
|
+
bunx --bun ghc-proxy@latest start --rate-limit 30
|
|
137
150
|
|
|
138
151
|
# Same, but queue requests instead of returning 429
|
|
139
|
-
bunx ghc-proxy@latest start --rate-limit 30 --wait
|
|
152
|
+
bunx --bun ghc-proxy@latest start --rate-limit 30 --wait
|
|
140
153
|
|
|
141
154
|
# Manually approve every request (useful for debugging)
|
|
142
|
-
bunx ghc-proxy@latest start --manual
|
|
155
|
+
bunx --bun ghc-proxy@latest start --manual
|
|
143
156
|
```
|
|
144
157
|
|
|
145
158
|
`--wait` only takes effect when `--rate-limit` is also set. Without `--rate-limit`, there is no cooldown to wait on and `--wait` has no effect.
|
|
@@ -149,8 +162,8 @@ bunx ghc-proxy@latest start --manual
|
|
|
149
162
|
If you have a GitHub Business or Enterprise Copilot plan, pass `--account-type`:
|
|
150
163
|
|
|
151
164
|
```bash
|
|
152
|
-
bunx ghc-proxy@latest start --account-type business
|
|
153
|
-
bunx ghc-proxy@latest start --account-type enterprise
|
|
165
|
+
bunx --bun ghc-proxy@latest start --account-type business
|
|
166
|
+
bunx --bun ghc-proxy@latest start --account-type enterprise
|
|
154
167
|
```
|
|
155
168
|
|
|
156
169
|
This routes requests to the correct Copilot API endpoint for your plan. See the [GitHub docs on network routing](https://docs.github.com/en/enterprise-cloud@latest/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/managing-github-copilot-access-to-your-organizations-network#configuring-copilot-subscription-based-network-routing-for-your-enterprise-or-organization) for details.
|
|
@@ -160,17 +173,17 @@ This routes requests to the correct Copilot API endpoint for your plan. See the
|
|
|
160
173
|
If your organization uses GitHub Enterprise Cloud (`*.ghe.com`), the standard GitHub device login URL differs from `github.com`. Pass your company's GHE domain on first auth:
|
|
161
174
|
|
|
162
175
|
```bash
|
|
163
|
-
bunx ghc-proxy@latest start --account-type enterprise --ghe-domain company.ghe.com
|
|
176
|
+
bunx --bun ghc-proxy@latest start --account-type enterprise --ghe-domain company.ghe.com
|
|
164
177
|
```
|
|
165
178
|
|
|
166
179
|
Or authenticate first, then start without the flag on subsequent runs:
|
|
167
180
|
|
|
168
181
|
```bash
|
|
169
182
|
# First run (authenticates and persists the domain)
|
|
170
|
-
bunx ghc-proxy@latest auth --ghe-domain company.ghe.com
|
|
183
|
+
bunx --bun ghc-proxy@latest auth --ghe-domain company.ghe.com
|
|
171
184
|
|
|
172
185
|
# Later runs (domain is read from persisted config)
|
|
173
|
-
bunx ghc-proxy@latest start --account-type enterprise
|
|
186
|
+
bunx --bun ghc-proxy@latest start --account-type enterprise
|
|
174
187
|
```
|
|
175
188
|
|
|
176
189
|
The proxy normalizes and persists the GHE domain automatically after a successful authentication, so you only need to pass `--ghe-domain` on the first run or when switching tenants.
|
|
@@ -179,17 +192,114 @@ The proxy normalizes and persists the GHE domain automatically after a successfu
|
|
|
179
192
|
|
|
180
193
|
## Configuration
|
|
181
194
|
|
|
182
|
-
The proxy reads an optional JSON config file at:
|
|
195
|
+
The proxy reads an optional JSON config file at:
|
|
183
196
|
|
|
184
197
|
```
|
|
185
|
-
~/.local/share/ghc-proxy/config.json
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
198
|
+
~/.local/share/ghc-proxy/config.json
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
GitHub credentials are stored separately at
|
|
202
|
+
`~/.local/share/ghc-proxy/credentials.json`. The credential file is versioned,
|
|
203
|
+
selects one active account for legacy single-account mode, and can retain
|
|
204
|
+
multiple named accounts:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"version": 1,
|
|
209
|
+
"activeAccount": "default",
|
|
210
|
+
"accounts": {
|
|
211
|
+
"default": {
|
|
212
|
+
"githubToken": "<base64>",
|
|
213
|
+
"gheDomain": "company.ghe.com"
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Base64 is low-cost obfuscation, not encryption; anyone who can read the file can
|
|
220
|
+
decode it. On first startup after upgrading, a legacy `config.json` token is
|
|
221
|
+
copied into this store only after a complete temporary config backup is created.
|
|
222
|
+
The legacy field and backup are removed after the stored credential succeeds at
|
|
223
|
+
both GitHub identity validation and Copilot token acquisition. A failed or
|
|
224
|
+
interrupted migration keeps the backup and reports its recovery path.
|
|
225
|
+
|
|
226
|
+
### Named Account Routing
|
|
227
|
+
|
|
228
|
+
Authenticate each account under a stable name:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
bunx --bun ghc-proxy@latest auth --account default
|
|
232
|
+
bunx --bun ghc-proxy@latest auth --account account1
|
|
233
|
+
|
|
234
|
+
# A named GHE.com account keeps its own tenant beside its credential.
|
|
235
|
+
bunx --bun ghc-proxy@latest auth --account work --ghe-domain company.ghe.com
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Account names are case-sensitive, 1-64 characters, and may contain ASCII
|
|
239
|
+
letters, numbers, `.`, `_`, and `-`; the first character must be alphanumeric.
|
|
240
|
+
|
|
241
|
+
For an existing single-account installation, open the local Dashboard Accounts
|
|
242
|
+
view. The current legacy account remains the default, and the bootstrap form
|
|
243
|
+
suggests `defaultaccount.localhost` as its dedicated hostname. Edit that value
|
|
244
|
+
if needed, then enable routing. The change is persisted transactionally and
|
|
245
|
+
takes effect without restarting the process.
|
|
246
|
+
|
|
247
|
+
You can also configure hostname routing directly in `config.json`:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"accountRouting": {
|
|
252
|
+
"baseHostname": "localhost",
|
|
253
|
+
"defaultAccount": "default",
|
|
254
|
+
"hostnames": {
|
|
255
|
+
"default.localhost": "default",
|
|
256
|
+
"account1.localhost": "account1"
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
With that configuration, `http://localhost:4141`, `http://127.0.0.1:4141`, and
|
|
263
|
+
the stable dedicated hostname `http://default.localhost:4141` use `default`, while
|
|
264
|
+
`http://account1.localhost:4141` uses `account1`. Every routed account must have
|
|
265
|
+
exactly one dedicated hostname. The base hostname is an additional alias for
|
|
266
|
+
the currently selected default; `127.0.0.1` is a fixed loopback alias for that
|
|
267
|
+
same default. Switching the default never changes any dedicated hostname. DNS
|
|
268
|
+
hostname matching is case-insensitive, ignores the request port, and accepts a
|
|
269
|
+
trailing root dot. Any other hostname is rejected with HTTP `421` before a route handler or
|
|
270
|
+
upstream request runs. `Forwarded` and `X-Forwarded-Host` are not trusted for
|
|
271
|
+
account selection.
|
|
272
|
+
|
|
273
|
+
Each account has independent GitHub/Copilot tokens, refresh scheduling, model
|
|
274
|
+
cache, Responses emulator state, local rate limiter, and upstream queue/cooldown
|
|
275
|
+
state. A failure or capacity response on one account never switches, falls back,
|
|
276
|
+
rotates, or load-balances the request to another account. Process-wide policy
|
|
277
|
+
configuration remains shared.
|
|
278
|
+
|
|
279
|
+
`accountRouting` is opt-in so existing single-account installations retain their
|
|
280
|
+
current Host behavior until the local Dashboard bootstrap is explicitly
|
|
281
|
+
confirmed. The active legacy credential becomes the explicit default account;
|
|
282
|
+
the suggested `defaultaccount.localhost` hostname is editable before commit. In
|
|
283
|
+
routing mode every referenced account must already exist, and `defaultAccount`
|
|
284
|
+
must be explicit. Invalid or ambiguous routing config fails startup. Dashboard
|
|
285
|
+
bootstrap is unavailable while process-wide `start --github-token` or
|
|
286
|
+
`start --ghe-domain` overrides are active, and those overrides are rejected once
|
|
287
|
+
routing is enabled because they cannot identify one named account. Hostname
|
|
288
|
+
routing is a deterministic selector, not an authorization boundary: callers
|
|
289
|
+
that can reach the listener and choose a configured `Host` can select that
|
|
290
|
+
account unless access is enforced separately.
|
|
291
|
+
|
|
292
|
+
For Docker deployments, leave `GH_TOKEN` unset in routing mode and mount the
|
|
293
|
+
populated credential/config directory. The image healthcheck reads
|
|
294
|
+
`accountRouting.baseHostname`, applies the same DNS ASCII/case/root-dot
|
|
295
|
+
normalization, and sends it as `Host` while connecting over loopback, so health
|
|
296
|
+
checks continue to exercise the configured base hostname rather than the
|
|
297
|
+
`127.0.0.1` default alias.
|
|
298
|
+
|
|
299
|
+
All fields are optional. The full schema:
|
|
189
300
|
|
|
190
301
|
| Field | Type | Default | Description |
|
|
191
302
|
|-------|------|---------|-------------|
|
|
192
|
-
| `githubToken` | `string` | unset | Persisted GitHub token. The device-code flow (`auth` or first startup) writes it automatically; `start --github-token` is runtime-only and does not write this field |
|
|
193
303
|
| `modelRewrites` | `{ from, to }[]` | `[]` | Glob-pattern model substitution rules (see [Model Rewrites](#model-rewrites)) |
|
|
194
304
|
| `modelFallback` | `object` | built-in family defaults | Override default model fallbacks (see [Customizing Fallbacks](#customizing-fallbacks)) |
|
|
195
305
|
| `modelFallback.claudeOpus` | `string` | `claude-opus-5` | Fallback for `claude-opus-*` models |
|
|
@@ -212,8 +322,9 @@ All fields are optional. The full schema:
|
|
|
212
322
|
| `upstreamRecoveryBudgetSeconds` | `number` | `60` | Shared recovery deadline after the first retryable outcome or active-cooldown encounter (`1..120` seconds) |
|
|
213
323
|
| `overloadFallbacks` | `Record<string, string>` | `{}` (disabled) | Exact effective-model mappings for one opt-in fallback dispatch after terminal model `529` |
|
|
214
324
|
| `upstreamQueueBaseDelaySeconds` | `number` | `2` | Base delay (seconds) for upstream retry backoff when `Retry-After` is absent |
|
|
215
|
-
| `upstreamQueueMaxDelaySeconds` | `number` | `60` | Maximum computed backoff (seconds); does not clamp `Retry-After` |
|
|
325
|
+
| `upstreamQueueMaxDelaySeconds` | `number` | `60` | Maximum computed backoff (seconds); does not clamp `Retry-After` |
|
|
216
326
|
| `gheDomain` | `string` | unset | GitHub Enterprise Cloud company domain (persisted automatically after GHE.com auth) |
|
|
327
|
+
| `accountRouting` | `{ baseHostname, defaultAccount, hostnames }` | unset | Opt-in exact DNS hostname to named-account routing; unknown hostnames are rejected |
|
|
217
328
|
|
|
218
329
|
Example:
|
|
219
330
|
|
|
@@ -363,7 +474,7 @@ When the Copilot token response includes `endpoints.api`, `ghc-proxy` now prefer
|
|
|
363
474
|
|
|
364
475
|
Incoming requests hit an [Elysia](https://elysiajs.com/) server. `chat/completions` requests are validated, normalized into the shared planning pipeline, and then forwarded to Copilot. `responses` requests use a native Responses path with explicit compatibility policies. `messages` requests are routed per-model and can use native Anthropic passthrough, the Responses translation path, or the existing chat-completions fallback. The translator tracks exact vs lossy vs unsupported behavior explicitly; see the [Messages Routing and Translation Guide](./docs/messages-routing-and-translation.md) and the [Anthropic Translation Matrix](./docs/anthropic-translation-matrix.md) for the current support surface.
|
|
365
476
|
|
|
366
|
-
The built-in
|
|
477
|
+
The built-in Dashboard projects process health, named account status, model routing, behavior, and recent request lifecycle metadata without storing request or response content. Its protected Accounts view can explicitly bootstrap a legacy account into named routing, authenticate a new account with a dedicated hostname, and switch the default account. See [Dashboard Observability](./docs/design/dashboard-observability.md).
|
|
367
478
|
|
|
368
479
|
For Anthropic `search_result` blocks, an April 17, 2026 probe against `claude-opus-4.6` on Copilot native `/v1/messages` accepted top-level search results and pure search-result tool outputs, but rejected top-level `citations` and mixed text/search-result tool output arrays. The native path sanitizes those observed rejection cases, while translated paths flatten search results to text; re-run the probe before treating that dated upstream result as universal.
|
|
369
480
|
|
|
@@ -414,7 +525,7 @@ This keeps the existing chat pipeline stable while allowing newer Copilot models
|
|
|
414
525
|
| `GET` | `/usage` | Copilot quota / usage monitoring |
|
|
415
526
|
| `GET` | `/token` | Inspect the current Copilot token |
|
|
416
527
|
|
|
417
|
-
**Local Dashboard
|
|
528
|
+
**Local Dashboard:**
|
|
418
529
|
|
|
419
530
|
| Method | Path | Description |
|
|
420
531
|
|--------|------|-------------|
|
|
@@ -425,10 +536,15 @@ This keeps the existing chat pipeline stable while allowing newer Copilot models
|
|
|
425
536
|
| `GET` | `/dashboard/api/models` | Upstream model metadata and effective proxy capabilities |
|
|
426
537
|
| `GET` | `/dashboard/api/behavior` | Active routing, compatibility policies, strategies, and effect counters |
|
|
427
538
|
| `GET` | `/dashboard/api/requests` | Active requests and the most recent 256 completed request summaries |
|
|
539
|
+
| `GET` | `/dashboard/api/accounts` | Safe per-account identity, tenant, authentication, Copilot status, quota, hostname, and default marker |
|
|
540
|
+
| `POST` | `/dashboard/api/accounts/bootstrap` | Persist and enable named routing for the current legacy default account |
|
|
541
|
+
| `POST` | `/dashboard/api/accounts` | Start device authentication for a new named account and its dedicated hostname |
|
|
542
|
+
| `GET` | `/dashboard/api/account-auth/:id` | Read the safe state of an in-progress account authentication |
|
|
543
|
+
| `POST` | `/dashboard/api/accounts/default` | Persist and activate an explicit default account |
|
|
428
544
|
|
|
429
|
-
Dashboard routes are restricted to local access and return `403` when the peer, request host, or supplied `Origin` fails the loopback/same-origin checks.
|
|
545
|
+
Dashboard routes are restricted to local access and return `403` when the peer, request host, or supplied `Origin` fails the loopback/same-origin checks. A normal legacy single-account process exposes an explicit bootstrap action; adding accounts and changing the default remain unavailable until bootstrap succeeds. Processes using `start --github-token` or `start --ghe-domain` retain legacy behavior and return `409` for account management because those overrides cannot be assigned safely. Dashboard requests are excluded from request history and access logging. See [Dashboard Observability](./docs/design/dashboard-observability.md) for the projection, transaction, and security contract.
|
|
430
546
|
|
|
431
|
-
> **Note:** The `/v1/` prefix is optional for OpenAI-compatible endpoints (`/chat/completions`, `/responses
|
|
547
|
+
> **Note:** The `/v1/` prefix is optional for OpenAI-compatible endpoints (`/chat/completions`, `/responses` and its resource routes, `/models`, `/embeddings`). Anthropic endpoints (`/v1/messages`, `/v1/messages/count_tokens`) require the `/v1` prefix. The utility and Dashboard endpoints are root-only and not exposed under `/v1`.
|
|
432
548
|
|
|
433
549
|
## Responses Compatibility
|
|
434
550
|
|
|
@@ -488,51 +604,79 @@ Stripped parameters are removed entirely (never sent as `null`), because upstrea
|
|
|
488
604
|
|
|
489
605
|
## Docker
|
|
490
606
|
|
|
491
|
-
Pre-built images are available on GHCR:
|
|
492
|
-
|
|
493
|
-
```bash
|
|
494
|
-
docker pull ghcr.io/wxxb789/ghc-proxy
|
|
495
|
-
docker
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
607
|
+
Pre-built images are available on GHCR:
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
docker pull ghcr.io/wxxb789/ghc-proxy
|
|
611
|
+
docker volume create ghc-proxy-data
|
|
612
|
+
docker run --rm -p 127.0.0.1:4141:4141 \
|
|
613
|
+
-v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
|
|
614
|
+
ghcr.io/wxxb789/ghc-proxy
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
Or build locally:
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
docker build -t ghc-proxy .
|
|
621
|
+
docker volume create ghc-proxy-data
|
|
622
|
+
docker run --rm -p 127.0.0.1:4141:4141 \
|
|
623
|
+
-v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
|
|
624
|
+
ghc-proxy
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
Authentication and settings are persisted in the `ghc-proxy-data` volume so they survive container restarts. The proxy does not provide API authentication. Keep the port bound to loopback as shown; any non-loopback deployment needs an authenticated TLS reverse proxy or a firewall that restricts access.
|
|
628
|
+
|
|
629
|
+
Run the device-code authentication flow once against the same volume:
|
|
630
|
+
|
|
631
|
+
```bash
|
|
632
|
+
docker run --rm -it \
|
|
633
|
+
-v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
|
|
634
|
+
ghcr.io/wxxb789/ghc-proxy auth
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
The legacy `--auth` container argument remains supported, but `auth` is the standard CLI subcommand:
|
|
638
|
+
|
|
639
|
+
```bash
|
|
640
|
+
docker run --rm -it \
|
|
641
|
+
-v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
|
|
642
|
+
ghcr.io/wxxb789/ghc-proxy --auth
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
You can also pass a GitHub token via `GH_TOKEN`. The container [entrypoint](entrypoint.sh) forwards a non-empty value only when starting the proxy, as `start --github-token`:
|
|
646
|
+
|
|
647
|
+
```bash
|
|
648
|
+
docker run --rm -p 127.0.0.1:4141:4141 \
|
|
649
|
+
-v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
|
|
650
|
+
-e GH_TOKEN=your_token \
|
|
651
|
+
ghcr.io/wxxb789/ghc-proxy
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Docker Compose:
|
|
521
655
|
|
|
522
656
|
```yaml
|
|
523
657
|
services:
|
|
524
|
-
ghc-proxy:
|
|
525
|
-
image: ghcr.io/wxxb789/ghc-proxy
|
|
526
|
-
ports:
|
|
527
|
-
- '4141:4141'
|
|
528
|
-
|
|
529
|
-
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
658
|
+
ghc-proxy:
|
|
659
|
+
image: ghcr.io/wxxb789/ghc-proxy
|
|
660
|
+
ports:
|
|
661
|
+
- '127.0.0.1:4141:4141'
|
|
662
|
+
volumes:
|
|
663
|
+
- ghc-proxy-data:/home/bun/.local/share/ghc-proxy
|
|
664
|
+
environment:
|
|
665
|
+
- GH_TOKEN=your_token_here
|
|
666
|
+
restart: unless-stopped
|
|
667
|
+
|
|
668
|
+
volumes:
|
|
669
|
+
ghc-proxy-data:
|
|
670
|
+
```
|
|
534
671
|
|
|
535
|
-
|
|
672
|
+
## Running from Source
|
|
673
|
+
|
|
674
|
+
Repository development uses Bun >= 1.4 even if you run the published package with Node.js.
|
|
675
|
+
Install dev dependencies when building from source: `gpt-tokenizer` is a
|
|
676
|
+
build-time dependency whose five encodings are still bundled into the published
|
|
677
|
+
runtime for the local count endpoints and packaged `selfcheck`.
|
|
678
|
+
|
|
679
|
+
```bash
|
|
536
680
|
git clone https://github.com/wxxb789/ghc-proxy.git
|
|
537
681
|
cd ghc-proxy
|
|
538
682
|
bun install
|
|
@@ -543,8 +687,8 @@ bun run start
|
|
|
543
687
|
|
|
544
688
|
## Development
|
|
545
689
|
|
|
546
|
-
```bash
|
|
547
|
-
bun install # Install dependencies
|
|
690
|
+
```bash
|
|
691
|
+
bun install # Install dependencies, including build-time tokenizer sources
|
|
548
692
|
bun run dev # Start with --watch
|
|
549
693
|
bun run start # Start without --watch
|
|
550
694
|
bun run build # Build with tsdown
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
ghc-proxy bundles portions of `gpt-tokenizer` in its published JavaScript.
|
|
4
|
+
|
|
5
|
+
## gpt-tokenizer
|
|
6
|
+
|
|
7
|
+
MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2023-2024 Bazyli Brzoska
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
@@ -76,7 +76,7 @@ function getSpecialTokenRegex(tokens) {
|
|
|
76
76
|
}
|
|
77
77
|
//#endregion
|
|
78
78
|
//#region node_modules/gpt-tokenizer/esm/BytePairEncodingCore.js
|
|
79
|
-
const emptyBuffer = new Uint8Array(0);
|
|
79
|
+
const emptyBuffer = /* @__PURE__ */ new Uint8Array(0);
|
|
80
80
|
const decoder = new TextDecoder("utf8");
|
|
81
81
|
var BytePairEncodingCore = class {
|
|
82
82
|
mergeableBytePairRankCount;
|
|
@@ -674,7 +674,7 @@ function Cl100KBase(bytePairRankDecoder) {
|
|
|
674
674
|
return {
|
|
675
675
|
tokenSplitRegex: CL100K_TOKEN_SPLIT_REGEX,
|
|
676
676
|
bytePairRankDecoder,
|
|
677
|
-
specialTokensEncoder: new Map([
|
|
677
|
+
specialTokensEncoder: /* @__PURE__ */ new Map([
|
|
678
678
|
[EndOfText, 100257],
|
|
679
679
|
[FimPrefix, 100258],
|
|
680
680
|
[FimMiddle, 100259],
|
|
@@ -745,7 +745,7 @@ function P50KBase(bytePairRankDecoder) {
|
|
|
745
745
|
expectedVocabularySize: 50281,
|
|
746
746
|
tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
|
|
747
747
|
bytePairRankDecoder,
|
|
748
|
-
specialTokensEncoder: new Map([[EndOfText, 50256]])
|
|
748
|
+
specialTokensEncoder: /* @__PURE__ */ new Map([[EndOfText, 50256]])
|
|
749
749
|
};
|
|
750
750
|
}
|
|
751
751
|
//#endregion
|
|
@@ -754,7 +754,7 @@ function P50KEdit(bytePairRankDecoder) {
|
|
|
754
754
|
return {
|
|
755
755
|
tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
|
|
756
756
|
bytePairRankDecoder,
|
|
757
|
-
specialTokensEncoder: new Map([
|
|
757
|
+
specialTokensEncoder: /* @__PURE__ */ new Map([
|
|
758
758
|
[EndOfText, 50256],
|
|
759
759
|
[FimPrefix, 50281],
|
|
760
760
|
[FimMiddle, 50282],
|
|
@@ -769,7 +769,7 @@ function R50KBase(bytePairRankDecoder) {
|
|
|
769
769
|
expectedVocabularySize: 50257,
|
|
770
770
|
tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
|
|
771
771
|
bytePairRankDecoder,
|
|
772
|
-
specialTokensEncoder: new Map([[EndOfText, 50256]])
|
|
772
|
+
specialTokensEncoder: /* @__PURE__ */ new Map([[EndOfText, 50256]])
|
|
773
773
|
};
|
|
774
774
|
}
|
|
775
775
|
//#endregion
|
|
@@ -883,11 +883,13 @@ var GptEncoding = class GptEncoding {
|
|
|
883
883
|
}
|
|
884
884
|
}
|
|
885
885
|
static getEncodingApi(encodingName, getMergeableRanks) {
|
|
886
|
-
|
|
886
|
+
const modelParams = getEncodingParams(encodingName, getMergeableRanks);
|
|
887
|
+
return new GptEncoding(modelParams);
|
|
887
888
|
}
|
|
888
889
|
static getEncodingApiForModel(modelName, getMergeableRanks, modelSpec) {
|
|
890
|
+
const modelParams = getEncodingParams(modelToEncodingMap[modelName] ?? "o200k_base", getMergeableRanks);
|
|
889
891
|
return new GptEncoding({
|
|
890
|
-
...
|
|
892
|
+
...modelParams,
|
|
891
893
|
modelName,
|
|
892
894
|
modelSpec
|
|
893
895
|
});
|
|
@@ -950,7 +952,7 @@ var GptEncoding = class GptEncoding {
|
|
|
950
952
|
const chatStartToken = this.specialTokensEncoder.get(ImStart);
|
|
951
953
|
const chatEndToken = this.specialTokensEncoder.get(ImEnd);
|
|
952
954
|
if (chatStartToken === void 0 || chatEndToken === void 0) throw new Error(`Model '${model}' does not support chat.`);
|
|
953
|
-
const allowedSpecial = new Set([ImSep]);
|
|
955
|
+
const allowedSpecial = /* @__PURE__ */ new Set([ImSep]);
|
|
954
956
|
const { messageSeparator, roleSeparator } = params;
|
|
955
957
|
const encodedMessageSeparator = messageSeparator.length > 0 ? this.encode(messageSeparator) : [];
|
|
956
958
|
const encodedRoleSeparator = roleSeparator.length > 0 ? this.encode(roleSeparator, { allowedSpecial }) : [];
|
|
@@ -1098,4 +1100,4 @@ var GptEncoding = class GptEncoding {
|
|
|
1098
1100
|
//#endregion
|
|
1099
1101
|
export { ImStart as _, FimPrefix as a, HarmonyChannel as c, HarmonyMessage as d, HarmonyReturn as f, ImSep as g, ImEnd as h, FimMiddle as i, HarmonyConstrain as l, HarmonyStartOfText as m, EndOfPrompt as n, FimSuffix as o, HarmonyStart as p, EndOfText as r, HarmonyCall as s, GptEncoding as t, HarmonyEnd as u, ALL_SPECIAL_TOKENS as v, DEFAULT_MERGE_CACHE_SIZE as y };
|
|
1100
1102
|
|
|
1101
|
-
//# sourceMappingURL=GptEncoding-
|
|
1103
|
+
//# sourceMappingURL=GptEncoding-DGbju5p-.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as ImStart, a as FimPrefix, c as HarmonyChannel, d as HarmonyMessage, f as HarmonyReturn, g as ImSep, h as ImEnd, i as FimMiddle, l as HarmonyConstrain, m as HarmonyStartOfText, n as EndOfPrompt, o as FimSuffix, p as HarmonyStart, r as EndOfText, s as HarmonyCall, t as GptEncoding, u as HarmonyEnd, v as ALL_SPECIAL_TOKENS, y as DEFAULT_MERGE_CACHE_SIZE } from "./GptEncoding-
|
|
1
|
+
import { _ as ImStart, a as FimPrefix, c as HarmonyChannel, d as HarmonyMessage, f as HarmonyReturn, g as ImSep, h as ImEnd, i as FimMiddle, l as HarmonyConstrain, m as HarmonyStartOfText, n as EndOfPrompt, o as FimSuffix, p as HarmonyStart, r as EndOfText, s as HarmonyCall, t as GptEncoding, u as HarmonyEnd, v as ALL_SPECIAL_TOKENS, y as DEFAULT_MERGE_CACHE_SIZE } from "./GptEncoding-DGbju5p-.mjs";
|
|
2
2
|
//#region node_modules/gpt-tokenizer/esm/bpeRanks/cl100k_base.js
|
|
3
3
|
const c0 = [
|
|
4
4
|
"!",
|
|
@@ -101368,4 +101368,4 @@ const { decode, decodeAsyncGenerator, decodeGenerator, encode, encodeGenerator,
|
|
|
101368
101368
|
//#endregion
|
|
101369
101369
|
export { ALL_SPECIAL_TOKENS, DEFAULT_MERGE_CACHE_SIZE, EndOfPrompt, EndOfText, FimMiddle, FimPrefix, FimSuffix, HarmonyCall, HarmonyChannel, HarmonyConstrain, HarmonyEnd, HarmonyMessage, HarmonyReturn, HarmonyStart, HarmonyStartOfText, ImEnd, ImSep, ImStart, clearMergeCache, countTokens, decode, decodeAsyncGenerator, decodeGenerator, api as default, encode, encodeChat, encodeChatGenerator, encodeGenerator, estimateCost, isWithinTokenLimit, setMergeCacheSize, vocabularySize };
|
|
101370
101370
|
|
|
101371
|
-
//# sourceMappingURL=cl100k_base-
|
|
101371
|
+
//# sourceMappingURL=cl100k_base-CR_-ZzWY.mjs.map
|