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 === ''}