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

  1. Run the registration inside the real tamagotchi host, which provides runtime.tools when creating kit clients.
  2. If you control the host, implement/attach the tool registry (register({ tool, availability, execute })) to the runtime you hand to the kit.
  3. In tests, inject a fake registry: { tools: { register: async () => {}, registerToolsetPrompt: async () => {} } }.
  4. 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

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


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)