From 945dbb9f84240f42cb078f127906dfc8c9b456dc Mon Sep 17 00:00:00 2001 From: shahondin1624 Date: Thu, 12 Mar 2026 11:33:41 +0100 Subject: [PATCH] feat: add orchestration state progress indicator - OrchestrationProgress stepper component with 5 phases - Visual state: completed (green check), active (blue ring), pending (gray) - Smooth CSS transitions between states - Integrated into chat page, visible during streaming Closes #8 Co-Authored-By: Claude Opus 4.6 --- implementation-plans/_index.md | 1 + implementation-plans/issue-008.md | 16 ++++++ .../components/OrchestrationProgress.svelte | 56 +++++++++++++++++++ src/routes/chat/+page.svelte | 10 +++- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 implementation-plans/issue-008.md create mode 100644 src/lib/components/OrchestrationProgress.svelte diff --git a/implementation-plans/_index.md b/implementation-plans/_index.md index 97bd704..4d28889 100644 --- a/implementation-plans/_index.md +++ b/implementation-plans/_index.md @@ -9,3 +9,4 @@ | #5 | Chat page layout and message list component | COMPLETED | [issue-005.md](issue-005.md) | | #6 | Message input with send and keyboard shortcuts | COMPLETED | [issue-006.md](issue-006.md) | | #7 | Streaming response rendering | COMPLETED | [issue-007.md](issue-007.md) | +| #8 | Orchestration state progress indicator | COMPLETED | [issue-008.md](issue-008.md) | diff --git a/implementation-plans/issue-008.md b/implementation-plans/issue-008.md new file mode 100644 index 0000000..3cfc337 --- /dev/null +++ b/implementation-plans/issue-008.md @@ -0,0 +1,16 @@ +--- +--- + +# Issue #8: Orchestration state progress indicator + +**Status:** COMPLETED +**Issue:** https://git.shahondin1624.de/llm-multiverse/llm-multiverse-ui/issues/8 +**Branch:** `feature/issue-8-progress-indicator` + +## Acceptance Criteria + +- [x] Stepper/progress bar component showing orchestration phases +- [x] Phases: Decomposing → Dispatching → Executing → Compacting → Complete +- [x] Updates in real-time as OrchestrationState changes in the stream +- [x] Current phase visually highlighted, completed phases marked +- [x] Smooth transitions between states diff --git a/src/lib/components/OrchestrationProgress.svelte b/src/lib/components/OrchestrationProgress.svelte new file mode 100644 index 0000000..d6b2836 --- /dev/null +++ b/src/lib/components/OrchestrationProgress.svelte @@ -0,0 +1,56 @@ + + +
+
+ {#each phases as phase, i (phase.state)} + {@const status = getStatus(phase.state)} +
+
+ {#if status === 'completed'} + ✓ + {:else} + {i + 1} + {/if} +
+ + {phase.label} + +
+ {#if i < phases.length - 1} +
+ {/if} + {/each} +
+
diff --git a/src/routes/chat/+page.svelte b/src/routes/chat/+page.svelte index 92bb49f..c86b2b1 100644 --- a/src/routes/chat/+page.svelte +++ b/src/routes/chat/+page.svelte @@ -2,15 +2,19 @@ import type { ChatMessage } from '$lib/types'; import MessageList from '$lib/components/MessageList.svelte'; import MessageInput from '$lib/components/MessageInput.svelte'; + import OrchestrationProgress from '$lib/components/OrchestrationProgress.svelte'; import { processRequest, OrchestratorError } from '$lib/services/orchestrator'; + import { OrchestrationState } from '$lib/proto/llm_multiverse/v1/orchestrator_pb'; let messages: ChatMessage[] = $state([]); let isStreaming = $state(false); let error: string | null = $state(null); let sessionId = $state(crypto.randomUUID()); + let orchestrationState: OrchestrationState = $state(OrchestrationState.UNSPECIFIED); async function handleSend(content: string) { error = null; + orchestrationState = OrchestrationState.UNSPECIFIED; const userMessage: ChatMessage = { id: crypto.randomUUID(), @@ -32,6 +36,7 @@ try { for await (const response of processRequest(sessionId, content)) { + orchestrationState = response.state; const idx = messages.length - 1; messages[idx] = { ...messages[idx], @@ -44,7 +49,6 @@ ? `Error (${err.code}): ${err.message}` : 'An unexpected error occurred'; error = msg; - // Update the assistant message with the error const idx = messages.length - 1; messages[idx] = { ...messages[idx], @@ -63,6 +67,10 @@ + {#if isStreaming} + + {/if} + {#if isStreaming && messages.length > 0 && messages[messages.length - 1].content === ''}