fix(preset): keep the token meter host-plane and name unjoined agents
Moving the agent plane behind presets left two readers on the wrong side of the host/agent line. `dsh-token-meter` was disabled on the host and mounted inside each preset's `compaction` realm, but its three projection units register into the process-wide `sessionProjections` table. A unit registered from one preset answers for every session, so whether a `minimal` session showed a context meter depended on whether some other session had mounted `standard` since boot, and a process that only ever ran `minimal` showed none. The meter takes no configuration, keys every fold by Session, and registers no tool or prompt section, so it returns to the host composition and leaves the presets' `isolate` map; the realm and `compact-basic` stay, because what a preset chooses is whether its agent compacts, not whether its tokens are counted. Nothing named an agent that joined no preset. The join is a scope-parent link, and without it the tools, prompt-section, and skill views resolve the empty global layer: the agent publishes, the turn runs, and the model receives nothing. `AgentPresets` now logs one warning per such agent while a roster is configured, and the invariant companion fails outright — at `system-prompt/assemble` rather than at publication, because an unjoined agent is legal until it addresses a model and `recompose` binds exactly such an agent. The warning stays advisory: a synchronous `agent/created` throw vetoes publication, and the ACP bridge, SDK server, and headless bundle all create an unjoined agent today. Three limits are recorded rather than fixed: projection key presence is not a per-session capability signal, a superseded standing generation is never reclaimed, and a `cordis_mount` temporary plugin belongs to the composition rather than the session that mounted it. Fixes #2203
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
* The tool registry itself stays on the host plane — the agent loop's
|
||||
* scheduler, the API proxy's presenters, and every tool plugin are all its
|
||||
* consumers, so it cannot move into a preset. What a preset CAN own is the
|
||||
* presentation: `ctx.tools.presentAs()` declares it for the mounting agent
|
||||
* alone, so a Code Mode agent runs beside native ones in one process.
|
||||
* presentation: `ctx.tools.presentAs()` declares it for the mounting SCOPE,
|
||||
* which is the preset's standing mount, so the declaration covers every agent
|
||||
* joined to that preset and a Code Mode preset runs beside native ones in one
|
||||
* process. One row per composition, not one per session.
|
||||
*
|
||||
* A code mode needs a TypeScript code runtime, which is a host-plane service
|
||||
* ([`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)).
|
||||
@@ -50,8 +52,8 @@ export const Config: z<Config> = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Declare this agent's tool presentation.
|
||||
* @param ctx - the mounting agent's scope context.
|
||||
* Declare the tool presentation for every agent this composition covers.
|
||||
* @param ctx - the mounting composition's scope context (a preset's standing scope).
|
||||
* @param config - the selected presentation.
|
||||
*/
|
||||
export function apply(ctx: Context, config: Config): void {
|
||||
|
||||
Reference in New Issue
Block a user