feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
// Type-state machine for agent lifecycle
|
|
|
|
|
// Ensures safe state transitions at compile time
|
|
|
|
|
|
2026-01-11 21:46:08 +00:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2026-01-11 21:46:08 +00:00
|
|
|
|
|
|
|
|
use crate::messages::TaskAssignment;
|
|
|
|
|
use crate::registry::AgentMetadata;
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
|
|
|
|
|
/// Agent states - compile-time enforced state machine
|
|
|
|
|
/// Initial state: Agent is idle
|
|
|
|
|
pub struct Idle;
|
|
|
|
|
|
|
|
|
|
/// Task assigned state
|
|
|
|
|
pub struct Assigned {
|
|
|
|
|
pub task: TaskAssignment,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Executing state
|
|
|
|
|
pub struct Executing {
|
|
|
|
|
pub task: TaskAssignment,
|
|
|
|
|
pub started_at: DateTime<Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Completed state
|
|
|
|
|
pub struct Completed;
|
|
|
|
|
|
|
|
|
|
/// Failed state
|
|
|
|
|
pub struct Failed {
|
|
|
|
|
pub error: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Execution result containing outcome data
|
|
|
|
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
|
|
|
pub struct ExecutionResult {
|
|
|
|
|
pub output: String,
|
|
|
|
|
pub input_tokens: u64,
|
|
|
|
|
pub output_tokens: u64,
|
|
|
|
|
pub duration_ms: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Agent with compile-time state tracking
|
|
|
|
|
pub struct Agent<S> {
|
|
|
|
|
pub metadata: AgentMetadata,
|
|
|
|
|
state: PhantomData<S>,
|
|
|
|
|
result: Option<ExecutionResult>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transitions from Idle state
|
|
|
|
|
impl Agent<Idle> {
|
|
|
|
|
/// Create new idle agent
|
|
|
|
|
pub fn new(metadata: AgentMetadata) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transition to Assigned state
|
|
|
|
|
pub fn assign_task(self, _task: TaskAssignment) -> Agent<Assigned> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transitions from Assigned state
|
|
|
|
|
impl Agent<Assigned> {
|
|
|
|
|
/// Transition to Executing state
|
|
|
|
|
pub fn start_execution(self) -> Agent<Executing> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transitions from Executing state
|
|
|
|
|
impl Agent<Executing> {
|
|
|
|
|
/// Complete execution successfully
|
|
|
|
|
pub fn complete(self, result: ExecutionResult) -> Agent<Completed> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: Some(result),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Fail execution
|
|
|
|
|
pub fn fail(self, _error: String) -> Agent<Failed> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transitions from Completed state
|
|
|
|
|
impl Agent<Completed> {
|
|
|
|
|
/// Get execution result
|
|
|
|
|
pub fn result(&self) -> Option<&ExecutionResult> {
|
|
|
|
|
self.result.as_ref()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transition back to Idle
|
|
|
|
|
pub fn reset(self) -> Agent<Idle> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transitions from Failed state
|
|
|
|
|
impl Agent<Failed> {
|
|
|
|
|
/// Get error message
|
|
|
|
|
pub fn error(&self) -> String {
|
|
|
|
|
match &self.result {
|
|
|
|
|
Some(result) => format!("Error: {}", result.output),
|
|
|
|
|
None => "Unknown error".to_string(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transition back to Idle
|
|
|
|
|
pub fn reset(self) -> Agent<Idle> {
|
|
|
|
|
Agent {
|
|
|
|
|
metadata: self.metadata,
|
|
|
|
|
state: PhantomData,
|
|
|
|
|
result: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use chrono::Utc;
|
|
|
|
|
|
2026-01-11 21:46:08 +00:00
|
|
|
use super::*;
|
|
|
|
|
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
#[test]
|
|
|
|
|
fn test_type_state_transitions() {
|
|
|
|
|
// Create metadata for testing
|
|
|
|
|
let metadata = AgentMetadata {
|
|
|
|
|
id: "test-agent".to_string(),
|
feat(agents): stable identity + hot-reload for zero learning loss on config change
Introduce stable_id = role on AgentMetadata so learning profiles and KG
execution records survive process restarts and hot-reloads. Previously
every Uuid::new_v4() rotation orphaned accumulated expertise.
- registry: add stable_id field (serde default, backward-compatible),
stable_id_or_role() fallback helper, drain_role(), list_roles()
- coordinator: profile lookup and KG writes use stable_id_or_role()
instead of the ephemeral UUID; drain_role() drops Sender to close
mpsc channels after in-flight messages drain; registry_arc() accessor
- executor: agent_id written to KG now uses stable_id_or_role()
- server: reload_agents() drain-and-respawn function; SIGHUP handler
via while sighup.recv().await.is_some(); POST /reload endpoint;
AppState extended with config_path, router, cap_registry
- fix: SIGHUP recv() spin-loop guard (is_some())
- fix: io_other_error clippy lint in vapora-agents, vapora-llm-router,
vapora-workflow-engine (std::io::Error::other instead of Error::new)
- docs: ADR-0040, CHANGELOG entry, README hot-reload section
2026-03-02 22:54:28 +00:00
|
|
|
stable_id: "developer".to_string(),
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
role: "developer".to_string(),
|
|
|
|
|
name: "Test Developer".to_string(),
|
|
|
|
|
version: "0.1.0".to_string(),
|
|
|
|
|
status: crate::registry::AgentStatus::Active,
|
|
|
|
|
capabilities: vec!["coding".to_string()],
|
|
|
|
|
llm_provider: "claude".to_string(),
|
|
|
|
|
llm_model: "claude-sonnet-4".to_string(),
|
|
|
|
|
max_concurrent_tasks: 5,
|
|
|
|
|
current_tasks: 0,
|
|
|
|
|
created_at: Utc::now(),
|
|
|
|
|
last_heartbeat: Utc::now(),
|
|
|
|
|
uptime_percentage: 100.0,
|
|
|
|
|
total_tasks_completed: 0,
|
feat(capabilities): add vapora-capabilities crate with in-process executor dispatch
- New vapora-capabilities crate: CapabilitySpec, Capability trait, CapabilityRegistry
(parking_lot RwLock), CapabilityLoader (TOML overrides), 3 built-ins
(code-reviewer, doc-generator, pr-monitor), 22 tests
- Move AgentDefinition to vapora-shared to break capabilities↔agents circular dep
- Wire system_prompt into AgentExecutor via LLMRouter.complete_with_budget
- AgentCoordinator: in-process task dispatch via DashMap<String, Sender<TaskAssignment>>
- server.rs: bootstrap CapabilityRegistry + LLMRouter from env, spawn executors per capability
- Landing page: 620 tests, 21 crates, Capability Packages feature box
- docs: capability-packages feature guide, ADR-0037, CHANGELOG, SUMMARY
EOF
2026-02-26 16:43:28 +00:00
|
|
|
system_prompt: None,
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Type-state chain: Idle → Assigned → Executing → Completed → Idle
|
|
|
|
|
let agent = Agent::new(metadata.clone());
|
|
|
|
|
let task = TaskAssignment {
|
|
|
|
|
id: "task-1".to_string(),
|
|
|
|
|
agent_id: "test-agent".to_string(),
|
|
|
|
|
required_role: "developer".to_string(),
|
|
|
|
|
title: "Test task".to_string(),
|
|
|
|
|
description: "Test description".to_string(),
|
|
|
|
|
context: "{}".to_string(),
|
|
|
|
|
priority: 1,
|
|
|
|
|
deadline: None,
|
|
|
|
|
assigned_at: Utc::now(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let agent = agent.assign_task(task);
|
|
|
|
|
let agent = agent.start_execution();
|
|
|
|
|
|
|
|
|
|
let result = ExecutionResult {
|
|
|
|
|
output: "Success".to_string(),
|
|
|
|
|
input_tokens: 100,
|
|
|
|
|
output_tokens: 50,
|
|
|
|
|
duration_ms: 1000,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let agent = agent.complete(result);
|
|
|
|
|
assert!(agent.result().is_some());
|
|
|
|
|
|
|
|
|
|
let _agent = agent.reset();
|
|
|
|
|
// agent is now back to Idle state - type system ensures this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_failed_state_transition() {
|
|
|
|
|
let metadata = AgentMetadata {
|
|
|
|
|
id: "test-agent".to_string(),
|
feat(agents): stable identity + hot-reload for zero learning loss on config change
Introduce stable_id = role on AgentMetadata so learning profiles and KG
execution records survive process restarts and hot-reloads. Previously
every Uuid::new_v4() rotation orphaned accumulated expertise.
- registry: add stable_id field (serde default, backward-compatible),
stable_id_or_role() fallback helper, drain_role(), list_roles()
- coordinator: profile lookup and KG writes use stable_id_or_role()
instead of the ephemeral UUID; drain_role() drops Sender to close
mpsc channels after in-flight messages drain; registry_arc() accessor
- executor: agent_id written to KG now uses stable_id_or_role()
- server: reload_agents() drain-and-respawn function; SIGHUP handler
via while sighup.recv().await.is_some(); POST /reload endpoint;
AppState extended with config_path, router, cap_registry
- fix: SIGHUP recv() spin-loop guard (is_some())
- fix: io_other_error clippy lint in vapora-agents, vapora-llm-router,
vapora-workflow-engine (std::io::Error::other instead of Error::new)
- docs: ADR-0040, CHANGELOG entry, README hot-reload section
2026-03-02 22:54:28 +00:00
|
|
|
stable_id: "developer".to_string(),
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
role: "developer".to_string(),
|
|
|
|
|
name: "Test Developer".to_string(),
|
|
|
|
|
version: "0.1.0".to_string(),
|
|
|
|
|
status: crate::registry::AgentStatus::Active,
|
|
|
|
|
capabilities: vec!["coding".to_string()],
|
|
|
|
|
llm_provider: "claude".to_string(),
|
|
|
|
|
llm_model: "claude-sonnet-4".to_string(),
|
|
|
|
|
max_concurrent_tasks: 5,
|
|
|
|
|
current_tasks: 0,
|
|
|
|
|
created_at: Utc::now(),
|
|
|
|
|
last_heartbeat: Utc::now(),
|
|
|
|
|
uptime_percentage: 100.0,
|
|
|
|
|
total_tasks_completed: 0,
|
feat(capabilities): add vapora-capabilities crate with in-process executor dispatch
- New vapora-capabilities crate: CapabilitySpec, Capability trait, CapabilityRegistry
(parking_lot RwLock), CapabilityLoader (TOML overrides), 3 built-ins
(code-reviewer, doc-generator, pr-monitor), 22 tests
- Move AgentDefinition to vapora-shared to break capabilities↔agents circular dep
- Wire system_prompt into AgentExecutor via LLMRouter.complete_with_budget
- AgentCoordinator: in-process task dispatch via DashMap<String, Sender<TaskAssignment>>
- server.rs: bootstrap CapabilityRegistry + LLMRouter from env, spawn executors per capability
- Landing page: 620 tests, 21 crates, Capability Packages feature box
- docs: capability-packages feature guide, ADR-0037, CHANGELOG, SUMMARY
EOF
2026-02-26 16:43:28 +00:00
|
|
|
system_prompt: None,
|
feat: Phase 5.3 - Multi-Agent Learning Infrastructure
Implement intelligent agent learning from Knowledge Graph execution history
with per-task-type expertise tracking, recency bias, and learning curves.
## Phase 5.3 Implementation
### Learning Infrastructure (✅ Complete)
- LearningProfileService with per-task-type expertise metrics
- TaskTypeExpertise model tracking success_rate, confidence, learning curves
- Recency bias weighting: recent 7 days weighted 3x higher (exponential decay)
- Confidence scoring prevents overfitting: min(1.0, executions / 20)
- Learning curves computed from daily execution windows
### Agent Scoring Service (✅ Complete)
- Unified AgentScore combining SwarmCoordinator + learning profiles
- Scoring formula: 0.3*base + 0.5*expertise + 0.2*confidence
- Rank agents by combined score for intelligent assignment
- Support for recency-biased scoring (recent_success_rate)
- Methods: rank_agents, select_best, rank_agents_with_recency
### KG Integration (✅ Complete)
- KGPersistence::get_executions_for_task_type() - query by agent + task type
- KGPersistence::get_agent_executions() - all executions for agent
- Coordinator::load_learning_profile_from_kg() - core KG→Learning integration
- Coordinator::load_all_learning_profiles() - batch load for multiple agents
- Convert PersistedExecution → ExecutionData for learning calculations
### Agent Assignment Integration (✅ Complete)
- AgentCoordinator uses learning profiles for task assignment
- extract_task_type() infers task type from title/description
- assign_task() scores candidates using AgentScoringService
- Fallback to load-based selection if no learning data available
- Learning profiles stored in coordinator.learning_profiles RwLock
### Profile Adapter Enhancements (✅ Complete)
- create_learning_profile() - initialize empty profiles
- add_task_type_expertise() - set task-type expertise
- update_profile_with_learning() - update swarm profiles from learning
## Files Modified
### vapora-knowledge-graph/src/persistence.rs (+30 lines)
- get_executions_for_task_type(agent_id, task_type, limit)
- get_agent_executions(agent_id, limit)
### vapora-agents/src/coordinator.rs (+100 lines)
- load_learning_profile_from_kg() - core KG integration method
- load_all_learning_profiles() - batch loading for agents
- assign_task() already uses learning-based scoring via AgentScoringService
### Existing Complete Implementation
- vapora-knowledge-graph/src/learning.rs - calculation functions
- vapora-agents/src/learning_profile.rs - data structures and expertise
- vapora-agents/src/scoring.rs - unified scoring service
- vapora-agents/src/profile_adapter.rs - adapter methods
## Tests Passing
- learning_profile: 7 tests ✅
- scoring: 5 tests ✅
- profile_adapter: 6 tests ✅
- coordinator: learning-specific tests ✅
## Data Flow
1. Task arrives → AgentCoordinator::assign_task()
2. Extract task_type from description
3. Query KG for task-type executions (load_learning_profile_from_kg)
4. Calculate expertise with recency bias
5. Score candidates (SwarmCoordinator + learning)
6. Assign to top-scored agent
7. Execution result → KG → Update learning profiles
## Key Design Decisions
✅ Recency bias: 7-day half-life with 3x weight for recent performance
✅ Confidence scoring: min(1.0, total_executions / 20) prevents overfitting
✅ Hierarchical scoring: 30% base load, 50% expertise, 20% confidence
✅ KG query limit: 100 recent executions per task-type for performance
✅ Async loading: load_learning_profile_from_kg supports concurrent loads
## Next: Phase 5.4 - Cost Optimization
Ready to implement budget enforcement and cost-aware provider selection.
2026-01-11 13:03:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let agent = Agent::new(metadata);
|
|
|
|
|
let task = TaskAssignment {
|
|
|
|
|
id: "task-1".to_string(),
|
|
|
|
|
agent_id: "test-agent".to_string(),
|
|
|
|
|
required_role: "developer".to_string(),
|
|
|
|
|
title: "Test task".to_string(),
|
|
|
|
|
description: "Test description".to_string(),
|
|
|
|
|
context: "{}".to_string(),
|
|
|
|
|
priority: 1,
|
|
|
|
|
deadline: None,
|
|
|
|
|
assigned_at: Utc::now(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let agent = agent.assign_task(task);
|
|
|
|
|
let agent = agent.start_execution();
|
|
|
|
|
|
|
|
|
|
let agent = agent.fail("API timeout".to_string());
|
|
|
|
|
let _error = agent.error();
|
|
|
|
|
|
|
|
|
|
let _agent = agent.reset();
|
|
|
|
|
// agent is now back to Idle state
|
|
|
|
|
}
|
|
|
|
|
}
|