API Reference normandy v#1.2.0
View SourceModules
Wraps a remote A2A agent as a Normandy BaseTool.
Helpers for discovering remote A2A agents and registering them as tools.
Exposes Normandy agents as A2A-compatible endpoints.
Core agent implementation providing conversational AI capabilities.
Configuration structure for BaseAgent instances.
Default input schema for agent interactions.
Default output schema for agent responses.
Splits a %BaseAgentConfig{} into a serializable, secret-free template
(persisted via SessionStore.save_config_template/3) and reconstructs a full
config on any node from template + node-local supplement + credential token.
The single chokepoint every agent tool call flows through.
Structured record of a denied (or approval-pending) tool call.
Carries the behaviour functions the chokepoint consults.
Protocol for LLM model interactions.
Response schema for agent outputs that may include tool calls.
The pure finite-state-machine core of an agent turn.
Generic synchronous interpreter for the pure Normandy.Agents.Turn core.
The injected side-effecting functions the driver consults per effect.
Inline (synchronous) interpreter for the pure Normandy.Agents.Turn core.
Eager-handoff trigger for distributed sessions.
Asynchronous :gen_statem interpreter of the pure Turn FSM — the async analog
of Turn.Driver. Coarse lifecycle states (:running, :awaiting_approval,
:idle) hang Tasks and state_timeouts off the turn; they are NOT a
re-encoding of the seven Turn.State statuses (the core stays the source of
truth). Blocking effects (:call_llm, :dispatch_tools, :execute_approved)
run in a monitored Task; non-blocking effects run synchronously in the handler.
Router in front of Turn.Server. Resolves session_id to a live pid via the
SessionRegistry; on a miss, rehydrates turn state + conversation memory from
the SessionStore and starts a Turn.Server under Turn.Supervisor with the
caller-supplied config (the store never holds config/credentials).
Serializable data for one in-flight turn (the design's %TurnState{}).
DynamicSupervisor for Turn.Server processes (one per live session).
Horde.DynamicSupervisor for Turn.Server processes — cluster-wide placement
and supervision. Children start under the registry's :via name (atomic
registration). resume_policy maps to the child restart value: :lazy →
:temporary (a lost node's session is NOT redistributed; it is rebuilt on the
next request), :eager → :transient (Phase 7d; redistributed on node-down).
Validation middleware for BaseAgent input/output schemas.
Batch processing utilities for handling multiple agent requests concurrently.
Resolves the node-local, non-serializable half of an agent's config from a
stable template_id: the tool registry, before/after hooks, and a
client_builder that turns a credential token into an LLM client struct.
Default node-local AgentTemplate: an Agent mapping template_id → supplement.
Contract for budget gating and accounting around tool calls.
Default BudgetTracker: no gating, no accounting (back-compat).
Contract for context-window compaction at the turn's :steering boundary.
Default Compactor: never compacts (back-compat, zero cost).
Opt-in Compactor that wraps Normandy.Context.WindowManager's truncation
strategies (:oldest_first | :sliding_window | :summarize).
Explicit, per-agent selection of the pluggable behaviours.
Contract for resolving an LLM provider token.
Default CredentialProvider: reads the binary api_key off the client.
Contract for model capability/limit lookup.
Default ModelCatalog: a fixed catalog absorbing WindowManager's hardcoded
context-window limits. All listed models are tool/vision/streaming-capable.
Contract for per-tool-call policy decisions, consulted at the dispatch
chokepoint via Normandy.Behaviours.Config.to_pipeline/1.
Default PolicyEngine: allows every call (back-compat).
PolicyEngine that evaluates an ordered list of in-memory rules, first match
wins, with a configurable default action. The ruleset is supplied as a
keyword list on ctx.opts (the opts half of the bundle's
{module, opts} ref — always a keyword list by construction)
Maps a session_id to the live Turn.Server pid serving it, so a router can
decide route-to-existing vs rehydrate-and-start. :none means no live process
(the session may still have persisted state in a SessionStore).
Distributed SessionRegistry over Horde.Registry (keys: :unique,
members: :auto). The handle is the registry's name (an atom). Cluster-wide
whereis; registration is atomic when servers start under the :via name from
child_name/2. Works as a cluster-of-one on a single node (and on
nonode@nohost) with the same config that serves N nodes.
Default SessionRegistry over Elixir's Registry (:unique keys). The
handle is the registry's name (an atom). register/3 registers the calling
process under session_id; the owner's death auto-unregisters it.
Distributed SessionRegistry using Redis as the shared session_id → pid name
table, with cross-node routing over Erlang distribution (Redis replaces Horde's
CRDT, not distribution). A per-node owner GenServer holds the Redix connection,
monitors locally-registered pids (clearing the key on :DOWN), and refreshes key
TTLs so a crashed node's keys lapse on their own.
:via callbacks for SessionRegistry.Redis, delegating to the local owner
GenServer. A Turn.Server started under {:via, __MODULE__, {owner, session_id}}
registers atomically at process start (SET … NX); a losing concurrent start gets
{:error, {:already_started, pid}} and the router routes to the winner.
Contract for externalizing a session's conversation entries and turn state.
ETS-backed SessionStore — fast, in-node. A GenServer owns a private ETS table
and serializes every mutation through its mailbox, so concurrent appends/forks to
the same session_id cannot clobber each other (the read-modify-write of a
session's %AgentMemory{} is exclusive). The handle is the owner pid.
Process-backed in-memory SessionStore — the reference impl and default
selection. Holds one AgentMemory per session_id plus an opaque turn-state
map, in an Agent. Used for tests and library/single-node runs; not consumed by
the turn loop in Phase 3.
Distributed, durable SessionStore over OTP-native Mnesia ("distributed ETS").
ram_copies tables are replicated ETS; :mnesia.transaction/1 serializes per-session
appends (the FOR-UPDATE equivalent), so concurrent/cross-node appends never lose an
entry. Mnesia stores Erlang terms natively, so content / turn_state /
config_template need no term_to_binary.
Durable, cluster-shared SessionStore over Postgres (Ecto). The handle is the
host's Ecto Repo module. Conversation content and opaque turn_state are stored
as Erlang terms (term_to_binary). Entries are a global parent-linked forest, so
fork/3 shares ancestors instead of copying.
Migration for the Postgres SessionStore. Call from a host migration
Adds the queryable resume_policy column to normandy_sessions (Phase 7d
resume reaper). Lets SessionStore.Postgres.list_resumable/1 filter eager
sessions without decoding the opaque config_template blob. Call from a host
migration alongside the other Postgres.Migration* modules.
Adds the config_template column to normandy_sessions (Phase 7c).
Durable SessionStore over Redis, modelled on Redis Streams. The conversation is an
append-only stream (XADD/XRANGE) so appends are atomic and O(1) with no
read-modify-write — concurrent appends never lose an entry. Session metadata
(turn state, config template, resume policy) lives in a hash; eager session_ids live
in a SET for list_resumable/1.
Raised when a changeset can't cast a value.
Optional convenience for wiring the distributed-session infra (Tier 2) into a host supervision tree. Returns child specs for
Conversation memory as a graph of parent-linked entries.
One message in the conversation graph.
Protocol for schema serialization and representation.
Represents a document content block inside a multimodal message.
Represents an image content block inside a multimodal message.
Represents a text content block inside a multimodal message.
Protocol for providing additional context information to agents.
Context provider that supplies current date and time information to agents.
Represents a single message in agent conversation history.
Defines the structure of an agent's system prompt.
Represents a Server-Sent Event (SSE) from a streaming LLM response.
Utilities for processing streaming LLM responses.
Generates structured system prompts for agents from prompt specifications.
Represents a tool call request from the LLM.
Represents the result of executing a tool.
Handles conversation summarization for context window management.
Provides token counting utilities using the Anthropic token counting API.
Manages context window limits for conversations with automatic truncation strategies.
Message structure for agent-to-agent communication.
Pool manager for agent processes with automatic checkout/checkin.
GenServer wrapper for running BaseAgent instances as supervised processes.
Dynamic supervisor for managing agent processes.
Coordinates hierarchical multi-agent systems with manager-worker patterns.
Orchestrates parallel execution of multiple agents.
Pattern matching utilities for agent results.
Reactive patterns for event-driven multi-agent coordination.
Orchestrates sequential execution of multiple agents.
Manages shared context between multiple agents.
GenServer-backed shared context for multi-agent systems.
DSL for defining AI agents with a clean, declarative syntax.
DSL for defining multi-agent workflows with a declarative syntax.
Runs a list of Normandy.Guardrails.Guard modules against a value.
Rejects strings containing any of the configured forbidden substrings.
Rejects values whose string length exceeds :limit.
Rejects (or requires) regex matches against a string.
Rejects a struct or map when any of the named fields are nil.
A hybrid scope guard: a cheap deterministic fast path in front of an injected classifier.
Behaviour for guardrails that inspect agent input or output.
Exception raised when an input guardrail rejects an agent's input.
Raised when we cannot perform an action because the changeset is invalid.
Adapter for integrating Claudio (Anthropic's Claude API client) with Normandy agents.
JSON deserialization helper with automatic error recovery.
Adapter implementing Normandy.Agents.Model against any OpenAI-compatible
Chat Completions endpoint (OpenAI, DigitalOcean Inference, etc.).
Helpers for discovering and registering MCP tools in a Normandy tool registry.
Configuration for server-side MCP servers passed to the Anthropic API.
Wraps an MCP tool as a Normandy BaseTool implementation.
Metadata attached to schema structs.
Parameterized types are Normandy types that can be customized per field.
Circuit Breaker pattern implementation to prevent cascading failures.
Retry mechanism with exponential backoff for handling transient failures.
Provides a macro-based DSL for defining structured data schemas.
Utilities for introspecting Normandy schemas at runtime.
Exception raised when schema validation fails.
Runtime validation of data against Normandy schemas.
Soft OpenTelemetry context propagation across process boundaries.
Protocol for implementing executable tools that agents can use.
A calculator tool for performing basic arithmetic operations.
Schema-based calculator tool demonstrating the new SchemaBaseTool approach.
A tool for processing lists with various operations.
A tool for performing string manipulation operations.
A weather tool that fetches current weather data from Open-Meteo API.
Executes tools safely with timeout and error handling.
Manages a collection of tools available to an agent.
Mixin module for creating tools with Normandy schema-based input definitions.
Defines functions and the Normandy.Type behaviour for implementing
basic custom types.
Provides changeset-style validation for schemas.