Preserve Claude model and thinking preferences (#2912)

* fix(agents): preserve Claude thinking selections

Model switches now resolve thinking against the target model's saved preference instead of resetting to the catalog default. Claude owns its configured-model defaults and legacy Fable alias handling, while persisted permission modes remain unchanged.

* chore(claude): tag Fable compatibility shim

* fix(app): resolve persisted model aliases

* fix(models): preserve aliases for older clients

* fix(models): hide compatibility aliases from listings

* fix(settings): hide compatibility model aliases

* test(claude): cover legacy catalog entry

* test(app): expect mock thinking controls in schedules

* fix(app): preserve queued thinking preferences

* fix(app): reconcile schedule provider snapshots

* fix(app): preserve schedule model selections

* fix(claude): preserve exact configured model ids

* fix(app): preserve committed thinking preferences

* fix(app): preserve aliased schedule thinking
This commit is contained in:
Mohamed Boudra
2026-08-06 11:33:18 +02:00
committed by GitHub
parent 73ba37a07a
commit f2054cc701
43 changed files with 1369 additions and 220 deletions
+2
View File
@@ -74,6 +74,8 @@ export type ProviderStatus = "ready" | "loading" | "error" | "unavailable";
export interface AgentModelDefinition {
provider: AgentProvider;
id: string;
aliases?: string[];
isSelectable?: boolean;
label: string;
description?: string;
isDefault?: boolean;
+2
View File
@@ -259,6 +259,8 @@ export const AgentFeatureSchema = z.discriminatedUnion("type", [
const AgentModelDefinitionSchema = z.object({
provider: AgentProviderSchema,
id: z.string(),
aliases: z.array(z.string()).optional(),
isSelectable: z.boolean().optional(),
label: z.string(),
description: z.string().optional(),
isDefault: z.boolean().optional(),
@@ -175,6 +175,13 @@ const MOCK_LOAD_TEST_MODES: AgentProviderModeDefinition[] = [
icon: "ShieldOff",
colorTier: "dangerous",
},
{
id: "approval-test",
label: "Approval Test",
description: "Alternate development-only permission mode for preference tests",
icon: "ShieldCheck",
colorTier: "safe",
},
];
const MOCK_SLOW_MODES: AgentProviderModeDefinition[] = [
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import type { ProviderSnapshotEntry } from "./agent-types.js";
import { CompactProviderSnapshotSchema } from "./messages.js";
import { compactProviderSnapshot, expandProviderSnapshot } from "./provider-snapshot-codec.js";
const sharedThinking = [
@@ -21,6 +22,8 @@ function providerEntry(): ProviderSnapshotEntry {
{
provider: "pi",
id: "openai/gpt-a",
aliases: ["openai/gpt-a-legacy"],
isSelectable: false,
label: "GPT A",
description: "openai/gpt-a",
metadata: { provider: "openai", modelId: "gpt-a" },
@@ -48,6 +51,9 @@ describe("provider snapshot codec", () => {
expect(compact.thinkingSets).toHaveLength(1);
expect(compact.entries[0]?.models?.map((model) => model.thinkingSet)).toEqual([0, 0]);
expect(CompactProviderSnapshotSchema.parse(compact)).toEqual(compact);
expect(compact.entries[0]?.models?.[0]?.aliases).toEqual(["openai/gpt-a-legacy"]);
expect(compact.entries[0]?.models?.[0]?.isSelectable).toBe(false);
expect(expanded).toEqual(original);
expect(expanded[0]?.models?.[0]?.thinkingOptions).toBe(
expanded[0]?.models?.[1]?.thinkingOptions,