fix(system-prompt): reject a toolOrder that names an unregistered tool
Review follow-up (#196): a listed name with no registered tool was silently ignored; misconfiguration must block work instead. The check lives in the assembly — the earliest moment the registered tool set exists (tool plugins register after the service constructs) and the only universal one (cordis has no "all plugins loaded" event; registrations change at any time). assemble() is now async so the throw surfaces as a rejection rather than a synchronous escape from a Promise-returning method. Blast radius, pinned by a loop-level test: the rejection reaches the turn's outer catch — the turn closes balanced with an `error` reason, agent/error mirrors it, no step opens, no request/header is logged, no request reaches the adapter, and the agent returns to idle; every turn fails identically until the config is fixed. A boot-time validation pass was considered and rejected (recorded in the RFC). The general principle — misconfiguration fails loud, never a silent skip — is added to AGENTS.md.
This commit is contained in:
@@ -24,7 +24,7 @@ Because the package wires no logger entry, an ACP leaf has **nothing to get wron
|
||||
|---|---|---|
|
||||
| `model` | (required) | the per-session agent template the bridge creates agents from |
|
||||
| `persona` | — | the deployment persona template (may reference `{{model}}`/`{{cwd}}`), routed to `dsh-system-prompt` |
|
||||
| `toolOrder` | — | explicit model-facing tool order (a name list with one `'<unlisted-tools>'` rest entry; absent — lexicographic), routed to `dsh-system-prompt` |
|
||||
| `toolOrder` | — | explicit model-facing tool order (a name list with one `'<unlisted-tools>'` rest entry; absent — lexicographic; an unregistered name fails each turn at prompt assembly), routed to `dsh-system-prompt` |
|
||||
| `persistenceRoot` | `./.sessions` | the JSONL backend's root directory |
|
||||
|
||||
The leaf supplies the swappable backends: an LLM adapter (`llm-deepseek` for the real model, `llm-replay` for keyless snapshot replay) and a bash executor (`bash-local`).
|
||||
|
||||
@@ -25,7 +25,7 @@ The leaf `cordis.yml` supplies only the **swappable backends** — an LLM adapte
|
||||
|---|---|---|
|
||||
| `model` | (required) | the pre-created `main` agent's model |
|
||||
| `persona` | — | the deployment persona template (may reference `{{model}}`), routed to `dsh-system-prompt` |
|
||||
| `toolOrder` | — | explicit model-facing tool order (a name list with one `'<unlisted-tools>'` rest entry; absent — lexicographic), routed to `dsh-system-prompt` |
|
||||
| `toolOrder` | — | explicit model-facing tool order (a name list with one `'<unlisted-tools>'` rest entry; absent — lexicographic; an unregistered name fails each turn at prompt assembly), routed to `dsh-system-prompt` |
|
||||
| `persistenceRoot` | `./.sessions` | the JSONL backend's root directory |
|
||||
| `welcome` | `ready.` | the stdin-chat banner |
|
||||
| `resumeSessionId` | — | resume a persisted session id instead of starting fresh (sourced from an env var in the leaf) |
|
||||
|
||||
Reference in New Issue
Block a user