Class: Riffer::Agent Abstract

Inherits:
Object
  • Object
show all
Extended by:
Helpers::ClassNameConverter, Helpers::Validations
Includes:
Messages::Converter
Defined in:
lib/riffer/agent.rb

Overview

This class is abstract.

Riffer::Agent is the base class for all agents in the Riffer framework.

Provides orchestration for LLM calls, tool use, and message management.

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Messages::Converter

#convert_to_message_object

Constructor Details

#initializevoid

Initializes a new agent

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/riffer/agent.rb', line 90

def initialize
  @messages = []
  @model_string = self.class.model
  @instructions_text = self.class.instructions

  provider_name, model_name = @model_string.split("/", 2)

  raise Riffer::ArgumentError, "Invalid model string: #{@model_string}" unless [provider_name, model_name].all? { |part| part.is_a?(String) && !part.strip.empty? }

  @provider_name = provider_name
  @model_name = model_name
end

Instance Attribute Details

#messagesArray<Riffer::Messages::Base> (readonly)

The message history for the agent

Returns:



85
86
87
# File 'lib/riffer/agent.rb', line 85

def messages
  @messages
end

Class Method Details

.allArray<Class>

Returns all agent subclasses

Returns:

  • (Array<Class>)

    all agent subclasses



78
79
80
# File 'lib/riffer/agent.rb', line 78

def all
  subclasses
end

.find(identifier) ⇒ Class?

Finds an agent class by identifier

Parameters:

  • identifier (String)

    the identifier to search for

Returns:

  • (Class, nil)

    the agent class, or nil if not found



72
73
74
# File 'lib/riffer/agent.rb', line 72

def find(identifier)
  subclasses.find { |agent_class| agent_class.identifier == identifier.to_s }
end

.identifier(value = nil) ⇒ String

Gets or sets the agent identifier

Parameters:

  • value (String, nil) (defaults to: nil)

    the identifier to set, or nil to get

Returns:

  • (String)

    the agent identifier



22
23
24
25
# File 'lib/riffer/agent.rb', line 22

def identifier(value = nil)
  return @identifier || class_name_to_path(name) if value.nil?
  @identifier = value.to_s
end

.instructions(instructions_text = nil) ⇒ String

Gets or sets the agent instructions

Parameters:

  • instructions_text (String, nil) (defaults to: nil)

    the instructions to set, or nil to get

Returns:

  • (String)

    the agent instructions



39
40
41
42
43
# File 'lib/riffer/agent.rb', line 39

def instructions(instructions_text = nil)
  return @instructions if instructions_text.nil?
  validate_is_string!(instructions_text, "instructions")
  @instructions = instructions_text
end

.model(model_string = nil) ⇒ String

Gets or sets the model string (e.g., “openai/gpt-4”)

Parameters:

  • model_string (String, nil) (defaults to: nil)

    the model string to set, or nil to get

Returns:

  • (String)

    the model string



30
31
32
33
34
# File 'lib/riffer/agent.rb', line 30

def model(model_string = nil)
  return @model if model_string.nil?
  validate_is_string!(model_string, "model")
  @model = model_string
end

.model_options(options = nil) ⇒ Hash

Gets or sets model options passed to generate_text/stream_text

Parameters:

  • options (Hash, nil) (defaults to: nil)

    the options to set, or nil to get

Returns:

  • (Hash)

    the model options



56
57
58
59
# File 'lib/riffer/agent.rb', line 56

def model_options(options = nil)
  return @model_options || {} if options.nil?
  @model_options = options
end

.provider_options(options = nil) ⇒ Hash

Gets or sets provider options passed to the provider client

Parameters:

  • options (Hash, nil) (defaults to: nil)

    the options to set, or nil to get

Returns:

  • (Hash)

    the provider options



48
49
50
51
# File 'lib/riffer/agent.rb', line 48

def provider_options(options = nil)
  return @provider_options || {} if options.nil?
  @provider_options = options
end

.uses_tools(tools_or_lambda = nil) ⇒ Array<Class>, ...

Gets or sets the tools used by this agent

Parameters:

  • tools_or_lambda (Array<Class>, Proc, nil) (defaults to: nil)

    tools array or lambda returning tools

Returns:

  • (Array<Class>, Proc, nil)

    the tools configuration



64
65
66
67
# File 'lib/riffer/agent.rb', line 64

def uses_tools(tools_or_lambda = nil)
  return @tools_config if tools_or_lambda.nil?
  @tools_config = tools_or_lambda
end

Instance Method Details

#generate(prompt_or_messages, tool_context: nil) ⇒ String

Generates a response from the agent

Parameters:

  • prompt_or_messages (String, Array<Hash, Riffer::Messages::Base>)
  • tool_context (Object, nil) (defaults to: nil)

    optional context object passed to all tool calls

Returns:

  • (String)


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/riffer/agent.rb', line 107

def generate(prompt_or_messages, tool_context: nil)
  @tool_context = tool_context
  @resolved_tools = nil
  initialize_messages(prompt_or_messages)

  loop do
    response = call_llm
    @messages << response

    break unless has_tool_calls?(response)

    execute_tool_calls(response)
  end

  extract_final_response
end

#stream(prompt_or_messages, tool_context: nil) ⇒ Enumerator

Streams a response from the agent

Parameters:

  • prompt_or_messages (String, Array<Hash, Riffer::Messages::Base>)
  • tool_context (Object, nil) (defaults to: nil)

    optional context object passed to all tool calls

Returns:

  • (Enumerator)

    an enumerator yielding stream events



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/riffer/agent.rb', line 128

def stream(prompt_or_messages, tool_context: nil)
  @tool_context = tool_context
  @resolved_tools = nil
  initialize_messages(prompt_or_messages)

  Enumerator.new do |yielder|
    loop do
      accumulated_content = ""
      accumulated_tool_calls = []
      current_tool_call = nil

      call_llm_stream.each do |event|
        yielder << event

        case event
        when Riffer::StreamEvents::TextDelta
          accumulated_content += event.content
        when Riffer::StreamEvents::TextDone
          accumulated_content = event.content
        when Riffer::StreamEvents::ToolCallDelta
          current_tool_call ||= {item_id: event.item_id, name: event.name, arguments: ""}
          current_tool_call[:arguments] += event.arguments_delta
          current_tool_call[:name] ||= event.name
        when Riffer::StreamEvents::ToolCallDone
          accumulated_tool_calls << {
            id: event.item_id,
            call_id: event.call_id,
            name: event.name,
            arguments: event.arguments
          }
          current_tool_call = nil
        end
      end

      response = Riffer::Messages::Assistant.new(accumulated_content, tool_calls: accumulated_tool_calls)
      @messages << response

      break unless has_tool_calls?(response)

      execute_tool_calls(response)
    end
  end
end