fix(github-copilot): publish model catalog

This commit is contained in:
Ayaan Zaidi
2026-04-29 16:30:44 +05:30
parent 1f9fafb288
commit 42b352c57e
3 changed files with 228 additions and 20 deletions

View File

@@ -8,16 +8,27 @@ const DEFAULT_MAX_TOKENS = 8192;
// We keep this list intentionally broad; if a model isn't available Copilot will
// return an error and users can remove it from their config.
const DEFAULT_MODEL_IDS = [
"claude-haiku-4.5",
"claude-opus-4.5",
"claude-opus-4.6",
"claude-opus-4.7",
"claude-sonnet-4",
"claude-sonnet-4.6",
"claude-sonnet-4.5",
"gpt-4o",
"gemini-2.5-pro",
"gemini-3-flash",
"gemini-3.1-pro",
"gpt-4.1",
"gpt-4.1-mini",
"gpt-4.1-nano",
"o1",
"o1-mini",
"o3-mini",
"gpt-5-mini",
"gpt-5.2",
"gpt-5.2-codex",
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.4-nano",
"grok-code-fast-1",
"raptor-mini",
"goldeneye",
] as const;
export function getDefaultCopilotModelIds(): string[] {

View File

@@ -23,12 +23,14 @@ vi.mock("openclaw/plugin-sdk/provider-model-shared", () => ({
}),
}));
const loadJsonFile = vi.fn();
const saveJsonFile = vi.fn();
const jsonStoreMocks = vi.hoisted(() => ({
loadJsonFile: vi.fn(),
saveJsonFile: vi.fn(),
}));
vi.mock("openclaw/plugin-sdk/json-store", () => ({
loadJsonFile,
saveJsonFile,
loadJsonFile: jsonStoreMocks.loadJsonFile,
saveJsonFile: jsonStoreMocks.saveJsonFile,
}));
vi.mock("openclaw/plugin-sdk/state-paths", () => ({
@@ -67,7 +69,7 @@ describe("github-copilot model defaults", () => {
describe("getDefaultCopilotModelIds", () => {
it("includes claude-opus-4.7", () => {
expect(getDefaultCopilotModelIds()).toContain("claude-opus-4.7");
expect(getDefaultCopilotModelIds()).not.toContain("claude-opus-4.6");
expect(getDefaultCopilotModelIds()).toContain("claude-opus-4.6");
});
it("includes claude-sonnet-4.6", () => {
@@ -303,8 +305,8 @@ describe("github-copilot token", () => {
beforeEach(async () => {
vi.resetModules();
loadJsonFile.mockClear();
saveJsonFile.mockClear();
jsonStoreMocks.loadJsonFile.mockClear();
jsonStoreMocks.saveJsonFile.mockClear();
({ deriveCopilotApiBaseUrlFromToken, resolveCopilotApiToken } = await import("./token.js"));
});
@@ -319,7 +321,7 @@ describe("github-copilot token", () => {
it("uses cache when token is still valid", async () => {
const now = Date.now();
loadJsonFile.mockReturnValue({
jsonStoreMocks.loadJsonFile.mockReturnValue({
token: "cached;proxy-ep=proxy.example.com;",
expiresAt: now + 60 * 60 * 1000,
updatedAt: now,
@@ -329,8 +331,8 @@ describe("github-copilot token", () => {
const res = await resolveCopilotApiToken({
githubToken: "gh",
cachePath,
loadJsonFileImpl: loadJsonFile,
saveJsonFileImpl: saveJsonFile,
loadJsonFileImpl: jsonStoreMocks.loadJsonFile,
saveJsonFileImpl: jsonStoreMocks.saveJsonFile,
fetchImpl: fetchImpl as unknown as typeof fetch,
});
@@ -341,7 +343,7 @@ describe("github-copilot token", () => {
});
it("fetches and stores token when cache is missing", async () => {
loadJsonFile.mockReturnValue(undefined);
jsonStoreMocks.loadJsonFile.mockReturnValue(undefined);
const fetchImpl = vi.fn().mockResolvedValue({
ok: true,
@@ -355,13 +357,13 @@ describe("github-copilot token", () => {
const res = await resolveCopilotApiToken({
githubToken: "gh",
cachePath,
loadJsonFileImpl: loadJsonFile,
saveJsonFileImpl: saveJsonFile,
loadJsonFileImpl: jsonStoreMocks.loadJsonFile,
saveJsonFileImpl: jsonStoreMocks.saveJsonFile,
fetchImpl: fetchImpl as unknown as typeof fetch,
});
expect(res.token).toBe("fresh;proxy-ep=https://proxy.contoso.test;");
expect(res.baseUrl).toBe("https://api.contoso.test");
expect(saveJsonFile).toHaveBeenCalledTimes(1);
expect(jsonStoreMocks.saveJsonFile).toHaveBeenCalledTimes(1);
});
});

View File

@@ -18,6 +18,201 @@
}
}
},
"modelCatalog": {
"providers": {
"github-copilot": {
"baseUrl": "https://api.individual.githubcopilot.com",
"api": "openai-responses",
"models": [
{
"id": "claude-haiku-4.5",
"name": "Claude Haiku 4.5",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-opus-4.5",
"name": "Claude Opus 4.5",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-opus-4.6",
"name": "Claude Opus 4.6",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-opus-4.7",
"name": "Claude Opus 4.7",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-sonnet-4",
"name": "Claude Sonnet 4",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-sonnet-4.5",
"name": "Claude Sonnet 4.5",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "claude-sonnet-4.6",
"name": "Claude Sonnet 4.6",
"api": "anthropic-messages",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gemini-2.5-pro",
"name": "Gemini 2.5 Pro",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gemini-3-flash",
"name": "Gemini 3 Flash",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gemini-3.1-pro",
"name": "Gemini 3.1 Pro",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-4.1",
"name": "GPT-4.1",
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5-mini",
"name": "GPT-5 mini",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.2",
"name": "GPT-5.2",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.2-codex",
"name": "GPT-5.2-Codex",
"reasoning": true,
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.3-codex",
"name": "GPT-5.3-Codex",
"reasoning": true,
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.4-mini",
"name": "GPT-5.4 mini",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "gpt-5.4-nano",
"name": "GPT-5.4 nano",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "grok-code-fast-1",
"name": "Grok Code Fast 1",
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "raptor-mini",
"name": "Raptor mini",
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
},
{
"id": "goldeneye",
"name": "Goldeneye",
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
}
]
}
},
"discovery": {
"github-copilot": "static"
}
},
"contracts": {
"memoryEmbeddingProviders": ["github-copilot"]
},