diff --git a/packages/coding-agent/test/model-catalog-protocol.test.ts b/packages/coding-agent/test/model-catalog-protocol.test.ts index 9222af565..197cab282 100644 --- a/packages/coding-agent/test/model-catalog-protocol.test.ts +++ b/packages/coding-agent/test/model-catalog-protocol.test.ts @@ -61,8 +61,6 @@ function startCatalogServer(requests: string[]): Promise { const catalogRequest = parseModelCatalogRequest(url, request.headers["user-agent"]); if (!provider) { response.writeHead(404).end(); - } else if (catalogRequest.kind === "redirect") { - response.writeHead(307, { location: catalogRequest.location, "cache-control": "no-store" }).end(); } else if (catalogRequest.kind === "invalid") { response.writeHead(400).end(catalogRequest.error); } else { @@ -120,7 +118,7 @@ describe("model catalog protocol with the current client", () => { expect([...refresh.errors]).toEqual([]); const catalogUrl = "/api/models/providers/openrouter?types=chat%2Cimage%2Cclassifier"; - expect(requests).toEqual([catalogUrl, `${catalogUrl}&pi-version=${VERSION}`]); + expect(requests).toEqual([catalogUrl]); const expectedModel = selectModelCatalog(index, VERSION)?.revision === legacyRevision ? legacyModel : mixedApiModel; diff --git a/scripts/model-catalog-protocol.test.ts b/scripts/model-catalog-protocol.test.ts index cdfcc0d50..0a7e3af77 100644 --- a/scripts/model-catalog-protocol.test.ts +++ b/scripts/model-catalog-protocol.test.ts @@ -55,25 +55,23 @@ test("selects the newest catalog a Pi version supports", () => { assert.equal(selectModelCatalog(index, undefined)?.revision, mixedApiRevision); }); -test("redirects Pi user agents to an explicit catalog version", () => { +test("serves Pi user agents the catalog for their version", () => { // Regression test for #9099: released clients identify themselves only by User-Agent. assert.deepEqual( parseModelCatalogRequest( "https://pi.dev/api/models/providers/openrouter?types=chat%2Cimage", "pi/0.84.4 (linux; node/v22.0.0; x64)", ), - { - kind: "redirect", - location: "https://pi.dev/api/models/providers/openrouter?types=chat%2Cimage&pi-version=0.84.4", - }, + { kind: "catalog", piVersion: "0.84.4", representation: "typed" }, ); assert.deepEqual(parseModelCatalogRequest("https://pi.dev/api/models", "pi/0.84.4"), { - kind: "redirect", - location: "https://pi.dev/api/models?pi-version=0.84.4", + kind: "catalog", + piVersion: "0.84.4", + representation: "legacy", }); }); -test("serves explicit and unversioned catalog requests without redirecting", () => { +test("serves explicit and unversioned catalog requests", () => { assert.deepEqual( parseModelCatalogRequest("https://pi.dev/api/models?pi-version=0.83.0", "pi/0.85.1 (linux; node/v22.0.0; x64)"), { kind: "catalog", piVersion: "0.83.0", representation: "legacy" }, diff --git a/scripts/model-catalog-protocol.ts b/scripts/model-catalog-protocol.ts index d151d36a5..173c62b19 100644 --- a/scripts/model-catalog-protocol.ts +++ b/scripts/model-catalog-protocol.ts @@ -53,7 +53,6 @@ export type ModelCatalogIndex = { export type ModelCatalogRequest = | { kind: "catalog"; piVersion: string | undefined; representation: ModelCatalogRepresentation } - | { kind: "redirect"; location: string } | { kind: "invalid"; error: string }; export function getModelCatalogArtifactKey(revision: string, artifact: ModelCatalogArtifact): string { @@ -97,10 +96,11 @@ export function parseModelCatalogRepresentation( /** * Decide how to answer a catalog request from its URL and User-Agent. * - * Released clients do not send `pi-version`. Responses are cached by URL, so - * instead of varying the response on the User-Agent, clients that identify - * as Pi are redirected to the equivalent URL with an explicit `pi-version`. - * Requests without a Pi User-Agent receive the default catalog. + * Released clients do not send `pi-version`, so clients that identify as Pi + * are served the catalog for the version in their User-Agent. The response + * therefore varies on the User-Agent, and the server must say so with `Vary`. + * An explicit `pi-version` takes precedence. Requests without a Pi User-Agent + * receive the default catalog. */ export function parseModelCatalogRequest(url: string | URL, userAgent: string | null | undefined): ModelCatalogRequest { const requestUrl = new URL(url); @@ -113,8 +113,7 @@ export function parseModelCatalogRequest(url: string | URL, userAgent: string | if (piVersion === null) { const userAgentVersion = PI_USER_AGENT_RE.exec(userAgent ?? "")?.[1]; if (userAgentVersion !== undefined && isValidModelCatalogPiVersion(userAgentVersion)) { - requestUrl.searchParams.set("pi-version", userAgentVersion); - return { kind: "redirect", location: requestUrl.toString() }; + return { kind: "catalog", piVersion: userAgentVersion, representation }; } return { kind: "catalog", piVersion: undefined, representation }; }