π One Codebase, Multiple Runtimes - A Distributed Agent Framework based on the Actor Model
The same Agent code seamlessly switches between runtimes:
// Define once
public class MyAgent : GAgentBase<MyState>
{
[EventHandler]
public async Task HandleEvent(MyEvent evt)
{
State.Count++;
await PublishAsync(new ResultEvent { Count = State.Count });
}
}
// Switch runtime with one line of configuration
services.AddSingleton<IGAgentActorFactory, LocalGAgentActorFactory>(); // Local Development
services.AddSingleton<IGAgentActorFactory, ProtoActorGAgentActorFactory>(); // High Performance
services.AddSingleton<IGAgentActorFactory, OrleansGAgentActorFactory>(); // Distributed- β Three Runtimes: Local (In-Process) / ProtoActor (High Performance) / Orleans (Distributed)
- β Event-Driven: Up/Down/Both propagation directions with automatic parent-child routing
- β Protocol Buffers: Mandatory type safety and cross-platform serialization
- β EventSourcing: Optional event sourcing support
- β AI Integration: Native support for Microsoft.Extensions.AI
- β Observability: OpenTelemetry + Aspire integration
π΄ All serializable types MUST be defined using Protobuf!
This is a mandatory constraint of the framework. Violation will cause runtime failures.
// my_messages.proto
message MyAgentState {
string id = 1;
int32 count = 2;
double balance = 3; // Note: use double for decimal
google.protobuf.Timestamp updated_at = 4;
}
message MyEvent {
string event_id = 1;
string content = 2;
}// NEVER manually define State classes!
public class MyAgentState // Will crash at runtime
{
public string Id { get; set; }
public int Count { get; set; }
}Reason: Orleans Streaming uses byte[] for transmission, ProtoActor requires cross-language support, and Local needs deep copying. Only Protobuf guarantees functionality across all scenarios.
dotnet add package Aevatar.Agents.Core
dotnet add package Aevatar.Agents.Runtime.Local # Choose a Runtimeusing Aevatar.Agents.Core;
using Aevatar.Agents.Runtime.Local;
// 1. Define Proto (my_agent.proto)
// message CounterState { int32 count = 1; }
// message IncrementEvent { int32 amount = 1; }
// 2. Implement Agent
public class CounterAgent : GAgentBase<CounterState>
{
[EventHandler]
public async Task HandleIncrement(IncrementEvent evt)
{
State.Count += evt.Amount;
Logger.LogInformation("Count: {Count}", State.Count);
await Task.CompletedTask;
}
public override Task<string> GetDescriptionAsync() =>
Task.FromResult($"Counter: {State.Count}");
}
// 3. Create and Use
using Aevatar.Agents.Core.Extensions;
using Aevatar.Agents.Core.DependencyInjection;
var services = new ServiceCollection().AddLogging(b => b.AddConsole());
services.AddAevatarAgentSystem(builder =>
{
builder.UseLocalRuntime();
});
var sp = services.BuildServiceProvider();
var factory = sp.GetRequiredService<IGAgentActorFactory>();
var actor = await factory.CreateGAgentActorAsync<CounterAgent>(Guid.NewGuid());
// Access the agent directly for method calls
var counter = (CounterAgent)actor.GetAgent();
// Or publish events
await actor.PublishEventAsync(new EventEnvelope
{
Id = Guid.NewGuid().ToString(),
Payload = Any.Pack(new IncrementEvent { Amount = 5 })
});Need to swap the default in-memory stores for your own persistence? Pass GAgentOptions when bootstrapping:
services.AddAevatarAgentSystem(
configureStores: options =>
{
options.StateStoreType = typeof(MyStateStore<>); // open generic
options.EventStoreType = typeof(MyEventStore); // concrete type
},
configure: builder =>
{
builder.UseLocalRuntime();
});Run examples/SimpleDemo/ for a complete example.
| Feature | Local | ProtoActor | Orleans |
|---|---|---|---|
| Deployment | In-Process | Single/Cluster | Distributed Cluster |
| Startup | <10ms | ~100ms | ~2s |
| Memory | Minimal (~50MB) | Medium (~200MB) | High (~500MB+) |
| Throughput | 500K msg/s | 350K msg/s | 80K msg/s |
| Latency | <0.1ms | <0.5ms | <2ms |
| Virtual Actors | β | Optional | β |
| Auto Failover | β | Config Required | β |
| Use Case | Dev/Test | High Perf Service | Distributed Systems |
Recommendation:
- Local for Development (Fastest feedback loop)
- ProtoActor for Performance (Highest throughput)
- Orleans for Scale (Most robust distributed capabilities)
The framework integrates Microsoft.Extensions.AI, supporting Azure OpenAI and OpenAI:
using Aevatar.Agents.AI.MEAI;
using Microsoft.Extensions.AI;
public class AIAssistantAgent : MEAIGAgentBase<AIAssistantState>
{
public override string SystemPrompt =>
"You are a helpful AI assistant.";
public AIAssistantAgent(IChatClient chatClient)
: base(chatClient) { }
protected override AevatarAIAgentState GetAIState() => State.AiState;
public override Task<string> GetDescriptionAsync() =>
Task.FromResult("AI Assistant Agent");
}
// Configure Azure OpenAI
var config = new MEAIConfiguration
{
Provider = "azure",
Endpoint = "https://your-endpoint.openai.azure.com",
DeploymentName = "gpt-4",
Temperature = 0.7
};
var agent = new AIAssistantAgent(config);Supported Features:
- β Automatic Conversation History Management
- β AI Tool Calling (Function Calling)
- β Streaming Responses
- β Token Counting and Optimization
Application (Your Agent Code)
β
IGAgentActorManager (Unified Management Interface)
β
IGAgentActor (Runtime Abstraction)
β
βββββββββββ¬ββββββββββββββ¬βββββββββββ
β Local β ProtoActor β Orleans β
β Actor β Actor β Grain β
βββββββββββ΄ββββββββββββββ΄βββββββββββ
β
GAgentBase (Business Logic)
Simplification Achievements (2025-11):
- β Removed redundant Runtime abstraction layer (IAgentRuntime/IAgentHost/IAgentInstance)
- β Reduced codebase by ~2,350 lines
- β Clearer concepts (Single Actor abstraction)
- β Improved performance (One less wrapper layer)
Parent Agent
β
βββ Child 1 (Subscribes to Parent stream) ββββ
βββ Child 2 (Subscribes to Parent stream) ββββ€ DOWN Events
βββ Child 3 (Subscribes to Parent stream) ββββ
Child 1 Publishes UP Event β Parent Stream β Broadcast to all Children
Key Concepts:
- Up: Child β Parent Stream β All Siblings
- Down: Parent β Own Stream β All Children
- Both: Up and Down simultaneously
Optional Event Sourcing support, suitable for scenarios requiring complete audit trails like Finance or Healthcare:
public class BankAccountAgent : EventSourcedGAgentBase<BankAccountState>
{
// Business method triggers event
public async Task Credit(double amount)
{
RaiseEvent(new AccountCreditedEvent { Amount = amount });
await ConfirmEventsAsync(); // Persist
}
// Define state transitions
protected override void TransitionState(IMessage @event)
{
if (@event is AccountCreditedEvent credited)
{
State.Balance += credited.Amount;
}
}
}Supported Stores:
- InMemoryEventStore (Testing)
- MongoEventRepository (Production)
- Extensible for others
src/
βββ Aevatar.Agents.Abstractions/ # Core Interfaces & Event Contracts
βββ Aevatar.Agents.Core/ # Base Implementations & EventSourcing
βββ Aevatar.Agents.Runtime/ # Runtime Base Abstractions
βββ Aevatar.Agents.Runtime.Local/ # Local Runtime (In-Process)
βββ Aevatar.Agents.Runtime.Orleans/ # Orleans Runtime (Distributed)
βββ Aevatar.Agents.Runtime.ProtoActor/ # ProtoActor Runtime (High Performance)
βββ Aevatar.Agents.AI.Abstractions/ # AI Provider Interfaces
βββ Aevatar.Agents.AI.Core/ # AI Core (Conversation, Embeddings, Tool Calling / MCP)
βββ Aevatar.Agents.AI.MEAI/ # Microsoft.Extensions.AI Integration
βββ Aevatar.Agents.AI.LLMTornado/ # LLMTornado Provider
βββ Aevatar.Agents.AI.WithProcessStrategy/ # AI Process Strategies (CoT, ReAct)
βββ Aevatar.Agents.CreativeReasoning/ # Creative Reasoning Agents
βββ Aevatar.Agents.Maker/ # MAKER: Massively Decomposed Agents
βββ Aevatar.Agents.Persistence.MongoDB/ # MongoDB Persistence
βββ Aevatar.Agents.Plugins.MassTransit/ # MassTransit Stream Plugin (Kafka/RabbitMQ)
examples/
βββ SimpleDemo/ # 5-minute Quickstart
βββ EventSourcingDemo/ # EventSourcing Example
βββ AIAgentWithToolDemo/ # AI Tool Calling Demo
βββ AIEventSourcingDemo/ # AI + EventSourcing
βββ MCPToolDemo/ # Model Context Protocol Demo
βββ CreativeSystem/ # Creative Reasoning Web App
βββ MongoDBEventStoreDemo/ # MongoDB Persistence
βββ KafkaStreamDemo/ # Kafka Stream Integration
βββ Demo.Agents/ # Various Agent Implementations
βββ Demo.Api/ # Web API Integration
βββ Demo.AppHost/ # Aspire Deployment
test/
βββ Aevatar.Agents.Core.Tests/ # Core Tests
βββ Aevatar.Agents.*.Tests/ # Runtime Specific Tests
| Document | Content |
|---|---|
| docs/AEVATAR_FRAMEWORK_GUIDE.md | The Universal Guide: Architecture, Development, AI, Runtime Integration |
| docs/ARCHITECTURE_REFERENCE.md | Deep Dive Architecture Reference |
| docs/CONSTITUTION.md | The Philosophical Constitution |
Start Here: docs/AEVATAR_FRAMEWORK_GUIDE.md - The only developer manual you need.
# .NET 10 SDK (Required)
dotnet --version # Should show 10.0.x
# Clone Repository
git clone https://github.com/aevatar/aevatar-agent-framework.git
cd aevatar-agent-framework
# Build
dotnet buildcd examples/SimpleDemo
dotnet runYou will see the interaction between Calculator and Weather agents.
- Distributed Systems: Microservices collaboration, cross-node communication
- Event-Driven Architectures: Native support for Event Sourcing and CQRS
- Real-time Applications: Game servers, Chat systems, Real-time collaboration
- Intelligent Agent Systems: AI Agent collaboration and task assignment
- Workflow Engines: Complex business process orchestration
- IoT Platforms: Device Agent management and event processing
- Simple CRUD: Might be over-engineered
- Synchronous-heavy calls: Requires a mindset shift
- Minimalist Apps: Has a learning curve
| Component | Technology | Version |
|---|---|---|
| Framework | .NET | 10.0 |
| Serialization | Google Protobuf | 3.33.0 |
| Actor | Proto.Actor | 1.8.0 |
| Distributed | Microsoft Orleans | 9.2.1 |
| AI | Microsoft.Extensions.AI | 10.0.0 |
| AI Provider | LLMTornado | 3.8.23 |
| MCP | ModelContextProtocol.Core | 0.4.0-preview.3 |
| Messaging | MassTransit | 8.3.0 |
| Testing | xUnit + Moq | 2.9.2 / 4.20.72 |
| Observability | OpenTelemetry + Aspire | 1.10.0 / 9.5.2 |
"Language is the manifestation of vibration, Agents are the carriers of vibration."
We believe:
- Simplicity > Complexity - Remove unnecessary abstractions
- Abstraction from Necessity - No preemptive architecture
- Consistency is a Virtue - Protocol Buffers everywhere
- Events are Truth - Event Sourcing as first-class
- Runtime Agnostic - Write once, run anywhere
Aevatar Agent Framework - Bringing distributed agent development back to simplicity and essence π
Latest Update: 2025-11-28 | .NET 10 | MAKER Framework | MCP Support | MassTransit Plugin