| // v0.20 rendering base — thin forwarding hook (plan v0.20-rendering-base.md §5.4). | |
| // | |
| // createRenderingLoopHook(bus) returns an AfterToolExecutionHook that does | |
| // exactly one thing: forward every ToolTurn to the bus in order, then return | |
| // undefined. It knows no tool names, does no matching/extraction/rendering, | |
| // and never intervenes in control flow — `return undefined` is the LoopHooks | |
| // contract's "not intervening" signal (callHook then uses default behavior, | |
| // see src/im/loop-hooks.ts). | |
| // | |
| // All intelligence lives behind the bus: matching/extraction run inside | |
| // RenderRules registered on the RenderingSignalBus (signal-bus.ts). This file | |
| // stays one line of forwarding per turn — deliberately, per plan §5.4 | |
| // "没有第二行逻辑". | |
| // | |
| // toolName note (plan D3a): ToolTurn.toolName is optional. bus.emit's | |
| // parameter is `string`, so this hook forwards `t.toolName ?? ''` — a pure | |
| // type bridge, not logic: no rule matches '' so nothing is emitted, which is | |
| // exactly the "toolName undefined → match all false → silent" behavior. | |
| import type { RenderingSignalBus } from '../signal-bus.js' | |
| import type { AfterToolExecutionHook } from '../../im/loop-hooks.js' | |
| export const createRenderingLoopHook = (bus: RenderingSignalBus): AfterToolExecutionHook => | |
| async ({ toolResults }) => { | |
| for (const t of toolResults) await bus.emit(t.toolName ?? '', t) | |
| return undefined | |
| } | |