Skip to main content

feagi_services/traits/
agent_service.rs

1// Copyright 2025 Neuraville Inc.
2// Licensed under the Apache License, Version 2.0
3
4//! Agent management service trait
5//!
6//! This service manages agent registration, heartbeats, and properties.
7//! It interfaces with the Registration Manager in feagi-io for actual
8//! agent lifecycle management and coordination.
9
10use async_trait::async_trait;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
15#[serde(rename_all = "snake_case")]
16pub enum ManualStimulationMode {
17    #[default]
18    Candidate,
19    ForceFire,
20}
21
22/// Result type for agent service operations
23pub type AgentResult<T> = Result<T, AgentError>;
24
25/// Errors that can occur during agent operations
26#[derive(Debug, thiserror::Error)]
27pub enum AgentError {
28    #[error("Agent not found: {0}")]
29    NotFound(String),
30
31    #[error("Registration service unavailable: {0}")]
32    ServiceUnavailable(String),
33
34    #[error("Registration failed: {0}")]
35    RegistrationFailed(String),
36
37    #[error("Invalid agent data: {0}")]
38    InvalidData(String),
39
40    #[error("Internal error: {0}")]
41    Internal(String),
42}
43
44/// Agent registration request
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct AgentRegistration {
47    pub agent_id: String,
48    pub agent_type: String,
49    pub agent_data_port: u16,
50    pub agent_version: String,
51    pub controller_version: String,
52    pub agent_ip: Option<String>,
53    pub capabilities: HashMap<String, serde_json::Value>,
54    pub metadata: Option<HashMap<String, serde_json::Value>>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub chosen_transport: Option<String>, // Agent reports which transport it chose
57}
58
59/// Transport configuration (FEAGI 2.0)
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct TransportConfig {
62    pub transport_type: String,
63    pub enabled: bool,
64    pub ports: HashMap<String, u16>,
65    pub host: String,
66}
67
68/// Agent registration response
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct AgentRegistrationResponse {
71    pub status: String,
72    pub message: String,
73    pub success: bool,
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub transport: Option<HashMap<String, serde_json::Value>>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub rates: Option<HashMap<String, HashMap<String, f64>>>,
78    // FEAGI 2.0: Multi-transport support
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub transports: Option<Vec<TransportConfig>>,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub recommended_transport: Option<String>,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub shm_paths: Option<HashMap<String, String>>,
85    /// Cortical area availability status for agent operations
86    pub cortical_areas: serde_json::Value,
87}
88
89/// Agent properties
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct AgentProperties {
92    pub agent_type: String,
93    pub agent_ip: String,
94    pub agent_data_port: u16,
95    pub agent_router_address: String,
96    pub agent_version: String,
97    pub controller_version: String,
98    pub capabilities: HashMap<String, serde_json::Value>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub chosen_transport: Option<String>, // Transport the agent chose: "zmq", "websocket", "shm", etc.
101}
102
103/// Heartbeat request
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct HeartbeatRequest {
106    pub agent_id: String,
107}
108
109/// Service for managing agents (registration, heartbeats, properties)
110#[async_trait]
111pub trait AgentService: Send + Sync {
112    /// Register a new agent
113    async fn register_agent(
114        &self,
115        registration: AgentRegistration,
116    ) -> AgentResult<AgentRegistrationResponse>;
117
118    /// Record a heartbeat for an agent
119    async fn heartbeat(&self, request: HeartbeatRequest) -> AgentResult<()>;
120
121    /// List all registered agents
122    async fn list_agents(&self) -> AgentResult<Vec<String>>;
123
124    /// Get properties for a specific agent
125    async fn get_agent_properties(&self, agent_id: &str) -> AgentResult<AgentProperties>;
126
127    /// Get shared memory information for all agents
128    async fn get_shared_memory_info(
129        &self,
130    ) -> AgentResult<HashMap<String, HashMap<String, serde_json::Value>>>;
131
132    /// Deregister an agent
133    async fn deregister_agent(&self, agent_id: &str) -> AgentResult<()>;
134
135    /// Trigger manual stimulation for specific cortical areas
136    async fn manual_stimulation(
137        &self,
138        stimulation_payload: HashMap<String, Vec<Vec<i32>>>,
139        mode: ManualStimulationMode,
140    ) -> AgentResult<HashMap<String, serde_json::Value>>;
141
142    /// Set runtime service for sensory injection (optional, implementations can ignore if not needed)
143    /// This allows runtime service to be connected after AgentService is wrapped in Arc
144    fn try_set_runtime_service(
145        &self,
146        _runtime_service: std::sync::Arc<dyn crate::traits::RuntimeService + Send + Sync>,
147    ) {
148        // Default implementation: no-op (for implementations that don't need runtime service)
149    }
150}