fix(pi-ai): filter unavailable github copilot models (#4031)

This commit is contained in:
mastertyko 2026-04-13 12:46:27 +02:00 committed by GitHub
parent 754979e7a6
commit 0df033dbac
2 changed files with 75 additions and 1 deletions

View file

@ -0,0 +1,71 @@
import assert from "node:assert/strict";
import test from "node:test";
import type { Api, Model } from "../../types.js";
import type { OAuthCredentials } from "./index.js";
import { githubCopilotOAuthProvider } from "./github-copilot.js";
function makeModel(provider: string, id: string): Model<Api> {
return {
id,
name: id,
api: "openai-completions",
provider,
baseUrl: `${provider}:`,
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 16384,
};
}
function makeCredentials(overrides: Partial<OAuthCredentials & { modelLimits?: Record<string, { contextWindow: number; maxTokens: number }> }> = {}) {
return {
type: "oauth" as const,
access: "copilot-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
...overrides,
};
}
test("githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)", () => {
const models = [
makeModel("github-copilot", "gpt-5"),
makeModel("github-copilot", "claude-sonnet-4"),
makeModel("openai", "gpt-4.1"),
];
assert.ok(githubCopilotOAuthProvider.modifyModels, "github copilot provider should expose modifyModels");
const modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials({
modelLimits: {
"gpt-5": { contextWindow: 256000, maxTokens: 32000 },
},
}));
assert.deepEqual(
modified.map((model) => `${model.provider}/${model.id}`),
["github-copilot/gpt-5", "openai/gpt-4.1"],
);
const copilotModel = modified.find((model) => model.provider === "github-copilot" && model.id === "gpt-5");
assert.ok(copilotModel, "available copilot model should remain");
assert.equal(copilotModel.contextWindow, 256000);
assert.equal(copilotModel.maxTokens, 32000);
assert.match(copilotModel.baseUrl, /githubcopilot\.com/);
});
test("githubCopilotOAuthProvider.modifyModels keeps all copilot models when limits are unavailable", () => {
const models = [
makeModel("github-copilot", "gpt-5"),
makeModel("github-copilot", "claude-sonnet-4"),
];
assert.ok(githubCopilotOAuthProvider.modifyModels, "github copilot provider should expose modifyModels");
const modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials());
assert.equal(modified.length, 2, "lack of limits should not hide every copilot model");
assert.ok(modified.every((model) => model.provider === "github-copilot"));
assert.ok(modified.every((model) => model.baseUrl.includes("githubcopilot.com")));
});

View file

@ -441,8 +441,11 @@ export const githubCopilotOAuthProvider: OAuthProviderInterface = {
const domain = creds.enterpriseUrl ? (normalizeDomain(creds.enterpriseUrl) ?? undefined) : undefined;
const baseUrl = getGitHubCopilotBaseUrl(creds.access, domain);
const limits = creds.modelLimits;
return models.map((m) => {
const availableModelIds = limits ? new Set(Object.keys(limits)) : null;
const shouldFilterByAvailability = !!availableModelIds && availableModelIds.size > 0;
return models.flatMap((m) => {
if (m.provider !== "github-copilot") return m;
if (shouldFilterByAvailability && !availableModelIds.has(m.id)) return [];
const modelLimits = limits?.[m.id];
return {
...m,