ITADN
obra/lace/Issues

Add Buffered Notifications and Message Queueing to Agents

#52Openobra 创建于 2025-07-03
O
obracommented
# Buffered Notifications Implementation Specification ## Overview Add message queueing to agents so they can receive notifications (task assignments, status updates) while busy processing. Messages queue up and are delivered when the agent returns to idle state. ## Background for Engineers ### Current Message Flow 1. User types message in terminal 2. UI blocks if agent is busy (shows warning) 3. User must wait and retry 4. No way to queue messages ### Agent States - `idle` - Ready for messages - `thinking` - Processing/planning response - `streaming` - Outputting response - `tool_execution` - Running tools ### Key Files to Understand - `src/agents/agent.ts` - Agent class and state machine - `src/interfaces/terminal-interface.tsx` - React terminal UI (uses Ink) - `src/threads/types.ts` - Message/event types - `src/agents/__tests__/agent.test.ts` - Agent tests ## Implementation Plan ### Phase 1: Add Message Queue to Agent **Task 1.1: Define queue types** File: `src/agents/types.ts` (update) ```typescript export interface QueuedMessage { id: string; type: 'user' | 'system' | 'task_notification'; content: string; timestamp: Date; metadata?: { taskId?: string; fromAgent?: string; priority?: 'normal' | 'high'; source?: 'task_system' | 'user_input' | 'agent_message'; }; } export interface MessageQueueStats { queueLength: number; oldestMessageAge?: number; highPriorityCount: number; } ``` Tests: - Type validation tests - Queue message creation **Commit**: "feat: define message queue types" **Task 1.2: Add queue to Agent class** File: `src/agents/agent.ts` Add to Agent class: ```typescript class Agent { private messageQueue: QueuedMessage[] = []; private isProcessingQueue = false; // Queue a message (public API) queueMessage( content: string, type: QueuedMessage['type'] = 'user', metadata?: QueuedMessage['metadata'] ): string // returns message ID // Get queue statistics getQueueStats(): MessageQueueStats // Clear queue (with optional filter) clearQueue(filter?: (msg: QueuedMessage) => boolean): number // Process queued messages when idle private async processQueuedMessages(): Promise<void> } ``` Implementation notes: - Only queue when state !== 'idle' - Process queue when returning to idle - High priority messages go to front - Emit events for queue changes Tests: - Test queueing while busy - Test immediate processing when idle - Test priority ordering - Test queue clearing **Commit**: "feat: add message queue to Agent class" ### Phase 2: Integrate Queue Processing **Task 2.1: Hook into state transitions** File: `src/agents/agent.ts` Modify `setState()` method: ```typescript private setState(newState: AgentState): void { const oldState = this.state; this.state = newState; this.emit('state_change', { from: oldState, to: newState }); // Process queue when returning to idle if (newState === 'idle' && !this.isProcessingQueue) { this.processQueuedMessages(); } } ``` Tests: - Test queue processing triggers on idle - Test no recursive processing - Test state transitions during queue processing **Commit**: "feat: auto-process queue on idle" **Task 2.2: Update sendMessage to support queueing** Current `sendMessage()` throws if not idle. Update to: ```typescript async sendMessage( content: string, options?: { queue?: boolean; metadata?: QueuedMessage['metadata']; } ): Promise<void> { if (this.state === 'idle') { // Process immediately return this.processMessage(content); } if (options?.queue) { // Queue for later const id = this.queueMessage(content, 'user', options.metadata); this.emit('message_queued', { id, queueLength: this.messageQueue.length }); return; } // Current behavior - throw error throw new Error(`Agent is ${this.state}, cannot accept messages`); } ``` Tests: - Test queue option works - Test backwards compatibility - Test events emitted **Commit**: "feat: add queue option to sendMessage" ### Phase 3: Add System Notifications **Task 3.1: Create notification formatter** File: `src/agents/notifications.ts` (new) ```typescript export class NotificationFormatter { static formatTaskAssignment(task: { title: string; prompt: string; priority: string; createdBy: string; }): string { return `[LACE TASK SYSTEM] You have been assigned a new task: Title: "${task.title}" Created by: ${task.createdBy} Priority: ${task.priority} --- TASK DETAILS --- ${task.prompt} --- END TASK DETAILS ---`; } static formatTaskCompletion(task: { title: string; assignedTo: string; notes: Array<{ content: string; author: string }>; }): string { // Format completion notification } } ``` Tests: - Test formatting produces expected output - Test escaping/sanitization - Test empty fields handled **Commit**: "feat: add notification formatters" ### Phase 4: UI Integration **Task 4.1: Show queue status in terminal** File: `src/interfaces/terminal-interface.tsx` Add queue indicator to status bar: ```typescript const QueueIndicator: React.FC<{ stats: MessageQueueStats }> = ({ stats }) => { if (stats.queueLength === 0) return null; return ( <Box> <Text color="yellow"> 📬 {stats.queueLength} queued {stats.highPriorityCount > 0 && ` (${stats.highPriorityCount} high)`} </Text> </Box> ); }; ``` Note for React devs: - Ink uses React but renders to terminal - No DOM, uses Box/Text components - Flexbox layout works similarly Tests: - Test indicator shows/hides correctly - Test count updates - Test priority indication **Commit**: "feat: add queue indicator to UI" **Task 4.2: Update input handling** Allow queueing when agent busy: ```typescript const handleSubmit = (input: string) => { if (agentState === 'idle') { // Normal send agent.sendMessage(input); } else { // Offer to queue setPrompt({ message: 'Agent is busy. Queue message? (y/n)', onResponse: (response) => { if (response.toLowerCase() === 'y') { agent.sendMessage(input, { queue: true }); addMessage({ type: 'system', content: '📬 Message queued', }); } } }); } }; ``` Tests: - Test queue prompt appears - Test message queued on 'y' - Test cancelled on 'n' **Commit**: "feat: add UI queue controls" ### Phase 5: Event Integration **Task 5.1: Emit queue events** Add events to Agent: - `message_queued` - When message added to queue - `queue_processing_start` - Starting to process queue - `queue_processing_complete` - Finished processing - `queue_cleared` - Queue was cleared File: `src/agents/agent.ts` Tests: - Test all events emitted - Test event data correct - Test event ordering **Commit**: "feat: add queue events" ### Phase 6: Testing & Polish **Task 6.1: End-to-end tests** File: `src/agents/__tests__/agent-queue-e2e.test.ts` Scenarios: 1. User queues multiple messages during long operation 2. Task notifications queue while agent busy 3. High priority messages processed first 4. Queue survives errors in processing **Task 6.2: Add queue management commands** Add commands to clear/inspect queue: - `/queue` - Show queue contents - `/queue clear` - Clear all queued - `/queue clear user` - Clear user messages only ## Testing Strategy ### Unit Tests - Queue operations (add, remove, reorder) - State transition hooks - Event emissions - Priority handling ### Integration Tests - Full message flow with queueing - UI updates with queue - Multiple agents with separate queues ### Manual Testing 1. Start long-running task 2. Try to send message (should offer queue) 3. Queue several messages 4. Watch them process when agent idle 5. Test high-priority interruption ## React/Ink Considerations ### For React Developers - Ink renders React to terminal - Use Box for layout (like div) - Use Text for content (like span) - No CSS - use props like color, bold - Hooks work normally - No onClick - keyboard input only ### Example Ink Component ```typescript const MyComponent: React.FC = () => { const [count, setCount] = useState(0); useInput((input) => { if (input === '+') setCount(c => c + 1); }); return ( <Box flexDirection="column"> <Text bold>Count: {count}</Text> <Text dim>Press + to increment</Text> </Box> ); }; ``` ## Performance Considerations - Limit queue size (e.g., 100 messages) - Process in batches for efficiency - Don't block UI updates during processing - Consider queue persistence for crashes ## Error Handling - Failed message processing shouldn't stop queue - Log errors but continue with next message - Provide way to retry failed messages - Never lose queued messages ## Future Enhancements - Persist queue to disk - Queue expiration times - Cancel specific queued messages - Queue analytics/metrics
0 条评论