UtilityAi.Maf 1.4.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package UtilityAi.Maf --version 1.4.5
                    
NuGet\Install-Package UtilityAi.Maf -Version 1.4.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="UtilityAi.Maf" Version="1.4.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="UtilityAi.Maf" Version="1.4.5" />
                    
Directory.Packages.props
<PackageReference Include="UtilityAi.Maf" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add UtilityAi.Maf --version 1.4.5
                    
#r "nuget: UtilityAi.Maf, 1.4.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package UtilityAi.Maf@1.4.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=UtilityAi.Maf&version=1.4.5
                    
Install as a Cake Addin
#tool nuget:?package=UtilityAi.Maf&version=1.4.5
                    
Install as a Cake Tool

🧠 UtilityAI Framework (.NET 8)

NuGet .NET 8 Tests License

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

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
var intent = UserIntent.ForGoal("my-goal");
await orchestrator.RunAsync(intent, 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());

Learn more β†’


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(intent, maxTicks: 10, ct, sink: new DashboardSink(dashboardState));

Navigate to http://localhost:5000/utilityai/dashboard to inspect scores, override priors/temperatures, and step through ticks.

Dashboard documentation β†’


πŸ§ͺ 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

Testing patterns β†’


πŸ“¦ 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


🎯 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!

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for your changes
  4. Ensure all tests pass (dotnet test)
  5. 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


<p align="center"> <sub>Built with ❀️ for the AI agent community</sub> </p>

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed