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,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}` } : {};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user