refactor: Services/Stores syntax + logic improvements
Refactors components to access stores directly instead of using exported getter functions. This change centralizes store access and logic, simplifying component code and improving maintainability by reducing the number of exported functions and promoting direct store interaction. Removes exported getter functions from `chat.svelte.ts`, `conversations.svelte.ts`, `models.svelte.ts` and `settings.svelte.ts`.
This commit is contained in:
parent
69065ddc56
commit
6a3d6e79d2
|
|
@ -9,16 +9,9 @@
|
|||
} from '$lib/components/app';
|
||||
import { INPUT_CLASSES } from '$lib/constants/input-classes';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import {
|
||||
modelOptions,
|
||||
selectedModelId,
|
||||
isRouterMode,
|
||||
fetchModelProps,
|
||||
getModelProps,
|
||||
modelSupportsVision,
|
||||
modelSupportsAudio
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { getConversationModel } from '$lib/stores/chat.svelte';
|
||||
import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte';
|
||||
import { isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { activeMessages } from '$lib/stores/conversations.svelte';
|
||||
import {
|
||||
FileTypeCategory,
|
||||
|
|
@ -77,7 +70,9 @@
|
|||
let textareaRef: ChatFormTextarea | undefined = $state(undefined);
|
||||
|
||||
// Check if model is selected (in ROUTER mode)
|
||||
let conversationModel = $derived(getConversationModel(activeMessages() as DatabaseMessage[]));
|
||||
let conversationModel = $derived(
|
||||
chatStore.getConversationModel(activeMessages() as DatabaseMessage[])
|
||||
);
|
||||
let isRouter = $derived(isRouterMode());
|
||||
let hasModelSelected = $derived(!isRouter || !!conversationModel || !!selectedModelId());
|
||||
|
||||
|
|
@ -109,9 +104,9 @@
|
|||
// Fetch model props when active model changes
|
||||
$effect(() => {
|
||||
if (isRouter && activeModelId) {
|
||||
const cached = getModelProps(activeModelId);
|
||||
const cached = modelsStore.getModelProps(activeModelId);
|
||||
if (!cached) {
|
||||
fetchModelProps(activeModelId).then(() => {
|
||||
modelsStore.fetchModelProps(activeModelId).then(() => {
|
||||
modelPropsVersion++;
|
||||
});
|
||||
}
|
||||
|
|
@ -122,7 +117,7 @@
|
|||
let hasAudioModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsAudio(activeModelId);
|
||||
return modelsStore.modelSupportsAudio(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -130,7 +125,7 @@
|
|||
let hasVisionModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsVision(activeModelId);
|
||||
return modelsStore.modelSupportsVision(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,17 +10,9 @@
|
|||
import { FileTypeCategory } from '$lib/enums';
|
||||
import { getFileTypeCategory } from '$lib/utils/file-type';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import {
|
||||
modelOptions,
|
||||
selectedModelId,
|
||||
selectModelByName,
|
||||
isRouterMode,
|
||||
fetchModelProps,
|
||||
getModelProps,
|
||||
modelSupportsVision,
|
||||
modelSupportsAudio
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { getConversationModel } from '$lib/stores/chat.svelte';
|
||||
import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte';
|
||||
import { isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { activeMessages } from '$lib/stores/conversations.svelte';
|
||||
import type { ChatUploadedFile } from '$lib/types/chat';
|
||||
|
||||
|
|
@ -53,14 +45,16 @@
|
|||
let currentConfig = $derived(config());
|
||||
let isRouter = $derived(isRouterMode());
|
||||
|
||||
let conversationModel = $derived(getConversationModel(activeMessages() as DatabaseMessage[]));
|
||||
let conversationModel = $derived(
|
||||
chatStore.getConversationModel(activeMessages() as DatabaseMessage[])
|
||||
);
|
||||
|
||||
let previousConversationModel: string | null = null;
|
||||
|
||||
$effect(() => {
|
||||
if (conversationModel && conversationModel !== previousConversationModel) {
|
||||
previousConversationModel = conversationModel;
|
||||
selectModelByName(conversationModel);
|
||||
modelsStore.selectModelByName(conversationModel);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -92,10 +86,10 @@
|
|||
$effect(() => {
|
||||
if (isRouter && activeModelId) {
|
||||
// Check if we already have cached props
|
||||
const cached = getModelProps(activeModelId);
|
||||
const cached = modelsStore.getModelProps(activeModelId);
|
||||
if (!cached) {
|
||||
// Fetch props for this model
|
||||
fetchModelProps(activeModelId).then(() => {
|
||||
modelsStore.fetchModelProps(activeModelId).then(() => {
|
||||
// Trigger reactivity update
|
||||
modelPropsVersion++;
|
||||
});
|
||||
|
|
@ -107,7 +101,7 @@
|
|||
let hasAudioModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsAudio(activeModelId);
|
||||
return modelsStore.modelSupportsAudio(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -115,7 +109,7 @@
|
|||
let hasVisionModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsVision(activeModelId);
|
||||
return modelsStore.modelSupportsVision(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { getDeletionInfo } from '$lib/stores/chat.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { copyToClipboard } from '$lib/utils/copy';
|
||||
import { isIMEComposing } from '$lib/utils/is-ime-composing';
|
||||
import type { ApiChatCompletionToolCall } from '$lib/types/api';
|
||||
|
|
@ -98,7 +98,7 @@
|
|||
}
|
||||
|
||||
async function handleDelete() {
|
||||
deletionInfo = await getDeletionInfo(message.id);
|
||||
deletionInfo = await chatStore.getDeletionInfo(message.id);
|
||||
showDeleteDialog = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { selectModel } from '$lib/stores/models.svelte';
|
||||
import { modelsStore } from '$lib/stores/models.svelte';
|
||||
import { copyToClipboard } from '$lib/utils/copy';
|
||||
import type { ApiChatCompletionToolCall } from '$lib/types/api';
|
||||
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
async function handleModelChange(modelId: string, modelName: string) {
|
||||
try {
|
||||
await selectModel(modelId);
|
||||
await modelsStore.selectModelById(modelId);
|
||||
|
||||
// Pass the selected model name for regeneration
|
||||
onRegenerate(modelName);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { ChatMessage } from '$lib/components/app';
|
||||
import { DatabaseService } from '$lib/services/database';
|
||||
import {
|
||||
continueAssistantMessage,
|
||||
deleteMessage,
|
||||
editAssistantMessage,
|
||||
editMessageWithBranching,
|
||||
editUserMessagePreserveResponses,
|
||||
regenerateMessageWithBranching
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import { activeConversation, navigateToSibling } from '$lib/stores/conversations.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { conversationsStore, activeConversation } from '$lib/stores/conversations.svelte';
|
||||
import { getMessageSiblings } from '$lib/utils/branching';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -64,13 +57,13 @@
|
|||
});
|
||||
|
||||
async function handleNavigateToSibling(siblingId: string) {
|
||||
await navigateToSibling(siblingId);
|
||||
await conversationsStore.navigateToSibling(siblingId);
|
||||
}
|
||||
|
||||
async function handleEditWithBranching(message: DatabaseMessage, newContent: string) {
|
||||
onUserAction?.();
|
||||
|
||||
await editMessageWithBranching(message.id, newContent);
|
||||
await chatStore.editMessageWithBranching(message.id, newContent);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
|
@ -82,7 +75,7 @@
|
|||
) {
|
||||
onUserAction?.();
|
||||
|
||||
await editAssistantMessage(message.id, newContent, shouldBranch);
|
||||
await chatStore.editAssistantMessage(message.id, newContent, shouldBranch);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
|
@ -90,7 +83,7 @@
|
|||
async function handleRegenerateWithBranching(message: DatabaseMessage, modelOverride?: string) {
|
||||
onUserAction?.();
|
||||
|
||||
await regenerateMessageWithBranching(message.id, modelOverride);
|
||||
await chatStore.regenerateMessageWithBranching(message.id, modelOverride);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
|
@ -98,7 +91,7 @@
|
|||
async function handleContinueAssistantMessage(message: DatabaseMessage) {
|
||||
onUserAction?.();
|
||||
|
||||
await continueAssistantMessage(message.id);
|
||||
await chatStore.continueAssistantMessage(message.id);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
|
@ -109,13 +102,13 @@
|
|||
) {
|
||||
onUserAction?.();
|
||||
|
||||
await editUserMessagePreserveResponses(message.id, newContent);
|
||||
await chatStore.editUserMessagePreserveResponses(message.id, newContent);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
||||
async function handleDeleteMessage(message: DatabaseMessage) {
|
||||
await deleteMessage(message.id);
|
||||
await chatStore.deleteMessage(message.id);
|
||||
|
||||
refreshAllMessages();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,30 +16,15 @@
|
|||
AUTO_SCROLL_INTERVAL,
|
||||
INITIAL_SCROLL_DELAY
|
||||
} from '$lib/constants/auto-scroll';
|
||||
import { chatStore, errorDialog, isLoading } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
dismissErrorDialog,
|
||||
errorDialog,
|
||||
isLoading,
|
||||
sendMessage,
|
||||
stopGeneration
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
conversationsStore,
|
||||
activeMessages,
|
||||
activeConversation,
|
||||
deleteConversation
|
||||
activeConversation
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { serverLoading, serverError, serverStore } from '$lib/stores/server.svelte';
|
||||
import {
|
||||
modelOptions,
|
||||
selectedModelId,
|
||||
isRouterMode,
|
||||
fetchModelProps,
|
||||
getModelProps,
|
||||
modelSupportsVision,
|
||||
modelSupportsAudio
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { getConversationModel } from '$lib/stores/chat.svelte';
|
||||
import { serverLoading, serverError, serverStore, isRouterMode } from '$lib/stores/server.svelte';
|
||||
import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte';
|
||||
import { parseFilesToMessageExtras } from '$lib/utils/convert-files-to-extra';
|
||||
import { isFileTypeSupported } from '$lib/utils/file-type';
|
||||
import { filterFilesByModalities } from '$lib/utils/modality-file-validation';
|
||||
|
|
@ -93,7 +78,9 @@
|
|||
|
||||
// Model-specific capability detection (same logic as ChatFormActions)
|
||||
let isRouter = $derived(isRouterMode());
|
||||
let conversationModel = $derived(getConversationModel(activeMessages() as DatabaseMessage[]));
|
||||
let conversationModel = $derived(
|
||||
chatStore.getConversationModel(activeMessages() as DatabaseMessage[])
|
||||
);
|
||||
|
||||
// Get active model ID for fetching props
|
||||
let activeModelId = $derived.by(() => {
|
||||
|
|
@ -123,9 +110,9 @@
|
|||
// Fetch model props when active model changes
|
||||
$effect(() => {
|
||||
if (isRouter && activeModelId) {
|
||||
const cached = getModelProps(activeModelId);
|
||||
const cached = modelsStore.getModelProps(activeModelId);
|
||||
if (!cached) {
|
||||
fetchModelProps(activeModelId).then(() => {
|
||||
modelsStore.fetchModelProps(activeModelId).then(() => {
|
||||
modelPropsVersion++;
|
||||
});
|
||||
}
|
||||
|
|
@ -136,7 +123,7 @@
|
|||
let hasAudioModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsAudio(activeModelId);
|
||||
return modelsStore.modelSupportsAudio(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -144,7 +131,7 @@
|
|||
let hasVisionModality = $derived.by(() => {
|
||||
if (activeModelId) {
|
||||
void modelPropsVersion; // Trigger reactivity on props fetch
|
||||
return modelSupportsVision(activeModelId);
|
||||
return modelsStore.modelSupportsVision(activeModelId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -152,7 +139,7 @@
|
|||
async function handleDeleteConfirm() {
|
||||
const conversation = activeConversation();
|
||||
if (conversation) {
|
||||
await deleteConversation(conversation.id);
|
||||
await conversationsStore.deleteConversation(conversation.id);
|
||||
}
|
||||
showDeleteDialog = false;
|
||||
}
|
||||
|
|
@ -175,7 +162,7 @@
|
|||
|
||||
function handleErrorDialogOpenChange(open: boolean) {
|
||||
if (!open) {
|
||||
dismissErrorDialog();
|
||||
chatStore.dismissErrorDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +249,7 @@
|
|||
userScrolledUp = false;
|
||||
autoScrollEnabled = true;
|
||||
}
|
||||
await sendMessage(message, extras);
|
||||
await chatStore.sendMessage(message, extras);
|
||||
scrollChatToBottom();
|
||||
|
||||
return true;
|
||||
|
|
@ -420,7 +407,7 @@
|
|||
onFileRemove={handleFileRemove}
|
||||
onFileUpload={handleFileUpload}
|
||||
onSend={handleSendMessage}
|
||||
onStop={() => stopGeneration()}
|
||||
onStop={() => chatStore.stopGeneration()}
|
||||
showHelperText={false}
|
||||
bind:uploadedFiles
|
||||
/>
|
||||
|
|
@ -480,7 +467,7 @@
|
|||
onFileRemove={handleFileRemove}
|
||||
onFileUpload={handleFileUpload}
|
||||
onSend={handleSendMessage}
|
||||
onStop={() => stopGeneration()}
|
||||
onStop={() => chatStore.stopGeneration()}
|
||||
showHelperText={true}
|
||||
bind:uploadedFiles
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -2,13 +2,7 @@
|
|||
import { untrack } from 'svelte';
|
||||
import { PROCESSING_INFO_TIMEOUT } from '$lib/constants/processing-info';
|
||||
import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
|
||||
import {
|
||||
isLoading,
|
||||
isChatStreaming,
|
||||
clearProcessingState,
|
||||
setActiveProcessingConversation,
|
||||
restoreProcessingStateFromMessages
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import { chatStore, isLoading, isChatStreaming } from '$lib/stores/chat.svelte';
|
||||
import { activeMessages, activeConversation } from '$lib/stores/conversations.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
|
||||
|
|
@ -26,7 +20,7 @@
|
|||
$effect(() => {
|
||||
const conversation = activeConversation();
|
||||
|
||||
untrack(() => setActiveProcessingConversation(conversation?.id ?? null));
|
||||
untrack(() => chatStore.setActiveProcessingConversation(conversation?.id ?? null));
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
|
|
@ -55,12 +49,12 @@
|
|||
|
||||
if (keepStatsVisible && conversation) {
|
||||
if (messages.length === 0) {
|
||||
untrack(() => clearProcessingState(conversation.id));
|
||||
untrack(() => chatStore.clearProcessingState(conversation.id));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentConversationLoading && !isStreaming) {
|
||||
untrack(() => restoreProcessingStateFromMessages(messages, conversation.id));
|
||||
untrack(() => chatStore.restoreProcessingStateFromMessages(messages, conversation.id));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
ChatSettingsFields
|
||||
} from '$lib/components/app';
|
||||
import { ScrollArea } from '$lib/components/ui/scroll-area';
|
||||
import { config, updateMultipleConfig } from '$lib/stores/settings.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { setMode } from 'mode-watcher';
|
||||
import type { Component } from 'svelte';
|
||||
|
||||
|
|
@ -333,7 +333,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
updateMultipleConfig(processedConfig);
|
||||
settingsStore.updateMultipleConfig(processedConfig);
|
||||
onSave?.();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import { SETTING_CONFIG_DEFAULT, SETTING_CONFIG_INFO } from '$lib/constants/settings-config';
|
||||
import { supportsVision } from '$lib/stores/server.svelte';
|
||||
import { getParameterInfo, resetParameterToServerDefault } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { ParameterSyncService } from '$lib/services/parameter-sync';
|
||||
import { ChatSettingsParameterSourceIndicator } from '$lib/components/app';
|
||||
import type { Component } from 'svelte';
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
return getParameterInfo(key);
|
||||
return settingsStore.getParameterInfo(key);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
resetParameterToServerDefault(field.key);
|
||||
settingsStore.resetParameterToServerDefault(field.key);
|
||||
// Trigger UI update by calling onConfigChange with the default value
|
||||
const defaultValue = propsDefault ?? SETTING_CONFIG_DEFAULT[field.key];
|
||||
onConfigChange(field.key, String(defaultValue));
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
resetParameterToServerDefault(field.key);
|
||||
settingsStore.resetParameterToServerDefault(field.key);
|
||||
// Trigger UI update by calling onConfigChange with the default value
|
||||
const defaultValue = propsDefault ?? SETTING_CONFIG_DEFAULT[field.key];
|
||||
onConfigChange(field.key, String(defaultValue));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { forceSyncWithServerDefaults } from '$lib/stores/settings.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { RotateCcw } from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
}
|
||||
|
||||
function handleConfirmReset() {
|
||||
forceSyncWithServerDefaults();
|
||||
settingsStore.forceSyncWithServerDefaults();
|
||||
onReset?.();
|
||||
|
||||
showResetDialog = false;
|
||||
|
|
|
|||
|
|
@ -7,11 +7,7 @@
|
|||
import * as Sidebar from '$lib/components/ui/sidebar';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import Input from '$lib/components/ui/input/input.svelte';
|
||||
import {
|
||||
conversations,
|
||||
deleteConversation,
|
||||
updateConversationName
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import { conversationsStore, conversations } from '$lib/stores/conversations.svelte';
|
||||
import ChatSidebarActions from './ChatSidebarActions.svelte';
|
||||
|
||||
const sidebar = Sidebar.useSidebar();
|
||||
|
|
@ -56,7 +52,7 @@
|
|||
showDeleteDialog = false;
|
||||
|
||||
setTimeout(() => {
|
||||
deleteConversation(selectedConversation.id);
|
||||
conversationsStore.deleteConversation(selectedConversation.id);
|
||||
selectedConversation = null;
|
||||
}, 100); // Wait for animation to finish
|
||||
}
|
||||
|
|
@ -67,7 +63,7 @@
|
|||
|
||||
showEditDialog = false;
|
||||
|
||||
updateConversationName(selectedConversation.id, editedName);
|
||||
conversationsStore.updateConversationName(selectedConversation.id, editedName);
|
||||
selectedConversation = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { Trash2, Pencil, MoreHorizontal, Download, Loader2 } from '@lucide/svelte';
|
||||
import { ActionDropdown } from '$lib/components/app';
|
||||
import { getAllLoadingChats } from '$lib/stores/chat.svelte';
|
||||
import { downloadConversation } from '$lib/stores/conversations.svelte';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
label: 'Export',
|
||||
onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
downloadConversation(conversation.id);
|
||||
conversationsStore.downloadConversation(conversation.id);
|
||||
},
|
||||
shortcut: ['shift', 'cmd', 's']
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,15 +4,12 @@
|
|||
import { cn } from '$lib/components/ui/utils';
|
||||
import { portalToBody } from '$lib/utils/portal-to-body';
|
||||
import {
|
||||
fetchModels,
|
||||
modelsStore,
|
||||
modelOptions,
|
||||
modelsLoading,
|
||||
modelsUpdating,
|
||||
selectModel,
|
||||
selectedModelId,
|
||||
unloadModel,
|
||||
routerModels,
|
||||
loadModel
|
||||
routerModels
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { isRouterMode, serverStore } from '$lib/stores/server.svelte';
|
||||
|
|
@ -89,7 +86,7 @@
|
|||
|
||||
onMount(async () => {
|
||||
try {
|
||||
await fetchModels();
|
||||
await modelsStore.fetch();
|
||||
} catch (error) {
|
||||
console.error('Unable to load models:', error);
|
||||
}
|
||||
|
|
@ -261,13 +258,13 @@
|
|||
onModelChange(option.id, option.model);
|
||||
} else {
|
||||
// Update global selection
|
||||
await selectModel(option.id);
|
||||
await modelsStore.selectModelById(option.id);
|
||||
}
|
||||
|
||||
// Load the model if not already loaded (router mode)
|
||||
if (isRouter && getModelStatus(option.model) !== ServerModelStatus.LOADED) {
|
||||
try {
|
||||
await loadModel(option.model);
|
||||
await modelsStore.loadModel(option.model);
|
||||
} catch (error) {
|
||||
console.error('Failed to load model:', error);
|
||||
}
|
||||
|
|
@ -438,7 +435,7 @@
|
|||
class="relative ml-2 flex h-4 w-4 shrink-0 items-center justify-center"
|
||||
onclick={(e) => {
|
||||
e.stopPropagation();
|
||||
unloadModel(option.model);
|
||||
modelsStore.unloadModel(option.model);
|
||||
}}
|
||||
title="Unload model"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import { Input } from '$lib/components/ui/input';
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { serverStore, serverLoading } from '$lib/stores/server.svelte';
|
||||
import { config, updateConfig } from '$lib/stores/settings.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { fade, fly, scale } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
try {
|
||||
// Update the API key in settings first
|
||||
updateConfig('apiKey', apiKeyInput.trim());
|
||||
settingsStore.updateConfig('apiKey', apiKeyInput.trim());
|
||||
|
||||
// Test the API key by making a real request to the server
|
||||
const response = await fetch('./props', {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface UseProcessingStateReturn {
|
|||
* useProcessingState - Reactive processing state hook
|
||||
*
|
||||
* This hook provides reactive access to the processing state of the server.
|
||||
* It directly reads from ChatStore's reactive state and provides
|
||||
* It directly reads from chatStore's reactive state and provides
|
||||
* formatted processing details for UI display.
|
||||
*
|
||||
* **Features:**
|
||||
|
|
@ -30,7 +30,7 @@ export function useProcessingState(): UseProcessingStateReturn {
|
|||
let isMonitoring = $state(false);
|
||||
let lastKnownState = $state<ApiProcessingState | null>(null);
|
||||
|
||||
// Derive processing state reactively from ChatStore's direct state
|
||||
// Derive processing state reactively from chatStore's direct state
|
||||
const processingState = $derived.by(() => {
|
||||
if (!isMonitoring) {
|
||||
return lastKnownState;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ import type { SettingsChatServiceOptions } from '$lib/types/settings';
|
|||
* - Converts database messages to API format
|
||||
* - Handles error translation for server responses
|
||||
*
|
||||
* - **ChatStore**: Uses ChatService for all AI model communication
|
||||
* - **ConversationsStore**: Provides message context for API requests
|
||||
* - **chatStore**: Uses ChatService for all AI model communication
|
||||
* - **conversationsStore**: Provides message context for API requests
|
||||
*
|
||||
* **Key Responsibilities:**
|
||||
* - Message format conversion (DatabaseMessage → API format)
|
||||
|
|
@ -67,7 +67,7 @@ export class ChatService {
|
|||
* @returns {Promise<string | void>} that resolves to the complete response string (non-streaming) or void (streaming)
|
||||
* @throws {Error} if the request fails or is aborted
|
||||
*/
|
||||
async sendMessage(
|
||||
static async sendMessage(
|
||||
messages: ApiChatMessageData[] | (DatabaseMessage & { extra?: DatabaseMessageExtra[] })[],
|
||||
options: SettingsChatServiceOptions = {},
|
||||
conversationId?: string,
|
||||
|
|
@ -130,7 +130,7 @@ export class ChatService {
|
|||
return true;
|
||||
});
|
||||
|
||||
const processedMessages = this.injectSystemMessage(normalizedMessages);
|
||||
const processedMessages = ChatService.injectSystemMessage(normalizedMessages);
|
||||
|
||||
const requestBody: ApiChatCompletionRequest = {
|
||||
messages: processedMessages.map((msg: ApiChatMessageData) => ({
|
||||
|
|
@ -200,7 +200,7 @@ export class ChatService {
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await this.parseErrorResponse(response);
|
||||
const error = await ChatService.parseErrorResponse(response);
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
|
|
@ -208,7 +208,7 @@ export class ChatService {
|
|||
}
|
||||
|
||||
if (stream) {
|
||||
await this.handleStreamResponse(
|
||||
await ChatService.handleStreamResponse(
|
||||
response,
|
||||
onChunk,
|
||||
onComplete,
|
||||
|
|
@ -222,7 +222,7 @@ export class ChatService {
|
|||
);
|
||||
return;
|
||||
} else {
|
||||
return this.handleNonStreamResponse(
|
||||
return ChatService.handleNonStreamResponse(
|
||||
response,
|
||||
onComplete,
|
||||
onError,
|
||||
|
|
@ -276,7 +276,7 @@ export class ChatService {
|
|||
* @returns {Promise<void>} Promise that resolves when streaming is complete
|
||||
* @throws {Error} if the stream cannot be read or parsed
|
||||
*/
|
||||
private async handleStreamResponse(
|
||||
private static async handleStreamResponse(
|
||||
response: Response,
|
||||
onChunk?: (chunk: string) => void,
|
||||
onComplete?: (
|
||||
|
|
@ -323,7 +323,7 @@ export class ChatService {
|
|||
return;
|
||||
}
|
||||
|
||||
aggregatedToolCalls = this.mergeToolCallDeltas(
|
||||
aggregatedToolCalls = ChatService.mergeToolCallDeltas(
|
||||
aggregatedToolCalls,
|
||||
toolCalls,
|
||||
toolCallIndexOffset
|
||||
|
|
@ -378,14 +378,14 @@ export class ChatService {
|
|||
const timings = parsed.timings;
|
||||
const promptProgress = parsed.prompt_progress;
|
||||
|
||||
const chunkModel = this.extractModelName(parsed);
|
||||
const chunkModel = ChatService.extractModelName(parsed);
|
||||
if (chunkModel && !modelEmitted) {
|
||||
modelEmitted = true;
|
||||
onModel?.(chunkModel);
|
||||
}
|
||||
|
||||
if (timings || promptProgress) {
|
||||
this.notifyTimings(timings, promptProgress, onTimings);
|
||||
ChatService.notifyTimings(timings, promptProgress, onTimings);
|
||||
if (timings) {
|
||||
lastTimings = timings;
|
||||
}
|
||||
|
|
@ -453,7 +453,7 @@ export class ChatService {
|
|||
* @returns {Promise<string>} Promise that resolves to the generated content string
|
||||
* @throws {Error} if the response cannot be parsed or is malformed
|
||||
*/
|
||||
private async handleNonStreamResponse(
|
||||
private static async handleNonStreamResponse(
|
||||
response: Response,
|
||||
onComplete?: (
|
||||
response: string,
|
||||
|
|
@ -475,7 +475,7 @@ export class ChatService {
|
|||
|
||||
const data: ApiChatCompletionResponse = JSON.parse(responseText);
|
||||
|
||||
const responseModel = this.extractModelName(data);
|
||||
const responseModel = ChatService.extractModelName(data);
|
||||
if (responseModel) {
|
||||
onModel?.(responseModel);
|
||||
}
|
||||
|
|
@ -491,7 +491,7 @@ export class ChatService {
|
|||
let serializedToolCalls: string | undefined;
|
||||
|
||||
if (toolCalls && toolCalls.length > 0) {
|
||||
const mergedToolCalls = this.mergeToolCallDeltas([], toolCalls);
|
||||
const mergedToolCalls = ChatService.mergeToolCallDeltas([], toolCalls);
|
||||
|
||||
if (mergedToolCalls.length > 0) {
|
||||
serializedToolCalls = JSON.stringify(mergedToolCalls);
|
||||
|
|
@ -527,7 +527,7 @@ export class ChatService {
|
|||
* @param indexOffset - Optional offset to apply to the index of new tool calls
|
||||
* @returns {ApiChatCompletionToolCall[]} The merged array of tool calls
|
||||
*/
|
||||
private mergeToolCallDeltas(
|
||||
private static mergeToolCallDeltas(
|
||||
existing: ApiChatCompletionToolCall[],
|
||||
deltas: ApiChatCompletionToolCallDelta[],
|
||||
indexOffset = 0
|
||||
|
|
@ -736,7 +736,7 @@ export class ChatService {
|
|||
* @returns Array of messages with system message injected at the beginning if configured
|
||||
* @private
|
||||
*/
|
||||
private injectSystemMessage(messages: ApiChatMessageData[]): ApiChatMessageData[] {
|
||||
private static injectSystemMessage(messages: ApiChatMessageData[]): ApiChatMessageData[] {
|
||||
const currentConfig = config();
|
||||
const systemMessage = currentConfig.systemMessage?.toString().trim();
|
||||
|
||||
|
|
@ -770,7 +770,7 @@ export class ChatService {
|
|||
* @param response - HTTP response object
|
||||
* @returns Promise<Error> - Parsed error with context info if available
|
||||
*/
|
||||
private async parseErrorResponse(response: Response): Promise<Error> {
|
||||
private static async parseErrorResponse(response: Response): Promise<Error> {
|
||||
try {
|
||||
const errorText = await response.text();
|
||||
const errorData: ApiErrorResponse = JSON.parse(errorText);
|
||||
|
|
@ -798,7 +798,7 @@ export class ChatService {
|
|||
* @returns Model name string if found, undefined otherwise
|
||||
* @private
|
||||
*/
|
||||
private extractModelName(data: unknown): string | undefined {
|
||||
private static extractModelName(data: unknown): string | undefined {
|
||||
// WORKAROUND: In single model mode, use model name from props instead of API response
|
||||
// because llama-server returns `gpt-3.5-turbo` value in the `model` field
|
||||
const isRouter = isRouterMode();
|
||||
|
|
@ -849,7 +849,7 @@ export class ChatService {
|
|||
* @param onTimingsCallback - Callback function to invoke with timing data
|
||||
* @private
|
||||
*/
|
||||
private notifyTimings(
|
||||
private static notifyTimings(
|
||||
timings: ChatMessageTimings | undefined,
|
||||
promptProgress: ChatMessagePromptProgress | undefined,
|
||||
onTimingsCallback:
|
||||
|
|
@ -860,5 +860,3 @@ export class ChatService {
|
|||
onTimingsCallback(timings, promptProgress);
|
||||
}
|
||||
}
|
||||
|
||||
export const chatService = new ChatService();
|
||||
|
|
|
|||
|
|
@ -42,12 +42,12 @@ import { v4 as uuid } from 'uuid';
|
|||
* - Uses DatabaseService for all persistence operations
|
||||
* - Adds import/export, navigation, and higher-level operations
|
||||
*
|
||||
* - **ConversationsStore**: Reactive state management for conversations
|
||||
* - **conversationsStore**: Reactive state management for conversations
|
||||
* - Uses ConversationsService for database operations
|
||||
* - Manages conversation list, active conversation, and messages in memory
|
||||
*
|
||||
* - **ChatStore**: Active AI interaction management
|
||||
* - Uses ConversationsStore for conversation context
|
||||
* - **chatStore**: Active AI interaction management
|
||||
* - Uses conversationsStore for conversation context
|
||||
* - Directly uses DatabaseService for message CRUD during streaming
|
||||
*
|
||||
* **Key Features:**
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
export { chatService } from './chat';
|
||||
export { ChatService } from './chat';
|
||||
export { DatabaseService } from './database';
|
||||
export { ModelsService } from './models';
|
||||
export { PropsService } from './props';
|
||||
export { ParameterSyncService } from './parameter-sync';
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import type {
|
|||
* - Check model status (ROUTER mode)
|
||||
*
|
||||
* **Used by:**
|
||||
* - ModelsStore: Primary consumer for model state management
|
||||
* - modelsStore: Primary consumer for model state management
|
||||
*/
|
||||
export class ModelsService {
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { getAuthHeaders } from '$lib/utils/api-headers';
|
|||
* - Parse and validate server response
|
||||
*
|
||||
* **Used by:**
|
||||
* - ServerStore: Primary consumer for server state management
|
||||
* - serverStore: Primary consumer for server state management
|
||||
*/
|
||||
export class PropsService {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { DatabaseService } from '$lib/services/database';
|
||||
import { chatService } from '$lib/services';
|
||||
import { DatabaseService, ChatService } from '$lib/services';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { contextSize } from '$lib/stores/server.svelte';
|
||||
|
|
@ -16,27 +15,27 @@ import type {
|
|||
import type { DatabaseMessage, DatabaseMessageExtra } from '$lib/types/database';
|
||||
|
||||
/**
|
||||
* ChatStore - Active AI interaction and streaming state management
|
||||
* chatStore - Active AI interaction and streaming state management
|
||||
*
|
||||
* **Terminology - Chat vs Conversation:**
|
||||
* - **Chat**: The active interaction space with the Chat Completions API. Represents the
|
||||
* real-time streaming session, loading states, and UI visualization of AI communication.
|
||||
* A "chat" is ephemeral - it exists only while the user is actively interacting with the AI.
|
||||
* - **Conversation**: The persistent database entity storing all messages and metadata.
|
||||
* Managed by ConversationsStore, conversations persist across sessions and page reloads.
|
||||
* Managed by conversationsStore, conversations persist across sessions and page reloads.
|
||||
*
|
||||
* This store manages all active AI interactions including real-time streaming, response
|
||||
* generation, and per-chat loading states. It handles the runtime layer between UI and
|
||||
* AI backend, supporting concurrent streaming across multiple conversations.
|
||||
*
|
||||
* **Architecture & Relationships:**
|
||||
* - **ChatStore** (this class): Active AI session and streaming management
|
||||
* - **chatStore** (this class): Active AI session and streaming management
|
||||
* - Manages real-time AI response streaming via ChatService
|
||||
* - Tracks per-chat loading and streaming states for concurrent sessions
|
||||
* - Handles message operations (send, edit, regenerate, branch)
|
||||
* - Coordinates with ConversationsStore for persistence
|
||||
* - Coordinates with conversationsStore for persistence
|
||||
*
|
||||
* - **ConversationsStore**: Provides conversation data and message arrays for chat context
|
||||
* - **conversationsStore**: Provides conversation data and message arrays for chat context
|
||||
* - **ChatService**: Low-level API communication with llama.cpp server
|
||||
* - **DatabaseService**: Message persistence and retrieval
|
||||
*
|
||||
|
|
@ -501,7 +500,7 @@ class ChatStore {
|
|||
|
||||
const abortController = this.getOrCreateAbortController(assistantMessage.convId);
|
||||
|
||||
await chatService.sendMessage(
|
||||
await ChatService.sendMessage(
|
||||
allMessages,
|
||||
{
|
||||
...this.getApiOptions(),
|
||||
|
|
@ -1140,7 +1139,7 @@ class ChatStore {
|
|||
|
||||
const abortController = this.getOrCreateAbortController(msg.convId);
|
||||
|
||||
await chatService.sendMessage(
|
||||
await ChatService.sendMessage(
|
||||
contextWithContinue,
|
||||
{
|
||||
...this.getApiOptions(),
|
||||
|
|
@ -1244,8 +1243,6 @@ class ChatStore {
|
|||
}
|
||||
}
|
||||
|
||||
// ============ Public Methods for Per-Conversation State ============
|
||||
|
||||
public isChatLoadingPublic(convId: string): boolean {
|
||||
return this.isChatLoading(convId);
|
||||
}
|
||||
|
|
@ -1264,57 +1261,13 @@ class ChatStore {
|
|||
|
||||
export const chatStore = new ChatStore();
|
||||
|
||||
// ChatStore state exports
|
||||
export const isLoading = () => chatStore.isLoading;
|
||||
export const currentResponse = () => chatStore.currentResponse;
|
||||
export const errorDialog = () => chatStore.errorDialogState;
|
||||
export const activeProcessingState = () => chatStore.activeProcessingState;
|
||||
export const isChatStreaming = () => chatStore.isStreaming();
|
||||
|
||||
// ChatStore method exports
|
||||
export const sendMessage = chatStore.sendMessage.bind(chatStore);
|
||||
export const dismissErrorDialog = chatStore.dismissErrorDialog.bind(chatStore);
|
||||
export function stopGeneration() {
|
||||
chatStore.stopGeneration();
|
||||
}
|
||||
|
||||
// Message operations
|
||||
export const updateMessage = chatStore.updateMessage.bind(chatStore);
|
||||
export const regenerateMessage = chatStore.regenerateMessage.bind(chatStore);
|
||||
export const deleteMessage = chatStore.deleteMessage.bind(chatStore);
|
||||
export const getDeletionInfo = chatStore.getDeletionInfo.bind(chatStore);
|
||||
|
||||
// Branching operations
|
||||
export const editAssistantMessage = chatStore.editAssistantMessage.bind(chatStore);
|
||||
export const editUserMessagePreserveResponses =
|
||||
chatStore.editUserMessagePreserveResponses.bind(chatStore);
|
||||
export const editMessageWithBranching = chatStore.editMessageWithBranching.bind(chatStore);
|
||||
export const regenerateMessageWithBranching =
|
||||
chatStore.regenerateMessageWithBranching.bind(chatStore);
|
||||
export const continueAssistantMessage = chatStore.continueAssistantMessage.bind(chatStore);
|
||||
|
||||
// Per-conversation state access
|
||||
export const isChatLoading = (convId: string) => chatStore.isChatLoadingPublic(convId);
|
||||
export const getChatStreaming = (convId: string) => chatStore.getChatStreamingPublic(convId);
|
||||
export const getAllLoadingChats = () => chatStore.getAllLoadingChats();
|
||||
export const getAllStreamingChats = () => chatStore.getAllStreamingChats();
|
||||
|
||||
// Sync/clear UI state when switching conversations
|
||||
export const syncLoadingStateForChat = chatStore.syncLoadingStateForChat.bind(chatStore);
|
||||
export const clearUIState = chatStore.clearUIState.bind(chatStore);
|
||||
|
||||
// Processing state (timing/context info)
|
||||
export const getProcessingState = chatStore.getProcessingState.bind(chatStore);
|
||||
export const getActiveProcessingState = chatStore.getActiveProcessingState.bind(chatStore);
|
||||
export const activeProcessingState = () => chatStore.activeProcessingState;
|
||||
export const getCurrentProcessingStateSync =
|
||||
chatStore.getCurrentProcessingStateSync.bind(chatStore);
|
||||
export const restoreProcessingStateFromMessages =
|
||||
chatStore.restoreProcessingStateFromMessages.bind(chatStore);
|
||||
export const clearProcessingState = chatStore.clearProcessingState.bind(chatStore);
|
||||
export const updateProcessingStateFromTimings =
|
||||
chatStore.updateProcessingStateFromTimings.bind(chatStore);
|
||||
export const setActiveProcessingConversation =
|
||||
chatStore.setActiveProcessingConversation.bind(chatStore);
|
||||
export const isChatStreaming = () => chatStore.isStreaming();
|
||||
|
||||
// Model detection
|
||||
export const getConversationModel = chatStore.getConversationModel.bind(chatStore);
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import type {
|
|||
} from '$lib/types/database';
|
||||
|
||||
/**
|
||||
* ConversationsStore - Persistent conversation data and lifecycle management
|
||||
* conversationsStore - Persistent conversation data and lifecycle management
|
||||
*
|
||||
* **Terminology - Chat vs Conversation:**
|
||||
* - **Chat**: The active interaction space with the Chat Completions API. Represents the
|
||||
* real-time streaming session, loading states, and UI visualization of AI communication.
|
||||
* Managed by ChatStore, a "chat" is ephemeral and exists during active AI interactions.
|
||||
* Managed by chatStore, a "chat" is ephemeral and exists during active AI interactions.
|
||||
* - **Conversation**: The persistent database entity storing all messages and metadata.
|
||||
* A "conversation" survives across sessions, page reloads, and browser restarts.
|
||||
* It contains the complete message history, branching structure, and conversation metadata.
|
||||
|
|
@ -26,13 +26,13 @@ import type {
|
|||
* conversation with its message history, providing reactive state for UI components.
|
||||
*
|
||||
* **Architecture & Relationships:**
|
||||
* - **ConversationsStore** (this class): Persistent conversation data management
|
||||
* - **conversationsStore** (this class): Persistent conversation data management
|
||||
* - Manages conversation list and active conversation state
|
||||
* - Handles conversation CRUD operations via DatabaseService
|
||||
* - Maintains active message array for current conversation
|
||||
* - Coordinates branching navigation (currNode tracking)
|
||||
*
|
||||
* - **ChatStore**: Uses conversation data as context for active AI streaming
|
||||
* - **chatStore**: Uses conversation data as context for active AI streaming
|
||||
* - **DatabaseService**: Low-level IndexedDB storage for conversations and messages
|
||||
*
|
||||
* **Key Features:**
|
||||
|
|
@ -148,7 +148,7 @@ class ConversationsStore {
|
|||
clearActiveConversation(): void {
|
||||
this.activeConversation = null;
|
||||
this.activeMessages = [];
|
||||
// Active processing conversation is now managed by ChatStore
|
||||
// Active processing conversation is now managed by chatStore
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -448,7 +448,7 @@ class ConversationsStore {
|
|||
|
||||
/**
|
||||
* Adds a message to the active messages array
|
||||
* Used by ChatStore when creating new messages
|
||||
* Used by chatStore when creating new messages
|
||||
* @param message - The message to add
|
||||
*/
|
||||
addMessageToActive(message: DatabaseMessage): void {
|
||||
|
|
@ -499,6 +499,8 @@ class ConversationsStore {
|
|||
|
||||
/**
|
||||
* Triggers file download in browser
|
||||
* @param data - The data to download
|
||||
* @param filename - Optional filename for the download
|
||||
*/
|
||||
private triggerDownload(data: ExportedConversations, filename?: string): void {
|
||||
const conversation =
|
||||
|
|
@ -531,27 +533,7 @@ class ConversationsStore {
|
|||
|
||||
export const conversationsStore = new ConversationsStore();
|
||||
|
||||
// Export getter functions for reactive access
|
||||
export const conversations = () => conversationsStore.conversations;
|
||||
export const activeConversation = () => conversationsStore.activeConversation;
|
||||
export const activeMessages = () => conversationsStore.activeMessages;
|
||||
export const isConversationsInitialized = () => conversationsStore.isInitialized;
|
||||
|
||||
// Export conversation operations
|
||||
export const createConversation = conversationsStore.createConversation.bind(conversationsStore);
|
||||
export const loadConversation = conversationsStore.loadConversation.bind(conversationsStore);
|
||||
export const deleteConversation = conversationsStore.deleteConversation.bind(conversationsStore);
|
||||
export const clearActiveConversation =
|
||||
conversationsStore.clearActiveConversation.bind(conversationsStore);
|
||||
export const updateConversationName =
|
||||
conversationsStore.updateConversationName.bind(conversationsStore);
|
||||
export const downloadConversation =
|
||||
conversationsStore.downloadConversation.bind(conversationsStore);
|
||||
export const exportAllConversations =
|
||||
conversationsStore.exportAllConversations.bind(conversationsStore);
|
||||
export const importConversations = conversationsStore.importConversations.bind(conversationsStore);
|
||||
export const navigateToSibling = conversationsStore.navigateToSibling.bind(conversationsStore);
|
||||
export const refreshActiveMessages =
|
||||
conversationsStore.refreshActiveMessages.bind(conversationsStore);
|
||||
export const setTitleUpdateConfirmationCallback =
|
||||
conversationsStore.setTitleUpdateConfirmationCallback.bind(conversationsStore);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { SvelteSet } from 'svelte/reactivity';
|
||||
import { ModelsService } from '$lib/services/models';
|
||||
import { PropsService } from '$lib/services/props';
|
||||
import { ServerModelStatus, ServerRole } from '$lib/enums';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import type { ModelOption, ModelModalities } from '$lib/types/models';
|
||||
import type { ApiModelDataEntry } from '$lib/types/api';
|
||||
|
||||
/**
|
||||
* ModelsStore - Reactive store for model management in both MODEL and ROUTER modes
|
||||
* modelsStore - Reactive store for model management in both MODEL and ROUTER modes
|
||||
*
|
||||
* This store manages:
|
||||
* - Available models list
|
||||
|
|
@ -18,8 +19,8 @@ import type { ApiModelDataEntry } from '$lib/types/api';
|
|||
* **Architecture & Relationships:**
|
||||
* - **ModelsService**: Stateless service for model API communication
|
||||
* - **PropsService**: Stateless service for props/modalities fetching
|
||||
* - **ModelsStore** (this class): Reactive store for model state
|
||||
* - **ConversationsStore**: Tracks which conversations use which models
|
||||
* - **modelsStore** (this class): Reactive store for model state
|
||||
* - **conversationsStore**: Tracks which conversations use which models
|
||||
*
|
||||
* **API Inconsistency Workaround:**
|
||||
* In MODEL mode, `/props` returns modalities for the single model.
|
||||
|
|
@ -48,13 +49,6 @@ class ModelsStore {
|
|||
private modelUsage = $state<Map<string, SvelteSet<string>>>(new Map());
|
||||
private modelLoadingStates = $state<Map<string, boolean>>(new Map());
|
||||
|
||||
/**
|
||||
* Server role detection - determines API behavior
|
||||
* In ROUTER mode, modalities come from /props?model=<id>
|
||||
* In MODEL mode, modalities come from /props (single model)
|
||||
*/
|
||||
serverRole = $state<ServerRole | null>(null);
|
||||
|
||||
/**
|
||||
* Model-specific props cache
|
||||
* Key: modelId, Value: props data including modalities
|
||||
|
|
@ -83,14 +77,6 @@ class ModelsStore {
|
|||
.map(([id]) => id);
|
||||
}
|
||||
|
||||
get isRouterMode(): boolean {
|
||||
return this.serverRole === ServerRole.ROUTER;
|
||||
}
|
||||
|
||||
get isModelMode(): boolean {
|
||||
return this.serverRole === ServerRole.MODEL;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Methods - Model Modalities
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
|
@ -189,10 +175,10 @@ class ModelsStore {
|
|||
this.error = null;
|
||||
|
||||
try {
|
||||
// Fetch server props to detect role and get modalities for MODEL mode
|
||||
const serverProps = await PropsService.fetch();
|
||||
this.serverRole =
|
||||
serverProps.role === ServerRole.ROUTER ? ServerRole.ROUTER : ServerRole.MODEL;
|
||||
// Ensure server props are loaded (for role detection and MODEL mode modalities)
|
||||
if (!serverStore.props) {
|
||||
await serverStore.fetch();
|
||||
}
|
||||
|
||||
const response = await ModelsService.list();
|
||||
|
||||
|
|
@ -216,10 +202,11 @@ class ModelsStore {
|
|||
|
||||
this.models = models;
|
||||
|
||||
// In MODEL mode, populate modalities from /props (single model)
|
||||
// In MODEL mode, populate modalities from serverStore.props (single model)
|
||||
// WORKAROUND: In MODEL mode, /props returns modalities for the single model,
|
||||
// but /v1/models doesn't include modalities. We bridge this gap here.
|
||||
if (this.isModelMode && this.models.length > 0 && serverProps.modalities) {
|
||||
const serverProps = serverStore.props;
|
||||
if (serverStore.isModelMode && this.models.length > 0 && serverProps?.modalities) {
|
||||
const modalities: ModelModalities = {
|
||||
vision: serverProps.modalities.vision ?? false,
|
||||
audio: serverProps.modalities.audio ?? false
|
||||
|
|
@ -347,7 +334,7 @@ class ModelsStore {
|
|||
/**
|
||||
* Select a model for new conversations
|
||||
*/
|
||||
async select(modelId: string): Promise<void> {
|
||||
async selectModelById(modelId: string): Promise<void> {
|
||||
if (!modelId || this.updating) return;
|
||||
if (this.selectedModelId === modelId) return;
|
||||
|
||||
|
|
@ -581,7 +568,6 @@ class ModelsStore {
|
|||
this.error = null;
|
||||
this.selectedModelId = null;
|
||||
this.selectedModelName = null;
|
||||
this.serverRole = null;
|
||||
this.modelUsage.clear();
|
||||
this.modelLoadingStates.clear();
|
||||
this.modelPropsCache.clear();
|
||||
|
|
@ -591,10 +577,6 @@ class ModelsStore {
|
|||
|
||||
export const modelsStore = new ModelsStore();
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Reactive Getters
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const modelOptions = () => modelsStore.models;
|
||||
export const routerModels = () => modelsStore.routerModels;
|
||||
export const modelsLoading = () => modelsStore.loading;
|
||||
|
|
@ -605,34 +587,3 @@ export const selectedModelName = () => modelsStore.selectedModelName;
|
|||
export const selectedModelOption = () => modelsStore.selectedModel;
|
||||
export const loadedModelIds = () => modelsStore.loadedModelIds;
|
||||
export const loadingModelIds = () => modelsStore.loadingModelIds;
|
||||
export const isRouterMode = () => modelsStore.isRouterMode;
|
||||
export const isModelMode = () => modelsStore.isModelMode;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Actions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const fetchModels = modelsStore.fetch.bind(modelsStore);
|
||||
export const fetchRouterModels = modelsStore.fetchRouterModels.bind(modelsStore);
|
||||
export const fetchModalitiesForLoadedModels =
|
||||
modelsStore.fetchModalitiesForLoadedModels.bind(modelsStore);
|
||||
export const updateModelModalities = modelsStore.updateModelModalities.bind(modelsStore);
|
||||
export const selectModel = modelsStore.select.bind(modelsStore);
|
||||
export const loadModel = modelsStore.loadModel.bind(modelsStore);
|
||||
export const unloadModel = modelsStore.unloadModel.bind(modelsStore);
|
||||
export const ensureModelLoaded = modelsStore.ensureModelLoaded.bind(modelsStore);
|
||||
export const registerModelUsage = modelsStore.registerModelUsage.bind(modelsStore);
|
||||
export const unregisterModelUsage = modelsStore.unregisterModelUsage.bind(modelsStore);
|
||||
export const clearConversationUsage = modelsStore.clearConversationUsage.bind(modelsStore);
|
||||
export const selectModelByName = modelsStore.selectModelByName.bind(modelsStore);
|
||||
export const clearModelSelection = modelsStore.clearSelection.bind(modelsStore);
|
||||
export const findModelByName = modelsStore.findModelByName.bind(modelsStore);
|
||||
export const findModelById = modelsStore.findModelById.bind(modelsStore);
|
||||
export const hasModel = modelsStore.hasModel.bind(modelsStore);
|
||||
|
||||
// Model modalities
|
||||
export const getModelModalities = modelsStore.getModelModalities.bind(modelsStore);
|
||||
export const modelSupportsVision = modelsStore.modelSupportsVision.bind(modelsStore);
|
||||
export const modelSupportsAudio = modelsStore.modelSupportsAudio.bind(modelsStore);
|
||||
export const fetchModelProps = modelsStore.fetchModelProps.bind(modelsStore);
|
||||
export const getModelProps = modelsStore.getModelProps.bind(modelsStore);
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@ import { PropsService } from '$lib/services/props';
|
|||
import { ServerRole, ModelModality } from '$lib/enums';
|
||||
|
||||
/**
|
||||
* ServerStore - Server connection state, configuration, and role detection
|
||||
* serverStore - Server connection state, configuration, and role detection
|
||||
*
|
||||
* This store manages the server connection state and properties fetched from `/props`.
|
||||
* It provides reactive state for server configuration and role detection.
|
||||
*
|
||||
* **Architecture & Relationships:**
|
||||
* - **PropsService**: Stateless service for fetching `/props` data
|
||||
* - **ServerStore** (this class): Reactive store for server state
|
||||
* - **ModelsStore**: Independent store for model management (uses PropsService directly)
|
||||
* - **serverStore** (this class): Reactive store for server state
|
||||
* - **modelsStore**: Independent store for model management (uses PropsService directly)
|
||||
*
|
||||
* **Key Features:**
|
||||
* - **Server State**: Connection status, loading, error handling
|
||||
|
|
@ -18,7 +18,7 @@ import { ServerRole, ModelModality } from '$lib/enums';
|
|||
* - **Default Params**: Server-wide generation defaults
|
||||
*
|
||||
* **Note on Modalities:**
|
||||
* Model-specific modalities (vision, audio) are now managed by ModelsStore.
|
||||
* Model-specific modalities (vision, audio) are now managed by modelsStore.
|
||||
* Use `modelsStore.getModelModalities(modelId)` for per-model modality info.
|
||||
* The `supportsVision`/`supportsAudio` getters here are deprecated and only
|
||||
* apply to MODEL mode (single model).
|
||||
|
|
@ -30,10 +30,6 @@ class ServerStore {
|
|||
role = $state<ServerRole | null>(null);
|
||||
private fetchPromise: Promise<void> | null = null;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Computed Getters
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Get model name from server props.
|
||||
* In MODEL mode: extracts from model_path or model_alias
|
||||
|
|
@ -93,10 +89,6 @@ class ServerStore {
|
|||
return this.role === ServerRole.MODEL;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Server Role Detection
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private detectRole(props: ApiLlamaCppServerProps): void {
|
||||
const newRole = props?.role === ServerRole.ROUTER ? ServerRole.ROUTER : ServerRole.MODEL;
|
||||
if (this.role !== newRole) {
|
||||
|
|
@ -105,10 +97,6 @@ class ServerStore {
|
|||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Fetch Server Properties
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
async fetch(): Promise<void> {
|
||||
if (this.fetchPromise) return this.fetchPromise;
|
||||
|
||||
|
|
@ -134,10 +122,6 @@ class ServerStore {
|
|||
await fetchPromise;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Error Handling
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
const message = error.message || '';
|
||||
|
|
@ -163,11 +147,6 @@ class ServerStore {
|
|||
|
||||
return 'Failed to connect to server';
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Clear State
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
clear(): void {
|
||||
this.props = null;
|
||||
this.error = null;
|
||||
|
|
@ -179,10 +158,6 @@ class ServerStore {
|
|||
|
||||
export const serverStore = new ServerStore();
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Reactive Getters (for use in components)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const serverProps = () => serverStore.props;
|
||||
export const serverLoading = () => serverStore.loading;
|
||||
export const serverError = () => serverStore.error;
|
||||
|
|
@ -196,6 +171,3 @@ export const defaultParams = () => serverStore.defaultParams;
|
|||
export const contextSize = () => serverStore.contextSize;
|
||||
export const isRouterMode = () => serverStore.isRouterMode;
|
||||
export const isModelMode = () => serverStore.isModelMode;
|
||||
|
||||
// Actions
|
||||
export const fetchServerProps = serverStore.fetch.bind(serverStore);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
* SettingsStore - Application configuration and theme management
|
||||
* settingsStore - Application configuration and theme management
|
||||
*
|
||||
* This store manages all application settings including AI model parameters, UI preferences,
|
||||
* and theme configuration. It provides persistent storage through localStorage with reactive
|
||||
* state management using Svelte 5 runes.
|
||||
*
|
||||
* **Architecture & Relationships:**
|
||||
* - **SettingsStore** (this class): Configuration state management
|
||||
* - **settingsStore** (this class): Configuration state management
|
||||
* - Manages AI model parameters (temperature, max tokens, etc.)
|
||||
* - Handles theme switching and persistence
|
||||
* - Provides localStorage synchronization
|
||||
|
|
@ -378,28 +378,8 @@ class SettingsStore {
|
|||
}
|
||||
}
|
||||
|
||||
// Create and export the settings store instance
|
||||
export const settingsStore = new SettingsStore();
|
||||
|
||||
// Export reactive getters for easy access in components
|
||||
export const config = () => settingsStore.config;
|
||||
export const theme = () => settingsStore.theme;
|
||||
export const isInitialized = () => settingsStore.isInitialized;
|
||||
|
||||
// Export bound methods for easy access
|
||||
export const updateConfig = settingsStore.updateConfig.bind(settingsStore);
|
||||
export const updateMultipleConfig = settingsStore.updateMultipleConfig.bind(settingsStore);
|
||||
export const updateTheme = settingsStore.updateTheme.bind(settingsStore);
|
||||
export const resetConfig = settingsStore.resetConfig.bind(settingsStore);
|
||||
export const resetTheme = settingsStore.resetTheme.bind(settingsStore);
|
||||
export const resetAll = settingsStore.resetAll.bind(settingsStore);
|
||||
export const getConfig = settingsStore.getConfig.bind(settingsStore);
|
||||
export const getAllConfig = settingsStore.getAllConfig.bind(settingsStore);
|
||||
export const syncWithServerDefaults = settingsStore.syncWithServerDefaults.bind(settingsStore);
|
||||
export const forceSyncWithServerDefaults =
|
||||
settingsStore.forceSyncWithServerDefaults.bind(settingsStore);
|
||||
export const getParameterInfo = settingsStore.getParameterInfo.bind(settingsStore);
|
||||
export const resetParameterToServerDefault =
|
||||
settingsStore.resetParameterToServerDefault.bind(settingsStore);
|
||||
export const getParameterDiff = settingsStore.getParameterDiff.bind(settingsStore);
|
||||
export const clearAllUserOverrides = settingsStore.clearAllUserOverrides.bind(settingsStore);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
import { untrack } from 'svelte';
|
||||
import { ChatSidebar, DialogConversationTitleUpdate } from '$lib/components/app';
|
||||
import { isLoading } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
activeMessages,
|
||||
setTitleUpdateConfirmationCallback
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import { conversationsStore, activeMessages } from '$lib/stores/conversations.svelte';
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import { isRouterMode, serverStore } from '$lib/stores/server.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
|
|
@ -158,14 +155,16 @@
|
|||
|
||||
// Set up title update confirmation callback
|
||||
$effect(() => {
|
||||
setTitleUpdateConfirmationCallback(async (currentTitle: string, newTitle: string) => {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
titleUpdateCurrentTitle = currentTitle;
|
||||
titleUpdateNewTitle = newTitle;
|
||||
titleUpdateResolve = resolve;
|
||||
titleUpdateDialogOpen = true;
|
||||
});
|
||||
});
|
||||
conversationsStore.setTitleUpdateConfirmationCallback(
|
||||
async (currentTitle: string, newTitle: string) => {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
titleUpdateCurrentTitle = currentTitle;
|
||||
titleUpdateNewTitle = newTitle;
|
||||
titleUpdateResolve = resolve;
|
||||
titleUpdateDialogOpen = true;
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { ChatScreen, DialogModelNotAvailable } from '$lib/components/app';
|
||||
import { sendMessage, clearUIState } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
conversationsStore,
|
||||
isConversationsInitialized,
|
||||
clearActiveConversation,
|
||||
createConversation
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import {
|
||||
fetchModels,
|
||||
modelOptions,
|
||||
selectModel,
|
||||
findModelByName
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { conversationsStore, isConversationsInitialized } from '$lib/stores/conversations.svelte';
|
||||
import { modelsStore, modelOptions } from '$lib/stores/models.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/state';
|
||||
import { replaceState } from '$app/navigation';
|
||||
|
|
@ -39,14 +29,14 @@
|
|||
|
||||
async function handleUrlParams() {
|
||||
// Ensure models are loaded first
|
||||
await fetchModels();
|
||||
await modelsStore.fetch();
|
||||
|
||||
// Handle model parameter - select model if provided
|
||||
if (modelParam) {
|
||||
const model = findModelByName(modelParam);
|
||||
const model = modelsStore.findModelByName(modelParam);
|
||||
if (model) {
|
||||
try {
|
||||
await selectModel(model.id);
|
||||
await modelsStore.selectModelById(model.id);
|
||||
} catch (error) {
|
||||
console.error('Failed to select model:', error);
|
||||
requestedModelName = modelParam;
|
||||
|
|
@ -63,8 +53,8 @@
|
|||
|
||||
// Handle ?q= parameter - create new conversation and send message
|
||||
if (qParam !== null) {
|
||||
await createConversation();
|
||||
await sendMessage(qParam);
|
||||
await conversationsStore.createConversation();
|
||||
await chatStore.sendMessage(qParam);
|
||||
// Clear URL params after message is sent
|
||||
clearUrlParams();
|
||||
} else if (modelParam || newChatParam === 'true') {
|
||||
|
|
@ -78,8 +68,8 @@
|
|||
await conversationsStore.initialize();
|
||||
}
|
||||
|
||||
clearActiveConversation();
|
||||
clearUIState();
|
||||
conversationsStore.clearActiveConversation();
|
||||
chatStore.clearUIState();
|
||||
|
||||
// Handle URL params only if we have ?q= or ?model= or ?new_chat=true
|
||||
if (qParam !== null || modelParam !== null || newChatParam === 'true') {
|
||||
|
|
|
|||
|
|
@ -3,24 +3,13 @@
|
|||
import { page } from '$app/state';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import { ChatScreen, DialogModelNotAvailable } from '$lib/components/app';
|
||||
import { chatStore, isLoading } from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
isLoading,
|
||||
stopGeneration,
|
||||
syncLoadingStateForChat,
|
||||
sendMessage
|
||||
} from '$lib/stores/chat.svelte';
|
||||
import {
|
||||
conversationsStore,
|
||||
activeConversation,
|
||||
activeMessages,
|
||||
loadConversation
|
||||
activeMessages
|
||||
} from '$lib/stores/conversations.svelte';
|
||||
import {
|
||||
selectModel,
|
||||
modelOptions,
|
||||
selectedModelId,
|
||||
fetchModels,
|
||||
findModelByName
|
||||
} from '$lib/stores/models.svelte';
|
||||
import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte';
|
||||
|
||||
let chatId = $derived(page.params.id);
|
||||
let currentChatId: string | undefined = undefined;
|
||||
|
|
@ -49,14 +38,14 @@
|
|||
|
||||
async function handleUrlParams() {
|
||||
// Ensure models are loaded first
|
||||
await fetchModels();
|
||||
await modelsStore.fetch();
|
||||
|
||||
// Handle model parameter - select model if provided
|
||||
if (modelParam) {
|
||||
const model = findModelByName(modelParam);
|
||||
const model = modelsStore.findModelByName(modelParam);
|
||||
if (model) {
|
||||
try {
|
||||
await selectModel(model.id);
|
||||
await modelsStore.selectModelById(model.id);
|
||||
} catch (error) {
|
||||
console.error('Failed to select model:', error);
|
||||
requestedModelName = modelParam;
|
||||
|
|
@ -73,7 +62,7 @@
|
|||
|
||||
// Handle ?q= parameter - send message in current conversation
|
||||
if (qParam !== null) {
|
||||
await sendMessage(qParam);
|
||||
await chatStore.sendMessage(qParam);
|
||||
// Clear URL params after message is sent
|
||||
clearUrlParams();
|
||||
} else if (modelParam) {
|
||||
|
|
@ -112,7 +101,7 @@
|
|||
|
||||
if (matchingModel) {
|
||||
try {
|
||||
await selectModel(matchingModel.id);
|
||||
await modelsStore.selectModelById(matchingModel.id);
|
||||
console.log(`Automatically loaded model: ${lastMessageWithModel.model} from last message`);
|
||||
} catch (error) {
|
||||
console.warn('Failed to automatically select model from last message:', error);
|
||||
|
|
@ -141,9 +130,9 @@
|
|||
}
|
||||
|
||||
(async () => {
|
||||
const success = await loadConversation(chatId);
|
||||
const success = await conversationsStore.loadConversation(chatId);
|
||||
if (success) {
|
||||
syncLoadingStateForChat(chatId);
|
||||
chatStore.syncLoadingStateForChat(chatId);
|
||||
|
||||
// Handle URL params after conversation is loaded
|
||||
if ((qParam !== null || modelParam !== null) && !urlParamsProcessed) {
|
||||
|
|
@ -161,7 +150,7 @@
|
|||
const handleBeforeUnload = () => {
|
||||
if (isLoading()) {
|
||||
console.log('Page unload detected while streaming - aborting stream');
|
||||
stopGeneration();
|
||||
chatStore.stopGeneration();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@
|
|||
message: userMessage
|
||||
}}
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', false);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', false);
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
@ -104,8 +104,8 @@
|
|||
message: assistantMessage
|
||||
}}
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', false);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', false);
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
@ -116,8 +116,8 @@
|
|||
message: assistantWithReasoning
|
||||
}}
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', false);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', false);
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
@ -128,8 +128,8 @@
|
|||
message: rawOutputMessage
|
||||
}}
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', true);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', true);
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
@ -140,8 +140,8 @@
|
|||
}}
|
||||
asChild
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', false);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', false);
|
||||
// Phase 1: Stream reasoning content in chunks
|
||||
let reasoningText =
|
||||
'I need to think about this carefully. Let me break down the problem:\n\n1. The user is asking for help with something complex\n2. I should provide a thorough and helpful response\n3. I need to consider multiple approaches\n4. The best solution would be to explain step by step\n\nThis approach will ensure clarity and understanding.';
|
||||
|
|
@ -192,8 +192,8 @@
|
|||
message: processingMessage
|
||||
}}
|
||||
play={async () => {
|
||||
const { updateConfig } = await import('$lib/stores/settings.svelte');
|
||||
updateConfig('disableReasoningFormat', false);
|
||||
const { settingsStore } = await import('$lib/stores/settings.svelte');
|
||||
settingsStore.updateConfig('disableReasoningFormat', false);
|
||||
// Import the chat store to simulate loading state
|
||||
const { chatStore } = await import('$lib/stores/chat.svelte');
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue