Nous.Tool.ContextUpdate (nous v0.13.3)

View Source

Structured context updates from tools.

When tools need to update the agent's context (e.g., storing data for later use), they can return a ContextUpdate along with their result. This provides a clear, explicit way to modify context state without magic keys.

Example

defmodule MyTools do
  alias Nous.Tool.ContextUpdate

  def add_todo(ctx, %{"text" => text}) do
    todo = %{id: generate_id(), text: text, done: false}
    todos = [todo | ctx.deps[:todos] || []]

    {:ok, %{success: true, todo: todo},
     ContextUpdate.new() |> ContextUpdate.set(:todos, todos)}
  end

  def increment_counter(ctx, _args) do
    count = (ctx.deps[:counter] || 0) + 1

    {:ok, %{count: count},
     ContextUpdate.new() |> ContextUpdate.set(:counter, count)}
  end

  def add_note(ctx, %{"note" => note}) do
    {:ok, %{added: note},
     ContextUpdate.new() |> ContextUpdate.append(:notes, note)}
  end
end

Operations

  • set/3 - Replace a key's value
  • merge/3 - Deep merge a map into an existing map key
  • append/3 - Append an item to a list key
  • delete/2 - Remove a key

Integration

The AgentRunner applies these updates to the context deps after tool execution:

case execute_tool(tool, args, ctx) do
  {:ok, result, %ContextUpdate{} = update} ->
    new_ctx = ContextUpdate.apply(update, ctx)
    {:ok, result, new_ctx}

  {:ok, result} ->
    {:ok, result, ctx}
end

Summary

Functions

Append an item to a list key in context deps.

Apply all operations to a context, returning the updated context.

Apply all operations to a RunContext, returning the updated context.

Delete a key from context deps.

Check if this ContextUpdate has any operations.

Deep merge a map into an existing map key in context deps.

Create a new empty ContextUpdate.

Get the list of operations in this update.

Set a key to a value in the context deps.

Types

operation()

@type operation() ::
  {:set, atom(), any()}
  | {:merge, atom(), map()}
  | {:append, atom(), any()}
  | {:delete, atom()}

t()

@type t() :: %Nous.Tool.ContextUpdate{operations: [operation()]}

Functions

append(update, key, item)

@spec append(t(), atom(), any()) :: t()

Append an item to a list key in context deps.

If the key doesn't exist or is nil, creates a new list with the item.

Example

ContextUpdate.new()
|> ContextUpdate.append(:history, %{action: "search", query: "elixir"})

apply(context_update, ctx)

Apply all operations to a context, returning the updated context.

Operations are applied in order.

Example

update = ContextUpdate.new()
|> ContextUpdate.set(:key, "value")
|> ContextUpdate.append(:list, "item")

new_ctx = ContextUpdate.apply(update, ctx)

apply_to_run_context(context_update, ctx)

@spec apply_to_run_context(t(), Nous.RunContext.t()) :: Nous.RunContext.t()

Apply all operations to a RunContext, returning the updated context.

For backwards compatibility with tools using RunContext.

delete(update, key)

@spec delete(t(), atom()) :: t()

Delete a key from context deps.

Example

ContextUpdate.new()
|> ContextUpdate.delete(:temp_data)

empty?(context_update)

@spec empty?(t()) :: boolean()

Check if this ContextUpdate has any operations.

merge(update, key, map)

@spec merge(t(), atom(), map()) :: t()

Deep merge a map into an existing map key in context deps.

If the key doesn't exist, it will be created with the map value.

Example

ContextUpdate.new()
|> ContextUpdate.merge(:settings, %{theme: "dark"})

new()

@spec new() :: t()

Create a new empty ContextUpdate.

Example

update = ContextUpdate.new()
|> ContextUpdate.set(:key, "value")

operations(context_update)

@spec operations(t()) :: [operation()]

Get the list of operations in this update.

set(update, key, value)

@spec set(t(), atom(), any()) :: t()

Set a key to a value in the context deps.

Replaces any existing value for the key.

Example

ContextUpdate.new()
|> ContextUpdate.set(:user_id, 123)