Skip to content

Commit 42b352c

Browse files
committed
fix(github-copilot): publish model catalog
1 parent 1f9fafb commit 42b352c

3 files changed

Lines changed: 228 additions & 20 deletions

File tree

extensions/github-copilot/models-defaults.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,27 @@ const DEFAULT_MAX_TOKENS = 8192;
88
// We keep this list intentionally broad; if a model isn't available Copilot will
99
// return an error and users can remove it from their config.
1010
const DEFAULT_MODEL_IDS = [
11+
"claude-haiku-4.5",
12+
"claude-opus-4.5",
13+
"claude-opus-4.6",
1114
"claude-opus-4.7",
15+
"claude-sonnet-4",
1216
"claude-sonnet-4.6",
1317
"claude-sonnet-4.5",
14-
"gpt-4o",
18+
"gemini-2.5-pro",
19+
"gemini-3-flash",
20+
"gemini-3.1-pro",
1521
"gpt-4.1",
16-
"gpt-4.1-mini",
17-
"gpt-4.1-nano",
18-
"o1",
19-
"o1-mini",
20-
"o3-mini",
22+
"gpt-5-mini",
23+
"gpt-5.2",
24+
"gpt-5.2-codex",
25+
"gpt-5.3-codex",
26+
"gpt-5.4",
27+
"gpt-5.4-mini",
28+
"gpt-5.4-nano",
29+
"grok-code-fast-1",
30+
"raptor-mini",
31+
"goldeneye",
2132
] as const;
2233

2334
export function getDefaultCopilotModelIds(): string[] {

extensions/github-copilot/models.test.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ vi.mock("openclaw/plugin-sdk/provider-model-shared", () => ({
2323
}),
2424
}));
2525

26-
const loadJsonFile = vi.fn();
27-
const saveJsonFile = vi.fn();
26+
const jsonStoreMocks = vi.hoisted(() => ({
27+
loadJsonFile: vi.fn(),
28+
saveJsonFile: vi.fn(),
29+
}));
2830

2931
vi.mock("openclaw/plugin-sdk/json-store", () => ({
30-
loadJsonFile,
31-
saveJsonFile,
32+
loadJsonFile: jsonStoreMocks.loadJsonFile,
33+
saveJsonFile: jsonStoreMocks.saveJsonFile,
3234
}));
3335

3436
vi.mock("openclaw/plugin-sdk/state-paths", () => ({
@@ -67,7 +69,7 @@ describe("github-copilot model defaults", () => {
6769
describe("getDefaultCopilotModelIds", () => {
6870
it("includes claude-opus-4.7", () => {
6971
expect(getDefaultCopilotModelIds()).toContain("claude-opus-4.7");
70-
expect(getDefaultCopilotModelIds()).not.toContain("claude-opus-4.6");
72+
expect(getDefaultCopilotModelIds()).toContain("claude-opus-4.6");
7173
});
7274

7375
it("includes claude-sonnet-4.6", () => {
@@ -303,8 +305,8 @@ describe("github-copilot token", () => {
303305

304306
beforeEach(async () => {
305307
vi.resetModules();
306-
loadJsonFile.mockClear();
307-
saveJsonFile.mockClear();
308+
jsonStoreMocks.loadJsonFile.mockClear();
309+
jsonStoreMocks.saveJsonFile.mockClear();
308310
({ deriveCopilotApiBaseUrlFromToken, resolveCopilotApiToken } = await import("./token.js"));
309311
});
310312

@@ -319,7 +321,7 @@ describe("github-copilot token", () => {
319321

320322
it("uses cache when token is still valid", async () => {
321323
const now = Date.now();
322-
loadJsonFile.mockReturnValue({
324+
jsonStoreMocks.loadJsonFile.mockReturnValue({
323325
token: "cached;proxy-ep=proxy.example.com;",
324326
expiresAt: now + 60 * 60 * 1000,
325327
updatedAt: now,
@@ -329,8 +331,8 @@ describe("github-copilot token", () => {
329331
const res = await resolveCopilotApiToken({
330332
githubToken: "gh",
331333
cachePath,
332-
loadJsonFileImpl: loadJsonFile,
333-
saveJsonFileImpl: saveJsonFile,
334+
loadJsonFileImpl: jsonStoreMocks.loadJsonFile,
335+
saveJsonFileImpl: jsonStoreMocks.saveJsonFile,
334336
fetchImpl: fetchImpl as unknown as typeof fetch,
335337
});
336338

@@ -341,7 +343,7 @@ describe("github-copilot token", () => {
341343
});
342344

343345
it("fetches and stores token when cache is missing", async () => {
344-
loadJsonFile.mockReturnValue(undefined);
346+
jsonStoreMocks.loadJsonFile.mockReturnValue(undefined);
345347

346348
const fetchImpl = vi.fn().mockResolvedValue({
347349
ok: true,
@@ -355,13 +357,13 @@ describe("github-copilot token", () => {
355357
const res = await resolveCopilotApiToken({
356358
githubToken: "gh",
357359
cachePath,
358-
loadJsonFileImpl: loadJsonFile,
359-
saveJsonFileImpl: saveJsonFile,
360+
loadJsonFileImpl: jsonStoreMocks.loadJsonFile,
361+
saveJsonFileImpl: jsonStoreMocks.saveJsonFile,
360362
fetchImpl: fetchImpl as unknown as typeof fetch,
361363
});
362364

363365
expect(res.token).toBe("fresh;proxy-ep=https://proxy.contoso.test;");
364366
expect(res.baseUrl).toBe("https://api.contoso.test");
365-
expect(saveJsonFile).toHaveBeenCalledTimes(1);
367+
expect(jsonStoreMocks.saveJsonFile).toHaveBeenCalledTimes(1);
366368
});
367369
});

extensions/github-copilot/openclaw.plugin.json

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,201 @@
1818
}
1919
}
2020
},
21+
"modelCatalog": {
22+
"providers": {
23+
"github-copilot": {
24+
"baseUrl": "https://api.individual.githubcopilot.com",
25+
"api": "openai-responses",
26+
"models": [
27+
{
28+
"id": "claude-haiku-4.5",
29+
"name": "Claude Haiku 4.5",
30+
"api": "anthropic-messages",
31+
"input": ["text", "image"],
32+
"contextWindow": 128000,
33+
"maxTokens": 8192,
34+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
35+
},
36+
{
37+
"id": "claude-opus-4.5",
38+
"name": "Claude Opus 4.5",
39+
"api": "anthropic-messages",
40+
"input": ["text", "image"],
41+
"contextWindow": 128000,
42+
"maxTokens": 8192,
43+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
44+
},
45+
{
46+
"id": "claude-opus-4.6",
47+
"name": "Claude Opus 4.6",
48+
"api": "anthropic-messages",
49+
"input": ["text", "image"],
50+
"contextWindow": 128000,
51+
"maxTokens": 8192,
52+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
53+
},
54+
{
55+
"id": "claude-opus-4.7",
56+
"name": "Claude Opus 4.7",
57+
"api": "anthropic-messages",
58+
"input": ["text", "image"],
59+
"contextWindow": 128000,
60+
"maxTokens": 8192,
61+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
62+
},
63+
{
64+
"id": "claude-sonnet-4",
65+
"name": "Claude Sonnet 4",
66+
"api": "anthropic-messages",
67+
"input": ["text", "image"],
68+
"contextWindow": 128000,
69+
"maxTokens": 8192,
70+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
71+
},
72+
{
73+
"id": "claude-sonnet-4.5",
74+
"name": "Claude Sonnet 4.5",
75+
"api": "anthropic-messages",
76+
"input": ["text", "image"],
77+
"contextWindow": 128000,
78+
"maxTokens": 8192,
79+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
80+
},
81+
{
82+
"id": "claude-sonnet-4.6",
83+
"name": "Claude Sonnet 4.6",
84+
"api": "anthropic-messages",
85+
"input": ["text", "image"],
86+
"contextWindow": 128000,
87+
"maxTokens": 8192,
88+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
89+
},
90+
{
91+
"id": "gemini-2.5-pro",
92+
"name": "Gemini 2.5 Pro",
93+
"input": ["text", "image"],
94+
"contextWindow": 128000,
95+
"maxTokens": 8192,
96+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
97+
},
98+
{
99+
"id": "gemini-3-flash",
100+
"name": "Gemini 3 Flash",
101+
"input": ["text", "image"],
102+
"contextWindow": 128000,
103+
"maxTokens": 8192,
104+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
105+
},
106+
{
107+
"id": "gemini-3.1-pro",
108+
"name": "Gemini 3.1 Pro",
109+
"input": ["text", "image"],
110+
"contextWindow": 128000,
111+
"maxTokens": 8192,
112+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
113+
},
114+
{
115+
"id": "gpt-4.1",
116+
"name": "GPT-4.1",
117+
"input": ["text", "image"],
118+
"contextWindow": 128000,
119+
"maxTokens": 8192,
120+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
121+
},
122+
{
123+
"id": "gpt-5-mini",
124+
"name": "GPT-5 mini",
125+
"reasoning": true,
126+
"input": ["text", "image"],
127+
"contextWindow": 128000,
128+
"maxTokens": 8192,
129+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
130+
},
131+
{
132+
"id": "gpt-5.2",
133+
"name": "GPT-5.2",
134+
"reasoning": true,
135+
"input": ["text", "image"],
136+
"contextWindow": 128000,
137+
"maxTokens": 8192,
138+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
139+
},
140+
{
141+
"id": "gpt-5.2-codex",
142+
"name": "GPT-5.2-Codex",
143+
"reasoning": true,
144+
"input": ["text"],
145+
"contextWindow": 128000,
146+
"maxTokens": 8192,
147+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
148+
},
149+
{
150+
"id": "gpt-5.3-codex",
151+
"name": "GPT-5.3-Codex",
152+
"reasoning": true,
153+
"input": ["text"],
154+
"contextWindow": 128000,
155+
"maxTokens": 8192,
156+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
157+
},
158+
{
159+
"id": "gpt-5.4",
160+
"name": "GPT-5.4",
161+
"reasoning": true,
162+
"input": ["text", "image"],
163+
"contextWindow": 128000,
164+
"maxTokens": 8192,
165+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
166+
},
167+
{
168+
"id": "gpt-5.4-mini",
169+
"name": "GPT-5.4 mini",
170+
"reasoning": true,
171+
"input": ["text", "image"],
172+
"contextWindow": 128000,
173+
"maxTokens": 8192,
174+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
175+
},
176+
{
177+
"id": "gpt-5.4-nano",
178+
"name": "GPT-5.4 nano",
179+
"reasoning": true,
180+
"input": ["text", "image"],
181+
"contextWindow": 128000,
182+
"maxTokens": 8192,
183+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
184+
},
185+
{
186+
"id": "grok-code-fast-1",
187+
"name": "Grok Code Fast 1",
188+
"input": ["text"],
189+
"contextWindow": 128000,
190+
"maxTokens": 8192,
191+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
192+
},
193+
{
194+
"id": "raptor-mini",
195+
"name": "Raptor mini",
196+
"input": ["text"],
197+
"contextWindow": 128000,
198+
"maxTokens": 8192,
199+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
200+
},
201+
{
202+
"id": "goldeneye",
203+
"name": "Goldeneye",
204+
"input": ["text"],
205+
"contextWindow": 128000,
206+
"maxTokens": 8192,
207+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
208+
}
209+
]
210+
}
211+
},
212+
"discovery": {
213+
"github-copilot": "static"
214+
}
215+
},
21216
"contracts": {
22217
"memoryEmbeddingProviders": ["github-copilot"]
23218
},

0 commit comments

Comments
 (0)