Skip to main content

HookBus

Struct HookBus 

Source
pub struct HookBus { /* private fields */ }
Expand description

The central hook dispatcher.

Thread-safe: uses RwLock so multiple concurrent emitters can read the handler list, and registration takes a write lock only briefly.

Implementations§

Source§

impl HookBus

Source

pub fn new() -> HookBus

Create an empty HookBus with no handlers.

Source

pub fn extension_generation(&self, extension_id: &str) -> u64

Current load generation of extension_id (0 until first unloaded).

Source

pub async fn set_session_injection_for(&self, session_id: &str, content: String)

Record context injected by an on_session_start handler for session_id.

Called once per session, by whoever emits the session-start event, after extensions have loaded. Later calls for the same id replace the stored value.

Source

pub async fn session_injection_for(&self, session_id: &str) -> Option<String>

Context injected at session start for session_id, if any. Read on every turn while composing the system prompt.

Source

pub async fn clear_session_injection(&self, session_id: &str)

Drop the injection recorded for session_id (session teardown).

Source

pub async fn set_session_injection(&self, content: String)

👎Deprecated:

use set_session_injection_for

Compatibility shim: writes under the empty key.

Source

pub async fn session_injection(&self) -> Option<String>

👎Deprecated:

use session_injection_for

Compatibility shim: reads the empty key.

Source

pub async fn subscribe( &self, kind: HookKind, handler: Arc<dyn ExtensionHandler>, tool_filter: Option<String>, matcher: Option<HookMatcher>, permissions: PermissionSet, ) -> Result<(), String>

Register a handler for a specific hook kind.

Returns an error if the handler’s permissions don’t allow subscribing to this hook kind.

Source

pub async fn emit(&self, event: &HookEvent) -> HookResult

Emit a hook event to all registered handlers.

Returns the first Block result if any handler blocks, otherwise returns Continue. Handlers are called in registration order.

For before_tool_call only Block ends the chain (#148 I1):

  • Modify rewrites the input and the chain continues; every later handler sees (and vets) the modified input, and the final input is returned as Modify unless something blocks or confirms.
  • Confirm is recorded and the chain continues, so a later Block wins even when the confirming extension is already latched. Confirms are merged (all sources, all messages) and returned last, carrying any input modified BEFORE the first Confirm.
  • A Modify after a pending Confirm is ignored (logged at warn): the user confirms the input as it stood when they were asked.

If no handlers are registered for this hook, returns immediately (the no-extensions fast path).

Source

pub async fn emit_concurrent(&self, event: &HookEvent) -> HookResult

Emit a hook event to all registered handlers concurrently.

All handlers race under a single shared timeout (per_handler_timeout). Results are collected and the first Block wins; injections are merged.

When to use this over emit():

Only safe for hook kinds whose handlers are order-independent — i.e. where no handler’s result depends on another’s execution. Currently that applies to:

  • on_session_end: only Continue is a valid result; handlers are fire-and-forget notification calls (deck, d20, jawz-widget, synaps-tasks all write to their own stores independently).

Do NOT use for before_tool_call / after_tool_call / before_message hooks where Block / Modify / Replace / Inject semantics require a defined winner when two handlers disagree — join_all completion order is nondeterministic, so the “winner” would be unstable. Those hooks must use the sequential emit, which enforces first-wins ordering.

With N extensions and a 5 s per-handler timeout, serial emit takes up to N×5 s; concurrent emit collapses that to a single 5 s window regardless of N — critical for teardown budgets.

Source

pub async fn unsubscribe_all(&self, extension_id: &str)

Remove all handlers for a given extension ID.

Source

pub async fn handler_count(&self) -> usize

Number of registered handlers across all hooks.

Source

pub async fn is_empty(&self) -> bool

Check if any handlers are registered (for fast-path decisions).

Source

pub async fn subscriptions_for( &self, extension_id: &str, ) -> Vec<(HookKind, Option<String>)>

Return all (kind, tool_filter) pairs subscribed by the given extension id. Sorted by kind name, then by tool_filter (None first), for stable output.

Trait Implementations§

Source§

impl Default for HookBus

Source§

fn default() -> HookBus

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ThreadSafetyMarker for T
where T: Send,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more