Class: Brute::MessageTransport

Inherits:
Object
  • Object
show all
Defined in:
lib/brute/message_transport.rb,
lib/brute/message_transport/llm.rb,
lib/brute/message_transport/openai.rb,
lib/brute/message_transport/ruby_llm.rb,
lib/brute/message_transport/anthropic.rb

Overview

Transports messages between an LLM library's format and Brute's format (Brute::Message). This is the seam that keeps Brute framework-agnostic: calling an LLM is trivial with any library, so Brute has no "completion middleware" — the terminal run proc of an agent pipeline makes the LLM call itself, and a MessageTransport translates at the boundary.

Inbound (library response -> Brute), the transport wraps whatever the proc got back and yields each message as a Brute::Message; the proc appends:

response = client.complete(...)
Brute::MessageTransport::RubyLLM.new(response).wrap_each do |message|
env[:messages] << message
end

Outbound (Brute -> library), dump_all converts env into the shape the library's completion call expects:

client.complete(Brute::MessageTransport::RubyLLM.dump_all(env[:messages]), ...)

This base class is the identity transport: it flattens the result into a list of messages and yields them untouched. Library-specific subclasses (see message_transport/*.rb) override #wrap and .dump. They reference their library lazily, so requiring the library is your job — Brute depends on none of them.

Defined Under Namespace

Classes: Anthropic, LLM, OpenAI, RubyLLM

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(result) ⇒ MessageTransport

Returns a new instance of MessageTransport.



48
49
50
# File 'lib/brute/message_transport.rb', line 48

def initialize(result)
  @result = result
end

Class Method Details

.dump(message) ⇒ Object

Outbound: one Brute::Message in the library's format. Identity here.



39
40
41
# File 'lib/brute/message_transport.rb', line 39

def self.dump(message)
  message
end

.dump_all(messages) ⇒ Object

Outbound: the whole log in the library's format.



44
45
46
# File 'lib/brute/message_transport.rb', line 44

def self.dump_all(messages)
  messages.map { |message| dump(message) }
end

.wrap_each(result, &block) ⇒ Object

Convenience: Brute::MessageTransport.wrap_each(result) { |m| ... }



34
35
36
# File 'lib/brute/message_transport.rb', line 34

def self.wrap_each(result, &block)
  new(result).wrap_each(&block)
end

Instance Method Details

#messagesObject

The result normalized to a flat list of the library's messages. A single message, an array, or anything transcript-shaped (responds to #messages).



64
65
66
67
68
69
# File 'lib/brute/message_transport.rb', line 64

def messages
  case @result
  when Array then @result.compact
  else @result.respond_to?(:messages) ? @result.messages : [@result].compact
  end
end

#wrap_eachObject

Yield each result message as a Brute::Message. Without a block, returns an Enumerator. The caller decides what to do with each (typically append to env).



55
56
57
58
59
# File 'lib/brute/message_transport.rb', line 55

def wrap_each
  return enum_for(:wrap_each) unless block_given?

  messages.each { |message| yield wrap(message) }
end