Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "copilot-sdk-proxy",
"version": "1.0.1",
"version": "1.0.2",
"description": "Generic proxy server translating OpenAI/Anthropic/Codex API requests into GitHub Copilot SDK sessions",
"type": "module",
"license": "MIT",
Expand Down
11 changes: 5 additions & 6 deletions src/providers/shared/model-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ function normalize(id: string): string {
return id.replace(/-\d{8}$/, "").replace(/\./g, "-");
}

// We need to group models by family for fallback matching, so we grab the
// prefix before the first digit (e.g. "claude-sonnet-4-5" becomes "claude-sonnet-").
// This works for Claude naming but would lump all GPT models into "gpt-"
// so it'll need reworking once we support non-Claude model families here
// e.g. if we add Codex support.
// Group models by family for fallback matching by grabbing everything before
// the first digit (e.g. "claude-sonnet-4-5" becomes "claude-sonnet-",
// "o3-mini" becomes "o", "gpt-5" becomes "gpt-"). The longest-prefix
// matching within the family handles disambiguation.
function extractFamily(id: string): string {
const match = id.match(/^(.*?-)\d/);
const match = id.match(/^(.*?)\d/);
return match?.[1] ?? id;
}

Expand Down
12 changes: 12 additions & 0 deletions test/model-resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const copilotModels = [
"claude-sonnet-4.5",
"gpt-5",
"gpt-5.1",
"o3-mini",
"o4-mini",
].map(model);

describe("resolveModel", () => {
Expand Down Expand Up @@ -80,6 +82,16 @@ describe("resolveModel", () => {
);
});

it("handles o-series models (exact match)", () => {
expect(resolveModel("o3-mini", copilotModels)).toBe("o3-mini");
});

it("falls back within o-series family", () => {
// o3 isn't available but o3-mini is, and they share the "o" family
// with o3-mini winning on longest prefix
expect(resolveModel("o3", copilotModels)).toBe("o3-mini");
});

it("returns undefined for empty models array", () => {
expect(resolveModel("claude-sonnet-4.5", [])).toBeUndefined();
});
Expand Down