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::AFTER_LLM_EVENT, Hooks::AFTER_TOOL_EVENT, Hooks::APPROVE_TOOL_EVENT, Hooks::BEFORE_LLM_EVENT, Hooks::BEFORE_TOOL_EVENT, Hooks::COMPACTED_EVENT, Hooks::COMPACT_DURATION_EVENT, Hooks::DURATION_EVENT, Hooks::ENTER_EVENT, Hooks::EXIT_EVENT, Hooks::FARADAY_ERROR_EVENT, Hooks::LLM_DURATION_EVENT, Hooks::LLM_FAILURE_EVENT, Hooks::MIDDLEWARE_ADDED_EVENT, Hooks::OPEN_ROUTER_SERVER_ERROR_EVENT, Hooks::STANDARD_ERROR_EVENT, Hooks::TOOL_DURATION_EVENT, Hooks::TURN_DURATION_EVENT, Hooks::TURN_END_EVENT, Hooks::TURN_START_EVENT

Instance Method Summary collapse

Methods included from Hooks

new

Instance Method Details

#onObject

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

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


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

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

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



60
61
62
63
64
65
# File 'lib/brute/turn/pipeline.rb', line 60

def run(app = nil, &block)
  tap do
    bind_emitter(app) unless app.nil?
    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 :enter and :exit around its own work on each turn. Both of those carry the middleware instance as self, and :exit 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
# File 'lib/brute/turn/pipeline.rb', line 27

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

    builder = @use.pop
    @use << lambda do |app|
      bind_emitter(builder.call(app)).tap do |layer|
        layer.define_singleton_method(:call) do |env|
          emit(ENTER_EVENT, env, self)

          # The layer's work is :duration's block, so its subscribers
          # are handed how long this layer took — its own work plus
          # everything below it. :exit then marks the layer done,
          # from an ensure so it lands even when the work raised.
          result = nil
          begin
            emit(DURATION_EVENT, env, self) { result = super(env) }
          ensure
            emit(EXIT_EVENT, env, self)
          end

          result
        end
      end
    end
  end
end