mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-08-12 22:31:11 +04:00
refactor: Remove dead context for Chat Settings and create a new one for Chat Messages Actions
This commit is contained in:
@@ -8,7 +8,12 @@
|
||||
ChatMessageUser
|
||||
} from '$lib/components/app/chat';
|
||||
import { REASONING_TAGS, ROUTES, SYSTEM_MESSAGE_PLACEHOLDER } from '$lib/constants';
|
||||
import { getChatActionsContext, setMessageEditContext } from '$lib/contexts';
|
||||
import {
|
||||
type ChatMessageDeletionInfo,
|
||||
getChatActionsContext,
|
||||
setChatMessageActionsContext,
|
||||
setMessageEditContext
|
||||
} from '$lib/contexts';
|
||||
import { AgenticSectionType, AttachmentType, MessageRole } from '$lib/enums';
|
||||
import { DatabaseService } from '$lib/services/database.service';
|
||||
import { chatStore, conversationsStore, isMobile } from '$lib/stores';
|
||||
@@ -38,12 +43,7 @@
|
||||
|
||||
const chatActions = getChatActionsContext();
|
||||
|
||||
let deletionInfo = $state<{
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null>(null);
|
||||
let deletionInfo = $state<ChatMessageDeletionInfo | null>(null);
|
||||
// The system message placeholder must never surface as editable content; keeping
|
||||
// it in the derived (not just in handleEdit) guards against prop invalidation
|
||||
// reverting the override while editing
|
||||
@@ -166,6 +166,30 @@
|
||||
startEdit: handleEdit
|
||||
});
|
||||
|
||||
setChatMessageActionsContext({
|
||||
confirmDelete: handleConfirmDelete,
|
||||
copy: handleCopy,
|
||||
get deletionInfo() {
|
||||
return deletionInfo;
|
||||
},
|
||||
get forkConversation() {
|
||||
const isForkableUser = message.role === MessageRole.USER && !mcpPromptExtra;
|
||||
|
||||
return isForkableUser || message.role === MessageRole.ASSISTANT
|
||||
? handleForkConversation
|
||||
: undefined;
|
||||
},
|
||||
navigateToSibling: handleNavigateToSibling,
|
||||
requestDelete: handleDelete,
|
||||
setShowDeleteDialog: handleShowDeleteDialogChange,
|
||||
get showDeleteDialog() {
|
||||
return showDeleteDialog;
|
||||
},
|
||||
get siblingInfo() {
|
||||
return siblingInfo;
|
||||
}
|
||||
});
|
||||
|
||||
let mcpPromptExtra = $derived.by(() => {
|
||||
if (message.role !== MessageRole.USER) return null;
|
||||
|
||||
@@ -360,73 +384,22 @@
|
||||
|
||||
<div class="chat-message" class:chat-message--synthetic={isSynthetic}>
|
||||
{#if message.role === MessageRole.SYSTEM}
|
||||
<ChatMessageSystem
|
||||
bind:textareaElement
|
||||
class={className}
|
||||
{deletionInfo}
|
||||
{message}
|
||||
onConfirmDelete={handleConfirmDelete}
|
||||
onCopy={handleCopy}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
onNavigateToSibling={handleNavigateToSibling}
|
||||
onShowDeleteDialogChange={handleShowDeleteDialogChange}
|
||||
{showDeleteDialog}
|
||||
{siblingInfo}
|
||||
/>
|
||||
<ChatMessageSystem bind:textareaElement class={className} {message} />
|
||||
{:else if mcpPromptExtra}
|
||||
<ChatMessageMcpPrompt
|
||||
class={className}
|
||||
{deletionInfo}
|
||||
{message}
|
||||
mcpPrompt={mcpPromptExtra}
|
||||
onConfirmDelete={handleConfirmDelete}
|
||||
onCopy={handleCopy}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
onNavigateToSibling={handleNavigateToSibling}
|
||||
onShowDeleteDialogChange={handleShowDeleteDialogChange}
|
||||
{showDeleteDialog}
|
||||
{siblingInfo}
|
||||
/>
|
||||
<ChatMessageMcpPrompt class={className} {message} mcpPrompt={mcpPromptExtra} />
|
||||
{:else if isSynthetic}
|
||||
<ChatMessageSynthetic {message} class={className} />
|
||||
{:else if message.role === MessageRole.USER}
|
||||
<ChatMessageUser
|
||||
class={className}
|
||||
{deletionInfo}
|
||||
{isLastUserMessage}
|
||||
{message}
|
||||
{nextAssistantMessage}
|
||||
onConfirmDelete={handleConfirmDelete}
|
||||
onCopy={handleCopy}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
onForkConversation={handleForkConversation}
|
||||
onNavigateToSibling={handleNavigateToSibling}
|
||||
onShowDeleteDialogChange={handleShowDeleteDialogChange}
|
||||
{showDeleteDialog}
|
||||
{siblingInfo}
|
||||
/>
|
||||
<ChatMessageUser class={className} {isLastUserMessage} {message} {nextAssistantMessage} />
|
||||
{:else}
|
||||
<ChatMessageAssistant
|
||||
bind:textareaElement
|
||||
class={className}
|
||||
{deletionInfo}
|
||||
{isLastAssistantMessage}
|
||||
{message}
|
||||
{toolMessages}
|
||||
onConfirmDelete={handleConfirmDelete}
|
||||
onContinue={handleContinue}
|
||||
onCopy={handleCopy}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
onForkConversation={handleForkConversation}
|
||||
onNavigateToSibling={handleNavigateToSibling}
|
||||
onRegenerate={handleRegenerate}
|
||||
onShowDeleteDialogChange={handleShowDeleteDialogChange}
|
||||
{showDeleteDialog}
|
||||
{siblingInfo}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
-35
@@ -17,45 +17,20 @@
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
deletionInfo: {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null;
|
||||
isLastAssistantMessage?: boolean;
|
||||
message: DatabaseMessage;
|
||||
toolMessages?: DatabaseMessage[];
|
||||
onCopy: () => void;
|
||||
onConfirmDelete: () => void;
|
||||
onContinue?: () => void;
|
||||
onDelete: () => void;
|
||||
onEdit?: () => void;
|
||||
onForkConversation?: (options: { name: string; includeAttachments: boolean }) => void;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
onRegenerate: (modelOverride?: string) => void;
|
||||
onShowDeleteDialogChange: (show: boolean) => void;
|
||||
showDeleteDialog: boolean;
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
textareaElement?: HTMLTextAreaElement;
|
||||
}
|
||||
|
||||
let {
|
||||
class: className = '',
|
||||
deletionInfo,
|
||||
isLastAssistantMessage = false,
|
||||
message,
|
||||
onConfirmDelete,
|
||||
onContinue,
|
||||
onCopy,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onForkConversation,
|
||||
onNavigateToSibling,
|
||||
onRegenerate,
|
||||
onShowDeleteDialogChange,
|
||||
showDeleteDialog,
|
||||
siblingInfo = null,
|
||||
textareaElement = $bindable(),
|
||||
toolMessages = []
|
||||
}: Props = $props();
|
||||
@@ -207,18 +182,8 @@
|
||||
role={MessageRole.ASSISTANT}
|
||||
justify="start"
|
||||
actionsPosition="left"
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
{deletionInfo}
|
||||
{onCopy}
|
||||
{onEdit}
|
||||
{onRegenerate}
|
||||
onContinue={currentConfig.enableContinueGeneration ? onContinue : undefined}
|
||||
{onForkConversation}
|
||||
{onDelete}
|
||||
{onConfirmDelete}
|
||||
{onNavigateToSibling}
|
||||
{onShowDeleteDialogChange}
|
||||
showRawOutputSwitch={currentConfig.showRawOutputSwitch}
|
||||
rawOutputEnabled={showRawOutput}
|
||||
onRawOutputToggle={(enabled) => (showRawOutput = enabled)}
|
||||
|
||||
+2
-42
@@ -12,36 +12,9 @@
|
||||
class?: string;
|
||||
message: DatabaseMessage;
|
||||
mcpPrompt: DatabaseMessageExtraMcpPrompt;
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
showDeleteDialog: boolean;
|
||||
deletionInfo: {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null;
|
||||
onCopy: () => void;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
onConfirmDelete: () => void;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
onShowDeleteDialogChange: (show: boolean) => void;
|
||||
}
|
||||
|
||||
let {
|
||||
class: className = '',
|
||||
deletionInfo,
|
||||
mcpPrompt,
|
||||
message,
|
||||
onConfirmDelete,
|
||||
onCopy,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onNavigateToSibling,
|
||||
onShowDeleteDialogChange,
|
||||
showDeleteDialog,
|
||||
siblingInfo = null
|
||||
}: Props = $props();
|
||||
let { class: className = '', mcpPrompt, message }: Props = $props();
|
||||
|
||||
// Get edit context
|
||||
const editCtx = getMessageEditContext();
|
||||
@@ -63,20 +36,7 @@
|
||||
|
||||
{#if message.timestamp}
|
||||
<div class="max-w-[80%]">
|
||||
<ChatMessageActionIcons
|
||||
actionsPosition="right"
|
||||
{deletionInfo}
|
||||
justify="end"
|
||||
{onConfirmDelete}
|
||||
{onCopy}
|
||||
{onDelete}
|
||||
{onEdit}
|
||||
{onNavigateToSibling}
|
||||
{onShowDeleteDialogChange}
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
role={MessageRole.USER}
|
||||
/>
|
||||
<ChatMessageActionIcons actionsPosition="right" justify="end" role={MessageRole.USER} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
+2
-42
@@ -12,37 +12,10 @@
|
||||
interface Props {
|
||||
class?: string;
|
||||
message: DatabaseMessage;
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
showDeleteDialog: boolean;
|
||||
deletionInfo: {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null;
|
||||
onCopy: () => void;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
onConfirmDelete: () => void;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
onShowDeleteDialogChange: (show: boolean) => void;
|
||||
textareaElement?: HTMLTextAreaElement;
|
||||
}
|
||||
|
||||
let {
|
||||
class: className = '',
|
||||
deletionInfo,
|
||||
message,
|
||||
onConfirmDelete,
|
||||
onCopy,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onNavigateToSibling,
|
||||
onShowDeleteDialogChange,
|
||||
showDeleteDialog,
|
||||
siblingInfo = null,
|
||||
textareaElement = $bindable()
|
||||
}: Props = $props();
|
||||
let { class: className = '', message, textareaElement = $bindable() }: Props = $props();
|
||||
|
||||
const editCtx = getMessageEditContext();
|
||||
|
||||
@@ -218,20 +191,7 @@
|
||||
|
||||
{#if message.timestamp}
|
||||
<div class="max-w-[80%]">
|
||||
<ChatMessageActionIcons
|
||||
actionsPosition="right"
|
||||
{deletionInfo}
|
||||
justify="end"
|
||||
{onConfirmDelete}
|
||||
{onCopy}
|
||||
{onDelete}
|
||||
{onEdit}
|
||||
{onNavigateToSibling}
|
||||
{onShowDeleteDialogChange}
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
role={MessageRole.USER}
|
||||
/>
|
||||
<ChatMessageActionIcons actionsPosition="right" justify="end" role={MessageRole.USER} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
+2
-41
@@ -13,40 +13,15 @@
|
||||
interface Props {
|
||||
class?: string;
|
||||
message: DatabaseMessage;
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
deletionInfo: {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null;
|
||||
isLastUserMessage?: boolean;
|
||||
nextAssistantMessage?: DatabaseMessage | null;
|
||||
showDeleteDialog: boolean;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
onConfirmDelete: () => void;
|
||||
onForkConversation?: (options: { name: string; includeAttachments: boolean }) => void;
|
||||
onShowDeleteDialogChange: (show: boolean) => void;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
onCopy: () => void;
|
||||
}
|
||||
|
||||
let {
|
||||
class: className = '',
|
||||
deletionInfo,
|
||||
isLastUserMessage = false,
|
||||
message,
|
||||
nextAssistantMessage = null,
|
||||
onConfirmDelete,
|
||||
onCopy,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onForkConversation,
|
||||
onNavigateToSibling,
|
||||
onShowDeleteDialogChange,
|
||||
showDeleteDialog,
|
||||
siblingInfo = null
|
||||
nextAssistantMessage = null
|
||||
}: Props = $props();
|
||||
|
||||
// Get contexts
|
||||
@@ -132,21 +107,7 @@
|
||||
|
||||
{#if message.timestamp}
|
||||
<div class="max-w-[80%]">
|
||||
<ChatMessageActionIcons
|
||||
actionsPosition="right"
|
||||
{deletionInfo}
|
||||
justify="end"
|
||||
{onConfirmDelete}
|
||||
{onCopy}
|
||||
{onDelete}
|
||||
{onEdit}
|
||||
{onForkConversation}
|
||||
{onNavigateToSibling}
|
||||
{onShowDeleteDialogChange}
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
role={MessageRole.USER}
|
||||
/>
|
||||
<ChatMessageActionIcons actionsPosition="right" justify="end" role={MessageRole.USER} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
+23
-43
@@ -9,6 +9,7 @@
|
||||
import Input from '$lib/components/ui/input/input.svelte';
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { getChatMessageActionsContext, getMessageEditContext } from '$lib/contexts';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import { conversationsStore } from '$lib/stores';
|
||||
|
||||
@@ -16,23 +17,8 @@
|
||||
role: MessageRole.USER | MessageRole.ASSISTANT;
|
||||
justify: 'start' | 'end';
|
||||
actionsPosition: 'left' | 'right';
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
showDeleteDialog: boolean;
|
||||
deletionInfo: {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
} | null;
|
||||
onCopy: () => void;
|
||||
onEdit?: () => void;
|
||||
onRegenerate?: () => void;
|
||||
onContinue?: () => void;
|
||||
onForkConversation?: (options: { name: string; includeAttachments: boolean }) => void;
|
||||
onDelete: () => void;
|
||||
onConfirmDelete: () => void;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
onShowDeleteDialogChange: (show: boolean) => void;
|
||||
showRawOutputSwitch?: boolean;
|
||||
rawOutputEnabled?: boolean;
|
||||
onRawOutputToggle?: (enabled: boolean) => void;
|
||||
@@ -40,32 +26,25 @@
|
||||
|
||||
let {
|
||||
actionsPosition,
|
||||
deletionInfo,
|
||||
justify,
|
||||
onConfirmDelete,
|
||||
onContinue,
|
||||
onCopy,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onForkConversation,
|
||||
onNavigateToSibling,
|
||||
onRawOutputToggle,
|
||||
onRegenerate,
|
||||
onShowDeleteDialogChange,
|
||||
rawOutputEnabled = false,
|
||||
role,
|
||||
showDeleteDialog,
|
||||
showRawOutputSwitch = false,
|
||||
siblingInfo = null
|
||||
showRawOutputSwitch = false
|
||||
}: Props = $props();
|
||||
|
||||
const messageActions = getChatMessageActionsContext();
|
||||
const editCtx = getMessageEditContext();
|
||||
|
||||
let showForkDialog = $state(false);
|
||||
let forkName = $state('');
|
||||
let forkIncludeAttachments = $state(true);
|
||||
|
||||
function handleConfirmDelete() {
|
||||
onConfirmDelete();
|
||||
onShowDeleteDialogChange(false);
|
||||
messageActions.confirmDelete();
|
||||
messageActions.setShowDeleteDialog(false);
|
||||
}
|
||||
|
||||
function handleOpenForkDialog() {
|
||||
@@ -77,7 +56,10 @@
|
||||
}
|
||||
|
||||
function handleConfirmFork() {
|
||||
onForkConversation?.({ includeAttachments: forkIncludeAttachments, name: forkName.trim() });
|
||||
messageActions.forkConversation?.({
|
||||
includeAttachments: forkIncludeAttachments,
|
||||
name: forkName.trim()
|
||||
});
|
||||
showForkDialog = false;
|
||||
}
|
||||
</script>
|
||||
@@ -88,18 +70,16 @@
|
||||
? 'left-0'
|
||||
: 'right-0'} flex items-center gap-2 opacity-100 transition-opacity"
|
||||
>
|
||||
{#if siblingInfo && siblingInfo.totalSiblings > 1}
|
||||
<ChatMessageActionIconsBranchingControls {siblingInfo} {onNavigateToSibling} />
|
||||
{#if messageActions.siblingInfo && messageActions.siblingInfo.totalSiblings > 1}
|
||||
<ChatMessageActionIconsBranchingControls />
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="pointer-events-auto inset-0 flex items-center gap-1 opacity-100 transition-all duration-150"
|
||||
>
|
||||
<ActionIcon icon={Copy} tooltip="Copy" onclick={onCopy} />
|
||||
<ActionIcon icon={Copy} tooltip="Copy" onclick={messageActions.copy} />
|
||||
|
||||
{#if onEdit}
|
||||
<ActionIcon icon={Edit} tooltip="Edit" onclick={onEdit} />
|
||||
{/if}
|
||||
<ActionIcon icon={Edit} tooltip="Edit" onclick={editCtx.startEdit} />
|
||||
|
||||
{#if role === MessageRole.ASSISTANT && onRegenerate}
|
||||
<ActionIcon icon={RefreshCw} tooltip="Regenerate" onclick={() => onRegenerate()} />
|
||||
@@ -109,11 +89,11 @@
|
||||
<ActionIcon icon={ArrowRight} tooltip="Continue" onclick={onContinue} />
|
||||
{/if}
|
||||
|
||||
{#if onForkConversation}
|
||||
{#if messageActions.forkConversation}
|
||||
<ActionIcon icon={GitBranch} tooltip="Fork conversation" onclick={handleOpenForkDialog} />
|
||||
{/if}
|
||||
|
||||
<ActionIcon icon={Trash2} tooltip="Delete" onclick={onDelete} />
|
||||
<ActionIcon icon={Trash2} tooltip="Delete" onclick={messageActions.requestDelete} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -129,19 +109,19 @@
|
||||
</div>
|
||||
|
||||
<DialogConfirmation
|
||||
bind:open={showDeleteDialog}
|
||||
open={messageActions.showDeleteDialog}
|
||||
title="Delete Message"
|
||||
description={deletionInfo && deletionInfo.totalCount > 1
|
||||
? `This will delete ${deletionInfo.totalCount} messages including: ${deletionInfo.userMessages} user message${deletionInfo.userMessages > 1 ? 's' : ''} and ${deletionInfo.assistantMessages} assistant response${deletionInfo.assistantMessages > 1 ? 's' : ''}. All messages in this branch and their responses will be permanently removed. This action cannot be undone.`
|
||||
description={messageActions.deletionInfo && messageActions.deletionInfo.totalCount > 1
|
||||
? `This will delete ${messageActions.deletionInfo.totalCount} messages including: ${messageActions.deletionInfo.userMessages} user message${messageActions.deletionInfo.userMessages > 1 ? 's' : ''} and ${messageActions.deletionInfo.assistantMessages} assistant response${messageActions.deletionInfo.assistantMessages > 1 ? 's' : ''}. All messages in this branch and their responses will be permanently removed. This action cannot be undone.`
|
||||
: 'Are you sure you want to delete this message? This action cannot be undone.'}
|
||||
confirmText={deletionInfo && deletionInfo.totalCount > 1
|
||||
? `Delete ${deletionInfo.totalCount} Messages`
|
||||
confirmText={messageActions.deletionInfo && messageActions.deletionInfo.totalCount > 1
|
||||
? `Delete ${messageActions.deletionInfo.totalCount} Messages`
|
||||
: 'Delete'}
|
||||
cancelText="Cancel"
|
||||
variant="destructive"
|
||||
icon={Trash2}
|
||||
onConfirm={handleConfirmDelete}
|
||||
onCancel={() => onShowDeleteDialogChange(false)}
|
||||
onCancel={() => messageActions.setShowDeleteDialog(false)}
|
||||
/>
|
||||
|
||||
<DialogConfirmation
|
||||
|
||||
+8
-5
@@ -1,14 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { ChevronLeft, ChevronRight } from '@lucide/svelte';
|
||||
import { ActionIcon } from '$lib/components/app';
|
||||
import { getChatMessageActionsContext } from '$lib/contexts';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
siblingInfo: ChatMessageSiblingInfo | null;
|
||||
onNavigateToSibling?: (siblingId: string) => void;
|
||||
}
|
||||
|
||||
let { class: className = '', onNavigateToSibling, siblingInfo }: Props = $props();
|
||||
let { class: className = '' }: Props = $props();
|
||||
|
||||
const messageActions = getChatMessageActionsContext();
|
||||
|
||||
let siblingInfo = $derived(messageActions.siblingInfo);
|
||||
|
||||
let hasPrevious = $derived(siblingInfo && siblingInfo.currentIndex > 0);
|
||||
let hasNext = $derived(siblingInfo && siblingInfo.currentIndex < siblingInfo.totalSiblings - 1);
|
||||
@@ -31,7 +34,7 @@
|
||||
tooltip="Previous version"
|
||||
disabled={!hasPrevious}
|
||||
class="h-5 w-5 p-0 {!hasPrevious ? '!cursor-not-allowed opacity-30' : ''}"
|
||||
onclick={() => onNavigateToSibling?.(previousSiblingId!)}
|
||||
onclick={() => messageActions.navigateToSibling(previousSiblingId!)}
|
||||
/>
|
||||
|
||||
<span class="px-1 font-mono text-xs">
|
||||
@@ -43,7 +46,7 @@
|
||||
tooltip="Next version"
|
||||
disabled={!hasNext}
|
||||
class="h-5 w-5 p-0 {!hasNext ? 'opacity-30' : ''}"
|
||||
onclick={() => onNavigateToSibling?.(nextSiblingId!)}
|
||||
onclick={() => messageActions.navigateToSibling(nextSiblingId!)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
SETTINGS_CHAT_SECTIONS,
|
||||
SETTINGS_SECTION_TITLES
|
||||
} from '$lib/constants';
|
||||
import { setChatSettingsConfigContext } from '$lib/contexts';
|
||||
import { ColorMode } from '$lib/enums/ui.enums';
|
||||
import { RouterService } from '$lib/services/router.service';
|
||||
import { modelsStore, serverStore, settingsReferrer, settingsStore } from '$lib/stores';
|
||||
@@ -122,14 +121,6 @@
|
||||
export function reset() {
|
||||
localConfig = { ...settingsStore.config };
|
||||
}
|
||||
|
||||
setChatSettingsConfigContext({
|
||||
handleConfigChange,
|
||||
handleThemeChange,
|
||||
get localConfig() {
|
||||
return localConfig;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="mx-auto flex h-full w-full flex-col md:pl-8" in:fade={{ duration: 150 }}>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const CONTEXT_KEY_MESSAGE_EDIT = 'chat-message-edit';
|
||||
export const CONTEXT_KEY_CHAT_ACTIONS = 'chat-actions';
|
||||
export const CONTEXT_KEY_CHAT_SETTINGS_CONFIG = 'chat-settings-config';
|
||||
export const CONTEXT_KEY_CHAT_MESSAGE_ACTIONS = 'chat-message-actions';
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { CONTEXT_KEY_CHAT_MESSAGE_ACTIONS } from '$lib/constants';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
|
||||
export interface ChatMessageDeletionInfo {
|
||||
totalCount: number;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
messageTypes: string[];
|
||||
}
|
||||
|
||||
export interface ChatMessageActionsContext {
|
||||
readonly siblingInfo: ChatMessageSiblingInfo | null;
|
||||
readonly deletionInfo: ChatMessageDeletionInfo | null;
|
||||
readonly showDeleteDialog: boolean;
|
||||
copy: () => void;
|
||||
requestDelete: () => void;
|
||||
confirmDelete: () => void;
|
||||
setShowDeleteDialog: (show: boolean) => void;
|
||||
navigateToSibling: (siblingId: string) => void;
|
||||
forkConversation?: (options: { name: string; includeAttachments: boolean }) => void;
|
||||
}
|
||||
|
||||
const CHAT_MESSAGE_ACTIONS_KEY = Symbol.for(CONTEXT_KEY_CHAT_MESSAGE_ACTIONS);
|
||||
|
||||
/**
|
||||
* Sets the per-message actions context. Call this in the parent component (ChatMessage.svelte).
|
||||
*/
|
||||
export function setChatMessageActionsContext(
|
||||
ctx: ChatMessageActionsContext
|
||||
): ChatMessageActionsContext {
|
||||
return setContext(CHAT_MESSAGE_ACTIONS_KEY, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the per-message actions context. Call this in child components.
|
||||
*/
|
||||
export function getChatMessageActionsContext(): ChatMessageActionsContext {
|
||||
return getContext(CHAT_MESSAGE_ACTIONS_KEY);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { CONTEXT_KEY_CHAT_SETTINGS_CONFIG } from '$lib/constants';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
|
||||
export interface ChatSettingsConfigContext {
|
||||
readonly localConfig: SettingsConfigType;
|
||||
handleConfigChange: (key: string, value: string | boolean) => void;
|
||||
handleThemeChange: (theme: string) => void;
|
||||
}
|
||||
|
||||
const CHAT_SETTINGS_CONFIG_KEY = Symbol.for(CONTEXT_KEY_CHAT_SETTINGS_CONFIG);
|
||||
|
||||
export function setChatSettingsConfigContext(
|
||||
ctx: ChatSettingsConfigContext
|
||||
): ChatSettingsConfigContext {
|
||||
return setContext(CHAT_SETTINGS_CONFIG_KEY, ctx);
|
||||
}
|
||||
|
||||
export function getChatSettingsConfigContext(): ChatSettingsConfigContext {
|
||||
return getContext(CHAT_SETTINGS_CONFIG_KEY);
|
||||
}
|
||||
@@ -13,7 +13,8 @@ export {
|
||||
} from './chat-actions.context';
|
||||
|
||||
export {
|
||||
getChatSettingsConfigContext,
|
||||
setChatSettingsConfigContext,
|
||||
type ChatSettingsConfigContext
|
||||
} from './chat-settings-config.context';
|
||||
getChatMessageActionsContext,
|
||||
setChatMessageActionsContext,
|
||||
type ChatMessageActionsContext,
|
||||
type ChatMessageDeletionInfo
|
||||
} from './chat-message-actions.context';
|
||||
|
||||
Reference in New Issue
Block a user