moeru-ai/airi · warning

[llm] Auto-disabling tools for "${key}" due to tool-related

Error message

[llm] Auto-disabling tools for "${key}" due to tool-related error

What it means

The chat LLM streaming wrapper caught an error from the provider stream that core-agent's isToolRelatedError() matched (a provider 4xx complaining about the tools/tool_choice parameters, e.g. 'tools is not supported' or an unknown tool-schema error). It then permanently records toolsCompatibility[key] = false for that provider so subsequent requests omit tools, and the failure is not rethrown for this class.

Source

Thrown at packages/stage-ui/src/stores/ai/chat-llm/llm.ts:41

    const runStream = () => coreStreamFrom({
      model,
      chatProvider,
      messages,
      options: {
        ...streamOptions,
        toolsCompatibility: toolsCompatibility.value,
        contentArrayCompatibility: contentArrayCompatibility.value,
      },
      builtinToolsResolver,
    })

    try {
      await runStream()
    }
    catch (err) {
      if (isToolRelatedError(err)) {
        console.warn(`[llm] Auto-disabling tools for "${key}" due to tool-related error`)
        toolsCompatibility.value.set(key, false)
      }
      // NOTICE:
      // Auto-degrade content-part arrays to plain strings on the next attempt
      // when the provider returned the Rust/serde-style "expected a string"
      // 400. We retry once inline so the user's failing turn recovers without
      // requiring them to resend; subsequent calls reuse the cached degrade.
      // See: https://github.com/moeru-ai/airi/issues/1500
      if (isContentArrayRelatedError(err) && contentArrayCompatibility.value.get(key) !== false) {
        console.warn(`[llm] Auto-disabling content-part arrays for "${key}" and retrying once`)
        contentArrayCompatibility.value.set(key, false)
        await runStream()
        return
      }
      throw err
    }
  }

View on GitHub (pinned to 677329427f)

Solutions

  1. Verify the provider/model actually supports function/tool calling; pick a tools-capable model if you need tools.
  2. Update the local OpenAI-compatible server to a build that implements the tools parameter.
  3. Clear the persisted/remembered toolsCompatibility entry after fixing the server so tools are retried.
  4. If tools are optional, accept the degraded mode — chat continues without tool use for that provider.
Defensive patterns

Strategy: fallback

Try / catch

try {
  await runStream()
}
catch (err) {
  if (isToolRelatedError(err)) {
    toolsCompatibility.value.set(key, false)
    // next turn omits tools; current turn must be re-sent or handled by caller
  }
}

Prevention

When it happens

Trigger: Streaming a chat turn with builtin tools against a provider/endpoint that does not implement the tools API — the provider returns a 400/422 naming 'tools', 'tool_choice', or function-calling; the wrapper downgrades and future calls for that key send no tools.

Common situations: OpenAI-compatible servers (llama.cpp, vLLM, LM Studio, Ollama builds) with partial or absent function-calling support; a proxy stripping tool fields then erroring; older model versions without tool support; wrong baseURL pointing at a chat-completions-only shim.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/fd27b3affaf734e4. Report an issue: GitHub.