From 2ed20e7ffefc673c177b901e0f74559e6efddcea Mon Sep 17 00:00:00 2001 From: "ashlee@vellum.ai" Date: Thu, 4 Jun 2026 17:43:51 +0000 Subject: [PATCH 1/3] refactor(web): dissolve reconcileFromDaemonConfig bridge utility (LUM-2239) The function extracted service mode/provider fields from the daemon config into a flat DaemonConfigReconciliation interface. Now that DaemonConfig is hand-typed and consumers have direct access to the config via useDaemonConfigQuery(), the indirection adds no value. Inline direct field access in both consumers (web-search-card, image-generation-card), delete the function and the DaemonConfigReconciliation type. Closes LUM-2239 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- apps/web/src/domains/settings/ai/ai-types.ts | 8 ------- apps/web/src/domains/settings/ai/ai-utils.ts | 24 ------------------- .../settings/ai/image-generation-card.tsx | 5 ++-- .../domains/settings/ai/web-search-card.tsx | 8 +++---- 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/apps/web/src/domains/settings/ai/ai-types.ts b/apps/web/src/domains/settings/ai/ai-types.ts index 0b34484e38c..495ad106971 100644 --- a/apps/web/src/domains/settings/ai/ai-types.ts +++ b/apps/web/src/domains/settings/ai/ai-types.ts @@ -99,14 +99,6 @@ export type DaemonConfigPatch = { }; }; -export interface DaemonConfigReconciliation { - inferenceProvider?: string; - selectedModel?: string; - webSearchMode?: ServiceMode; - webSearchProvider?: string; - imageGenMode?: ServiceMode; -} - export interface InferenceTokenBudgetState { maxOutputTokens: number; maxOutputTouched: boolean; diff --git a/apps/web/src/domains/settings/ai/ai-utils.ts b/apps/web/src/domains/settings/ai/ai-utils.ts index c7657e68b01..681a06984a2 100644 --- a/apps/web/src/domains/settings/ai/ai-utils.ts +++ b/apps/web/src/domains/settings/ai/ai-utils.ts @@ -7,11 +7,9 @@ import type { CallSiteOverrideDraft, DaemonConfig, DaemonConfigPatch, - DaemonConfigReconciliation, InferenceTokenBudgetState, ProfileEntry, ProfileWithName, - ServiceMode, } from "@/domains/settings/ai/ai-types"; import { TOKEN_SLIDER_MIN_TOKENS } from "@/domains/settings/ai/ai-types"; @@ -47,28 +45,6 @@ export function assertProvisionSuccess(result: unknown): void { } } -export function reconcileFromDaemonConfig(config: DaemonConfig): DaemonConfigReconciliation { - const services = config.services ?? {}; - const llm = config.llm ?? {}; - const result: DaemonConfigReconciliation = {}; - - const provider = llm.default?.provider; - if (provider) result.inferenceProvider = provider; - - const model = llm.default?.model; - if (model) result.selectedModel = model; - - const wsMode = services["web-search"]?.mode; - if (wsMode === "managed" || wsMode === "your-own") result.webSearchMode = wsMode as ServiceMode; - const wsProvider = services["web-search"]?.provider; - if (wsProvider) result.webSearchProvider = wsProvider; - - const igMode = services["image-generation"]?.mode; - if (igMode === "managed" || igMode === "your-own") result.imageGenMode = igMode as ServiceMode; - - return result; -} - export function clampTokenBudget( value: number, max: number, diff --git a/apps/web/src/domains/settings/ai/image-generation-card.tsx b/apps/web/src/domains/settings/ai/image-generation-card.tsx index 346a769b0cb..e640e509705 100644 --- a/apps/web/src/domains/settings/ai/image-generation-card.tsx +++ b/apps/web/src/domains/settings/ai/image-generation-card.tsx @@ -20,7 +20,7 @@ import { LS_IMAGE_GEN_MODE, LS_IMAGE_GEN_MODEL, } from "@/domains/settings/ai/ai-types"; -import { reconcileFromDaemonConfig } from "@/domains/settings/ai/ai-utils"; + import { ServiceCard, SaveButton, ResetButton } from "@/domains/settings/ai/ai-shared-ui"; import { useAssistantId, useDaemonConfigQuery, useDaemonConfigMutation, useProvisionProviderKey } from "@/domains/settings/ai/use-daemon-config"; import { useDraftOverride } from "@/domains/settings/ai/use-draft-override"; @@ -36,8 +36,7 @@ export function ImageGenerationCard() { // Updates automatically when the cache refreshes. const serverImageGenMode = useMemo(() => { if (!daemonConfig) return getLocalSetting(LS_IMAGE_GEN_MODE, "your-own") as ServiceMode; - const reconciled = reconcileFromDaemonConfig(daemonConfig); - return reconciled.imageGenMode ?? (getLocalSetting(LS_IMAGE_GEN_MODE, "your-own") as ServiceMode); + return (daemonConfig.services?.["image-generation"]?.mode ?? getLocalSetting(LS_IMAGE_GEN_MODE, "your-own")) as ServiceMode; }, [daemonConfig]); const [imageGenMode, setDraftImageGenMode] = useDraftOverride(serverImageGenMode); diff --git a/apps/web/src/domains/settings/ai/web-search-card.tsx b/apps/web/src/domains/settings/ai/web-search-card.tsx index 438da4acc1c..26995a150e7 100644 --- a/apps/web/src/domains/settings/ai/web-search-card.tsx +++ b/apps/web/src/domains/settings/ai/web-search-card.tsx @@ -21,7 +21,7 @@ import { secretPlaceholder } from "@/domains/settings/ai/secret-placeholder"; import type { ServiceMode } from "@/domains/settings/ai/ai-types"; import { LS_WEB_SEARCH_MODE, LS_WEB_SEARCH_PROVIDER } from "@/domains/settings/ai/ai-types"; -import { getWebSearchProviderKeyStorage, reconcileFromDaemonConfig } from "@/domains/settings/ai/ai-utils"; +import { getWebSearchProviderKeyStorage } from "@/domains/settings/ai/ai-utils"; import { ServiceCard, SaveButton, ResetButton } from "@/domains/settings/ai/ai-shared-ui"; import { useDaemonConfigQuery, useDaemonConfigMutation, useProvisionProviderKey } from "@/domains/settings/ai/use-daemon-config"; import { useDraftOverride } from "@/domains/settings/ai/use-draft-override"; @@ -46,10 +46,10 @@ export function WebSearchCard() { serverWebSearchProvider: getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), }; } - const reconciled = reconcileFromDaemonConfig(daemonConfig); + const wsService = daemonConfig.services?.["web-search"]; return { - serverWebSearchMode: (reconciled.webSearchMode ?? getLocalSetting(LS_WEB_SEARCH_MODE, "your-own")) as ServiceMode, - serverWebSearchProvider: reconciled.webSearchProvider ?? getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), + serverWebSearchMode: (wsService?.mode ?? getLocalSetting(LS_WEB_SEARCH_MODE, "your-own")) as ServiceMode, + serverWebSearchProvider: wsService?.provider ?? getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), }; }, [daemonConfig]); From b5d1110b25af327e6cf1675d32fd46831b4d098d Mon Sep 17 00:00:00 2001 From: "ashlee@vellum.ai" Date: Thu, 4 Jun 2026 17:47:38 +0000 Subject: [PATCH 2/3] fix(web): preserve ServiceMode validation guard during config access The dissolved reconcileFromDaemonConfig() only assigned mode fields when they matched a known ServiceMode value ("managed" | "your-own"). The initial inline replacement used ?? which falls through on unexpected strings. Restore the explicit guard so unknown/future mode values fall back to localStorage defaults. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- apps/web/src/domains/settings/ai/image-generation-card.tsx | 3 ++- apps/web/src/domains/settings/ai/web-search-card.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/domains/settings/ai/image-generation-card.tsx b/apps/web/src/domains/settings/ai/image-generation-card.tsx index e640e509705..3363f92844c 100644 --- a/apps/web/src/domains/settings/ai/image-generation-card.tsx +++ b/apps/web/src/domains/settings/ai/image-generation-card.tsx @@ -36,7 +36,8 @@ export function ImageGenerationCard() { // Updates automatically when the cache refreshes. const serverImageGenMode = useMemo(() => { if (!daemonConfig) return getLocalSetting(LS_IMAGE_GEN_MODE, "your-own") as ServiceMode; - return (daemonConfig.services?.["image-generation"]?.mode ?? getLocalSetting(LS_IMAGE_GEN_MODE, "your-own")) as ServiceMode; + const mode = daemonConfig.services?.["image-generation"]?.mode; + return (mode === "managed" || mode === "your-own" ? mode : getLocalSetting(LS_IMAGE_GEN_MODE, "your-own")) as ServiceMode; }, [daemonConfig]); const [imageGenMode, setDraftImageGenMode] = useDraftOverride(serverImageGenMode); diff --git a/apps/web/src/domains/settings/ai/web-search-card.tsx b/apps/web/src/domains/settings/ai/web-search-card.tsx index 26995a150e7..908472a193a 100644 --- a/apps/web/src/domains/settings/ai/web-search-card.tsx +++ b/apps/web/src/domains/settings/ai/web-search-card.tsx @@ -47,8 +47,9 @@ export function WebSearchCard() { }; } const wsService = daemonConfig.services?.["web-search"]; + const mode = wsService?.mode; return { - serverWebSearchMode: (wsService?.mode ?? getLocalSetting(LS_WEB_SEARCH_MODE, "your-own")) as ServiceMode, + serverWebSearchMode: (mode === "managed" || mode === "your-own" ? mode : getLocalSetting(LS_WEB_SEARCH_MODE, "your-own")) as ServiceMode, serverWebSearchProvider: wsService?.provider ?? getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), }; }, [daemonConfig]); From 85a4ec55c04982824f813b5dcce7bcb45d59e0b7 Mon Sep 17 00:00:00 2001 From: "ashlee@vellum.ai" Date: Thu, 4 Jun 2026 17:48:59 +0000 Subject: [PATCH 3/3] fix(web): use truthy fallback for provider to match original semantics The old reconcileFromDaemonConfig used `if (wsProvider)` which treats empty string as falsy. Use || instead of ?? to preserve this behavior. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- apps/web/src/domains/settings/ai/web-search-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/domains/settings/ai/web-search-card.tsx b/apps/web/src/domains/settings/ai/web-search-card.tsx index 908472a193a..21c58c7733c 100644 --- a/apps/web/src/domains/settings/ai/web-search-card.tsx +++ b/apps/web/src/domains/settings/ai/web-search-card.tsx @@ -50,7 +50,7 @@ export function WebSearchCard() { const mode = wsService?.mode; return { serverWebSearchMode: (mode === "managed" || mode === "your-own" ? mode : getLocalSetting(LS_WEB_SEARCH_MODE, "your-own")) as ServiceMode, - serverWebSearchProvider: wsService?.provider ?? getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), + serverWebSearchProvider: wsService?.provider || getLocalSetting(LS_WEB_SEARCH_PROVIDER, "inference-provider-native"), }; }, [daemonConfig]);