Universal.Operative.Sdk
6.1.3
dotnet add package Universal.Operative.Sdk --version 6.1.3
NuGet\Install-Package Universal.Operative.Sdk -Version 6.1.3
<PackageReference Include="Universal.Operative.Sdk" Version="6.1.3" />
<PackageVersion Include="Universal.Operative.Sdk" Version="6.1.3" />
<PackageReference Include="Universal.Operative.Sdk" />
paket add Universal.Operative.Sdk --version 6.1.3
#r "nuget: Universal.Operative.Sdk, 6.1.3"
#:package Universal.Operative.Sdk@6.1.3
#addin nuget:?package=Universal.Operative.Sdk&version=6.1.3
#tool nuget:?package=Universal.Operative.Sdk&version=6.1.3
About
Universal.Operative.Sdk is the shared kernel for the Universal.Operative.Sdk family: the provider-neutral content model (Block and its subtypes, Source, Citation), the tool-calling contract (ITool, Tool<TArgs>, ToolResult, ToolDefinition, ToolChoice), the canonical dispatch boundary (ToolCallDispatcher, IToolCallHook), token accounting (Usage, ITokenEstimator), and cross-cutting infrastructure (IDiagnosticSink). It also ships a baseline tool set (Read, Write, Edit, Glob, Grep, a shell, and TodoWrite) and an alternate coding set (Read, Glob, Grep, shell, apply_patch, and update_plan).
None of this assumes a particular execution model — it's reused unchanged by both Universal.Operative.Sdk.Discrete (turn-based: Conversation, Engine, Operative) and Universal.Operative.Sdk.Realtime (live duplex sessions). Install this package alongside whichever of those two matches what you're building; you won't normally install it alone.
How to Use
Installation
dotnet add package Universal.Operative.Sdk
dotnet add package Universal.Operative.Sdk.Discrete # turn-based agents
# or
dotnet add package Universal.Operative.Sdk.Realtime # duplex-stream / voice agents
Core concepts
Block— the provider-neutral content unit (TextBlock,ImageBlock,AudioBlock,DocumentBlock,VideoBlock,ToolCallBlock,ToolResultBlock,ReasoningBlock,RefusalBlock,ServerToolUseBlock/ServerToolResultBlock,RawJsonBlock). Both execution models build their message/event shapes out of these.Source(Base64Source,UrlSource,FileIdSource,TextSource,ContentSource) backs any media-bearing block;Citation(DocumentCitation,UrlCitation) attaches source attribution to aTextBlock.ITool/Tool<TArgs>— a callable the model can invoke. SubclassTool<TArgs>with a typed argument record and aDefinitionwhoseParametersschema is generated straight from that record viaBuildParametersSchema(), so the schema the model sees and the typeExecuteAsyncdeserializes into can't drift apart; the base class handles (de)serialization and turns malformed arguments into a model-readable error instead of an exception. SeeTools/BaselineToolSet.csandTools/FileSystem/GlobTool.csfor worked examples.ToolResult— a tool's output: aBlocklist plusIsError. FactoriesText,Json<T>,Image; implicit conversions fromstring/Block.ToolDefinition— a tool's name, description, and JSON Schema parameters, as sent to a provider;ToolChoice(Auto/Required/None/Tool) controls whether/which tool the model must call.Usage— token accounting (InputTokens,OutputTokens, provider-specificExtensions), reused by both a turn-basedMessage.Usageand a realtime session's usage events.ITokenEstimator(default:CharHeuristicTokenEstimator) estimates the token footprint of aBlock/text for budget-aware transformers.IDiagnosticSink— a seam for the SDK to surface internal notices (a dropped stream block, an abandoned tool call) without taking a dependency on any particular logging library.
Tool dispatch hooks
ToolCallDispatcher is the provider-neutral execution boundary shared by turn-based engines, callback-driven adapters, and realtime sessions. It enforces the exact per-model-call tool allowlist, runs before/after hooks, routes requested background work, applies tool-specific/default/capped timeouts, and reports abandoned faults through IDiagnosticSink. Scheduling, concurrency gates, and lifecycle events remain owned by the caller.
A before hook may rewrite ToolCallExecution.Call or set Result to veto execution; an after hook may inspect or replace a completed result. IToolCallHookContext.Scope provides state shared by calls in the same host-defined scope. Setting ToolCallExecution.TurnTerminationReason asks a turn-based host to stop after recording the call result.
public sealed class AuditHook : IToolCallHook
{
public Task<ToolCallHookResult?> InvokeAsync(
IToolCallHookContext context,
CancellationToken cancellationToken = default)
{
Console.WriteLine($"{context.Stage}: {context.Execution.Call.Name}");
return Task.FromResult<ToolCallHookResult?>(null);
}
}
In version 6 these contracts live in Universal.Operative.Sdk, not Universal.Operative.Sdk.Discrete, because they apply equally to discrete and realtime execution.
Writing a custom tool
using System.ComponentModel;
using System.Text.Json.Serialization;
using Universal.Operative.Sdk.Tools;
public sealed class WeatherTool : Tool<WeatherTool.Args>
{
public override string Name => "get_weather";
public override bool IsConcurrencySafe => true;
public override ToolDefinition Definition { get; } = new()
{
Name = "get_weather",
Description = "Get the current weather for a city.",
Parameters = BuildParametersSchema(),
};
public sealed record Args
{
[JsonPropertyName("city")]
[Description("The city to get the weather for.")]
public required string City { get; init; }
}
protected override async Task<ToolResult> ExecuteAsync(Args args, CancellationToken cancellationToken)
=> ToolResult.Json(new { city = args.City, tempF = 72 });
}
BuildParametersSchema() reflects over Args: [JsonPropertyName] controls each parameter's wire name, [Description] becomes the text the model sees for it, and required string/[Required] marks it mandatory. Use a real C# enum (not a loosely-typed string) for any parameter with a closed set of valid values. Parameters is a Universal.Common.Json.JsonSchema, so a hand-authored schema still works when reflection can't express the shape you need (e.g. oneOf/$ref). IsConcurrencySafe = true marks a read-only tool as safe to run in parallel with other calls in the same turn/session; mutating tools default to false.
A tool whose work can outlive a single call implements IBackgroundTool (most conveniently via BackgroundTool<TArgs>) — see ShellTool for a worked example.
Model-oriented tool sets
CodingToolSet.Create() returns portable implementations of Read, Glob, Grep, shell, apply_patch, and update_plan. Every provider can expose them as ordinary function tools. Adapters may recognize their semantic ToolDefinition.Kind and promote them to native tools.
using Universal.Operative.Sdk.Tools.Coding;
IReadOnlyList<ITool> tools = CodingToolSet.Create(new CodingToolSet.Options
{
WorkingDirectory = workspace,
});
HTTP proxy tools
A tool that just calls an external REST API can subclass HttpProxyTool<TArgs> instead of hand-rolling ExecuteAsync — it owns the build → send → format template; a subclass overrides BuildRequestAsync and, optionally, FormatResponseAsync. HttpClientProxyTool<TArgs> is the plain-HttpClient implementation. Pair this with Universal.Operative.Sdk.Http's HttpServiceClientProxyTool<TServiceClient, TArgs> when the target API already has a Universal.Common.Net.Http.HttpServiceClient.
References
ReferenceTool fetches whatever content a reference URI points to, via a registered IReferenceResolver (InMemoryReferenceResolver is the built-in default). It's deliberately generic — the tool carries no opinion about what a reference is; it only resolves a URI to IReadOnlyList<Block> content.
Capability catalogs
When an application owns more tools than it wants to publish on every model request, group related tools into immutable capability packs:
using Universal.Operative.Sdk.Tools;
ToolPack documents = new(
new ToolPackDescriptor
{
Id = "documents",
Name = "Documents",
Description = "Creates, edits, and renders documents.",
Aliases = ["word document", "report"],
Actions = ["create", "edit", "render"],
FileExtensions = [".docx"],
},
[inspectTool, editTool, renderTool]);
ToolCatalog catalog = new([documents, presentations]);
IToolPackResolver is the policy seam that selects relevant packs. LexicalToolPackResolver is the deterministic built-in implementation; applications can replace it with semantic search, authorization-aware routing, or another strategy.
A compact catalog summary can tell a model which capabilities may be discovered without including every full tool schema:
IToolCatalogSummarizer summarizer = new ConciseToolCatalogSummarizer();
string capabilitySummary = await summarizer.SummarizeAsync(
new ToolCatalogSummaryRequest
{
Catalog = catalog,
MaximumCharacters = 2_000,
});
The built-in summary lists pack names, stable identifiers, and truncated descriptions in registration order. Implement IToolCatalogSummarizer for a different token budget, localization, permission-aware redaction, or grouping. Summarization is intentionally separate from resolution and prompt composition: the host decides where and when the summary belongs in its model instructions.
License
Free for noncommercial use under the Universal.Operative Noncommercial License. Source is closed; commercial use requires a separate license from Andrew Ong.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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
- Universal.Common.Json (>= 1.10.0)
-
net8.0
- Universal.Common.Json (>= 1.10.0)
NuGet packages (35)
Showing the top 5 NuGet packages that depend on Universal.Operative.Sdk:
| Package | Downloads |
|---|---|
|
Universal.Operative.Sdk.Discrete
Turn-based agent runtime for Universal.Operative.Sdk: Conversation/Message, IModel, Engine, and Operative. |
|
|
Universal.Operative.Sdk.Tavily
Tavily-backed web search and web fetch tools for the Universal.Operative.Sdk. |
|
|
Universal.Operative.Sdk.Discrete.OpenAI
OpenAI Chat Completions and Responses API adapters for Universal.Operative.Sdk.Discrete. |
|
|
Universal.Operative.Sdk.Discrete.Anthropic
Anthropic Messages API adapter for Universal.Operative.Sdk.Discrete. |
|
|
Universal.Operative.Sdk.Discrete.Anthropic.ClaudeAgentSdk
Claude Agent SDK model adapter for Universal.Operative.Sdk.Discrete. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.3 | 558 | 10/2/2026 |
| 6.1.2 | 1,170 | 9/7/2026 |
| 6.1.1 | 142 | 9/5/2026 |
| 6.0.3 | 330 | 9/4/2026 |
| 6.0.2 | 302 | 9/3/2026 |
| 6.0.1 | 328 | 9/2/2026 |
| 6.0.0 | 868 | 9/1/2026 |
| 5.2.0 | 778 | 8/26/2026 |
| 5.1.1 | 125 | 8/25/2026 |
| 5.1.0 | 289 | 8/24/2026 |
| 5.0.1 | 546 | 8/19/2026 |
| 5.0.0 | 422 | 8/12/2026 |
| 4.2.0 | 262 | 8/5/2026 |
| 4.1.3 | 136 | 8/4/2026 |
| 4.1.2 | 148 | 7/31/2026 |
| 4.1.1 | 141 | 7/31/2026 |
| 4.1.0 | 220 | 7/30/2026 |
| 4.0.0 | 371 | 7/28/2026 |
| 3.3.0 | 146 | 7/28/2026 |
| 3.2.0 | 369 | 7/27/2026 |
Preserve tool kinds and provider extension metadata when renaming tools.