feat: 引入 AgentRuntimeConfig,重构相关模块以支持运行时配置
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
3111abf4db
commit
716d92a618
@ -1,6 +1,6 @@
|
|||||||
|
use crate::agent::AgentRuntimeConfig;
|
||||||
use crate::bus::ChatMessage;
|
use crate::bus::ChatMessage;
|
||||||
use crate::bus::message::ToolMessageState;
|
use crate::bus::message::ToolMessageState;
|
||||||
use crate::config::LLMProviderConfig;
|
|
||||||
use crate::domain::messages::{ContentBlock, ToolCall};
|
use crate::domain::messages::{ContentBlock, ToolCall};
|
||||||
use crate::observability::{
|
use crate::observability::{
|
||||||
Observer, ObserverEvent, ToolExecutionOutcome, ToolExecutionState, truncate_args,
|
Observer, ObserverEvent, ToolExecutionOutcome, ToolExecutionState, truncate_args,
|
||||||
@ -292,7 +292,7 @@ fn chat_message_to_llm_message(m: &ChatMessage) -> Message {
|
|||||||
/// AgentLoop - Stateless agent that processes messages with tool calling support.
|
/// AgentLoop - Stateless agent that processes messages with tool calling support.
|
||||||
/// History is managed externally by SessionManager.
|
/// History is managed externally by SessionManager.
|
||||||
pub struct AgentLoop {
|
pub struct AgentLoop {
|
||||||
provider_config: LLMProviderConfig,
|
runtime_config: AgentRuntimeConfig,
|
||||||
provider: Box<dyn LLMProvider>,
|
provider: Box<dyn LLMProvider>,
|
||||||
tools: Arc<ToolRegistry>,
|
tools: Arc<ToolRegistry>,
|
||||||
skills: Arc<dyn SkillProvider>,
|
skills: Arc<dyn SkillProvider>,
|
||||||
@ -327,13 +327,14 @@ impl SkillProvider for EmptySkillProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AgentLoop {
|
impl AgentLoop {
|
||||||
pub fn new(provider_config: LLMProviderConfig) -> Result<Self, AgentError> {
|
pub fn new(config: impl Into<AgentRuntimeConfig>) -> Result<Self, AgentError> {
|
||||||
let max_iterations = provider_config.max_tool_iterations;
|
let runtime_config = config.into();
|
||||||
let provider = create_provider(provider_config.clone())
|
let max_iterations = runtime_config.max_tool_iterations;
|
||||||
|
let provider = create_provider(runtime_config.provider.clone())
|
||||||
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
provider_config,
|
runtime_config,
|
||||||
provider,
|
provider,
|
||||||
tools: Arc::new(ToolRegistry::new()),
|
tools: Arc::new(ToolRegistry::new()),
|
||||||
skills: Arc::new(EmptySkillProvider),
|
skills: Arc::new(EmptySkillProvider),
|
||||||
@ -345,15 +346,16 @@ impl AgentLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_tools(
|
pub fn with_tools(
|
||||||
provider_config: LLMProviderConfig,
|
config: impl Into<AgentRuntimeConfig>,
|
||||||
tools: Arc<ToolRegistry>,
|
tools: Arc<ToolRegistry>,
|
||||||
) -> Result<Self, AgentError> {
|
) -> Result<Self, AgentError> {
|
||||||
let max_iterations = provider_config.max_tool_iterations;
|
let runtime_config = config.into();
|
||||||
let provider = create_provider(provider_config.clone())
|
let max_iterations = runtime_config.max_tool_iterations;
|
||||||
|
let provider = create_provider(runtime_config.provider.clone())
|
||||||
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
provider_config,
|
runtime_config,
|
||||||
provider,
|
provider,
|
||||||
tools,
|
tools,
|
||||||
skills: Arc::new(EmptySkillProvider),
|
skills: Arc::new(EmptySkillProvider),
|
||||||
@ -365,16 +367,17 @@ impl AgentLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_tools_and_skill_provider(
|
pub fn with_tools_and_skill_provider(
|
||||||
provider_config: LLMProviderConfig,
|
config: impl Into<AgentRuntimeConfig>,
|
||||||
tools: Arc<ToolRegistry>,
|
tools: Arc<ToolRegistry>,
|
||||||
skills: Arc<dyn SkillProvider>,
|
skills: Arc<dyn SkillProvider>,
|
||||||
) -> Result<Self, AgentError> {
|
) -> Result<Self, AgentError> {
|
||||||
let max_iterations = provider_config.max_tool_iterations;
|
let runtime_config = config.into();
|
||||||
let provider = create_provider(provider_config.clone())
|
let max_iterations = runtime_config.max_tool_iterations;
|
||||||
|
let provider = create_provider(runtime_config.provider.clone())
|
||||||
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
provider_config,
|
runtime_config,
|
||||||
provider,
|
provider,
|
||||||
tools,
|
tools,
|
||||||
skills,
|
skills,
|
||||||
@ -543,10 +546,8 @@ impl AgentLoop {
|
|||||||
tracing::info!(tool = %tool_call.name, args = %args_str, "Calling tool");
|
tracing::info!(tool = %tool_call.name, args = %args_str, "Calling tool");
|
||||||
|
|
||||||
// Truncate tool result if too large
|
// Truncate tool result if too large
|
||||||
let truncated_output = truncate_tool_result(
|
let truncated_output =
|
||||||
&result.output,
|
truncate_tool_result(&result.output, self.runtime_config.tool_result_max_chars);
|
||||||
self.provider_config.tool_result_max_chars,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Record tool call and check for loops
|
// Record tool call and check for loops
|
||||||
let loop_result = loop_detector.record(&tool_call.name, &tool_call.arguments);
|
let loop_result = loop_detector.record(&tool_call.name, &tool_call.arguments);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::config::LLMProviderConfig;
|
|||||||
use crate::providers::{ChatCompletionRequest, LLMProvider, Message, create_provider};
|
use crate::providers::{ChatCompletionRequest, LLMProvider, Message, create_provider};
|
||||||
use crate::text::{char_count, take_prefix_chars};
|
use crate::text::{char_count, take_prefix_chars};
|
||||||
|
|
||||||
use crate::agent::AgentError;
|
use crate::agent::{AgentError, AgentRuntimeConfig};
|
||||||
|
|
||||||
/// Token estimation using ~4 chars/token heuristic with 1.2x safety margin.
|
/// Token estimation using ~4 chars/token heuristic with 1.2x safety margin.
|
||||||
pub fn estimate_tokens(messages: &[ChatMessage]) -> usize {
|
pub fn estimate_tokens(messages: &[ChatMessage]) -> usize {
|
||||||
@ -263,10 +263,14 @@ Be concise, aim for {} characters or less.
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_provider_config(provider_config: &LLMProviderConfig) -> Self {
|
pub fn from_provider_config(provider_config: &LLMProviderConfig) -> Self {
|
||||||
|
Self::from_runtime_config(&AgentRuntimeConfig::from(provider_config.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_runtime_config(config: &AgentRuntimeConfig) -> Self {
|
||||||
Self::with_config(
|
Self::with_config(
|
||||||
provider_config.context_window_tokens(),
|
config.context_window_tokens,
|
||||||
ContextCompressionConfig {
|
ContextCompressionConfig {
|
||||||
summary_max_chars: provider_config.context_summary_char_budget(),
|
summary_max_chars: config.context_summary_char_budget,
|
||||||
..ContextCompressionConfig::default()
|
..ContextCompressionConfig::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -434,7 +438,8 @@ Be concise, aim for {} characters or less.
|
|||||||
return Ok(String::new());
|
return Ok(String::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let provider = create_provider(provider_config.clone())
|
let runtime_config = AgentRuntimeConfig::from(provider_config.clone());
|
||||||
|
let provider = create_provider(runtime_config.provider)
|
||||||
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
.map_err(|e| AgentError::ProviderCreation(e.to_string()))?;
|
||||||
let transcript = Self::build_transcript(messages);
|
let transcript = Self::build_transcript(messages);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
pub mod agent_loop;
|
pub mod agent_loop;
|
||||||
pub mod context_compressor;
|
pub mod context_compressor;
|
||||||
|
pub mod runtime_config;
|
||||||
|
|
||||||
pub use agent_loop::{
|
pub use agent_loop::{
|
||||||
AgentError, AgentLoop, AgentProcessResult, EmittedMessageHandler, SkillProvider,
|
AgentError, AgentLoop, AgentProcessResult, EmittedMessageHandler, SkillProvider,
|
||||||
};
|
};
|
||||||
pub use context_compressor::ContextCompressor;
|
pub use context_compressor::ContextCompressor;
|
||||||
|
pub use runtime_config::AgentRuntimeConfig;
|
||||||
|
|||||||
39
src/agent/runtime_config.rs
Normal file
39
src/agent/runtime_config.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use crate::config::LLMProviderConfig;
|
||||||
|
use crate::providers::ProviderRuntimeConfig;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AgentRuntimeConfig {
|
||||||
|
pub provider: ProviderRuntimeConfig,
|
||||||
|
pub context_window_tokens: usize,
|
||||||
|
pub context_summary_char_budget: usize,
|
||||||
|
pub max_tool_iterations: usize,
|
||||||
|
pub tool_result_max_chars: usize,
|
||||||
|
pub context_tool_result_trim_chars: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LLMProviderConfig> for AgentRuntimeConfig {
|
||||||
|
fn from(config: LLMProviderConfig) -> Self {
|
||||||
|
let context_window_tokens = config.context_window_tokens();
|
||||||
|
let context_summary_char_budget = config.context_summary_char_budget();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
provider: ProviderRuntimeConfig {
|
||||||
|
provider_type: config.provider_type,
|
||||||
|
name: config.name,
|
||||||
|
base_url: config.base_url,
|
||||||
|
api_key: config.api_key,
|
||||||
|
extra_headers: config.extra_headers,
|
||||||
|
llm_timeout_secs: config.llm_timeout_secs,
|
||||||
|
model_id: config.model_id,
|
||||||
|
temperature: config.temperature,
|
||||||
|
max_tokens: config.max_tokens,
|
||||||
|
model_extra: config.model_extra,
|
||||||
|
},
|
||||||
|
context_window_tokens,
|
||||||
|
context_summary_char_budget,
|
||||||
|
max_tool_iterations: config.max_tool_iterations,
|
||||||
|
tool_result_max_chars: config.tool_result_max_chars,
|
||||||
|
context_tool_result_trim_chars: config.context_tool_result_trim_chars,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::agent::AgentError;
|
use crate::agent::{AgentError, AgentRuntimeConfig};
|
||||||
use crate::config::LLMProviderConfig;
|
use crate::config::LLMProviderConfig;
|
||||||
use crate::providers::{ChatCompletionRequest, Message, create_provider};
|
use crate::providers::{ChatCompletionRequest, Message, create_provider};
|
||||||
use crate::storage::{MemoryRecord, SessionStore};
|
use crate::storage::{MemoryRecord, SessionStore};
|
||||||
@ -114,7 +114,8 @@ impl MemoryMaintenanceService {
|
|||||||
scope_key: &str,
|
scope_key: &str,
|
||||||
plan: &MemoryMaintenancePlan,
|
plan: &MemoryMaintenancePlan,
|
||||||
) -> Result<MemoryMaintenanceModelOutput, AgentError> {
|
) -> Result<MemoryMaintenanceModelOutput, AgentError> {
|
||||||
let provider = create_provider(self.provider_config.clone()).map_err(|err| {
|
let runtime_config = AgentRuntimeConfig::from(self.provider_config.clone());
|
||||||
|
let provider = create_provider(runtime_config.provider).map_err(|err| {
|
||||||
AgentError::Other(format!("create maintenance provider error: {}", err))
|
AgentError::Other(format!("create maintenance provider error: {}", err))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub mod processor;
|
|||||||
pub mod prompt;
|
pub mod prompt;
|
||||||
pub mod prompt_injector;
|
pub mod prompt_injector;
|
||||||
pub mod provider_config_service;
|
pub mod provider_config_service;
|
||||||
|
pub mod runtime;
|
||||||
pub mod scheduled_agent_task_service;
|
pub mod scheduled_agent_task_service;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod session_factory;
|
pub mod session_factory;
|
||||||
@ -38,6 +39,7 @@ use crate::skills::SkillRuntime;
|
|||||||
use agent_task_executor::{AgentTaskExecutor, SchedulerMaintenanceService};
|
use agent_task_executor::{AgentTaskExecutor, SchedulerMaintenanceService};
|
||||||
use outbound_dispatcher::OutboundDispatcher;
|
use outbound_dispatcher::OutboundDispatcher;
|
||||||
use processor::InboundProcessor;
|
use processor::InboundProcessor;
|
||||||
|
use runtime::build_session_manager;
|
||||||
use session::SessionManager;
|
use session::SessionManager;
|
||||||
|
|
||||||
pub struct GatewayState {
|
pub struct GatewayState {
|
||||||
@ -63,7 +65,7 @@ impl GatewayState {
|
|||||||
|
|
||||||
let skills = Arc::new(SkillRuntime::from_config(config.skills.clone()));
|
let skills = Arc::new(SkillRuntime::from_config(config.skills.clone()));
|
||||||
|
|
||||||
let session_manager = SessionManager::new(
|
let session_manager = build_session_manager(
|
||||||
session_ttl_hours,
|
session_ttl_hours,
|
||||||
agent_prompt_reinject_every,
|
agent_prompt_reinject_every,
|
||||||
show_tool_results,
|
show_tool_results,
|
||||||
|
|||||||
96
src/gateway/runtime.rs
Normal file
96
src/gateway/runtime.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::agent::AgentError;
|
||||||
|
use crate::config::LLMProviderConfig;
|
||||||
|
use crate::skills::SkillRuntime;
|
||||||
|
use crate::storage::{
|
||||||
|
ConversationRepository, MemoryRepository, PromptInjectionRepository, SchedulerJobRepository,
|
||||||
|
SessionStore, SkillEventRepository,
|
||||||
|
};
|
||||||
|
use crate::tools::ToolRegistry;
|
||||||
|
|
||||||
|
use super::agent_factory::AgentFactory;
|
||||||
|
use super::cli_session::CliSessionService;
|
||||||
|
use super::memory_maintenance_coordinator::MemoryMaintenanceCoordinator;
|
||||||
|
use super::prompt_injector::PromptInjector;
|
||||||
|
use super::provider_config_service::ProviderConfigService;
|
||||||
|
use super::scheduled_agent_task_service::ScheduledAgentTaskService;
|
||||||
|
use super::session::{SessionManager, SessionManagerServices};
|
||||||
|
use super::session_factory::SessionFactory;
|
||||||
|
use super::session_lifecycle::SessionLifecycleService;
|
||||||
|
use super::session_message_service::SessionMessageService;
|
||||||
|
use super::tool_registry_factory::ToolRegistryFactory;
|
||||||
|
|
||||||
|
pub(crate) fn build_session_manager(
|
||||||
|
session_ttl_hours: u64,
|
||||||
|
agent_prompt_reinject_every: u64,
|
||||||
|
show_tool_results: bool,
|
||||||
|
default_timezone: String,
|
||||||
|
provider_config: LLMProviderConfig,
|
||||||
|
provider_configs: HashMap<String, LLMProviderConfig>,
|
||||||
|
skills: Arc<SkillRuntime>,
|
||||||
|
) -> Result<SessionManager, AgentError> {
|
||||||
|
let store = Arc::new(
|
||||||
|
SessionStore::new()
|
||||||
|
.map_err(|err| AgentError::Other(format!("session store init error: {}", err)))?,
|
||||||
|
);
|
||||||
|
let known_agents = provider_configs.keys().cloned().collect::<HashSet<_>>();
|
||||||
|
let provider_configs = ProviderConfigService::new(provider_config.clone(), provider_configs);
|
||||||
|
|
||||||
|
if let Err(err) =
|
||||||
|
store.append_skill_event(None, "discovered", None, &skills.discovery_event_payload())
|
||||||
|
{
|
||||||
|
tracing::warn!(error = %err, "Failed to record skill discovery event");
|
||||||
|
}
|
||||||
|
|
||||||
|
let memories: Arc<dyn MemoryRepository> = store.clone();
|
||||||
|
let scheduler_jobs: Arc<dyn SchedulerJobRepository> = store.clone();
|
||||||
|
let skill_events: Arc<dyn SkillEventRepository> = store.clone();
|
||||||
|
let tools = Arc::new(
|
||||||
|
ToolRegistryFactory::new(
|
||||||
|
skills.clone(),
|
||||||
|
memories,
|
||||||
|
scheduler_jobs,
|
||||||
|
skill_events.clone(),
|
||||||
|
known_agents,
|
||||||
|
default_timezone,
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let agent_factory = AgentFactory::new(tools.clone(), skills.clone());
|
||||||
|
let conversations: Arc<dyn ConversationRepository> = store.clone();
|
||||||
|
let prompt_repository: Arc<dyn PromptInjectionRepository> = store.clone();
|
||||||
|
let prompt_injector = PromptInjector::new(prompt_repository, agent_prompt_reinject_every);
|
||||||
|
let session_factory = SessionFactory::new(
|
||||||
|
provider_config.clone(),
|
||||||
|
skills.clone(),
|
||||||
|
agent_factory,
|
||||||
|
prompt_injector,
|
||||||
|
conversations,
|
||||||
|
skill_events,
|
||||||
|
);
|
||||||
|
let lifecycle = SessionLifecycleService::new(session_ttl_hours, session_factory);
|
||||||
|
let cli_sessions = CliSessionService::new(store.clone());
|
||||||
|
let messages = SessionMessageService::new(lifecycle.clone(), show_tool_results);
|
||||||
|
let scheduled_tasks = ScheduledAgentTaskService::new(
|
||||||
|
lifecycle.clone(),
|
||||||
|
provider_configs.clone(),
|
||||||
|
show_tool_results,
|
||||||
|
);
|
||||||
|
let memory_maintenance =
|
||||||
|
MemoryMaintenanceCoordinator::new(store.clone(), provider_configs.clone());
|
||||||
|
|
||||||
|
Ok(SessionManager::from_services(SessionManagerServices {
|
||||||
|
tools: tools as Arc<ToolRegistry>,
|
||||||
|
skills,
|
||||||
|
store,
|
||||||
|
show_tool_results,
|
||||||
|
lifecycle,
|
||||||
|
cli_sessions,
|
||||||
|
messages,
|
||||||
|
scheduled_tasks,
|
||||||
|
memory_maintenance,
|
||||||
|
}))
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ use crate::skills::SkillRuntime;
|
|||||||
use crate::storage::{ConversationRepository, SessionRecord, SessionStore, SkillEventRepository};
|
use crate::storage::{ConversationRepository, SessionRecord, SessionStore, SkillEventRepository};
|
||||||
use crate::tools::ToolRegistry;
|
use crate::tools::ToolRegistry;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{Mutex, mpsc};
|
use tokio::sync::{Mutex, mpsc};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -26,13 +26,10 @@ use super::memory_maintenance::{
|
|||||||
use super::memory_maintenance::{MemoryMaintenanceModelOutput, MemoryMaintenanceScopeResult};
|
use super::memory_maintenance::{MemoryMaintenanceModelOutput, MemoryMaintenanceScopeResult};
|
||||||
use super::memory_maintenance_coordinator::MemoryMaintenanceCoordinator;
|
use super::memory_maintenance_coordinator::MemoryMaintenanceCoordinator;
|
||||||
use super::prompt_injector::PromptInjector;
|
use super::prompt_injector::PromptInjector;
|
||||||
use super::provider_config_service::ProviderConfigService;
|
|
||||||
use super::scheduled_agent_task_service::ScheduledAgentTaskService;
|
use super::scheduled_agent_task_service::ScheduledAgentTaskService;
|
||||||
use super::session_factory::SessionFactory;
|
|
||||||
use super::session_history::SessionHistory;
|
use super::session_history::SessionHistory;
|
||||||
use super::session_lifecycle::SessionLifecycleService;
|
use super::session_lifecycle::SessionLifecycleService;
|
||||||
use super::session_message_service::SessionMessageService;
|
use super::session_message_service::SessionMessageService;
|
||||||
use super::tool_registry_factory::ToolRegistryFactory;
|
|
||||||
|
|
||||||
/// Session 按 channel 隔离,每个 channel 一个 Session
|
/// Session 按 channel 隔离,每个 channel 一个 Session
|
||||||
/// History 按 chat_id 隔离,由 Session 统一管理
|
/// History 按 chat_id 隔离,由 Session 统一管理
|
||||||
@ -346,7 +343,33 @@ pub struct SessionManager {
|
|||||||
memory_maintenance: MemoryMaintenanceCoordinator,
|
memory_maintenance: MemoryMaintenanceCoordinator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SessionManagerServices {
|
||||||
|
pub(crate) tools: Arc<ToolRegistry>,
|
||||||
|
pub(crate) skills: Arc<SkillRuntime>,
|
||||||
|
pub(crate) store: Arc<SessionStore>,
|
||||||
|
pub(crate) show_tool_results: bool,
|
||||||
|
pub(crate) lifecycle: SessionLifecycleService,
|
||||||
|
pub(crate) cli_sessions: CliSessionService,
|
||||||
|
pub(crate) messages: SessionMessageService,
|
||||||
|
pub(crate) scheduled_tasks: ScheduledAgentTaskService,
|
||||||
|
pub(crate) memory_maintenance: MemoryMaintenanceCoordinator,
|
||||||
|
}
|
||||||
|
|
||||||
impl SessionManager {
|
impl SessionManager {
|
||||||
|
pub(crate) fn from_services(services: SessionManagerServices) -> Self {
|
||||||
|
Self {
|
||||||
|
tools: services.tools,
|
||||||
|
skills: services.skills,
|
||||||
|
store: services.store,
|
||||||
|
show_tool_results: services.show_tool_results,
|
||||||
|
lifecycle: services.lifecycle,
|
||||||
|
cli_sessions: services.cli_sessions,
|
||||||
|
messages: services.messages,
|
||||||
|
scheduled_tasks: services.scheduled_tasks,
|
||||||
|
memory_maintenance: services.memory_maintenance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
session_ttl_hours: u64,
|
session_ttl_hours: u64,
|
||||||
agent_prompt_reinject_every: u64,
|
agent_prompt_reinject_every: u64,
|
||||||
@ -356,63 +379,15 @@ impl SessionManager {
|
|||||||
provider_configs: HashMap<String, LLMProviderConfig>,
|
provider_configs: HashMap<String, LLMProviderConfig>,
|
||||||
skills: Arc<SkillRuntime>,
|
skills: Arc<SkillRuntime>,
|
||||||
) -> Result<Self, AgentError> {
|
) -> Result<Self, AgentError> {
|
||||||
let store = Arc::new(
|
super::runtime::build_session_manager(
|
||||||
SessionStore::new()
|
session_ttl_hours,
|
||||||
.map_err(|err| AgentError::Other(format!("session store init error: {}", err)))?,
|
agent_prompt_reinject_every,
|
||||||
);
|
|
||||||
let known_agents = provider_configs.keys().cloned().collect::<HashSet<_>>();
|
|
||||||
let provider_configs =
|
|
||||||
ProviderConfigService::new(provider_config.clone(), provider_configs);
|
|
||||||
|
|
||||||
if let Err(err) =
|
|
||||||
store.append_skill_event(None, "discovered", None, &skills.discovery_event_payload())
|
|
||||||
{
|
|
||||||
tracing::warn!(error = %err, "Failed to record skill discovery event");
|
|
||||||
}
|
|
||||||
|
|
||||||
let tools = Arc::new(
|
|
||||||
ToolRegistryFactory::new(
|
|
||||||
skills.clone(),
|
|
||||||
store.clone(),
|
|
||||||
known_agents,
|
|
||||||
default_timezone,
|
|
||||||
)
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
let agent_factory = AgentFactory::new(tools.clone(), skills.clone());
|
|
||||||
let conversations: Arc<dyn ConversationRepository> = store.clone();
|
|
||||||
let skill_events: Arc<dyn SkillEventRepository> = store.clone();
|
|
||||||
let prompt_injector = PromptInjector::new(store.clone(), agent_prompt_reinject_every);
|
|
||||||
let session_factory = SessionFactory::new(
|
|
||||||
provider_config.clone(),
|
|
||||||
skills.clone(),
|
|
||||||
agent_factory,
|
|
||||||
prompt_injector,
|
|
||||||
conversations,
|
|
||||||
skill_events,
|
|
||||||
);
|
|
||||||
let lifecycle = SessionLifecycleService::new(session_ttl_hours, session_factory);
|
|
||||||
let cli_sessions = CliSessionService::new(store.clone());
|
|
||||||
let messages = SessionMessageService::new(lifecycle.clone(), show_tool_results);
|
|
||||||
let scheduled_tasks = ScheduledAgentTaskService::new(
|
|
||||||
lifecycle.clone(),
|
|
||||||
provider_configs.clone(),
|
|
||||||
show_tool_results,
|
show_tool_results,
|
||||||
);
|
default_timezone,
|
||||||
let memory_maintenance =
|
provider_config,
|
||||||
MemoryMaintenanceCoordinator::new(store.clone(), provider_configs.clone());
|
provider_configs,
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
tools,
|
|
||||||
skills,
|
skills,
|
||||||
store,
|
)
|
||||||
show_tool_results,
|
|
||||||
lifecycle,
|
|
||||||
cli_sessions,
|
|
||||||
messages,
|
|
||||||
scheduled_tasks,
|
|
||||||
memory_maintenance,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tools(&self) -> Arc<ToolRegistry> {
|
pub fn tools(&self) -> Arc<ToolRegistry> {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::skills::SkillRuntime;
|
use crate::skills::SkillRuntime;
|
||||||
use crate::storage::SessionStore;
|
use crate::storage::{MemoryRepository, SchedulerJobRepository, SkillEventRepository};
|
||||||
use crate::tools::{
|
use crate::tools::{
|
||||||
BashTool, CalculatorTool, FileEditTool, FileReadTool, FileWriteTool, HttpRequestTool,
|
BashTool, CalculatorTool, FileEditTool, FileReadTool, FileWriteTool, HttpRequestTool,
|
||||||
MemoryManageTool, MemorySearchTool, SchedulerManageTool, SkillActivateTool, SkillListTool,
|
MemoryManageTool, MemorySearchTool, SchedulerManageTool, SkillActivateTool, SkillListTool,
|
||||||
@ -11,7 +11,9 @@ use crate::tools::{
|
|||||||
|
|
||||||
pub(crate) struct ToolRegistryFactory {
|
pub(crate) struct ToolRegistryFactory {
|
||||||
skills: Arc<SkillRuntime>,
|
skills: Arc<SkillRuntime>,
|
||||||
store: Arc<SessionStore>,
|
memories: Arc<dyn MemoryRepository>,
|
||||||
|
scheduler_jobs: Arc<dyn SchedulerJobRepository>,
|
||||||
|
skill_events: Arc<dyn SkillEventRepository>,
|
||||||
known_agents: HashSet<String>,
|
known_agents: HashSet<String>,
|
||||||
default_timezone: String,
|
default_timezone: String,
|
||||||
}
|
}
|
||||||
@ -19,13 +21,17 @@ pub(crate) struct ToolRegistryFactory {
|
|||||||
impl ToolRegistryFactory {
|
impl ToolRegistryFactory {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
skills: Arc<SkillRuntime>,
|
skills: Arc<SkillRuntime>,
|
||||||
store: Arc<SessionStore>,
|
memories: Arc<dyn MemoryRepository>,
|
||||||
|
scheduler_jobs: Arc<dyn SchedulerJobRepository>,
|
||||||
|
skill_events: Arc<dyn SkillEventRepository>,
|
||||||
known_agents: HashSet<String>,
|
known_agents: HashSet<String>,
|
||||||
default_timezone: String,
|
default_timezone: String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
skills,
|
skills,
|
||||||
store,
|
memories,
|
||||||
|
scheduler_jobs,
|
||||||
|
skill_events,
|
||||||
known_agents,
|
known_agents,
|
||||||
default_timezone,
|
default_timezone,
|
||||||
}
|
}
|
||||||
@ -38,15 +44,15 @@ impl ToolRegistryFactory {
|
|||||||
registry.register(FileReadTool::new());
|
registry.register(FileReadTool::new());
|
||||||
registry.register(FileWriteTool::new());
|
registry.register(FileWriteTool::new());
|
||||||
registry.register(FileEditTool::new());
|
registry.register(FileEditTool::new());
|
||||||
registry.register(MemorySearchTool::new(self.store.clone()));
|
registry.register(MemorySearchTool::new(self.memories.clone()));
|
||||||
registry.register(MemoryManageTool::new(self.store.clone()));
|
registry.register(MemoryManageTool::new(self.memories.clone()));
|
||||||
registry.register(SchedulerManageTool::new(
|
registry.register(SchedulerManageTool::new(
|
||||||
self.store.clone(),
|
self.scheduler_jobs.clone(),
|
||||||
self.known_agents.clone(),
|
self.known_agents.clone(),
|
||||||
));
|
));
|
||||||
registry.register(SkillActivateTool::new(
|
registry.register(SkillActivateTool::new(
|
||||||
self.skills.clone(),
|
self.skills.clone(),
|
||||||
self.store.clone(),
|
self.skill_events.clone(),
|
||||||
));
|
));
|
||||||
registry.register(SkillListTool::new(self.skills.clone()));
|
registry.register(SkillListTool::new(self.skills.clone()));
|
||||||
registry.register(SkillManageTool::new(self.skills.clone()));
|
registry.register(SkillManageTool::new(self.skills.clone()));
|
||||||
|
|||||||
@ -5,12 +5,16 @@ pub mod traits;
|
|||||||
pub use self::anthropic::AnthropicProvider;
|
pub use self::anthropic::AnthropicProvider;
|
||||||
pub use self::openai::OpenAIProvider;
|
pub use self::openai::OpenAIProvider;
|
||||||
|
|
||||||
use crate::config::LLMProviderConfig;
|
|
||||||
pub use crate::domain::messages::ToolCall;
|
pub use crate::domain::messages::ToolCall;
|
||||||
pub use crate::domain::tools::{Tool, ToolFunction};
|
pub use crate::domain::tools::{Tool, ToolFunction};
|
||||||
pub use traits::{ChatCompletionRequest, ChatCompletionResponse, LLMProvider, Message, Usage};
|
pub use traits::{
|
||||||
|
ChatCompletionRequest, ChatCompletionResponse, LLMProvider, Message, ProviderRuntimeConfig,
|
||||||
|
Usage,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn create_provider(config: LLMProviderConfig) -> Result<Box<dyn LLMProvider>, ProviderError> {
|
pub fn create_provider(
|
||||||
|
config: ProviderRuntimeConfig,
|
||||||
|
) -> Result<Box<dyn LLMProvider>, ProviderError> {
|
||||||
match config.provider_type.as_str() {
|
match config.provider_type.as_str() {
|
||||||
"openai" => Ok(Box::new(OpenAIProvider::new(
|
"openai" => Ok(Box::new(OpenAIProvider::new(
|
||||||
config.name,
|
config.name,
|
||||||
|
|||||||
@ -2,6 +2,21 @@ use crate::domain::messages::{ContentBlock, ToolCall};
|
|||||||
use crate::domain::tools::Tool;
|
use crate::domain::tools::Tool;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ProviderRuntimeConfig {
|
||||||
|
pub provider_type: String,
|
||||||
|
pub name: String,
|
||||||
|
pub base_url: String,
|
||||||
|
pub api_key: String,
|
||||||
|
pub extra_headers: HashMap<String, String>,
|
||||||
|
pub llm_timeout_secs: u64,
|
||||||
|
pub model_id: String,
|
||||||
|
pub temperature: Option<f32>,
|
||||||
|
pub max_tokens: Option<u32>,
|
||||||
|
pub model_extra: HashMap<String, serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user