Tools¶
AgentTool¶
tau_agent_core.tools.base.AgentTool
Validated tool wrapper used by the agent loop.
Reference: SUBPHASE-0.0.md, "2. Tool Definitions" section.
Wraps a ToolDefinition with validated name alias. The agent loop works with AgentTool (validated, wrapped), while extensions register with ToolDefinition (raw, unvalidated).
definition is annotated with the tau-llm BASE class deliberately, so every
member of the hierarchy fits: the runtime :class:ToolDefinition, an
:class:ExtensionToolDefinition, and a bare
:class:tau_llm.tools.ToolDefinition straight out of define_tool().
Narrowing it to the subclass is what made AgentTool(definition=define_tool(
...)) raise "Input should be a valid dictionary or instance of
ToolDefinition" against a value of an identically-shaped class.
definition¶
tau_agent_core.tools.base.AgentTool.definition: LlmToolDefinition
The underlying ToolDefinition
description¶
tau_agent_core.tools.base.AgentTool.description: str
Alias for definition.description.
execute¶
tau_agent_core.tools.base.AgentTool.execute: Callable[..., Any]
Alias for definition.execute.
execution_mode¶
tau_agent_core.tools.base.AgentTool.execution_mode: Literal['sequential', 'parallel']
Alias for definition.execution_mode.
name¶
tau_agent_core.tools.base.AgentTool.name: str
Alias for definition.name.
parameters¶
tau_agent_core.tools.base.AgentTool.parameters: dict[str, Any]
Alias for definition.parameters.
AgentToolResult¶
tau_agent_core.tools.base.AgentToolResult
Result from a single tool execution.
content¶
tau_agent_core.tools.base.AgentToolResult.content: list[dict[str, Any]]
List of content blocks (mirrors Message content)
details¶
tau_agent_core.tools.base.AgentToolResult.details: dict[str, Any] | None
Structured facts about the execution that are NOT part of what
the model reads — a path, a line range, a match count, a diff. Every
built-in tool sets it; it rides the toolResult message and the
tool_execution_end event so a head can render more than the text
block. None means the tool declared none, never "dropped".
error_message¶
tau_agent_core.tools.base.AgentToolResult.error_message: str | None
Error description (if is_error=True)
from_error¶
from_error(tool_name: str, error_message: str, tool_call_id: str | None = None) -> 'AgentToolResult'
tau_agent_core.tools.base.AgentToolResult.from_error
Create a failure result.
Parameters
tool_name: str— (no description)error_message: str— (no description)tool_call_id: str | None = None— (no description)
is_error¶
tau_agent_core.tools.base.AgentToolResult.is_error: bool
Whether the execution failed
terminate¶
tau_agent_core.tools.base.AgentToolResult.terminate: bool
Whether the agent loop should terminate after this tool
tool_call_id¶
tau_agent_core.tools.base.AgentToolResult.tool_call_id: str | None
ID of the tool call
tool_name¶
tau_agent_core.tools.base.AgentToolResult.tool_name: str
Name of the executed tool
ExtensionToolDefinition¶
tau_agent_core.tools.base.ExtensionToolDefinition
A tool an extension registered, as the registry holds it.
Third and last member of the hierarchy. It used to be a bare dict passed
to api.register_tool() and stored as a dict, which meant the one shape
crossing the extension boundary was the one shape with no schema — nothing to
validate against, nothing to generate documentation from, and four separate
defn["key"] / defn.get("key", default) readers each deciding for
themselves what was required. A missing key surfaced as a KeyError from
inside the agent loop, one turn after the mistake.
api.register_tool() still accepts the plain dict, so pi parity and every
existing extension are unaffected; the dict is validated into this model at
the boundary instead of being carried raw.
Two differences from the parent, both real rather than cosmetic:
source — who registered it, for the /extensions surface. Default
"built-in", matching what :meth:ExtensionRegistry.get_all_tools reported
before; ExtensionAPI.register_tool sets "extension". Accepted under
its historical _source spelling too, because that is the key extensions
and tests already write.
execute — the EXTENSION signature, execute(tool_call_id, params, signal,
on_update, ctx), five arguments with the bound ExtensionContext last. The
parent's is the loop's four-argument form. Nothing here can enforce that
difference — both are Callable and a decorated or *args wrapper has no
inspectable arity — so AgentSession._resolve_extension_tools adapts one to
the other, and this docstring is where the difference is stated.
model_config¶
tau_agent_core.tools.base.ExtensionToolDefinition.model_config
No description. This object is marked but undocumented.
source¶
tau_agent_core.tools.base.ExtensionToolDefinition.source: str
No description. This object is marked but undocumented.
ToolBatchResult¶
tau_agent_core.tools.base.ToolBatchResult
Result from a batch of tool executions.
Returned by the agent loop after executing a batch of tool calls.
messages¶
tau_agent_core.tools.base.ToolBatchResult.messages: list[dict[str, Any]]
List of messages produced by the tool executions
terminate¶
tau_agent_core.tools.base.ToolBatchResult.terminate: bool
Whether the agent loop should terminate
tool_results¶
tau_agent_core.tools.base.ToolBatchResult.tool_results: list[AgentToolResult]
Individual tool execution results
tau_agent_core.tools.base.ToolDefinition¶
tau_agent_core.tools.base.ToolDefinition
The runtime tool definition: :class:tau_llm.tools.ToolDefinition plus
name-based identity.
It SUBCLASSES the tau-llm model rather than restating its fields. It used to
restate them — eight fields duplicated verbatim in two packages — and the copy
was not harmless: define_tool() returns the tau-llm class, and pydantic
compares by class identity, so the value τ's own public builder produced could
not be handed to :class:AgentTool. Two identical shapes that refuse each
other is a worse failure than one shape, because it looks like it should work.
pi has the same layering and expresses it the same way -- AgentTool extends
Tool (packages/agent/src/types.ts:366) over packages/ai's Tool.
τ had copied the fields instead of the relationship.
Adds only identity: two definitions with one name ARE the same tool, because the name is what the model calls and what the registry keys on. Field-by-field equality (pydantic's default, which the base keeps) would call two wrappers around the same tool different whenever a closure differs.
Reference: SUBPHASE-0.0.md, "2. Tool Definitions" section.
tau_llm.tools.ToolDefinition¶
tau_llm.tools.ToolDefinition
Tool definition for the LLM API.
Reference: SUBPHASE-0.0.md, "2. Tool Definitions" section.
description¶
tau_llm.tools.ToolDefinition.description: str
No description. This object is marked but undocumented.
execute¶
tau_llm.tools.ToolDefinition.execute: ToolExecute
No description. This object is marked but undocumented.
execution_mode¶
tau_llm.tools.ToolDefinition.execution_mode: Literal['sequential', 'parallel']
No description. This object is marked but undocumented.
label¶
tau_llm.tools.ToolDefinition.label: str
No description. This object is marked but undocumented.
name¶
tau_llm.tools.ToolDefinition.name: str
No description. This object is marked but undocumented.
parameters¶
tau_llm.tools.ToolDefinition.parameters: dict[str, Any]
No description. This object is marked but undocumented.
prompt_guidelines¶
tau_llm.tools.ToolDefinition.prompt_guidelines: list[str] | None
No description. This object is marked but undocumented.
prompt_snippet¶
tau_llm.tools.ToolDefinition.prompt_snippet: str | None
No description. This object is marked but undocumented.
ToolSpec¶
tau_llm.tools.ToolSpec
What a provider needs in order to put a tool on the wire.
The three attributes _convert_tools_to_openai actually reads, and nothing
else. This exists because the annotation there used to say
list[ToolDefinition] and that was false at runtime: the agent loop
passes tau_agent_core.tools.base.AgentTool instances, which are not
ToolDefinition at all — they wrap one and re-expose these three as
properties. The call worked by duck typing and the type checker could never
see it, because tau_llm does not import tau_agent_core (the dependency
arrow points the other way, correctly).
A Protocol states the real contract in the layer that owns it: any object with
these three members may be sent, whichever package built it. Declared as
read-only properties so an object exposing them as properties — which
AgentTool does — satisfies it.
description¶
tau_llm.tools.ToolSpec.description: str
No description. This object is marked but undocumented.
name¶
tau_llm.tools.ToolSpec.name: str
No description. This object is marked but undocumented.
parameters¶
tau_llm.tools.ToolSpec.parameters: dict[str, Any]
No description. This object is marked but undocumented.
define_tool¶
define_tool(definition: Mapping[str, Any] | None = None, **fields: Any) -> ToolDefinition
tau_llm.tools.define_tool
Build a validated :class:ToolDefinition.
The keyword form is the one to reach for::
word_count = define_tool(
name="word_count",
label="Word count",
description="Count the words in a string.",
parameters={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
execute=lambda text: {"words": len(text.split())},
)
A single mapping may also be passed positionally —
define_tool({"name": ..., ...}) — which is the shape this function
originally advertised. Passing both forms, or neither, is a caller error.
NOTE: this is not the shape tau_agent_core's
ExtensionAPI.register_tool() takes. That one is a plain dict whose
execute has the five-argument extension signature
execute(tool_call_id, params, signal, on_update, ctx), and it defaults a
missing label to name. The two are separate contracts on purpose;
do not feed the result of this function to register_tool.
Reference: SUBPHASE-0.0.md, "2. Tool Definitions" section.
Parameters
definition: Mapping[str, Any] | None = None— (no description)**fields: Any— (no description)
Raises
TypeError— if both forms or neither form is used, if the positional argument is not a mapping, or if a field is present with the wrong Python type (executenot callable,parametersnot a dict).ValueError— if a required field is missing or empty, if an unknown field is passed, ifnameis not wire-safe, or ifparametersis not a JSON Schema object schema this package can validate against.
validate_tool_arguments¶
validate_tool_arguments(tool: Any, tool_call: Any) -> dict[str, Any]
tau_llm.tools.validate_tool_arguments
Validate tool call arguments against tool schema.
Uses the tool's JSON Schema (parameters field) to validate the arguments from a ToolCall. Raises ValueError if validation fails.
Reference: SUBPHASE-0.0.md, "2. Tool Definitions" section.
Parameters
tool: Any— Tool with a 'parameters' attribute (dict) and optionally 'name'.tool_call: Any— ToolCall with an 'arguments' attribute (dict).
Returns
Validated parameter dict.
Raises
ValueError— If arguments don't match the tool's JSON schema.