refactor(thinking): move provider thinking fallback out of core

This commit is contained in:
Peter Steinberger 2026-04-04 07:00:16 +01:00
parent b59ce0903c
commit fca80d2ee2
No known key found for this signature in database
3 changed files with 16 additions and 73 deletions

View File

@ -1,5 +1,3 @@
import { matchesExactOrPrefix } from "../plugins/provider-model-helpers.js";
export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive";
export type VerboseLevel = "off" | "on" | "full";
export type NoticeLevel = "off" | "on" | "full";
@ -14,59 +12,19 @@ export type ThinkingCatalogEntry = {
};
const BASE_THINKING_LEVELS: ThinkLevel[] = ["off", "minimal", "low", "medium", "high", "adaptive"];
const ANTHROPIC_CLAUDE_46_MODEL_RE = /^claude-(?:opus|sonnet)-4(?:\.|-)6(?:$|[-.])/i;
const AMAZON_BEDROCK_CLAUDE_46_MODEL_RE = /claude-(?:opus|sonnet)-4(?:\.|-)6(?:$|[-.])/i;
const OPENAI_XHIGH_MODEL_IDS = [
"gpt-5.4",
"gpt-5.4-pro",
"gpt-5.4-mini",
"gpt-5.4-nano",
"gpt-5.2",
] as const;
const OPENAI_CODEX_XHIGH_MODEL_IDS = [
"gpt-5.4",
"gpt-5.3-codex-spark",
"gpt-5.2-codex",
"gpt-5.1-codex",
] as const;
const GITHUB_COPILOT_XHIGH_MODEL_IDS = ["gpt-5.2", "gpt-5.2-codex"] as const;
export function normalizeProviderId(provider?: string | null): string {
if (!provider) {
return "";
}
const normalized = provider.trim().toLowerCase();
if (normalized === "z.ai" || normalized === "z-ai") {
return "zai";
}
if (normalized === "bedrock" || normalized === "aws-bedrock") {
return "amazon-bedrock";
}
return normalized;
}
const NO_THINKING_LEVELS: ThinkLevel[] = [...BASE_THINKING_LEVELS];
export function isBinaryThinkingProvider(provider?: string | null): boolean {
return normalizeProviderId(provider) === "zai";
void provider;
return false;
}
export function supportsBuiltInXHighThinking(
provider?: string | null,
model?: string | null,
): boolean {
const providerId = normalizeProviderId(provider);
const modelId = model?.trim().toLowerCase();
if (!providerId || !modelId) {
return false;
}
if (providerId === "openai") {
return matchesExactOrPrefix(modelId, OPENAI_XHIGH_MODEL_IDS);
}
if (providerId === "openai-codex") {
return matchesExactOrPrefix(modelId, OPENAI_CODEX_XHIGH_MODEL_IDS);
}
if (providerId === "github-copilot") {
return GITHUB_COPILOT_XHIGH_MODEL_IDS.includes(modelId as never);
}
void provider;
void model;
return false;
}
@ -113,7 +71,7 @@ export function listThinkingLevels(
_provider?: string | null,
_model?: string | null,
): ThinkLevel[] {
return [...BASE_THINKING_LEVELS];
return [...NO_THINKING_LEVELS];
}
export function listThinkingLevelLabels(provider?: string | null, model?: string | null): string[] {
@ -140,14 +98,6 @@ export function resolveThinkingDefaultForModel(params: {
model: string;
catalog?: ThinkingCatalogEntry[];
}): ThinkLevel {
const normalizedProvider = normalizeProviderId(params.provider);
const modelId = params.model.trim();
if (normalizedProvider === "anthropic" && ANTHROPIC_CLAUDE_46_MODEL_RE.test(modelId)) {
return "adaptive";
}
if (normalizedProvider === "amazon-bedrock" && AMAZON_BEDROCK_CLAUDE_46_MODEL_RE.test(modelId)) {
return "adaptive";
}
const candidate = params.catalog?.find(
(entry) => entry.provider === params.provider && entry.id === params.model,
);

View File

@ -127,8 +127,9 @@ describe("listThinkingLevelLabels", () => {
expect(listThinkingLevelLabels("zai", "glm-4.7")).toEqual(["off", "on"]);
});
it("keeps built-in binary thinking fallback without provider runtime", () => {
expect(listThinkingLevelLabels("zai", "glm-4.7")).toEqual(["off", "on"]);
it("does not assume binary thinking without provider runtime", () => {
expect(listThinkingLevelLabels("zai", "glm-4.7")).toContain("low");
expect(listThinkingLevelLabels("zai", "glm-4.7")).not.toContain("on");
});
it("returns full levels for non-ZAI", () => {
@ -170,13 +171,13 @@ describe("resolveThinkingDefaultForModel", () => {
).toBe("adaptive");
});
it("keeps built-in adaptive defaults without provider runtime", () => {
it("does not assume adaptive defaults without provider runtime", () => {
expect(
resolveThinkingDefaultForModel({ provider: "anthropic", model: "claude-opus-4-6" }),
).toBe("adaptive");
).toBe("off");
expect(
resolveThinkingDefaultForModel({ provider: "aws-bedrock", model: "claude-sonnet-4-6" }),
).toBe("adaptive");
).toBe("off");
});
it("defaults reasoning-capable catalog models to low", () => {

View File

@ -1,11 +1,9 @@
import { normalizeProviderId } from "../agents/provider-id.js";
import {
formatThinkingLevels as formatThinkingLevelsFallback,
isBinaryThinkingProvider as isBinaryThinkingProviderFallback,
listThinkingLevelLabels as listThinkingLevelLabelsFallback,
listThinkingLevels as listThinkingLevelsFallback,
normalizeProviderId,
resolveThinkingDefaultForModel as resolveThinkingDefaultForModelFallback,
supportsBuiltInXHighThinking,
} from "./thinking.shared.js";
import type { ThinkLevel, ThinkingCatalogEntry } from "./thinking.shared.js";
export {
@ -37,10 +35,7 @@ import {
} from "../plugins/provider-thinking.js";
export function isBinaryThinkingProvider(provider?: string | null, model?: string | null): boolean {
if (isBinaryThinkingProviderFallback(provider)) {
return true;
}
const normalizedProvider = normalizeProviderId(provider);
const normalizedProvider = provider?.trim() ? normalizeProviderId(provider) : "";
if (!normalizedProvider) {
return false;
}
@ -55,7 +50,7 @@ export function isBinaryThinkingProvider(provider?: string | null, model?: strin
if (typeof pluginDecision === "boolean") {
return pluginDecision;
}
return isBinaryThinkingProviderFallback(provider);
return false;
}
export function supportsXHighThinking(provider?: string | null, model?: string | null): boolean {
@ -63,10 +58,7 @@ export function supportsXHighThinking(provider?: string | null, model?: string |
if (!modelKey) {
return false;
}
if (supportsBuiltInXHighThinking(provider, modelKey)) {
return true;
}
const providerKey = normalizeProviderId(provider);
const providerKey = provider?.trim() ? normalizeProviderId(provider) : "";
if (providerKey) {
const pluginDecision = resolveProviderXHighThinking({
provider: providerKey,