feat: structured artifact rendering, UX improvements
- Render structured artifacts from agent results with type-aware formatting: code blocks with syntax highlighting and copy button, terminal-style command output, search result cards, and text findings - Make FinalResult panel collapsible (default collapsed) with scrollable content (max-h-96) to prevent dominating the chat view - Add clickable URL detection in summaries and artifact content - Fix code block contrast for both light and dark mode - Animate progress bar with pulse ring on active step and gradient shimmer on connecting lines - Fix tab-switching bug: use module-level orchestrationStore singleton so orchestration state survives route navigation - Remove sample/demo data seeding and clean up persisted localStorage entries from previous sample sessions - Remove showSampleBadge prop from PageHeader - Regenerate proto types for new Artifact message and ArtifactType enum - Update README project structure (remove deleted data/ directory) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import { OrchestrationState } from '$lib/proto/llm_multiverse/v1/orchestrator_pb
|
||||
import { sessionStore } from '$lib/stores/sessions.svelte';
|
||||
import { memoryStore } from '$lib/stores/memory.svelte';
|
||||
import { auditStore } from '$lib/stores/audit.svelte';
|
||||
import { toastStore } from '$lib/stores/toast.svelte';
|
||||
import { logger } from '$lib/utils/logger';
|
||||
|
||||
export function createOrchestration() {
|
||||
let isStreaming = $state(false);
|
||||
@@ -57,6 +57,10 @@ export function createOrchestration() {
|
||||
|
||||
if (response.state !== lastAuditState) {
|
||||
const stateLabel = OrchestrationState[response.state] ?? String(response.state);
|
||||
logger.debug('useOrchestration', `State: ${stateLabel}`, {
|
||||
sessionId,
|
||||
state: response.state
|
||||
});
|
||||
auditStore.addEvent(sessionId, {
|
||||
eventType: 'state_change',
|
||||
details: response.message || `State changed to ${stateLabel}`,
|
||||
@@ -88,21 +92,27 @@ export function createOrchestration() {
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
const friendlyMsg =
|
||||
err instanceof OrchestratorError
|
||||
? friendlyMessage(err.code)
|
||||
: 'An unexpected error occurred';
|
||||
error = friendlyMsg;
|
||||
const isOrcErr = err instanceof OrchestratorError;
|
||||
const code = isOrcErr ? err.code : 'unknown';
|
||||
const details = isOrcErr ? err.details : undefined;
|
||||
const friendlyMsg = isOrcErr
|
||||
? friendlyMessage(err.code)
|
||||
: 'An unexpected error occurred';
|
||||
const displayMsg =
|
||||
code && code !== 'unknown'
|
||||
? `${friendlyMsg} (${code})`
|
||||
: friendlyMsg;
|
||||
error = displayMsg;
|
||||
lastFailedContent = content;
|
||||
toastStore.addToast({ message: friendlyMsg, type: 'error' });
|
||||
logger.error('useOrchestration', 'Request failed', { code, details });
|
||||
auditStore.addEvent(sessionId, {
|
||||
eventType: 'error',
|
||||
details: friendlyMsg
|
||||
details: `${friendlyMsg} | code=${code}${details ? ` | details=${details}` : ''}`
|
||||
});
|
||||
const idx = messages.length - 1;
|
||||
messages[idx] = {
|
||||
...messages[idx],
|
||||
content: `\u26A0 ${friendlyMsg}`
|
||||
content: `\u26A0 ${displayMsg}`
|
||||
};
|
||||
} finally {
|
||||
isStreaming = false;
|
||||
@@ -149,3 +159,9 @@ export function createOrchestration() {
|
||||
reset
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Module-level singleton so orchestration state survives tab/route changes.
|
||||
* The chat page uses this instead of calling createOrchestration() per mount.
|
||||
*/
|
||||
export const orchestrationStore = createOrchestration();
|
||||
|
||||
Reference in New Issue
Block a user