Skip to main content
A tool is an action your agent takes. Wrapping a function as a tool routes every call through the kernel, where it’s recorded as a tool_call step. Policy applies to it, it replays on resume, and it shows up in the audit trail.

defineTool

The returned value is callable and carries name, description, inputSchema, idempotency, and execute, so frameworks that introspect a tool object bind it unchanged. Hand tools to a framework as a plain array:

Idempotency

idempotency controls whether a tool may run again when a dispatch replays.
  • safe_to_retry (default) is for reads and anything else fine to execute again. On resume the recorded result replays, and a step that never completed runs again.
  • at_most_once is for destructive operations such as sending an email or charging a card. If a resumed dispatch finds the step already executing, the kernel fails it with reason indeterminate and the SDK throws ToolError, so your handler decides how to reconcile. A step recorded but never started is still safe, so it runs.

Denied calls

A tool denied by policy does not throw. defineTool and wrapTool catch the PolicyError and return a string instead:
The LLM sees that as the tool’s result and can pick a different path, rather than the denial crashing the run. A denied step() throws PolicyError normally, since nothing reads its result as a tool response.

Blocking work

The event loop has to stay responsive. The kernel lease is renewed by a background timer that only fires while the handler yields (see How it works). Offload CPU-bound work to a worker thread so the loop stays live.

Calling context

A tool records against the current execution. Calling one outside an active dispatch throws an Error. Active means inside a handler running under agent.serve() or agent.fetch, or inside a test context.

wrapTool

defineTool fits functions you own. wrapTool builds a Rebuno-routed tool from a name plus an invoke(args) seam. Use it for tools that aren’t plain callables, like framework tool objects or schema-only tools:
  • name is the tool id the LLM sees and the kernel sees, so put any namespace prefix directly in it.
  • inputSchema is passed through to the returned tool for frameworks that read it.
  • toResult maps the raw return before it’s recorded. Defaults to identity.
  • transformArgs maps the argument object before it’s recorded and passed to invoke, for something like null-stripping. Defaults to a shallow copy.

MCP tools

wrapMcpTool and wrapMcpTools wrap Model Context Protocol tool descriptors, so MCP tools get the same treatment as native ones.
  • Descriptors carry name, description, and inputSchema, the spec field names.
  • prefix namespaces the tool id. The LLM and the kernel see `${prefix}_${name}`, while the MCP server (via call) sees the bare name. An empty prefix uses the name as-is.
  • The result is flattened from a standard MCP CallToolResult by default, preferring structured content and otherwise joining text blocks. Override it with toResult.
  • Null arguments are stripped by default, since LLMs often fill optional fields with null and typed MCP parameters reject it.
wrapMcpTool does one descriptor; wrapMcpTools maps over a list.