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
This commit is contained in:
+1
-1
@@ -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';
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<string | undefined>(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}
|
||||
<ChatFormMcpResourcesList
|
||||
class="mb-3"
|
||||
onResourceClick={(uri) => {
|
||||
|
||||
+1
-2
@@ -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 {
|
||||
|
||||
+1
-2
@@ -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 {
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+16
-23
@@ -1,15 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { ModelsSelectorDropdown, ModelsSelectorSheet } from '$lib/components/app';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { activeMessages } from '$lib/stores/conversations.svelte';
|
||||
import {
|
||||
modelOptions,
|
||||
modelsStore,
|
||||
selectedModelId,
|
||||
selectedModelName
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { isRouterMode, serverError } from '$lib/stores/server.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { chatStore, conversationsStore, isMobile, modelsStore, serverStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
disabled?: boolean;
|
||||
@@ -35,17 +26,17 @@
|
||||
useGlobalSelection = false
|
||||
}: Props = $props();
|
||||
|
||||
let isRouter = $derived(isRouterMode());
|
||||
let isOffline = $derived(!!serverError());
|
||||
let isRouter = $derived(serverStore.isRouterMode);
|
||||
let isOffline = $derived(!!serverStore.error);
|
||||
|
||||
let conversationModel = $derived(
|
||||
chatStore.getConversationModel(activeMessages() as DatabaseMessage[])
|
||||
chatStore.getConversationModel(conversationsStore.activeMessages as DatabaseMessage[])
|
||||
);
|
||||
|
||||
let lastSyncedConversationModel: string | null = null;
|
||||
|
||||
let selectorModel = $derived.by(() => {
|
||||
const storeModel = selectedModelName();
|
||||
const storeModel = modelsStore.selectedModelName;
|
||||
|
||||
if (storeModel && storeModel !== conversationModel) {
|
||||
return storeModel;
|
||||
@@ -60,7 +51,7 @@
|
||||
|
||||
$effect(() => {
|
||||
if (conversationModel && conversationModel !== lastSyncedConversationModel) {
|
||||
if (modelOptions().some((m) => m.model === conversationModel)) {
|
||||
if (modelsStore.models.some((m) => m.model === conversationModel)) {
|
||||
modelsStore.selectedModelName = conversationModel;
|
||||
modelsStore.selectModelByName(conversationModel);
|
||||
} else {
|
||||
@@ -73,24 +64,24 @@
|
||||
isRouter &&
|
||||
!modelsStore.selectedModelId &&
|
||||
modelsStore.loadedModelIds.length > 0 &&
|
||||
activeMessages().length > 0 &&
|
||||
conversationsStore.activeMessages.length > 0 &&
|
||||
!conversationModel
|
||||
) {
|
||||
lastSyncedConversationModel = null;
|
||||
const first = modelOptions().find((m) => modelsStore.loadedModelIds.includes(m.model));
|
||||
const first = modelsStore.models.find((m) => modelsStore.loadedModelIds.includes(m.model));
|
||||
|
||||
if (first) modelsStore.selectModelById(first.id);
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -140,21 +131,23 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
hasModelSelected = !isRouter || !!conversationModel || !!selectedModelId();
|
||||
hasModelSelected = !isRouter || !!conversationModel || !!modelsStore.selectedModelId;
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (!isRouter) {
|
||||
isSelectedModelInCache = true;
|
||||
} else if (conversationModel) {
|
||||
isSelectedModelInCache = modelOptions().some((option) => option.model === conversationModel);
|
||||
isSelectedModelInCache = modelsStore.models.some(
|
||||
(option) => option.model === conversationModel
|
||||
);
|
||||
} else {
|
||||
const currentModelId = selectedModelId();
|
||||
const currentModelId = modelsStore.selectedModelId;
|
||||
|
||||
if (!currentModelId) {
|
||||
isSelectedModelInCache = false;
|
||||
} else {
|
||||
isSelectedModelInCache = modelOptions().some((option) => option.id === currentModelId);
|
||||
isSelectedModelInCache = modelsStore.models.some((option) => option.id === currentModelId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+5
-12
@@ -13,14 +13,7 @@
|
||||
import { ICON_CLASS_DEFAULT, ROUTES } from '$lib/constants';
|
||||
import { FileTypeCategory, MessageRole } from '$lib/enums';
|
||||
import { ChatService } from '$lib/services';
|
||||
import {
|
||||
activeProcessingState,
|
||||
isChatStreaming,
|
||||
isLoading as chatIsLoading
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import { activeMessages, conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { chatStore, conversationsStore, mcpStore, settingsStore } from '$lib/stores';
|
||||
import { getFileTypeCategory } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -61,7 +54,7 @@
|
||||
uploadedFiles = []
|
||||
}: Props = $props();
|
||||
|
||||
let currentConfig = $derived(config());
|
||||
let currentConfig = $derived(settingsStore.config);
|
||||
|
||||
let hasMcpPromptsSupport = $derived.by(() => {
|
||||
const perChatOverrides = conversationsStore.getAllMcpServerOverrides();
|
||||
@@ -103,7 +96,7 @@
|
||||
let hasProcessedTokens = $derived.by(() => {
|
||||
if (!page.params.id) return false;
|
||||
|
||||
const messages = activeMessages() as DatabaseMessage[];
|
||||
const messages = conversationsStore.activeMessages as DatabaseMessage[];
|
||||
|
||||
let totalHistoricalTokens = 0;
|
||||
|
||||
@@ -125,9 +118,9 @@
|
||||
|
||||
if (totalHistoricalTokens > 0) return true;
|
||||
|
||||
if (!chatIsLoading() && !isChatStreaming()) return false;
|
||||
if (!chatStore.isLoading && !chatStore.isStreaming()) return false;
|
||||
|
||||
const processingState = activeProcessingState();
|
||||
const processingState = chatStore.activeProcessingState;
|
||||
|
||||
if (!processingState) return false;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { CODE_BLOCK } from '$lib/constants';
|
||||
import { ColorMode } from '$lib/enums';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import type { ContentEditableToken } from '$lib/types';
|
||||
import type { SourceHistoryEntry } from '$lib/utils';
|
||||
import {
|
||||
|
||||
+7
-7
@@ -1,32 +1,32 @@
|
||||
<script lang="ts">
|
||||
import ContextGaugeDial from './ContextGaugeDial.svelte';
|
||||
import { useContextGauge } from '$lib/hooks/use-context-gauge.svelte';
|
||||
import { chatStore, isChatStreaming, isLoading } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
chatStore,
|
||||
conversationsStore,
|
||||
gaugeTriggerClick,
|
||||
gaugeTriggerEnter,
|
||||
gaugeTriggerKeydown,
|
||||
gaugeTriggerLeave,
|
||||
gaugeTriggerPointerDown
|
||||
} from '$lib/stores/context-gauge-popup.svelte';
|
||||
import { activeConversation, activeMessages } from '$lib/stores/conversations.svelte';
|
||||
} from '$lib/stores';
|
||||
import { untrack } from 'svelte';
|
||||
|
||||
const gauge = useContextGauge();
|
||||
|
||||
$effect(() => {
|
||||
const conv = activeConversation();
|
||||
const conv = conversationsStore.activeConversation;
|
||||
|
||||
untrack(() => chatStore.setActiveProcessingConversation(conv?.id ?? null));
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const conv = activeConversation();
|
||||
const messages = activeMessages() as DatabaseMessage[];
|
||||
const conv = conversationsStore.activeConversation;
|
||||
const messages = conversationsStore.activeMessages as DatabaseMessage[];
|
||||
|
||||
if (!conv) return;
|
||||
|
||||
if (isLoading() || isChatStreaming()) return;
|
||||
if (chatStore.isLoading || chatStore.isStreaming()) return;
|
||||
|
||||
if (messages.length === 0) {
|
||||
untrack(() => chatStore.clearProcessingState(conv.id));
|
||||
|
||||
+2
-7
@@ -3,12 +3,7 @@
|
||||
import ContextGaugeDetails from './ContextGaugeDetails.svelte';
|
||||
import ContextGaugeLoadModel from './ContextGaugeLoadModel.svelte';
|
||||
import { useContextGauge } from '$lib/hooks/use-context-gauge.svelte';
|
||||
import {
|
||||
gaugeCardEnter,
|
||||
gaugeCardLeave,
|
||||
gaugePopup,
|
||||
gaugePopupClose
|
||||
} from '$lib/stores/context-gauge-popup.svelte';
|
||||
import { gaugeCardEnter, gaugeCardLeave, gaugePopup, gaugePopupClose } from '$lib/stores';
|
||||
import { formatParameters } from '$lib/utils/formatters';
|
||||
|
||||
const gauge = useContextGauge();
|
||||
@@ -92,7 +87,7 @@
|
||||
<span class={colorLevelTextClass(gauge.colorLevel)}>{gauge.contextPercent}%</span> used
|
||||
</span>
|
||||
<span>
|
||||
{formatParameters((gauge.contextTotal ?? 0) - gauge.contextUsed)} remaining
|
||||
{formatParameters(gauge.contextAvailable ?? 0)} remaining
|
||||
</span>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
ChatAttachmentsListItemMcpResource,
|
||||
HorizontalScrollCarousel
|
||||
} from '$lib/components/app';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import {
|
||||
mcpHasResourceAttachments,
|
||||
mcpResourceAttachments
|
||||
} from '$lib/stores/mcp-resources.svelte';
|
||||
import { mcpResourceStore, mcpStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
@@ -16,8 +12,8 @@
|
||||
|
||||
let { class: className, onResourceClick }: Props = $props();
|
||||
|
||||
const attachments = $derived(mcpResourceAttachments());
|
||||
const hasAttachments = $derived(mcpHasResourceAttachments());
|
||||
const attachments = $derived(mcpResourceStore.attachments);
|
||||
const hasAttachments = $derived(mcpResourceStore.hasAttachments);
|
||||
|
||||
function handleRemove(attachmentId: string) {
|
||||
mcpStore.removeResourceAttachment(attachmentId);
|
||||
|
||||
+2
-4
@@ -8,9 +8,7 @@
|
||||
import { BuiltInTool, FileMentionEntryType, GlobSearchType, KeyboardKey } from '$lib/enums';
|
||||
import { useDebouncedSearch } from '$lib/hooks/use-debounced-search.svelte';
|
||||
import { usePickerNavigation } from '$lib/hooks/use-picker-navigation.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { isMobile, settingsStore, toolsStore } from '$lib/stores';
|
||||
import type { FileMentionEntry, GlobEntryResult } from '$lib/types';
|
||||
import { abbreviateHome, runGlobSearchWithChildren } from '$lib/utils';
|
||||
|
||||
@@ -64,7 +62,7 @@
|
||||
// Coerce the depth setting to a positive integer; an invalid value
|
||||
// would otherwise reach the server as max_depth 0 = unlimited.
|
||||
const searchDepth = $derived.by(() => {
|
||||
const n = Number(config().mentionSearchMaxDepth);
|
||||
const n = Number(settingsStore.config.mentionSearchMaxDepth);
|
||||
|
||||
return Number.isInteger(n) && n > 0 ? n : FILE_GLOB_SEARCH_PICKERS.DEFAULT_SEARCH_DEPTH;
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { MCPServerSettingsEntry } from '$lib/types';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
|
||||
+1
-2
@@ -9,8 +9,7 @@
|
||||
} from '$lib/components/app/chat';
|
||||
import Badge from '$lib/components/ui/badge/badge.svelte';
|
||||
import { KeyboardKey } 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 { GetPromptResult, MCPPromptInfo, MCPServerSettingsEntry } from '$lib/types';
|
||||
import { debounce, uuid } from '$lib/utils';
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { autoResizeTextarea } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import { usePickerNavigation } from '$lib/hooks/use-picker-navigation.svelte';
|
||||
import { useScrollActiveRow } from '$lib/hooks/use-scroll-active-row.svelte';
|
||||
import { ToolsService } from '$lib/services/tools.service';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { toolsStore } from '$lib/stores';
|
||||
import type { GlobEntry } from '$lib/types';
|
||||
import {
|
||||
abbreviateHome,
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
import { getChatActionsContext, setMessageEditContext } from '$lib/contexts';
|
||||
import { AgenticSectionType, AttachmentType, MessageRole } from '$lib/enums';
|
||||
import { DatabaseService } from '$lib/services/database.service';
|
||||
import { chatStore, pendingEditMessageId } from '$lib/stores/chat.svelte';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { chatStore, conversationsStore, isMobile } from '$lib/stores';
|
||||
import type { DatabaseMessageExtraMcpPrompt } from '$lib/types';
|
||||
import { deriveAgenticSections } from '$lib/utils';
|
||||
import { parseFilesToMessageExtras } from '$lib/utils/browser-only';
|
||||
@@ -185,7 +183,7 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const pendingId = pendingEditMessageId();
|
||||
const pendingId = chatStore.pendingEditMessageId;
|
||||
|
||||
if (pendingId && pendingId === message.id && !isEditing) {
|
||||
handleEdit();
|
||||
|
||||
+8
-11
@@ -11,10 +11,7 @@
|
||||
import { getMessageEditContext } from '$lib/contexts';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
|
||||
import { chatStore, isChatStreaming, isLoading } from '$lib/stores/chat.svelte';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { chatStore, modelsStore, serverStore, settingsStore } from '$lib/stores';
|
||||
import { modelLoadProgressText } from '$lib/utils';
|
||||
import { hasAgenticContent } from '$lib/utils';
|
||||
|
||||
@@ -69,15 +66,15 @@
|
||||
const isAgentic = $derived(hasAgenticContent(message, toolMessages));
|
||||
const processingState = useProcessingState();
|
||||
|
||||
let currentConfig = $derived(config());
|
||||
let isRouter = $derived(isRouterMode());
|
||||
let currentConfig = $derived(settingsStore.config);
|
||||
let isRouter = $derived(serverStore.isRouterMode);
|
||||
|
||||
let showRawOutput = $state(false);
|
||||
|
||||
let displayedModel = $derived(message.model ?? null);
|
||||
|
||||
let isCurrentlyLoading = $derived(isLoading());
|
||||
let isStreaming = $derived(isChatStreaming());
|
||||
let isCurrentlyLoading = $derived(chatStore.isLoading);
|
||||
let isStreaming = $derived(chatStore.isStreaming());
|
||||
let hasNoContent = $derived(!message?.content?.trim());
|
||||
let isActivelyProcessing = $derived(isCurrentlyLoading || isStreaming);
|
||||
|
||||
@@ -175,7 +172,7 @@
|
||||
<ChatMessageAgenticContent
|
||||
{message}
|
||||
{toolMessages}
|
||||
isStreaming={isChatStreaming()}
|
||||
isStreaming={chatStore.isStreaming()}
|
||||
{isLastAssistantMessage}
|
||||
/>
|
||||
{/if}
|
||||
@@ -190,14 +187,14 @@
|
||||
<div class="inline-flex flex-wrap items-start gap-2 text-xs text-muted-foreground">
|
||||
<ChatMessageAssistantModel
|
||||
{displayedModel}
|
||||
isLoading={isLoading()}
|
||||
isLoading={chatStore.isLoading}
|
||||
{isRouter}
|
||||
{onRegenerate}
|
||||
/>
|
||||
|
||||
<ChatMessageAssistantStatistics
|
||||
{message}
|
||||
isLoading={isLoading()}
|
||||
isLoading={chatStore.isLoading}
|
||||
{processingState}
|
||||
showMessageStats={currentConfig.showMessageStats}
|
||||
/>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ModelBadge, ModelsSelectorDropdown } from '$lib/components/app';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
import { copyToClipboard } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
let { modelLoadingText, position, processingState }: Props = $props();
|
||||
|
||||
const marginClass = position === 'top' ? 'mt-6' : 'mt-4';
|
||||
const marginClass = $derived(position === 'top' ? 'mt-6' : 'mt-4');
|
||||
</script>
|
||||
|
||||
<div class="{marginClass} w-full max-w-3xl" in:fade>
|
||||
|
||||
+19
-1
@@ -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
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if showMessageStats && message.timings && message.timings.predicted_n && message.timings.predicted_ms}
|
||||
{#if showMessageStats && isLiveFlowRoot && liveLlm}
|
||||
<ChatMessageStatistics
|
||||
mode={ChatMessageStatisticsMode.GENERATION}
|
||||
isLive
|
||||
promptTokens={liveLlm.prompt_n}
|
||||
promptMs={liveLlm.prompt_ms}
|
||||
predictedTokens={liveLlm.predicted_n}
|
||||
predictedMs={liveLlm.predicted_ms}
|
||||
/>
|
||||
{:else if showMessageStats && message.timings && message.timings.predicted_n && message.timings.predicted_ms}
|
||||
{@const agentic = message.timings.agentic}
|
||||
<ChatMessageStatistics
|
||||
mode={ChatMessageStatisticsMode.GENERATION}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
import { Card } from '$lib/components/ui/card';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
import { McpPromptVariant } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { DatabaseMessageExtraMcpPrompt } from '$lib/types';
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
import { INPUT_CLASSES } from '$lib/constants';
|
||||
import { getMessageEditContext } from '$lib/contexts';
|
||||
import { KeyboardKey, MessageRole } from '$lib/enums';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
import { autoResizeTextarea, isIMEComposing } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -64,7 +64,7 @@
|
||||
let contentHeight = $state(0);
|
||||
|
||||
const MAX_HEIGHT = 200; // pixels
|
||||
const currentConfig = config();
|
||||
const currentConfig = settingsStore.config;
|
||||
|
||||
let showExpandButton = $derived(contentHeight > MAX_HEIGHT);
|
||||
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+2
-3
@@ -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);
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Info, Loader2 } from '@lucide/svelte';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { toolsStore } from '$lib/stores';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome } from '$lib/utils';
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
import { parseGrepSearchMeta } from './parsers/grep-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';
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
import * as HoverCard from '$lib/components/ui/hover-card';
|
||||
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { AgenticSection, SearchResult } from '$lib/types';
|
||||
import {
|
||||
extractSearchQuery,
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
import { XCircle } from '@lucide/svelte';
|
||||
import { SyntaxHighlightedCode } from '$lib/components/app';
|
||||
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 } from '$lib/utils';
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
import { CollapsibleContentBlock } from '$lib/components/app';
|
||||
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { AgenticSection, BuiltinToolUiEntry } from '$lib/types';
|
||||
import { getBuiltinToolUi } from '$lib/utils';
|
||||
import type { Component, Snippet } from 'svelte';
|
||||
|
||||
+3
-4
@@ -8,8 +8,7 @@
|
||||
import { getMessageEditContext } from '$lib/contexts';
|
||||
import { ChatMessageStatisticsMode, MessageRole } from '$lib/enums';
|
||||
import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
|
||||
import { isLoading } from '$lib/stores/chat.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { chatStore, settingsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
@@ -54,8 +53,8 @@
|
||||
const editCtx = getMessageEditContext();
|
||||
const processingState = useProcessingState();
|
||||
|
||||
const currentConfig = $derived(config());
|
||||
const isActivelyProcessing = $derived(isLastUserMessage && isLoading());
|
||||
const currentConfig = $derived(settingsStore.config);
|
||||
const isActivelyProcessing = $derived(isLastUserMessage && chatStore.isLoading);
|
||||
|
||||
// For agentic turns, prefer the cumulative agentic.llm totals over per-call timings.
|
||||
let storedReadingStats = $derived.by(() => {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ChatAttachmentsList, MarkdownContent, MentionText } from '$lib/components/app';
|
||||
import { Card } from '$lib/components/ui/card';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
import type { DatabaseMessageExtra } from '$lib/types/database';
|
||||
|
||||
interface Props {
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
let isMultiline = $state(false);
|
||||
let messageElement: HTMLElement | undefined = $state();
|
||||
const currentConfig = config();
|
||||
const currentConfig = settingsStore.config;
|
||||
|
||||
$effect(() => {
|
||||
if (!messageElement || !content.trim()) return;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
import { cn } from '$lib/components/ui/utils';
|
||||
import { TOOL_SERVER_LABELS } from '$lib/constants';
|
||||
import { ToolPermissionDecision, ToolSource } from '$lib/enums';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { toolsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
toolName: string;
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import { activeConversation } from '$lib/stores/conversations.svelte';
|
||||
import { conversationsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
role: MessageRole.USER | MessageRole.ASSISTANT;
|
||||
@@ -69,7 +69,7 @@
|
||||
}
|
||||
|
||||
function handleOpenForkDialog() {
|
||||
const conv = activeConversation();
|
||||
const conv = conversationsStore.activeConversation;
|
||||
|
||||
forkName = `Fork of ${conv?.name ?? 'Conversation'}`;
|
||||
forkIncludeAttachments = true;
|
||||
|
||||
+19
-19
@@ -8,15 +8,7 @@
|
||||
MarkdownContent
|
||||
} from '$lib/components/app';
|
||||
import { AgenticSectionType, ChatMessageStatsView, ToolPermissionDecision } from '$lib/enums';
|
||||
import {
|
||||
agenticExecutingToolCallId,
|
||||
agenticLastError,
|
||||
agenticPendingContinueRequest,
|
||||
agenticPendingPermissionRequest,
|
||||
agenticResolveContinue,
|
||||
agenticResolvePermission
|
||||
} from '$lib/stores/agentic.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { agenticStore, settingsStore } from '$lib/stores';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import type {
|
||||
ChatMessageAgenticTimings,
|
||||
@@ -41,19 +33,25 @@
|
||||
|
||||
let expandedStates: Record<number, boolean> = $state({});
|
||||
|
||||
const showThoughtInProgress = $derived(Boolean(config().showThoughtInProgress));
|
||||
const alwaysShowToolCallContent = $derived(Boolean(config().alwaysShowToolCallContent));
|
||||
const showMessageStats = $derived(Boolean(config().showMessageStats));
|
||||
const showAgenticTurnStats = $derived(showMessageStats && Boolean(config().showAgenticTurnStats));
|
||||
const showThoughtInProgress = $derived(Boolean(settingsStore.config.showThoughtInProgress));
|
||||
const alwaysShowToolCallContent = $derived(
|
||||
Boolean(settingsStore.config.alwaysShowToolCallContent)
|
||||
);
|
||||
const showMessageStats = $derived(Boolean(settingsStore.config.showMessageStats));
|
||||
const showAgenticTurnStats = $derived(
|
||||
showMessageStats && Boolean(settingsStore.config.showAgenticTurnStats)
|
||||
);
|
||||
|
||||
const hasReasoningError = $derived(
|
||||
isLastAssistantMessage ? !!agenticLastError(message.convId) : false
|
||||
isLastAssistantMessage ? !!agenticStore.lastError(message.convId) : false
|
||||
);
|
||||
|
||||
let permissionDismissed = $state(false);
|
||||
|
||||
const pendingPermission = $derived(
|
||||
isStreaming && isLastAssistantMessage ? agenticPendingPermissionRequest(message.convId) : null
|
||||
isStreaming && isLastAssistantMessage
|
||||
? agenticStore.pendingPermissionRequest(message.convId)
|
||||
: null
|
||||
);
|
||||
|
||||
let prevPendingRef: typeof pendingPermission = null;
|
||||
@@ -69,13 +67,15 @@
|
||||
|
||||
function handlePermission(decision: ToolPermissionDecision) {
|
||||
permissionDismissed = true;
|
||||
agenticResolvePermission(message.convId, decision);
|
||||
agenticStore.resolvePermission(message.convId, decision);
|
||||
}
|
||||
|
||||
let continueDismissed = $state(false);
|
||||
|
||||
const pendingContinue = $derived(
|
||||
isStreaming && isLastAssistantMessage ? agenticPendingContinueRequest(message.convId) : false
|
||||
isStreaming && isLastAssistantMessage
|
||||
? agenticStore.pendingContinueRequest(message.convId)
|
||||
: false
|
||||
);
|
||||
|
||||
let prevContinueRef = false;
|
||||
@@ -91,13 +91,13 @@
|
||||
|
||||
function handleContinue(shouldContinue: boolean) {
|
||||
continueDismissed = true;
|
||||
agenticResolveContinue(message.convId, shouldContinue);
|
||||
agenticStore.resolveContinue(message.convId, shouldContinue);
|
||||
}
|
||||
|
||||
const sections = $derived(deriveAgenticSections(message, toolMessages, [], isStreaming));
|
||||
|
||||
const currentlyExecutingToolCallId = $derived(
|
||||
isStreaming ? agenticExecutingToolCallId(message.convId) : null
|
||||
isStreaming ? agenticStore.executingToolCallId(message.convId) : null
|
||||
);
|
||||
|
||||
type TurnGroup = {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { getMessageEditContext } from '$lib/contexts';
|
||||
import { KeyboardKey, MessageRole } from '$lib/enums';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { chatStore } from '$lib/stores';
|
||||
import { processFilesToChatUploaded } from '$lib/utils/browser-only';
|
||||
|
||||
const editCtx = getMessageEditContext();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { CollapsibleContentBlock, MarkdownContent } from '$lib/components/app';
|
||||
import { REASONING_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
import type { DatabaseMessageExtra } from '$lib/types';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
section
|
||||
}: Props = $props();
|
||||
|
||||
const currentConfig = config();
|
||||
const currentConfig = settingsStore.config;
|
||||
|
||||
const REASONING_HEADER = 'Reasoning';
|
||||
const REASONING_HEADER_PENDING = 'Reasoning...';
|
||||
|
||||
@@ -2,21 +2,7 @@
|
||||
import { ChatMessage, ChatMessageUserPending } from '$lib/components/app';
|
||||
import { setChatActionsContext } from '$lib/contexts';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import {
|
||||
agenticClearSteeringMessage,
|
||||
agenticInjectSteeringMessage,
|
||||
agenticPendingSteeringMessageContent,
|
||||
agenticPendingSteeringMessageExtras
|
||||
} from '$lib/stores/agentic.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
chatClearPendingMessage,
|
||||
chatInjectPendingMessage,
|
||||
chatPendingMessageContent,
|
||||
chatPendingMessageExtras
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import { activeConversation, conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { agenticStore, chatStore, conversationsStore, settingsStore } from '$lib/stores';
|
||||
import {
|
||||
buildSiblingInfoMap,
|
||||
copyToClipboard,
|
||||
@@ -34,7 +20,7 @@
|
||||
|
||||
let allConversationMessages = $state<DatabaseMessage[]>([]);
|
||||
|
||||
const currentConfig = config();
|
||||
const currentConfig = settingsStore.config;
|
||||
|
||||
setChatActionsContext({
|
||||
continueAssistantMessage: async (message: DatabaseMessage) => {
|
||||
@@ -108,7 +94,7 @@
|
||||
});
|
||||
|
||||
function refreshAllMessages() {
|
||||
const conversation = activeConversation();
|
||||
const conversation = conversationsStore.activeConversation;
|
||||
|
||||
if (conversation) {
|
||||
conversationsStore.getConversationMessages(conversation.id).then((messages) => {
|
||||
@@ -121,7 +107,7 @@
|
||||
|
||||
// Refresh messages whenever the active conversation changes
|
||||
$effect(() => {
|
||||
if (activeConversation()) {
|
||||
if (conversationsStore.activeConversation) {
|
||||
refreshAllMessages();
|
||||
}
|
||||
});
|
||||
@@ -251,32 +237,33 @@
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#if activeConversation() && agenticPendingSteeringMessageContent(activeConversation()!.id)}
|
||||
{@const convId = activeConversation()!.id}
|
||||
{@const pendingContent = agenticPendingSteeringMessageContent(convId)}
|
||||
{#if conversationsStore.activeConversation && agenticStore.pendingSteeringMessageContent(conversationsStore.activeConversation!.id)}
|
||||
{@const convId = conversationsStore.activeConversation!.id}
|
||||
{@const pendingContent = agenticStore.pendingSteeringMessageContent(convId)}
|
||||
|
||||
{#if pendingContent}
|
||||
<ChatMessageUserPending
|
||||
class="mx-auto mt-12 w-full max-w-[48rem]"
|
||||
content={pendingContent}
|
||||
extras={agenticPendingSteeringMessageExtras(convId)}
|
||||
extras={agenticStore.pendingSteeringMessageExtras(convId)}
|
||||
onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
|
||||
onEdit={(newContent, extras) => agenticInjectSteeringMessage(convId, newContent, extras)}
|
||||
onDelete={() => agenticClearSteeringMessage(convId)}
|
||||
onEdit={(newContent, extras) =>
|
||||
agenticStore.injectSteeringMessage(convId, newContent, extras)}
|
||||
onDelete={() => agenticStore.clearSteeringMessage(convId)}
|
||||
/>
|
||||
{/if}
|
||||
{:else if activeConversation() && chatPendingMessageContent(activeConversation()!.id)}
|
||||
{@const convId = activeConversation()!.id}
|
||||
{@const pendingContent = chatPendingMessageContent(convId)}
|
||||
{:else if conversationsStore.activeConversation && chatStore.pendingMessageContent(conversationsStore.activeConversation!.id)}
|
||||
{@const convId = conversationsStore.activeConversation!.id}
|
||||
{@const pendingContent = chatStore.pendingMessageContent(convId)}
|
||||
|
||||
{#if pendingContent}
|
||||
<ChatMessageUserPending
|
||||
class="mx-auto mt-12 w-full max-w-[48rem]"
|
||||
content={pendingContent}
|
||||
extras={chatPendingMessageExtras(convId)}
|
||||
extras={chatStore.pendingMessageExtras(convId)}
|
||||
onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
|
||||
onEdit={(newContent, extras) => chatInjectPendingMessage(convId, newContent, extras)}
|
||||
onDelete={() => chatClearPendingMessage(convId)}
|
||||
onEdit={(newContent, extras) => chatStore.injectPendingMessage(convId, newContent, extras)}
|
||||
onDelete={() => chatStore.clearPendingMessage(convId)}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -20,26 +20,20 @@
|
||||
import { useKeyboardShortcuts } from '$lib/hooks/use-keyboard-shortcuts.svelte';
|
||||
import {
|
||||
chatStore,
|
||||
errorDialog,
|
||||
isChatStreaming,
|
||||
isEditing,
|
||||
isLoading
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
activeConversation,
|
||||
activeMessages,
|
||||
conversationsStore
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import { device } from '$lib/stores/device.svelte';
|
||||
import { serverError, serverLoading } from '$lib/stores/server.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
conversationsStore,
|
||||
device,
|
||||
isMobile,
|
||||
serverStore,
|
||||
settingsStore
|
||||
} from '$lib/stores';
|
||||
import { parseFilesToMessageExtras } from '$lib/utils/browser-only';
|
||||
import { onDestroy, onMount, tick } from 'svelte';
|
||||
|
||||
let { showCenteredEmpty = false } = $props();
|
||||
|
||||
let disableAutoScroll = $derived(Boolean(config().disableAutoScroll) || isMobile.current);
|
||||
let disableAutoScroll = $derived(
|
||||
Boolean(settingsStore.config.disableAutoScroll) || isMobile.current
|
||||
);
|
||||
let isMobileUserScrolledUp = $state(false);
|
||||
let mobileScrollDownHint = $state(false);
|
||||
let mobileScrollDownHintLockedUntil = $state(0);
|
||||
@@ -48,12 +42,15 @@
|
||||
let showDeleteDialog = $state(false);
|
||||
let showEmptyFileDialog = $state(false);
|
||||
let isEmpty = $derived(
|
||||
showCenteredEmpty && !activeConversation() && activeMessages().length === 0 && !isLoading()
|
||||
showCenteredEmpty &&
|
||||
!conversationsStore.activeConversation &&
|
||||
conversationsStore.activeMessages.length === 0 &&
|
||||
!chatStore.isLoading
|
||||
);
|
||||
let activeErrorDialog = $derived(errorDialog());
|
||||
let isServerLoading = $derived(serverLoading());
|
||||
let hasPropsError = $derived(!!serverError());
|
||||
let isCurrentConversationLoading = $derived(isLoading() || isChatStreaming());
|
||||
let activeErrorDialog = $derived(chatStore.errorDialogState);
|
||||
let isServerLoading = $derived(serverStore.loading);
|
||||
let hasPropsError = $derived(!!serverStore.error);
|
||||
let isCurrentConversationLoading = $derived(chatStore.isLoading || chatStore.isStreaming());
|
||||
let chatFormBottomPosition = $derived.by(() => {
|
||||
if (!isMobile.current) return '1rem';
|
||||
|
||||
@@ -80,7 +77,7 @@
|
||||
});
|
||||
const { handleKeydown } = useKeyboardShortcuts({
|
||||
deleteActiveConversation: () => {
|
||||
if (activeConversation()) {
|
||||
if (conversationsStore.activeConversation) {
|
||||
showDeleteDialog = true;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +97,7 @@
|
||||
}
|
||||
|
||||
async function handleDeleteConfirm() {
|
||||
const conversation = activeConversation();
|
||||
const conversation = conversationsStore.activeConversation;
|
||||
|
||||
if (conversation) {
|
||||
await conversationsStore.deleteConversation(conversation.id);
|
||||
@@ -148,7 +145,7 @@
|
||||
async function handleMessagesReady(messageCount: number) {
|
||||
if (messageCount === 0) return;
|
||||
|
||||
const id = activeConversation()?.id ?? null;
|
||||
const id = conversationsStore.activeConversation?.id ?? null;
|
||||
|
||||
if (!id || id === lastScrolledConversationId) return;
|
||||
|
||||
@@ -168,7 +165,7 @@
|
||||
const settle = () => {
|
||||
if (autoScroll.userScrolledUp) return;
|
||||
|
||||
if (activeConversation()?.id !== id) return;
|
||||
if (conversationsStore.activeConversation?.id !== id) return;
|
||||
|
||||
autoScroll.scrollToBottom();
|
||||
const height = container.scrollHeight;
|
||||
@@ -246,7 +243,7 @@
|
||||
|
||||
$effect(() => {
|
||||
const shouldDisableAutoScroll =
|
||||
config().disableAutoScroll || (isMobile.current && isCurrentConversationLoading);
|
||||
settingsStore.config.disableAutoScroll || (isMobile.current && isCurrentConversationLoading);
|
||||
|
||||
autoScroll.setDisabled(shouldDisableAutoScroll);
|
||||
|
||||
@@ -310,7 +307,7 @@
|
||||
>
|
||||
{#if !isEmpty}
|
||||
<ChatMessages
|
||||
messages={activeMessages()}
|
||||
messages={conversationsStore.activeMessages}
|
||||
onMessagesReady={handleMessagesReady}
|
||||
onUserAction={() => {
|
||||
handleSendLikeScroll();
|
||||
@@ -354,7 +351,7 @@
|
||||
|
||||
<ChatScreenForm
|
||||
class="pointer-events-auto conversation-chat-form"
|
||||
disabled={hasPropsError || isEditing()}
|
||||
disabled={hasPropsError || chatStore.isEditing()}
|
||||
{initialMessage}
|
||||
isLoading={isCurrentConversationLoading}
|
||||
onFileRemove={fileUpload.handleFileRemove}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { page } from '$app/state';
|
||||
import { ChatForm } from '$lib/components/app';
|
||||
import { useDraftMessages } from '$lib/hooks/use-draft-messages.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { serverStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
isEmpty: boolean;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { AlertTriangle, Loader2, RefreshCw } from '@lucide/svelte';
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { serverError, serverLoading, serverStatus, serverStore } from '$lib/stores/server.svelte';
|
||||
import { serverStore } from '$lib/stores';
|
||||
|
||||
let hasError = $derived(!!serverError());
|
||||
let isLoadingModel = $derived(serverStatus() === 503);
|
||||
let hasError = $derived(!!serverStore.error);
|
||||
let isLoadingModel = $derived(serverStore.status === 503);
|
||||
</script>
|
||||
|
||||
{#if hasError}
|
||||
@@ -23,17 +23,17 @@
|
||||
{#if !isLoadingModel}
|
||||
<button
|
||||
onclick={() => serverStore.fetch()}
|
||||
disabled={serverLoading()}
|
||||
disabled={serverStore.loading}
|
||||
class="flex items-center gap-1.5 rounded-lg bg-destructive/20 px-2 py-1 text-xs font-medium hover:bg-destructive/30 disabled:opacity-50"
|
||||
>
|
||||
<RefreshCw class="h-3 w-3 {serverLoading() ? 'animate-spin' : ''}" />
|
||||
{serverLoading() ? 'Retrying...' : 'Retry'}
|
||||
<RefreshCw class="h-3 w-3 {serverStore.loading ? 'animate-spin' : ''}" />
|
||||
{serverStore.loading ? 'Retrying...' : 'Retry'}
|
||||
</button>
|
||||
{/if}
|
||||
</Alert.Title>
|
||||
|
||||
{#if !isLoadingModel}
|
||||
<Alert.Description>{serverError()}</Alert.Description>
|
||||
<Alert.Description>{serverStore.error}</Alert.Description>
|
||||
{/if}
|
||||
</Alert.Root>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from '@lucide/svelte';
|
||||
import { StreamConnectionState } from '$lib/enums';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { chatStore } from '$lib/stores';
|
||||
|
||||
let state = $derived(chatStore.streamConnectionState);
|
||||
</script>
|
||||
|
||||
@@ -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 @@
|
||||
<div
|
||||
bind:this={containerRef}
|
||||
onclick={handleMermaidClick}
|
||||
class="markdown-content {className}{config()[SETTINGS_KEYS.FULL_HEIGHT_CODE_BLOCKS]
|
||||
class="markdown-content {className}{settingsStore.config[SETTINGS_KEYS.FULL_HEIGHT_CODE_BLOCKS]
|
||||
? ' full-height-code-blocks'
|
||||
: ''}"
|
||||
>
|
||||
|
||||
+1
-2
@@ -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';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { 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 {
|
||||
getMentionBadgeIconPaths,
|
||||
getMentionBadgeLabel,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { DEFAULT_RESOURCE_FILENAME, MIME_TYPE_SUBSTRINGS } from '$lib/constants';
|
||||
import { MimeTypeText } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { DatabaseMessageExtraMcpResource } from '$lib/types';
|
||||
import {
|
||||
downloadResourceContent,
|
||||
|
||||
@@ -8,13 +8,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import {
|
||||
mcpResources,
|
||||
mcpResourceStore,
|
||||
mcpTotalResourceCount
|
||||
} from '$lib/stores/mcp-resources.svelte';
|
||||
import { conversationsStore, mcpResourceStore, mcpStore } from '$lib/stores';
|
||||
import type { MCPResourceContent, MCPResourceInfo, MCPResourceTemplateInfo } from '$lib/types';
|
||||
import { getResourceDisplayName } from '$lib/utils';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
@@ -39,7 +33,7 @@
|
||||
let templatePreviewLoading = $state(false);
|
||||
let templatePreviewError = $state<string | null>(null);
|
||||
|
||||
const totalCount = $derived(mcpTotalResourceCount());
|
||||
const totalCount = $derived(mcpResourceStore.totalResourceCount);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
@@ -205,7 +199,7 @@
|
||||
|
||||
function getAllResourcesFlatInTreeOrder(): MCPResourceInfo[] {
|
||||
const allResources: MCPResourceInfo[] = [];
|
||||
const resourcesMap = mcpResources();
|
||||
const resourcesMap = mcpResourceStore.serverResources;
|
||||
|
||||
for (const [serverName, serverRes] of resourcesMap.entries()) {
|
||||
for (const resource of serverRes.resources) {
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
RECOMMENDED_MCP_SERVERS
|
||||
} 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 { canonicalizeServerUrl, parseHeadersToArray, uuid } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
import { ActionIconCopyToClipboard, BadgesModality } from '$lib/components/app';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import * as Table from '$lib/components/ui/table';
|
||||
import { modelOptions, modelsLoading, modelsStore } from '$lib/stores/models.svelte';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { modelsStore, serverStore } from '$lib/stores';
|
||||
import type { ApiLlamaCppServerProps } from '$lib/types';
|
||||
import { formatFileSize, formatNumber, formatParameters } from '$lib/utils';
|
||||
|
||||
@@ -26,8 +25,8 @@
|
||||
let serverProps = $derived(isRouter && modelId ? routerModelProps : serverStore.props);
|
||||
|
||||
let modelName = $derived(isRouter && modelId ? modelId : modelsStore.singleModelName);
|
||||
let models = $derived(modelOptions());
|
||||
let isLoadingModels = $derived(modelsLoading());
|
||||
let models = $derived(modelsStore.models);
|
||||
let isLoadingModels = $derived(modelsStore.loading);
|
||||
|
||||
// in router mode, find the model option matching modelId
|
||||
// in single mode, use the first model as before
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
import { ICON_CLASS_DEFAULT, MAX_DISPLAYED_MCP_AVATARS } 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';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { MimeTypeApplication, MimeTypeText } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { MCPResourceContent, MCPResourceInfo } from '$lib/types';
|
||||
import {
|
||||
createBase64DataUrl,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { MIN_AUTOCOMPLETE_INPUT_LENGTH } from '$lib/constants';
|
||||
import { KeyboardKey } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { MCPResourceTemplateInfo } from '$lib/types';
|
||||
import {
|
||||
debounce,
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
import McpResourcesBrowserEmptyState from './McpResourcesBrowserEmptyState.svelte';
|
||||
import McpResourcesBrowserHeader from './McpResourcesBrowserHeader.svelte';
|
||||
import McpResourcesBrowserServerItem from './McpResourcesBrowserServerItem.svelte';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpResources, mcpResourcesLoading } from '$lib/stores/mcp-resources.svelte';
|
||||
import { mcpResourceStore, mcpStore } from '$lib/stores';
|
||||
import type { MCPResourceInfo, MCPResourceTemplateInfo, MCPServerResources } from '$lib/types';
|
||||
import { parseResourcePath } from '$lib/utils';
|
||||
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
||||
@@ -32,8 +31,8 @@
|
||||
let expandedFolders = new SvelteSet<string>();
|
||||
let searchQuery = $state('');
|
||||
|
||||
const resources = $derived(mcpResources());
|
||||
const isLoading = $derived(mcpResourcesLoading());
|
||||
const resources = $derived(mcpResourceStore.serverResources);
|
||||
const isLoading = $derived(mcpResourceStore.isLoading);
|
||||
|
||||
const filteredResources = $derived.by(() => {
|
||||
if (!searchQuery.trim()) {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { MCPResourceInfo, MCPResourceTemplateInfo, MCPServerResources } from '$lib/types';
|
||||
import { getDisplayName, getResourceIcon } from '$lib/utils';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { HealthCheckStatus } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { HealthCheckState, MCPServerSettingsEntry } from '$lib/types';
|
||||
import { tick } from 'svelte';
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { CLI_FLAGS, HEADERS, MCP_SERVER_URL_PLACEHOLDER } from '$lib/constants';
|
||||
import { UrlProtocol } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpStore } from '$lib/stores';
|
||||
import type { KeyValuePair } from '$lib/types';
|
||||
import { parseHeadersToArray, serializeHeaders } from '$lib/utils';
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import { Package } from '@lucide/svelte';
|
||||
import { ActionIconCopyToClipboard, BadgeInfo } from '$lib/components/app';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { modelsStore, serverStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { TruncatedText } from '$lib/components/app';
|
||||
import { ModelsService } from '$lib/services/models.service';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
modelId: string;
|
||||
@@ -32,9 +32,13 @@
|
||||
'inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-md border border-border/50 px-1 py-0 text-[10px] font-mono text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground';
|
||||
|
||||
let parsed = $derived(ModelsService.parseModelId(modelId));
|
||||
let resolvedShowRaw = $derived(showRaw ?? (config().showRawModelNames as boolean) ?? false);
|
||||
let resolvedHideQuantization = $derived(hideQuantization ?? !config().showModelQuantization);
|
||||
let resolvedHideTags = $derived(hideTags ?? !config().showModelTags);
|
||||
let resolvedShowRaw = $derived(
|
||||
showRaw ?? (settingsStore.config.showRawModelNames as boolean) ?? false
|
||||
);
|
||||
let resolvedHideQuantization = $derived(
|
||||
hideQuantization ?? !settingsStore.config.showModelQuantization
|
||||
);
|
||||
let resolvedHideTags = $derived(hideTags ?? !settingsStore.config.showModelTags);
|
||||
|
||||
let uniqueAliases = $derived([...new Set(aliases ?? [])]);
|
||||
let uniqueTags = $derived([...new Set([...(parsed.tags ?? []), ...(tags ?? [])])]);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { MODEL_SELECTOR_ICON } from '$lib/constants';
|
||||
import { KeyboardKey, ServerModelStatus } from '$lib/enums';
|
||||
import { useModelsSelector } from '$lib/hooks/use-models-selector.svelte';
|
||||
import { modelsStore, routerModels } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
import { modelLoadFraction } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -111,7 +111,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const model = routerModels().find((m) => m.id === modelId);
|
||||
const model = modelsStore.routerModels.find((m) => m.id === modelId);
|
||||
const status = model?.status?.value as ServerModelStatus | undefined;
|
||||
|
||||
if (status === ServerModelStatus.LOADING) return;
|
||||
@@ -169,7 +169,7 @@
|
||||
{@const selectedOption = ms.getDisplayOption()}
|
||||
{@const triggerModel = selectedOption?.model}
|
||||
{@const triggerStatus = triggerModel
|
||||
? routerModels().find((m) => m.id === triggerModel)?.status?.value
|
||||
? modelsStore.routerModels.find((m) => m.id === triggerModel)?.status?.value
|
||||
: undefined}
|
||||
{@const triggerLoading =
|
||||
!!triggerModel &&
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { GroupedModelOptions, ModelItem } from './utils';
|
||||
import { ModelsSelectorOption } from '$lib/components/app';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
groups: GroupedModelOptions;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import { ActionIcon, ModelId } from '$lib/components/app';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { modelsStore, routerModels } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
import type { ModelOption } from '$lib/types/models';
|
||||
import { modelLoadFraction, modelLoadProgressText } from '$lib/utils';
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
option
|
||||
}: Props = $props();
|
||||
|
||||
let currentRouterModels = $derived(routerModels());
|
||||
let currentRouterModels = $derived(modelsStore.routerModels);
|
||||
let serverStatus = $derived.by(() => {
|
||||
const model = currentRouterModels.find((m) => m.id === option.model);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import * as Sheet from '$lib/components/ui/sheet';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { useModelsSelector } from '$lib/hooks/use-models-selector.svelte';
|
||||
import { modelsStore, routerModels } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
import { modelLoadFraction } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -67,7 +67,7 @@
|
||||
{@const selectedOption = ms.getDisplayOption()}
|
||||
{@const triggerModel = selectedOption?.model}
|
||||
{@const triggerStatus = triggerModel
|
||||
? routerModels().find((m) => m.id === triggerModel)?.status?.value
|
||||
? modelsStore.routerModels.find((m) => m.id === triggerModel)?.status?.value
|
||||
: undefined}
|
||||
{@const triggerLoading =
|
||||
!!triggerModel &&
|
||||
|
||||
+9
-16
@@ -14,15 +14,8 @@
|
||||
import { useKeyboardShortcuts } from '$lib/hooks/use-keyboard-shortcuts.svelte';
|
||||
import { useMarqueeSelection } from '$lib/hooks/use-marquee-selection.svelte';
|
||||
import { RouterService } from '$lib/services/router.service';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
buildConversationTree,
|
||||
conversations,
|
||||
conversationsStore
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import { device } from '$lib/stores/device.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { chatStore, conversationsStore, device, isMobile, settingsStore } from '$lib/stores';
|
||||
import { buildConversationTree } from '$lib/utils';
|
||||
import { circIn } from 'svelte/easing';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
import { fade } from 'svelte/transition';
|
||||
@@ -44,7 +37,7 @@
|
||||
|
||||
const isStripExpanded = $derived(isExpandedMode || hoveredTooltip !== null);
|
||||
const isOnMobile = $derived(isMobile.current);
|
||||
const alwaysShowOnDesktop = $derived(config().alwaysShowSidebarOnDesktop as boolean);
|
||||
const alwaysShowOnDesktop = $derived(settingsStore.config.alwaysShowSidebarOnDesktop as boolean);
|
||||
|
||||
$effect(() => {
|
||||
if (alwaysShowOnDesktop && !isOnMobile) {
|
||||
@@ -84,7 +77,7 @@
|
||||
let filteredConversations = $derived.by(() => {
|
||||
if (isSearchModeActive) {
|
||||
if (searchQuery.trim().length > 0) {
|
||||
return conversations().filter((conversation: { name: string }) =>
|
||||
return conversationsStore.conversations.filter((conversation: { name: string }) =>
|
||||
conversation.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
}
|
||||
@@ -92,7 +85,7 @@
|
||||
return [];
|
||||
}
|
||||
|
||||
return conversations();
|
||||
return conversationsStore.conversations;
|
||||
});
|
||||
|
||||
let isSelectionMode = $state(false);
|
||||
@@ -110,7 +103,7 @@
|
||||
const allSelectedArePinned = $derived.by(() => {
|
||||
if (selectedIds.size === 0) return false;
|
||||
|
||||
const convs = conversations();
|
||||
const convs = conversationsStore.conversations;
|
||||
|
||||
for (const id of selectedIds) {
|
||||
const c = convs.find((conv) => conv.id === id);
|
||||
@@ -124,7 +117,7 @@
|
||||
const pinStateIsMixed = $derived.by(() => {
|
||||
if (selectedIds.size === 0) return false;
|
||||
|
||||
const convs = conversations();
|
||||
const convs = conversationsStore.conversations;
|
||||
|
||||
let anyPinned = false;
|
||||
let anyUnpinned = false;
|
||||
@@ -242,7 +235,7 @@
|
||||
}
|
||||
|
||||
async function handleEditConversation(id: string) {
|
||||
const conversation = conversations().find((conv) => conv.id === id);
|
||||
const conversation = conversationsStore.conversations.find((conv) => conv.id === id);
|
||||
|
||||
if (!conversation) return;
|
||||
|
||||
@@ -275,7 +268,7 @@
|
||||
}
|
||||
|
||||
async function handleDeleteConversation(id: string) {
|
||||
const conversation = conversations().find((conv) => conv.id === id);
|
||||
const conversation = conversationsStore.conversations.find((conv) => conv.id === id);
|
||||
|
||||
if (!conversation) return;
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
SIDEBAR_ACTIONS_ITEMS
|
||||
} from '$lib/constants';
|
||||
import { TooltipSide } from '$lib/enums';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import type { Component } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { circIn } from 'svelte/easing';
|
||||
|
||||
+2
-3
@@ -17,8 +17,7 @@
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
import { FORK_TREE_DEPTH_PADDING, ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { RouterService } from '$lib/services/router.service';
|
||||
import { getAllLoadingChats } from '$lib/stores/chat.svelte';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { chatStore, conversationsStore } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -56,7 +55,7 @@
|
||||
let renderActionsDropdown = $state(false);
|
||||
let dropdownOpen = $state(false);
|
||||
|
||||
let isLoading = $derived(getAllLoadingChats().includes(conversation.id));
|
||||
let isLoading = $derived(chatStore.getAllLoadingChats().includes(conversation.id));
|
||||
|
||||
function handleEdit(event: Event) {
|
||||
event.stopPropagation();
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
import SidebarNavigationSearchResults from './SidebarNavigationSearchResults.svelte';
|
||||
import SidebarNavigationSelectionBar from './SidebarNavigationSelectionBar.svelte';
|
||||
import { Pin } from '@lucide/svelte';
|
||||
import { buildConversationTree } from '$lib/stores/conversations.svelte';
|
||||
import { buildConversationTree } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import SidebarNavigationConversationItem from './SidebarNavigationConversationItem.svelte';
|
||||
import { buildConversationTree } from '$lib/stores/conversations.svelte';
|
||||
import { buildConversationTree } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { HEADERS, ICON_CLASS_DEFAULT, ROUTES, SETTINGS_KEYS } from '$lib/constants';
|
||||
import { KeyboardKey } from '$lib/enums';
|
||||
import { serverLoading, serverStore } from '$lib/stores/server.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { serverStore, settingsStore } from '$lib/stores';
|
||||
import { fade, fly, scale } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
@@ -27,7 +26,7 @@
|
||||
showTroubleshooting = false
|
||||
}: Props = $props();
|
||||
|
||||
let isServerLoading = $derived(serverLoading());
|
||||
let isServerLoading = $derived(serverStore.loading);
|
||||
let isAccessDeniedError = $derived(
|
||||
error.toLowerCase().includes('access denied') ||
|
||||
error.toLowerCase().includes('invalid api key') ||
|
||||
@@ -52,7 +51,7 @@
|
||||
function handleShowApiKeyInput() {
|
||||
showApiKeyInput = true;
|
||||
// Pre-fill with current API key if it exists
|
||||
const currentConfig = config();
|
||||
const currentConfig = settingsStore.config;
|
||||
|
||||
apiKeyInput = currentConfig.apiKey?.toString() || '';
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { singleModelName } from '$lib/stores/models.svelte';
|
||||
import { serverError, serverLoading, serverProps } from '$lib/stores/server.svelte';
|
||||
import { modelsStore, serverStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
@@ -13,10 +12,10 @@
|
||||
|
||||
let { class: className = '', showActions = false }: Props = $props();
|
||||
|
||||
let error = $derived(serverError());
|
||||
let loading = $derived(serverLoading());
|
||||
let model = $derived(singleModelName());
|
||||
let serverData = $derived(serverProps());
|
||||
let error = $derived(serverStore.error);
|
||||
let loading = $derived(serverStore.loading);
|
||||
let model = $derived(modelsStore.singleModelName);
|
||||
let serverData = $derived(serverStore.props);
|
||||
|
||||
function getStatusColor() {
|
||||
if (loading) return 'bg-yellow-500';
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
import { setChatSettingsConfigContext } from '$lib/contexts';
|
||||
import { ColorMode } from '$lib/enums/ui.enums';
|
||||
import { RouterService } from '$lib/services/router.service';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { settingsReferrer } from '$lib/stores/settings-referrer.svelte';
|
||||
import { modelsStore, serverStore, settingsReferrer, settingsStore } from '$lib/stores';
|
||||
import type { SettingsSection } from '$lib/types';
|
||||
import { setMode } from 'mode-watcher';
|
||||
import { fade } from 'svelte/transition';
|
||||
@@ -43,14 +40,14 @@
|
||||
SETTINGS_CHAT_SECTIONS[0]
|
||||
);
|
||||
|
||||
let localConfig: SettingsConfigType = $state({ ...config() });
|
||||
let localConfig: SettingsConfigType = $state({ ...settingsStore.config });
|
||||
|
||||
let mobileHeader: { updateCarousel: () => void } | undefined;
|
||||
|
||||
let fetchInitiated = false;
|
||||
|
||||
$effect(() => {
|
||||
if (isRouterMode() && currentSection.fields && !fetchInitiated) {
|
||||
if (serverStore.isRouterMode && currentSection.fields && !fetchInitiated) {
|
||||
fetchInitiated = true;
|
||||
|
||||
void modelsStore
|
||||
@@ -71,7 +68,7 @@
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
localConfig = { ...config() };
|
||||
localConfig = { ...settingsStore.config };
|
||||
setMode(localConfig.theme as ColorMode);
|
||||
mobileHeader?.updateCarousel();
|
||||
}
|
||||
@@ -123,7 +120,7 @@
|
||||
}
|
||||
|
||||
export function reset() {
|
||||
localConfig = { ...config() };
|
||||
localConfig = { ...settingsStore.config };
|
||||
}
|
||||
|
||||
setChatSettingsConfigContext({
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import { ICON_CLASS_DEFAULT, SETTING_CONFIG_INFO, SETTINGS_KEYS } from '$lib/constants';
|
||||
import { SettingsFieldType } from '$lib/enums/settings.enums';
|
||||
import { modelsStore, propsCacheVersion, selectedModelName } from '$lib/stores/models.svelte';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { modelsStore, serverStore, settingsStore } from '$lib/stores';
|
||||
import { normalizeFloatingPoint } from '$lib/utils/precision';
|
||||
import type { Component } from 'svelte';
|
||||
|
||||
@@ -25,10 +23,10 @@
|
||||
let { fields, localConfig, onConfigChange, onThemeChange }: Props = $props();
|
||||
|
||||
let currentModelParams = $derived.by(() => {
|
||||
propsCacheVersion();
|
||||
void modelsStore.propsCacheVersion;
|
||||
|
||||
if (serverStore.isRouterMode) {
|
||||
const currentModelName = selectedModelName();
|
||||
const currentModelName = modelsStore.selectedModelName;
|
||||
|
||||
if (currentModelName) {
|
||||
const currentModelProps = modelsStore.getModelProps(currentModelName);
|
||||
|
||||
+3
-4
@@ -8,8 +8,7 @@
|
||||
} from '$lib/components/app';
|
||||
import SettingsGroup from '$lib/components/app/settings/SettingsGroup.svelte';
|
||||
import { ConversationSelectionMode, FileExtensionText, HtmlInputType } from '$lib/enums';
|
||||
import { conversations, conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { conversationsStore, settingsStore } from '$lib/stores';
|
||||
import { createMessageCountMap } from '$lib/utils';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { toast } from 'svelte-sonner';
|
||||
@@ -112,7 +111,7 @@
|
||||
|
||||
async function handleExportClick() {
|
||||
try {
|
||||
const allConversations = conversations();
|
||||
const allConversations = conversationsStore.conversations;
|
||||
|
||||
if (allConversations.length === 0) {
|
||||
toast.info('No conversations to export');
|
||||
@@ -231,7 +230,7 @@
|
||||
|
||||
async function handleDeleteAllClick() {
|
||||
try {
|
||||
const allConversations = conversations();
|
||||
const allConversations = conversationsStore.conversations;
|
||||
|
||||
if (allConversations.length === 0) {
|
||||
toast.info('No conversations to delete');
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||
import { ICON_CLASS_DEFAULT } from '$lib/constants';
|
||||
import { ToolSource } from '$lib/enums/tools.enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { permissionsStore } from '$lib/stores/permissions.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { mcpStore, permissionsStore, toolsStore } from '$lib/stores';
|
||||
import { getBuiltinToolUi } from '$lib/utils';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { RotateCcw } from '@lucide/svelte';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
onReset?: () => void;
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
import * as Empty from '$lib/components/ui/empty';
|
||||
import { ROUTES } from '$lib/constants';
|
||||
import { HealthCheckStatus } from '$lib/enums';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { conversationsStore, mcpStore, toolsStore } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user