fix(tools,client): chain-mode resolution and a live preset label

modeFor read only the exact scope's layer, so a `code`-preset session
advertised the native catalog: the mode is declared on the preset's STANDING
scope, and the agent only parents to it. Nearest scope wins along the chain —
the mode decides what the model SEES, which is the class of fact the chain
inherits. Caught live (the model politely computed with bash and said
run_code was not in its list); the chain test pins it.

The client half of the label fix: the create echo and the session-added
frame's agentPreset now reach the session list (newest wins in the upsert —
every producer of the field reports the CURRENT composition), and a confirmed
blank-session switch publishes through the new ISessions.noteAgentPreset, so
the header label moves with the composition instead of waiting for a reload.
This commit is contained in:
Yichen Jiang
2026-08-08 20:19:00 +08:00
parent 3926e95c61
commit 66e9b01fbd
8 changed files with 81 additions and 2 deletions
+10 -1
View File
@@ -835,7 +835,16 @@ export class ToolRegistry extends Service {
* @returns the resolved presentation mode.
*/
private modeFor(scope?: ScopeKey): ToolPresentationMode {
return this.layers.peek(scope)?.mode ?? this.defaultMode
// Nearest scope wins along the chain: a preset's standing declaration
// covers every agent parented under it, and an agent's own (were one ever
// declared) would override its preset's. The mode decides what the model
// SEES, which is exactly the class of fact the chain inherits.
const layers = this.layers.chainLayers(scope)
for (let index = layers.length - 1; index >= 0; index -= 1) {
const mode = layers[index]?.mode
if (mode !== undefined) return mode
}
return this.defaultMode
}
/**