betahi-copilot-bridge 0.1.7 → 0.19.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 +29 -11
- package/dist/main.js +115 -36
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">copilot-bridge</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<a href="https://www.npmjs.com/package/betahi-copilot-bridge"><img src="https://img.shields.io/npm/v/betahi-copilot-bridge.svg?v=0.
|
|
4
|
+
<a href="https://www.npmjs.com/package/betahi-copilot-bridge"><img src="https://img.shields.io/npm/v/betahi-copilot-bridge.svg?v=0.19.0" alt="npm version"></a>
|
|
5
5
|
<a href="https://github.com/betahi/copilot-bridge/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/betahi-copilot-bridge.svg" alt="license"></a>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
@@ -100,13 +100,23 @@ these keys across rewrites:
|
|
|
100
100
|
```toml
|
|
101
101
|
model = "gpt-5.3-codex"
|
|
102
102
|
model_reasoning_effort = "high"
|
|
103
|
+
model_supports_reasoning_summaries = true
|
|
103
104
|
```
|
|
104
105
|
|
|
105
106
|
If `model_reasoning_effort` is omitted, the bridge leaves it unset and does not
|
|
106
107
|
send a reasoning effort for Codex requests (a startup info log also reminds you).
|
|
108
|
+
Codex requires `model_supports_reasoning_summaries = true` for custom providers
|
|
109
|
+
to serialize the `reasoning` object; `start --select-model` writes it for you
|
|
110
|
+
when it writes `model_reasoning_effort`.
|
|
107
111
|
|
|
108
112
|
`model_reasoning_effort` only affects Codex requests; it does not affect Claude.
|
|
109
113
|
|
|
114
|
+
For Claude Opus 4.7 through Codex, you can keep `model = "claude-opus-4.7"`
|
|
115
|
+
and set `model_reasoning_effort = "high"` or `"xhigh"`; the bridge routes the
|
|
116
|
+
request to the matching Opus 4.7 reasoning variant upstream. Use
|
|
117
|
+
`model = "claude-opus-4.7-1m"` for the 1M context window; it maps to the upstream
|
|
118
|
+
1M model without exposing the upstream-only suffix in your config.
|
|
119
|
+
|
|
110
120
|
That's it — `codex exec '...'` will now route through the bridge to Copilot.
|
|
111
121
|
|
|
112
122
|
Use `--no-codex-setup` to skip the managed-block writer entirely (e.g. if you
|
|
@@ -163,6 +173,11 @@ project-local `.claude/settings.json` and `.claude/settings.local.json` and
|
|
|
163
173
|
applied to Claude requests only when the model supports reasoning. If it is not
|
|
164
174
|
configured, Claude requests do not infer or attach a reasoning effort.
|
|
165
175
|
|
|
176
|
+
For compatibility, `ANTHROPIC_MODEL=claude-opus-4.7` plus
|
|
177
|
+
`MODEL_REASONING_EFFORT=high` or `xhigh` is automatically routed to the matching
|
|
178
|
+
Opus 4.7 reasoning variant upstream, so existing settings keep the intended
|
|
179
|
+
reasoning level.
|
|
180
|
+
|
|
166
181
|
## Environment overrides
|
|
167
182
|
|
|
168
183
|
| Variable | Purpose |
|
|
@@ -194,16 +209,19 @@ accepts upstream.
|
|
|
194
209
|
|
|
195
210
|
### Claude family — translated to chat completions
|
|
196
211
|
|
|
197
|
-
| Model
|
|
198
|
-
|
|
|
199
|
-
| `claude-opus-4.7`
|
|
200
|
-
| `claude-opus-4.
|
|
201
|
-
| `claude-opus-4.
|
|
202
|
-
| `claude-
|
|
203
|
-
| `claude-opus-4.
|
|
204
|
-
| `claude-
|
|
205
|
-
| `claude-sonnet-4`
|
|
206
|
-
| `claude-
|
|
212
|
+
| Model | Reasoning efforts | Notes |
|
|
213
|
+
| -------------------------------- | --------------------------------------- | -------------------------------------- |
|
|
214
|
+
| `claude-opus-4.7` | `medium` | Effort sent as `output_config.effort`. |
|
|
215
|
+
| `claude-opus-4.7-1m` | `low`, `medium`, `high`, `xhigh` | 1M-token context window; effort sent as `output_config.effort`. |
|
|
216
|
+
| `claude-opus-4.7-high` | `high` | Fixed high reasoning; effort sent as `output_config.effort`. |
|
|
217
|
+
| `claude-opus-4.7-xhigh` | `xhigh` | Fixed extra-high reasoning; effort sent as `output_config.effort`. |
|
|
218
|
+
| `claude-opus-4.6` | `low`, `medium`, `high` | |
|
|
219
|
+
| `claude-opus-4.6-1m` | `low`, `medium`, `high` | 1M-token context window. |
|
|
220
|
+
| `claude-sonnet-4.6` | `low`, `medium`, `high` | |
|
|
221
|
+
| `claude-opus-4.5` | — | Reasoning not accepted upstream. |
|
|
222
|
+
| `claude-sonnet-4.5` | — | Reasoning not accepted upstream. |
|
|
223
|
+
| `claude-sonnet-4` | — | Reasoning not accepted upstream. |
|
|
224
|
+
| `claude-haiku-4.5` | — | Reasoning not accepted upstream. |
|
|
207
225
|
|
|
208
226
|
### Gemini family — translated to chat completions
|
|
209
227
|
|
package/dist/main.js
CHANGED
|
@@ -502,11 +502,20 @@ function setTopScalar(topSection, key, value) {
|
|
|
502
502
|
if (topSection.length === 0) return `${line}\n`;
|
|
503
503
|
return `${line}\n${topSection.startsWith("\n") ? "" : ""}${topSection}`;
|
|
504
504
|
}
|
|
505
|
+
function setTopBoolean(topSection, key, value) {
|
|
506
|
+
if (value === void 0) return topSection;
|
|
507
|
+
const re = new RegExp(`^\\s*${key}\\s*=\\s*(true|false)\\s*$`, "m");
|
|
508
|
+
const line = `${key} = ${value ? "true" : "false"}`;
|
|
509
|
+
if (re.test(topSection)) return topSection.replace(re, line);
|
|
510
|
+
if (topSection.length === 0) return `${line}\n`;
|
|
511
|
+
return `${line}\n${topSection.startsWith("\n") ? "" : ""}${topSection}`;
|
|
512
|
+
}
|
|
505
513
|
function applyUserScalars(content, input) {
|
|
506
514
|
const { top, rest } = splitTopSection(content);
|
|
507
515
|
let nextTop = top;
|
|
508
516
|
nextTop = setTopScalar(nextTop, "model", input.model);
|
|
509
517
|
nextTop = setTopScalar(nextTop, "model_reasoning_effort", input.modelReasoningEffort);
|
|
518
|
+
nextTop = setTopBoolean(nextTop, "model_supports_reasoning_summaries", input.modelReasoningEffort === void 0 ? void 0 : true);
|
|
510
519
|
if (nextTop === top) return content;
|
|
511
520
|
if (rest.length === 0) return nextTop.endsWith("\n") ? nextTop : `${nextTop}\n`;
|
|
512
521
|
const sep = nextTop.endsWith("\n") ? "" : "\n";
|
|
@@ -649,21 +658,43 @@ const MODEL_CAPABILITIES = [
|
|
|
649
658
|
default: "medium"
|
|
650
659
|
}
|
|
651
660
|
},
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
661
|
+
...[
|
|
662
|
+
{
|
|
663
|
+
id: "claude-opus-4.7",
|
|
664
|
+
supported: ["medium"],
|
|
665
|
+
defaultEffort: "medium"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
id: "claude-opus-4.7-1m-internal",
|
|
669
|
+
aliases: ["claude-opus-4.7-1m"],
|
|
657
670
|
supported: [
|
|
658
671
|
"low",
|
|
659
672
|
"medium",
|
|
660
673
|
"high",
|
|
661
|
-
"xhigh"
|
|
662
|
-
"max"
|
|
674
|
+
"xhigh"
|
|
663
675
|
],
|
|
664
|
-
|
|
676
|
+
defaultEffort: "medium"
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
id: "claude-opus-4.7-high",
|
|
680
|
+
supported: ["high"],
|
|
681
|
+
defaultEffort: "high"
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
id: "claude-opus-4.7-xhigh",
|
|
685
|
+
supported: ["xhigh"],
|
|
686
|
+
defaultEffort: "xhigh"
|
|
665
687
|
}
|
|
666
|
-
}
|
|
688
|
+
].map(({ id, aliases, supported, defaultEffort }) => ({
|
|
689
|
+
id,
|
|
690
|
+
aliases,
|
|
691
|
+
fallback: "chat-completions",
|
|
692
|
+
reasoningField: "output_config.effort",
|
|
693
|
+
reasoning: {
|
|
694
|
+
supported,
|
|
695
|
+
default: defaultEffort
|
|
696
|
+
}
|
|
697
|
+
})),
|
|
667
698
|
{
|
|
668
699
|
id: "claude-opus-4.6",
|
|
669
700
|
fallback: "chat-completions",
|
|
@@ -1155,7 +1186,7 @@ const normalizeClaudeOpus47Effort = (value) => {
|
|
|
1155
1186
|
default: return;
|
|
1156
1187
|
}
|
|
1157
1188
|
};
|
|
1158
|
-
const getEnvValueCaseInsensitive = (env, key) => {
|
|
1189
|
+
const getEnvValueCaseInsensitive$1 = (env, key) => {
|
|
1159
1190
|
const direct = env[key];
|
|
1160
1191
|
if (typeof direct === "string") return direct;
|
|
1161
1192
|
const lower = key.toLowerCase();
|
|
@@ -1163,7 +1194,7 @@ const getEnvValueCaseInsensitive = (env, key) => {
|
|
|
1163
1194
|
};
|
|
1164
1195
|
const getConfiguredReasoningEffort = (client, claudeSettingsEnv) => {
|
|
1165
1196
|
if (client !== "claude") return;
|
|
1166
|
-
return process.env.MODEL_REASONING_EFFORT ?? getEnvValueCaseInsensitive(claudeSettingsEnv, "MODEL_REASONING_EFFORT");
|
|
1197
|
+
return process.env.MODEL_REASONING_EFFORT ?? getEnvValueCaseInsensitive$1(claudeSettingsEnv, "MODEL_REASONING_EFFORT");
|
|
1167
1198
|
};
|
|
1168
1199
|
const getRequestedReasoningEffort = (payload, claudeSettingsEnv, client) => {
|
|
1169
1200
|
const configuredReasoningEffort = getConfiguredReasoningEffort(client, claudeSettingsEnv);
|
|
@@ -1173,7 +1204,9 @@ const getRequestedReasoningEffort = (payload, claudeSettingsEnv, client) => {
|
|
|
1173
1204
|
const getRequestedClaudeOpus47Effort = (payload, claudeSettingsEnv, client) => {
|
|
1174
1205
|
if (!isClaudeOpus47Model$1(payload.model)) return;
|
|
1175
1206
|
const configuredReasoningEffort = getConfiguredReasoningEffort(client, claudeSettingsEnv);
|
|
1176
|
-
|
|
1207
|
+
const requested = normalizeClaudeOpus47Effort(payload.reasoning_effort) ?? normalizeClaudeOpus47Effort(configuredReasoningEffort) ?? payload.output_config?.effort;
|
|
1208
|
+
if (!requested) return;
|
|
1209
|
+
return clampReasoningEffort(payload.model, requested)?.effort;
|
|
1177
1210
|
};
|
|
1178
1211
|
const sanitizeUserIdentifier = (user) => {
|
|
1179
1212
|
if (!user) return;
|
|
@@ -1366,20 +1399,21 @@ embeddingRoutes.post("/", async (c) => {
|
|
|
1366
1399
|
const normalizeModelId = (modelId) => modelId.trim().toLowerCase().replaceAll(/[\s._-]+/g, "");
|
|
1367
1400
|
const stripSnapshotSuffix = (modelId) => {
|
|
1368
1401
|
const id = modelId.trim().toLowerCase().replace(/\[1m\]$/, "");
|
|
1369
|
-
|
|
1402
|
+
if (id === "claude-opus-4.7-1m") return "claude-opus-4.7-1m-internal";
|
|
1403
|
+
const claudeSnapshotMatch = id.match(/^claude-(opus|sonnet|haiku)-(\d)-(\d)((?:-[a-z0-9]+)*?)(?:-\d{8})?$/);
|
|
1370
1404
|
if (claudeSnapshotMatch) {
|
|
1371
|
-
const [, family, major, minor,
|
|
1372
|
-
return `claude-${family}-${major}.${minor}${
|
|
1405
|
+
const [, family, major, minor, suffix = ""] = claudeSnapshotMatch;
|
|
1406
|
+
return `claude-${family}-${major}.${minor}${suffix}`;
|
|
1373
1407
|
}
|
|
1374
1408
|
return id;
|
|
1375
1409
|
};
|
|
1376
1410
|
const getAliasCandidates = (modelId) => {
|
|
1377
1411
|
const canonicalModelId = stripSnapshotSuffix(modelId);
|
|
1378
1412
|
const aliases = new Set([canonicalModelId]);
|
|
1379
|
-
const canonicalClaudeMatch = canonicalModelId.match(/^claude-(opus|sonnet|haiku)-(\d+)\.(\d+)(-
|
|
1413
|
+
const canonicalClaudeMatch = canonicalModelId.match(/^claude-(opus|sonnet|haiku)-(\d+)\.(\d+)((?:-[a-z0-9]+)*)$/);
|
|
1380
1414
|
if (canonicalClaudeMatch) {
|
|
1381
|
-
const [, family, major, minor,
|
|
1382
|
-
aliases.add(`claude-${family}-${major}-${minor}${
|
|
1415
|
+
const [, family, major, minor, suffix = ""] = canonicalClaudeMatch;
|
|
1416
|
+
aliases.add(`claude-${family}-${major}-${minor}${suffix}`);
|
|
1383
1417
|
return [...aliases];
|
|
1384
1418
|
}
|
|
1385
1419
|
const familyMatch = canonicalModelId.match(/^[a-z]+(?:-[a-z]+)*-\d+(?:\.\d+)?/);
|
|
@@ -1463,7 +1497,7 @@ const getToolNameMapperOptionsForModel = (modelId) => {
|
|
|
1463
1497
|
allowDots: true,
|
|
1464
1498
|
maxNameLength: EXTENDED_TOOL_NAME_MAX_LENGTH
|
|
1465
1499
|
};
|
|
1466
|
-
if (/^gpt-5-(?:2|4)(?:$|-)/.test(normalized) || /^gpt-5-(?:2|3)-codex(?:$|-)/.test(normalized) || /^gpt-5-4-mini(?:$|-)/.test(normalized) || /^gpt-5-5(?:$|-)/.test(normalized)) return {
|
|
1500
|
+
if (/^gpt-5-(?:2|4)(?:$|-)/.test(normalized) || /^gpt-5-(?:2|3)-codex(?:$|-)/.test(normalized) || /^gpt-5-4-mini(?:$|-)/.test(normalized) || /^gpt-5-mini(?:$|-)/.test(normalized) || /^gpt-5-5(?:$|-)/.test(normalized)) return {
|
|
1467
1501
|
allowDots: false,
|
|
1468
1502
|
maxNameLength: EXTENDED_TOOL_NAME_MAX_LENGTH
|
|
1469
1503
|
};
|
|
@@ -1526,12 +1560,42 @@ const normalizeClaudeModelAlias = (model) => {
|
|
|
1526
1560
|
const trimmed = model.trim().toLowerCase();
|
|
1527
1561
|
if (trimmed === "opus[1m]") return "claude-opus-4.6-1m";
|
|
1528
1562
|
const normalized = trimmed.replace(/\[1m\]$/, "");
|
|
1529
|
-
|
|
1530
|
-
if (
|
|
1531
|
-
if (
|
|
1532
|
-
if (
|
|
1533
|
-
|
|
1534
|
-
|
|
1563
|
+
const prefixed = normalized.startsWith("opus-") ? `claude-${normalized}` : normalized;
|
|
1564
|
+
if (prefixed === "opus") return "claude-opus";
|
|
1565
|
+
if (prefixed === "sonnet") return "claude-sonnet";
|
|
1566
|
+
if (prefixed === "haiku") return "claude-haiku";
|
|
1567
|
+
const claudeSnapshotMatch = prefixed.match(/^claude-(opus|sonnet|haiku)-(\d)-(\d)((?:-[a-z0-9]+)*?)(?:-\d{8})?$/);
|
|
1568
|
+
if (claudeSnapshotMatch) {
|
|
1569
|
+
const [, family, major, minor, suffix = ""] = claudeSnapshotMatch;
|
|
1570
|
+
return `claude-${family}-${major}.${minor}${suffix}`;
|
|
1571
|
+
}
|
|
1572
|
+
return prefixed;
|
|
1573
|
+
};
|
|
1574
|
+
function normalizeClaudeReasoningEffortForRouting(value) {
|
|
1575
|
+
switch (value?.toLowerCase()) {
|
|
1576
|
+
case "low":
|
|
1577
|
+
case "medium":
|
|
1578
|
+
case "high":
|
|
1579
|
+
case "xhigh":
|
|
1580
|
+
case "max": return value.toLowerCase();
|
|
1581
|
+
default: return;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
const getEnvValueCaseInsensitive = (env, key) => {
|
|
1585
|
+
const direct = env[key];
|
|
1586
|
+
if (typeof direct === "string") return direct;
|
|
1587
|
+
const lower = key.toLowerCase();
|
|
1588
|
+
return Object.entries(env).find(([k]) => k.toLowerCase() === lower)?.[1];
|
|
1589
|
+
};
|
|
1590
|
+
const getConfiguredClaudeReasoningEffort = (settings) => process.env.MODEL_REASONING_EFFORT ?? getEnvValueCaseInsensitive(settings?.env ?? {}, "MODEL_REASONING_EFFORT");
|
|
1591
|
+
const routeClaudeOpus47ByEffort = (model, requestedEffort) => {
|
|
1592
|
+
if (model !== "claude-opus-4.7") return model;
|
|
1593
|
+
switch (normalizeClaudeReasoningEffortForRouting(requestedEffort)) {
|
|
1594
|
+
case "high": return "claude-opus-4.7-high";
|
|
1595
|
+
case "xhigh":
|
|
1596
|
+
case "max": return "claude-opus-4.7-xhigh";
|
|
1597
|
+
default: return model;
|
|
1598
|
+
}
|
|
1535
1599
|
};
|
|
1536
1600
|
const getConfiguredClaudeDefaultModel = (settings) => {
|
|
1537
1601
|
if (!settings) return;
|
|
@@ -1551,8 +1615,8 @@ const resolveClaudeRequestedModel = (model, settings) => {
|
|
|
1551
1615
|
if (model.trim().toLowerCase() !== "definitely-not-a-real-model") return model;
|
|
1552
1616
|
return getConfiguredClaudeDefaultModel(settings) ?? model;
|
|
1553
1617
|
};
|
|
1554
|
-
function translateModelName(model, settings) {
|
|
1555
|
-
return resolveUpstreamModelId(normalizeClaudeModelAlias(resolveClaudeRequestedModel(model, settings)));
|
|
1618
|
+
function translateModelName(model, settings, requestedReasoningEffort) {
|
|
1619
|
+
return resolveUpstreamModelId(routeClaudeOpus47ByEffort(normalizeClaudeModelAlias(resolveClaudeRequestedModel(model, settings)), requestedReasoningEffort ?? getConfiguredClaudeReasoningEffort(settings)));
|
|
1556
1620
|
}
|
|
1557
1621
|
function isClaudeModel(modelId) {
|
|
1558
1622
|
return modelId.startsWith("claude-");
|
|
@@ -1582,12 +1646,12 @@ function getClaudeOpus47Effort(payload) {
|
|
|
1582
1646
|
return "xhigh";
|
|
1583
1647
|
}
|
|
1584
1648
|
function translateThinking(payload, settings) {
|
|
1585
|
-
if (!isClaudeOpus47Model(translateModelName(payload.model, settings))) return;
|
|
1649
|
+
if (!isClaudeOpus47Model(translateModelName(payload.model, settings, payload.reasoning_effort))) return;
|
|
1586
1650
|
if (payload.thinking?.type === "adaptive") return { type: "adaptive" };
|
|
1587
1651
|
return payload.thinking?.type === "enabled" ? { type: "adaptive" } : void 0;
|
|
1588
1652
|
}
|
|
1589
1653
|
function translateOutputConfig(payload, settings) {
|
|
1590
|
-
if (!isClaudeOpus47Model(translateModelName(payload.model, settings))) return;
|
|
1654
|
+
if (!isClaudeOpus47Model(translateModelName(payload.model, settings, payload.reasoning_effort))) return;
|
|
1591
1655
|
const effort = getClaudeOpus47Effort(payload);
|
|
1592
1656
|
return effort ? { effort } : void 0;
|
|
1593
1657
|
}
|
|
@@ -1603,7 +1667,7 @@ function normalizeReasoningEffort(value) {
|
|
|
1603
1667
|
}
|
|
1604
1668
|
}
|
|
1605
1669
|
function translateReasoningEffort(payload, settings) {
|
|
1606
|
-
const modelId = translateModelName(payload.model, settings);
|
|
1670
|
+
const modelId = translateModelName(payload.model, settings, payload.reasoning_effort);
|
|
1607
1671
|
if (isClaudeOpus47Model(modelId)) return;
|
|
1608
1672
|
if (payload.reasoning_effort) return sanitizeReasoningEffortForModel(modelId, normalizeReasoningEffort(payload.reasoning_effort));
|
|
1609
1673
|
if (isClaudeModel(modelId)) return;
|
|
@@ -1616,7 +1680,7 @@ function translateReasoningEffort(payload, settings) {
|
|
|
1616
1680
|
return sanitizeReasoningEffortForModel(modelId, "xhigh");
|
|
1617
1681
|
}
|
|
1618
1682
|
function translateToOpenAI(payload, settings, toolNameMapper) {
|
|
1619
|
-
const model = translateModelName(payload.model, settings);
|
|
1683
|
+
const model = translateModelName(payload.model, settings, payload.reasoning_effort);
|
|
1620
1684
|
const mapper = toolNameMapper ?? createAnthropicToolNameMapper(payload.tools, { ...getToolNameMapperOptionsForModel(model) });
|
|
1621
1685
|
const tools = translateAnthropicToolsToOpenAI(payload.tools, mapper);
|
|
1622
1686
|
return {
|
|
@@ -2532,9 +2596,19 @@ const removeReasoningEffort = (reasoning) => {
|
|
|
2532
2596
|
return Object.keys(next).length > 0 ? next : void 0;
|
|
2533
2597
|
};
|
|
2534
2598
|
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2599
|
+
const routeClaudeOpus47ByReasoningEffort = (model, effort) => {
|
|
2600
|
+
if (model !== "claude-opus-4.7") return model;
|
|
2601
|
+
switch (typeof effort === "string" ? effort.toLowerCase() : void 0) {
|
|
2602
|
+
case "high": return "claude-opus-4.7-high";
|
|
2603
|
+
case "xhigh":
|
|
2604
|
+
case "max": return "claude-opus-4.7-xhigh";
|
|
2605
|
+
default: return model;
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2535
2608
|
const normalizeCodexResponsesRequest = (payload) => {
|
|
2536
2609
|
const parsed = codexResponsesRequestSchema.parse(payload);
|
|
2537
|
-
const
|
|
2610
|
+
const requestedReasoningEffort = isPlainObject(parsed.reasoning) ? parsed.reasoning.effort : void 0;
|
|
2611
|
+
const canonical = routeClaudeOpus47ByReasoningEffort(resolveModelId(parsed.model), requestedReasoningEffort);
|
|
2538
2612
|
const capability = getModelCapability(canonical);
|
|
2539
2613
|
if (!capability) return parsed;
|
|
2540
2614
|
const next = {
|
|
@@ -2758,6 +2832,8 @@ const startServer = (config) => serve({
|
|
|
2758
2832
|
|
|
2759
2833
|
//#endregion
|
|
2760
2834
|
//#region src/start.ts
|
|
2835
|
+
const getPublicModelId = (id) => id === "claude-opus-4.7-1m-internal" ? "claude-opus-4.7-1m" : id;
|
|
2836
|
+
const unique = (ids) => [...new Set(ids)];
|
|
2761
2837
|
const fetchAvailableModels = async (config) => {
|
|
2762
2838
|
try {
|
|
2763
2839
|
const response = await fetchCopilot(getCopilotProviderContext(config), "/models", {
|
|
@@ -2897,10 +2973,13 @@ const start = defineCommand({
|
|
|
2897
2973
|
consola.warn(`Could not update codex config (${codexConfigPath}):`, error);
|
|
2898
2974
|
}
|
|
2899
2975
|
const models = await fetchAvailableModels(config);
|
|
2900
|
-
const supportedIds = new Set(MODEL_CAPABILITIES.
|
|
2901
|
-
const
|
|
2902
|
-
const
|
|
2903
|
-
|
|
2976
|
+
const supportedIds = new Set(MODEL_CAPABILITIES.flatMap((m) => [m.id, ...m.aliases ?? []]));
|
|
2977
|
+
const fallbackModelIds = unique(MODEL_CAPABILITIES.map((m) => getPublicModelId(m.id)));
|
|
2978
|
+
const pickable = models.length > 0 ? unique(models.filter((id) => supportedIds.has(id)).map((id) => getPublicModelId(id))) : fallbackModelIds;
|
|
2979
|
+
const finalPickable = pickable.length > 0 ? pickable : fallbackModelIds;
|
|
2980
|
+
if (models.length > 0) consola.info(`Available models:\n${models.map((id) => {
|
|
2981
|
+
return `- ${getPublicModelId(id)}${supportedIds.has(id) ? " (bridge-supported)" : ""}`;
|
|
2982
|
+
}).join("\n")}`);
|
|
2904
2983
|
else consola.warn("Could not fetch model list from upstream Copilot API");
|
|
2905
2984
|
consola.box([
|
|
2906
2985
|
`🌐 Usage viewer`,
|