🌌 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