Skip to content

Let tools use the State

A tool can read or change the run it is part of.

from alpineagents import Agent, State, tool


@tool
def remember(key: str, value: str, state: State) -> str:
    """Save a note for later in this run"""
    with state.edit_extra_data() as data:
        data.setdefault("notes", {})[key] = value
    return f"Saved {key}"


@tool
def recall(key: str, state: State) -> str:
    """Read a note saved with remember"""
    return state.extra_data.get("notes", {}).get(key, f"No note named {key}")


agent = Agent(model="claude-sonnet-5", tools=[remember, recall])
print(agent.run("Remember that the deploy key is in vault, then tell me where it is"))
  1. A parameter typed State is hidden from the model. The model sees remember(key, value) and recall(key).
  2. When the tool runs, that parameter receives the current State.
  3. state.extra_data keeps values across turns. The model never sees it. edit_extra_data() changes it.

What a tool can do with the State

Call Effect
state.extra_data[...] Read your own values. It is read-only: change it with with state.edit_extra_data() as data:
state.finish(answer) End the run after this turn. See Stop a run
state.add_message(Message.notice(text)) Tell the model something. It goes into the context right after this turn's results
state.answer, state.turn, state.usage, ... Read the run

Thread safety

Tools in one turn can run at the same time on worker threads. Every State method is thread-safe. A with state.edit_extra_data() as data: block is atomic: edits from several threads take turns, so data["n"] = data.get("n", 0) + 1 never loses an update. If the block raises, nothing changes. Values must be JSON (a set raises TypeError naming the key: use a list).