docs(subagents): clarify detached session lifecycle
This commit is contained in:
+29
-25
@@ -3,9 +3,10 @@
|
||||
Sub-agents are persistent background instances of the agent loop. The parent
|
||||
opens one with a focused task, gets back an `agent_id` and session name
|
||||
immediately, and continues working while the sub-agent runs to completion.
|
||||
Sub-agents inherit the parent's tool registry by default and run with
|
||||
`CancellationToken::child_token()`, so cancelling the parent cancels every
|
||||
descendant.
|
||||
Sub-agents inherit the parent's tool registry by default. `agent_open`
|
||||
launches them as detached background work: cancelling the parent turn stops the
|
||||
parent wait/eval path, but it does not kill already-opened child sessions. Use
|
||||
`agent_close` to cancel a running child explicitly.
|
||||
|
||||
This doc covers the role taxonomy. The active orchestration surface is
|
||||
`agent_open`, `agent_eval`, and `agent_close`; see `prompts/base.md`
|
||||
@@ -17,15 +18,15 @@ The `type` field on `agent_open` selects a system-prompt posture for the child
|
||||
(`agent_type` is accepted as a compatibility alias). Each role is a distinct
|
||||
stance toward the work — not just a different label.
|
||||
|
||||
| Role | Stance | Writes? | Runs shell? | Typical use |
|
||||
|---------------|----------------------------------------|---------|-------------|----------------------------------------------|
|
||||
| `general` | flexible; do whatever the parent says | yes | yes | the default; multi-step tasks |
|
||||
| `explore` | read-only; map the relevant code fast | no | yes (read) | "find every call site of `Foo`" |
|
||||
| `plan` | analyse and produce a strategy | minimal | minimal | "design the migration; don't execute" |
|
||||
| `review` | read-and-grade with severity scores | no | no | "audit this PR for bugs" |
|
||||
| `implementer` | land a specific change with min edit | yes | yes | "rewrite `bar.rs::Foo::bar` to do X" |
|
||||
| `verifier` | run tests / validation, report outcome | no | yes (test) | "run cargo test --workspace, report" |
|
||||
| `custom` | explicit narrow tool allowlist | depends | depends | locked-down dispatch with hand-picked tools |
|
||||
| Role | Stance | Writes? | Shell posture | Typical use |
|
||||
|---------------|----------------------------------------|---------|---------------|----------------------------------------------|
|
||||
| `general` | flexible; do whatever the parent says | yes | yes | the default; multi-step tasks |
|
||||
| `explore` | read-only; map the relevant code fast | no | read-only | "find every call site of `Foo`" |
|
||||
| `plan` | analyse and produce a strategy | minimal | minimal | "design the migration; don't execute" |
|
||||
| `review` | read-and-grade with severity scores | no | read-only | "audit this PR for bugs" |
|
||||
| `implementer` | land a specific change with min edit | yes | yes | "rewrite `bar.rs::Foo::bar` to do X" |
|
||||
| `verifier` | run tests / validation, report outcome | no | test-focused | "run cargo test --workspace, report" |
|
||||
| `custom` | explicit narrow tool allowlist | depends | depends | locked-down dispatch with hand-picked tools |
|
||||
|
||||
Each role's full system prompt lives in
|
||||
`crates/tui/src/tools/subagent/mod.rs` (search for
|
||||
@@ -100,8 +101,9 @@ the next turn.
|
||||
The dispatcher caps concurrent sub-agents at 10 by default
|
||||
(configurable via `[subagents].max_concurrent` in `~/.deepseek/config.toml`,
|
||||
hard ceiling 20). When the parent hits the cap, `agent_open` returns
|
||||
an error with the cap value; the parent should use `agent_eval` to wait for
|
||||
completion or `agent_close` to free a slot before retrying.
|
||||
an error with the cap value; the parent should use `agent_eval` to wait for a
|
||||
running agent to complete, or `agent_close` to cancel a running agent, before
|
||||
retrying.
|
||||
|
||||
The cap counts only **running** agents — completed / failed /
|
||||
cancelled records persist for inspection but don't occupy a slot.
|
||||
@@ -116,17 +118,16 @@ Each opened session produces a record that progresses through:
|
||||
Pending → Running → (Completed | Failed(reason) | Cancelled | Interrupted(reason))
|
||||
```
|
||||
|
||||
`Interrupted` fires when the manager detects a `Running` agent
|
||||
whose task handle is gone — typically after a process restart that
|
||||
loaded the agent from `~/.deepseek/subagents.v1.json`. The parent
|
||||
can open a replacement session with the same assignment or treat it as a
|
||||
terminal state.
|
||||
`Interrupted` fires when the manager detects a `Running` agent whose task
|
||||
handle is gone — typically after a process restart that loaded the workspace's
|
||||
persisted state from `.deepseek/state/subagents.v1.json`. The parent can open a
|
||||
replacement session with the same assignment or treat it as a terminal state.
|
||||
|
||||
### Session boundaries (#405)
|
||||
|
||||
Each `SubAgentManager` instance assigns itself a fresh
|
||||
`session_boot_id` on construction. Every new session stamps the agent
|
||||
with that id; the persisted state file carries it across restarts.
|
||||
Each `SubAgentManager` instance assigns itself a fresh `session_boot_id` on
|
||||
construction. Every new session stamps the agent with that id; the workspace
|
||||
state file records it for restart recovery.
|
||||
|
||||
`agent_eval` and the sidebar/status projections focus on current-session
|
||||
agents by default. Prior-session agents that are not still running are treated
|
||||
@@ -166,10 +167,13 @@ don't go through the standard write-approval flow.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- Source: `crates/tui/src/tools/subagent/mod.rs` (about 3500 LOC).
|
||||
- Persisted state: `~/.deepseek/subagents.v1.json`. Schema version
|
||||
`1` (forward-compatible — new optional fields use
|
||||
- Source: `crates/tui/src/tools/subagent/mod.rs`.
|
||||
- Persisted state: `<workspace>/.deepseek/state/subagents.v1.json`. Schema
|
||||
version `1` (forward-compatible — new optional fields use
|
||||
`#[serde(default)]`).
|
||||
- `SubAgentRuntime::background_runtime()` starts from `child_runtime()` but
|
||||
replaces the turn-scoped child token with a fresh cancellation token, so
|
||||
parent turn cancellation does not stop detached background sessions.
|
||||
- The `is_running` check ignores agents whose `task_handle` is
|
||||
`None`; this avoids counting persisted-but-detached records
|
||||
toward the concurrency cap (#509).
|
||||
|
||||
Reference in New Issue
Block a user