Files
paseo/packages/voice-assistant/IMPLEMENTATION_PLAN.md
T
Mohamed Boudra 40b199e329 Based on the git diff showing extensive package-lock.json changes and modifications to the agent system prompt and configuration, here's the commit message:
```
feat: add AI SDK dependencies and refine agent voice interaction config

- Add @ai-sdk packages for enhanced AI capabilities
- Install Deepgram SDK, livekit-client, and werift for voice/WebRTC
- Expand agent system prompt with multi-tool workflows and Claude Code interaction patterns
- Adjust VAD timing (1.2s silence threshold) and turn detection for better voice UX
- Switch TTS to inworld/inworld-tts-1 with Olivia voice
- Configure interruption timing (0.2s detection, no word requirement)
- Add comprehensive guidelines for conversational responses vs structured output
- Document plan mode triggers and Claude response type handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
```
2025-10-19 15:41:42 +02:00

497 lines
14 KiB
Markdown

# Voice Assistant - Implementation Plan
## Project Overview
**Goal**: Build a voice-controlled terminal assistant that runs locally as a single Express service.
**Architecture**:
- Single Express process serving everything
- Vite React UI bundled and served from Express
- WebSocket for control messages (activity log, status updates)
- Agent logic (STT/TTS/LLM pipeline using APIs)
- Daemon logic (terminal control using tmux) - same process, direct function calls
- Audio streaming solution (Phase 8)
## Technology Stack
### Server
- **Runtime**: Node.js with TypeScript
- **Framework**: Express
- **WebSocket**: ws library
- **Terminal Control**: tmux (via child_process)
- **APIs**:
- OpenAI (GPT-4 Turbo for LLM, TTS)
- Deepgram (Streaming STT)
### Client
- **Framework**: React 18
- **Build Tool**: Vite
- **Styling**: CSS (custom)
- **WebSocket**: Native WebSocket API
## Package Structure
```
packages/voice-assistant/
├── package.json
├── tsconfig.json # UI TypeScript config
├── tsconfig.server.json # Server TypeScript config
├── tsconfig.node.json # Vite config TypeScript
├── vite.config.ts # Vite bundler config
├── .env.example
├── .gitignore
├── IMPLEMENTATION_PLAN.md # This file
│
├── src/
│ ├── server/
│ │ ├── index.ts # ✅ Express + HTTP server entry point
│ │ ├── types.ts # ✅ Shared server types
│ │ ├── websocket-server.ts # ✅ WebSocket server
│ │ │
│ │ ├── agent/
│ │ │ ├── orchestrator.ts # Agent pipeline coordinator
│ │ │ ├── stt-deepgram.ts # Deepgram streaming STT
│ │ │ ├── llm-openai.ts # OpenAI GPT-4 with tools
│ │ │ ├── tts-openai.ts # OpenAI TTS (stream)
│ │ │ └── system-prompt.ts # Load from agent-prompt.md
│ │ │
│ │ └── daemon/
│ │ ├── terminal-manager.ts # Terminal control API
│ │ ├── tmux.ts # tmux primitives (from mcp-server)
│ │ └── tool-definitions.ts # LLM tool schemas
│ │
│ └── ui/
│ ├── index.html # ✅ HTML entry point
│ ├── main.tsx # ✅ React root
│ ├── App.tsx # ✅ Main app component
│ ├── App.css # ✅ App styles
│ ├── index.css # ✅ Global styles
│ │
│ ├── components/
│ │ ├── VoiceInterface.tsx # Main voice UI
│ │ ├── ActivityLog.tsx # Conversation log
│ │ ├── ConnectionIndicator.tsx # Connection status
│ │ └── AudioVisualizer.tsx # Audio waveform
│ │
│ ├── hooks/
│ │ ├── useWebSocket.ts # ✅ WebSocket client
│ │ └── useWebRTC.ts # WebRTC client (Phase 8)
│ │
│ └── lib/
│ └── audio-utils.ts # Audio processing utilities
│
└── dist/
├── server/ # Compiled TypeScript
└── ui/ # Built Vite app
```
---
## Implementation Phases
### ✅ Phase 1: Foundation (COMPLETED)
**Tasks**:
1. ✅ Create package structure and configuration files
2. ✅ Set up package.json with dependencies and scripts
3. ✅ Create TypeScript configurations (tsconfig.json, tsconfig.server.json)
4. ✅ Create Vite configuration (vite.config.ts)
5. ✅ Create basic Express server (src/server/index.ts)
6. ✅ Create basic Vite React app (src/ui/)
7. ✅ Install dependencies and test dev servers
**Key Files Created**:
- `src/server/index.ts` - Express server with production static file serving
- `src/server/types.ts` - Shared TypeScript types
- `src/ui/App.tsx` - Main React component
- `src/ui/index.html` - HTML entry point
- `vite.config.ts` - Vite build configuration
**Development Workflow**:
```bash
npm run dev # Runs both servers (concurrently)
npm run dev:server # Express on port 3000
npm run dev:ui # Vite on port 5173
```
**Production Build**:
```bash
npm run build # Builds UI + server
npm start # Serves from dist/
```
---
### ✅ Phase 2: WebSocket Communication (COMPLETED)
**Tasks**:
1. ✅ Add WebSocket server (websocket-server.ts)
2. ✅ Add WebSocket client hook (useWebSocket.ts)
3. ✅ Test WebSocket ping/pong communication
**Key Features**:
- WebSocket server on `/ws` path
- Client-side `useWebSocket` hook with auto-reconnect
- Message handler registration system
- Ping/pong messaging for connection testing
- Activity log UI component
- Real-time connection status indicator
**Key Files Created**:
- `src/server/websocket-server.ts` - VoiceAssistantWebSocketServer class
- `src/ui/hooks/useWebSocket.ts` - Client WebSocket hook
- Updated `src/ui/App.tsx` - WebSocket integration & activity log
**WebSocket Message Types**:
```typescript
interface WebSocketMessage {
type: 'activity_log' | 'status' | 'webrtc_signal' | 'ping' | 'pong';
payload: unknown;
}
```
**Testing**:
1. Start both servers: `npm run dev`
2. Open http://localhost:5173
3. Click "Send Ping" button
4. See "Received pong from server" in activity log
---
### ⏳ Phase 3: Terminal Control (Daemon)
**Tasks**:
1. ⏳ Copy tmux.ts from mcp-server package
2. ⏳ Create terminal-manager.ts with tool functions
3. ⏳ Create tool-definitions.ts for LLM schemas
4. ⏳ Test terminal operations (list, create, capture)
**Objectives**:
- Reuse existing tmux primitives from mcp-server
- Create high-level terminal management API
- Define LLM tool schemas for terminal operations
- Test terminal creation, command execution, output capture
**Terminal Tools** (7 core operations):
```typescript
// Tool functions to implement in terminal-manager.ts
1. listTerminals() → TerminalInfo[]
2. createTerminal(name, workingDirectory, initialCommand?)
3. captureTerminal(terminalId, lines?, wait?)
4. sendText(terminalId, text, pressEnter?, return_output?)
5. sendKeys(terminalId, keys, repeat?, return_output?)
6. renameTerminal(terminalId, name)
7. killTerminal(terminalId)
```
**Terminal Model**:
- Default tmux session: `voice-dev`
- Terminal = tmux window (single pane)
- Terminal ID = window ID (format: `@123`)
- Working directory set on creation
---
### ⏳ Phase 4: LLM Integration
**Tasks**:
1. ⏳ Copy agent-prompt.md from agent-python
2. ⏳ Create system-prompt.ts to load prompt file
3. ⏳ Create llm-openai.ts (GPT-4 with function calling)
4. ⏳ Test LLM integration with tool calls
**Objectives**:
- Reuse existing system prompt from Python agent
- Implement OpenAI GPT-4 Turbo with function calling
- Define terminal tools as OpenAI functions
- Test: "create a terminal called test" → executes createTerminal()
**LLM Configuration**:
```typescript
{
model: "gpt-4-turbo",
tools: terminalToolDefinitions,
tool_choice: "auto",
stream: true
}
```
---
### ⏳ Phase 5: Agent Orchestrator
**Tasks**:
1. ⏳ Create agent orchestrator.ts
2. ⏳ Wire text input → LLM → tool execution → response
3. ⏳ Emit activity log events to WebSocket
4. ⏳ Test end-to-end text-based commands
**Objectives**:
- Create main agent loop
- Handle: user input → LLM → tool calls → terminal → response
- Broadcast activity to WebSocket clients
- Test complete text-based interaction flow
**Agent Loop**:
```
1. Receive user input (text/transcript)
2. Add to conversation context
3. Call LLM with tools
4. If tool calls:
a. Execute each tool via terminal-manager
b. Add results to context
c. Call LLM again with results
5. Return final response
6. Broadcast all events to WebSocket
```
---
### ⏳ Phase 6: Speech-to-Text (Deepgram)
**Tasks**:
1. ⏳ Add Deepgram STT integration (stt-deepgram.ts)
2. ⏳ Test STT with audio input
**Objectives**:
- Implement Deepgram streaming STT
- Handle audio chunks from client
- Return transcript fragments in real-time
- Detect end-of-utterance
**Deepgram Configuration**:
```typescript
{
model: "nova-2",
language: "en",
smart_format: true,
punctuate: true,
interim_results: true
}
```
---
### ⏳ Phase 7: Text-to-Speech (OpenAI)
**Tasks**:
1. ⏳ Add OpenAI TTS integration (tts-openai.ts)
2. ⏳ Test TTS with text input
**Objectives**:
- Implement OpenAI TTS API
- Convert text responses to audio
- Stream audio chunks to client
- Handle playback in browser
**TTS Configuration**:
```typescript
{
model: "tts-1",
voice: "alloy",
response_format: "pcm" // or "opus" for streaming
}
```
---
### ⏳ Phase 8: Audio Streaming
**Tasks**:
1. ⏳ Research WebRTC alternatives for audio streaming
2. ⏳ Implement audio streaming solution
3. ⏳ Test end-to-end voice interaction
**Objectives**:
- Implement bidirectional audio streaming
- Browser → Server: Microphone input
- Server → Browser: TTS output
- Consider: WebRTC (browser native) or WebSocket audio
**Note**:
- `wrtc` package removed due to native compilation issues
- Alternative options:
1. **WebRTC (browser-to-browser via signaling)** - Most robust
2. **WebSocket audio streaming** - Simpler, less efficient
3. **simple-peer** - WebRTC wrapper library
4. **MediaRecorder API** - Send audio chunks via WebSocket
---
### ⏳ Phase 9: UI Polish
**Tasks**:
1. ⏳ Create ActivityLog component (proper component)
2. ⏳ Create ConnectionIndicator component
3. ⏳ Add mute/unmute controls
4. ⏳ Polish UI and test full application
**Objectives**:
- Extract activity log into reusable component
- Add microphone mute/unmute button
- Add visual audio level indicator
- Improve styling and UX
- End-to-end testing
---
## Environment Variables
`.env` file (copy from `.env.example`):
```bash
# OpenAI API Key (for GPT-4 and TTS)
OPENAI_API_KEY=sk-...
# Deepgram API Key (for streaming STT)
DEEPGRAM_API_KEY=...
# Server Configuration
PORT=3000
NODE_ENV=development
```
---
## Development Commands
```bash
# Install dependencies
npm install
# Development (runs both servers)
npm run dev
# Development (individual servers)
npm run dev:server # Express on port 3000
npm run dev:ui # Vite on port 5173
# Build
npm run build:ui # Build Vite UI → dist/ui/
npm run build:server # Compile TS → dist/server/
npm run build # Build both
# Production
npm start # Serve from dist/
# Type checking
npm run typecheck # Check both UI and server types
```
---
## Testing Strategy
### Phase 1-2 (Foundation + WebSocket)
- ✅ Manual: Start servers, check endpoints
- ✅ Manual: Open UI, test ping/pong
### Phase 3 (Terminal Control)
- Manual: Call terminal-manager functions from server
- Manual: Verify tmux windows created/destroyed
- Manual: Check command execution and output capture
### Phase 4 (LLM)
- Manual: Send text prompts, check tool calls
- Manual: Verify tool execution results in context
### Phase 5 (Orchestrator)
- Manual: Send "create a terminal called test"
- Verify: LLM calls createTerminal tool
- Verify: Activity log shows tool call and result
### Phase 6-7 (STT/TTS)
- Manual: Record audio, check transcript
- Manual: Send text, check audio playback
### Phase 8 (Audio Streaming)
- Manual: Speak into microphone
- Verify: Real-time transcription
- Verify: Agent response plays back
### Phase 9 (Full E2E)
- Manual: Complete voice interaction loop
- Test: Various terminal commands via voice
- Test: Error handling and edge cases
---
## Key Decisions & Trade-offs
### 1. **Single Process Architecture**
- **Decision**: Run agent + daemon in same process
- **Why**: Simpler V1, avoid IPC complexity
- **Future**: Can split into microservices later
### 2. **OpenAI All-in-One**
- **Decision**: Use OpenAI for both LLM and TTS, Deepgram for STT
- **Why**: Simpler integration, fewer providers
- **Note**: Deepgram required because OpenAI Whisper doesn't support streaming
### 3. **Removed wrtc Package**
- **Decision**: Defer WebRTC server implementation to Phase 8
- **Why**: `wrtc` has native compilation issues
- **Alternative**: Will use browser-native WebRTC or WebSocket audio
### 4. **Auto-Execute Terminal Commands**
- **Decision**: No permission prompts in V1
- **Why**: Faster development, simpler UX
- **Future**: Add permission system in V2
### 5. **Reuse Existing Code**
- **Decision**: Copy tmux.ts and agent-prompt.md from existing packages
- **Why**: Proven, tested code
- **Benefit**: Consistent terminal model across packages
---
## Current Progress
**✅ Completed**: 10/33 tasks (30%)
- Phase 1: Foundation (7 tasks)
- Phase 2: WebSocket (3 tasks)
**⏳ In Progress**: Phase 3 (Terminal Control)
**📋 Remaining**: 23 tasks
- Phase 3: 4 tasks
- Phase 4: 4 tasks
- Phase 5: 4 tasks
- Phase 6: 2 tasks
- Phase 7: 2 tasks
- Phase 8: 3 tasks
- Phase 9: 4 tasks
---
## Next Steps
1. **Phase 3**: Copy `tmux.ts` from mcp-server
2. **Phase 3**: Create `terminal-manager.ts` with 7 core tools
3. **Phase 3**: Define OpenAI function schemas for tools
4. **Phase 3**: Test terminal operations manually
5. **Phase 4**: Copy `agent-prompt.md` and set up LLM
---
## References
- **Existing Packages**:
- `packages/mcp-server/src/tmux.ts` - Terminal control primitives
- `packages/agent-python/agent-prompt.md` - System prompt
- `packages/web/app/hooks/use-livekit-voice.ts` - LiveKit reference
- **APIs**:
- [OpenAI API Docs](https://platform.openai.com/docs)
- [Deepgram API Docs](https://developers.deepgram.com/)
- [WebRTC API Docs](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
---
## Notes
- This is a **V1 implementation** focused on getting a working prototype
- Prioritize simplicity over optimization
- Each phase should be independently testable
- WebSocket infrastructure is ready for real-time updates
- Audio streaming is the most complex remaining piece