diff --git a/README.md b/README.md index fb4e50e..19972da 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ Use [uniGPT](https://unigpt.uni-graz.at), the University of Graz's AI assistant, inside the [pi](https://pi.dev) coding agent. -Once set up, every model your uniGPT account offers appears in pi's model -picker, including GPT-4o, GPT-4.1, and the GPT-5 and GPT-6 families. Tools, -streaming responses, and image input all work. +Models exposed by your uniGPT API key appear in pi's model picker. +Streaming and tool calls are supported; recognized vision models also +support image input. ## What you need diff --git a/src/provider.ts b/src/provider.ts index 7ff187e..79bea34 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -53,8 +53,11 @@ function isRecord(value: unknown): value is Record { } function isValidId(id: unknown): id is string { - // IDs become an HTTP header value, so reject padding and control characters. - return typeof id === "string" && id.length > 0 && id.trim() === id && !/[\u0000-\u001f\u007f]/.test(id); + // Fetch header values must fit Latin-1; also reject padding and control characters. + return typeof id === "string" + && id.length > 0 + && id.trim() === id + && !/[\u0000-\u001f\u007f\u0100-\uffff]/.test(id); } export interface ParsedCatalog { diff --git a/test/provider.test.ts b/test/provider.test.ts index 5225fba..8d53738 100644 --- a/test/provider.test.ts +++ b/test/provider.test.ts @@ -58,6 +58,20 @@ test("skips unusable entries but rejects malformed or entirely unusable catalogs } }); +test("catalog IDs must fit Fetch's Latin-1 header values", () => { + const valid = ["gpt-4o", "model-\u00ff"]; + const invalid = ["model-\u0100", "model-\u{1f600}", "model-\ud800"]; + const parsed = parseCatalog({ data: [...valid, ...invalid].map((id) => ({ id })) }); + assert.deepEqual(parsed, { ids: valid, skipped: invalid.length }); + for (const id of parsed.ids) { + const headers = new Headers(makeModel(id, BASE_URL).headers); + assert.equal(headers.get("deployment-id"), id); + } + for (const id of invalid) { + assert.throws(() => parseCatalog({ data: [{ id }] }), /without any valid model IDs/); + } +}); + const known: Record = { "model-a": { name: "Model A", input: ["text", "image"], contextWindow: 272_000, maxTokens: 128_000 }, };