From 094e53db1c2974c20f61818315d6a60702fc2d4b Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Thu, 13 Aug 2026 08:11:30 +0200 Subject: [PATCH] ui: Stores architecture improvements (#26910) * refactor: Stores barrel imports + SSR gates * refactor: Drop agenticStore wrapper exports * refactor: Drop chatStore wrapper exports * refactor: Drop modelsStore wrapper exports * refactor: Drop serverStore wrapper exports * refactor: Drop unused mcpStore wrapper exports * refactor: Drop mcpResourceStore wrapper exports * refactor: Drop conversationsStore wrapper exports + move buildConversationTree to utils * refactor: Drop settingsStore wrapper exports * refactor: Drop unused toolsStore wrapper exports * refactor: Fix lint errors from store wrapper removal * fix: Missing change * refactor: Cleanup * refactor: Context Stats store --- .../ChatAttachmentsListItemMcpResource.svelte | 2 +- .../ChatAttachmentsPreview.svelte | 2 +- .../app/chat/ChatForm/ChatForm.svelte | 37 ++- .../ChatFormActionAddMcpServersSubmenu.svelte | 3 +- .../ChatFormActionAddSheet.svelte | 3 +- .../ChatFormActionAddToolsSubmenu.svelte | 3 +- .../ChatFormActionsAdd.svelte | 2 +- .../ChatFormActionModels.svelte | 39 ++- .../ChatFormActions/ChatFormActions.svelte | 17 +- .../ChatForm/ChatFormContentEditable.svelte | 2 +- .../ChatFormContextGauge.svelte | 14 +- .../ContextGaugePopup.svelte | 9 +- .../ChatForm/ChatFormMcpResourcesList.svelte | 10 +- .../ChatFormMentionPicker.svelte | 6 +- .../ChatFormPickerItemHeader.svelte | 2 +- .../ChatFormPickerMcpPrompts.svelte | 3 +- .../app/chat/ChatForm/ChatFormTextarea.svelte | 2 +- .../ChatForm/ChatFormWorkingDirectory.svelte | 2 +- .../ChatMessage/ChatMessage.svelte | 6 +- .../ChatMessageAssistant.svelte | 19 +- .../ChatMessageAssistantModel.svelte | 2 +- .../ChatMessageAssistantProcessingInfo.svelte | 2 +- .../ChatMessageAssistantStatistics.svelte | 20 +- .../ChatMessageMcpPromptContent.svelte | 2 +- .../ChatMessageSystem.svelte | 4 +- .../ChatMessageToolCallBlockEditFile.svelte | 2 +- ...essageToolCallBlockExecShellCommand.svelte | 5 +- ...tMessageToolCallBlockFileGlobSearch.svelte | 2 +- .../ChatMessageToolCallBlockGetInfo.svelte | 2 +- .../ChatMessageToolCallBlockGrepSearch.svelte | 2 +- ...atMessageToolCallBlockSearchResults.svelte | 2 +- .../ChatMessageToolCallBlockWriteFile.svelte | 2 +- .../ChatMessageToolCall/ToolCallBlock.svelte | 2 +- .../ChatMessageUser/ChatMessageUser.svelte | 7 +- .../ChatMessageUserBubble.svelte | 4 +- ...tMessageActionCardPermissionRequest.svelte | 2 +- .../ChatMessageActionIcons.svelte | 4 +- .../ChatMessageAgenticContent.svelte | 38 +-- .../ChatMessages/ChatMessageEditForm.svelte | 2 +- .../ChatMessageReasoningBlock.svelte | 4 +- .../app/chat/ChatMessages/ChatMessages.svelte | 47 ++-- .../app/chat/ChatScreen/ChatScreen.svelte | 51 ++-- .../app/chat/ChatScreen/ChatScreenForm.svelte | 2 +- .../chat/ChatScreen/ChatScreenGreeting.svelte | 2 +- .../ChatScreen/ChatScreenServerError.svelte | 14 +- .../ChatScreenStreamResumeStatus.svelte | 2 +- .../MarkdownContent/MarkdownContent.svelte | 4 +- .../plugins/rehype/file-badge.ts | 3 +- .../app/content/MentionBadge.svelte | 3 +- .../dialogs/DialogMcpResourcePreview.svelte | 2 +- .../dialogs/DialogMcpResourcesBrowser.svelte | 12 +- .../app/dialogs/DialogMcpServerAddNew.svelte | 3 +- .../app/dialogs/DialogModelInformation.svelte | 7 +- .../app/mcp/McpActiveServersAvatars.svelte | 3 +- .../app/mcp/McpResourcePreview.svelte | 2 +- .../app/mcp/McpResourceTemplateForm.svelte | 2 +- .../McpResourcesBrowser.svelte | 7 +- .../McpResourcesBrowserServerItem.svelte | 2 +- .../mcp/McpServerCard/McpServerCard.svelte | 2 +- .../components/app/mcp/McpServerForm.svelte | 2 +- .../components/app/models/ModelBadge.svelte | 3 +- .../lib/components/app/models/ModelId.svelte | 12 +- .../app/models/ModelsSelectorDropdown.svelte | 6 +- .../app/models/ModelsSelectorList.svelte | 2 +- .../app/models/ModelsSelectorOption.svelte | 4 +- .../app/models/ModelsSelectorSheet.svelte | 4 +- .../SidebarNavigation.svelte | 25 +- .../SidebarNavigationActions.svelte | 2 +- .../SidebarNavigationConversationItem.svelte | 5 +- .../SidebarNavigationConversationList.svelte | 2 +- .../SidebarNavigationSearchResults.svelte | 2 +- .../app/server/ServerErrorSplash.svelte | 7 +- .../components/app/server/ServerStatus.svelte | 11 +- .../settings/SettingsChat/SettingsChat.svelte | 13 +- .../SettingsChat/SettingsChatFields.svelte | 8 +- .../SettingsChatImportExportTab.svelte | 7 +- .../SettingsChat/SettingsChatToolsTab.svelte | 4 +- .../app/settings/SettingsFooter.svelte | 2 +- .../app/settings/SettingsMcpServers.svelte | 4 +- .../use-chat-screen-active-model.svelte.ts | 13 +- .../use-chat-screen-drag-and-drop.svelte.ts | 6 +- .../use-chat-screen-file-upload.svelte.ts | 4 +- .../src/lib/hooks/use-context-gauge.svelte.ts | 229 +++--------------- .../lib/hooks/use-draft-messages.svelte.ts | 2 +- .../lib/hooks/use-models-selector.svelte.ts | 22 +- .../lib/hooks/use-processing-state.svelte.ts | 6 +- tools/ui/src/lib/hooks/use-pwa.svelte.ts | 2 +- .../lib/hooks/use-reasoning-menu.svelte.ts | 29 +-- .../hooks/use-settings-navigation.svelte.ts | 2 +- .../src/lib/hooks/use-tools-panel.svelte.ts | 4 +- tools/ui/src/lib/services/sandbox.service.ts | 4 +- tools/ui/src/lib/stores/agentic.svelte.ts | 113 ++++----- tools/ui/src/lib/stores/chat.svelte.ts | 139 +++++------ .../ui/src/lib/stores/context-stats.svelte.ts | 212 ++++++++++++++++ .../ui/src/lib/stores/conversations.svelte.ts | 84 +------ tools/ui/src/lib/stores/index.ts | 78 ++++++ .../ui/src/lib/stores/mcp-resources.svelte.ts | 8 - tools/ui/src/lib/stores/mcp.svelte.ts | 35 +-- tools/ui/src/lib/stores/models.svelte.ts | 38 +-- tools/ui/src/lib/stores/permissions.svelte.ts | 4 + tools/ui/src/lib/stores/server.svelte.ts | 12 +- tools/ui/src/lib/stores/settings.svelte.ts | 5 +- tools/ui/src/lib/stores/tools.svelte.ts | 21 +- tools/ui/src/lib/types/agentic.d.ts | 14 +- tools/ui/src/lib/utils/api-headers.ts | 4 +- tools/ui/src/lib/utils/api-key-validation.ts | 4 +- tools/ui/src/lib/utils/conversation-utils.ts | 70 ++++++ .../src/lib/utils/convert-files-to-extra.ts | 4 +- tools/ui/src/lib/utils/index.ts | 25 +- tools/ui/src/routes/(chat)/+page.svelte | 15 +- .../src/routes/(chat)/chat/[id]/+page.svelte | 10 +- tools/ui/src/routes/+layout.svelte | 36 +-- tools/ui/src/routes/search/+page.svelte | 10 +- ...ettings-registry-invariants.svelte.test.ts | 4 +- ...tings-render-keys-migration.svelte.test.ts | 14 +- .../client/ui-settings-sync.svelte.test.ts | 12 +- 116 files changed, 937 insertions(+), 945 deletions(-) create mode 100644 tools/ui/src/lib/stores/context-stats.svelte.ts create mode 100644 tools/ui/src/lib/stores/index.ts diff --git a/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsList/ChatAttachmentsListItem/ChatAttachmentsListItemMcpResource.svelte b/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsList/ChatAttachmentsListItem/ChatAttachmentsListItemMcpResource.svelte index 486b15b3b1..80ef25bbcb 100644 --- a/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsList/ChatAttachmentsListItem/ChatAttachmentsListItemMcpResource.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsList/ChatAttachmentsListItem/ChatAttachmentsListItemMcpResource.svelte @@ -3,7 +3,7 @@ import { X } from '@lucide/svelte'; import { ActionIcon } from '$lib/components/app'; import * as Tooltip from '$lib/components/ui/tooltip'; - import { mcpStore } from '$lib/stores/mcp.svelte'; + import { mcpStore } from '$lib/stores'; import type { MCPResourceAttachment } from '$lib/types'; import { getResourceDisplayName, getResourceIcon } from '$lib/utils'; diff --git a/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsPreview.svelte b/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsPreview.svelte index c161e55247..0efe052b1f 100644 --- a/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsPreview.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsPreview.svelte @@ -5,7 +5,7 @@ ChatAttachmentsPreviewNavButtons, ChatAttachmentsPreviewThumbnailStrip } from '$lib/components/app'; - import { modelsStore } from '$lib/stores/models.svelte'; + import { modelsStore } from '$lib/stores'; import { createBase64DataUrl, formatFileSize, diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatForm.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatForm.svelte index 9921d8d88d..bf56e91083 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatForm.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatForm.svelte @@ -26,19 +26,16 @@ SpecialFileType } from '$lib/enums'; import { useChatFormPickers } from '$lib/hooks/use-chat-form-pickers.svelte'; - import { chatStore } from '$lib/stores/chat.svelte'; import { - activeConversation, - activeMessages, + chatStore, conversationsStore, - pendingCwd - } from '$lib/stores/conversations.svelte'; - import { mcpStore } from '$lib/stores/mcp.svelte'; - import { mcpHasResourceAttachments } from '$lib/stores/mcp-resources.svelte'; - import { modelOptions, selectedModelId } from '$lib/stores/models.svelte'; - import { isRouterMode } from '$lib/stores/server.svelte'; - import { config } from '$lib/stores/settings.svelte'; - import { toolsStore } from '$lib/stores/tools.svelte'; + mcpResourceStore, + mcpStore, + modelsStore, + serverStore, + settingsStore, + toolsStore + } from '$lib/stores'; import type { FileMentionEntry, GetPromptResult, @@ -143,7 +140,7 @@ // float above the box. let mentionAnchor: HTMLDivElement | null = $state(null); - let cwd = $derived(activeConversation()?.cwd ?? pendingCwd()); + let cwd = $derived(conversationsStore.activeConversation?.cwd ?? conversationsStore.pendingCwd); const pickers = useChatFormPickers({ focusInput: refocusInput, @@ -184,7 +181,7 @@ let isResourceDialogOpen = $state(false); let preSelectedResourceUri = $state(undefined); - let currentConfig = $derived(config()); + let currentConfig = $derived(settingsStore.config); let pasteLongTextToFileLength = $derived.by(() => { const n = Number(currentConfig.pasteLongTextToFileLen); @@ -192,18 +189,18 @@ return Number.isNaN(n) ? Number(SETTING_CONFIG_DEFAULT.pasteLongTextToFileLen) : n; }); - let isRouter = $derived(isRouterMode()); + let isRouter = $derived(serverStore.isRouterMode); let conversationModel = $derived( - chatStore.getConversationModel(activeMessages() as DatabaseMessage[]) + chatStore.getConversationModel(conversationsStore.activeMessages as DatabaseMessage[]) ); let activeModelId = $derived.by(() => { - const options = modelOptions(); + const options = modelsStore.models; if (!isRouter) { return options.length > 0 ? options[0].model : null; } - const selectedId = selectedModelId(); + const selectedId = modelsStore.selectedModelId; if (selectedId) { const model = options.find((m) => m.id === selectedId); @@ -220,7 +217,9 @@ return null; }); - let hasModelSelected = $derived(!isRouter || !!conversationModel || !!selectedModelId()); + let hasModelSelected = $derived( + !isRouter || !!conversationModel || !!modelsStore.selectedModelId + ); let hasLoadingAttachments = $derived(uploadedFiles.some((f) => f.isLoading)); let hasAttachments = $derived( (attachments && attachments.length > 0) || (uploadedFiles && uploadedFiles.length > 0) @@ -634,7 +633,7 @@ /> {/if} - {#if mcpHasResourceAttachments()} + {#if mcpResourceStore.hasAttachments} { diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddMcpServersSubmenu.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddMcpServersSubmenu.svelte index 178345e834..3d04d14cb1 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddMcpServersSubmenu.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddMcpServersSubmenu.svelte @@ -6,8 +6,7 @@ import { Switch } from '$lib/components/ui/switch'; import { ICON_CLASS_DEFAULT, ROUTES } from '$lib/constants'; import { HealthCheckStatus } from '$lib/enums'; - import { conversationsStore } from '$lib/stores/conversations.svelte'; - import { mcpStore } from '$lib/stores/mcp.svelte'; + import { conversationsStore, mcpStore } from '$lib/stores'; import type { MCPServerSettingsEntry } from '$lib/types'; interface Props { diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddSheet.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddSheet.svelte index 299b22209f..aa5397ca0b 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddSheet.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddSheet.svelte @@ -24,8 +24,7 @@ import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte'; import { useReasoningMenu } from '$lib/hooks/use-reasoning-menu.svelte'; import { useToolsPanel } from '$lib/hooks/use-tools-panel.svelte'; - import { conversationsStore } from '$lib/stores/conversations.svelte'; - import { mcpStore } from '$lib/stores/mcp.svelte'; + import { conversationsStore, mcpStore } from '$lib/stores'; import type { Snippet } from 'svelte'; interface Props { diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddToolsSubmenu.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddToolsSubmenu.svelte index ac3b5712fc..1204390fd8 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddToolsSubmenu.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionAddToolsSubmenu.svelte @@ -6,8 +6,7 @@ import * as Tooltip from '$lib/components/ui/tooltip'; import { CLI_FLAGS, ICON_CLASS_DEFAULT } from '$lib/constants'; import { useToolsPanel } from '$lib/hooks/use-tools-panel.svelte'; - import { mcpStore } from '$lib/stores/mcp.svelte'; - import { toolsStore } from '$lib/stores/tools.svelte'; + import { mcpStore, toolsStore } from '$lib/stores'; const toolsPanel = useToolsPanel(); const hasMcpServersAvailable = $derived(mcpStore.getServers().length > 0); diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionsAdd.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionsAdd.svelte index c54471a5ae..a31ffb394d 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionsAdd.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAdd/ChatFormActionsAdd.svelte @@ -2,7 +2,7 @@ import ChatFormActionAddButton from './ChatFormActionAddButton.svelte'; import ChatFormActionAddDropdown from './ChatFormActionAddDropdown.svelte'; import ChatFormActionAddSheet from './ChatFormActionAddSheet.svelte'; - import { isMobile } from '$lib/stores/viewport.svelte'; + import { isMobile } from '$lib/stores'; interface Props { disabled?: boolean; diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte index 62befb5dda..fad223a98b 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte @@ -1,15 +1,6 @@
diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistantStatistics.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistantStatistics.svelte index 5c5ac8c25c..e6e18ae080 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistantStatistics.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistantStatistics.svelte @@ -2,6 +2,7 @@ import { ChatMessageStatistics } from '$lib/components/app'; import { ChatMessageStatisticsMode } from '$lib/enums'; import type { UseProcessingStateReturn } from '$lib/hooks/use-processing-state.svelte'; + import { agenticStore } from '$lib/stores'; interface Props { message: DatabaseMessage; @@ -11,9 +12,26 @@ } let { isLoading, message, processingState, showMessageStats }: Props = $props(); + + // A running agentic flow stamps per-turn timings on its root message at each + // turn boundary and the cumulative agentic totals only on exit; while it runs, + // show the session's live totals on the root message instead. + const liveLlm = $derived(agenticStore.getLiveLlmTotals(message.convId)); + const isLiveFlowRoot = $derived( + liveLlm !== null && agenticStore.getFlowRootMessageId(message.convId) === message.id + ); -{#if showMessageStats && message.timings && message.timings.predicted_n && message.timings.predicted_ms} +{#if showMessageStats && isLiveFlowRoot && liveLlm} + +{:else if showMessageStats && message.timings && message.timings.predicted_n && message.timings.predicted_ms} {@const agentic = message.timings.agentic} MAX_HEIGHT); diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockEditFile.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockEditFile.svelte index 6b95a92fb2..6545cc39f7 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockEditFile.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockEditFile.svelte @@ -3,7 +3,7 @@ import ToolCallBlock from './ToolCallBlock.svelte'; import { XCircle } from '@lucide/svelte'; import { MAX_HEIGHT_CODE_BLOCK, RESULT_STAT_SEPARATOR } from '$lib/constants'; - import { toolsStore } from '$lib/stores/tools.svelte'; + import { toolsStore } from '$lib/stores'; import type { AgenticSection } from '$lib/types'; import { abbreviateHome, computeLineDiff, prefixFor } from '$lib/utils'; diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockExecShellCommand.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockExecShellCommand.svelte index caf6d832b1..639bee8978 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockExecShellCommand.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockExecShellCommand.svelte @@ -12,8 +12,7 @@ import { CollapsibleTerminalBlock } from '$lib/components/app'; import { SETTINGS_KEYS, TOOL_RUNTIME_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants'; import { AttachmentType } from '$lib/enums'; - import { config } from '$lib/stores/settings.svelte'; - import { toolsStore } from '$lib/stores/tools.svelte'; + import { settingsStore, toolsStore } from '$lib/stores'; import type { AgenticSection, ToolResultLine } from '$lib/types'; import type { DatabaseMessageExtra } from '$lib/types'; import { @@ -93,7 +92,7 @@ ); const useFullHeightCodeBlocks = $derived( - Boolean(config()[SETTINGS_KEYS.FULL_HEIGHT_CODE_BLOCKS]) + Boolean(settingsStore.config[SETTINGS_KEYS.FULL_HEIGHT_CODE_BLOCKS]) ); const autoScroll = $derived(isLive && !useFullHeightCodeBlocks); diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockFileGlobSearch.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockFileGlobSearch.svelte index 66eb3a2ad6..7a9fbe97b6 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockFileGlobSearch.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockFileGlobSearch.svelte @@ -2,7 +2,7 @@ import { parseFileGlobSearchMeta } from './parsers/file-glob-search'; import ToolCallBlock from './ToolCallBlock.svelte'; import { XCircle } from '@lucide/svelte'; - import { toolsStore } from '$lib/stores/tools.svelte'; + import { toolsStore } from '$lib/stores'; import type { AgenticSection } from '$lib/types'; import { abbreviateHome } from '$lib/utils'; diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetInfo.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetInfo.svelte index 9e6ef10919..6b39e7d92f 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetInfo.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetInfo.svelte @@ -1,7 +1,7 @@ {#if hasError} @@ -23,17 +23,17 @@ {#if !isLoadingModel} {/if} {#if !isLoadingModel} - {serverError()} + {serverStore.error} {/if}
diff --git a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenStreamResumeStatus.svelte b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenStreamResumeStatus.svelte index 9061186101..a8e0dcc196 100644 --- a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenStreamResumeStatus.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenStreamResumeStatus.svelte @@ -1,7 +1,7 @@ diff --git a/tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte b/tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte index edfa32d48b..04d48f0aa8 100644 --- a/tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte +++ b/tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte @@ -45,7 +45,7 @@ import { ColorMode, UrlProtocol } from '$lib/enums'; import { FileTypeText } from '$lib/enums/files.enums'; import { createAutoScrollController } from '$lib/hooks/use-auto-scroll.svelte'; - import { config } from '$lib/stores/settings.svelte'; + import { settingsStore } from '$lib/stores'; import type { DatabaseMessageExtra } from '$lib/types/database'; import { copyCodeToClipboard, @@ -864,7 +864,7 @@
diff --git a/tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/file-badge.ts b/tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/file-badge.ts index 24a78de46f..7bc5ca3b8e 100644 --- a/tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/file-badge.ts +++ b/tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/file-badge.ts @@ -16,8 +16,7 @@ import { PATH_SEPARATOR, SETTINGS_KEYS } from '$lib/constants'; -import { settingsStore } from '$lib/stores/settings.svelte'; -import { toolsStore } from '$lib/stores/tools.svelte'; +import { settingsStore, toolsStore } from '$lib/stores'; import { decodeFileLinkPath, getMentionBadgeIconPaths, getMentionBadgeLabel } from '$lib/utils'; import type { Element, Root } from 'hast'; import type { Plugin } from 'unified'; diff --git a/tools/ui/src/lib/components/app/content/MentionBadge.svelte b/tools/ui/src/lib/components/app/content/MentionBadge.svelte index 1af126267c..feda3aa43a 100644 --- a/tools/ui/src/lib/components/app/content/MentionBadge.svelte +++ b/tools/ui/src/lib/components/app/content/MentionBadge.svelte @@ -1,7 +1,6 @@ - {activeConversation()?.name || 'Chat'} - {APP_NAME} + {conversationsStore.activeConversation?.name || 'Chat'} - {APP_NAME} { - node.textContent = (config().customCss as string | undefined) ?? ''; + node.textContent = (settingsStore.config.customCss as string | undefined) ?? ''; }); } @@ -188,7 +192,7 @@ let routerModelsFetched = false; $effect(() => { - const isRouter = isRouterMode(); + const isRouter = serverStore.isRouterMode; const modelsCount = modelsStore.models.length; // Only fetch router models once when we have models loaded and in router mode @@ -205,7 +209,7 @@ $effect(() => { if (!browser) return; - if (!isRouterMode()) return; + if (!serverStore.isRouterMode) return; untrack(() => { modelsStore.subscribeStatus(); @@ -252,7 +256,7 @@ {/if} - {#if config().customCss} + {#if settingsStore.config.customCss} {/if} diff --git a/tools/ui/src/routes/search/+page.svelte b/tools/ui/src/routes/search/+page.svelte index 424b74f67c..cb7f77f95e 100644 --- a/tools/ui/src/routes/search/+page.svelte +++ b/tools/ui/src/routes/search/+page.svelte @@ -5,9 +5,7 @@ import { SearchInput, SidebarNavigationSearchResults } from '$lib/components/app'; import { ROUTES } from '$lib/constants'; import { RouterService } from '$lib/services/router.service'; - import { chatStore } from '$lib/stores/chat.svelte'; - import { conversations, conversationsStore } from '$lib/stores/conversations.svelte'; - import { isMobile } from '$lib/stores/viewport.svelte'; + import { chatStore, conversationsStore, isMobile } from '$lib/stores'; let searchQuery = $state(''); let searchInputRef = $state(null); @@ -19,7 +17,7 @@ if (query.length === 0) return []; - return conversations().filter((c) => c.name.toLowerCase().includes(query)); + return conversationsStore.conversations.filter((c) => c.name.toLowerCase().includes(query)); }); // Search page is intended for mobile; on desktop the sidebar already exposes @@ -35,7 +33,7 @@ } async function handleEditConversation(id: string) { - const conversation = conversations().find((c) => c.id === id); + const conversation = conversationsStore.conversations.find((c) => c.id === id); if (!conversation) return; @@ -47,7 +45,7 @@ } async function handleDeleteConversation(id: string) { - const conversation = conversations().find((c) => c.id === id); + const conversation = conversationsStore.conversations.find((c) => c.id === id); if (!conversation) return; diff --git a/tools/ui/tests/client/settings-registry-invariants.svelte.test.ts b/tools/ui/tests/client/settings-registry-invariants.svelte.test.ts index ddf1393e70..45af7e0d15 100644 --- a/tools/ui/tests/client/settings-registry-invariants.svelte.test.ts +++ b/tools/ui/tests/client/settings-registry-invariants.svelte.test.ts @@ -1,7 +1,7 @@ import { CONFIG_LOCALSTORAGE_KEY, SETTING_CONFIG_DEFAULT } from '$lib/constants'; import { ParameterSyncService } from '$lib/services/parameter-sync.service'; import { serverStore } from '$lib/stores/server.svelte'; -import { config, settingsStore } from '$lib/stores/settings.svelte'; +import { settingsStore } from '$lib/stores/settings.svelte'; import type { SettingsConfigType } from '$lib/types'; import { beforeEach, describe, expect, it } from 'vitest'; @@ -40,7 +40,7 @@ function mockProps(uiSettings: Record) { const setUser = (key: string, value: Primitive) => settingsStore.updateConfig(key as keyof SettingsConfigType, value as never); -const current = (key: string) => (config() as Record)[key]; +const current = (key: string) => (settingsStore.config as Record)[key]; describe('registry-wide invariants', () => { beforeEach(() => { diff --git a/tools/ui/tests/client/settings-render-keys-migration.svelte.test.ts b/tools/ui/tests/client/settings-render-keys-migration.svelte.test.ts index 078cc7cbec..32f4ff3dd4 100644 --- a/tools/ui/tests/client/settings-render-keys-migration.svelte.test.ts +++ b/tools/ui/tests/client/settings-render-keys-migration.svelte.test.ts @@ -6,7 +6,7 @@ import { CONFIG_LOCALSTORAGE_KEY } from '$lib/constants'; import { MigrationService } from '$lib/services/migration.service'; -import { config, settingsStore } from '$lib/stores/settings.svelte'; +import { settingsStore } from '$lib/stores/settings.svelte'; import { beforeEach, describe, expect, it } from 'vitest'; const RENDER_KEYS_MIGRATION_ID = 'render-keys-unfold-v1'; @@ -33,22 +33,22 @@ describe('renderContentAsRawText unfolding', () => { it('maps raw text to user content as plain text', async () => { await seedConfig({ renderContentAsRawText: true }); - expect(config().renderUserContentAsMarkdown).toBe(false); + expect(settingsStore.config.renderUserContentAsMarkdown).toBe(false); }); it('maps markdown to user content as markdown', async () => { await seedConfig({ renderContentAsRawText: false }); - expect(config().renderUserContentAsMarkdown).toBe(true); + expect(settingsStore.config.renderUserContentAsMarkdown).toBe(true); }); it('leaves thinking on its own default', async () => { await seedConfig({ renderContentAsRawText: true }); - expect(config().renderThinkingAsMarkdown).toBe(true); + expect(settingsStore.config.renderThinkingAsMarkdown).toBe(true); }); it('keeps an explicit user preference over the toggle', async () => { await seedConfig({ renderContentAsRawText: true, renderUserContentAsMarkdown: true }); - expect(config().renderUserContentAsMarkdown).toBe(true); + expect(settingsStore.config.renderUserContentAsMarkdown).toBe(true); }); it('drops the toggle from the persisted config', async () => { @@ -58,7 +58,7 @@ describe('renderContentAsRawText unfolding', () => { it('leaves both surfaces on markdown when nothing is stored', async () => { await seedConfig({}); - expect(config().renderUserContentAsMarkdown).toBe(true); - expect(config().renderThinkingAsMarkdown).toBe(true); + expect(settingsStore.config.renderUserContentAsMarkdown).toBe(true); + expect(settingsStore.config.renderThinkingAsMarkdown).toBe(true); }); }); diff --git a/tools/ui/tests/client/ui-settings-sync.svelte.test.ts b/tools/ui/tests/client/ui-settings-sync.svelte.test.ts index 110011ef0d..86e0898937 100644 --- a/tools/ui/tests/client/ui-settings-sync.svelte.test.ts +++ b/tools/ui/tests/client/ui-settings-sync.svelte.test.ts @@ -1,6 +1,6 @@ import { CONFIG_LOCALSTORAGE_KEY } from '$lib/constants'; import { serverStore } from '$lib/stores/server.svelte'; -import { config, settingsStore } from '$lib/stores/settings.svelte'; +import { settingsStore } from '$lib/stores/settings.svelte'; import { beforeEach, describe, expect, it } from 'vitest'; function mockProps(uiSettings: Record) { @@ -25,7 +25,7 @@ describe('server ui_settings application semantics', () => { settingsStore.syncWithServerDefaults(); - expect(config().theme).toBe('dark'); + expect(settingsStore.config.theme).toBe('dark'); }); it('never reapplies on later loads: the user config diverges freely', () => { @@ -40,8 +40,8 @@ describe('server ui_settings application semantics', () => { settingsStore.syncWithServerDefaults(); settingsStore.syncWithServerDefaults(); - expect(config().theme).toBe('light'); - expect(config().apiKey).toBe('sk-user-key'); + expect(settingsStore.config.theme).toBe('light'); + expect(settingsStore.config.apiKey).toBe('sk-user-key'); const stored = JSON.parse(localStorage.getItem(CONFIG_LOCALSTORAGE_KEY) ?? '{}'); expect(stored.apiKey).toBe('sk-user-key'); @@ -55,8 +55,8 @@ describe('server ui_settings application semantics', () => { settingsStore.forceSyncWithServerDefaults(); - expect(config().theme).toBe('dark'); - expect(config().apiKey).toBe(''); + expect(settingsStore.config.theme).toBe('dark'); + expect(settingsStore.config.apiKey).toBe(''); }); });