From f2e452bbebc7d99d1ae9ba74b32334b85af7902d Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Wed, 24 Jun 2026 04:26:40 +0900 Subject: feat: persistent per-conversation model selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A chat's selected provider + model is now persisted per conversation (like cwd and reasoningEffort). Opening a conversation in a new browser recalls the originally selected model instead of defaulting. - transport-contract 0.19.0→0.20.0: ModelResponse + SetModelRequest types for GET/PUT /conversations/:id/model. - conversation-store: getModel/setModel (model: key, mirrors getReasoningEffort/setReasoningEffort); forkHistory copies model; empty string clears. - session-orchestrator: resolve model from persisted store when no per-turn override; persist the resolved model so it sticks; warm path parity. - transport-http: GET/PUT /conversations/:id/model endpoints with validation. 1433 vitest pass; tsc + biome clean. --- packages/session-orchestrator/src/queue.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'packages/session-orchestrator/src/queue.test.ts') diff --git a/packages/session-orchestrator/src/queue.test.ts b/packages/session-orchestrator/src/queue.test.ts index 71b1fb4..225d1af 100644 --- a/packages/session-orchestrator/src/queue.test.ts +++ b/packages/session-orchestrator/src/queue.test.ts @@ -25,16 +25,19 @@ function createInMemoryStore(): ConversationStore & { readonly metricsData: Map; readonly cwdData: Map; readonly effortData: Map; + readonly modelData: Map; } { const data = new Map(); const metricsData = new Map(); const cwdData = new Map(); const effortData = new Map(); + const modelData = new Map(); return { data, metricsData, cwdData, effortData, + modelData, async append(conversationId, messages) { const existing = data.get(conversationId) ?? []; data.set(conversationId, [...existing, ...messages]); @@ -75,6 +78,16 @@ function createInMemoryStore(): ConversationStore & { async setReasoningEffort(conversationId, effort) { effortData.set(conversationId, effort); }, + async getModel(conversationId) { + return modelData.get(conversationId) ?? null; + }, + async setModel(conversationId, model) { + if (model === "") { + modelData.delete(conversationId); + } else { + modelData.set(conversationId, model); + } + }, async listConversations() { return []; }, -- cgit v1.2.3