mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-19 00:01:19 +00:00
261 lines
9.8 KiB
Markdown
261 lines
9.8 KiB
Markdown
# ARCHITECTURE_NOTES
|
|
|
|
## 1. High-level overview — How the VS Code extension works
|
|
|
|
- Activation
|
|
- VS Code activates the extension via `package.json` activation events.
|
|
- Extension creates singletons: `ClineProvider`, API adapters, managers (ProviderSettingsManager, CustomModesManager), and registers webview providers / commands.
|
|
- UI
|
|
- Sidebar/tab webview(s) host the chat UI.
|
|
- Webview <-> extension comms use postMessage handlers implemented in `webviewMessageHandler`.
|
|
- Settings views must bind inputs to a local `cachedState` (see AGENTS.md) and only persist on explicit Save.
|
|
- Task model
|
|
- `Task` is the runtime unit for an agent conversation/workflow: orchestrates prompt building, streaming, tool execution, retries, checkpoints, and persistence.
|
|
- A `ClineProvider` manages tasks and exposes methods for creating/finding the visible task.
|
|
- API & streaming
|
|
- Provider-specific API adapters (Anthropic/OpenAI-like) implement `createMessage` returning a stream.
|
|
- Task creates an `AbortController` per call, streams the response, parses events (text chunks, tool calls, usage), and renders partial assistant messages to the webview.
|
|
- Persistence & state
|
|
- `contextProxy` is used for global state persistence (settings, stored messages, conversation history).
|
|
- Checkpoints are created by the task on user sends / important state transitions.
|
|
|
|
---
|
|
|
|
## 2. Core components and responsibilities
|
|
|
|
- ClineProvider
|
|
|
|
- Lifetime manager for tasks and UI provider for the webview.
|
|
- Exposes contextProxy, settings managers, and task creation.
|
|
|
|
- Task
|
|
|
|
- submitUserMessage(), handleWebviewAskResponse(), ask(), recursivelyMakeClineRequests(), abortTask(), checkpointSave(), saveClineMessages().
|
|
- Maintains: clineMessages, assistantMessageContent, userMessageContent, currentRequest controller, abort flags, usage counters, autoApproval timers.
|
|
|
|
- API Adapter
|
|
|
|
- Abstracted provider interface to make streaming requests and parse provider-specific events into a normalized internal event stream.
|
|
|
|
- MessageQueueService
|
|
|
|
- Serializes transport of messages to UI / persistence to avoid races.
|
|
|
|
- Managers
|
|
|
|
- ProviderSettingsManager, CustomModesManager — config and mode lifecycle.
|
|
|
|
- WebviewMessageHandler
|
|
|
|
- Normalizes incoming UI messages and routes to provider or Task methods (e.g., askResponse → Task.submitUserMessage).
|
|
|
|
- Tool Executors
|
|
- Execute tool calls (file read/write, shell, formatters) as requested by the model; results are injected back into the task loop.
|
|
|
|
---
|
|
|
|
## 3. The agent loop: recursivelyMakeClineRequests — conceptual steps
|
|
|
|
1. Build or pop a userContent stack item to process.
|
|
2. Check abort/paused/reset flags and backoff state.
|
|
3. Compose prompt: conversation messages, tool metadata, file details (optional), environment hints, mode-specific system content.
|
|
4. Create an `api_req_started` placeholder message in UI and start streaming via provider API with an AbortController.
|
|
5. Stream parse:
|
|
- On text chunks: append to assistant buffer and present partial assistant message.
|
|
- On tool-call events: execute tool immediately or schedule; push tool results to user content buffer.
|
|
- On usage/grounding events: aggregate telemetry/usage.
|
|
6. When assistant completes:
|
|
- Convert assistant output and tool results into user content blocks and push back to the stack.
|
|
- If stack not empty → recurse (continue loop).
|
|
7. Handle error paths:
|
|
- Rate limits → exponential backoff and retry.
|
|
- Context window truncate → condense context and retry (MAX_CONTEXT_WINDOW_RETRIES).
|
|
- Network/first-chunk failures → retry with exponential backoff.
|
|
- Abort → update UI row with cancel reason and possibly call abortTask().
|
|
8. Persist checkpoints and telemetry periodically and on state transitions.
|
|
|
|
Return semantics:
|
|
|
|
- Returns false on normal termination (stack empty).
|
|
- Returns true/throws on unexpected error forcing outer stop.
|
|
|
|
---
|
|
|
|
## 4. Message flow (sequence diagram)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Webview
|
|
participant WebviewHandler
|
|
participant ClineProvider
|
|
participant Task
|
|
participant APIAdapter
|
|
participant ToolExecutor
|
|
|
|
User->>Webview: type + send
|
|
Webview->>WebviewHandler: postMessage("askResponse")
|
|
WebviewHandler->>ClineProvider: getVisibleInstance() / getTask
|
|
WebviewHandler->>Task: submitUserMessage(text, images)
|
|
Task->>Task: handleWebviewAskResponse(...)
|
|
Note over Task: ask() awaiting predicate resolves
|
|
Task->>APIAdapter: createMessage(prompt, controller)
|
|
APIAdapter-->>Task: stream chunks (text/tool/usage)
|
|
Task->>Webview: presentAssistantMessage(partial)
|
|
alt tool call event
|
|
Task->>ToolExecutor: execute(toolCall)
|
|
ToolExecutor-->>Task: toolResult
|
|
Task->>Task: push toolResult into userContent
|
|
end
|
|
Task->>Task: push userContent to stack -> continue loop
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Hook system: purpose and architecture
|
|
|
|
Purpose: provide extension points for cross-cutting concerns without leaking internal Task implementation. Hooks enable logging, telemetry, testing, customization (modes/providers), and third-party integrations.
|
|
|
|
Design goals:
|
|
|
|
- Minimal surface area: well-defined hook types for Task lifecycle and stream events.
|
|
- Async-capable: hooks can be async and must not block the critical fast-path; use awaited or fire-and-forget based on hook type.
|
|
- Backpressure-safe: streaming hooks receive deltas; heavy processing should be offloaded.
|
|
- Idempotent & resilient: hooks must not mutate core state in ways that affect correctness; errors should be captured and logged, not crash the task.
|
|
- Observability-first: hooks expose granular events for debugging and telemetry.
|
|
|
|
Hook categories:
|
|
|
|
- Lifecycle hooks (synchronous optional await):
|
|
- onTaskStart(taskMeta)
|
|
- onTaskStop(taskMeta, reason)
|
|
- onCheckpointSaved(checkpointMeta)
|
|
- Ask/Response hooks:
|
|
- beforeAsk(promptContext) — may mutate promptContext copy
|
|
- afterAsk(responseSummary)
|
|
- Streaming hooks (should be non-blocking):
|
|
- onStreamChunk(chunk)
|
|
- onStreamComplete(assistantMessage)
|
|
- Tool hooks:
|
|
- onToolCall(toolRequest)
|
|
- onToolResult(toolResult)
|
|
- Persistence hooks:
|
|
- onSaveMessages(messages)
|
|
- Admin hooks:
|
|
- onAbort(reason)
|
|
|
|
Hook registration API (concept):
|
|
|
|
- Task.hooks.register(name, fn, { priority = 0, awaitable = false })
|
|
- Task.hooks.unregister(id)
|
|
- Invocation: Task.hooks.invoke(name, payload) — wraps calls in try/catch and observes awaitable flag.
|
|
|
|
Decision: streaming hooks default to non-awaitable to avoid blocking the parse -> render loop. Lifecycle hooks default to awaitable.
|
|
|
|
---
|
|
|
|
## 6. Hook invocation schema (mermaid)
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[Task Event Occurs] --> B{Registered Hooks?}
|
|
B -- Yes --> C[Sort by priority]
|
|
C --> D{awaitable?}
|
|
D -- true --> E[await hook(payload)]
|
|
D -- false --> F[call hook(payload) in microtask / Promise.resolve()]
|
|
E --> G[collect results / errors]
|
|
F --> G
|
|
G --> H[continue core logic]
|
|
B -- No --> H
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Component diagram (mermaid)
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class Webview {
|
|
+postMessage()
|
|
+onMessage()
|
|
}
|
|
class WebviewHandler {
|
|
+handle(message)
|
|
}
|
|
class ClineProvider {
|
|
+createTask()
|
|
+getVisibleInstance()
|
|
}
|
|
class Task {
|
|
+submitUserMessage()
|
|
+ask()
|
|
+recursivelyMakeClineRequests()
|
|
+abortTask()
|
|
+checkpointSave()
|
|
+hooks
|
|
}
|
|
class APIAdapter {
|
|
+createMessage()
|
|
}
|
|
class ToolExecutor {
|
|
+execute()
|
|
}
|
|
|
|
Webview --> WebviewHandler
|
|
WebviewHandler --> ClineProvider
|
|
ClineProvider --> Task
|
|
Task --> APIAdapter
|
|
Task --> ToolExecutor
|
|
Task --> Webview
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Architectural decisions & rationale
|
|
|
|
- Event-driven task loop: a streaming, event-based loop simplifies partial UI updates and tool interleaving; streaming allows progressive display and early tool execution.
|
|
- Isolation of UI -> Task pathway: UI writes are normalized through `webviewMessageHandler` → `Task.submitUserMessage()` → `Task.handleWebviewAskResponse()` to avoid races and ensure canonical state changes.
|
|
- Per-request AbortController: enables precise cancellation of single API calls; Task-level `abortTask()` sets task abort state and coordinates higher-level shutdown.
|
|
- Hooks with priority & await semantics: gives control to extensions/internals for synchronous lifecycle needs while protecting the stream path from blocking.
|
|
- Checkpointing on user sends: safety and reproducibility for long-running tasks and file operations.
|
|
- Separate managers for settings/modes: keep config, mode logic, and UI concerns decoupled from Task runtime.
|
|
- Use cachedState in SettingsView: prevents race conditions between UI edits and ContextProxy live state.
|
|
|
|
---
|
|
|
|
## 9. Implementation notes and best practices
|
|
|
|
- Always write hooks defensively: catch and log errors.
|
|
- Keep streaming hooks lightweight; delegate heavy processing to worker tasks or background jobs.
|
|
- Respect task abort and per-request AbortController to avoid leaking tool executions.
|
|
- When adding a UI input to SettingsView follow AGENTS.md: bind to `cachedState` and persist to `contextProxy` only on explicit Save.
|
|
- When modifying prompt composition, prefer creating a copy of `clineMessages` to avoid concurrent mutation issues.
|
|
- Use messageQueueService for UI and persistence writes to serialize state transitions.
|
|
|
|
---
|
|
|
|
## 10. Example hook registration (conceptual)
|
|
|
|
```ts
|
|
// Example (conceptual) — register a non-blocking stream logger
|
|
Task.hooks.register(
|
|
"onStreamChunk",
|
|
(chunk) => {
|
|
// lightweight logging
|
|
console.debug("stream chunk", chunk.type, chunk.length)
|
|
},
|
|
{ awaitable: false, priority: 10 },
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Appendix — Recap of critical constants & limits
|
|
|
|
- MAX_CONTEXT_WINDOW_RETRIES = 3
|
|
- MAX_EXPONENTIAL_BACKOFF_SECONDS = 600
|
|
- FORCED_CONTEXT_REDUCTION_PERCENT = 75
|
|
|
|
---
|
|
|
|
End of ARCHITECTURE_NOTES.md
|