EnerOS v0.21.0 Release Notes
Release Date: June 22, 2025 Codename: Swarm Git Tag: v0.21.0 Support Status: Stable Total Crates: 48 (6 new) Test Cases: 6100+ (700+ new)
Overview
EnerOS v0.21.0 “Swarm” is the first version of EnerOS’s “Multi-Agent Collaboration” phase, focusing on Multi-Agent Collaboration. Prior to this version, EnerOS’s Agent runtime could support single Agents completing tasks such as dispatch, inspection, and trading, but real-world power system business scenarios often require dozens or even hundreds of Agents working collaboratively—for example, a provincial dispatch center might simultaneously run 200+ Agents covering generation dispatch, load forecasting, renewable energy integration, fault localization, and inspection scheduling. v0.21.0 brings “Multi-Agent Collaboration” from the application layer down to a kernel first-class capability.
This version introduces a complete multi-agent collaboration framework: Agent Communication Protocol (ACP), Task Dispatcher, Negotiation Protocol, and Collective Decision engine. Agents are no longer isolated processes but form an orchestrable, observable, and governable “Swarm.” The swarm can automatically form collaborative relationships based on grid topology—for example, when a line fault occurs, the fault localization Agent, isolation Agent, load transfer Agent, and inspection Agent automatically form a temporary collaboration group based on electrical connectivity, automatically disbanding after fault handling is complete.
The core design philosophy of v0.21.0 is “grid topology determines collaboration topology”—Agent collaboration relationships are not hard-coded by developers but dynamically derived from the grid’s electrical connectivity, equipment jurisdiction, and safety responsibility boundaries. This gives collaboration electrical semantics: when topology changes (switch operations, equipment commissioning/decommissioning), Agent collaboration relationships automatically rebalance.
Key Metrics
| Metric | Value | Description |
|---|---|---|
| Collaborative Agent scale | 1-1024 | Single cluster support |
| Agent communication latency P99 | 180μs | Same-node shared memory |
| Task dispatch latency P99 | 850μs | Same node |
| Negotiation latency | < 50ms | 3-node PBFT |
| Collective decision throughput | 120K/s | Single cluster |
| New Crates | 6 | Collaboration-related |
| New tests | 700+ | Including 80 end-to-end |
New Features
1. Multi-Agent Collaboration Framework
Introduced the eneros-swarm Crate, providing a complete multi-agent collaboration runtime. A Swarm is a logical collection of collaborating Agents with independent lifecycle, shared context, unified task queue, and observable collaboration graph.
Swarm Data Structure
use eneros_swarm::{Swarm, SwarmConfig, SwarmId, AgentRole, Permission};
use eneros_swarm::consensus::ConsensusProtocol;
// Create a swarm
let mut swarm = Swarm::new(SwarmId::from("dispatch-swarm-1"))
.config(SwarmConfig {
max_agents: 64,
task_queue_capacity: 4096,
consensus_protocol: ConsensusProtocol::Pbft,
topology_aware: true,
auto_rebalance: true,
});
// Register Agent roles
swarm.register_role(AgentRole::new("coordinator")
.replicas(1)
.permission(Permission::DispatchCommand))?;
swarm.register_role(AgentRole::new("executor")
.replicas(8)
.permission(Permission::ExecuteCommand))?;
swarm.register_role(AgentRole::new("observer")
.replicas(4)
.permission(Permission::ReadOnly))?;
// Start the swarm
swarm.start().await?;
Automatic Collaboration Topology Building
Swarm automatically builds communication topology between Agents based on grid topology, giving collaboration relationships electrical semantics:
// Automatically build collaboration relationships based on electrical connectivity
swarm.bind_to_topology(&network)?;
// When topology changes (switch operation), collaboration relationships automatically rebalance
network.on_event(TopologyEvent::SwitchOpened(switch_id), |event| {
swarm.rebalance_on_topology_change(event);
});
Comparison with Traditional Approaches
| Dimension | Traditional (Application-layer orchestration) | EnerOS Swarm (Kernel first-class citizen) |
|---|---|---|
| Collaboration relationship source | Developer hard-coded | Topology-derived |
| Topology change response | Service restart | Automatic rebalancing |
| Communication mechanism | External middleware | Kernel shared memory |
| Failover | Manual configuration | Automatic election |
| Observability | Application logs | Collaboration graph + tracing |
2. Agent Communication Protocol (ACP)
Introduced eneros-swarm-acp (Agent Communication Protocol), defining a unified protocol for message exchange between Agents. ACP draws on FIPA-ACL semantics and extends electrical semantic primitives for power scenarios.
Message Types
| Message Type | Semantics | Power Scenario Example |
|---|---|---|
| Request | Request execution | Request switch operation |
| Inform | Notify fact | Notify fault location result |
| Query | Query information | Query bus voltage |
| Propose | Make proposal | Propose load transfer plan |
| Accept | Accept proposal | Accept transfer plan |
| Reject | Reject proposal | Reject out-of-limit plan |
| Subscribe | Subscribe to event | Subscribe to topology changes |
| Coordinate | Coordinate actions | Coordinate multi-Agent isolation |
Message Structure
use eneros_swarm_acp::{AcpMessage, Performative, AgentId};
let msg = AcpMessage::new()
.from(AgentId::from("fault-locator-1"))
.to(AgentId::from("isolator-3"))
.performative(Performative::Inform)
.content(FaultLocation {
bus_id: 42,
distance_km: 3.2,
confidence: 0.97,
})
.ontology("grid-fault")
.reply_by(Duration::seconds(5));
swarm.send(msg).await?;
Transport Layer
ACP supports multiple transport backends, automatically selecting the optimal path based on Agent location:
use eneros_swarm_acp::transport::{Transport, SharedMemory, TcpTransport};
// Same node: shared memory + lock-free queue (180μs)
let local = Transport::SharedMemory(SharedMemory::new()
.ring_size(4096)
.zero_copy(true));
// Cross-node: TCP + Protobuf (2.3ms)
let remote = Transport::Tcp(TcpTransport::new()
.compression(Compression::Zstd)
.tls(TlsConfig::from_file("agent.crt")?));
swarm.set_transport(local, remote);
Transport Performance Comparison
| Transport | Latency P99 | Throughput | Use Case |
|---|---|---|---|
| Shared memory | 180μs | 500K/s | Same node |
| Unix socket | 350μs | 200K/s | Same host cross-process |
| TCP local | 800μs | 100K/s | Same rack |
| TCP cross-node | 2.3ms | 50K/s | Cross-host |
3. Task Decomposition and Dispatch
Introduced eneros-swarm-dispatcher, providing Task Decomposition and Dispatch capabilities. Complex tasks are automatically decomposed into subtasks, selecting appropriate Agents based on electrical semantics, priority, and load.
Task Decomposition
use eneros_swarm_dispatcher::{Dispatcher, Task, Decomposer};
let dispatcher = Dispatcher::new(&swarm);
// Complex task auto-decomposition
let complex_task = Task::new("fault-handling")
.payload(FaultEvent {
bus_id: 42,
fault_type: FaultType::ShortCircuit,
});
let subtasks = Decomposer::decompose(&complex_task)?;
// Decomposed into:
// 1. fault-location
// 2. fault-isolation
// 3. load-transfer
// 4. inspection
for sub in subtasks {
dispatcher.dispatch(sub).await?;
}
Dispatch Strategies
use eneros_swarm_dispatcher::DispatchStrategy;
// Strategy 1: Nearest dispatch (closest electrical distance)
dispatcher.strategy(DispatchStrategy::NearestByElectricalDistance);
// Strategy 2: Load balancing
dispatcher.strategy(DispatchStrategy::LeastLoaded);
// Strategy 3: Affinity dispatch (same region preferred)
dispatcher.strategy(DispatchStrategy::Affinity {
key: "region_id",
sticky: true,
});
// Strategy 4: Priority dispatch
dispatcher.strategy(DispatchStrategy::Priority {
high_priority_agents: vec!["executor-0", "executor-1"],
});
// Dispatch task
let task = Task::new("check-bus-1")
.target(BusId::from(1))
.priority(Priority::High)
.deadline(Duration::seconds(30));
let handle = dispatcher.dispatch(task).await?;
let result = handle.await?;
Dispatch Strategy Performance
| Dispatch Strategy | Scheduling Latency P99 | Throughput | Use Case |
|---|---|---|---|
| Nearest | 850μs | 50K/s | Fault handling |
| Load balancing | 1.2ms | 120K/s | Batch tasks |
| Affinity | 950μs | 80K/s | Regional tasks |
| Priority | 1.5ms | 60K/s | Urgent tasks |
4. Negotiation Mechanism
Introduced eneros-swarm-negotiation, providing multiple negotiation protocols to ensure multi-Agent consensus on critical decisions. Power system critical operations (switch operations, generator output adjustments, load shedding) must undergo negotiation to prevent single-point errors from causing grid incidents.
Negotiation Protocol Selection
use eneros_swarm_negotiation::{Negotiator, Protocol};
// PBFT: 3-7 node small cluster, strong consistency
let negotiator = Negotiator::new(Protocol::Pbft {
n: 3,
f: 0,
timeout: Duration::milliseconds(500),
});
// Raft: 3-9 nodes, CP system
let negotiator = Negotiator::new(Protocol::Raft {
election_timeout: Duration::milliseconds(150),
heartbeat_interval: Duration::milliseconds(50),
});
// Gossip: Large-scale eventual consistency
let negotiator = Negotiator::new(Protocol::Gossip {
fanout: 6,
interval: Duration::milliseconds(100),
});
Critical Operation Negotiation
// Switch operations must undergo negotiation
let proposal = NegotiationProposal::new("open-switch-42")
.payload(Command::OpenSwitch { id: 42 })
.required_quorum(Quorum::TwoThirds)
.timeout(Duration::seconds(5));
match negotiator.propose(proposal).await {
Ok(consensus) => {
ctx.syscall(ExecuteCommand(consensus.command)).await?;
}
Err(NegotiationError::Timeout) => {
log::warn!("Switch operation failed to reach negotiation consensus");
}
}
Negotiation Protocol Comparison
| Protocol | Node Count | Consistency | Latency | Fault Tolerance | Use Case |
|---|---|---|---|---|---|
| PBFT | 3-7 | Strong | < 50ms | f < n/3 Byzantine | Critical operations |
| Raft | 3-9 | Strong | < 100ms | f < n/2 crash | Configuration changes |
| Gossip | Any | Eventual | 100ms-1s | Any partition | State synchronization |
5. Collective Decision
Introduced eneros-swarm-collective, supporting multi-Agent collective decision-making. When multiple Agents propose different solutions (such as multiple load transfer plans), the optimal solution is selected through voting, weighting, auction, and other mechanisms.
Decision Modes
use eneros_swarm_collective::{CollectiveDecision, Voting, Auction};
// Mode 1: Majority voting
let decision = CollectiveDecision::new(Voting::Majority)
.proposals(vec![plan_a, plan_b, plan_c])
.voters(all_agents)
.decide().await?;
// Mode 2: Weighted voting (by Agent weight)
let decision = CollectiveDecision::new(Voting::Weighted)
.proposals(vec![plan_a, plan_b])
.weight("dispatcher", 5.0)
.weight("protection", 3.0)
.decide().await?;
// Mode 3: Auction (highest bidder wins)
let auction = Auction::new("load-transfer-job")
.bidders(executors)
.bid_fn(|agent| agent.estimate_cost(&job))
.settle().await?;
Decision Recording
All collective decisions are persisted for audit, including proposals, votes, results, and timestamps:
// Decision records are traceable
let record = decision.record();
assert!(record.proposals.len() == 3);
assert!(record.winner == "plan_b");
assert!(record.votes_for == 5);
assert!(record.votes_against == 2);
Improvements
- Agent Communication: Changed inter-Agent communication from TCP-based to shared memory + lock-free queue, reducing single-node message latency from 2.3ms to 180μs
- Topology-aware Scheduling: Scheduler now senses electrical island boundaries, avoiding cross-island task dispatch
- Observability: New
eneros-swarm-traceCrate, providing collaboration graph visualization - Failure Detection: Agent heartbeat detection reduced from 5 seconds to 500ms, more timely fault discovery
- Resource Isolation: Each Swarm has independent task queue and memory pool, avoiding mutual interference
Bug Fixes
- Fixed
eneros-agentscheduler deadlock when Agent count exceeds 64 (#2103) - Fixed
eneros-agentmemory leak where Agent context was not cleaned up after heartbeat timeout (#2107) - Fixed
eneros-topologyhigh broadcast latency for topology change events in Swarm mode (#2112) - Fixed
eneros-constraintrace condition during concurrent multi-Agent validation (#2118) - Fixed
eneros-timeseriestimezone handling error in aggregation queries (#2120)
Breaking Changes
Agent::runsignature change: Newswarm_ctx: &SwarmContextparameter; original signature migrated toAgent::run_standaloneDispatcher::dispatchreturn type: Changed fromResult<TaskResult>toResult<TaskHandle>, requires.awaitto get resultConsensusEnginerename: Unified toNegotiator, original name retained as alias until v0.25.0
Upgrade Guide
Upgrading from v0.20.0 to v0.21.0:
- Run
cargo update -p eneros-swarm - Replace
Agent::runcalls withAgent::run_standalone, or migrate to Swarm mode - Update
Dispatcher::dispatchcalls to adapt to newTaskHandlereturn type - Refer to
docs/migration/v0.21.0.mdfor detailed migration steps
Acknowledgments
Thanks to the 12 contributors who participated in this version’s development, with special thanks to the scheduling algorithm, consensus protocol, and communication transport working groups for their hard work.