fix(coding-agent): expose finish reason compatibility override (#8487)

Closes #8460
This commit is contained in:
Petr Houška 2026-08-23 23:34:30 +02:00 • committed by GitHub
parent 81152d88bb
commit a470b121bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 23 additions and 0 deletions

View file

@ -18,6 +18,7 @@
### Fixed
- Fixed `models.json` typings omitting the documented OpenAI-compatible `compat.supportsFinishReason` provider and model override ([#8460](https://github.com/earendil-works/pi/issues/8460)).
- Fixed writes to `auth.json` and `models-store.json` overriding administrator-managed file permissions and ACLs ([#7779](https://github.com/earendil-works/pi/issues/7779)).
- Fixed UTF-8 BOM markers preventing frontmatter and user configuration files from loading ([#8337](https://github.com/earendil-works/pi/issues/8337)).
- Fixed invalid settings files being easy to miss during interactive startup by rendering warnings with the file path inside the TUI ([#7829](https://github.com/earendil-works/pi/issues/7829)).

View file

@ -75,6 +75,7 @@ const OpenAICompletionsCompatSchema = Type.Object({
supportsDeveloperRole: Type.Optional(Type.Boolean()),
supportsReasoningEffort: Type.Optional(Type.Boolean()),
supportsUsageInStreaming: Type.Optional(Type.Boolean()),
supportsFinishReason: Type.Optional(Type.Boolean()),
maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
requiresToolResultName: Type.Optional(Type.Boolean()),
requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),

View file

@ -11,6 +11,7 @@ import type {
import { getApiProvider, getSupportedThinkingLevels } from "@earendil-works/pi-ai/compat";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { AuthStorage } from "../src/core/auth-storage.ts";
import type { ModelsJsonProvider } from "../src/core/model-config.ts";
import { clearApiKeyCache, type ModelRegistry, type ProviderConfigInput } from "../src/core/model-registry.ts";
import { createModelRegistry } from "./model-runtime-test-utils.ts";
@ -767,6 +768,26 @@ describe("ModelRegistry", () => {
expect(compat?.openRouterRouting).toEqual({ only: ["amazon-bedrock"] });
});
test("supportsFinishReason can be configured at provider and model levels", async () => {
const provider: ModelsJsonProvider = {
compat: { supportsFinishReason: true },
modelOverrides: {
"anthropic/claude-sonnet-4": {
compat: { supportsFinishReason: false },
},
},
};
writeRawModelsJson({ openrouter: provider });
const registry = await createModelRegistry(authStorage, modelsJsonPath);
const models = getModelsForProvider(registry, "openrouter");
const sonnet = models.find((model) => model.id === "anthropic/claude-sonnet-4");
const opus = models.find((model) => model.id === "anthropic/claude-opus-4");
expect((sonnet?.compat as OpenAICompletionsCompat | undefined)?.supportsFinishReason).toBe(false);
expect((opus?.compat as OpenAICompletionsCompat | undefined)?.supportsFinishReason).toBe(true);
});
test("model override deep merges compat settings", async () => {
writeRawModelsJson({
openrouter: {