moeru-ai/airi · error · Error
toolKit requires a host tool registry runtime.
Error message
toolKit requires a host tool registry runtime.
What it means
toolKit (kit.tool in plugin-sdk-tamagotchi) expects the host to supply a tool registry runtime when it instantiates the kit client; registerTool checks runtime.tools and throws this error when it is absent. The registry is what actually stores tool metadata (id, title, activation keywords/patterns, serialized parameters) and wires execute callbacks for later invocation. Without it there is nowhere to register, so the kit fails fast instead of silently dropping tools.
Solutions
- Run the registration inside the real tamagotchi host, which provides runtime.tools when creating kit clients.
- If you control the host, implement/attach the tool registry (register({ tool, availability, execute })) to the runtime you hand to the kit.
- In tests, inject a fake registry: { tools: { register: async () => {}, registerToolsetPrompt: async () => {} } }.
- Feature-detect before registering when the same extension must run on hosts with and without tool support.
Example fix
// before
const tools = await module.kits.use(toolKit)
await tools.registerTool(definition) // throws: mock runtime has no .tools
// after (test)
const tools = await module.kits.use(toolKit, {
tools: { register: vi.fn(async () => {}), registerToolsetPrompt: vi.fn(async () => {}) },
})
await tools.registerTool(definition) Defensive patterns
Strategy: validation
Validate before calling
const tools = await module.kits.use(toolKit)
// only register when the host actually provides a tool registry
if (hostRuntime?.tools) {
await tools.registerTool(definition)
} Type guard
interface ToolRuntimeLike { tools?: { register(input: unknown): Promise<void> } }
function hasToolRegistry(runtime: ToolRuntimeLike): runtime is ToolRuntimeLike & { tools: NonNullable<ToolRuntimeLike['tools']> } {
return typeof runtime.tools?.register === 'function'
} Try / catch
try {
await tools.registerTool(definition)
} catch (error) {
if (errorMessageFrom(error).includes('requires a host tool registry runtime')) {
// host without tool support: skip registration, log once
} else throw error
} Prevention
- In unit tests, always inject a stub registry: { tools: { register: async () => {}, registerToolsetPrompt: async () => {} } }.
- Feature-detect the tool capability at module setup instead of letting the first registerTool crash the extension session.
- Keep registration inside the live session window — after stop/dispose the host runtime is torn down.
When it happens
Trigger: Calling module.kits.use(toolKit) then registerTool(...) in a unit test with a minimal mock runtime, in a bare plugin-sdk host that never attached a tools registry, or in a host integration where tool support is not implemented. Also when kit clients are created for a runtime shape that was cast (as ToolKitRuntime) but not actually populated with tools.
Common situations: Extension authors running vitest against their module's registration code with a hand-rolled runtime; new hosts embedding plugin-sdk-tamagotchi piecemeal; regression after a host refactor stopped passing tools into kit creation.
Related errors
- gameletKit requires a host binding runtime.
- gameletKit requires a host gamelet orchestration runtime.
- Tamagotchi extension tool not found
- Tool input schema must be a JSON Schema object or a…
- Extension module ` ` is already registered for session .
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/1858e414914fb822.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugin-sdk-tamagotchi/src/tools/index.ts:296
*
* Expects:
* - The host provides tool registry APIs when creating the kit client
*
* Returns:
* - A client that registers LLM tools without depending on domain-specific kits
*/
export const toolKit = defineKit<ToolKitClient>({
id: 'kit.tool',
version: '1.0.0',
allowedExposePolicies: ['local-only', 'remote-observable'],
defaultExposePolicy: 'local-only',
createClient(runtime) {
const toolRuntime = runtime as ToolKitRuntime
return {
async registerTool(definition) {
if (!toolRuntime.tools) {
throw new Error('toolKit requires a host tool registry runtime.')
}
const isAvailable = definition.isAvailable
await toolRuntime.tools.register({
tool: {
id: definition.id,
title: definition.title,
description: definition.description,
activation: {
keywords: definition.activation?.keywords ?? [],
patterns: (definition.activation?.patterns ?? []).map(pattern => pattern.source),
},
parameters: await serializeToolParameters(definition.inputSchema),
},
availability: isAvailable,
execute: definition.execute,
})View on GitHub (pinned to 677329427f)