diff --git a/docs/wireframes/agent-inbox.md b/docs/wireframes/agent-inbox.md new file mode 100644 index 0000000..348f4fe --- /dev/null +++ b/docs/wireframes/agent-inbox.md @@ -0,0 +1,364 @@ +# Agent Inbox Wireframe + +Message queue UI where users see questions from agents and respond to them. + +## Screen Layout + +### Inbox List View + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Agent Inbox (3) [Refresh] │ +├─────────────────────────────────────────────────────────────┤ +│ Filter: [All ▾] Sort: [Newest ▾] │ +├─────────────────────────────────────────────────────────────┤ +│ ● gastown (waiting) 2 min ago │ +│ "Which auth provider should we use? I need to decide..." │ +├─────────────────────────────────────────────────────────────┤ +│ ● chinatown (waiting) 5 min ago │ +│ "I found 3 potential issues with the migration..." │ +├─────────────────────────────────────────────────────────────┤ +│ ○ yaletown (done) 15 min ago │ +│ "Task completed: Created user schema" │ +└─────────────────────────────────────────────────────────────┘ +``` + +**Legend:** +- ● = Requires response (agent waiting) +- ○ = Informational (no response needed) + +### Empty State + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Agent Inbox (0) [Refresh] │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ No pending messages │ +│ │ +│ Agents will appear here when they have │ +│ questions or status updates │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Message Detail View + +### Single Question (Radio Buttons) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ gastown → You 2 minutes ago │ +│ Task: Implement auth middleware │ +│ Worktree: .cw-worktrees/gastown │ +├─────────────────────────────────────────────────────────────┤ +│ Q1: Which authentication provider should we use? │ +│ │ +│ ○ Supabase Auth - Built-in with our DB │ +│ ○ Clerk - Beautiful pre-built UI │ +│ ○ NextAuth.js - Self-hosted, maximum control │ +│ ○ Other: [________________] │ +│ │ +│ [Cancel] [Send Answers] │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Multi-Question Format + +``` +┌─────────────────────────────────────────────────────────────┐ +│ gastown → You 2 minutes ago │ +│ Task: Implement auth middleware │ +│ Worktree: .cw-worktrees/gastown │ +├─────────────────────────────────────────────────────────────┤ +│ Q1: Which authentication provider should we use? │ +│ │ +│ ○ Supabase Auth - Built-in with our DB │ +│ ○ Clerk - Beautiful pre-built UI │ +│ ○ NextAuth.js - Self-hosted, maximum control │ +│ ○ Other: [________________] │ +│ │ +│ Q2: Should we implement refresh token rotation? │ +│ │ +│ ○ Yes - More secure │ +│ ○ No - Simpler implementation │ +│ │ +│ Q3: Session storage preference? │ +│ │ +│ ○ Database - Full control, revocation │ +│ ○ JWT only - Stateless, simpler │ +│ │ +│ [Cancel] [Send Answers] │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Multi-Select Question (Checkboxes) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ chinatown → You 5 minutes ago │ +│ Task: Configure database schema │ +│ Worktree: .cw-worktrees/chinatown │ +├─────────────────────────────────────────────────────────────┤ +│ Q1: Which optional features should we include? │ +│ (Select all that apply) │ +│ │ +│ ☐ Soft deletes - Mark deleted instead of removing │ +│ ☐ Audit logging - Track all changes │ +│ ☐ Full-text search - PostgreSQL tsvector │ +│ ☐ Row-level security - Fine-grained access │ +│ │ +│ Q2: Primary key strategy? │ +│ │ +│ ○ UUID - Globally unique, no collisions │ +│ ○ Serial - Simple, human-readable │ +│ ○ ULID - Sortable UUIDs │ +│ │ +│ [Cancel] [Send Answers] │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Free-Text Answer + +``` +┌─────────────────────────────────────────────────────────────┐ +│ yaletown → You 10 minutes ago │ +│ Task: Set up deployment │ +│ Worktree: .cw-worktrees/yaletown │ +├─────────────────────────────────────────────────────────────┤ +│ Q1: What should the production domain be? │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ app.example.com │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ Q2: Any custom environment variables needed? │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ FEATURE_FLAGS=beta │ │ +│ │ API_RATE_LIMIT=1000 │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ [Cancel] [Send Answers] │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Notification Message (No Response) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ yaletown → You 15 minutes ago │ +│ Task: Create user schema │ +│ Worktree: .cw-worktrees/yaletown │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ✓ Task completed successfully │ +│ │ +│ Created: │ +│ - src/db/schema/user.ts │ +│ - src/db/schema/session.ts │ +│ - migrations/001_create_users.sql │ +│ │ +│ Ready for merge into main branch. │ +│ │ +│ [Dismiss] [View Changes] │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Component Specifications + +### InboxList + +**Props:** +- `messages: Message[]` - List of messages to display +- `filter: 'all' | 'waiting' | 'completed'` - Current filter state +- `sort: 'newest' | 'oldest'` - Sort order +- `onFilterChange: (filter) => void` - Filter change handler +- `onSortChange: (sort) => void` - Sort change handler +- `onRefresh: () => void` - Refresh handler +- `onSelectMessage: (messageId: string) => void` - Message selection handler + +**Behavior:** +- Displays message cards in a scrollable list +- Shows unread count badge in header +- Filterable by status (All, Waiting, Completed) +- Sortable by timestamp (Newest first, Oldest first) +- Clicking a message expands the detail view + +### MessageCard + +**Props:** +- `message: Message` - Message data +- `isSelected: boolean` - Whether this card is currently selected +- `onClick: () => void` - Click handler + +**Display:** +- Sender agent name with status indicator (● waiting, ○ done) +- Message preview (first line, truncated) +- Relative timestamp (e.g., "2 min ago", "1 hour ago") + +**States:** +- Default - normal styling +- Selected - highlighted/expanded +- Unread - bold text, filled indicator + +### MessageDetail + +**Props:** +- `message: Message` - Full message data +- `onSubmit: (answers: Record) => void` - Submit handler +- `onCancel: () => void` - Cancel/close handler + +**Display:** +- Header: Sender name, timestamp, task info, worktree path +- Content: All questions with their input components +- Footer: Action buttons (Cancel, Send Answers / Dismiss) + +**Behavior:** +- Validates all required questions are answered before enabling submit +- Calls agent resume with formatted answers on submit +- Closes detail view on cancel or successful submit + +### QuestionForm + +**Props:** +- `questions: Question[]` - Array of questions to render +- `answers: Record` - Current answer state +- `onAnswerChange: (questionId: string, answer: string) => void` - Answer change handler + +**Renders:** +- Sequential question components based on question type +- Each question has unique ID for answer correlation +- Supports mixed question types in same form + +### OptionGroup + +**Props:** +- `questionId: string` - Question identifier +- `options: Option[]` - Available options +- `multiSelect: boolean` - Whether to use checkboxes (true) or radio buttons (false) +- `value: string | string[]` - Current selection +- `onChange: (value: string | string[]) => void` - Change handler +- `allowOther: boolean` - Whether to show "Other" free-text option + +**Behavior:** +- Radio buttons for single-select (default) +- Checkboxes for multi-select +- "Other" field appears when `allowOther` is true +- Typing in "Other" selects it automatically + +### FreeTextInput + +**Props:** +- `questionId: string` - Question identifier +- `placeholder: string` - Placeholder text +- `multiline: boolean` - Single line or textarea +- `value: string` - Current value +- `onChange: (value: string) => void` - Change handler + +**Behavior:** +- Single line input for short answers +- Textarea for longer content (auto-resize optional) +- Character limit indicator if applicable + +## Interaction Notes + +### Message Selection Flow + +1. User clicks message in InboxList +2. MessageCard enters selected state +3. MessageDetail panel appears (expands below or in side panel) +4. Previous selection collapses + +### Answer Submission Flow + +1. User selects/enters answers for all questions +2. "Send Answers" button becomes enabled when all required answered +3. User clicks "Send Answers" +4. System calls `agent.resume` with formatted answers: + ```typescript + { + [questionId: string]: answer: string + } + ``` +5. Detail panel closes +6. Message moves to "Completed" status +7. Agent continues execution + +### Notification Handling + +1. Completed task notifications don't require response +2. User can dismiss to archive +3. "View Changes" opens diff/preview (future feature) + +### Real-Time Updates + +1. New messages appear at top with subtle animation +2. Unread count updates automatically +3. Message status updates when agent state changes +4. Optional desktop notification for new messages + +## Filter & Sort Options + +### Filter Options + +| Filter | Shows | +|--------|-------| +| All | All messages | +| Waiting | Messages requiring response (agent status = waiting_for_input) | +| Completed | Notifications and answered messages | + +### Sort Options + +| Sort | Behavior | +|------|----------| +| Newest first | Most recent at top (default) | +| Oldest first | Oldest at top | + +## Data Schema Reference + +### Message + +```typescript +interface Message { + id: string + sender: { type: 'agent' | 'user', id?: string } + recipient: { type: 'agent' | 'user', id?: string } + content: string + requiresResponse: boolean + parentMessageId?: string // For response threading + createdAt: Date +} +``` + +### Question + +```typescript +interface Question { + id: string // Unique ID for answer correlation + question: string // The question text + options?: Option[] // Available choices + multiSelect?: boolean // Checkboxes vs radio buttons +} + +interface Option { + value: string + label: string +} +``` + +### Agent Context + +```typescript +interface AgentContext { + name: string // Human-readable name (gastown, chinatown) + status: AgentStatus // 'waiting_for_input' | 'running' | 'completed' + taskId?: string // Associated task + worktreeId?: string // Associated worktree +} +``` + +--- + +*Wireframe: Agent Inbox* +*Created: 2026-02-02*