Module: Brute::Turn::Pipeline::Chainable

Includes:
Hooks
Included in:
Brute::Turn::Pipeline
Defined in:
lib/brute/turn/pipeline.rb

Constant Summary

Constants included from Hooks

Hooks::COMPACT_DURATION_EVENT, Hooks::COMPACT_END_EVENT, Hooks::COMPACT_FAILURE_EVENT, Hooks::COMPACT_START_EVENT, Hooks::CONTENT_EVENT, Hooks::FARADAY_ERROR_EVENT, Hooks::LLM_DURATION_EVENT, Hooks::LLM_END_EVENT, Hooks::LLM_FAILURE_EVENT, Hooks::LLM_START_EVENT, Hooks::MIDDLEWARE_ADDED_EVENT, Hooks::MIDDLEWARE_DURATION_EVENT, Hooks::MIDDLEWARE_END_EVENT, Hooks::MIDDLEWARE_FAILURE_EVENT, Hooks::MIDDLEWARE_START_EVENT, Hooks::OPEN_ROUTER_SERVER_ERROR_EVENT, Hooks::REASONING_EVENT, Hooks::STANDARD_ERROR_EVENT, Hooks::TOOL_APPROVE_EVENT, Hooks::TOOL_CALLS_EVENT, Hooks::TOOL_DURATION_EVENT, Hooks::TOOL_END_EVENT, Hooks::TOOL_FAILURE_EVENT, Hooks::TOOL_START_EVENT, Hooks::TURN_DURATION_EVENT, Hooks::TURN_END_EVENT, Hooks::TURN_FAILURE_EVENT, Hooks::TURN_START_EVENT

Instance Method Summary collapse

Instance Method Details

#onObject

Subscribe a lifecycle hook (see Brute::Hooks):

Brute.agent
.use(MaxProfit)
.run(->(env) { ... })
.on(:llm_start) { |env| ... }
.on(:tool_approve) { |call| call[:name] != "exec" }


90
# File 'lib/brute/turn/pipeline.rb', line 90

def on(...) = tap { hooks.on(...) }

#run(app = nil, &block) ⇒ Object



76
77
78
79
80
# File 'lib/brute/turn/pipeline.rb', line 76

def run(app = nil, &block)
  tap do
    super
  end
end

#use(middleware, *args, &block) ⇒ Object

Enables the following syntax:

Brute.agent
.use(UltraSecurity)
.use(MaxProfit)
.use(DontTellMom)
.run -> (env) {
  your_llm_library.complete("How to make money?")
}

Every layer announces itself: :middleware_added when it goes on the stack, then :middleware_start and :middleware_end around its own work on each turn. Both of those carry the middleware instance as self, and :middleware_end fires from an ensure so a layer that raises is still reported.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/brute/turn/pipeline.rb', line 27

def use(middleware, *args, &block)
  tap do
    super
    hooks.emit(
      MIDDLEWARE_ADDED_EVENT,
      {},
      middleware,
      *args,
    )

    @use.pop.then do |builder|
      @use << lambda do |app|
        builder.call(app).tap do |layer|
          layer.define_singleton_method(:call) do |env|
            result = nil

            # A layer is one call: what it emits, and what the layers
            # below it emit, belong to this trace.
            env.emit_trace do |env|
              env.emit(MIDDLEWARE_START_EVENT, self)

              # The layer's work is :middleware_duration's block, so its subscribers
              # are handed how long this layer took — its own work plus
              # everything below it. :middleware_end then marks the layer done,
              # from an ensure so it lands even when the work raised.
              begin
                env.emit(MIDDLEWARE_DURATION_EVENT, self) { result = super(env) }
              rescue => error
                env.emit(MIDDLEWARE_FAILURE_EVENT, self, error)
                raise
              ensure
                env.emit(MIDDLEWARE_END_EVENT, self)
              end
            end

            result
          end
        end
      end
    end
  end
end