docs(15-03): create agent inbox wireframe
- ASCII wireframes for inbox list and message detail views - Multi-question Q&A layout with radio/checkbox variants - Component specifications: InboxList, MessageCard, MessageDetail, QuestionForm, OptionGroup, FreeTextInput - Interaction flow for answer submission and real-time updates - Filter/sort options for message management
This commit is contained in:
364
docs/wireframes/agent-inbox.md
Normal file
364
docs/wireframes/agent-inbox.md
Normal file
@@ -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<string, string>) => 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<string, string>` - 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*
|
||||
Reference in New Issue
Block a user