Agents
An agent is an LLM-powered worker defined by a name, description, system prompt, and LLM client. Agents are the fundamental building blocks of LogicGrid; all higher-level structures — including admins, graphs, and RAG — are composed of them.
Building an agent
using LogicGrid.Core.Agents;
using LogicGrid.Core.Llm;
var llm = LlmClientBase.Ollama("llama3.2");
IAgent translator = new Agent<string>(
name: "Translator",
description: "Translates English to French.",
systemPrompt:
"Translate the user's English text to natural, fluent French. " +
"Output only the translation — no commentary.",
llm: llm);
var ctx = new AgentContext();
Console.WriteLine(
await translator.RunAsync("Hello, how are you?", ctx));
Bonjour, comment ça va ?
Constructor reference
public Agent(
string name,
string description,
string systemPrompt,
LlmClientBase llm,
IList<ToolBase>? tools = null,
LlmOptions? llmOptions = null,
RetryPolicy? retryPolicy = null,
IToolCallingStrategy? toolCallingStrategy = null)
| Parameter | Required | What for |
|---|---|---|
name | yes | Short identifier. Admins use it for selection; the logger prefixes lines with it. |
description | yes | One-line role description. Specificity helps the Admin LLM select the correct agent for the task. |
systemPrompt | yes | Instructions sent with every call. Supports {{slot}} injection for dynamic templates — see Prompt templates. |
llm | yes | The LLM client. Different agents in the same app can use different providers — see Providers. |
tools | optional | Tools available to the agent. See Tools. |
llmOptions | optional | Generation options (Temperature, MaxTokens, etc.). See Providers. |
retryPolicy | optional | Controls retries on validation failure. See Retry policies. |
toolCallingStrategy | optional | Determines the tool invocation protocol. defaults to PromptSchemaStrategy for universal compatibility or use NativeToolCallingStrategy for providers with built-in tool support. See Tool calling strategy. |
Agent<T> and AgentBase<T>
LogicGrid ships two agent classes. Both live in
LogicGrid.Core.Agents.
| Type | What it is |
|---|---|
Agent<TOutput> | Concrete class. Configure name, description, system prompt, LLM, and tools through the constructor. |
AgentBase<TOutput> | Abstract class. Use it to customise prompt rendering, output validation, deserialization, retry behaviour or how agent runs. For more details on how to customize AgentBase<T> see Overriding AgentBase<T> |
Return type & typed output
Agent<TOutput> provides a dual-interface for execution. While the concrete class returns a strongly-typed object, its explicit IAgent implementation provides a serialized string. This design allows the same agent instance to serve both local business logic and framework-level orchestration.
- Typed Execution (
Agent<TOutput>): CallingRunAsyncon the concrete generic type returnsTOutput. LogicGrid automatically handles the heavy lifting: it extracts JSON from the LLM's response, deserializes it into your type, and executes a retry loop if the output fails validation or schema constraints.
public sealed class Sentiment
{
public string Label { get; set; } = ""; // positive / negative / neutral
public double Confidence { get; set; }
}
var sentiment = new Agent<Sentiment>(
name: "Sentiment",
description: "Classifies sentiment.",
systemPrompt:
"Classify the sentiment of the user's text. " +
"Reply with JSON: { \"label\": \"...\", \"confidence\": 0.0 }",
llm: llm);
Sentiment s = await sentiment.RunAsync(
"I love this library.", new AgentContext());
Console.WriteLine($"{s.Label} ({s.Confidence:P0})");
positive (95%)
- Erased Execution (
IAgent): By implementingIAgent.RunAsyncexplicitly, LogicGrid avoids method signature collisions while providing a string-based contract. When called through this interface, the agent serializes itsTOutputto a JSON string. This "type erasure" is what enables heterogeneous agents to be composed into pipelines or graphs that expect a uniformTask<string>exchange.
public sealed class Sentiment
{
public string Label { get; set; } = ""; // positive / negative / neutral
public double Confidence { get; set; }
}
IAgent sentiment = new Agent<Sentiment>(
name: "Sentiment",
description: "Classifies sentiment.",
systemPrompt:
"Classify the sentiment of the user's text. " +
"Reply with JSON: { \"label\": \"...\", \"confidence\": 0.0 }",
llm: llm);
Sentiment s = await sentiment.RunAsync(
"I love this library.", new AgentContext());
Console.WriteLine($"{s.Label} ({s.Confidence:P0})");
{"Label":"positive","Confidence":0.95}
Tools
Tools are passed to the constructor. The agent's LLM decides when to call them; LogicGrid handles the call-loop and feeds results back.
using LogicGrid.Core.Tools;
using LogicGrid.Tools.Tools;
IAgent math = new Agent<string>(
name: "Mathlete",
description: "Solves arithmetic.",
systemPrompt: "Use the calculator tool when the user asks for a number.",
llm: llm,
tools: new ToolBase[] { new CalculatorTool() });
Console.WriteLine(
await math.RunAsync("What is 17 * 23 + 91?", new AgentContext()));
17 * 23 + 91 = 482.
See Built-in tools, Custom tools (typed), and MCP.
Scoped message history
The agent's message history is reset on every RunAsync call.
There is no context bleed between invocations. This is intentional:
- Agents become predictable — the same input gives the same prompt shape every time.
- They become safe to share between threads and concurrent pipelines.
- They become testable without setup teardown.
If you need cross-call memory, you have two options:
- The admin holds persistent
MessageHistoryacross the agents in a single run. See Admins. - For session-style memory across runs, use Sliding window or Semantic memory.
Events
When an AgentContext carries an EventBus, the agent publishes a strongly typed event at every step of a run: AgentStartedEvent, LlmCallStartedEvent, LlmCallCompletedEvent, LlmCallRetryingEvent,
ToolCallStartedEvent, ToolCallCompletedEvent, ToolCallFailedEvent, AgentCompletedEvent,
AgentFailedEvent. Subscribe your own handler to forward them to your log/metrics system, react to
failures. The full catalog is on the Events page.
Customising via AgentBase<T>
AgentBase<T> exposes virtual members you can override:
RenderSystemPromptAsync— build the prompt asynchronously (RAG retrieval, user-profile lookup, etc.).ValidateOutput— reject responses that don't pass your rule so the framework retries automatically.DeserializeOutput— parse a non-JSON response format.OnRetry— emit your own telemetry on retries.- Computed
Tools/LlmOptions/RetryPolicy— when those depend on state that isn't available at construction time.
The full walkthrough is at
Overriding AgentBase<T>.