Skip to content
Open
1 change: 1 addition & 0 deletions clients/openframe-client/src/config/update_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ pub const RECONNECTION_DELAY_MS: u64 = 5000; // 5 seconds
// NATS message settings
pub const CONSUMER_ACK_WAIT_SECS: u64 = 120;
pub const CONSUMER_MAX_DELIVER: i64 = 10; // Maximum delivery attempts
pub const UNINSTALL_CONSUMER_MAX_DELIVER: i64 = 20; // Larger budget: uninstall may defer behind a long install holding the tool lock
22 changes: 22 additions & 0 deletions clients/openframe-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use crate::listener::execution_listener::ExecutionListener;
use crate::listener::openframe_client_update_listener::OpenFrameClientUpdateListener;
use crate::listener::tool_agent_update_listener::ToolAgentUpdateListener;
use crate::listener::tool_installation_message_listener::ToolInstallationMessageListener;
use crate::listener::tool_uninstall_message_listener::ToolUninstallMessageListener;
use crate::logging::nats_streaming::LogStreamingRunManager;
use crate::models::{CommandMessage, ScriptMessage};
use crate::platform::DirectoryManager;
Expand All @@ -68,6 +69,7 @@ use crate::services::tool_agent_update_service::ToolAgentUpdateService;
use crate::services::tool_connection_message_publisher::ToolConnectionMessagePublisher;
use crate::services::tool_connection_service::ToolConnectionService;
use crate::services::tool_installation_service::ToolInstallationService;
use crate::services::tool_uninstall_service::ToolUninstallService;
use crate::services::InstalledToolsService;
use crate::services::{
AgentAuthService, AgentRegistrationService, InitialConfigurationService,
Expand Down Expand Up @@ -144,6 +146,7 @@ pub struct Client {
auth_processor: InitialAuthenticationProcessor,
nats_connection_manager: NatsConnectionManager,
tool_installation_message_listener: ToolInstallationMessageListener,
tool_uninstall_message_listener: ToolUninstallMessageListener,
openframe_client_update_listener: OpenFrameClientUpdateListener,
tool_agent_update_listener: ToolAgentUpdateListener,
command_execution_listener: ExecutionListener<CommandMessage>,
Expand Down Expand Up @@ -321,6 +324,7 @@ impl Client {
tool_kill_service.clone(),
initial_configuration_service.clone(),
config_service.clone(),
tool_run_manager.clone(),
);

// Initialize tool connection service
Expand All @@ -334,6 +338,7 @@ impl Client {
tool_connection_message_publisher.clone(),
config_service.clone(),
tool_connection_service.clone(),
tool_run_manager.clone(),
);

// Initialize OpenFrame client info service
Expand Down Expand Up @@ -395,6 +400,19 @@ impl Client {
config_service.clone(),
);

let tool_uninstall_service = ToolUninstallService::new(
installed_tools_service.clone(),
tool_command_params_resolver.clone(),
tool_kill_service.clone(),
directory_manager.clone(),
);
let tool_uninstall_message_listener = ToolUninstallMessageListener::new(
nats_connection_manager.clone(),
tool_run_manager.clone(),
tool_uninstall_service,
config_service.clone(),
);

// Initialize OpenFrame client update listener
let openframe_client_update_listener = OpenFrameClientUpdateListener::new(
nats_connection_manager.clone(),
Expand All @@ -407,6 +425,7 @@ impl Client {
nats_connection_manager.clone(),
tool_agent_update_service,
config_service.clone(),
tool_run_manager.clone(),
);

let execution_service = ExecutionService::new();
Expand Down Expand Up @@ -445,6 +464,7 @@ impl Client {
auth_processor,
nats_connection_manager,
tool_installation_message_listener,
tool_uninstall_message_listener,
openframe_client_update_listener,
tool_agent_update_listener,
command_execution_listener,
Expand Down Expand Up @@ -494,6 +514,8 @@ impl Client {
//Start tool installation message listener in background
self.tool_installation_message_listener.start().await?;

self.tool_uninstall_message_listener.start().await?;

// Start OpenFrame client update listener in background
self.openframe_client_update_listener.start().await?;

Expand Down
2 changes: 2 additions & 0 deletions clients/openframe-client/src/listener/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ pub mod execution_listener;
pub mod openframe_client_update_listener;
pub mod tool_agent_update_listener;
pub mod tool_installation_message_listener;
pub mod tool_uninstall_message_listener;

pub use execution_listener::ExecutionListener;
pub use openframe_client_update_listener::OpenFrameClientUpdateListener;
pub use tool_agent_update_listener::ToolAgentUpdateListener;
pub use tool_installation_message_listener::ToolInstallationMessageListener;
pub use tool_uninstall_message_listener::ToolUninstallMessageListener;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::config::update_config::{
use crate::models::tool_agent_update_message::ToolAgentUpdateMessage;
use crate::services::nats_connection_manager::NatsConnectionManager;
use crate::services::tool_agent_update_service::ToolAgentUpdateService;
use crate::services::tool_run_manager::ToolRunManager;
use crate::services::AgentConfigurationService;
use anyhow::Result;
use async_nats::jetstream;
Expand All @@ -22,6 +23,7 @@ pub struct ToolAgentUpdateListener {
pub nats_connection_manager: NatsConnectionManager,
pub tool_agent_update_service: ToolAgentUpdateService,
pub config_service: AgentConfigurationService,
pub tool_run_manager: ToolRunManager,
}

impl ToolAgentUpdateListener {
Expand All @@ -31,11 +33,13 @@ impl ToolAgentUpdateListener {
nats_connection_manager: NatsConnectionManager,
tool_agent_update_service: ToolAgentUpdateService,
config_service: AgentConfigurationService,
tool_run_manager: ToolRunManager,
) -> Self {
Self {
nats_connection_manager,
tool_agent_update_service,
config_service,
tool_run_manager,
}
}

Expand Down Expand Up @@ -111,6 +115,21 @@ impl ToolAgentUpdateListener {

let tool_agent_id = tool_agent_update_message.tool_agent_id.clone();

// Serialize with install/uninstall via the per-tool lock (same pattern as the
// uninstall listener): if another operation holds it, leave the message unacked
// so JetStream redelivers the update once the tool is free.
let tool_lock = self.tool_run_manager.tool_lock(&tool_agent_id).await;
let _guard = match tool_lock.try_lock() {
Ok(guard) => guard,
Err(_) => {
info!(
"Tool {} busy with another operation, deferring update for redelivery",
tool_agent_id
);
return Ok(());
}
};

match self
.tool_agent_update_service
.process_update(tool_agent_update_message)
Expand Down
Loading