Class ToolMethodDispatcher

java.lang.Object
com.tnsai.tools.method.ToolMethodDispatcher

public final class ToolMethodDispatcher extends Object
Dispatches an LLM tool call to a discovered ToolMethod.

Slim resolver: looks the name up in the ToolMethodRegistry, then delegates to ToolMethod.invoke(Map, ObjectMapper). Each variant of ToolMethod owns its own dispatch semantics:

Input guardrails

For a guarded StaticToolMethod, dispatch validates the raw argument map, materializes defaults and Jackson coercions exactly once, then validates those effective values before idempotency resolution or body invocation. An immutable, null-tolerant snapshot of the exact effective values accepted by the guardrail is used for both the idempotency key and the reflected method call. DynamicToolMethod has no annotation target, so this annotation-driven guardrail path does not apply to dynamic tools.

Idempotency protection (issue #91)

Tools whose underlying method (or declaring class) carries Idempotent are routed through IdempotencyResolver before the body runs: the resolver consults an IdempotencyStore keyed by the call's derived key, returns the cached outcome on a hit, or executes the body and caches the new outcome on a miss. Tools without @Idempotent bypass the resolver entirely (zero overhead). Only StaticToolMethod variants are subject to this discovery — DynamicToolMethods have no annotation source and always run unprotected; idempotency for dynamic tools needs a richer construction API tracked as a follow-up.

Error semantics

Since:
0.5.7 (LangChain-style tool refactor — see issue #188; slimmed in 0.7.0 when ToolMethod became a sealed interface; idempotency wiring added in 0.8.6 — issue #91)
  • Constructor Details

    • ToolMethodDispatcher

      public ToolMethodDispatcher(ToolMethodRegistry registry)
    • ToolMethodDispatcher

      public ToolMethodDispatcher(ToolMethodRegistry registry, com.fasterxml.jackson.databind.ObjectMapper mapper)
    • ToolMethodDispatcher

      public ToolMethodDispatcher(ToolMethodRegistry registry, com.fasterxml.jackson.databind.ObjectMapper mapper, IdempotencyStore idempotencyStore)
      Full constructor with an explicit IdempotencyStore. Use to wire a Redis / Postgres adapter (when those land) or to share one store instance across multiple agents in the same process.
      Parameters:
      registry - tool name → method registry (required)
      mapper - Jackson mapper for StaticToolMethod type coercion
      idempotencyStore - store consulted for Idempotent tools (required; pass InMemoryIdempotencyStore for the default per-process behaviour)
      Since:
      0.8.6 (issue #91)
  • Method Details

    • securityEnforcer

      public SecurityEnforcerHandle securityEnforcer()
      Shared provider and gate used by an owning ActionExecutor.
    • accessGate

      public AccessGate accessGate()
    • setAccessPrincipal

      public void setAccessPrincipal(AgentPrincipal principal)
      Host startup wiring; never set from request data.
    • setAccessAuthority

      public void setAccessAuthority(AuthorityScope authority)
    • configureExecution

      public void configureExecution(AgentPrincipal principal, AuthorityScope authority, AccessSubject agent)
    • authorizeTool

      public void authorizeTool(String name, Map<String,Object> arguments)
      Preflight shares exactly the dispatch gate and does not invoke a tool or cache.
    • idempotencyStore

      public IdempotencyStore idempotencyStore()
      Returns:
      the IdempotencyStore consulted for Idempotent tools. Useful for tests that need to inspect or pre-populate the cache.
      Since:
      0.8.6 (issue #91)
    • lookup

      public ToolMethod lookup(String toolName)
      Look up a tool by name without dispatching. Returns null when no such tool is registered.
      Since:
      0.7.0 (delegate so callers don't have to hold the registry separately)
    • registry

      public ToolMethodRegistry registry()
      Returns:
      the underlying ToolMethodRegistry. Use for catalog enumeration (e.g. building the LLM tool catalog from ToolMethod.parametersSchema()).
    • dispatch

      public Object dispatch(String toolName, Map<String,Object> arguments)
      Resolve, dispatch.

      Checked exceptions thrown by the tool body are wrapped in RuntimeException so the dispatch signature stays throws-free. The original checked exception is the cause.

      Parameters:
      toolName - the tool name as emitted by the LLM
      arguments - the LLM's argument map (Jackson-friendly)
      Returns:
      the tool's return value (caller serialises back to the LLM)
      Throws:
      IllegalArgumentException - for unknown tool name
      GuardrailViolationException - when a static tool's input guardrail rejects the call
      RuntimeException - wrapping any checked exception thrown by the tool body. Unchecked exceptions propagate as-is.