Normandy.DSL.Agent
(normandy v0.6.2)
View Source
DSL for defining AI agents with a clean, declarative syntax.
Provides macros to simplify agent creation with sensible defaults and expressive configuration options.
Examples
defmodule MyResearchAgent do
use Normandy.DSL.Agent
agent do
name "Research Agent"
description "Conducts research and analysis"
model "claude-3-5-sonnet-20241022"
temperature 0.7
max_tokens 4096
system_prompt """
You are a helpful research assistant.
Provide thorough, well-researched answers.
"""
# Optional: Define tools
tool CalculatorTool
tool SearchTool
end
end
# Create an instance
{:ok, agent} = MyResearchAgent.new(client: my_client)
# Run the agent
{updated_agent, response} = MyResearchAgent.run(agent, "Research quantum computing")Without DSL (for comparison)
config = %{
client: my_client,
model: "claude-3-5-sonnet-20241022",
temperature: 0.7,
max_tokens: 4096
}
agent = Normandy.Agents.BaseAgent.init(config)
# ... configure system prompt, tools, etc.Features
- Clean, declarative syntax
- Sensible defaults
- Compile-time validation
- Generated helper functions
- Tool registration support
- Memory management helpers
Summary
Functions
Defines an agent configuration block.
Sets the background context.
Sets the agent description.
Configures guardrails for the agent.
Sets the maximum number of messages in memory.
Sets the max tokens.
Sets the maximum number of tool calls executed concurrently inside a single
tool-loop iteration. Defaults to 1 (sequential — matches pre-0.5.0
observable behaviour). Values > 1 opt the agent into bounded parallel tool
execution with up to N tools running at once. The final result list passed
back to the LLM stays in the LLM's tool-call order (Task.async_stream is
invoked with ordered: true).
Sets the LLM model.
Sets the agent name.
Sets the output instructions.
Sets the internal steps.
Sets the chunk size (bytes of accumulated text) at which incremental output
guardrails run. Only takes effect when streaming_mode :incremental is set.
Default: 200.
Selects the output-guardrail streaming mode for this agent.
Sets the system prompt.
Sets the temperature.
Registers a tool module.
Functions
Defines an agent configuration block.
Available Options
name- Agent name (optional)description- Agent description (optional)model- LLM model to use (required)temperature- Sampling temperature 0.0-1.0 (default: 0.7)max_tokens- Maximum tokens in response (default: 4096)system_prompt- System prompt text (optional)background- Background context for prompt (optional)steps- Internal reasoning steps (optional)output_instructions- Output formatting instructions (optional)tool- Register a tool module (can be called multiple times)max_messages- Maximum messages in memory (optional)
Examples
agent do
name "My Agent"
model "claude-3-5-sonnet-20241022"
temperature 0.8
system_prompt "You are helpful."
end
Sets the background context.
Sets the agent description.
Configures guardrails for the agent.
stage is either :input or :output. specs is a list of guard
specifications — either a module atom or {module, opts} tuple. See
Normandy.Guardrails for the full contract.
Calling this macro twice for the same stage replaces the previous list.
Example
agent do
model "claude-sonnet-4-6"
guardrails :input, [
{Normandy.Guardrails.Builtins.MaxLength, limit: 10_000},
{Normandy.Guardrails.Builtins.ForbiddenSubstrings, terms: ["ignore previous"]}
]
guardrails :output, [
{Normandy.Guardrails.Builtins.RegexGuard,
patterns: [~r/\b\d{3}-\d{2}-\d{4}\b/], mode: :deny}
]
end
Sets the maximum number of messages in memory.
Sets the max tokens.
Sets the maximum number of tool calls executed concurrently inside a single
tool-loop iteration. Defaults to 1 (sequential — matches pre-0.5.0
observable behaviour). Values > 1 opt the agent into bounded parallel tool
execution with up to N tools running at once. The final result list passed
back to the LLM stays in the LLM's tool-call order (Task.async_stream is
invoked with ordered: true).
Streaming callback ordering: BaseAgent.stream_with_tools/3 invokes
callback.(:tool_result, result) from inside each worker as soon as that
tool finishes. At max_tool_concurrency > 1, callers therefore observe
:tool_result events in completion order, not LLM-call order — a
100ms tool that fires after a 500ms tool will still emit its :tool_result
first. If you need LLM-order callback handling, set max_tool_concurrency: 1 or buffer events and reorder them yourself after the stream completes.
Process-semantics note: tool invocations run inside Task.async_stream
workers, even at max_tool_concurrency: 1. Streaming callbacks fired while
a tool is executing therefore run in those worker processes — capture
parent = self() outside the callback before sending messages to the
test/owner process. Streaming callbacks fired outside tool execution (e.g.
:text_delta before any tool_use) still run in the caller's process.
Sets the LLM model.
Sets the agent name.
Sets the output instructions.
Sets the internal steps.
Sets the chunk size (bytes of accumulated text) at which incremental output
guardrails run. Only takes effect when streaming_mode :incremental is set.
Default: 200.
Selects the output-guardrail streaming mode for this agent.
:accumulate (default) runs guards on the full message after the stream
completes; :incremental runs guards at chunk boundaries and halts the
stream on violation. See Normandy.Guardrails for the full semantics.
Sets the system prompt.
Sets the temperature.
Registers a tool module.