Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/openhuman/agent/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ pub fn register_embedder_post_turn_hook(hook: Arc<dyn PostTurnHook>) {
.push(hook);
}

/// Replace an embedder post-turn hook by name, or remove it when absent.
///
/// This prevents a host that rebuilds its core from retaining callbacks from a
/// previous configuration in the process-global registry.
pub fn replace_embedder_post_turn_hook(name: &str, hook: Option<Arc<dyn PostTurnHook>>) {
let mut hooks = EMBEDDER_POST_TURN_HOOKS
.lock()
.expect("embedder post-turn hooks poisoned");
hooks.retain(|registered| registered.name() != name);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Release the registry lock before invoking or dropping hooks

When the registry owns the last Arc, this retain both calls embedder-controlled name() and drops the removed callback while EMBEDDER_POST_TURN_HOOKS is locked. During a core rebuild, a callback whose Drop or name() re-enters registration/replacement—or acquires a host lock in the inverse order—will deadlock this registry and block every subsequent registration or snapshot. Move embedder-controlled calls and destruction outside the mutex; replace_embedder_tool_hook has the same issue.

Useful? React with 👍 / 👎.

if let Some(hook) = hook {
hooks.push(hook);
}
}

/// Snapshot hooks supplied by the embedding host.
pub fn embedder_post_turn_hooks() -> Vec<Arc<dyn PostTurnHook>> {
EMBEDDER_POST_TURN_HOOKS
Expand Down Expand Up @@ -164,6 +178,20 @@ pub fn register_embedder_tool_hook(hook: Arc<dyn ToolHook>) {
.push(hook);
}

/// Replace an embedder tool hook by name, or remove it when absent.
///
/// This prevents a host that rebuilds its core from retaining callbacks from a
/// previous configuration in the process-global registry.
pub fn replace_embedder_tool_hook(name: &str, hook: Option<Arc<dyn ToolHook>>) {
let mut hooks = EMBEDDER_TOOL_HOOKS
.lock()
.expect("embedder tool hooks poisoned");
hooks.retain(|registered| registered.name() != name);
if let Some(hook) = hook {
hooks.push(hook);
}
}

/// Snapshot tool hooks supplied by the embedding host.
pub fn embedder_tool_hooks() -> Vec<Arc<dyn ToolHook>> {
EMBEDDER_TOOL_HOOKS
Expand Down
Loading