fix(github): route Copilot Codex models to /responses (port from 9router#102) (#4626)

Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port #102); release-green
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-23 22:15:12 -03:00
committed by GitHub
parent 9244d930ea
commit cc8e1bedf5
2 changed files with 31 additions and 1 deletions

View File

@@ -27,7 +27,10 @@ export class GithubExecutor extends BaseExecutor {
buildUrl(model: string, _stream: boolean, _urlIndex = 0) {
const targetFormat = getModelTargetFormat("gh", model);
if (targetFormat === "openai-responses") {
// 9router#102: Copilot Codex models advertise supported_endpoints: ["/responses"]
// and 400 on /chat/completions. Route any *-codex id to /responses even when it
// isn't in the curated registry, so newly-shipped Codex models work out of the box.
if (targetFormat === "openai-responses" || /codex/i.test(model)) {
return (
this.config.responsesBaseUrl ||
this.config.baseUrl?.replace(/\/chat\/completions\/?$/, "/responses") ||

View File

@@ -71,6 +71,33 @@ test("GithubExecutor.buildUrl keeps GitHub Claude Opus 4.6 on /chat/completions"
assert.equal(url, "https://api.githubcopilot.com/chat/completions");
});
test("GithubExecutor.buildUrl routes unlisted Codex models to /responses (9router#102)", () => {
// Copilot Codex models advertise supported_endpoints: ["/responses"]. When such
// a model isn't in the curated gh registry, getModelTargetFormat returns null and
// the request fell through to /chat/completions -> upstream 400 "model <id> is not
// accessible via the /chat/completions endpoint". Any *-codex id must route to
// /responses regardless of whether it's explicitly registered.
const executor = new GithubExecutor();
for (const model of [
"gpt-5-codex",
"gpt-5.1-codex",
"gpt-5.1-codex-mini",
"gpt-5.1-codex-max",
"gpt-5.2-codex",
]) {
assert.equal(
executor.buildUrl(model, true),
"https://api.githubcopilot.com/responses",
`${model} must route to /responses`
);
}
// Non-codex unlisted models keep the chat/completions default.
assert.equal(
executor.buildUrl("some-random-chat-model", true),
"https://api.githubcopilot.com/chat/completions"
);
});
test("GithubExecutor.transformRequest injects JSON response instructions for Claude and strips reasoning fields", () => {
const executor = new GithubExecutor();
const body = {