Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit ace099a

Browse files
committed
docs: add Phase 6 architectural design for background task visibility
Addresses Issue #12330 Phase 6 planning discussion. Covers: - Conversation replay (6a) - Tab/panel switching (6b) - Real-time progress streaming (6c) Includes feasibility analysis, priority recommendations, and detailed design with message types, component structure, and testing strategy.
1 parent 8922418 commit ace099a

1 file changed

Lines changed: 277 additions & 0 deletions

File tree

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# Phase 6: Background Task Visibility and Interaction
2+
3+
> Architectural design document for Issue #12330
4+
> Phase 6 of "Support parallel execution of specialized agents and improve context handoff between modes"
5+
6+
## 1. Context
7+
8+
Phase 5 (Background Tasks Panel UI) is complete. This document proposes the scope, priority, and architecture for Phase 6, which focuses on enabling better visibility and interaction with background tasks.
9+
10+
## 2. Current Architecture
11+
12+
### Task Lifecycle
13+
14+
`ClineProvider` maintains a `clineStack: Task[]` (LIFO). Only the top-of-stack task is "current" -- all state updates, webview messages, and user interactions route through `getCurrentTask()`.
15+
16+
```
17+
ClineProvider
18+
├── clineStack: Task[] # LIFO stack, sequential execution
19+
├── taskHistoryStore # Per-task file persistence
20+
├── getCurrentTask() # Returns top of stack
21+
├── addClineToStack(task) # Push new task
22+
└── removeClineFromStack() # Pop completed task
23+
```
24+
25+
### Task Persistence
26+
27+
| Layer | File | Purpose |
28+
|-------|------|---------|
29+
| Messages | `taskMessages.ts` | Save/load `ClineMessage[]` per task |
30+
| API History | `apiMessages.ts` | Save/load API conversation history |
31+
| History Items | `TaskHistoryStore.ts` | Per-task metadata files with in-memory cache |
32+
| Metadata | `taskMetadata.ts` | Task metadata helpers |
33+
34+
### Webview Communication
35+
36+
The extension sends typed `ExtensionMessage` objects to the webview. Key message types:
37+
38+
- `state` -- Full state snapshot (includes `clineMessages`, `currentTaskId`)
39+
- `taskHistoryUpdated` -- Full history list refresh
40+
- `taskHistoryItemUpdated` -- Single history item update
41+
42+
Currently, `postStateToWebviewWithoutTaskHistory()` sends state for only the current task. There is no mechanism to send updates for background tasks.
43+
44+
### Subtask Support
45+
46+
Parent-child relationships exist via `parentTaskId` and `childIds` on `HistoryItem`. The `new_task` tool creates subtasks that push onto the stack. When a subtask completes, it pops and returns control to the parent.
47+
48+
## 3. Agreed Scope for Phase 6
49+
50+
**In scope (Items 1-3):**
51+
1. Full conversation replay for completed background tasks
52+
2. Tab switching / multi-task view
53+
3. Real-time progress streaming for active background tasks
54+
55+
**Deferred to Phase 7 (Items 4-5):**
56+
4. Write-capable background tasks + basic file locking
57+
5. Persistent background task history across sessions
58+
59+
## 4. Feasibility Analysis
60+
61+
### Item 1: Full Conversation Replay
62+
63+
**Complexity: Medium | Risk: Low**
64+
65+
`readTaskMessages(taskId, globalStoragePath)` already loads the full `ClineMessage[]` array from disk for any task. The existing `ChatView` component renders these messages. The main work is creating a read-only wrapper that:
66+
67+
- Accepts a `taskId` prop instead of reading from global state
68+
- Loads messages on mount via a new webview message
69+
- Hides input controls (chat box, approval buttons)
70+
- Renders tool calls, outputs, and assistant responses in the same format
71+
72+
**Why it's low risk:** No changes to task execution, persistence, or the foreground task flow. Purely additive UI + a new message handler.
73+
74+
### Item 2: Tab Switching / Multi-task View
75+
76+
**Complexity: Medium-High | Risk: Medium**
77+
78+
The webview already has a tab system in `App.tsx` (`tab === "history"`, `tab === "settings"`, `tab === "chat"`). Adding a background tasks view requires:
79+
80+
- A new tab or panel within the chat view
81+
- A list of active/completed background tasks with status indicators
82+
- Navigation to open a task's replay view or live view
83+
- State management to track which background task is currently being viewed
84+
85+
**Key challenge:** The webview currently receives state for only one task. Viewing a background task must not disrupt the foreground task's state. This requires either:
86+
- (a) A separate message channel for background task data, or
87+
- (b) A secondary state context in the webview that can hold background task data alongside the primary task state
88+
89+
Option (a) is cleaner and avoids polluting the existing state management.
90+
91+
### Item 3: Real-time Progress Streaming
92+
93+
**Complexity: High | Risk: Medium-High**
94+
95+
Currently, `Task.ts` calls `provider.postStateToWebviewWithoutTaskHistory()` to update the UI. This method sends the full state for the current task only. For background tasks to stream progress:
96+
97+
1. `Task.ts` must emit incremental updates even when it is not the "current" task
98+
2. A new message type (`backgroundTaskProgress`) must carry task-scoped updates
99+
3. The webview must handle concurrent update streams without degrading performance
100+
4. Throttling/batching is needed to prevent excessive re-renders
101+
102+
**Why it's harder:** Requires changes to the core task execution loop (`Task.ts`), not just additive UI. The task currently assumes it IS the visible task when posting updates.
103+
104+
## 5. Recommended Priority Order
105+
106+
```
107+
Phase 6a: Conversation Replay (Foundation -- standalone value)
108+
109+
110+
Phase 6b: Tab/Panel Switching (Navigation framework, depends on 6a)
111+
112+
113+
Phase 6c: Real-time Progress Streaming (Highest complexity, builds on 6b)
114+
```
115+
116+
Each sub-phase is independently shippable and testable.
117+
118+
## 6. Detailed Design
119+
120+
### 6a. Conversation Replay
121+
122+
#### New Message Types
123+
124+
```typescript
125+
// Webview → Extension
126+
interface RequestBackgroundTaskMessages {
127+
type: "requestBackgroundTaskMessages"
128+
taskId: string
129+
}
130+
131+
// Extension → Webview
132+
interface BackgroundTaskMessages {
133+
type: "backgroundTaskMessages"
134+
taskId: string
135+
messages: ClineMessage[]
136+
}
137+
```
138+
139+
#### Extension Handler (webviewMessageHandler.ts)
140+
141+
```typescript
142+
case "requestBackgroundTaskMessages": {
143+
const taskId = message.taskId
144+
const globalStoragePath = provider.contextProxy.globalStorageUri.fsPath
145+
const messages = await readTaskMessages(taskId, globalStoragePath)
146+
provider.postMessageToWebview({
147+
type: "backgroundTaskMessages",
148+
taskId,
149+
messages: messages ?? [],
150+
})
151+
break
152+
}
153+
```
154+
155+
#### Webview Component
156+
157+
```
158+
BackgroundTaskReplayView
159+
├── Props: { taskId: string, onClose: () => void }
160+
├── State: messages (ClineMessage[]), loading (boolean)
161+
├── On mount: sends requestBackgroundTaskMessages
162+
├── On message: receives backgroundTaskMessages, filters by taskId
163+
├── Renders: read-only message list (reuses ChatRow components)
164+
└── No input controls, no approval buttons
165+
```
166+
167+
### 6b. Tab/Panel Switching
168+
169+
#### UI Structure
170+
171+
```
172+
App.tsx
173+
├── tab === "chat" → ChatView (foreground task)
174+
├── tab === "history" → HistoryView
175+
├── tab === "settings" → SettingsView
176+
└── tab === "bgTask" → BackgroundTaskView
177+
├── BackgroundTasksList (sidebar/panel)
178+
│ ├── Active tasks with status badges
179+
│ └── Completed tasks
180+
└── BackgroundTaskReplayView (from 6a) OR BackgroundTaskLiveView (from 6c)
181+
```
182+
183+
#### State Management
184+
185+
```typescript
186+
// New webview state (in App.tsx or dedicated context)
187+
interface BackgroundTaskViewState {
188+
selectedTaskId: string | null
189+
viewMode: "replay" | "live"
190+
}
191+
```
192+
193+
#### Navigation Flow
194+
195+
1. User clicks background task icon/tab
196+
2. App switches to `tab === "bgTask"`
197+
3. BackgroundTasksList shows available tasks
198+
4. User clicks a task → sets `selectedTaskId`
199+
5. If task is completed → opens BackgroundTaskReplayView
200+
6. If task is active → opens BackgroundTaskLiveView (Phase 6c)
201+
202+
### 6c. Real-time Progress Streaming
203+
204+
#### New Message Types
205+
206+
```typescript
207+
// Extension → Webview (incremental updates)
208+
interface BackgroundTaskProgress {
209+
type: "backgroundTaskProgress"
210+
taskId: string
211+
update: BackgroundTaskUpdate
212+
}
213+
214+
interface BackgroundTaskUpdate {
215+
kind: "tool_call" | "tool_result" | "assistant_text" | "status_change" | "error"
216+
timestamp: number
217+
data: any // Typed per kind
218+
}
219+
```
220+
221+
#### Task.ts Changes
222+
223+
Add a method that emits progress regardless of whether the task is "current":
224+
225+
```typescript
226+
// In Task.ts
227+
private emitBackgroundProgress(update: BackgroundTaskUpdate) {
228+
const provider = this.providerRef.deref()
229+
if (!provider) return
230+
231+
// Only emit background updates when this task is NOT the current task
232+
if (provider.getCurrentTask()?.taskId === this.taskId) return
233+
234+
provider.postMessageToWebview({
235+
type: "backgroundTaskProgress",
236+
taskId: this.taskId,
237+
update,
238+
})
239+
}
240+
```
241+
242+
#### Throttling Strategy
243+
244+
- Batch updates in 200ms windows
245+
- Cap at 10 updates per batch per task
246+
- Drop older updates if buffer exceeds threshold
247+
- Priority: status_change > error > tool_result > tool_call > assistant_text
248+
249+
#### Webview: BackgroundTaskLiveView
250+
251+
```
252+
BackgroundTaskLiveView
253+
├── Props: { taskId: string }
254+
├── State: updates (BackgroundTaskUpdate[]), status
255+
├── Subscribes to backgroundTaskProgress messages filtered by taskId
256+
├── Renders: streaming list of tool calls and results
257+
├── Auto-scrolls to latest update
258+
└── Shows task status badge (running, paused, completed, errored)
259+
```
260+
261+
## 7. Testing Strategy
262+
263+
| Area | Test Type | Key Scenarios |
264+
|------|-----------|---------------|
265+
| Message handler | Unit (vitest) | Request/response for task messages, missing task, corrupt data |
266+
| BackgroundTaskReplayView | Component (vitest + RTL) | Loading state, message rendering, empty state |
267+
| Tab switching | Component (vitest + RTL) | Tab navigation, state preservation, back to foreground |
268+
| Progress streaming | Unit (vitest) | Throttling, batching, concurrent tasks |
269+
| Integration | E2E (if feasible) | Full flow: start bg task → view progress → replay after completion |
270+
271+
## 8. Open Questions
272+
273+
1. **Should the background task list be a sidebar panel or a tab?** A sidebar panel (like the existing Phase 5 panel) keeps the foreground task visible. A tab replaces the view entirely but is simpler.
274+
275+
2. **Message size limits for replay:** Completed tasks can have thousands of messages. Should we paginate or lazy-load? Initial recommendation: load all at once (same as current ChatView behavior), optimize if performance becomes an issue.
276+
277+
3. **Progress streaming granularity:** Should we stream every tool call parameter, or just tool names + status? Start with names + status, add detail incrementally.

0 commit comments

Comments
 (0)