From 527ee1a6fcc89a6a478232e01fa5bc38c2ddf7b7 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Thu, 25 Jun 2026 23:43:45 -0300 Subject: [PATCH] feat(sse): add GPT-4o mini to GitHub Copilot provider (#4797) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green. --- .../config/providers/registry/github/index.ts | 4 ++ tests/unit/github-copilot-gpt-4o-mini.test.ts | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/unit/github-copilot-gpt-4o-mini.test.ts diff --git a/open-sse/config/providers/registry/github/index.ts b/open-sse/config/providers/registry/github/index.ts index 149e9669c5..f8c25d05a1 100644 --- a/open-sse/config/providers/registry/github/index.ts +++ b/open-sse/config/providers/registry/github/index.ts @@ -31,6 +31,10 @@ export const githubProvider: RegistryEntry = { // 9router#98 — Copilot still serves GPT-4o via chat/completions; keep it // alongside the GPT-5.x family so apps that hard-code `gpt-4o` resolve here. { id: "gpt-4o", name: "GPT-4o", contextLength: 128000 }, + // Copilot also serves the cheaper GPT-4o mini via chat/completions; keep it + // alongside gpt-4o so apps that hard-code `gpt-4o-mini` resolve to the Copilot + // (`gh`) provider rather than only the github-models (`ghm`) marketplace entry. + { id: "gpt-4o-mini", name: "GPT-4o mini", contextLength: 128000 }, { id: "gpt-5-mini", name: "GPT-5 Mini", targetFormat: "openai-responses" }, { id: "gpt-5.3-codex", name: "GPT-5.3 Codex", targetFormat: "openai-responses" }, { id: "gpt-5.4-mini", name: "GPT-5.4 Mini", targetFormat: "openai-responses" }, diff --git a/tests/unit/github-copilot-gpt-4o-mini.test.ts b/tests/unit/github-copilot-gpt-4o-mini.test.ts new file mode 100644 index 0000000000..0f6d0a766d --- /dev/null +++ b/tests/unit/github-copilot-gpt-4o-mini.test.ts @@ -0,0 +1,45 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { getRegistryEntry } from "../../open-sse/config/providerRegistry.ts"; + +// Regression guard: the GitHub Copilot (`gh`) provider must expose `gpt-4o-mini` +// alongside `gpt-4o`. Copilot serves the cheaper mini variant via +// chat/completions, so apps that hard-code `gpt-4o-mini` should resolve to the +// Copilot provider — not only to the separate github-models (`ghm`) marketplace +// entry, which lists it under the `openai/` prefix (`openai/gpt-4o-mini`). +// +// Ported from upstream decolua/9router (add GPT-4o mini to GitHub Copilot). + +test("github (Copilot) provider exposes gpt-4o-mini next to gpt-4o", () => { + const entry = getRegistryEntry("github"); + assert.ok(entry, "github registry entry should exist"); + assert.ok(entry.models, "github registry entry should have a models array"); + + const ids = entry.models!.map((m) => m.id); + assert.ok(ids.includes("gpt-4o"), "gpt-4o should remain registered"); + assert.ok( + ids.includes("gpt-4o-mini"), + "gpt-4o-mini should be registered on the Copilot (gh) provider" + ); + + const mini = entry.models!.find((m) => m.id === "gpt-4o-mini"); + assert.equal(mini?.name, "GPT-4o mini"); + assert.equal(mini?.contextLength, 128000); +}); + +test("Copilot gpt-4o-mini is distinct from the github-models openai/gpt-4o-mini", () => { + const copilot = getRegistryEntry("github"); + const marketplace = getRegistryEntry("github-models"); + + const copilotIds = (copilot?.models ?? []).map((m) => m.id); + const marketplaceIds = (marketplace?.models ?? []).map((m) => m.id); + + // The two providers reference the same upstream model under different ids: + // Copilot uses the bare `gpt-4o-mini`; the marketplace uses `openai/gpt-4o-mini`. + assert.ok(copilotIds.includes("gpt-4o-mini")); + assert.ok(marketplaceIds.includes("openai/gpt-4o-mini")); + assert.ok( + !copilotIds.includes("openai/gpt-4o-mini"), + "Copilot should not carry the marketplace-prefixed id" + ); +});