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:
Aleksander Grygier
2026-08-13 08:11:30 +02:00
committed by GitHub
parent a6040c925c
commit 094e53db1c
116 changed files with 937 additions and 945 deletions
+2 -2
View File
@@ -1,14 +1,14 @@
import { redactValue } from './redact';
import { CORS_PROXY, HEADERS } from '$lib/constants';
import { MimeTypeApplication } from '$lib/enums';
import { config } from '$lib/stores/settings.svelte';
import { settingsStore } from '$lib/stores/settings.svelte';
/**
* Get authorization headers for API requests
* Includes Bearer token if API key is configured
*/
export function getAuthHeaders(): Record<string, string> {
const currentConfig = config();
const currentConfig = settingsStore.config;
const apiKey = currentConfig.apiKey?.toString().trim();
return apiKey ? { [HEADERS.AUTHORIZATION]: `${HEADERS.BEARER}${apiKey}` } : {};
+2 -2
View File
@@ -3,7 +3,7 @@ import { browser } from '$app/environment';
import { base } from '$app/paths';
import { HEADERS } from '$lib/constants';
import { MimeTypeApplication } from '$lib/enums';
import { config } from '$lib/stores/settings.svelte';
import { settingsStore } from '$lib/stores/settings.svelte';
/**
* Validates API key by making a request to the server props endpoint
@@ -14,7 +14,7 @@ export async function validateApiKey(fetch: typeof globalThis.fetch): Promise<vo
return;
}
const apiKey = config().apiKey;
const apiKey = settingsStore.config.apiKey;
try {
const headers: Record<string, string> = {
@@ -29,3 +29,73 @@ export function createMessageCountMap(
export function getMessageCount(conversationId: string, countMap: Map<string, number>): number {
return countMap.get(conversationId) ?? 0;
}
export interface ConversationTreeItem {
conversation: DatabaseConversation;
depth: number;
}
// Pinned conversations first, then by lastModified descending
const comparePinnedThenRecent = (a: DatabaseConversation, b: DatabaseConversation) => {
if (a.pinned && !b.pinned) return -1;
if (!a.pinned && b.pinned) return 1;
return b.lastModified - a.lastModified;
};
/**
* Builds a flat tree of conversations with depth levels for nested forks.
* Accepts a pre-filtered list so search filtering stays in the component.
*
* Output order matches the sidebar render exactly: pinned first, then
* unpinned by lastModified desc, with forks interleaved under their parents.
* Range-select / marquee in the sidebar rely on this alignment.
*/
export function buildConversationTree(convs: DatabaseConversation[]): ConversationTreeItem[] {
const childrenByParent = new Map<string, DatabaseConversation[]>();
const forkIds = new Set<string>();
for (const conv of convs) {
if (conv.forkedFromConversationId) {
forkIds.add(conv.id);
const siblings = childrenByParent.get(conv.forkedFromConversationId) || [];
siblings.push(conv);
childrenByParent.set(conv.forkedFromConversationId, siblings);
}
}
const result: ConversationTreeItem[] = [];
const visited = new Set<string>();
function walk(conv: DatabaseConversation, depth: number) {
visited.add(conv.id);
result.push({ conversation: conv, depth });
const children = childrenByParent.get(conv.id);
if (children) {
children.sort(comparePinnedThenRecent);
for (const child of children) {
walk(child, depth + 1);
}
}
}
const roots = convs.filter((c) => !forkIds.has(c.id)).sort(comparePinnedThenRecent);
for (const root of roots) {
walk(root, 0);
}
for (const conv of convs) {
if (!visited.has(conv.id)) {
walk(conv, 1);
}
}
return result;
}
@@ -5,7 +5,7 @@ import { isWebpMimeType, webpBase64UrlToPngDataURL } from './webp-to-png';
import { SETTINGS_KEYS } from '$lib/constants';
import { AttachmentType, FileTypeCategory, SpecialFileType } from '$lib/enums';
import { modelsStore } from '$lib/stores/models.svelte';
import { config, settingsStore } from '$lib/stores/settings.svelte';
import { settingsStore } from '$lib/stores/settings.svelte';
import type { ChatUploadedFile, DatabaseMessageExtra, FileProcessingResult } from '$lib/types';
import { getFileTypeCategory } from '$lib/utils';
import { toast } from 'svelte-sonner';
@@ -109,7 +109,7 @@ export async function parseFilesToMessageExtras(
try {
// Always get base64 data for preview functionality
const base64Data = await readFileAsBase64(file.file);
const currentConfig = config();
const currentConfig = settingsStore.config;
// Use per-model vision check for router mode
const hasVisionSupport = activeModelId
? modelsStore.modelSupportsVision(activeModelId)
+20 -5
View File
@@ -9,7 +9,7 @@
// API utilities
export { getAuthHeaders, getJsonHeaders, sanitizeHeaders } from './api-headers';
export { apiFetch, apiFetchWithParams, apiPost, type ApiFetchOptions } from './api-fetch';
export { ApiError, apiFetch, apiFetchWithParams, apiPost } from './api-fetch';
export { validateApiKey } from './api-key-validation';
// Attachment utilities
@@ -51,7 +51,12 @@ export { extractRootDomain, sanitizeExternalUrl, canonicalizeServerUrl } from '.
export { modelLoadFraction, modelLoadProgressText } from './progress';
// Conversation utilities
export { createMessageCountMap, getMessageCount } from './conversation-utils';
export {
createMessageCountMap,
getMessageCount,
buildConversationTree,
type ConversationTreeItem
} from './conversation-utils';
// Clipboard utilities
export {
@@ -124,7 +129,10 @@ export { getImageErrorFallbackHtml } from './image-error-fallback';
// SSE-with-JSON stream iterator (used by built-in tool streaming, decoupled
// from chat.service.ts which embeds its own SSE parser for resume support)
export { parseSseJsonStream, type SseJsonEvent } from './sse';
export { parseSseJsonStream } from './sse';
// Stream session identity (conversation-id based)
export { streamIdentity } from './stream-identity';
// MCP utilities
export {
@@ -236,6 +244,12 @@ export {
buildMentionInsertion
} from './mention-badge';
// Chat template utilities
export {
detectThinkingSupport,
detectThinkingSupportWithReason
} from './chat-template-thinking-detector';
// Agentic content utilities (structured section derivation)
export {
deriveAgenticSections,
@@ -243,7 +257,8 @@ export {
parseToolResultWithMedia,
splitSearchSummaryList,
hasAgenticContent,
classifyToolResult
classifyToolResult,
classifyContinueIntent
} from './agentic';
// Line-level unified diff for tool result rendering (`edit_file` block)
@@ -270,7 +285,7 @@ export {
} from './search-results';
// Cache utilities
export { TTLCache, ReactiveTTLMap, type TTLCacheOptions } from './cache-ttl';
export { TTLCache, ReactiveTTLMap } from './cache-ttl';
// Redaction utilities
export { redactValue } from './redact';