Agents

July 28, 2026 · View on GitHub

Agent is the single orchestration primitive — an LLM with optional tools and/or sub-agents. Everything else in this section builds on it.

Defining an agent

The name must match ^[a-zA-Z_][a-zA-Z0-9_-]*$.

Object-initializer style:

var agent = new Agent("assistant")
{
    Model        = "anthropic/claude-sonnet-4-6",
    Instructions = "You are helpful.",
    Tools        = tools,             // optional: List<ToolDef>
    Agents       = [subAgent],        // optional: sub-agents (multi-agent)
    Strategy     = Strategy.Handoff,  // required when Agents is non-empty
    MaxTurns     = 10,                // optional
    Temperature  = 0.2,               // optional
    MaxTokens    = 2048,              // optional
};

Fluent builder style (AgentBuilder):

var agent = AgentBuilder.Create("assistant")
    .WithModel("anthropic/claude-sonnet-4-6")
    .WithInstructions("You are helpful.")
    .WithTools(tools.ToArray())
    .WithMaxTurns(10)
    .Build();

Build() throws ConfigurationException if sub-agents are present but no Strategy is set.

Instructions

A static system prompt:

var agent = new Agent("a") { Instructions = "You are helpful." };

Dynamic instructions — a Func<string> re-evaluated every time the agent is submitted to the server, so the prompt can reflect current state (date, flags, fetched context). InstructionsFn takes precedence over Instructions:

var agent = new Agent("a")
{
    InstructionsFn = () => $"You are helpful. Today is {DateTime.UtcNow:yyyy-MM-dd}.",
};

// builder:
AgentBuilder.Create("a").WithInstructions(() => $"Today is {DateTime.UtcNow:d}").Build();

Server-side prompt templates are also supported via PromptTemplate:

agent.PromptTemplateInstructions =
    new PromptTemplate("support_prompt", Variables: new() { ["tone"] = "warm" });

Agents from methods ([AgentDef])

Define agents declaratively on a host object. [Tool] / [Guardrail] methods on the same object are attached automatically (filter with the Tools / Guardrails properties). An [AgentDef] method may return void (attribute-only), string (a no-arg method becomes dynamic instructions), or Agent (a full factory).

internal sealed class AgentHost
{
    [Tool("Greet the user.")]
    public Dictionary<string, object> SayHi() => new() { ["greeting"] = "hello" };

    // returns string -> becomes InstructionsFn; attaches only the say_hi tool
    [AgentDef(Name = "greeter", Tools = new[] { "say_hi" })]
    public string Greeter() => "Be friendly.";

    // void -> defined entirely by the attribute; wires greeter as a sub-agent
    [AgentDef(Name = "coordinator", Tools = new string[0],
              Agents = new[] { "greeter" }, Strategy = Strategy.Sequential)]
    public void Coordinator() { }
}

var host = new AgentHost();

List<Agent> all = Agent.FromInstance(host);            // all [AgentDef] methods
Agent       one = Agent.FromInstance(host, "greeter"); // a single one by name
one.Model = "anthropic/claude-sonnet-4-6";             // supply a model if the attribute left it unset

await using var runtime = new AgentRuntime();
await runtime.RunAsync(one, "Greet the user by calling say_hi.");

[AgentDef] properties: Name, Model, Instructions, Tools (["*"] = all, [] = none, or names), Guardrails, Agents (sub-agent names), Strategy, MaxTurns, MaxTokens, Temperature.

See reference/agent-definition.md for the full attribute surface.

Next