onellm
LLM inference and an agent runtime for .NET, in C#. One set of calls over Anthropic, OpenAI, Gemini and OpenAI-compatible servers, a price on every call, and agents, scripts and deciders as files you can run, save and resume.
Open source, MIT or Apache-2.0, made by Recursive AI. Version 1.0.0 is on NuGet.
A quick look
A model is a catalog name; the key comes from the environment. Every call returns its usage and a line-item cost, and an agent is a YAML file run with your C# tools.
The output shown is from a run on 1.0.0 with the library’s own scripted provider, priced from the shipped catalog. Getting started has the whole program.
Getting startedstring answer = await Llm.AskAsync("claude-sonnet", "In one sentence, what is a monad?"); AskResult r = await Llm.GenerateAsync("gpt-6-luna", "Name three prime numbers.", []); Console.WriteLine($"{r.Text} [{r.Usage?.InputTokens} in, " + $"{r.Usage?.OutputTokens} out, {r.Cost.Total}]"); // 2, 3 and 5. [13 in, 7 out, 0.0000048] // agents/clerk.yaml names get_docket, a [Tool] method AgentResult a = await Llm.RunAgentAsync("agents/clerk.yaml", new Dictionary<string, object?> { ["caseNo"] = "24-1234" }); // Completed: Docket 24-1234 is open. (0.001730)
What it does
One set of calls
AskAsync, typed AskAsync<T> through the provider’s native structured output, StreamAsync, Chat and EmbedAsync, over one message model. Streamed events build the same message a whole call returns.
Providers and deployments
Anthropic, OpenAI and Gemini, first-party and on Azure OpenAI / Foundry, Amazon Bedrock and Vertex AI, plus presets for Ollama, vLLM, LM Studio, OpenRouter, Groq, DeepSeek, xAI, Mistral and Together. No cloud SDK. Every row is tested from recorded fixtures; at release a live smoke ran against OpenAI and Gemini only, and Anthropic, Azure, Bedrock and Vertex were not run live.
Cloud deploymentsA price on every call
Pricing is catalog data you can layer and override, with source URLs and asOf dates. Every result, tool call and instance carries decimal line items; an unpriced model costs zero with a warning, never a guess. Spend caps are checked before a call is sent.
Agents
The tool loop, with parallel calls returned in call order, approvals that survive a restart, steering, sub-agents, monitors and context strategies. Tools are C# methods marked [Tool]; a source generator writes the schema and an invoker with no reflection.
Scripts and deciders
A .flow file is prompts in order, one call each, written in Go’s text/template language. A decider asks typed choice, score and yes/no questions on TypeSafe Jev, OpenAI Decisions or any chat model.
The host grants, not the file
Loading a definition never grants anything. The default is files under the working directory only; the host adds file roots, shell commands and network hosts. Sub-agents get at most their parent’s grants.
CapabilitiesEvery run is saved
Each call is an instance with its messages, usage and cost, kept in memory, as readable YAML files, in OneLite or through Entity Framework Core, so a chat or an agent can be listed, forked and resumed. JSONL and event record sinks, and OpenTelemetry GenAI spans and metrics.
Stores and sinksMicrosoft.Extensions.AI, both ways
OneLLM models as IChatClient, IEmbeddingGenerator and the speech and image clients, with cost in AdditionalProperties; any IChatClient as a OneLLM provider; AIFunction and ITool in both directions.
The onellm tool
run, chat, instances, cost, catalog and examples from a shell, with grants as explicit flags and eight example agents built in.
Speed, plainly, and what was tested live
The project’s own measurements for 1.0 (not an external audit), with their method on the results page.
- The agent loop is slower than the fastest managed reference, by a factor of 7.92, by design. An eleven-turn run on the scripted provider takes 78.2 µs and 56.8 KB, or 7.1 µs and 5.2 KB per turn. In the results page’s words: “That is above the fastest managed reference by a factor of 7.92, because every OneLLM run is a persisted instance with a snapshot, priced line items and events for each turn.”
- Requests and streams, against a local mock server so the numbers are client code, not a network: a whole turn with a 1,000-token history in 35.9–50.0 µs; a 2,000-event stream read in 610.7–813.7 µs, depending on the provider.
- Conformance is from recorded fixtures. In the results page’s words: “Each feature of each provider, on each deployment that has one, is replayed from recorded fixtures: the request bytes OneLLM sends and the result it parses are both checked.” 217 fixture files, 0 failed.
- Live runs. A smoke against each real API under hard spend caps passed 8 of 8 on OpenAI and 7 of 7 on Gemini. Anthropic was “Not run: no API key was available for the release check”; Azure OpenAI / Foundry, Amazon Bedrock and Vertex AI were not run, for want of an account, and are “covered by recorded fixtures” only.
- Cost and parity. Cost agrees with the reference calculator to the cent on 1,260 of 1,260 usages; on 12.86 million generated templates, the template engine and Go’s
text/templatedisagreed 124 times: 6 fixed, 118 documented differences.
Known gaps at 1.0.0
- No live Anthropic, Azure, Bedrock or Vertex run. Those rows are tested from recorded fixtures (and, for Bedrock and Vertex, the published SigV4 and JWT test vectors) only.
- Compatible-server quirks. From the OpenAI notes: “The quirks for Mistral and DeepSeek, the vLLM default port and reasoning-field names are recorded from the docs only partly and are to be checked against live servers.”
- Token counts. “Core ships no local tokenizer”: a count comes from the provider’s endpoint when one exists, otherwise from a calibrated estimate.
- Pricing. “Code-interpreter container sessions are not priced yet.”
- Grants. From the capabilities page: “Not covered on any platform: hard links (see above), a detached process that survives its parent, and an allow-listed program that is itself an interpreter.”
Status and packages
- Core
RecursiveAI.OneLlm: provider clients and deployments, the message model, catalog and pricing, templating, the runtime, agents, tools and their generator, deciders, file and memory stores, JSONL and event sinks, OpenTelemetry. Depends on OneYaml and OneImage; no native code. - Web
RecursiveAI.OneLlm.Web: thefetch_webpage_markdowntool, on OneHtml. - JavaScript
RecursiveAI.OneLlm.JavaScript: JavaScript tools, hooks and decider logic in a sandbox, andrun_javascript, on OneEcma. - Extensions.AI
RecursiveAI.OneLlm.Extensions.AI: the Microsoft.Extensions.AI bridge, both ways. - EF Core
RecursiveAI.OneLlm.EntityFrameworkCore: an instance store and a record sink on yourDbContext. - OneLite
RecursiveAI.OneLlm.OneLite: an instance store and a record sink on a OneLite file. - Tool
RecursiveAI.OneLlm.Cli, theonellmcommand:dotnet tool install -g RecursiveAI.OneLlm.Cli. - Status
1.0.0, all seven packages on one version. From the changelog: “The first public release.”
- .NET
.NET 10, C#. Trim and NativeAOT safe on the main paths: the sample apps publish with 0 warnings and run on Windows x64, Linux x64 and arm64, and macOS arm64. MIT or Apache-2.0.
Go further
OneLLM is unaffiliated with the onellm package on PyPI and with the OneLLM research model.