diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 00fefb699..44d4e5284 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixed +- Fixed Vercel AI Gateway replaying unsigned thinking as assistant text ([#9676](https://github.com/earendil-works/pi/issues/9676)). - Fixed Google Generative AI and Vertex AI using unsupported thinking levels when reasoning is omitted or when model capabilities differ within a Gemini family ([#9455](https://github.com/earendil-works/pi/issues/9455)). - Fixed Anthropic-compatible relays breaking signed thinking replay when they report a different response model, while preserving fallback pricing ([#9188](https://github.com/earendil-works/pi/issues/9188)). - Fixed Amazon Bedrock one-hour cache writes being priced at the five-minute rate ([#9457](https://github.com/earendil-works/pi/issues/9457)). diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index da85a69b8..b1dfcf10f 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -1306,6 +1306,7 @@ async function fetchAiGatewayModels(): Promise[]> { provider: "vercel-ai-gateway", reasoning: tags.includes("reasoning"), input, + compat: { allowEmptySignature: true }, cost: { input: inputCost, output: outputCost, diff --git a/packages/ai/test/anthropic-empty-thinking-signature-compat.test.ts b/packages/ai/test/anthropic-empty-thinking-signature-compat.test.ts index 8f393ac57..4811e895d 100644 --- a/packages/ai/test/anthropic-empty-thinking-signature-compat.test.ts +++ b/packages/ai/test/anthropic-empty-thinking-signature-compat.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { getModel, streamSimple } from "../src/compat.ts"; +import { getModel, getModels, streamSimple } from "../src/compat.ts"; import type { AssistantMessage, Context, Model } from "../src/types.ts"; interface AnthropicPayload { @@ -97,6 +97,13 @@ describe("Anthropic empty thinking signature compat", () => { expect(assistant?.content).toEqual([{ type: "thinking", thinking: "internal reasoning", signature: "" }]); }); + // Regression for #9676: Vercel AI Gateway emits unsigned thinking for translated models. + it("allows empty thinking signatures for every Vercel AI Gateway model", () => { + const models = getModels("vercel-ai-gateway"); + expect(models.length).toBeGreaterThan(0); + expect(models.every((model) => model.compat?.allowEmptySignature === true)).toBe(true); + }); + // Regression for #9323: Fireworks emits unsigned thinking that must survive replay. it.each([ "accounts/fireworks/models/deepseek-v4-flash-0731",