NovaCore.Agents
4.0.0
See the version list below for details.
dotnet add package NovaCore.Agents --version 4.0.0
NuGet\Install-Package NovaCore.Agents -Version 4.0.0
<PackageReference Include="NovaCore.Agents" Version="4.0.0" />
<PackageVersion Include="NovaCore.Agents" Version="4.0.0" />
<PackageReference Include="NovaCore.Agents" />
paket add NovaCore.Agents --version 4.0.0
#r "nuget: NovaCore.Agents, 4.0.0"
#:package NovaCore.Agents@4.0.0
#addin nuget:?package=NovaCore.Agents&version=4.0.0
#tool nuget:?package=NovaCore.Agents&version=4.0.0
NovaCore.Agents
NovaCore.Agents is a .NET 10 library for building LLM agents. Its core is one small loop: it takes a window of messages you own, streams a model over it, runs the tools the model asks for, and hands you every message it creates before it goes on. It stores nothing, so your database stays the record. Around the loop sit provider clients (OpenAI, Anthropic, Google, Bedrock and OpenAI-compatible gateways), an optional hosting layer for durable conversations, multi-agent setups and human approvals, a browser and computer-use stack, MCP and OpenTelemetry.
Install
dotnet add package NovaCore.Agents.Hosting # Agent and durable conversations; brings the core loop
dotnet add package NovaCore.Agents.Providers.OpenAI # or .Anthropic, .Google, .Bedrock, or .Providers for all of them
Add NovaCore.Agents.Browser for browser use, NovaCore.Agents.ComputerUse for computer use,
NovaCore.Agents.Mcp for MCP servers, NovaCore.Agents.Observability.OpenTelemetry for traces and metrics, and
NovaCore.Agents.Testing for models that need no key. Everything targets .NET 10.
Hello, agent
using NovaCore.Agents;
using NovaCore.Agents.Hosting;
using NovaCore.Agents.Testing;
var client = new EchoLlmClient(); // a real one: new OpenAiChatClient(new OpenAiOptions { ApiKey = key, Model = "gpt-5.1" })
var agent = new Agent(new AgentProfile { Name = "helper", Client = client, SystemPrompt = "Be brief." });
var result = await agent.RunAsync("Hello!");
Console.WriteLine(result.Text);
EchoLlmClient (from NovaCore.Agents.Testing) answers without a key, so this runs as written.
A tool
A tool is a record of arguments plus a function. The schema the model sees is generated from the record, so the
two cannot drift apart. ([Description] is System.ComponentModel.DescriptionAttribute.)
public sealed record WeatherArgs(
[property: Description("The city, for example \"Oslo\".")] string City,
[property: Description("The unit for temperatures.")] TemperatureUnit Unit = TemperatureUnit.Celsius);
public enum TemperatureUnit { Celsius, Fahrenheit }
var weather = Tools.Create<WeatherArgs>(
"get_weather",
"The current weather for a city.",
(args, ctx, ct) => Task.FromResult(ToolResult.Ok($"Sunny, 21 degrees in {args.City}.")));
var agent = new Agent(new AgentProfile
{
Name = "weather",
Client = client,
SystemPrompt = "Answer weather questions with get_weather.",
Tools = [weather],
});
var result = await agent.RunAsync("What's the weather in Oslo?");
Console.WriteLine(result.Text);
Every C# example in this README is compiled by samples/NovaCore.Agents.Samples,
and the ones that need no browser are run by it too.
Packages
| Package | What it gives you |
|---|---|
NovaCore.Agents |
Messages, the ILlmClient contract, tools, AgentLoop, run events, budget and spend, the inbox (steer, interrupt, stop), approvals, compaction, sub-agents, structured output, decisions (IDecider, LlmDecider). Depends only on Microsoft.Extensions.Logging.Abstractions. |
NovaCore.Agents.Providers.OpenAI |
Chat Completions, Responses, Azure OpenAI and 20 OpenAI-compatible profiles (Groq, DeepSeek, OpenRouter, xAI, Ollama, …). The Responses client sends OpenAI's native computer tool; the experimental native decisions client. |
NovaCore.Agents.Providers.Anthropic |
Claude Messages API, direct and on Vertex. Automatic cache breakpoints, thinking round-trip, Claude's native computer tool. |
NovaCore.Agents.Providers.Google |
Gemini API and Vertex. Thought-signature round-trip. |
NovaCore.Agents.Providers.Bedrock |
The Bedrock Converse API for every vendor on Bedrock. Cache points. |
NovaCore.Agents.Providers |
One ProviderSpec → ILlmClient for every provider above, known-provider descriptors, model catalog, built-in prices. |
NovaCore.Agents.Hosting |
Agent, durable conversations (AgentSession), stores, message-in-the-loop, approvals and answers, AgentHost for agents that talk to each other. |
NovaCore.Agents.Hosting.EntityFramework |
An EF Core conversation store whose two tables live in your own DbContext. |
NovaCore.Agents.Browser |
Browser use for every model: the library's browser tools over a CDP engine (page rendering, actions, slow-page waiting, downloads), and a Playwright launcher. |
NovaCore.Agents.Browser.LiveView |
Screencast fan-out to viewers and a gate for a person's input. No dependencies. |
NovaCore.Agents.ComputerUse |
Native computer use: OpenAI's computer tool and Claude's computer toolset over a screen (a CDP tab or your own), picked from the model's capabilities by ComputerTools.ToolFor. |
NovaCore.Agents.Mcp |
MCP servers (stdio and streamable HTTP) as tools. |
NovaCore.Agents.Observability.OpenTelemetry |
gen_ai.* traces and metrics for model calls and runs. |
NovaCore.Agents.Testing |
ScriptedLlmClient, EchoLlmClient, RecordingLlmClient, CacheAssert. |
Providers and models
Each provider package has a client you build from an options record (new OpenAiResponsesClient(...),
new AnthropicClient(...), new GeminiClient(...), new BedrockClient(...)). When the route comes from
configuration, NovaCore.Agents.Providers builds any of them from one record:
ILlmClient client = LlmProviders.Create(new ProviderSpec
{
Provider = "openai-responses", // or "anthropic", "google", "bedrock", "azure-openai", "groq", …
Model = "gpt-6-luna",
ApiKey = key,
});
ModelInfo model = client.Model; // what the library knows: window, output cap, efforts, price, computer tool
Console.WriteLine($"{model.Model}: {model.ContextWindowTokens:N0} tokens, " +
$"${model.Price?.InputPerMTok}/M in, computer tool: {model.Capabilities.NativeComputerTool ?? "none"}");
Picking one:
- A model the library knows (the current Claude, GPT and Gemini families) comes with its context window, output
cap, reasoning efforts, capabilities and list price, so cost reporting and cost caps work out of the box. For any
other model set
PriceandCapabilitiesin the options; a model with no price costs 0 and a cost cap never fires. - Tool-using runs on GPT-6 belong on the Responses client (
openai-responses): OpenAI's Chat Completions takes function calls from GPT-6 only in limited cases. - Computer use needs a native computer tool: Claude on
AnthropicClient(direct or Vertex), or an OpenAI model that takes one (GPT-6, GPT-5.6 Luna, GPT-5.4) onOpenAiResponsesClient. Browser use works with every client. - Every client caches by default, retries before the first byte, and reports failures as
LlmExceptionwith aKind. Details per provider: providers.
Tools, approvals and conversations
A tool's ToolKind says what it does: Read tools run in parallel, Write tools change something outside the
conversation, Suspend tools park the run on something that outlives the turn. Inside a session a Write call
waits for a person: the run ends Suspended, the call is in session.Pending, and ApproveAsync or RejectAsync
decides it — from another process hours later if need be. AgentProfile.AutoApprove and your own IApprovalGate
take the person out where policy allows (tools).
Agent.SessionAsync opens a durable conversation that you can steer, interrupt or stop while it runs
(session.SendAsync(text, Delivery.Steer)), in memory or in your database through EfConversationStore
(hosting). AgentHost runs many sessions that message each other and spawn children;
SubAgentRunner runs a child inside one tool call (multi-agent). If your app already has a
message table, skip the hosting layer and call AgentLoop with your window (the loop).
Browser use
The model reads an indexed text rendering of the page and acts on element indices. It works with any model on any provider; the same tools serve every model.
await using var browser = new ManagedBrowserSession(new ManagedBrowserOptions { Headless = true });
await browser.StartAsync(ct);
var bundle = BrowserTools.Create(new BrowserContext(browser.CdpSession));
var agent = new Agent(new AgentProfile
{
Name = "browser",
Client = client,
SystemPrompt = "You complete tasks on websites for the user.\n\n" + bundle.SystemPrompt,
Tools = bundle.Tools,
});
var result = await agent.RunAsync("Find the opening hours of the Oslo public library.", ct);
The bundle's tools are navigate, read_page, find, click, hover, input_text, select_option,
send_keys, scroll, upload_file, switch_tab, close_tab, go_back, wait and screenshot, with a smaller
read-only Research set and an optional human_takeover that hands the page to a person. Slow pages are waited out
on what they show, results say what changed, and screenshots and downloads reach your host as evidence. See
browser.
Computer use
The model sees screenshots and acts in pixels, through the computer tool its provider trained it on.
await using var browser = new ManagedBrowserSession();
await browser.StartAsync(ct);
var screen = await CdpComputer.CreateAsync(browser.CdpSession, ct: ct);
// client: Claude on AnthropicClient (direct or Vertex), or an OpenAI model on OpenAiResponsesClient.
var computer = ComputerTools.ToolFor(client.Model, screen); // NotSupportedException for any other model
var agent = new Agent(new AgentProfile
{
Name = "operator",
Client = client,
SystemPrompt = "You operate a web browser by looking at the screen.",
Tools = [computer],
Images = ComputerRunSettings.Recommended.Images,
});
var result = await agent.RunAsync("Open example.com and tell me the heading.", ct);
The screen is any IComputer: CdpComputer drives a browser tab, and you can implement it over a desktop or a
virtual machine. See computer use. (Usings for these two examples: NovaCore.Agents.Browser,
NovaCore.Agents.Browser.Cdp, NovaCore.Agents.Browser.Tools and NovaCore.Agents.ComputerUse.)
Browser use or computer use?
| Browser use | Computer use | |
|---|---|---|
| The model sees | A text rendering of the page (screenshots optional) | Screenshots |
| It acts by | Element index (a point of the screenshot as a fallback) | Pixel coordinates |
| Models | Any model, any provider | Claude on AnthropicClient, OpenAI models on OpenAiResponsesClient |
| Drives | Chromium | Any screen you implement IComputer for, or a browser tab |
| Cost per step | Low: text, and a screenshot only when something changed | Higher: a screenshot every step |
Start with browser use for anything on the web: forms, research, multi-step flows. Use computer use for desktop
applications, or for web apps the rendering cannot describe. A run uses one or the other: AgentLoop refuses a run
whose tools include both with ArgumentException, so a task that needs both is two runs.
MCP, observability and testing
- MCP.
McpTools.ConnectStdioAsyncandConnectHttpAsyncturn an MCP server's tools intoITools; mark the ones that change things asWriteso they go through approvals (MCP). - Observability. Every run streams events and every client can report usage through an
IUsageSink;NovaCore.Agents.Observability.OpenTelemetryaddsgen_ai.*spans and metrics for model calls, runs and sessions (observability). - Testing.
ScriptedLlmClientplays back scripted turns and records requests,EchoLlmClientruns an app with no provider, andCacheAssert.AppendOnlyproves the prompt cache prefix was never rewritten (testing).
What the library promises
- Your transcript. The loop stores nothing. Every message it creates goes to your
OnMessageAppendedcallback, and the loop waits for it before going on. Each message has a stable id, so you can commit it in your own transaction and ignore a replay. - Append-only, so cached by default. Nothing already sent to the model is rewritten. Tool results are cut to size when they are created, never later. Changing context is appended as a new message. The tool list is fixed for a run. Every provider client turns on its prompt cache without your help. The one rewrite is a fold (summary) when the next call would not fit, and it happens only then.
- No lost tool calls. Every tool call gets exactly one result before a run ends, whatever ends it. A call cut
off by the output limit is never run. Malformed arguments are repaired or answered with an error that names the
fields; they are never replaced by
{}. - One account per tree. A run, its folds and every sub-agent draw on one spend; the ceiling is checked before each paid call.
- Cancelled means you cancelled. A timeout or a network fault is a failure (or a retry), never
Cancelled. - Provider state round-trips. Reasoning signatures and encrypted reasoning are replayed unchanged to the provider that produced them and dropped for any other.
Documentation
The pages live in the repository's doc/ folder
(on GitHub).
- Getting started — install, first agent, tools, conversations, approvals, typed results
- The loop —
RunSpec, events, statuses, budget and spend, folds, context, images, cancellation - Tools —
ITool,Tool<T>, kinds, schema, argument repair, results, timeouts, approvals, suspension - Providers — every client, options, compatible profiles, Azure, the facade, catalog and prices
- Caching — why append-only, what each provider does, how to check it
- Hosting —
Agent,AgentSession, delivery kinds, steer and stop, approvals, stores - Decisions — fast routing, triage and pre-screening with probabilities and confidence
- Multi-agent — sub-agents inside a turn,
AgentHostfor agents that message each other - Browser — the browser tools, what the model reads, slow pages, evidence, handing over to a person
- Computer use —
ComputerTools.ToolFor, the native tools, screens, run settings - MCP · Observability
- Testing — scripted models, recording, cache assertions
- Migrating from 3.x — every 3.x concept and where it went
- Changelog
Status
Version 4.0.0, a breaking rewrite of 3.x. There is no compatibility layer; see migrating from 3.x.
License
Proprietary. Copyright (c) 2025 NovaCore. All rights reserved — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
NuGet packages (14)
Showing the top 5 NuGet packages that depend on NovaCore.Agents:
| Package | Downloads |
|---|---|
|
NovaCore.Agents.Providers.OpenAI
OpenAI provider for NovaCore.Agents: Chat Completions, Responses, OpenAI-compatible gateways and Azure OpenAI; the Responses client sends OpenAI's native computer tool. |
|
|
NovaCore.Agents.Providers.Anthropic
Anthropic Claude provider for NovaCore.Agents: the Messages API, direct and on Vertex, with automatic cache breakpoints and Claude's native computer tool. |
|
|
NovaCore.Agents.Providers.Google
Google Gemini provider for NovaCore.Agents: the Gemini API and Vertex, with thought-signature round-trip. |
|
|
NovaCore.Agents.BrowserUse
CDP-based browser automation tools for NovaCore.Agents. Parallel DOM+AX+snapshot fetch, enhanced DOM merge, LLM-friendly serialization with stable indices, 12 browser tools, managed or host-supplied browser sessions. |
|
|
NovaCore.Agents.Observability.OpenTelemetry
OpenTelemetry traces and metrics for NovaCore.Agents from the run event stream, hosted sessions and model client calls. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.8 | 52 | 10/10/2026 |
| 4.0.7 | 57 | 10/10/2026 |
| 4.0.6 | 53 | 10/10/2026 |
| 4.0.5 | 50 | 10/10/2026 |
| 4.0.4 | 57 | 10/9/2026 |
| 4.0.3 | 50 | 10/9/2026 |
| 4.0.2 | 70 | 10/9/2026 |
| 4.0.1 | 71 | 10/9/2026 |
| 4.0.0 | 71 | 10/8/2026 |
| 3.6.1 | 159 | 10/5/2026 |
| 3.6.0 | 312 | 9/8/2026 |
| 3.5.9 | 369 | 9/3/2026 |
| 3.5.8 | 204 | 9/3/2026 |
| 3.5.7 | 202 | 9/3/2026 |
| 3.5.6 | 251 | 9/2/2026 |
| 3.5.5 | 196 | 9/2/2026 |
| 3.5.4 | 206 | 9/1/2026 |
| 3.5.3 | 194 | 9/1/2026 |
| 3.5.2 | 247 | 8/31/2026 |
| 3.5.1 | 201 | 8/31/2026 |