refactor: Clean up UI types (#26909)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import {
|
||||
ChatAttachmentsList,
|
||||
ChatFormActions,
|
||||
ChatFormContenteditable,
|
||||
ChatFormContentEditable,
|
||||
ChatFormFileInputInvisible,
|
||||
ChatFormMcpResourcesList,
|
||||
ChatFormPickers,
|
||||
@@ -605,7 +605,7 @@
|
||||
class="flex-column relative min-h-12 items-center rounded-4xl md:rounded-3xl py-2 pb-2.25 shadow-sm transition-all focus-within:shadow-md md:py-3!"
|
||||
>
|
||||
{#if useContenteditable}
|
||||
<ChatFormContenteditable
|
||||
<ChatFormContentEditable
|
||||
class="px-5 py-1.5 md:pt-0 mb-0.5"
|
||||
bind:this={inputRef}
|
||||
bind:value
|
||||
|
||||
+3
-2
@@ -2,7 +2,8 @@
|
||||
import { CODE_BLOCK } from '$lib/constants';
|
||||
import { ColorMode } from '$lib/enums';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import type { ContentToken, SourceHistoryEntry } from '$lib/utils';
|
||||
import type { ContentEditableToken } from '$lib/types';
|
||||
import type { SourceHistoryEntry } from '$lib/utils';
|
||||
import {
|
||||
badgeAwareWordJump,
|
||||
buildFragment,
|
||||
@@ -63,7 +64,7 @@
|
||||
rootElement.dataset.empty = source.length === 0 ? 'true' : 'false';
|
||||
}
|
||||
|
||||
function renderTokens(tokens: ContentToken[]) {
|
||||
function renderTokens(tokens: ContentEditableToken[]) {
|
||||
if (!rootElement) return;
|
||||
|
||||
const caret = rangeToTextOffset(rootElement, safeRange());
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { ColorLevel } from './context-gauge';
|
||||
import { colorLevelTextClass } from './context-gauge';
|
||||
import type { ColorLevel } from '$lib/enums';
|
||||
|
||||
interface Props {
|
||||
percent: number | null;
|
||||
|
||||
+11
-11
@@ -1,25 +1,25 @@
|
||||
export type ColorLevel = 'ok' | 'warning' | 'critical' | 'neutral';
|
||||
import { ColorLevel } from '$lib/enums';
|
||||
|
||||
const WARNING_THRESHOLD = 80;
|
||||
const CRITICAL_THRESHOLD = 95;
|
||||
|
||||
export function colorLevelFromPercent(percent: number | null): ColorLevel {
|
||||
if (percent === null) return 'neutral';
|
||||
if (percent === null) return ColorLevel.NEUTRAL;
|
||||
|
||||
if (percent >= CRITICAL_THRESHOLD) return 'critical';
|
||||
if (percent >= CRITICAL_THRESHOLD) return ColorLevel.CRITICAL;
|
||||
|
||||
if (percent >= WARNING_THRESHOLD) return 'warning';
|
||||
if (percent >= WARNING_THRESHOLD) return ColorLevel.WARNING;
|
||||
|
||||
return 'ok';
|
||||
return ColorLevel.OK;
|
||||
}
|
||||
|
||||
export function colorLevelTextClass(level: ColorLevel): string {
|
||||
switch (level) {
|
||||
case 'critical':
|
||||
case ColorLevel.CRITICAL:
|
||||
return 'text-red-400';
|
||||
case 'warning':
|
||||
case ColorLevel.WARNING:
|
||||
return 'text-amber-400';
|
||||
case 'ok':
|
||||
case ColorLevel.OK:
|
||||
return 'text-muted-foreground';
|
||||
default:
|
||||
return 'text-muted-foreground';
|
||||
@@ -28,11 +28,11 @@ export function colorLevelTextClass(level: ColorLevel): string {
|
||||
|
||||
export function colorLevelBgClass(level: ColorLevel): string {
|
||||
switch (level) {
|
||||
case 'critical':
|
||||
case ColorLevel.CRITICAL:
|
||||
return 'bg-red-500';
|
||||
case 'warning':
|
||||
case ColorLevel.WARNING:
|
||||
return 'bg-amber-500';
|
||||
case 'ok':
|
||||
case ColorLevel.OK:
|
||||
return 'bg-green-500';
|
||||
default:
|
||||
return 'bg-muted';
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { isMobile } from '$lib/stores/viewport.svelte';
|
||||
import type { FileMentionEntry } from '$lib/types';
|
||||
import { abbreviateHome, type GlobEntryResult, runGlobSearchWithChildren } from '$lib/utils';
|
||||
import type { FileMentionEntry, GlobEntryResult } from '$lib/types';
|
||||
import { abbreviateHome, runGlobSearchWithChildren } from '$lib/utils';
|
||||
|
||||
/**
|
||||
* Floating file/folder mention picker. The chat input is the search
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
import { useScrollActiveRow } from '$lib/hooks/use-scroll-active-row.svelte';
|
||||
import { ToolsService } from '$lib/services/tools.service';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import type { GlobEntry } from '$lib/types';
|
||||
import {
|
||||
abbreviateHome,
|
||||
buildCaseInsensitiveGlob,
|
||||
type GlobEntry,
|
||||
joinPath,
|
||||
lastPathSegment,
|
||||
runGlobSearchWithChildren
|
||||
|
||||
+2
-6
@@ -12,13 +12,9 @@
|
||||
import ChatMessageToolCallBlockSearchResults from './ChatMessageToolCallBlockSearchResults.svelte';
|
||||
import ChatMessageToolCallBlockWriteFile from './ChatMessageToolCallBlockWriteFile.svelte';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import type { DatabaseMessageExtra } from '$lib/types';
|
||||
import {
|
||||
type AgenticSection,
|
||||
extractSearchQuery,
|
||||
extractSearchResults,
|
||||
isWebSearchToolName
|
||||
} from '$lib/utils';
|
||||
import { extractSearchQuery, extractSearchResults, isWebSearchToolName } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+2
-4
@@ -8,14 +8,12 @@
|
||||
import { MarkdownContent, SyntaxHighlightedCode } from '$lib/components/app';
|
||||
import { MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
|
||||
import { AttachmentType, FileTypeText, MimeTypeAudio, ToolResultKind } from '$lib/enums';
|
||||
import type { DatabaseMessageExtra } from '$lib/types';
|
||||
import type { AgenticSection, DatabaseMessageExtra, ToolResultLine } from '$lib/types';
|
||||
import {
|
||||
type AgenticSection,
|
||||
classifyToolResult,
|
||||
formatJsonPretty,
|
||||
getBuiltinToolUi,
|
||||
parseToolResultWithMedia,
|
||||
type ToolResultLine
|
||||
parseToolResultWithMedia
|
||||
} from '$lib/utils';
|
||||
import { createBase64DataUrl } from '$lib/utils/data-url';
|
||||
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
import { XCircle } from '@lucide/svelte';
|
||||
import { MAX_HEIGHT_CODE_BLOCK, RESULT_STAT_SEPARATOR } from '$lib/constants';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { abbreviateHome, type AgenticSection, computeLineDiff, prefixFor } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome, computeLineDiff, prefixFor } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+4
-4
@@ -11,19 +11,19 @@
|
||||
import { AlertTriangle, Check, Loader2, XCircle } from '@lucide/svelte';
|
||||
import { CollapsibleTerminalBlock } from '$lib/components/app';
|
||||
import { SETTINGS_KEYS, TOOL_RUNTIME_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants';
|
||||
import { AttachmentType } from '$lib/enums';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import type { AgenticSection, ToolResultLine } from '$lib/types';
|
||||
import type { DatabaseMessageExtra } from '$lib/types';
|
||||
import {
|
||||
abbreviateHome,
|
||||
type AgenticSection,
|
||||
type ExecShellExitStatus,
|
||||
highlightCode,
|
||||
isExitCodeSummaryLine,
|
||||
parseExecShellCommandError,
|
||||
parseExecShellCommandExitStatus,
|
||||
parseToolResultWithMedia,
|
||||
type ToolResultLine
|
||||
parseToolResultWithMedia
|
||||
} from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -222,7 +222,7 @@
|
||||
>
|
||||
{#each outputLines as line, i (i)}
|
||||
<div class="font-mono text-[11px] leading-relaxed whitespace-pre-wrap">{line.text}</div>
|
||||
{#if line.media}
|
||||
{#if line.media?.type === AttachmentType.IMAGE}
|
||||
<img
|
||||
src={line.media.base64Url}
|
||||
alt={line.media.name}
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
import ToolCallBlock from './ToolCallBlock.svelte';
|
||||
import { XCircle } from '@lucide/svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { abbreviateHome, type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Clock, Loader2 } from '@lucide/svelte';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import type { AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
import { Info, Loader2 } from '@lucide/svelte';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { abbreviateHome, type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
import ToolCallBlock from './ToolCallBlock.svelte';
|
||||
import { XCircle } from '@lucide/svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { abbreviateHome, type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
import ToolCallBlock from './ToolCallBlock.svelte';
|
||||
import { SyntaxHighlightedCode } from '$lib/components/app';
|
||||
import { CODE_BLOCK, MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
|
||||
import { type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
import { ATTACHMENT_SAVED_REGEX } from '$lib/constants/agentic.constants';
|
||||
import { AttachmentType, MimeTypeAudio } from '$lib/enums';
|
||||
import type { DatabaseMessageExtraAudioFile, DatabaseMessageExtraImageFile } from '$lib/types';
|
||||
import { type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { createBase64DataUrl } from '$lib/utils/data-url';
|
||||
|
||||
interface Props {
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@
|
||||
import { SyntaxHighlightedCode } from '$lib/components/app';
|
||||
import { MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
|
||||
import { FileTypeText } from '$lib/enums';
|
||||
import { type AgenticSection, getBuiltinToolUi } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { getBuiltinToolUi } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+2
-3
@@ -5,13 +5,12 @@
|
||||
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import type { AgenticSection, SearchResult } from '$lib/types';
|
||||
import {
|
||||
type AgenticSection,
|
||||
extractSearchQuery,
|
||||
extractSearchResults,
|
||||
faviconForUrl,
|
||||
sanitizeExternalUrl,
|
||||
type SearchResult
|
||||
sanitizeExternalUrl
|
||||
} from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@
|
||||
import { SyntaxHighlightedCode } from '$lib/components/app';
|
||||
import { MAX_HEIGHT_CODE_BLOCK, RESULT_STAT_SEPARATOR } from '$lib/constants';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
import { abbreviateHome, type AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { abbreviateHome } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@
|
||||
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { type AgenticSection, type BuiltinToolUiEntry, getBuiltinToolUi } from '$lib/utils';
|
||||
import type { AgenticSection, BuiltinToolUiEntry } from '$lib/types';
|
||||
import { getBuiltinToolUi } from '$lib/utils';
|
||||
import type { Component, Snippet } from 'svelte';
|
||||
|
||||
type ToolCallBlockMetaWithError = TMeta & { errorMessage?: string };
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
// stay focused on its own format quirks.
|
||||
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import type { AgenticSection } from '$lib/utils/agentic';
|
||||
import type { AgenticSection } from '$lib/types/agentic';
|
||||
import { parsePartialJsonArgs } from '$lib/utils/parse-partial-json-args';
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import { type AgenticSection, tryParseToolResultObject } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { tryParseToolResultObject } from '$lib/utils';
|
||||
|
||||
export type EditFileEdit = {
|
||||
oldText: string;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import type { AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
export type ExecShellCommandMeta = {
|
||||
command: string;
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@
|
||||
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import { type AgenticSection, splitSearchSummaryList } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { splitSearchSummaryList } from '$lib/utils';
|
||||
|
||||
export type FileGlobSearchMeta = {
|
||||
path: string;
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@
|
||||
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import { type AgenticSection, splitSearchSummaryList } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { splitSearchSummaryList } from '$lib/utils';
|
||||
|
||||
export type GrepSearchMatch = {
|
||||
file: string;
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { CODE_BLOCK, FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import { type AgenticSection, getFileTypeByExtension } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { getFileTypeByExtension } from '$lib/utils';
|
||||
|
||||
export type ReadFileMeta = {
|
||||
fileName: string;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
||||
PREFIX_SIZE,
|
||||
READ_MEDIA_SIZE_REGEX
|
||||
} from '$lib/constants/read-media';
|
||||
import type { AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
export interface ReadMediaMeta {
|
||||
fileName: string;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import type { AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
export type RunJavascriptMeta = {
|
||||
code: string;
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@
|
||||
import { parseToolArgs } from './_shared';
|
||||
import { CODE_BLOCK, FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
|
||||
import { BuiltInTool } from '$lib/enums';
|
||||
import { type AgenticSection, getFileTypeByExtension, tryParseToolResultObject } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import { getFileTypeByExtension, tryParseToolResultObject } from '$lib/utils';
|
||||
|
||||
export type WriteFileMeta = {
|
||||
fileName: string;
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
agenticResolvePermission
|
||||
} from '$lib/stores/agentic.svelte';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
import type {
|
||||
ChatMessageAgenticTimings,
|
||||
ChatMessageAgenticTurnStats,
|
||||
DatabaseMessage
|
||||
} from '$lib/types';
|
||||
import { type AgenticSection, deriveAgenticSections } from '$lib/utils';
|
||||
import { deriveAgenticSections } from '$lib/utils';
|
||||
|
||||
interface Props {
|
||||
message: DatabaseMessage;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { AgenticSectionType } from '$lib/enums';
|
||||
import { config } from '$lib/stores/settings.svelte';
|
||||
import type { DatabaseMessageExtra } from '$lib/types';
|
||||
import type { AgenticSection } from '$lib/utils';
|
||||
import type { AgenticSection } from '$lib/types';
|
||||
|
||||
interface Props {
|
||||
section: AgenticSection;
|
||||
|
||||
@@ -120,7 +120,7 @@ export { default as ChatAttachmentsPreviewCurrentItem } from './ChatAttachments/
|
||||
* Used by ChatScreenForm and ChatMessageEditForm for both new conversations and message editing.
|
||||
*
|
||||
* **Architecture:**
|
||||
* - Composes ChatFormTextarea (or ChatFormContenteditable for messages with
|
||||
* - Composes ChatFormTextarea (or ChatFormContentEditable for messages with
|
||||
* file mention links), ChatFormActions, and ChatFormPickerMcpPrompts
|
||||
* - Manages file upload state via `uploadedFiles` bindable prop
|
||||
* - Integrates with ModelsSelectorDropdown for model selection in router mode
|
||||
@@ -272,7 +272,7 @@ export { default as ChatFormMcpResourcesList } from './ChatForm/ChatFormMcpResou
|
||||
* source string. ChatForm swaps it in once a mention link lands in the
|
||||
* buffer. Shares the focus()/resetHeight()/caret handle with the textarea.
|
||||
*/
|
||||
export { default as ChatFormContenteditable } from './ChatForm/ChatFormContenteditable.svelte';
|
||||
export { default as ChatFormContentEditable } from './ChatForm/ChatFormContentEditable.svelte';
|
||||
|
||||
/**
|
||||
* Plain auto-resizing textarea with IME composition support. Default input
|
||||
|
||||
@@ -89,3 +89,13 @@ export enum FileMentionEntryType {
|
||||
FILE = 'file',
|
||||
DIRECTORY = 'directory'
|
||||
}
|
||||
|
||||
/**
|
||||
* Kinds of tokens the chat-form contenteditable produces.
|
||||
*/
|
||||
export enum ContentEditableTokenKind {
|
||||
TEXT = 'text',
|
||||
BADGE = 'badge',
|
||||
INLINE_CODE = 'inlineCode',
|
||||
CODE_BLOCK = 'codeBlock'
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ export {
|
||||
PdfViewMode,
|
||||
ReasoningFormat,
|
||||
ChatFormCommandAction,
|
||||
FileMentionEntryType
|
||||
FileMentionEntryType,
|
||||
ContentEditableTokenKind
|
||||
} from './chat.enums';
|
||||
|
||||
export { SessionRecordType } from './conversation-import.enums';
|
||||
@@ -71,7 +72,14 @@ export { ServerRole, ServerModelStatus, ServerModelsSseEventType } from './serve
|
||||
|
||||
export { ParameterSource, SyncableParameterType, SettingsFieldType } from './settings.enums';
|
||||
|
||||
export { ColorMode, HtmlInputType, McpPromptVariant, TooltipSide, UrlProtocol } from './ui.enums';
|
||||
export {
|
||||
ColorLevel,
|
||||
ColorMode,
|
||||
HtmlInputType,
|
||||
McpPromptVariant,
|
||||
TooltipSide,
|
||||
UrlProtocol
|
||||
} from './ui.enums';
|
||||
|
||||
export { KeyboardKey } from './keyboard.enums';
|
||||
|
||||
|
||||
@@ -34,3 +34,13 @@ export enum UrlProtocol {
|
||||
export enum HtmlInputType {
|
||||
FILE = 'file'
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert level that drives the context gauge dial color.
|
||||
*/
|
||||
export enum ColorLevel {
|
||||
OK = 'ok',
|
||||
WARNING = 'warning',
|
||||
CRITICAL = 'critical',
|
||||
NEUTRAL = 'neutral'
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
*/
|
||||
|
||||
import { useProcessingState } from './use-processing-state.svelte';
|
||||
import {
|
||||
type ColorLevel,
|
||||
colorLevelFromPercent
|
||||
} from '$lib/components/app/chat/ChatForm/ChatFormContextGauge/context-gauge';
|
||||
import { colorLevelFromPercent } from '$lib/components/app/chat/ChatForm/ChatFormContextGauge/context-gauge';
|
||||
import { STATS_UNITS } from '$lib/constants';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import { ColorLevel, MessageRole } from '$lib/enums';
|
||||
import { chatStore } from '$lib/stores/chat.svelte';
|
||||
import { activeMessages } from '$lib/stores/conversations.svelte';
|
||||
import {
|
||||
|
||||
Vendored
+59
-2
@@ -5,9 +5,14 @@ import type {
|
||||
ApiChatMessageData
|
||||
} from './api';
|
||||
import type { ChatMessagePromptProgress, ChatMessageTimings } from './chat';
|
||||
import type { DatabaseMessage, DatabaseMessageExtra, McpServerOverride } from './database';
|
||||
import type {
|
||||
DatabaseMessage,
|
||||
DatabaseMessageExtra,
|
||||
DatabaseMessageExtraAudioFile,
|
||||
DatabaseMessageExtraImageFile
|
||||
} from './database';
|
||||
import type { MessageRole } from '$lib/enums';
|
||||
import { ToolCallType } from '$lib/enums';
|
||||
import { AgenticSectionType, ContinueIntentKind, ToolCallType } from '$lib/enums';
|
||||
|
||||
/**
|
||||
* Agentic orchestration configuration.
|
||||
@@ -171,3 +176,55 @@ export interface SteeringMessage {
|
||||
content: string;
|
||||
extras?: DatabaseMessageExtra[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a parsed section of agentic content for display
|
||||
*/
|
||||
export interface AgenticSection {
|
||||
type: AgenticSectionType;
|
||||
content: string;
|
||||
toolName?: string;
|
||||
toolArgs?: string;
|
||||
toolResult?: string;
|
||||
toolResultExtras?: DatabaseMessageExtra[];
|
||||
/** Working directory the tool call ran with (from the tool result
|
||||
* message), shown by the exec_shell_command renderer. */
|
||||
toolCwd?: string;
|
||||
/** ID of the model-side tool call (matches tool_calls[i].id). Lets
|
||||
* downstream consumers correlate a section with the agentic loop's
|
||||
* currently-executing tool, e.g. to drive live-streaming UI state
|
||||
* by matching against agenticStore.executingToolCallId. */
|
||||
toolCallId?: string;
|
||||
wasInterrupted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a tool result line that may reference an image attachment
|
||||
*/
|
||||
export type ToolResultLine = {
|
||||
text: string;
|
||||
media?: DatabaseMessageExtraImageFile | DatabaseMessageExtraAudioFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Classification of how a Continue click on an assistant message should resume
|
||||
* generation. The caller dispatches the resume path based on this value.
|
||||
*
|
||||
* append_text -> the target is a plain text turn, resume with
|
||||
* continue_final_message and rehydrate the persisted
|
||||
* tool_calls and attachments through the regular DB to API
|
||||
* message converter.
|
||||
* rerun_turn -> the target carries tool_calls that were never resolved by
|
||||
* tool result messages. The agentic stream was cut mid turn,
|
||||
* so we drop the target and rerun the loop from the previous
|
||||
* history. truncateAfter is the last kept index, inclusive.
|
||||
* next_turn -> the target's tool_calls were already resolved by trailing
|
||||
* tool results. Hand the history up to and including the
|
||||
* last consecutive tool result back to the agentic loop so it
|
||||
* starts the next turn naturally. truncateAfter points at
|
||||
* that last tool result.
|
||||
*/
|
||||
export type ContinueIntent =
|
||||
| { kind: ContinueIntentKind.APPEND_TEXT }
|
||||
| { kind: ContinueIntentKind.RERUN_TURN; truncateAfter: number }
|
||||
| { kind: ContinueIntentKind.NEXT_TURN; truncateAfter: number };
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { ContentEditableTokenKind } from '$lib/enums';
|
||||
|
||||
/**
|
||||
* A single token produced by the chat-form contenteditable tokenizer:
|
||||
* plain text, a file/folder mention badge, or an inline/fenced code span.
|
||||
*/
|
||||
export type ContentEditableToken =
|
||||
| { kind: ContentEditableTokenKind.TEXT; text: string }
|
||||
| { kind: ContentEditableTokenKind.BADGE; name: string; path: string }
|
||||
| { kind: ContentEditableTokenKind.INLINE_CODE; text: string }
|
||||
| { kind: ContentEditableTokenKind.CODE_BLOCK; text: string };
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
import type { GlobSearchType } from '$lib/enums';
|
||||
|
||||
/**
|
||||
* A single directory entry returned by the server's `file_glob_search`
|
||||
* tool.
|
||||
*/
|
||||
export interface GlobEntry {
|
||||
path: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query arguments for a `file_glob_search` run.
|
||||
*/
|
||||
export interface GlobSearchArgs {
|
||||
path: string;
|
||||
include: string;
|
||||
maxDepth: number;
|
||||
rankQuery: string;
|
||||
/** Last segment of a path-navigation query (`~/dir/sub`), undefined for
|
||||
* a plain home-relative glob. Lets callers act on the exact targeted
|
||||
* segment (e.g. the WD picker "entering" a directory). */
|
||||
last?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ranked result of a glob search against a base path.
|
||||
*/
|
||||
export interface GlobSearchResult {
|
||||
base: string;
|
||||
entries: GlobEntry[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A glob entry resolved to an absolute path with its display name.
|
||||
*/
|
||||
export interface GlobEntryResult {
|
||||
path: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options controlling how a search descends into a matched directory.
|
||||
*/
|
||||
export interface GlobSearchChildOptions {
|
||||
type?: GlobSearchType;
|
||||
/** Descend only on a trailing path separator (mention picker); off for
|
||||
* the WD picker, which descends on any exact match. */
|
||||
descendOnTrailingSeparator?: boolean;
|
||||
childMaxDepth?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a glob search that may also list a matched directory's
|
||||
* children.
|
||||
*/
|
||||
export interface GlobSearchChildResult {
|
||||
base: string;
|
||||
args: GlobSearchArgs;
|
||||
/** Outer ranked entries plus the walked directory's children (absolute). */
|
||||
entries: GlobEntryResult[];
|
||||
/** Absolute path of the directory whose children were appended. */
|
||||
exactDir?: string;
|
||||
error?: string;
|
||||
}
|
||||
@@ -161,6 +161,22 @@ export type {
|
||||
MCPServerResources
|
||||
} from './mcp';
|
||||
|
||||
// Search result types
|
||||
export type { SearchResult } from './search';
|
||||
|
||||
// Glob search types (working-directory / mention pickers)
|
||||
export type {
|
||||
GlobEntry,
|
||||
GlobSearchArgs,
|
||||
GlobSearchResult,
|
||||
GlobEntryResult,
|
||||
GlobSearchChildOptions,
|
||||
GlobSearchChildResult
|
||||
} from './glob';
|
||||
|
||||
// Contenteditable token types (chat form)
|
||||
export type { ContentEditableToken } from './contenteditable';
|
||||
|
||||
// Agentic types
|
||||
export type {
|
||||
AgenticConfig,
|
||||
@@ -174,7 +190,10 @@ export type {
|
||||
AgenticFlowOptions,
|
||||
AgenticFlowParams,
|
||||
AgenticFlowResult,
|
||||
SteeringMessage
|
||||
SteeringMessage,
|
||||
AgenticSection,
|
||||
ToolResultLine,
|
||||
ContinueIntent
|
||||
} from './agentic';
|
||||
|
||||
// Navigation types
|
||||
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* A single parsed entry from a web-search MCP tool result.
|
||||
*/
|
||||
export type SearchResult = {
|
||||
title: string;
|
||||
url: string;
|
||||
published?: string;
|
||||
author?: string;
|
||||
highlights?: string;
|
||||
};
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
MessageRole,
|
||||
ToolResultKind
|
||||
} from '$lib/enums';
|
||||
import type { AgenticSection, ContinueIntent, ToolResultLine } from '$lib/types/agentic';
|
||||
import type { ApiChatCompletionToolCall } from '$lib/types/api';
|
||||
import type {
|
||||
DatabaseMessage,
|
||||
@@ -20,35 +21,6 @@ import type {
|
||||
DatabaseMessageExtraImageFile
|
||||
} from '$lib/types/database';
|
||||
|
||||
/**
|
||||
* Represents a parsed section of agentic content for display
|
||||
*/
|
||||
export interface AgenticSection {
|
||||
type: AgenticSectionType;
|
||||
content: string;
|
||||
toolName?: string;
|
||||
toolArgs?: string;
|
||||
toolResult?: string;
|
||||
toolResultExtras?: DatabaseMessageExtra[];
|
||||
/** Working directory the tool call ran with (from the tool result
|
||||
* message), shown by the exec_shell_command renderer. */
|
||||
toolCwd?: string;
|
||||
/** ID of the model-side tool call (matches tool_calls[i].id). Lets
|
||||
* downstream consumers correlate a section with the agentic loop's
|
||||
* currently-executing tool, e.g. to drive live-streaming UI state
|
||||
* by matching against agenticStore.executingToolCallId. */
|
||||
toolCallId?: string;
|
||||
wasInterrupted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a tool result line that may reference a media attachment (image or audio)
|
||||
*/
|
||||
export type ToolResultLine = {
|
||||
text: string;
|
||||
media?: DatabaseMessageExtraImageFile | DatabaseMessageExtraAudioFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Derives display sections from a single assistant message and its direct tool results.
|
||||
*
|
||||
@@ -485,29 +457,6 @@ export function hasAgenticContent(
|
||||
return toolMessages.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classification of how a Continue click on an assistant message should resume
|
||||
* generation. The caller dispatches the resume path based on this value.
|
||||
*
|
||||
* append_text -> the target is a plain text turn, resume with
|
||||
* continue_final_message and rehydrate the persisted
|
||||
* tool_calls and attachments through the regular DB to API
|
||||
* message converter.
|
||||
* rerun_turn -> the target carries tool_calls that were never resolved by
|
||||
* tool result messages. The agentic stream was cut mid turn,
|
||||
* so we drop the target and rerun the loop from the previous
|
||||
* history. truncateAfter is the last kept index, inclusive.
|
||||
* next_turn -> the target's tool_calls were already resolved by trailing
|
||||
* tool results. Hand the history up to and including the
|
||||
* last consecutive tool result back to the agentic loop so it
|
||||
* starts the next turn naturally. truncateAfter points at
|
||||
* that last tool result.
|
||||
*/
|
||||
export type ContinueIntent =
|
||||
| { kind: ContinueIntentKind.APPEND_TEXT }
|
||||
| { kind: ContinueIntentKind.RERUN_TURN; truncateAfter: number }
|
||||
| { kind: ContinueIntentKind.NEXT_TURN; truncateAfter: number };
|
||||
|
||||
/**
|
||||
* Decide how a Continue click on messages[idx] should resume generation.
|
||||
* Pure function over the persisted history snapshot.
|
||||
|
||||
@@ -35,14 +35,10 @@ import {
|
||||
MENTION_BADGE_SVG_ATTRIBUTES,
|
||||
SETTINGS_KEYS
|
||||
} from '$lib/constants';
|
||||
import { ContentEditableTokenKind } from '$lib/enums';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { toolsStore } from '$lib/stores/tools.svelte';
|
||||
|
||||
export type ContentToken =
|
||||
| { kind: 'text'; text: string }
|
||||
| { kind: 'badge'; name: string; path: string }
|
||||
| { kind: 'inlineCode'; text: string }
|
||||
| { kind: 'codeBlock'; text: string };
|
||||
import type { ContentEditableToken } from '$lib/types/contenteditable';
|
||||
|
||||
// Block wrappers browsers insert for newlines; each folds back into a
|
||||
// single `\n` during serialization.
|
||||
@@ -112,8 +108,8 @@ export function isOffsetInCodeBlock(source: string, offset: number): boolean {
|
||||
* interleave in the remaining gaps. Any whitespace after a badge
|
||||
* stays in a plain text token so the round trip is byte-exact.
|
||||
*/
|
||||
export function tokenizeContent(input: string): ContentToken[] {
|
||||
const tokens: ContentToken[] = [];
|
||||
export function tokenizeContent(input: string): ContentEditableToken[] {
|
||||
const tokens: ContentEditableToken[] = [];
|
||||
|
||||
let cursor = 0;
|
||||
|
||||
@@ -130,8 +126,8 @@ export function tokenizeContent(input: string): ContentToken[] {
|
||||
|
||||
tokens.push(
|
||||
match[1] !== undefined
|
||||
? { kind: 'codeBlock', text: match[1] }
|
||||
: { kind: 'inlineCode', text: match[2] }
|
||||
? { kind: ContentEditableTokenKind.CODE_BLOCK, text: match[1] }
|
||||
: { kind: ContentEditableTokenKind.INLINE_CODE, text: match[2] }
|
||||
);
|
||||
cursor = start + match[0].length;
|
||||
}
|
||||
@@ -146,7 +142,7 @@ export function tokenizeContent(input: string): ContentToken[] {
|
||||
/**
|
||||
* Tokenize a code-free segment into text and badge tokens.
|
||||
*/
|
||||
function pushTextAndBadgeTokens(input: string, tokens: ContentToken[]) {
|
||||
function pushTextAndBadgeTokens(input: string, tokens: ContentEditableToken[]) {
|
||||
let cursor = 0;
|
||||
|
||||
MENTION_BADGE_RE.lastIndex = 0;
|
||||
@@ -158,15 +154,15 @@ function pushTextAndBadgeTokens(input: string, tokens: ContentToken[]) {
|
||||
const start = match.index;
|
||||
|
||||
if (start > cursor) {
|
||||
tokens.push({ kind: 'text', text: input.slice(cursor, start) });
|
||||
tokens.push({ kind: ContentEditableTokenKind.TEXT, text: input.slice(cursor, start) });
|
||||
}
|
||||
|
||||
tokens.push({ kind: 'badge', name, path });
|
||||
tokens.push({ kind: ContentEditableTokenKind.BADGE, name, path });
|
||||
cursor = start + whole.length;
|
||||
}
|
||||
|
||||
if (cursor < input.length) {
|
||||
tokens.push({ kind: 'text', text: input.slice(cursor) });
|
||||
tokens.push({ kind: ContentEditableTokenKind.TEXT, text: input.slice(cursor) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +285,8 @@ export function serializeContent(root: HTMLElement): string {
|
||||
* A mismatch means token boundaries shifted (a code span was just
|
||||
* completed or broken) and the DOM needs a rebuild to restyle.
|
||||
*/
|
||||
export function domMatchesTokens(root: HTMLElement, tokens: ContentToken[]): boolean {
|
||||
const expected = tokens.filter((token) => token.kind !== 'text');
|
||||
export function domMatchesTokens(root: HTMLElement, tokens: ContentEditableToken[]): boolean {
|
||||
const expected = tokens.filter((token) => token.kind !== ContentEditableTokenKind.TEXT);
|
||||
|
||||
let index = 0;
|
||||
|
||||
@@ -313,7 +309,7 @@ export function domMatchesTokens(root: HTMLElement, tokens: ContentToken[]): boo
|
||||
if (!token) return false;
|
||||
|
||||
if (isBadge) {
|
||||
if (token.kind !== 'badge') return false;
|
||||
if (token.kind !== ContentEditableTokenKind.BADGE) return false;
|
||||
|
||||
if (token.name !== (el.dataset.mentionName ?? '')) return false;
|
||||
|
||||
@@ -322,15 +318,18 @@ export function domMatchesTokens(root: HTMLElement, tokens: ContentToken[]): boo
|
||||
continue;
|
||||
}
|
||||
|
||||
const codeKind = el.dataset.codeToken === 'block' ? 'codeBlock' : 'inlineCode';
|
||||
const codeKind: ContentEditableTokenKind =
|
||||
el.dataset.codeToken === 'block'
|
||||
? ContentEditableTokenKind.CODE_BLOCK
|
||||
: ContentEditableTokenKind.INLINE_CODE;
|
||||
|
||||
if (token.kind !== codeKind) return false;
|
||||
|
||||
if (
|
||||
(token.kind === 'inlineCode' || token.kind === 'codeBlock') &&
|
||||
token.text !== (el.textContent ?? '')
|
||||
token.kind === ContentEditableTokenKind.INLINE_CODE ||
|
||||
token.kind === ContentEditableTokenKind.CODE_BLOCK
|
||||
) {
|
||||
return false;
|
||||
if (token.text !== (el.textContent ?? '')) return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,23 +521,26 @@ export function rangeToTextOffset(root: HTMLElement, range: Range | null): numbe
|
||||
* string + inline SVG are shared with the rehype plugin via
|
||||
* `$lib/constants`.
|
||||
*/
|
||||
export function buildFragment(tokens: ContentToken[]): DocumentFragment {
|
||||
export function buildFragment(tokens: ContentEditableToken[]): DocumentFragment {
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
for (let index = 0; index < tokens.length; index++) {
|
||||
const token = tokens[index];
|
||||
|
||||
if (token.kind === 'text') {
|
||||
if (token.kind === ContentEditableTokenKind.TEXT) {
|
||||
let text = token.text;
|
||||
|
||||
// The separator \n at a fenced-block boundary is synthesized
|
||||
// at serialization time; keeping it in the DOM would render a
|
||||
// phantom empty line next to the block.
|
||||
if (tokens[index - 1]?.kind === 'codeBlock' && text.startsWith('\n')) {
|
||||
if (
|
||||
tokens[index - 1]?.kind === ContentEditableTokenKind.CODE_BLOCK &&
|
||||
text.startsWith('\n')
|
||||
) {
|
||||
text = text.slice(1);
|
||||
}
|
||||
|
||||
if (tokens[index + 1]?.kind === 'codeBlock' && text.endsWith('\n')) {
|
||||
if (tokens[index + 1]?.kind === ContentEditableTokenKind.CODE_BLOCK && text.endsWith('\n')) {
|
||||
text = text.slice(0, -1);
|
||||
}
|
||||
|
||||
@@ -549,10 +551,14 @@ export function buildFragment(tokens: ContentToken[]): DocumentFragment {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.kind === 'inlineCode' || token.kind === 'codeBlock') {
|
||||
if (
|
||||
token.kind === ContentEditableTokenKind.INLINE_CODE ||
|
||||
token.kind === ContentEditableTokenKind.CODE_BLOCK
|
||||
) {
|
||||
const code = document.createElement('code');
|
||||
|
||||
code.dataset.codeToken = token.kind === 'codeBlock' ? 'block' : 'inline';
|
||||
code.dataset.codeToken =
|
||||
token.kind === ContentEditableTokenKind.CODE_BLOCK ? 'block' : 'inline';
|
||||
code.textContent = token.text;
|
||||
fragment.appendChild(code);
|
||||
|
||||
@@ -728,11 +734,14 @@ export function badgeAwareWordJump(
|
||||
|
||||
for (const token of tokenizeContent(source)) {
|
||||
const len =
|
||||
token.kind === 'badge' ? badgeSourceLength(token.name, token.path) : token.text.length;
|
||||
token.kind === ContentEditableTokenKind.BADGE
|
||||
? badgeSourceLength(token.name, token.path)
|
||||
: token.text.length;
|
||||
|
||||
if (token.kind === 'badge') badgeSpans.push([masked.length, masked.length + len]);
|
||||
if (token.kind === ContentEditableTokenKind.BADGE)
|
||||
badgeSpans.push([masked.length, masked.length + len]);
|
||||
|
||||
masked += token.kind === 'badge' ? 'a'.repeat(len) : token.text;
|
||||
masked += token.kind === ContentEditableTokenKind.BADGE ? 'a'.repeat(len) : token.text;
|
||||
}
|
||||
|
||||
if (badgeSpans.length === 0) return null;
|
||||
@@ -795,7 +804,7 @@ export function badgeAwareWordJump(
|
||||
export function leadingBadgeEdgeOffset(source: string, caret: number): number | null {
|
||||
const [first] = tokenizeContent(source);
|
||||
|
||||
if (!first || first.kind !== 'badge') return null;
|
||||
if (!first || first.kind !== ContentEditableTokenKind.BADGE) return null;
|
||||
|
||||
return caret === badgeSourceLength(first.name, first.path) ? 0 : null;
|
||||
}
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
*/
|
||||
|
||||
import { lastPathSegment } from './path-display';
|
||||
import {
|
||||
buildGlobSearchArgs,
|
||||
type GlobEntry,
|
||||
type GlobSearchArgs,
|
||||
joinPath,
|
||||
rankEntries
|
||||
} from './working-directory';
|
||||
import { buildGlobSearchArgs, joinPath, rankEntries } from './working-directory';
|
||||
import { GLOB, PATH_SEPARATOR, SEARCH } from '$lib/constants';
|
||||
import { BuiltInTool, GlobSearchType } from '$lib/enums';
|
||||
import { ToolsService } from '$lib/services/tools.service';
|
||||
import type {
|
||||
GlobEntry,
|
||||
GlobEntryResult,
|
||||
GlobSearchArgs,
|
||||
GlobSearchChildOptions,
|
||||
GlobSearchChildResult,
|
||||
GlobSearchResult
|
||||
} from '$lib/types/glob';
|
||||
|
||||
const SEARCH_CACHE_TTL_MS = 2000;
|
||||
|
||||
@@ -26,12 +28,6 @@ interface CacheEntry {
|
||||
|
||||
const searchCache = new Map<string, CacheEntry>();
|
||||
|
||||
export interface GlobSearchResult {
|
||||
base: string;
|
||||
entries: GlobEntry[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export async function runGlobSearch(
|
||||
args: GlobSearchArgs,
|
||||
type: GlobSearchType,
|
||||
@@ -66,30 +62,6 @@ export async function runGlobSearch(
|
||||
return { base, entries };
|
||||
}
|
||||
|
||||
export interface GlobEntryResult {
|
||||
path: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface GlobSearchChildOptions {
|
||||
type?: GlobSearchType;
|
||||
/** Descend only on a trailing path separator (mention picker); off for
|
||||
* the WD picker, which descends on any exact match. */
|
||||
descendOnTrailingSeparator?: boolean;
|
||||
childMaxDepth?: number;
|
||||
}
|
||||
|
||||
export interface GlobSearchChildResult {
|
||||
base: string;
|
||||
args: GlobSearchArgs;
|
||||
/** Outer ranked entries plus the walked directory's children (absolute). */
|
||||
entries: GlobEntryResult[];
|
||||
/** Absolute path of the directory whose children were appended. */
|
||||
exactDir?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
function toEntryResult(e: GlobEntry, base: string): GlobEntryResult {
|
||||
return { name: lastPathSegment(e.path), path: joinPath(base, e.path), type: e.type };
|
||||
}
|
||||
|
||||
@@ -179,18 +179,11 @@ export {
|
||||
rankEntries,
|
||||
joinPath,
|
||||
highlightMatch,
|
||||
type GlobEntry,
|
||||
type GlobSearchArgs,
|
||||
type PathQuery
|
||||
} from './working-directory';
|
||||
|
||||
// Shared `file_glob_search` runner with a short-lived result cache
|
||||
export {
|
||||
runGlobSearch,
|
||||
runGlobSearchWithChildren,
|
||||
type GlobEntryResult,
|
||||
type GlobSearchResult
|
||||
} from './glob-search';
|
||||
export { runGlobSearch, runGlobSearchWithChildren } from './glob-search';
|
||||
|
||||
// Mention-token detection (for the `@`-triggered file/folder mention picker)
|
||||
export {
|
||||
@@ -219,8 +212,7 @@ export {
|
||||
rangeToTextOffset,
|
||||
textOffsetToRange,
|
||||
badgeAwareWordJump,
|
||||
leadingBadgeEdgeOffset,
|
||||
type ContentToken
|
||||
leadingBadgeEdgeOffset
|
||||
} from './contenteditable-tokenizer';
|
||||
|
||||
// Source-space undo/redo history for the chat-form contenteditable
|
||||
@@ -251,9 +243,7 @@ export {
|
||||
parseToolResultWithMedia,
|
||||
splitSearchSummaryList,
|
||||
hasAgenticContent,
|
||||
classifyToolResult,
|
||||
type AgenticSection,
|
||||
type ToolResultLine
|
||||
classifyToolResult
|
||||
} from './agentic';
|
||||
|
||||
// Line-level unified diff for tool result rendering (`edit_file` block)
|
||||
@@ -276,8 +266,7 @@ export {
|
||||
extractSearchResults,
|
||||
extractSearchQuery,
|
||||
faviconForUrl,
|
||||
isWebSearchToolName,
|
||||
type SearchResult
|
||||
isWebSearchToolName
|
||||
} from './search-results';
|
||||
|
||||
// Cache utilities
|
||||
@@ -318,7 +307,6 @@ export { tryParseToolResultObject } from './tool-call-meta';
|
||||
// Re-exported through $lib/utils so renderer components can read the
|
||||
// label without depending on $lib/constants directly.
|
||||
export { getBuiltinToolUi } from './built-in-tools';
|
||||
export type { BuiltinToolUiEntry } from '$lib/types';
|
||||
|
||||
// Chat command picker
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { SearchResult } from '$lib/types/search';
|
||||
|
||||
/**
|
||||
* Parsers for MCP web-search tool responses shaped like:
|
||||
*
|
||||
@@ -16,14 +18,6 @@
|
||||
* servers without hardcoding tool names.
|
||||
*/
|
||||
|
||||
export type SearchResult = {
|
||||
title: string;
|
||||
url: string;
|
||||
published?: string;
|
||||
author?: string;
|
||||
highlights?: string;
|
||||
};
|
||||
|
||||
const SEPARATOR_LINE_RE = /^\s*---\s*$/;
|
||||
const URL_SCHEME_RE = /^https?:\/\//i;
|
||||
// Match either Unix or Windows line endings so chunking/parsing handles
|
||||
|
||||
@@ -14,11 +14,7 @@ import {
|
||||
SEARCH,
|
||||
TRAILING_SLASHES_REGEX
|
||||
} from '$lib/constants';
|
||||
|
||||
export interface GlobEntry {
|
||||
path: string;
|
||||
type: string;
|
||||
}
|
||||
import type { GlobEntry, GlobSearchArgs } from '$lib/types/glob';
|
||||
|
||||
export interface PathQuery {
|
||||
parent: string;
|
||||
@@ -93,17 +89,6 @@ export function buildCaseInsensitiveGlob(query: string): string {
|
||||
return out + GLOB.WILDCARD;
|
||||
}
|
||||
|
||||
export interface GlobSearchArgs {
|
||||
path: string;
|
||||
include: string;
|
||||
maxDepth: number;
|
||||
rankQuery: string;
|
||||
/** Last segment of a path-navigation query (`~/dir/sub`), undefined for
|
||||
* a plain home-relative glob. Lets callers act on the exact targeted
|
||||
* segment (e.g. the WD picker "entering" a directory). */
|
||||
last?: string;
|
||||
}
|
||||
|
||||
export function buildGlobSearchArgs(
|
||||
query: string,
|
||||
scopePath: string,
|
||||
|
||||
Reference in New Issue
Block a user