API Reference normandy v#1.1.1

View Source

Modules

Documentation for Normandy.

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.

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.