Nous.ToolExecutor (nous v0.16.4)
View SourceExecutes tool functions with retry logic, timeout handling, and error handling.
The ToolExecutor is responsible for:
- Calling tool functions with the correct arguments
- Managing the RunContext
- Implementing retry logic on failures
- Handling timeouts
- Processing ContextUpdate returns
- Logging execution
Telemetry & sensitive data
The [:nous, :tool, :execute, :exception] event carries the raw :reason
(the exception/exit term) and full :stacktrace in its metadata so local
handlers can debug failures. A tool that fails while holding a secret (an API
key in an error message, a token in a struct field) can therefore surface
that secret in the event. This is safe for in-process handlers but any
subscriber that forwards these events off-box (Sentry, Honeycomb, log
shippers) MUST scrub :reason/:stacktrace first. The emitter intentionally
does not redact, to preserve debuggability for trusted handlers.
Summary
Functions
Execute a tool with the given arguments.
Types
@type execute_result() :: {:ok, any()} | {:ok, any(), Nous.Tool.ContextUpdate.t()} | {:error, term()}
Functions
@spec execute(Nous.Tool.t(), map(), Nous.RunContext.t()) :: execute_result()
Execute a tool with the given arguments.
Automatically handles:
- Passing RunContext to tools that need it
- Retrying on failure (up to tool.retries times)
- Timeout enforcement (if tool.timeout is set)
- ContextUpdate extraction from tool results
- Error wrapping and logging
Return Values
{:ok, result}- Tool executed successfully{:ok, result, context_update}- Tool executed and wants to update context{:error, reason}- Tool failed after all retries
Examples
ctx = RunContext.new(%{database: MyApp.DB})
arguments = %{"query" => "elixir"}
case ToolExecutor.execute(tool, arguments, ctx) do
{:ok, result} ->
# Tool executed successfully
result
{:ok, result, context_update} ->
# Tool executed and wants to update context
new_ctx = ContextUpdate.apply_to_run_context(context_update, ctx)
{result, new_ctx}
{:error, reason} ->
# Tool failed after all retries
handle_error(reason)
end