``` 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> ```
14 KiB
14 KiB
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:
- ✅ Create package structure and configuration files
- ✅ Set up package.json with dependencies and scripts
- ✅ Create TypeScript configurations (tsconfig.json, tsconfig.server.json)
- ✅ Create Vite configuration (vite.config.ts)
- ✅ Create basic Express server (src/server/index.ts)
- ✅ Create basic Vite React app (src/ui/)
- ✅ Install dependencies and test dev servers
Key Files Created:
src/server/index.ts- Express server with production static file servingsrc/server/types.ts- Shared TypeScript typessrc/ui/App.tsx- Main React componentsrc/ui/index.html- HTML entry pointvite.config.ts- Vite build configuration
Development Workflow:
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:
npm run build # Builds UI + server
npm start # Serves from dist/
✅ Phase 2: WebSocket Communication (COMPLETED)
Tasks:
- ✅ Add WebSocket server (websocket-server.ts)
- ✅ Add WebSocket client hook (useWebSocket.ts)
- ✅ Test WebSocket ping/pong communication
Key Features:
- WebSocket server on
/wspath - Client-side
useWebSockethook 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 classsrc/ui/hooks/useWebSocket.ts- Client WebSocket hook- Updated
src/ui/App.tsx- WebSocket integration & activity log
WebSocket Message Types:
interface WebSocketMessage {
type: 'activity_log' | 'status' | 'webrtc_signal' | 'ping' | 'pong';
payload: unknown;
}
Testing:
- Start both servers:
npm run dev - Open http://localhost:5173
- Click "Send Ping" button
- See "Received pong from server" in activity log
⏳ Phase 3: Terminal Control (Daemon)
Tasks:
- ⏳ Copy tmux.ts from mcp-server package
- ⏳ Create terminal-manager.ts with tool functions
- ⏳ Create tool-definitions.ts for LLM schemas
- ⏳ 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):
// 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:
- ⏳ Copy agent-prompt.md from agent-python
- ⏳ Create system-prompt.ts to load prompt file
- ⏳ Create llm-openai.ts (GPT-4 with function calling)
- ⏳ 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:
{
model: "gpt-4-turbo",
tools: terminalToolDefinitions,
tool_choice: "auto",
stream: true
}
⏳ Phase 5: Agent Orchestrator
Tasks:
- ⏳ Create agent orchestrator.ts
- ⏳ Wire text input → LLM → tool execution → response
- ⏳ Emit activity log events to WebSocket
- ⏳ 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:
- ⏳ Add Deepgram STT integration (stt-deepgram.ts)
- ⏳ 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:
{
model: "nova-2",
language: "en",
smart_format: true,
punctuate: true,
interim_results: true
}
⏳ Phase 7: Text-to-Speech (OpenAI)
Tasks:
- ⏳ Add OpenAI TTS integration (tts-openai.ts)
- ⏳ 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:
{
model: "tts-1",
voice: "alloy",
response_format: "pcm" // or "opus" for streaming
}
⏳ Phase 8: Audio Streaming
Tasks:
- ⏳ Research WebRTC alternatives for audio streaming
- ⏳ Implement audio streaming solution
- ⏳ 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:
wrtcpackage removed due to native compilation issues- Alternative options:
- WebRTC (browser-to-browser via signaling) - Most robust
- WebSocket audio streaming - Simpler, less efficient
- simple-peer - WebRTC wrapper library
- MediaRecorder API - Send audio chunks via WebSocket
⏳ Phase 9: UI Polish
Tasks:
- ⏳ Create ActivityLog component (proper component)
- ⏳ Create ConnectionIndicator component
- ⏳ Add mute/unmute controls
- ⏳ 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):
# 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
# 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:
wrtchas 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
- Phase 3: Copy
tmux.tsfrom mcp-server - Phase 3: Create
terminal-manager.tswith 7 core tools - Phase 3: Define OpenAI function schemas for tools
- Phase 3: Test terminal operations manually
- Phase 4: Copy
agent-prompt.mdand set up LLM
References
-
Existing Packages:
packages/mcp-server/src/tmux.ts- Terminal control primitivespackages/agent-python/agent-prompt.md- System promptpackages/web/app/hooks/use-livekit-voice.ts- LiveKit reference
-
APIs:
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