refactor: Cleanup
This commit is contained in:
parent
b0ba550928
commit
223c6333e9
|
|
@ -5,7 +5,7 @@ import type {
|
|||
} from '$lib/types/api';
|
||||
import type { ChatMessagePromptProgress, ChatMessageTimings } from '$lib/types/chat';
|
||||
import { mergeToolCallDeltas, extractModelName } from '$lib/utils/chat-stream';
|
||||
import type { AgenticChatCompletionRequest } from './types';
|
||||
import type { AgenticChatCompletionRequest } from '$lib/types/agentic';
|
||||
|
||||
export type OpenAISseCallbacks = {
|
||||
onChunk?: (chunk: string) => void;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
} from '$lib/components/app';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { Wrench, Loader2 } from '@lucide/svelte';
|
||||
import { AgenticSectionType } from '$lib/types/agentic';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { AGENTIC_TAGS, AGENTIC_REGEX } from '$lib/constants/agentic';
|
||||
import { formatJsonPretty } from '$lib/utils/formatters';
|
||||
|
||||
|
|
@ -38,16 +38,20 @@
|
|||
|
||||
const showToolCallInProgress = $derived(config().showToolCallInProgress as boolean);
|
||||
|
||||
function isExpanded(index: number, isPending: boolean): boolean {
|
||||
if (showToolCallInProgress && isPending) {
|
||||
return true;
|
||||
}
|
||||
function getDefaultExpanded(isPending: boolean): boolean {
|
||||
return showToolCallInProgress && isPending;
|
||||
}
|
||||
|
||||
return expandedStates[index] ?? showToolCallInProgress;
|
||||
function isExpanded(index: number, isPending: boolean): boolean {
|
||||
if (expandedStates[index] !== undefined) {
|
||||
return expandedStates[index];
|
||||
}
|
||||
return getDefaultExpanded(isPending);
|
||||
}
|
||||
|
||||
function toggleExpanded(index: number, isPending: boolean) {
|
||||
expandedStates[index] = !isExpanded(index, isPending);
|
||||
const currentState = isExpanded(index, isPending);
|
||||
expandedStates[index] = !currentState;
|
||||
}
|
||||
|
||||
function parseAgenticContent(rawContent: string): AgenticSection[] {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import { DatabaseService } from '$lib/services';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { SYSTEM_MESSAGE_PLACEHOLDER } from '$lib/constants/ui';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import { copyToClipboard, isIMEComposing, formatMessageForClipboard } from '$lib/utils';
|
||||
import ChatMessageAssistant from './ChatMessageAssistant.svelte';
|
||||
import ChatMessageUser from './ChatMessageUser.svelte';
|
||||
|
|
@ -70,7 +71,7 @@
|
|||
let textareaElement: HTMLTextAreaElement | undefined = $state();
|
||||
|
||||
let thinkingContent = $derived.by(() => {
|
||||
if (message.role === 'assistant') {
|
||||
if (message.role === MessageRole.ASSISTANT) {
|
||||
const trimmedThinking = message.thinking?.trim();
|
||||
|
||||
return trimmedThinking ? trimmedThinking : null;
|
||||
|
|
@ -92,7 +93,7 @@
|
|||
isEditing = false;
|
||||
|
||||
// If canceling a new system message with placeholder content, remove it without deleting children
|
||||
if (message.role === 'system') {
|
||||
if (message.role === MessageRole.SYSTEM) {
|
||||
const conversationDeleted = await removeSystemPromptPlaceholder(message.id);
|
||||
|
||||
if (conversationDeleted) {
|
||||
|
|
@ -136,7 +137,7 @@
|
|||
isEditing = true;
|
||||
// Clear temporary placeholder content for system messages
|
||||
editedContent =
|
||||
message.role === 'system' && message.content === SYSTEM_MESSAGE_PLACEHOLDER
|
||||
message.role === MessageRole.SYSTEM && message.content === SYSTEM_MESSAGE_PLACEHOLDER
|
||||
? ''
|
||||
: message.content;
|
||||
textareaElement?.focus();
|
||||
|
|
@ -179,7 +180,7 @@
|
|||
}
|
||||
|
||||
async function handleSaveEdit() {
|
||||
if (message.role === 'system') {
|
||||
if (message.role === MessageRole.SYSTEM) {
|
||||
// System messages: update in place without branching
|
||||
const newContent = editedContent.trim();
|
||||
|
||||
|
|
@ -198,7 +199,7 @@
|
|||
if (index !== -1) {
|
||||
conversationsStore.updateMessageAtIndex(index, { content: newContent });
|
||||
}
|
||||
} else if (message.role === 'user') {
|
||||
} else if (message.role === MessageRole.USER) {
|
||||
const finalExtras = await getMergedExtras();
|
||||
onEditWithBranching?.(message, editedContent.trim(), finalExtras);
|
||||
} else {
|
||||
|
|
@ -213,7 +214,7 @@
|
|||
}
|
||||
|
||||
async function handleSaveEditOnly() {
|
||||
if (message.role === 'user') {
|
||||
if (message.role === MessageRole.USER) {
|
||||
// For user messages, trim to avoid accidental whitespace
|
||||
const finalExtras = await getMergedExtras();
|
||||
onEditUserMessagePreserveResponses?.(message, editedContent.trim(), finalExtras);
|
||||
|
|
@ -240,7 +241,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
{#if message.role === 'system'}
|
||||
{#if message.role === MessageRole.SYSTEM}
|
||||
<ChatMessageSystem
|
||||
bind:textareaElement
|
||||
class={className}
|
||||
|
|
@ -261,7 +262,7 @@
|
|||
{showDeleteDialog}
|
||||
{siblingInfo}
|
||||
/>
|
||||
{:else if message.role === 'user'}
|
||||
{:else if message.role === MessageRole.USER}
|
||||
<ChatMessageUser
|
||||
bind:textareaElement
|
||||
class={className}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
DialogConfirmation
|
||||
} from '$lib/components/app';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
|
||||
interface Props {
|
||||
role: 'user' | 'assistant';
|
||||
role: MessageRole.USER | MessageRole.ASSISTANT;
|
||||
justify: 'start' | 'end';
|
||||
actionsPosition: 'left' | 'right';
|
||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||
|
|
@ -77,11 +78,11 @@
|
|||
<ActionButton icon={Edit} tooltip="Edit" onclick={onEdit} />
|
||||
{/if}
|
||||
|
||||
{#if role === 'assistant' && onRegenerate}
|
||||
{#if role === MessageRole.ASSISTANT && onRegenerate}
|
||||
<ActionButton icon={RefreshCw} tooltip="Regenerate" onclick={() => onRegenerate()} />
|
||||
{/if}
|
||||
|
||||
{#if role === 'assistant' && onContinue}
|
||||
{#if role === MessageRole.ASSISTANT && onContinue}
|
||||
<ActionButton icon={ArrowRight} tooltip="Continue" onclick={onContinue} />
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
import { Button } from '$lib/components/ui/button';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import { INPUT_CLASSES } from '$lib/constants/css-classes';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
|
|
@ -245,7 +246,7 @@
|
|||
|
||||
{#if message.timestamp && !isEditing}
|
||||
<ChatMessageActions
|
||||
role="assistant"
|
||||
role={MessageRole.ASSISTANT}
|
||||
justify="start"
|
||||
actionsPosition="left"
|
||||
{siblingInfo}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { INPUT_CLASSES } from '$lib/constants/css-classes';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import ChatMessageActions from './ChatMessageActions.svelte';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
|
@ -211,7 +212,7 @@
|
|||
{onShowDeleteDialogChange}
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
role="user"
|
||||
role={MessageRole.USER}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { config } from '$lib/stores/settings.svelte';
|
||||
import ChatMessageActions from './ChatMessageActions.svelte';
|
||||
import ChatMessageEditForm from './ChatMessageEditForm.svelte';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
|
@ -156,7 +157,7 @@
|
|||
{onShowDeleteDialogChange}
|
||||
{siblingInfo}
|
||||
{showDeleteDialog}
|
||||
role="user"
|
||||
role={MessageRole.USER}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
<script lang="ts">
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import McpSettingsSection from '../mcp/McpSettingsSection.svelte';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import McpLogo from '../misc/McpLogo.svelte';
|
||||
import { McpLogo, McpSettingsSection } from '$lib/components/app';
|
||||
|
||||
interface Props {
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export { default as ActionButton } from './misc/ActionButton.svelte';
|
|||
export { default as ActionDropdown } from './misc/ActionDropdown.svelte';
|
||||
export { default as BadgeChatStatistic } from './misc/BadgeChatStatistic.svelte';
|
||||
export { default as BadgeInfo } from './misc/BadgeInfo.svelte';
|
||||
export { default as ModelBadge } from './models/ModelBadge.svelte';
|
||||
export { default as McpLogo } from './misc/McpLogo.svelte';
|
||||
export { default as BadgeModality } from './misc/BadgeModality.svelte';
|
||||
export { default as ConversationSelection } from './misc/ConversationSelection.svelte';
|
||||
export { default as CopyToClipboardIcon } from './misc/CopyToClipboardIcon.svelte';
|
||||
|
|
@ -70,6 +70,10 @@ export { default as RemoveButton } from './misc/RemoveButton.svelte';
|
|||
export { default as SearchInput } from './misc/SearchInput.svelte';
|
||||
export { default as SearchableDropdownMenu } from './misc/SearchableDropdownMenu.svelte';
|
||||
export { default as SyntaxHighlightedCode } from './misc/SyntaxHighlightedCode.svelte';
|
||||
|
||||
// Models
|
||||
|
||||
export { default as ModelBadge } from './models/ModelBadge.svelte';
|
||||
export { default as ModelsSelector } from './models/ModelsSelector.svelte';
|
||||
|
||||
// MCP
|
||||
|
|
|
|||
|
|
@ -1,13 +1,3 @@
|
|||
/**
|
||||
* Agentic orchestration configuration.
|
||||
*/
|
||||
export interface AgenticConfig {
|
||||
enabled: boolean;
|
||||
maxTurns: number;
|
||||
maxToolPreviewLines: number;
|
||||
filterReasoningAfterFirstTurn: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of sections in agentic content display.
|
||||
*/
|
||||
|
|
@ -2,3 +2,22 @@ export enum ChatMessageStatsView {
|
|||
GENERATION = 'generation',
|
||||
READING = 'reading'
|
||||
}
|
||||
|
||||
/**
|
||||
* Message roles for chat messages.
|
||||
*/
|
||||
export enum MessageRole {
|
||||
USER = 'user',
|
||||
ASSISTANT = 'assistant',
|
||||
SYSTEM = 'system'
|
||||
}
|
||||
|
||||
/**
|
||||
* Message types for different content kinds.
|
||||
*/
|
||||
export enum MessageType {
|
||||
ROOT = 'root',
|
||||
TEXT = 'text',
|
||||
THINK = 'think',
|
||||
SYSTEM = 'system'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
export { AttachmentType } from './attachment';
|
||||
|
||||
export { ChatMessageStatsView } from './chat';
|
||||
export { AgenticSectionType } from './agentic';
|
||||
|
||||
export { ChatMessageStatsView, MessageRole, MessageType } from './chat';
|
||||
|
||||
export {
|
||||
FileTypeCategory,
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export { MCPError } from './mcp';
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* MCP-specific error class with error code and optional data.
|
||||
*/
|
||||
export class MCPError extends Error {
|
||||
code: number;
|
||||
data?: unknown;
|
||||
|
||||
constructor(message: string, code: number, data?: unknown) {
|
||||
super(message);
|
||||
this.name = 'MCPError';
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ import type {
|
|||
ClientCapabilities,
|
||||
Implementation
|
||||
} from '$lib/types/mcp';
|
||||
import { MCPError } from '$lib/types/mcp';
|
||||
import { MCPError } from '$lib/errors';
|
||||
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
export interface MCPHostManagerConfig {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ export type {
|
|||
ToolExecutionResult
|
||||
} from './server-connection';
|
||||
|
||||
// Errors
|
||||
export { MCPError } from '$lib/errors';
|
||||
|
||||
// Types
|
||||
export { MCPError } from '$lib/types/mcp';
|
||||
export type {
|
||||
MCPClientConfig,
|
||||
MCPServerConfig,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/webso
|
|||
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
||||
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
||||
import type { MCPServerConfig, ClientCapabilities, Implementation } from '$lib/types/mcp';
|
||||
import { MCPError } from '$lib/types/mcp';
|
||||
import { MCPError } from '$lib/errors';
|
||||
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
|
||||
|
||||
// Type for tool call result content item
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@
|
|||
*/
|
||||
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { OpenAISseClient, type OpenAISseTurnResult } from '$lib/agentic/openai-sse-client';
|
||||
import {
|
||||
toAgenticMessages,
|
||||
type AgenticMessage,
|
||||
type AgenticChatCompletionRequest,
|
||||
type AgenticToolCallList
|
||||
} from '$lib/agentic/types';
|
||||
import { OpenAISseClient, type OpenAISseTurnResult } from '$lib/clients/openai-sse';
|
||||
import type {
|
||||
AgenticMessage,
|
||||
AgenticChatCompletionRequest,
|
||||
AgenticToolCallList
|
||||
} from '$lib/types/agentic';
|
||||
import { toAgenticMessages } from '$lib/utils';
|
||||
import type { ApiChatCompletionToolCall, ApiChatMessageData } from '$lib/types/api';
|
||||
import type { ChatMessagePromptProgress, ChatMessageTimings } from '$lib/types/chat';
|
||||
import type { MCPToolCall } from '$lib/types/mcp';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
import type { ApiChatCompletionRequest, ApiChatMessageContentPart } from './api';
|
||||
|
||||
/**
|
||||
* Agentic orchestration configuration.
|
||||
*/
|
||||
export interface AgenticConfig {
|
||||
enabled: boolean;
|
||||
maxTurns: number;
|
||||
maxToolPreviewLines: number;
|
||||
filterReasoningAfterFirstTurn: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool call payload for agentic messages.
|
||||
*/
|
||||
export type AgenticToolCallPayload = {
|
||||
id: string;
|
||||
type: 'function';
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Agentic message types for different roles.
|
||||
*/
|
||||
export type AgenticMessage =
|
||||
| {
|
||||
role: 'system' | 'user';
|
||||
content: string | ApiChatMessageContentPart[];
|
||||
}
|
||||
| {
|
||||
role: 'assistant';
|
||||
content?: string | ApiChatMessageContentPart[];
|
||||
tool_calls?: AgenticToolCallPayload[];
|
||||
}
|
||||
| {
|
||||
role: 'tool';
|
||||
tool_call_id: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
export type AgenticAssistantMessage = Extract<AgenticMessage, { role: 'assistant' }>;
|
||||
export type AgenticToolCallList = NonNullable<AgenticAssistantMessage['tool_calls']>;
|
||||
|
||||
export type AgenticChatCompletionRequest = Omit<ApiChatCompletionRequest, 'messages'> & {
|
||||
messages: AgenticMessage[];
|
||||
stream: true;
|
||||
tools?: ApiChatCompletionRequest['tools'];
|
||||
};
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
export type ChatMessageType = 'root' | 'text' | 'think' | 'system';
|
||||
export type ChatRole = 'user' | 'assistant' | 'system';
|
||||
|
||||
export interface ChatUploadedFile {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -32,17 +32,15 @@ export type {
|
|||
ApiRouterModelsUnloadResponse
|
||||
} from './api';
|
||||
|
||||
// Chat types
|
||||
// Chat types - interfaces only (enums are in $lib/enums)
|
||||
export type {
|
||||
ChatMessageType,
|
||||
ChatRole,
|
||||
ChatUploadedFile,
|
||||
ChatAttachmentDisplayItem,
|
||||
ChatAttachmentPreviewItem,
|
||||
ChatMessageSiblingInfo,
|
||||
ChatMessagePromptProgress,
|
||||
ChatMessageTimings
|
||||
} from './chat';
|
||||
} from './chat.d';
|
||||
|
||||
// Database types
|
||||
export type {
|
||||
|
|
|
|||
|
|
@ -10,18 +10,6 @@ export type { Tool, CallToolResult };
|
|||
export type ClientCapabilities = SDKClientCapabilities;
|
||||
export type Implementation = SDKImplementation;
|
||||
|
||||
export class MCPError extends Error {
|
||||
code: number;
|
||||
data?: unknown;
|
||||
|
||||
constructor(message: string, code: number, data?: unknown) {
|
||||
super(message);
|
||||
this.name = 'MCPError';
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
export type MCPTransportType = 'websocket' | 'streamable_http';
|
||||
|
||||
export type MCPServerConfig = {
|
||||
|
|
|
|||
|
|
@ -1,43 +1,9 @@
|
|||
import type {
|
||||
ApiChatCompletionRequest,
|
||||
ApiChatMessageContentPart,
|
||||
ApiChatMessageData
|
||||
} from '$lib/types/api';
|
||||
|
||||
export type AgenticToolCallPayload = {
|
||||
id: string;
|
||||
type: 'function';
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type AgenticMessage =
|
||||
| {
|
||||
role: 'system' | 'user';
|
||||
content: string | ApiChatMessageContentPart[];
|
||||
}
|
||||
| {
|
||||
role: 'assistant';
|
||||
content?: string | ApiChatMessageContentPart[];
|
||||
tool_calls?: AgenticToolCallPayload[];
|
||||
}
|
||||
| {
|
||||
role: 'tool';
|
||||
tool_call_id: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
export type AgenticAssistantMessage = Extract<AgenticMessage, { role: 'assistant' }>;
|
||||
export type AgenticToolCallList = NonNullable<AgenticAssistantMessage['tool_calls']>;
|
||||
|
||||
export type AgenticChatCompletionRequest = Omit<ApiChatCompletionRequest, 'messages'> & {
|
||||
messages: AgenticMessage[];
|
||||
stream: true;
|
||||
tools?: ApiChatCompletionRequest['tools'];
|
||||
};
|
||||
import type { ApiChatMessageData } from '$lib/types/api';
|
||||
import type { AgenticMessage } from '$lib/types/agentic';
|
||||
|
||||
/**
|
||||
* Converts API messages to agentic format.
|
||||
*/
|
||||
export function toAgenticMessages(messages: ApiChatMessageData[]): AgenticMessage[] {
|
||||
return messages.map((message) => {
|
||||
if (message.role === 'assistant' && message.tool_calls && message.tool_calls.length > 0) {
|
||||
|
|
@ -94,3 +94,6 @@ export { getLanguageFromFilename } from './syntax-highlight-language';
|
|||
|
||||
// Text file utilities
|
||||
export { isTextFileByName, readFileAsText, isLikelyTextFile } from './text-files';
|
||||
|
||||
// Agentic utilities
|
||||
export { toAgenticMessages } from './agentic';
|
||||
|
|
|
|||
Loading…
Reference in New Issue