AgentsDefining agents

Defining agents

Register Runiq agents in ASP.NET Core and keep definitions maintainable.

Agents are created with the Agent class and registered with AddRuniqServer.

Minimal registration

C#
using Runiq.Agents;
using Runiq.Core;

var builder = WebApplication.CreateBuilder(args);

var openAiApiKey = builder.Configuration["OpenAI:ApiKey"];

builder.Services.AddRuniqServer(options =>
{
    options.AddAgent(
        new Agent(
            id: "weather-agent",
            name: "Weather Agent",
            instructions: "Answer weather-aware planning questions.",
            model: "openai/gpt-5",
            apiKey: openAiApiKey));
});

var app = builder.Build();

app.UseRuniqDashboard();

app.Run();

This registers the agent with the Runiq runtime. The dashboard and runtime metadata can now discover it.

For anything beyond a quick experiment, keep agent definitions out of Program.cs. A separate Agents folder keeps identity, instructions, model settings, and tool attachments easier to review.

The travel planner sample uses this pattern:

C#
builder.Services.AddRuniqServer(options =>
{
    options.AddAgent(WeatherAgent.Create(openAiApiKey));
    options.AddAgent(PlacesAgent.Create(openAiApiKey));
    options.AddAgent(PlannerAgent.Create(openAiApiKey));
});

Weather Agent

C#
using Runiq.Agents;
using Runiq.Agents.Tools;
using Runiq.WorkflowTravelPlanner.Tools;

namespace Runiq.WorkflowTravelPlanner.Agents;

public sealed class WeatherAgent : Agent
{
    private WeatherAgent(string? apiKey)
        : base(
            id: "weather-agent",
            name: "Weather Agent",
            instructions: """
            You are the Weather Analyst in a deterministic travel planning workflow.

            Your responsibility:
            - Analyze weather and travel comfort only.
            - Always use WeatherTool when the request involves a city or trip plan.
            - After using WeatherTool, write a short natural-language contribution.

            Boundaries:
            - Do not create an itinerary.
            - Do not write the final travel plan.
            - Do not print raw JSON.
            """,
            model: "openai/gpt-5",
            apiKey: apiKey)
    {
    }

    public static Agent Create(string? apiKey)
    {
        return new WeatherAgent(apiKey)
            .AddTool<WeatherTool>();
    }
}

The constructor is private because application code should use WeatherAgent.Create(...). That factory returns the agent with its required tool attached.

Travel Planner Agent

The planner has a different responsibility and a different tool:

C#
using Runiq.Agents;
using Runiq.Agents.Tools;
using Runiq.WorkflowTravelPlanner.Tools;

namespace Runiq.WorkflowTravelPlanner.Agents;

public sealed class PlannerAgent : Agent
{
    private PlannerAgent(string? apiKey)
        : base(
            id: "planner-agent",
            name: "Planner Agent",
            instructions: """
            You are the final Travel Planner in a deterministic travel planning workflow.

            Your responsibility:
            - Create the final user-facing itinerary.
            - Use the previous workflow step output as context.
            - Always use MealSuggestionTool before finalizing.
            - Produce a practical, clear, low-fatigue travel plan.

            Boundaries:
            - Do not print raw JSON.
            - Do not expose internal tool output directly.
            """,
            model: "openai/gpt-5",
            apiKey: apiKey)
    {
    }

    public static Agent Create(string? apiKey)
    {
        return new PlannerAgent(apiKey)
            .AddTool<MealSuggestionTool>();
    }
}

This is usually easier to maintain than one large "travel agent" with every responsibility and every tool attached.

id vs name

ValueMeaning
idStable technical identifier. Used by runtime lookup, dashboard routes, chat endpoints, workflows, and metadata.
nameDisplay label shown to developers in the dashboard.

Good ids are stable, lowercase, and route-friendly:

Text
weather-agent
places-agent
planner-agent
expense-data-analyst

Do not casually rename an id after other code, workflows, dashboard links, or tests depend on it.

API keys

The apiKey constructor parameter is optional because not every provider needs a key and because a provider can also be configured with a custom URL.

That does not mean OpenAI works without a key. With the default OpenAI provider endpoint, the runtime requires a valid key when the agent executes.

C#
new Agent(
    id: "weather-agent",
    name: "Weather Agent",
    instructions: "Answer weather-aware planning questions.",
    model: "openai/gpt-5",
    apiKey: builder.Configuration["OpenAI:ApiKey"]);

Local providers such as ollama are represented in the current runtime defaults without an API key requirement:

C#
new Agent(
    id: "local-agent",
    name: "Local Agent",
    instructions: "Answer using the local model.",
    model: "ollama/llama3.2");

OpenAI, Groq, Mistral, DeepSeek, OpenRouter, Together, Fireworks, NVIDIA, and Azure OpenAI are registered as API-key providers in the current implementation.

On this page