fix(collaboration): harden delegated task isolation (#1486)

* feat(collaboration): isolate delegated artifacts and child runs

Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution.

* fix(collaboration): harden delegated task isolation

Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces.

* fix(collaboration): recover interrupted async tasks

* fix(collaboration): normalize persisted child-run status

---------

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
This commit is contained in:
Duc Nguyenandntduc authored and GitHub committed 2026-07-30 14:17:40 +07:00
1 parent 496b7ffce6
commit bb7712a9ff
186 files changed
+18858 -1233

No files matched your search

+54 -3
View File
@@ -144,7 +144,7 @@ Memory layers: L1 (`memory_search`) returns ranked abstracts; L2 (`memory_expand
| Tool | Description |
|---|---|
| `delegate` | Inter-agent task delegation via agent_links (async/sync modes with timeout) |
| `delegate` | Inter-agent task delegation via `agent_links` (async/sync, optional structured input files, isolated output publication) |
### Teams (`group:team`)
@@ -170,6 +170,19 @@ Memory layers: L1 (`memory_search`) returns ranked abstracts; L2 (`memory_expand
| `read_document` | Extract and analyze documents (PDF, DOCX, images). Supports local-first extraction via pdftotext/pandoc before falling back to cloud vision (opt-in via config) |
| `read_video` | Analyze/transcribe video content |
Image attachments keep absolute paths only in internal `MediaRef` storage.
Model-visible `<media:image>` tags expose an exact media ID plus a logical path
such as `.uploads/photo.jpg` or delegated `inputs/photo.jpg`. Image tools resolve
those values against the active workspace; they never infer another agent's
absolute workspace path. Unknown image IDs fail instead of falling back to an
unrelated image. Exact `media_id` lookup is an in-process convenience; Claude
CLI/MCP uses the workspace-confined logical `path` under signed bridge context.
For Agent Link artifact runs, Claude CLI MCP requests carry a signed delegation
ID and staged-input root. Bridge tools therefore apply the same read-only
`inputs/` policy as in-process tools, and generated media remains inside
`outputs/` until the delegation manifest is validated and atomically published.
### Skills & Content
| Tool | Description |
@@ -613,13 +626,51 @@ stateDiagram-v2
| Constraint | Default |
|---|---|
| Max concurrent | 8 (across all parents) |
| Max concurrent | 20 executing descendants per root agent |
| Max spawn depth | 1 |
| Max children per agent | 5 |
| Archive after | 60 min |
| Max iterations | 20 per subagent |
**Actions:** `spawn` (async, returns immediately), `run` (sync, blocks until done), `list`, `cancel` (by ID / `"all"` / `"last"`), `steer` (cancel + respawn with new message).
`maxSpawnDepth` applies only to an agent's own subagent tree. Agent Link
delegation starts a new tree whose spawn depth, concurrency, fanout, retry, and
model settings are resolved from the target agent.
**Actions:** `spawn(action="spawn", mode="async"|"sync")`, `get`, `list`,
`cancel` (by ID / `"all"` / `"last"`), `steer` (cancel + respawn with new
message), and `wait`.
An accepted async spawn returns its short runtime `task_id` plus a durable
`completion_id`. Terminal status, the full text result, and workspace-safe
logical media descriptors are written to `subagent_tasks` before the parent
announcement is attempted. Announcement delivery retries a bounded number of
times; if the inbound queue is still full or the gateway restarts after
terminal persistence, the owning root agent can recover the result and logical
file paths with:
```text
spawn(action="get", completion_id="<uuid>")
```
The lookup is scoped by tenant and immutable root-agent UUID. A same-key agent
created later, another agent in the tenant, and delegation completion rows
cannot satisfy the lookup.
Terminal persistence uses per-attempt database deadlines and a longer bounded
retry window than announcement delivery. If the database remains unavailable
for the entire window, GoClaw does not falsely mark the announcement as
delivered; a live announcement is still attempted. On the next startup that
can reach the database, every non-terminal completion row left by the previous
process is marked `failed` with an interruption reason, so it cannot remain
`queued` or `running` forever. The single-process gateway retries this
reconciliation before accepting traffic when the database is temporarily
unavailable. Graceful gateway shutdown drains this completion lifecycle before
provider and database teardown.
Self-spawn and Agent Link callbacks also share a process safety cap (Standard:
32; Lite: 2) and a bounded pending queue of 128. Inside an Agent Link artifact
run, async `spawn` and async nested `delegate` are rejected; configured
synchronous descendants complete before the outer artifact is published.
Subagents share the same `SecureCLIStore` as their parent — the credentialed binary gate cannot be bypassed by delegating exec to a child.