`ui-question`'s node half called `ctx.tools.register` on the host context. `ScopedLayers.merge()` combines the global layer with the agent's exact-scope layer, and an unscoped registration lands in the global one — so the tool reached every agent no matter which preset composed it. `core-web`, sold as a two-tool benchmark surface, really presented three. Rendering a question is a host UI capability; having the tool is an agent capability, and only a preset decides that. The node half is now empty and the `tool-ask-user` row moved into the preset that wants it. The TUI keeps its own row, having no presets. The composition tests now assert the global tool layer is EMPTY, which is the invariant that would have caught this: any tool outside a preset reaches every agent. The browser lane's composition, seeded-history, and hermetic-skill assertions address their registries through a composed agent for the same reason — those services are per session now, and the host cannot resolve an `isolate` realm by name.
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { Context } from 'cordis'
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
|
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
|
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
|
import { apply } from '../src/index.ts'
|
|
|
|
let ctx: Context | undefined
|
|
|
|
afterEach(async () => {
|
|
await ctx?.fiber.dispose()
|
|
ctx = undefined
|
|
})
|
|
|
|
describe('ui-question node plugin', () => {
|
|
it('mounts no model-facing tool', async () => {
|
|
ctx = new Context()
|
|
await ctx.plugin(SystemPrompt)
|
|
await ctx.plugin(ToolRegistry)
|
|
await ctx.plugin(UserInteractionService)
|
|
|
|
await ctx.plugin({ apply }).await()
|
|
|
|
// Selecting the Web question FEATURE must not hand every agent the tool.
|
|
// `ctx.tools.register` on an unscoped host context files into the global
|
|
// layer, which merges into every agent's view regardless of the preset
|
|
// that composed it — so a two-tool benchmark preset would really present
|
|
// three. The `tool-ask-user` row belongs to the presets that want it.
|
|
expect(ctx.tools.get('ask_user_question')).toBeUndefined()
|
|
})
|
|
})
|