copilot-relay 0.3.3 → 0.3.5

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
@@ -49,13 +49,14 @@ Routing:
49
49
  | Requested model | Upstream model |
50
50
  | --- | --- |
51
51
  | contains `opus` | `claude-opus-5` |
52
- | `gpt-5.6-sol[1m]`, plain `gpt-5.6-sol`, or another non-Opus alias | `gpt-5.6-sol` |
52
+ | `gpt-6-astra[1m]`, plain `gpt-6-astra`, or another non-Opus alias | `gpt-6-astra` |
53
53
 
54
- The relay advertises `gpt-5.6-sol[1m]` to Claude Code. The `[1m]` selector
55
- changes Claude Code's client-side context budgeting only; every Copilot request
56
- still uses `gpt-5.6-sol`, and the relay cannot enlarge GitHub Copilot's upstream
57
- capacity. An explicit CLI or API model override that bypasses the managed Claude
58
- settings is outside this guarantee.
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.
59
60
 
60
61
  Claude Code can still show its built-in Haiku and Sonnet picker entries. The
61
62
  managed `model` field sets the startup default but does not restrict
@@ -73,8 +74,8 @@ npx copilot-relay@latest stop
73
74
  With `claudeSetup: true`, `start` manages `ANTHROPIC_BASE_URL`, a dummy
74
75
  `ANTHROPIC_AUTH_TOKEN` when auth is absent, and the configured GPT default via
75
76
  the top-level `model` field in `~/.claude/settings.json`. Exact
76
- `gpt-5.6-sol` model overrides are normalized to the Claude-facing
77
- `gpt-5.6-sol[1m]` identity; unrelated model choices are preserved.
77
+ `gpt-6-astra` and `gpt-5.6-sol` overrides are normalized to Claude-facing
78
+ `[1m]` identities; unrelated model choices are preserved.
78
79
 
79
80
  ## Config
80
81
 
@@ -90,12 +91,16 @@ logRetentionDays: 3
90
91
  thinkEffort: max
91
92
  upstreamTimeoutSeconds: 180
92
93
  webSearchBackend:
94
+ gptModel: gpt-6-astra
95
+ opusModel: claude-opus-5
93
96
  ```
94
97
 
95
98
  copilot-relay writes the resolved config back to this file, so every key is
96
99
  present after the first start. Shipped defaults therefore apply to fresh
97
100
  installs only — once a value is in your `config.yaml` it is never rewritten by
98
- an upgrade. To pick up a changed default, edit the key yourself.
101
+ an upgrade. To pick up a changed default, edit the key yourself. See
102
+ [Configuration](wiki/EN-Configuration.md) / [配置说明](wiki/ZH-Configuration.md)
103
+ for live model discovery, compatible thinking efforts, and copy-paste updates.
99
104
 
100
105
  `logLevel` controls verbosity:
101
106
 
@@ -137,7 +142,7 @@ copilot-relay 0.2.5
137
142
  version 0.2.5
138
143
  listening http://127.0.0.1:4142
139
144
  health ok (9ms)
140
- models gpt-5.6-sol[1m], claude-opus-5
145
+ models gpt-6-astra[1m], claude-opus-5
141
146
  upstream not checked (use --deep)
142
147
  log ~/.copilot-relay/logs/copilot-relay.2026-07-25.log
143
148
  config ~/.copilot-relay/config.yaml
@@ -150,7 +155,7 @@ copilot-relay 0.2.5
150
155
  thinkEffort max
151
156
  upstreamTimeoutSeconds 180
152
157
  webSearchBackend (unset — uses gptModel)
153
- gptModel gpt-5.6-sol
158
+ gptModel gpt-6-astra
154
159
  opusModel claude-opus-5
155
160
  host, port and claudeSetup take effect on restart; the rest hot-reload.
156
161
  ```
@@ -52,7 +52,7 @@ webSearchBackend:
52
52
  # Model routing: requests containing "opus" use opusModel; all others use gptModel.
53
53
  #
54
54
  # Upstream Copilot model used for non-Opus requests.
55
- gptModel: gpt-5.6-sol
55
+ gptModel: gpt-6-astra
56
56
 
57
57
  # Upstream Copilot model used for requests containing "opus".
58
58
  opusModel: claude-opus-5
package/dist/main.js CHANGED
@@ -543,15 +543,19 @@ const runtimeState = {};
543
543
  //#region src/lib/models.ts
544
544
  const defaultReasoningEffort = "max";
545
545
  const defaultModelRouting = {
546
- gptModel: "gpt-5.6-sol",
546
+ gptModel: "gpt-6-astra",
547
547
  opusModel: "claude-opus-5"
548
548
  };
549
549
  const isReasoningEffort = (value) => value === "none" || value === "low" || value === "medium" || value === "high" || value === "xhigh" || value === "max";
550
- const exactGpt56SolPattern = /^gpt-5\.6-sol(?:\[1m\])*$/i;
551
- const claudeContextModelId = "gpt-5.6-sol[1m]";
552
- const copilotModelId = "gpt-5.6-sol";
553
- const normalizeClaudeModelId = (model) => exactGpt56SolPattern.test(model) ? claudeContextModelId : model;
554
- const normalizeCopilotModelId = (model) => exactGpt56SolPattern.test(model) ? copilotModelId : model;
550
+ const oneMillionContextModelPattern = /^(gpt-5\.6-sol|gpt-6-astra)(?:\[1m\])*$/i;
551
+ const normalizeOneMillionContextModel = (model) => {
552
+ return oneMillionContextModelPattern.exec(model)?.[1]?.toLowerCase();
553
+ };
554
+ const normalizeClaudeModelId = (model) => {
555
+ const normalized = normalizeOneMillionContextModel(model);
556
+ return normalized ? `${normalized}[1m]` : model;
557
+ };
558
+ const normalizeCopilotModelId = (model) => normalizeOneMillionContextModel(model) ?? model;
555
559
  const getConfiguredModelRouting = () => runtimeState.modelRouting ?? defaultModelRouting;
556
560
  const getModelRouting = () => {
557
561
  const routing = getConfiguredModelRouting();
@@ -591,7 +595,7 @@ const logLevels = [
591
595
  const defaultConfig = {
592
596
  claudeSetup: true,
593
597
  copilotBaseUrl: "https://api.githubcopilot.com",
594
- gptModel: "gpt-5.6-sol",
598
+ gptModel: "gpt-6-astra",
595
599
  host: "127.0.0.1",
596
600
  logLevel: "info",
597
601
  logRetentionDays: 3,
@@ -1197,7 +1201,7 @@ const hasPrimaryModelOverride = (parsed, env) => typeof parsed.model === "string
1197
1201
  /**
1198
1202
  * Update `~/.claude/settings.json` so its env block points Claude Code at the
1199
1203
  * running proxy. Preserves unrelated keys and model choices while normalizing
1200
- * managed gpt-5.6-sol overrides. Sets a dummy auth token only if none is present.
1204
+ * managed one-million-context GPT overrides. Sets a dummy auth token only if absent.
1201
1205
  */
1202
1206
  async function applyClaudeConfig(input) {
1203
1207
  const { configPath: configPath$1, baseUrl, gptModel } = input;
@@ -1387,7 +1391,7 @@ const fetchCopilot = async (provider, path$1, init, options = {}) => {
1387
1391
 
1388
1392
  //#endregion
1389
1393
  //#region src/copilot/responses.ts
1390
- const responsesOnlyModelPattern = /^(?:gpt-5\.5|gpt-5\.6)(?:-|$)/i;
1394
+ const responsesOnlyModelPattern = /^(?:gpt-5\.5|gpt-5\.6|gpt-6-astra)(?:-|$)/i;
1391
1395
  function shouldUseResponsesApiForModel(model) {
1392
1396
  return responsesOnlyModelPattern.test(model);
1393
1397
  }
@@ -3646,7 +3650,7 @@ const renderStatus = (status$1) => {
3646
3650
  const health = status$1.health;
3647
3651
  lines.push(health?.ok ? ` health ok (${health.ms}ms)` : ` health FAILED${health?.detail ? ` — ${health.detail}` : ""}`);
3648
3652
  lines.push(status$1.models?.length ? ` models ${status$1.models.join(", ")}` : " models unavailable");
3649
- if (status$1.deep) lines.push(status$1.deep.ok ? ` upstream ok (${status$1.deep.ms}ms) — end-to-end Copilot round trip` : ` upstream FAILED${status$1.deep.detail ? ` — ${status$1.deep.detail}` : ""}`);
3653
+ if (status$1.deep) lines.push(status$1.deep.ok ? ` upstream ok (${status$1.deep.ms}ms) — ${status$1.deep.detail ?? "end-to-end Copilot round trip"}` : ` upstream FAILED${status$1.deep.detail ? ` — ${status$1.deep.detail}` : ""}`);
3650
3654
  else lines.push(" upstream not checked (use --deep)");
3651
3655
  lines.push(` log ${status$1.logPath}`, ` config ${status$1.configPath}`, ...renderConfig(status$1.config, true));
3652
3656
  if (status$1.health?.ok && status$1.deep && !status$1.deep.ok) lines.push("", " The relay is listening but cannot reach Copilot.", " Try: copilot-relay auth");
@@ -3736,11 +3740,19 @@ const checkDeep = async (baseUrl, model) => {
3736
3740
  ok: false
3737
3741
  };
3738
3742
  }
3739
- const content = result.body?.content;
3740
- return Array.isArray(content) && content.length > 0 ? {
3741
- ms: result.ms,
3742
- ok: true
3743
- } : {
3743
+ const body = result.body;
3744
+ if (Array.isArray(body?.content)) {
3745
+ if (body.content.length > 0) return {
3746
+ ms: result.ms,
3747
+ ok: true
3748
+ };
3749
+ if (body.type === "message" && body.role === "assistant" && body.stop_reason === "max_tokens" && typeof body.usage?.output_tokens === "number" && Number.isFinite(body.usage.output_tokens) && body.usage.output_tokens > 0) return {
3750
+ detail: "output budget exhausted before visible text",
3751
+ ms: result.ms,
3752
+ ok: true
3753
+ };
3754
+ }
3755
+ return {
3744
3756
  detail: "empty response",
3745
3757
  ms: result.ms,
3746
3758
  ok: false