Nous.RunContext (nous v0.17.1)

Copy Markdown View Source

Context passed to tools and dynamic prompts during agent execution.

The RunContext provides access to:

  • Dependencies (deps) - User-provided data like database connections
  • Retry count - Number of times this tool has been retried
  • Usage information - Token and request counts so far

Example with Tool

defmodule MyTools do
  def search_database(ctx, query) do
    # Access database from dependencies
    ctx.deps.database
    |> Database.search(query)
    |> format_results()
  end
end

# Pass deps when running agent
deps = %{database: MyApp.Database}
{:ok, result} = Agent.run(agent, "Search for users", deps: deps)

The struct itself is plain data — build one directly to call a tool outside the agent loop, or to assert on what a tool would see:

iex> ctx = RunContext.new(%{database: MyApp.Database, api_key: "secret"})
iex> ctx.deps.api_key
"secret"
iex> {ctx.retry, ctx.approval_gated?, ctx.usage.total_tokens}
{0, false, 0}

Summary

Types

Decision returned by an approval handler for a single tool call.

Called before an approval-gated tool runs. Receives the same %{name:, id:, arguments:, tool:} shape the agent runner passes its handler, so one handler works for both entry points (id is nil outside the runner, which is the only place a provider tool-call id exists).

t()

Functions

Create a new run context with dependencies.

Types

approval_decision()

@type approval_decision() :: :approve | :reject | {:edit, map()}

Decision returned by an approval handler for a single tool call.

approval_handler()

@type approval_handler() :: (map() -> approval_decision())

Called before an approval-gated tool runs. Receives the same %{name:, id:, arguments:, tool:} shape the agent runner passes its handler, so one handler works for both entry points (id is nil outside the runner, which is the only place a provider tool-call id exists).

t()

@type t() :: t(any())

t(deps)

@type t(deps) :: %Nous.RunContext{
  approval_gated?: boolean(),
  approval_handler: approval_handler() | nil,
  deps: deps,
  retry: non_neg_integer(),
  sandbox: Nous.Sandbox.Policy.t() | nil,
  usage: Nous.Usage.t()
}

Functions

new(deps, opts \\ [])

@spec new(deps :: any(), opts :: keyword()) :: t(any())

Create a new run context with dependencies.

Options

  • :retry - Current retry count (default: 0)
  • :usage - Current usage information (default: empty Usage)
  • :approval_handler - Called before a tool with requires_approval: true runs. Without one, such tools are rejected (see Nous.ToolExecutor).
  • :approval_gated? - Set by a caller that has ALREADY run its own approval pipeline (the agent runner does), so Nous.ToolExecutor does not prompt a second time. Defaults to false — i.e. ungated.
  • :sandbox - Optional Nous.Sandbox.Policy for this session. Tools that spawn subprocesses pass the context to Nous.Sandbox.Policy.resolve/2, which treats this field as the session-level override: it wins over deps[:workspace_root] and over the :sandbox_mode application setting. nil (the default) means unset — resolution falls back to app config.

Examples

iex> ctx = RunContext.new(%{database: MyApp.Database, api_key: "secret"})
iex> ctx.deps.database
MyApp.Database

An approval-gated context carries the handler the tool executor consults before running a requires_approval: true tool:

iex> handler = fn %{name: name} -> if name == "delete_all", do: :reject, else: :approve end
iex> ctx = RunContext.new(%{}, retry: 2, approval_handler: handler)
iex> {ctx.retry, ctx.approval_handler.(%{name: "delete_all"}), ctx.approval_gated?}
{2, :reject, false}