Code Mode was a deployment-wide field on the host `tools` row: a deployment ran every session that way or none. The obvious product shape — 代码模式 beside 标准/极简/创造 in the preset picker — had nothing to hang on. The registry itself cannot move into a preset; the agent loop's scheduler, the api-proxy's presenters, and every tool plugin are its consumers. So split the registry from its projection: `presentAs(mode)` writes one cell on the calling agent's scope layer, exactly as `restrict()` does, and the three reads that decided presentation take that scope's mode instead of the service's. The config `mode` becomes the default agents shadow rather than a process-wide fact. Two consequences are load-bearing. `run_code` now enters a view only for scopes whose own mode presents it — a native agent must not find it dispatchable because another agent in the process does — and the reserved name holds whatever the configured mode, since any agent may select a code mode later. `dsh-agent-tool-mode` is the row a preset carries to declare this. A code mode waits for the host's `codeRuntime` rather than assuming it, so a runtime-less deployment fails the preset at mount, naming the row, instead of at the session's first request. The shipped `code` preset is `standard` plus that row, ordered second.
32 lines
2.4 KiB
Markdown
32 lines
2.4 KiB
Markdown
# dsh-agent-tool-mode
|
|
|
|
English | [中文](README.zh.md)
|
|
|
|
The row an [agent preset](../../preset/agent-presets/README.md) carries to say which form of its tools the model sees: `native` (every schema), `code` (only `run_code` plus a generated TypeScript SDK), or `both`.
|
|
|
|
## Why a row rather than a registry
|
|
|
|
The tool registry cannot move into a preset. Its consumers are all host-plane — [`dsh-agent-loop`](../agent-loop/README.md) reads its scheduler, [`dsh-apiproxy`](../../host/apiproxy/README.md) reads its presenters to render tool cards, and every tool plugin registers into it — and a service only moves down when all of its consumers move with it.
|
|
|
|
What a preset can own is the **presentation** of that registry. `ctx.tools.presentAs()` declares it for the mounting agent alone, so a Code Mode session runs beside native ones in one process, each seeing its own catalog. The deployment's `mode` on the [`dsh-tools`](../tools/README.md) row remains the default that agents declaring nothing get.
|
|
|
|
## What it does
|
|
|
|
`native` applies immediately. A code mode instead waits for `ctx.codeRuntime`, which is a host-plane service ([`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)): a preset selecting Code Mode against a deployment composing no runtime then holds this row pending, and `dsh-agent-presets` refuses the mount naming this id. The alternative — applying optimistically — moves the failure to the session's first request, where the operator can act on neither the preset nor the composition.
|
|
|
|
`mode` is required rather than defaulted, because a preset without this row already gets the deployment default; an omitted value would mean the row was composed for nothing.
|
|
|
|
One agent declares one presentation. A second declaration in the same composition is refused rather than merged: two answers to "which form does the model see" is a contradiction, not an override.
|
|
|
|
## Model Experience
|
|
|
|
Indirectly, through the projection it selects in `dsh-tools`: `code` presents `run_code` plus a generated SDK section, `native` presents every tool schema.
|
|
|
|
#### KV Cache effect
|
|
|
|
No direct invalidation; the presentation is fixed when the agent is composed, so its request prefix is stable for the session's life.
|
|
|
|
## Known Limitations and Deferred Work
|
|
|
|
- **The runtime stays host-plane** — a preset can select Code Mode but cannot supply the TypeScript runtime it needs; a deployment that composes none can compose no code-mode preset.
|