Module: Brute::Hooks
- Included in:
- Completion::LLMrb, Completion::LangChain, Completion::OpenRouter, Completion::RubyLLM, Middleware::Base, Turn::Pipeline::Chainable
- Defined in:
- lib/brute/hooks.rb
Overview
Pub/sub registry for agent lifecycle hooks, subscribed on the builder:
Brute.agent
.use(Brute::Middleware::MaxIterations)
.run(->(env) { env[:messages].assistant("done") })
.on(:before_llm) { |env| ... }
.on(:approve_tool) { |_env, call| call[:name] != "exec" }
Every subscriber is called with the turn env first, followed by whatever extras that event carries. A block that only wants the env can take one argument and ignore the rest.
Emission points and payloads:
:turn_start, :turn_end → the turn env (AgentPipeline#start; turn_end
fires from an ensure, so it also fires on
error)
:turn_duration → env, started, finished: the turn's work is
this event's block
:middleware_added → an empty env, then the middleware and every
argument `use` was given (fires at build time,
so only subscribers registered before the `use`
see it)
:enter → env, the middleware instance, before the
layer does anything
:duration → env, started, finished, the middleware
instance: the layer's work is this event's
block, so it reports how long that took
:exit → env, the middleware instance, marking the
layer done (from an ensure, so it fires on
error too)
:before_llm, :after_llm → the turn env, around every LLM call
:llm_duration → env, started, finished: the provider call is
this event's block
:llm_failure → the turn env, when the LLM call raises; the
completion middleware then emits one of
:faraday_error, :open_router_server_error or
:standard_error with the exception as an extra
:compact_duration → env, started, finished, the compactor: one
strategy's attempt is this event's block, so
the strategy that spends a model call is
visible, and one that declined is still timed
:compacted → env, {strategy:, before:, after:} — a
compaction strategy rewrote env[:messages];
what it replaced is already gone, so an
application that keeps a transcript preserves
it here
:before_tool → env, call env {name:, arguments:, result:,
denied:, events:, metadata:, turn_env:} —
mutate :arguments to rewrite the call, or set
:result to answer it without executing
:approve_tool → env, call env — set :denied to true to deny
the call, or to a String to deny it with that
message
:tool_duration → env, started, finished, call env: the tool's
own execution is this event's block, so a
skipped or denied call never fires it
:after_tool → env, call env — mutate :result
Subscribers run inline (tool events may fire from parallel threads). Exceptions propagate to the caller — layers that want fail-open semantics rescue in their own subscriber. Include this in anything that emits or subscribes and the event names are first class there: ENTER_EVENT rather than Brute::Hooks::ENTER_EVENT. The registry itself is Hooks::Registry, and Brute::Hooks.new builds one.
Defined Under Namespace
Classes: Registry
Constant Summary collapse
- TURN_START_EVENT =
:turn_start- TURN_DURATION_EVENT =
:turn_duration- TURN_END_EVENT =
:turn_end- MIDDLEWARE_ADDED_EVENT =
:middleware_added- ENTER_EVENT =
:enter- DURATION_EVENT =
:duration- EXIT_EVENT =
:exit- BEFORE_LLM_EVENT =
:before_llm- LLM_DURATION_EVENT =
:llm_duration- AFTER_LLM_EVENT =
:after_llm- LLM_FAILURE_EVENT =
:llm_failure- FARADAY_ERROR_EVENT =
:faraday_error- OPEN_ROUTER_SERVER_ERROR_EVENT =
:open_router_server_error- STANDARD_ERROR_EVENT =
:standard_error- COMPACT_DURATION_EVENT =
:compact_duration- COMPACTED_EVENT =
:compacted- BEFORE_TOOL_EVENT =
:before_tool- APPROVE_TOOL_EVENT =
:approve_tool- TOOL_DURATION_EVENT =
:tool_duration- AFTER_TOOL_EVENT =
:after_tool
Class Method Summary collapse
Class Method Details
.new ⇒ Object
147 |
# File 'lib/brute/hooks.rb', line 147 def self.new(...) = Registry.new(...) |