fix(web-app,agent-presets): keep the task registry on the host plane

`tool-bash` resolves the background-task registry with `ctx.get('tasks')`,
and it sits at the preset's top level. The registry sat inside an
entry-local `isolate: { tasks: true }` realm, which is invisible to every
sibling row outside it, while the Web surface disabled the host row — so
both lookups missed and every `run_in_background` call answered
"background tasks unavailable" with `task_output`, `task_list`, and
`task_kill` still listed in the catalog. `task_list` returning
"(no background tasks)" is what made the outage read as an empty queue
rather than a severed producer.

That is the `goals` criterion read from inside the preset: a Service a row
outside its realm READS belongs to the plane both can see. `tasks` already
keys access by owning agent (`assertAccess` compares `task.owner.id`) and
mints an independent token per `attachSurface` call, so one host instance
serves every session exactly as before presets — the per-preset-standing-mounts
note records that sharing `tasks-local` is a return to its design.

`minimal` mounts no `tool-tasks`, and the `start()` control-surface gate is
a service-wide set that another preset's controls would open for it, so its
`tool-bash` disables `run_in_background` and drops the parameter from the
schema.

Fixes #2141
This commit is contained in:
Yichen Jiang
2026-08-10 14:18:41 +08:00
parent 6648ff984a
commit 5d86a284e5
6 changed files with 107 additions and 36 deletions

View File

@@ -218,10 +218,17 @@
- id: tool-bash
disabled: true
- id: tool-tasks
disabled: true
# The background-task REGISTRY stays on the host plane; only the model-facing
# `task_*` controls move. Its producers — `tool-bash` here, `tool-pty` and a
# non-continuable `tool-subagent` elsewhere — are preset rows that resolve it
# with `ctx.get`, and an entry-local realm around the registry is invisible to
# every sibling row outside that realm, so `run_in_background` answered
# "background tasks unavailable" while the controls sat in the catalog. That is
# the `goals` criterion read from inside the preset: a Service a row outside its
# realm READS belongs to the plane both can see. The registry is keyed by owning
# agent, so one host instance serves every session exactly as before presets.
- id: tasks
- id: tool-tasks
disabled: true
- id: tool-fs