Annotation Interface Tool
Methods annotated with @Tool on any POJO are discovered by the
framework via reflection when the containing object instance is registered
with a Role through Role.tools(). Each @Tool method becomes
a separate logical tool exposed to the LLM with its own JSON Schema derived
from the method signature plus ToolParam annotations on its
parameters.
Usage
public class CsvTools {
@Tool(description = "Extract specific columns from a CSV file at the given path")
public List<Map<String, String>> csvColumns(
@ToolParam(description = "Absolute file path") String path,
@ToolParam(description = "Column names to extract") List<String> columns
) throws IOException {
// real implementation — body actually runs
}
}
Then in a Role:
@Override
public List<Object> tools() {
return List.of(new CsvTools(), new JsonTools(), new MyCustomTool());
}
Convention
name()defaults to the method name when left empty.description()is required — the LLM uses this to decide when to invoke the tool. Missing or thin descriptions degrade tool-call quality measurably.- The method body executes when the LLM emits a tool call; the return value is JSON-serialised and fed back into the model.
timeoutMs()can bound an individual call. The default (0) adds no dispatcher deadline and preserves the enclosing agent's timeout policy.- Cross-cutting annotations (
Traced,Metered,Fallback,InputGuardrail,OutputGuardrail) can be applied to the same method and are honoured by the tool dispatcher.
- Since:
- 0.5.7 (LangChain-style tool refactor — see issue #188)
- See Also:
-
Required Element Summary
Required ElementsModifier and TypeRequired ElementDescriptionHuman-readable description that appears in the LLM tool catalog. -
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionSame runtime access policy as ActionSpec; not a side-effect hint.Declares whether runtime dispatch requires an active, stableIdempotentpolicy for this tool (TNS-299).booleanWhether this tool's effect is idempotent (calling twice with the same arguments has the same observable effect as calling once).String[]Optional keywords for fuzzy lookup inside the framework registry.Tool name surfaced to the LLM.booleanWhether this tool's invocation should be gated through the agent's configuredToolCallFilterfor explicit per-call approval.Classification of this tool's observable effect (TNS-299).intMaximum wall-clock time for one invocation of this tool, in milliseconds.
-
Element Details
-
execution
ExecutionPolicy[] executionSame runtime access policy as ActionSpec; not a side-effect hint.- Default:
{}
-
name
String nameTool name surfaced to the LLM. Defaults to the method name if left empty — typical case is to leave it empty and let reflection use the Java method name.- Returns:
- the tool name (empty means "use method name")
- Default:
""
-
description
String descriptionHuman-readable description that appears in the LLM tool catalog. Required — the LLM relies on this to decide when to call the tool. Be specific about inputs, outputs, side effects, and when NOT to use the tool.- Returns:
- the tool description (must be non-empty)
-
keywords
String[] keywordsOptional keywords for fuzzy lookup inside the framework registry. Not surfaced to the LLM — purely a discovery aid for tools and tests.- Returns:
- keyword array (empty by default)
- Default:
{}
-
timeoutMs
int timeoutMsMaximum wall-clock time for one invocation of this tool, in milliseconds. A positive value is enforced by the POJO tool dispatcher; expiry raises a retryableToolTimeoutException. The timed-out invocation is interrupted on a best-effort basis and may continue if its code ignores interruption.The default
0adds no per-tool deadline, preserving existing behavior and any timeout policy applied by the enclosing agent.- Returns:
- the per-invocation deadline in milliseconds, or
0to use no additional dispatcher deadline - Since:
- 0.14.0 (TAN-2958)
- Default:
0
-
idempotent
boolean idempotentWhether this tool's effect is idempotent (calling twice with the same arguments has the same observable effect as calling once). Hint for the framework's retry / fallback layer; idempotent tools are eligible for automatic retry on transient failures.- Returns:
- true if idempotent
- Default:
false
-
requiresConfirmation
boolean requiresConfirmationWhether this tool's invocation should be gated through the agent's configuredToolCallFilterfor explicit per-call approval. Marktruefor irreversible or financially material operations (payment execution, deleting a remote resource, posting to a public channel, anything classifiable asHIGHorCRITICALblast radius).Orthogonal to
idempotent(): idempotency is a retry-layer hint, confirmation is a runtime safety gate. IssueAGENT-V006(theToolApprovalValidator) warns at build time when a tool declaresrequiresConfirmation = truebut the agent has noToolCallFilterwired throughAgentBuilder.toolCallFilter(...)— without one, the runtime will execute the call unattended.- Returns:
- true if the call should require explicit approval via the configured tool-call filter
- Since:
- 0.8.5 (issue #234 — AGENT-V006 prerequisite)
- Default:
false
-
sideEffect
SideEffect sideEffectClassification of this tool's observable effect (TNS-299).ToolMethodRegistryretains this metadata for the runtime dispatcher and logs a registration-time warning whenSideEffect.EXTERNALtools omit anidempotencyHint().Orthogonal to
idempotent():idempotentis a retry-layer hint about call safety; this enum classifies where the effect lives (in-process / disk / external API).- Returns:
- the effect classification — defaults to
SideEffect.NONEso existing tools retain their current behaviour - Since:
- 0.10.0 (TNS-299)
- Default:
NONE
-
idempotencyHint
IdempotencyHint idempotencyHintDeclares whether runtime dispatch requires an active, stableIdempotentpolicy for this tool (TNS-299).IdempotencyHint.NONE— no tracking; default for pure / read-only tools.IdempotencyHint.OPTIONAL— dispatch unguarded unless an independent@Idempotentpolicy is present.IdempotencyHint.REQUIRED— refuse to dispatch unless@Idempotentsupplies a stableHASH_INPUTorEXPLICITkey strategy and a positive cache TTL. Reserve for tools where a duplicate would cause real damage (payments, public posts, deletes). Durability of the record is the caller's responsibility: the default store is in-memory and per-process — wire a durable store throughAgentBuilder.idempotencyStore(...)for restart-safe protection (TAN-5933).
- Returns:
- the hint — defaults to
IdempotencyHint.NONEso existing tools retain their current behaviour - Since:
- 0.10.0 (TNS-299)
- Default:
NONE
-