One host registry serves every composition in the process, so its two service-wide collections answered per-owner questions process-wide. `start()` asked only whether SOME surface was attached, so an agent whose own composition loads no `tool-tasks` could start work it has no tool to collect or stop as soon as any other preset attached one — and the answer changed depending on which sessions happened to be open. `settle()` walked every registered listener, so a task settling without a waiter injected one completion notice per mounted preset into the same owner. Both collections now sit in `ScopedLayers`, the layered-registry primitive `tools` and `skills` already use: a registration files into its registering context's scope, and a read unions the global layer with the owner's scope chain. A surface or listener registered from an unscoped context lands in the global layer and serves every owner, which is exactly the host-plane composition's own controls, so the TUI path is unchanged without a special case. This supersedes the consumer-side filter in the previous commit. That filter produced the right notices but sat in the wrong layer: it left the `start()` gate process-wide, it could not be enforced against a producer that resolves the registry directly, and it made a Consumer carry scope knowledge that the other layered registries keep in the registry. `tool-tasks` is scope-agnostic again and the `dsh-scope` edge moves to `tasks-local`. `start()`'s refusal is now owner-relative, so its model-visible text names the agent rather than the process. The shipped `minimal` preset keeps `enableRunInBackground: false`, no longer as the safety boundary — the registry owns that now — but so an agent that could never collect a task is not offered the parameter at all. Refs #2141
40 lines
1.8 KiB
YAML
40 lines
1.8 KiB
YAML
# The `minimal` agent preset: the two-tool benchmark surface.
|
|
#
|
|
# The native model surface is exactly persistent `bash` plus
|
|
# `str_replace_editor`. Everything else a session could reach — skills, goals,
|
|
# plan mode, delegation, workflows, todo, web — is simply absent rather than
|
|
# disabled, because a preset composes what an agent has instead of subtracting
|
|
# from a shared default.
|
|
#
|
|
# The host composition is unchanged: this agent still runs inside the same
|
|
# sandbox, approval, persistence, and model routing as any other session.
|
|
|
|
- id: persona
|
|
name: '@deepseek-ai/dsh-persona'
|
|
config:
|
|
text: >-
|
|
You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
|
|
# `bash-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
|
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
|
# the criterion for host-plane ownership — injection resolves before any session
|
|
# exists, so there is no agent to key by. Behind a preset realm those variables
|
|
# never reached the model's shell at all. `tool-bash` consumes the host registry
|
|
# from here; the executor behind it (`bash-sandbox`) is host-plane too, where the
|
|
# sandbox policy owns it.
|
|
#
|
|
# `run_in_background` is off because this preset mounts no `tool-tasks`. The
|
|
# host registry already refuses a start for an owner no attached control
|
|
# surface serves, so this is not the safety boundary — it is the model-facing
|
|
# one: an agent that could never collect a task should not be offered the
|
|
# parameter at all, and disabling it drops the parameter from the schema.
|
|
- id: tool-bash
|
|
name: '@deepseek-ai/dsh-tool-bash'
|
|
config:
|
|
enableRunInBackground: false
|
|
|
|
- id: tool-str-replace-editor
|
|
name: '@deepseek-ai/dsh-tool-str-replace-editor'
|
|
config:
|
|
maxOutputChars: 16000
|