VibecoderMcSwaggins's picture
docs: finalize implementation documentation for Phase 4 Orchestrator and UI
62d32ab
|
raw
history blame
2.64 kB
# Phase 4 Implementation Spec: Orchestrator & UI
**Goal**: Connect the Brain and the Body, then give it a Face.
**Philosophy**: "Streaming is Trust."
**Estimated Effort**: 4-5 hours
**Prerequisite**: Phases 1-3 complete
---
## 1. The Slice Definition
This slice connects:
1. **Orchestrator**: The loop calling `SearchHandler``JudgeHandler`.
2. **UI**: Gradio app.
**Files**:
- `src/utils/models.py`: Add Orchestrator models
- `src/orchestrator.py`: Main logic
- `src/app.py`: UI
---
## 2. Models (`src/utils/models.py`)
Add to models file:
```python
from enum import Enum
class AgentState(str, Enum):
SEARCHING = "searching"
JUDGING = "judging"
COMPLETE = "complete"
ERROR = "error"
class AgentEvent(BaseModel):
state: AgentState
message: str
data: dict[str, Any] | None = None
```
---
## 3. Orchestrator (`src/orchestrator.py`)
```python
"""Main agent orchestrator."""
import structlog
from typing import AsyncGenerator
from src.shared.config import settings
from src.tools.search_handler import SearchHandler
from src.agent_factory.judges import JudgeHandler
from src.utils.models import AgentEvent, AgentState
logger = structlog.get_logger()
class Orchestrator:
def __init__(self):
self.search = SearchHandler(...)
self.judge = JudgeHandler()
async def run(self, question: str) -> AsyncGenerator[AgentEvent, None]:
"""Run the loop."""
yield AgentEvent(state=AgentState.SEARCHING, message="Starting...")
# ... while loop implementation ...
# ... yield events ...
```
---
## 4. UI (`src/app.py`)
```python
"""Gradio UI."""
import gradio as gr
from src.orchestrator import Orchestrator
async def chat(message, history):
agent = Orchestrator()
async for event in agent.run(message):
yield f"**[{event.state.value}]** {event.message}"
# ... gradio blocks setup ...
```
---
## 5. TDD Workflow
### Test File: `tests/unit/test_orchestrator.py`
```python
"""Unit tests for Orchestrator."""
import pytest
from unittest.mock import AsyncMock
class TestOrchestrator:
@pytest.mark.asyncio
async def test_run_loop(self, mocker):
from src.orchestrator import Orchestrator
# Mock handlers
# ... setup mocks ...
orch = Orchestrator()
events = [e async for e in orch.run("test")]
assert len(events) > 0
```
---
## 6. Implementation Checklist
- [ ] Update `src/utils/models.py`
- [ ] Implement `src/orchestrator.py`
- [ ] Implement `src/app.py`
- [ ] Write tests in `tests/unit/test_orchestrator.py`
- [ ] Run `uv run python src/app.py`