Events

While a turn runs, middleware and tools push events to env[:events] — a sink you can stack handlers onto for live progress. By default it’s a null sink that swallows everything; add the EventHandler middleware to route events somewhere.

Turning it on

Brute.agent
  .use(Brute::Middleware::EventHandler, handler_class: Brute::Events::TerminalOutput)
  # ... rest of the stack ...

EventHandler wraps env[:events] in your handler class on the way in, so everything downstream streams through it.

The events

Events are { type:, data: } hashes. The common types:

Type Emitted when data
:content assistant text streams/arrives the text
:reasoning thinking/reasoning text the text
:tool_call_start the model calls tools array of { name, call_id, arguments }
:tool_result a tool finishes { name, content }
:error a tool raises { error, message }

Writing a handler

Handlers are stackable: subclass Brute::Events::Handler, override <<, do your thing, then call super to pass the event down the stack (or don’t, to swallow it). Brute::Events::TerminalOutput dispatches each event to an on_<type> method:

class MyHandler < Brute::Events::Handler
  def <<(event)
    case event.to_h[:type]
    when :tool_call_start
      event.to_h[:data].each { |tc| warn "→ #{tc[:name]} #{tc[:arguments]}" }
    when :content
      print event.to_h[:data]
    end
    super   # pass down to the inner handler
  end
end

Brute.agent.use(Brute::Middleware::EventHandler, handler_class: MyHandler)

Because handlers stack, you can layer several — say, terminal output plus a JSONL logger — by nesting EventHandler middleware. Each wraps the sink the previous one installed.

Terminal output

Brute::Events::TerminalOutput is the batteries-included handler used by the examples: it streams assistant content to stdout, prints [tool] name - args when tools start and [tool] name - done when they finish, indents reasoning to stderr, and formats errors. It’s a good template to copy for a custom UI.


This site uses Just the Docs, a documentation theme for Jekyll.