- Gradio 5.50.0 ChatInterface with type='messages' streaming - LangGraph create_react_agent with InMemorySaver checkpointer - 4 @tool functions: search_dashboards, get_health_summary, list_environments, get_task_status - Structured ChatMessage metadata (7 discriminator types: stream_token, tool_start/end/error, confirm_required, confirm_resolved, error) - HITL resume via second submit() with interrupt_before/Command - Dual-identity RBAC: service JWT + user JWT for tool calls - File upload (10 MB limit, pdfplumber/xlsx/JSON parser) - Conversation persistence via POST /api/agent/conversations/save - REST API: list, history, archive conversations; multi-tab gate; LLM config - LLM provider selection via Admin -> LLM Settings (assistant_planner_provider) - Svelte 5 AgentChatModel with stream event queue, dedup, stream_status watcher - MarkdownRenderer using svelte-markdown with semantic Tailwind tokens - ToolCallCard (3 states: executing/completed/failed) - ConversationList with search, date grouping, infinite scroll - ConnectionIndicator with Gradio health status - /agent route with two-column layout - Vite proxy /api/agent/gradio -> Gradio SSE - Fixed: not_() SQLAlchemy operator, route collision with _admin_routes - Fixed: conversation_id -> id normalization, .pyc cache staleness - Fixed: event.data array parsing (Gradio returns [jsonStr, null]) - Requirements pinned: gradio==5.50.0, pydantic>=2.7,<=2.12.3
136 lines
3.6 KiB
Svelte
136 lines
3.6 KiB
Svelte
<!-- #region AssistantChat.MarkdownRenderer [C:2] [TYPE Component] [SEMANTICS assistant,chat,markdown,rendering] -->
|
|
<!-- @ingroup AgentChat -->
|
|
<!-- @BRIEF Renders markdown text using svelte-markdown with semantic Tailwind prose styles. -->
|
|
<!-- @LAYER UI -->
|
|
<!-- @RELATION DEPENDS_ON -> [EXT:svelte-markdown] -->
|
|
<!-- @UX_STATE Rendered -> Markdown rendered with proper headings, lists, code blocks, links. -->
|
|
<!-- @UX_STATE Empty -> Empty string renders nothing. -->
|
|
<script lang="ts">
|
|
import SvelteMarkdown from "svelte-markdown";
|
|
|
|
let { source = "" } = $props();
|
|
</script>
|
|
|
|
{#if source}
|
|
<div class="markdown-text">
|
|
<SvelteMarkdown {source} />
|
|
</div>
|
|
{/if}
|
|
|
|
<style>
|
|
/* svelte-markdown renderers use semantic HTML tags — style via cascade */
|
|
.markdown-text :global(h1),
|
|
.markdown-text :global(h2),
|
|
.markdown-text :global(h3) {
|
|
font-weight: 600;
|
|
color: var(--color-text, #1a1a2e);
|
|
margin-top: 0.75rem;
|
|
margin-bottom: 0.375rem;
|
|
}
|
|
.markdown-text :global(h1) {
|
|
font-size: 1.125rem;
|
|
line-height: 1.5rem;
|
|
}
|
|
.markdown-text :global(h2) {
|
|
font-size: 1rem;
|
|
line-height: 1.375rem;
|
|
}
|
|
.markdown-text :global(h3) {
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
}
|
|
.markdown-text :global(p) {
|
|
font-size: 0.875rem;
|
|
line-height: 1.5;
|
|
color: var(--color-text, #1a1a2e);
|
|
margin-bottom: 0.375rem;
|
|
}
|
|
.markdown-text :global(ul),
|
|
.markdown-text :global(ol) {
|
|
list-style-position: inside;
|
|
font-size: 0.875rem;
|
|
line-height: 1.5;
|
|
color: var(--color-text, #1a1a2e);
|
|
margin-bottom: 0.375rem;
|
|
padding-left: 0;
|
|
}
|
|
.markdown-text :global(ul) {
|
|
list-style-type: disc;
|
|
}
|
|
.markdown-text :global(ol) {
|
|
list-style-type: decimal;
|
|
}
|
|
.markdown-text :global(li) {
|
|
margin-bottom: 0.125rem;
|
|
}
|
|
.markdown-text :global(code) {
|
|
border-radius: 0.25rem;
|
|
background-color: var(--color-surface-muted, #f3f4f6);
|
|
padding: 0.125rem 0.375rem;
|
|
font-size: 0.75rem;
|
|
font-family: ui-monospace, monospace;
|
|
color: var(--color-text, #1a1a2e);
|
|
}
|
|
.markdown-text :global(pre) {
|
|
border-radius: 0.5rem;
|
|
background-color: var(--color-surface-muted, #f3f4f6);
|
|
padding: 0.75rem;
|
|
overflow-x: auto;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.markdown-text :global(pre code) {
|
|
background: none;
|
|
padding: 0;
|
|
font-size: 0.75rem;
|
|
}
|
|
.markdown-text :global(a) {
|
|
color: var(--color-primary, #2563eb);
|
|
text-decoration: underline;
|
|
}
|
|
.markdown-text :global(a:hover) {
|
|
color: var(--color-primary-hover, #1d4ed8);
|
|
}
|
|
.markdown-text :global(strong) {
|
|
font-weight: 600;
|
|
color: var(--color-text, #1a1a2e);
|
|
}
|
|
.markdown-text :global(em) {
|
|
font-style: italic;
|
|
color: var(--color-text, #1a1a2e);
|
|
}
|
|
.markdown-text :global(hr) {
|
|
border: none;
|
|
border-top: 1px solid var(--color-border, #e5e7eb);
|
|
margin: 0.75rem 0;
|
|
}
|
|
.markdown-text :global(blockquote) {
|
|
border-left: 3px solid var(--color-primary, #2563eb);
|
|
padding-left: 0.75rem;
|
|
margin: 0.5rem 0;
|
|
color: var(--color-text-muted, #6b7280);
|
|
font-style: italic;
|
|
}
|
|
.markdown-text :global(table) {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.8125rem;
|
|
}
|
|
.markdown-text :global(th),
|
|
.markdown-text :global(td) {
|
|
border: 1px solid var(--color-border, #e5e7eb);
|
|
padding: 0.375rem 0.5rem;
|
|
text-align: left;
|
|
}
|
|
.markdown-text :global(th) {
|
|
background-color: var(--color-surface-muted, #f3f4f6);
|
|
font-weight: 600;
|
|
}
|
|
.markdown-text :global(img) {
|
|
max-width: 100%;
|
|
border-radius: 0.375rem;
|
|
margin: 0.5rem 0;
|
|
}
|
|
</style>
|
|
<!-- #endregion AssistantChat.MarkdownRenderer -->
|