UtilityAi.Maf
1.5.2
See the version list below for details.
dotnet add package UtilityAi.Maf --version 1.5.2
NuGet\Install-Package UtilityAi.Maf -Version 1.5.2
<PackageReference Include="UtilityAi.Maf" Version="1.5.2" />
<PackageVersion Include="UtilityAi.Maf" Version="1.5.2" />
<PackageReference Include="UtilityAi.Maf" />
paket add UtilityAi.Maf --version 1.5.2
#r "nuget: UtilityAi.Maf, 1.5.2"
#:package UtilityAi.Maf@1.5.2
#addin nuget:?package=UtilityAi.Maf&version=1.5.2
#tool nuget:?package=UtilityAi.Maf&version=1.5.2
π§ UtilityAI Framework (.NET 8)
A lightweight, modular .NET 8 framework for building AI agent orchestration systems using classic Utility AI decision-making patterns. The framework evaluates and scores candidate actions each tick, executing the highest-utility option based on current context β no hardcoded workflows required.
Don't script workflows β evaluate them.
Table of Contents
- Features
- Quick Start
- Architecture Overview
- Core Features
- Integration Examples
- Dashboard
- Testing
- Project Structure
- Documentation
- Use Cases
- Contributing
- License
β¨ Features
| Category | Highlights |
|---|---|
| Decision Making | Utility-based scoring with response curves (logistic, power, piecewise) |
| LLM Integration | Intent interpretation with rich parameters; self-documenting capability metadata for prompt generation |
| Agent Orchestration | Microsoft Agent Framework (MAF) integration; multi-agent coordination with scoped state |
| Event System | Timestamped event history, type-safe subscriptions, scoped buses |
| Memory | Two-tier memory with automatic archival from EventBus to long-term storage |
| Extensibility | Pluggable sensors, modules, considerations, and selection strategies |
| Tooling | Real-time web dashboard for visualizing proposals, scores, and tick history |
| Observability | Built-in sinks for logging, metrics, and testing |
| Quality | 203+ tests, thread-safe, XML-documented public API |
π Quick Start
Installation
# NuGet (recommended)
dotnet add package UtilityAi
Or clone the repository to explore the source and examples:
git clone https://github.com/mrrasmussendk/UtilityAi.git
cd UtilityAi
dotnet build
dotnet test
Minimal Example
using UtilityAi.Orchestration;
using UtilityAi.Utils;
// 1. Create the event bus (shared state / blackboard)
var bus = new EventBus();
// 2. Configure the orchestrator
var orchestrator = new UtilityAiOrchestrator(bus: bus)
.AddSensor(new MyEnvironmentSensor())
.AddModule(new MyCapabilityModule());
// 3. Run the sense β propose β score β act loop
await orchestrator.RunAsync(maxTicks: 10, CancellationToken.None);
Attribute-Based Registration
Reduce boilerplate with declarative attributes:
[Capability(Priority = 100, Domain = "validation")]
[RequiresFact<TaskQueue>]
[ActiveWhen("priority_mode", "urgent", "balanced")]
public class ValidationModule : ICapabilityModule
{
public IEnumerable<Proposal> Propose(Runtime rt) { /* ... */ }
}
// Auto-discover all modules from the assembly
var orchestrator = new UtilityAiOrchestrator(bus: bus)
.AddSensor(new MySensor())
.DiscoverCapabilities(Assembly.GetExecutingAssembly());
See the Example project for a complete demo comparing manual and attribute-based approaches.
ποΈ Architecture Overview
The framework follows a Sense β Propose β Score β Act loop:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EventBus β
β (Shared state with history & scoping) β
ββββββββββββ²βββββββββββββββββββββββ¬βββββββββββββββββββ
β β
ββββββββ΄βββββββ βββββββΌβββββββ
β Sensors β β Modules β
β (Observe) β β (Propose) β
βββββββββββββββ βββββββ¬βββββββ
β
ββββββββΌβββββββ
β Proposals β
β + Score β
ββββββββ¬βββββββ
β
ββββββββΌβββββββ
βOrchestrator β
β Select Best β
β & Act β
βββββββββββββββ
Key Components
| Component | Purpose | Extensibility |
|---|---|---|
| EventBus | Central state container with history, subscriptions, and scoping | Use as-is or wrap for persistence |
| ISensor | Observe environment and publish facts | Implement for your data sources |
| ICapabilityModule | Propose candidate actions | Implement + use attributes for auto-discovery |
| IConsideration | Score proposals (0.0β1.0) | Implement custom scoring logic |
| IOrchestrationSink | Observe orchestration events | Implement for logging/metrics |
Utility Formula
utility = prior Γ (geometric_mean_of_considerations) ^ temperature
- Prior β base tendency (0β1)
- Considerations β each returns a score in 0β1, combined via geometric mean
- Temperature β >1 sharpens differences, <1 flattens them
π‘ Core Features in Detail
1οΈβ£ LLM Intent Interpretation
Proposals declare what parameters they need; the framework exposes this metadata so an LLM can provide structured responses that drive scoring automatically.
yield return ProposalHelper.For("ticket.create.priority")
.WithDescription("Create high-priority support ticket")
.ForIntent("ticket.create", IntentMatchType.Exact)
.ScoreByIntentParameter("urgency", x => Math.Pow(x, 3), (0, 1),
description: "How urgent the issue is (0=low, 1=critical)")
.UsesIntentParameter("customer_tier", "string",
allowedValues: new[] { "free", "premium", "enterprise" })
.WithAction(async ct => await CreatePriorityTicket(rt, ct));
Flow: Proposals declare parameters β Framework exposes metadata via GetCapabilitiesInfo() β LLM prompt includes parameter specs β LLM returns structured intent β Proposals score automatically β Best action wins.
See the complete Intent-Based Agent example β
2οΈβ£ Event History & Subscriptions
// Timestamped history β perfect for building LLM conversation context
var history = bus.GetHistory<UserMessage>(maxItems: 10);
foreach (var evt in history)
Console.WriteLine($"{evt.Timestamp}: {evt.Value.Text}");
// Type-safe subscriptions β react to events as they happen
using var sub = bus.Subscribe<TaskCompleted>(task =>
logger.LogInformation($"Task {task.Id} completed in {task.Duration}"));
3οΈβ£ Scoped Buses (Multi-Agent State)
Isolate per-agent state while sharing global facts:
var rootBus = new EventBus();
rootBus.Publish(new GlobalConfig("production"));
var agent1Bus = rootBus.CreateScope("agent-1");
var agent2Bus = rootBus.CreateScope("agent-2");
agent1Bus.Publish(new AgentStatus("busy"));
agent2Bus.TryGet<AgentStatus>(out var status); // β Not found (isolated)
agent1Bus.TryGetWithFallback<GlobalConfig>(out var config); // β
Found in parent
4οΈβ£ Memory Management
Two-tier architecture: EventBus (fast, last 100 events per type) + IMemoryStore (long-term, unlimited). The MemorySensor archives old facts automatically.
var memoryStore = new InMemoryStore();
var orchestrator = new UtilityAiOrchestrator(bus: bus)
.AddSensor(new MemorySensor(
store: memoryStore,
archiveThreshold: TimeSpan.FromMinutes(10),
typeof(UserMessage), typeof(AssistantMessage)))
.AddModule(new MyModule());
5οΈβ£ Microsoft Agent Framework (MAF) Integration
Orchestrate MAF agents with utility-based decision-making:
var orchestrator = new UtilityAiOrchestrator(bus: bus)
.AddMafAgentSensor(
new MafAgentRegistration("research", researchAgent),
new MafAgentRegistration("writer", writerAgent))
.AddMafAgent(researchAgent, "research",
considerations: new IConsideration[] { new MafAgentAvailable("research") })
.AddMafAgent(writerAgent, "writer",
considerations: new IConsideration[] { new HasMafAgentResult("research") });
See the MAF example β | MAF Integration Guide β
π Integration Examples
OpenAI
public class OpenAIModule : ICapabilityModule
{
private readonly ChatClient _client;
public OpenAIModule(string apiKey)
=> _client = new ChatClient("gpt-4", apiKey);
public IEnumerable<Proposal> Propose(Runtime rt)
{
var userMsg = rt.Bus.GetOrDefault<UserMessage>();
if (userMsg == null) yield break;
yield return new Proposal(
id: "openai.respond",
cons: new[] { new HasFact<UserMessage>() },
act: async ct =>
{
var history = rt.Bus.GetHistory<UserMessage>(maxItems: 5);
var messages = history.Select(e => new UserChatMessage(e.Value.Text)).ToList();
var response = await _client.CompleteChatAsync(messages, ct);
rt.Bus.Publish(new AssistantMessage(response.Value.Content[0].Text));
});
}
}
The framework also supports Azure OpenAI, Anthropic Claude, and any custom provider via the ILlmProvider abstraction. See the Integration Guide for complete examples.
π Dashboard
An optional web dashboard to visualize proposals, consideration scores, and tick history in real time:
var dashboardState = new DashboardState();
app.MapUtilityAiDashboard(dashboardState);
await orchestrator.RunAsync(maxTicks: 10, ct, sink: new DashboardSink(dashboardState));
Navigate to http://localhost:5000/utilityai/dashboard to inspect scores, override priors/temperatures, and step through ticks.
π§ͺ Testing
The framework is designed for testability. 203 tests cover all core functionality.
[Fact]
public async Task Orchestrator_ChoosesHighestUtility()
{
var bus = new EventBus();
bus.Publish(new UserMessage("test"));
var sink = new TestingSink();
var orch = new UtilityAiOrchestrator(bus: bus)
.AddModule(new MyModule());
await orch.RunAsync( maxTicks: 1, CancellationToken.None, sink);
Assert.Single(sink.ExecutedProposals);
Assert.Equal("my.action", sink.ExecutedProposals[0]);
}
dotnet test
π¦ Project Structure
UtilityAi/
βββ src/
β βββ UtilityAi/ # Core framework (NuGet: UtilityAi)
β βββ Utils/ # EventBus, Runtime
β βββ Orchestration/ # UtilityAiOrchestrator, Extensions
β βββ Sensor/ # ISensor + built-in sensors
β βββ Capabilities/ # ICapabilityModule, Attributes
β βββ Consideration/ # IConsideration + built-in considerations
β βββ Evaluators/ # Response curves (Logistic, Power, etc.)
β βββ Memory/ # IMemoryStore, InMemoryStore, MemorySensor
βββ integrations/
β βββ UtilityAi.Maf/ # Microsoft Agent Framework integration
β βββ UtilityAi.LLM.Abstractions/ # LLM provider abstraction
β βββ UtilityAi.LLM.OpenAI/ # OpenAI provider implementation
βββ examples/
β βββ Example/ # Demo agents (AgentAssistant, SmartHome, ChatBot, Intent)
β βββ Example.Maf/ # MAF integration demo
βββ tools/
β βββ UtilityAi.Dashboard/ # Real-time web dashboard
βββ Tests/ # 203 xUnit tests
βββ docs/ # Architecture, integration, and pattern guides
π Documentation
Getting Started
| Guide | Description |
|---|---|
| Architecture | Framework design, orchestration loop, component roles |
| Integration | Connect to MAF, OpenAI, Anthropic, Azure AI, and more |
| Built-in Components | Reference for all built-in sensors, considerations, and modules |
| Proposal Patterns | Best practices and anti-patterns for building proposals |
| Eligibility vs Considerations | When to use hard gates vs soft scoring |
Examples
| Example | Description |
|---|---|
| Agent Assistant | Multi-strategy conversational AI agent |
| Smart Home | IoT automation balancing comfort, energy, and security |
| LLM ChatBot | Simple OpenAI-powered chatbot |
| Intent-Based Agent | LLM intent interpretation with rich parameters |
| MAF Integration | Microsoft Agent Framework orchestration |
Deep Dives
- Memory System β Long-term storage, querying, and automatic archival
- Sensors Reference β TimeSensor, ConversationHistorySensor, ResourceSensor, MemorySensor
- Considerations Reference β HasFact, CurveSignal, Cooldown, TimeWindow, and more
- Built-in Modules Reference β IdleModule, CleanupModule, StopOnSignalModule
- Dashboard β Real-time orchestration visualization
π― Use Cases
- AI Agent Systems β Coordinate multiple AI agents with shared and isolated state
- LLM-Based Applications β Build context from event history for prompts
- Dynamic Workflows β Let actions emerge from current state instead of hardcoding sequences
- Game AI β Classic utility AI for NPCs and decision-making
- Task Orchestration β Prioritize and execute tasks based on resources and constraints
- IoT / Smart Home β Balance competing objectives (comfort, energy, security)
π€ Contributing
Contributions that improve extensibility, documentation, or add well-tested features are welcome!
- Fork the repository
- Create a feature branch
- Write tests for your changes
- Ensure all tests pass (
dotnet test) - Submit a pull request
For maintainers: see RELEASE.md for the release process.
π License
MIT License β see LICENSE for details.
π Acknowledgments
Built with inspiration from:
- Utility AI pattern from game development
- Blackboard pattern from classical AI
- Java Annotations (Spring Framework, Jakarta EE)
- Modern agent orchestration (Microsoft Agent Framework, Semantic Kernel, AutoGen, LangGraph)
π Support
- π Documentation
- π¬ Issues
- π§ Discussions
<p align="center"> <sub>Built with β€οΈ for the AI agent community</sub> </p>
| 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 was computed. 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. |
-
net8.0
- Azure.AI.Agents.Persistent (>= 1.2.0-beta.8)
- Azure.AI.Projects (>= 1.2.0-beta.5)
- Azure.AI.Projects.OpenAI (>= 1.0.0-beta.5)
- Azure.Identity (>= 1.18.0-beta.2)
- Microsoft.Agents.AI.Abstractions (>= 1.0.0-preview.260212.1)
- UtilityAi (>= 1.5.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.5 | 58 | 2/25/2026 |
| 1.6.3 | 86 | 2/20/2026 |
| 1.6.2 | 39 | 2/20/2026 |
| 1.6.1 | 43 | 2/20/2026 |
| 1.6.0 | 38 | 2/20/2026 |
| 1.5.9 | 41 | 2/20/2026 |
| 1.5.8 | 39 | 2/20/2026 |
| 1.5.7 | 39 | 2/20/2026 |
| 1.5.6 | 36 | 2/20/2026 |
| 1.5.5 | 44 | 2/20/2026 |
| 1.5.4 | 42 | 2/20/2026 |
| 1.5.3 | 36 | 2/20/2026 |
| 1.5.2 | 41 | 2/20/2026 |
| 1.5.1 | 39 | 2/20/2026 |
| 1.5.0 | 37 | 2/20/2026 |
| 1.4.9 | 38 | 2/20/2026 |
| 1.4.8 | 45 | 2/20/2026 |
| 1.4.7 | 40 | 2/20/2026 |
| 1.4.6 | 40 | 2/20/2026 |
| 1.4.5 | 41 | 2/20/2026 |