Skip to content

Tornado Agent Basics ​

Overview ​

TornadoAgent is the core agent class in LlmTornado.Agents that provides a high-level abstraction for building AI agents. It combines AI models with tools, instructions, and structured output to create agents capable of performing complex tasks.

Quick Start ​

csharp
using LlmTornado;
using LlmTornado.Agents;
using LlmTornado.Chat.Models;

TornadoApi api = new TornadoApi("your-api-key");

// Create a simple agent
TornadoAgent agent = new TornadoAgent(
    client: api,
    model: ChatModel.OpenAi.Gpt41.V41Mini,
    instructions: "You are a helpful assistant."
);

// Run the agent
Conversation result = await agent.RunAsync("Hello, what can you help me with?");
Console.WriteLine(result.Messages.Last().Content);

Prerequisites ​

  • LlmTornado.Agents package installed
  • Understanding of basic LlmTornado chat functionality
  • Familiarity with C# async/await patterns

TornadoAgent ​

TornadoAgent Architecture ​

A TornadoAgent consists of:

  • Client: TornadoApi instance for API communication
  • Model: The AI model powering the agent
  • Instructions: System-level guidance defining behavior
  • Tools: Functions the agent can call
  • Output Schema: Optional type for structured responses
  • Streaming: Real-time response capability

Agent Initialization ​

csharp
TornadoAgent agent = new TornadoAgent(
    client: api,                    // Required: API client
    model: ChatModel.OpenAi.Gpt4.O, // Required: AI model
    name: "CodeAssistant",          // Optional: Agent name
    instructions: "You are a coding expert specialized in C#", // Optional: Behavior instructions
    outputSchema: typeof(Response), // Optional: Structured output type
    tools: toolsList,               // Optional: Available functions
    mcpServers: mcpList,            // Optional: MCP servers
    streaming: true,                // Optional: Enable streaming
    toolPermissionRequired: perms    // Optional: Tool permissions
);

Basic Usage ​

Simple Agent ​

csharp
TornadoAgent agent = new TornadoAgent(
    client: api,
    model: ChatModel.OpenAi.Gpt41.V41Mini,
    instructions: "You are a helpful assistant."
);

Conversation result = await agent.RunAsync("What is 2+2?");
Console.WriteLine(result.Messages.Last().Content);

Agent with Custom Instructions ​

csharp
string instructions = @"
You are a senior software architect with expertise in:
- Microservices architecture
- Cloud-native design patterns
- System scalability and performance
- Security best practices

Provide detailed, actionable advice with code examples when appropriate.
";

TornadoAgent agent = new TornadoAgent(
    client: api,
    model: ChatModel.OpenAi.Gpt4.O,
    name: "ArchitectBot",
    instructions: instructions
);

Conversation result = await agent.RunAsync(
    "How should I design a scalable event-driven system?"
);

Agent with Tools ​

csharp
TornadoAgent agent = new TornadoAgent(
    client: api,
    model: ChatModel.OpenAi.Gpt41.V41Mini,
    instructions: "You are a helpful assistant that can check weather.",
    tools: [weathertools.GetWeather]
);

Conversation result = await agent.RunAsync("What's the weather like in Prague?");

Console.WriteLine(result.Messages.Last().Content);
// Agent will call GetWeather("Prague") and use the result

public class weathertools
{
    // Define a tool function
    [Description("get the weather")]
    public static string GetWeather([Description("cit to get weather from")] string city)
    {
        // Simulated weather data
        return $"The weather in {city} is sunny with 22°C.";
    }
}

Agent with Structured Output ​

csharp
TornadoAgent agent = new TornadoAgent(
    client: api,
    model: ChatModel.OpenAi.Gpt4.O,
    instructions: "Analyze tasks and provide structured breakdown.",
    outputSchema: typeof(TaskAnalysis)
);

Conversation result = await agent.RunAsync("Analyze: Build a REST API with authentication");
TaskAnalysis? analysis = JsonConvert.DeserializeObject<TaskAnalysis>(
    result.Messages.Last().Content
);

Console.WriteLine($"Task: {analysis?.Task}" +
    $" Complexity: {analysis?.ComplexityScore} " +
    $" Steps: {string.Join(", ", analysis?.Steps ?? Array.Empty<string>())} " +
    $" Estimated Time: {analysis?.EstimatedMinutes} minutes");

public class TaskAnalysis
{
    public string Task { get; set; }
    public int ComplexityScore { get; set; }
    public string[] Steps { get; set; }
    public int EstimatedMinutes { get; set; }
}

Advanced Usage ​

Maintaining Conversation Context ​

csharp
TornadoAgent agent = new TornadoAgent(api, ChatModel.OpenAi.Gpt41.V41Mini);

// First interaction
Conversation result = await agent.RunAsync("My name is Alice and I'm learning C#.");

// Continue conversation
result = await agent.RunAsync(
    "What should I learn next?",
    appendMessages: result.Messages.ToList()
);

// Agent remembers context
result = await agent.RunAsync(
    "What's my name again?",
    appendMessages: result.Messages.ToList()
);

Dynamic Output Schema Changes ​

csharp
TornadoAgent agent = new TornadoAgent(
    api, 
    ChatModel.OpenAi.Gpt4.O,
    outputSchema: typeof(PersonInfo)
);

// Use initial schema
Conversation result = await agent.RunAsync("Extract: John, 30, NYC");

// Change schema dynamically
agent.UpdateOutputSchema(typeof(CompanyInfo));

// Use new schema
result = await agent.RunAsync("Extract: TechCorp, founded 2010, 500 employees");

Adding Tools Dynamically ​

csharp
TornadoAgent agent = new TornadoAgent(api, ChatModel.OpenAi.Gpt41.V41);

// Add tool later
Tool weatherTool = new Tool(
    (string city) => $"Weather in {city}: Sunny",
    "get_weather",
    "Gets weather for a city"
);

agent.AddTornadoTool(weatherTool);

Conversation result = await agent.RunAsync("What's the weather in London?");

Best Practices ​

Clear Instructions ​

  • Be specific about the agent's role
  • Define boundaries and limitations
  • Provide examples when helpful
  • Use structured format for complex instructions

Tool Design ​

  • Keep tools focused and single-purpose
  • Provide clear descriptions
  • Handle errors gracefully
  • Return meaningful results

Error Handling ​

csharp
try
{
    Conversation result = await agent.RunAsync(userInput);
    
    if (!result.Messages.Any())
    {
        Console.WriteLine("No response generated");
        return;
    }
    
    string response = result.Messages.Last().Content;
    Console.WriteLine(response);
}
catch (Exception ex)
{
    Console.WriteLine($"Agent error: {ex.Message}");
    // Implement retry or fallback logic
}

Memory Management ​

  • Trim conversation history for long sessions
  • Save important context to external storage
  • Use conversation serialization for persistence

Common Issues ​

Agent Not Using Tools ​

Solutions:

  • Ensure instructions mention tool availability
  • Use models with strong function calling (GPT-4, Claude 3+)
  • Provide clear tool descriptions
  • Test tools individually first

Context Loss ​

Solutions:

  • Always use appendMessages for continuity
  • Implement conversation persistence
  • Monitor token usage and trim history

Poor Output Quality ​

Solutions:

  • Improve instruction clarity
  • Use more capable models
  • Provide examples in instructions
  • Adjust temperature and other parameters

API Reference ​

Constructor ​

csharp
public TornadoAgent(
    TornadoApi client,
    ChatModel model,
    string name = "Assistant",
    string instructions = "You are a helpful assistant",
    Type? outputSchema = null,
    List<Delegate>? tools = null,
    List<MCPServer>? mcpServers = null,
    bool streaming = false,
    Dictionary<string, bool>? toolPermissionRequired = null
)

TornadoAgent Methods ​

  • RunAsync(string input, ...) - Execute agent with input
  • UpdateOutputSchema(Type? schema) - Change output format after initilization

TornadoAgent Properties ​

TornadoApi Client ​

TornadoApi required with authentication for api access to run the agent.

ChatModel Model ​

ChatModel desired to run on the agent while performing task. Close consideration should be taken when considering which model to use for each job.

ChatRequest Options ​

ChatRequest Used to configure any option within the specific api's to get a more advanced control. (Please set this after initilization)

ResponseRequest ResponseOptions ​

ResponseRequest Response Options to support OpenAI response Tools (Please set this after initilization)

string Name ​

Use to differentiate the agent when using as a tool or within the logging.

string Instructions ​

System message the agent will use as instructions for how to process users prompts

string Id ​

Unique generated GUID to differentiate agents on the backend

Type OutputSchema ​

The Type used to define the json stuctured output the agent should respond with.

List<Delegate> Tools ​

List of delegate functions used to extract tools from on initilization.

Dictionary<string, bool> ToolPermissionRequired ​

Set the Dictionary string Key as the tool name = true if you want the agent loop to send event for permission request.

Dictionary<string, Tool> ToolList ​

List of available Tornado tools that have been converted and ready to use within the agent loop

Dictionary<string, TornadoAgentTool> AgentTools ​

List of available Agents converted into Tornado tools and ready to be use within the agent loop

Dictionary<string, MCPServer> McpTools ​

List of available MCP tools as keys = MCP servers that host the tool required for the agent loop

List<MCPServer> MpcServers ​

List of MCP Servers to extract Tools from on initilization

bool Streaming ​

Used to enable to the default runner streaming capability if paired with a streaming handler. (or else it will not run streaming).

⚡ Event ⚡ Func<AgentRunnerEvents, ValueTask>? OnAgentRunnerEvent ​

Used to get Streaming Results, debugging information, tool results, ects.