Update tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentsList.svelte
Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionAttachmentsDropdown.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormPromptPicker/ChatFormPromptPicker.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormPromptPicker/ChatFormPromptPicker.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormPromptPicker/ChatFormPromptPickerArgumentForm.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageStatistics.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/index.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/index.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/chat/index.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/content/CollapsibleContentBlock.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/content/CollapsibleContentBlock.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/content/MarkdownContent.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/content/MarkdownContent.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/content/MarkdownContent.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/dialogs/DialogMcpResources.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServerCard/McpServerCardDeleteDialog.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpCapabilitiesBadges.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpConnectionLogs.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServerForm.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServerSelector.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServersSettings.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServersSettings.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServersSettings.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/mcp/McpServersSettings.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/misc/index.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/misc/TruncatedText.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/misc/TruncatedText.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/components/app/misc/TruncatedText.svelte Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Update tools/server/webui/src/lib/services/mcp.service.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> Load more...
This commit is contained in:
parent
65e8bb6df4
commit
ec604a03e1
|
|
@ -171,6 +171,7 @@
|
|||
arguments: item.uploadedFile.mcpPrompt.arguments
|
||||
}
|
||||
: null}
|
||||
|
||||
{#if mcpPrompt}
|
||||
<ChatAttachmentMcpPrompt
|
||||
class="max-w-[300px] min-w-[200px]"
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
onclick={() => onFileUpload?.()}
|
||||
>
|
||||
<FILE_TYPE_ICONS.image class="h-4 w-4" />
|
||||
|
||||
<span>Images</span>
|
||||
</DropdownMenu.Item>
|
||||
{:else}
|
||||
|
|
@ -104,9 +105,11 @@
|
|||
disabled
|
||||
>
|
||||
<FILE_TYPE_ICONS.image class="h-4 w-4" />
|
||||
|
||||
<span>Images</span>
|
||||
</DropdownMenu.Item>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content side="right">
|
||||
<p>Images require vision models to be processed</p>
|
||||
</Tooltip.Content>
|
||||
|
|
@ -119,6 +122,7 @@
|
|||
onclick={() => onFileUpload?.()}
|
||||
>
|
||||
<FILE_TYPE_ICONS.audio class="h-4 w-4" />
|
||||
|
||||
<span>Audio Files</span>
|
||||
</DropdownMenu.Item>
|
||||
{:else}
|
||||
|
|
@ -126,9 +130,11 @@
|
|||
<Tooltip.Trigger class="w-full">
|
||||
<DropdownMenu.Item class="audio-button flex cursor-pointer items-center gap-2" disabled>
|
||||
<FILE_TYPE_ICONS.audio class="h-4 w-4" />
|
||||
|
||||
<span>Audio Files</span>
|
||||
</DropdownMenu.Item>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content side="right">
|
||||
<p>Audio files require audio models to be processed</p>
|
||||
</Tooltip.Content>
|
||||
|
|
@ -140,6 +146,7 @@
|
|||
onclick={() => onFileUpload?.()}
|
||||
>
|
||||
<FILE_TYPE_ICONS.text class="h-4 w-4" />
|
||||
|
||||
<span>Text Files</span>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
|
|
@ -149,6 +156,7 @@
|
|||
onclick={() => onFileUpload?.()}
|
||||
>
|
||||
<FILE_TYPE_ICONS.pdf class="h-4 w-4" />
|
||||
|
||||
<span>PDF Files</span>
|
||||
</DropdownMenu.Item>
|
||||
{:else}
|
||||
|
|
@ -159,9 +167,11 @@
|
|||
onclick={() => onFileUpload?.()}
|
||||
>
|
||||
<FILE_TYPE_ICONS.pdf class="h-4 w-4" />
|
||||
|
||||
<span>PDF Files</span>
|
||||
</DropdownMenu.Item>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content side="right">
|
||||
<p>PDFs will be converted to text. Image-based PDFs may not work properly.</p>
|
||||
</Tooltip.Content>
|
||||
|
|
@ -175,9 +185,11 @@
|
|||
onclick={() => onSystemPromptClick?.()}
|
||||
>
|
||||
<MessageSquare class="h-4 w-4" />
|
||||
|
||||
<span>System Message</span>
|
||||
</DropdownMenu.Item>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content side="right">
|
||||
<p>{systemMessageTooltip}</p>
|
||||
</Tooltip.Content>
|
||||
|
|
|
|||
|
|
@ -165,11 +165,13 @@
|
|||
|
||||
let hasMcpPromptsSupport = $derived.by(() => {
|
||||
const perChatOverrides = conversationsStore.getAllMcpServerOverrides();
|
||||
|
||||
return mcpStore.hasPromptsCapability(perChatOverrides);
|
||||
});
|
||||
|
||||
let hasMcpResourcesSupport = $derived.by(() => {
|
||||
const perChatOverrides = conversationsStore.getAllMcpServerOverrides();
|
||||
|
||||
return mcpStore.hasResourcesCapability(perChatOverrides);
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
|
||||
if (!initialized) {
|
||||
prompts = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +143,7 @@
|
|||
const fetchCompletions = debounce(async (argName: string, value: string) => {
|
||||
if (!selectedPrompt || value.length < 1) {
|
||||
suggestions[argName] = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
role="alert"
|
||||
>
|
||||
<span class="shrink-0">⚠</span>
|
||||
|
||||
<span>{promptError}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -162,13 +162,16 @@
|
|||
onclick={() => (activeView = ChatMessageStatsView.TOOLS)}
|
||||
>
|
||||
<Wrench class="h-3 w-3" />
|
||||
|
||||
<span class="sr-only">Tools</span>
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content>
|
||||
<p>Tool calls</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<button
|
||||
|
|
@ -180,9 +183,11 @@
|
|||
onclick={() => (activeView = ChatMessageStatsView.SUMMARY)}
|
||||
>
|
||||
<Layers class="h-3 w-3" />
|
||||
|
||||
<span class="sr-only">Summary</span>
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content>
|
||||
<p>Agentic summary</p>
|
||||
</Tooltip.Content>
|
||||
|
|
|
|||
|
|
@ -105,9 +105,11 @@
|
|||
: messages.filter((msg) => msg.type !== MessageRole.SYSTEM);
|
||||
|
||||
let lastAssistantIndex = -1;
|
||||
|
||||
for (let i = filteredMessages.length - 1; i >= 0; i--) {
|
||||
if (filteredMessages[i].role === MessageRole.ASSISTANT) {
|
||||
lastAssistantIndex = i;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* ATTACHMENTS
|
||||
*
|
||||
* Components for displaying and managing file attachments in chat messages.
|
||||
* Components for displaying and managing different attachment types in chat messages.
|
||||
* Supports two operational modes:
|
||||
* - **Readonly mode**: For displaying stored attachments in sent messages (DatabaseMessageExtra[])
|
||||
* - **Editable mode**: For managing pending uploads in the input form (ChatUploadedFile[])
|
||||
|
|
@ -96,7 +96,7 @@ export { default as ChatAttachmentsViewAll } from './ChatAttachments/ChatAttachm
|
|||
* FORM
|
||||
*
|
||||
* Components for the chat input area. The form handles user input, file attachments,
|
||||
* audio recording, and MCP prompt selection. It integrates with multiple stores:
|
||||
* audio recording, and MCP prompts & resources selection. It integrates with multiple stores:
|
||||
* - `chatStore` for message submission and generation control
|
||||
* - `modelsStore` for model selection and validation
|
||||
* - `mcpStore` for MCP prompt browsing and loading
|
||||
|
|
@ -130,6 +130,7 @@ export { default as ChatAttachmentsViewAll } from './ChatAttachments/ChatAttachm
|
|||
* - File upload via button dropdown (images/text/PDF), drag-drop, or paste
|
||||
* - Audio recording with WAV conversion (when model supports audio)
|
||||
* - MCP prompt picker with search and argument forms
|
||||
* - MCP reource picker with component to list attached resources at the bottom of Chat Form
|
||||
* - Model selector integration (router mode)
|
||||
* - Loading state with stop button, disabled state for errors
|
||||
*
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@
|
|||
{#if Icon}
|
||||
<Icon class={iconClass} />
|
||||
{/if}
|
||||
|
||||
<span class="font-mono text-sm font-medium">{title}</span>
|
||||
|
||||
{#if subtitle}
|
||||
<span class="text-xs italic">{subtitle}</span>
|
||||
{/if}
|
||||
|
|
@ -76,6 +78,7 @@
|
|||
})}
|
||||
>
|
||||
<ChevronsUpDownIcon class="h-4 w-4" />
|
||||
|
||||
<span class="sr-only">Toggle content</span>
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
|
|
|
|||
|
|
@ -197,9 +197,11 @@
|
|||
type?: string;
|
||||
position?: { start?: { offset?: number }; end?: { offset?: number } };
|
||||
};
|
||||
|
||||
if (n.position?.start?.offset != null && n.position?.end?.offset != null) {
|
||||
return `${n.type}-${n.position.start.offset}-${n.position.end.offset}`;
|
||||
}
|
||||
|
||||
return `${n.type}-idx${index}`;
|
||||
}
|
||||
|
||||
|
|
@ -414,6 +416,7 @@
|
|||
{ position: (child as { position?: unknown }).position } as HastRootContent,
|
||||
index
|
||||
);
|
||||
|
||||
nextBlocks.push({ id, html, contentHash: hash });
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +428,7 @@
|
|||
const transformedRoot = (await processorInstance.run(
|
||||
singleNodeRoot as MdastRoot
|
||||
)) as HastRoot;
|
||||
|
||||
unstableHtml = processorInstance.stringify(transformedRoot);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
async function loadResources() {
|
||||
const perChatOverrides = conversationsStore.getAllMcpServerOverrides();
|
||||
const initialized = await mcpStore.ensureInitialized(perChatOverrides);
|
||||
|
||||
if (initialized) {
|
||||
await mcpStore.fetchAllResources();
|
||||
}
|
||||
|
|
@ -48,6 +49,7 @@
|
|||
function handleOpenChange(newOpen: boolean) {
|
||||
open = newOpen;
|
||||
onOpenChange?.(newOpen);
|
||||
|
||||
if (!newOpen) {
|
||||
selectedResources.clear();
|
||||
lastSelectedUri = null;
|
||||
|
|
@ -81,6 +83,7 @@
|
|||
} else {
|
||||
selectedResources.delete(resource.uri);
|
||||
}
|
||||
|
||||
lastSelectedUri = resource.uri;
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +104,7 @@
|
|||
if (selectedResources.size === 0) return;
|
||||
|
||||
isAttaching = true;
|
||||
|
||||
try {
|
||||
const allResources = getAllResourcesFlat();
|
||||
const resourcesToAttach = allResources.filter((r) => selectedResources.has(r.uri));
|
||||
|
|
@ -111,6 +115,7 @@
|
|||
}
|
||||
|
||||
const count = resourcesToAttach.length;
|
||||
|
||||
toast.success(
|
||||
count === 1
|
||||
? `Resource attached: ${resourcesToAttach[0].name}`
|
||||
|
|
@ -127,9 +132,12 @@
|
|||
|
||||
async function handleQuickAttach(resource: MCPResourceInfo) {
|
||||
isAttaching = true;
|
||||
|
||||
try {
|
||||
await mcpStore.attachResource(resource.uri);
|
||||
|
||||
onAttach?.(resource);
|
||||
|
||||
toast.success(`Resource attached: ${resource.name}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to attach resource:', error);
|
||||
|
|
@ -144,11 +152,14 @@
|
|||
<Dialog.Header class="border-b px-6 py-4">
|
||||
<Dialog.Title class="flex items-center gap-2">
|
||||
<FolderOpen class="h-5 w-5" />
|
||||
|
||||
<span>MCP Resources</span>
|
||||
|
||||
{#if totalCount > 0}
|
||||
<span class="text-sm font-normal text-muted-foreground">({totalCount})</span>
|
||||
{/if}
|
||||
</Dialog.Title>
|
||||
|
||||
<Dialog.Description>
|
||||
Browse and attach resources from connected MCP servers to your chat context.
|
||||
</Dialog.Description>
|
||||
|
|
@ -169,6 +180,7 @@
|
|||
{#if selectedResources.size === 1}
|
||||
{@const allResources = getAllResourcesFlat()}
|
||||
{@const selectedResource = allResources.find((r) => selectedResources.has(r.uri))}
|
||||
|
||||
<McpResourcePreview resource={selectedResource ?? null} />
|
||||
{:else if selectedResources.size > 1}
|
||||
<div class="flex h-full items-center justify-center text-sm text-muted-foreground">
|
||||
|
|
@ -184,12 +196,14 @@
|
|||
|
||||
<Dialog.Footer class="border-t px-6 py-4">
|
||||
<Button variant="outline" onclick={() => handleOpenChange(false)}>Cancel</Button>
|
||||
|
||||
<Button onclick={handleAttach} disabled={selectedResources.size === 0 || isAttaching}>
|
||||
{#if isAttaching}
|
||||
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
||||
{:else}
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
|
||||
Attach {selectedResources.size > 0 ? `(${selectedResources.size})` : 'Resource'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
{#if capabilities.server.tools}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-green-50 px-1.5 text-[10px] dark:bg-green-950">
|
||||
<Wrench class="h-3 w-3 text-green-600 dark:text-green-400" />
|
||||
|
||||
Tools
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
{#if capabilities.server.resources}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-blue-50 px-1.5 text-[10px] dark:bg-blue-950">
|
||||
<Database class="h-3 w-3 text-blue-600 dark:text-blue-400" />
|
||||
|
||||
Resources
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
@ -28,6 +30,7 @@
|
|||
{#if capabilities.server.prompts}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-purple-50 px-1.5 text-[10px] dark:bg-purple-950">
|
||||
<MessageSquare class="h-3 w-3 text-purple-600 dark:text-purple-400" />
|
||||
|
||||
Prompts
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
@ -35,6 +38,7 @@
|
|||
{#if capabilities.server.logging}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-orange-50 px-1.5 text-[10px] dark:bg-orange-950">
|
||||
<FileText class="h-3 w-3 text-orange-600 dark:text-orange-400" />
|
||||
|
||||
Logging
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
@ -42,6 +46,7 @@
|
|||
{#if capabilities.server.completions}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-cyan-50 px-1.5 text-[10px] dark:bg-cyan-950">
|
||||
<Sparkles class="h-3 w-3 text-cyan-600 dark:text-cyan-400" />
|
||||
|
||||
Completions
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
@ -49,6 +54,7 @@
|
|||
{#if capabilities.server.tasks}
|
||||
<Badge variant="outline" class="h-5 gap-1 bg-pink-50 px-1.5 text-[10px] dark:bg-pink-950">
|
||||
<ListChecks class="h-3 w-3 text-pink-600 dark:text-pink-400" />
|
||||
|
||||
Tasks
|
||||
</Badge>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
{:else}
|
||||
<ChevronRight class="h-3.5 w-3.5" />
|
||||
{/if}
|
||||
|
||||
<span>Connection Log ({logs.length})</span>
|
||||
|
||||
{#if connectionTimeMs !== undefined}
|
||||
|
|
|
|||
|
|
@ -94,18 +94,21 @@
|
|||
{#if !resource}
|
||||
<div class="flex flex-col items-center justify-center gap-2 py-8 text-muted-foreground">
|
||||
<FileText class="h-8 w-8 opacity-50" />
|
||||
|
||||
<span class="text-sm">Select a resource to preview</span>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Header -->
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="truncate font-medium">{resource.title || resource.name}</h3>
|
||||
|
||||
<p class="truncate text-xs text-muted-foreground">{resource.uri}</p>
|
||||
|
||||
{#if resource.description}
|
||||
<p class="mt-1 text-sm text-muted-foreground">{resource.description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
|
|
@ -121,6 +124,7 @@
|
|||
<Copy class="h-3.5 w-3.5" />
|
||||
{/if}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
|
@ -134,7 +138,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="min-h-[200px] overflow-auto rounded-md border bg-muted/30 p-3">
|
||||
{#if isLoading}
|
||||
<div class="flex items-center justify-center py-8">
|
||||
|
|
@ -143,6 +146,7 @@
|
|||
{:else if error}
|
||||
<div class="flex flex-col items-center justify-center gap-2 py-8 text-red-500">
|
||||
<AlertCircle class="h-6 w-6" />
|
||||
|
||||
<span class="text-sm">{error}</span>
|
||||
</div>
|
||||
{:else if content}
|
||||
|
|
@ -163,6 +167,7 @@
|
|||
{:else}
|
||||
<div class="flex items-center gap-2 rounded bg-muted p-2 text-sm text-muted-foreground">
|
||||
<FileText class="h-4 w-4" />
|
||||
|
||||
<span>Binary content ({blob.mimeType || 'unknown type'})</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -174,17 +179,18 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Metadata -->
|
||||
{#if resource.mimeType || resource.annotations}
|
||||
<div class="flex flex-wrap gap-2 text-xs text-muted-foreground">
|
||||
{#if resource.mimeType}
|
||||
<span class="rounded bg-muted px-1.5 py-0.5">{resource.mimeType}</span>
|
||||
{/if}
|
||||
|
||||
{#if resource.annotations?.priority !== undefined}
|
||||
<span class="rounded bg-muted px-1.5 py-0.5">
|
||||
Priority: {resource.annotations.priority}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<span class="rounded bg-muted px-1.5 py-0.5">
|
||||
Server: {resource.serverName}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -15,13 +15,16 @@
|
|||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>Delete Server</AlertDialog.Title>
|
||||
|
||||
<AlertDialog.Description>
|
||||
Are you sure you want to delete <strong>{displayName}</strong>? This action cannot be
|
||||
undone.
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
|
||||
|
||||
<AlertDialog.Action
|
||||
class="text-destructive-foreground bg-destructive hover:bg-destructive/90"
|
||||
onclick={onConfirm}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
checked={useProxy}
|
||||
onCheckedChange={(checked) => onUseProxyChange?.(checked)}
|
||||
/>
|
||||
|
||||
<span class="text-xs text-muted-foreground">Use llama-server proxy</span>
|
||||
</label>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -110,14 +110,18 @@
|
|||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<span class="truncate text-sm">{getServerLabel(server)}</span>
|
||||
|
||||
{#if hasError}
|
||||
<span
|
||||
class="shrink-0 rounded bg-destructive/15 px-1.5 py-0.5 text-xs text-destructive"
|
||||
>Error</span
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Switch
|
||||
checked={isEnabledForChat}
|
||||
disabled={hasError}
|
||||
|
|
@ -131,6 +135,7 @@
|
|||
{#snippet footer()}
|
||||
<DropdownMenu.Item class="flex cursor-pointer items-center gap-2" onclick={onSettingsClick}>
|
||||
<Settings class="h-4 w-4" />
|
||||
|
||||
<span>Manage MCP Servers</span>
|
||||
</DropdownMenu.Item>
|
||||
{/snippet}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
servers.length > 0 &&
|
||||
servers.every((server) => {
|
||||
const state = mcpStore.getHealthCheckState(server.id);
|
||||
|
||||
return state.status === 'success' || state.status === 'error';
|
||||
});
|
||||
|
||||
|
|
@ -55,11 +56,13 @@
|
|||
|
||||
function saveNewServer() {
|
||||
if (newServerUrlError) return;
|
||||
|
||||
mcpStore.addServer({
|
||||
enabled: true,
|
||||
url: newServerUrl.trim(),
|
||||
headers: newServerHeaders.trim() || undefined
|
||||
});
|
||||
|
||||
isAddingServer = false;
|
||||
newServerUrl = '';
|
||||
newServerHeaders = '';
|
||||
|
|
@ -75,6 +78,7 @@
|
|||
{#if !isAddingServer}
|
||||
<Button variant="outline" size="sm" class="shrink-0" onclick={showAddServerForm}>
|
||||
<Plus class="h-4 w-4" />
|
||||
|
||||
Add New Server
|
||||
</Button>
|
||||
{/if}
|
||||
|
|
@ -85,6 +89,7 @@
|
|||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="font-medium">Add New Server</p>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* TruncatedText - Shows tooltip only when text is actually truncated
|
||||
*/
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -23,9 +20,10 @@
|
|||
$effect(() => {
|
||||
if (textElement) {
|
||||
checkTruncation();
|
||||
// Re-check on resize
|
||||
|
||||
const observer = new ResizeObserver(checkTruncation);
|
||||
observer.observe(textElement);
|
||||
|
||||
return () => observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
|
@ -38,6 +36,7 @@
|
|||
{text}
|
||||
</span>
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content class="z-[9999]">
|
||||
<p>{text}</p>
|
||||
</Tooltip.Content>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* **TruncatedText** - Text with ellipsis and tooltip
|
||||
*
|
||||
* Displays text with automatic truncation and full content in tooltip.
|
||||
* Useful for long names or paths in constrained spaces.
|
||||
*/
|
||||
export { default as TruncatedText } from './TruncatedText.svelte';
|
||||
|
||||
/**
|
||||
* **ConversationSelection** - Multi-select conversation picker
|
||||
*
|
||||
|
|
@ -35,3 +27,11 @@ export { default as ConversationSelection } from './ConversationSelection.svelte
|
|||
* with left/right navigation buttons that appear on hover.
|
||||
*/
|
||||
export { default as HorizontalScrollCarousel } from './HorizontalScrollCarousel.svelte';
|
||||
|
||||
/**
|
||||
* **TruncatedText** - Text with ellipsis and tooltip
|
||||
*
|
||||
* Displays text with automatic truncation and full content in tooltip.
|
||||
* Useful for long names or paths in constrained spaces.
|
||||
*/
|
||||
export { default as TruncatedText } from './TruncatedText.svelte';
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ export class MCPService {
|
|||
)
|
||||
);
|
||||
|
||||
console.log(`[MCPService][${serverName}] Creating transport...`);
|
||||
if (import.meta.env.DEV) {
|
||||
console.log(`[MCPService][${serverName}] Creating transport...`);
|
||||
}
|
||||
const { transport, type: transportType } = this.createTransport(serverConfig);
|
||||
|
||||
// Phase: Transport ready
|
||||
|
|
@ -414,8 +416,10 @@ export class MCPService {
|
|||
|
||||
if (content.type === 'resource' && content.resource) {
|
||||
const resource = content.resource;
|
||||
|
||||
if (resource.text) return resource.text;
|
||||
if (resource.blob) return resource.blob;
|
||||
|
||||
return JSON.stringify(resource);
|
||||
}
|
||||
|
||||
|
|
@ -453,9 +457,11 @@ export class MCPService {
|
|||
ref,
|
||||
argument
|
||||
});
|
||||
|
||||
return result.completion;
|
||||
} catch (error) {
|
||||
console.error(`[MCPService] Failed to get completions:`, error);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -480,12 +486,14 @@ export class MCPService {
|
|||
): Promise<{ resources: MCPResource[]; nextCursor?: string }> {
|
||||
try {
|
||||
const result = await connection.client.listResources(cursor ? { cursor } : undefined);
|
||||
|
||||
return {
|
||||
resources: (result.resources ?? []) as MCPResource[],
|
||||
nextCursor: result.nextCursor
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(`[MCPService][${connection.serverName}] Failed to list resources:`, error);
|
||||
|
||||
return { resources: [] };
|
||||
}
|
||||
}
|
||||
|
|
@ -520,6 +528,7 @@ export class MCPService {
|
|||
): Promise<{ resourceTemplates: MCPResourceTemplate[]; nextCursor?: string }> {
|
||||
try {
|
||||
const result = await connection.client.listResourceTemplates(cursor ? { cursor } : undefined);
|
||||
|
||||
return {
|
||||
resourceTemplates: (result.resourceTemplates ?? []) as MCPResourceTemplate[],
|
||||
nextCursor: result.nextCursor
|
||||
|
|
@ -529,6 +538,7 @@ export class MCPService {
|
|||
`[MCPService][${connection.serverName}] Failed to list resource templates:`,
|
||||
error
|
||||
);
|
||||
|
||||
return { resourceTemplates: [] };
|
||||
}
|
||||
}
|
||||
|
|
@ -563,12 +573,14 @@ export class MCPService {
|
|||
): Promise<MCPReadResourceResult> {
|
||||
try {
|
||||
const result = await connection.client.readResource({ uri });
|
||||
|
||||
return {
|
||||
contents: (result.contents ?? []) as MCPResourceContent[],
|
||||
_meta: result._meta
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`[MCPService][${connection.serverName}] Failed to read resource:`, error);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -582,12 +594,14 @@ export class MCPService {
|
|||
static async subscribeResource(connection: MCPConnection, uri: string): Promise<void> {
|
||||
try {
|
||||
await connection.client.subscribeResource({ uri });
|
||||
|
||||
console.log(`[MCPService][${connection.serverName}] Subscribed to resource: ${uri}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[MCPService][${connection.serverName}] Failed to subscribe to resource:`,
|
||||
error
|
||||
);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -600,12 +614,14 @@ export class MCPService {
|
|||
static async unsubscribeResource(connection: MCPConnection, uri: string): Promise<void> {
|
||||
try {
|
||||
await connection.client.unsubscribeResource({ uri });
|
||||
|
||||
console.log(`[MCPService][${connection.serverName}] Unsubscribed from resource: ${uri}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[MCPService][${connection.serverName}] Failed to unsubscribe from resource:`,
|
||||
error
|
||||
);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue