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:
resources names the external resources the tool may change. Defaults to none. wrapTool accepts the same option. See Resources.

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.

Subagents

subagent() runs another agent as a subagent of the calling tool. Return its result from the tool body:
The tool’s result is the subagent’s output, and a failed or cancelled subagent throws ToolError. Other tool calls keep running while it waits. Once every call in flight waits, the execution suspends and releases its worker. The handler reruns after they settle and replays their outcomes, so concurrent tool calls can each start a subagent. Pass { session } to continue a conversation with a subagent. Subagents started with the same session run one at a time, and each continues from the last one that completed. The session must differ from the parent’s. Derive it from the parent’s session or ID so other parents cannot reuse it:
The subagent is created with a Client, which needs a key with the executions:write scope. Pass { client }, or set REBUNO_URL and REBUNO_API_KEY. Calling subagent() outside a tool body throws an Error.

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.