Class: RubyLLM::Chat

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ruby_llm/chat.rb

Overview

Represents a conversation with an AI model

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model: nil, provider: nil, assume_model_exists: false, context: nil) ⇒ Chat

Returns a new instance of Chat.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/ruby_llm/chat.rb', line 10

def initialize(model: nil, provider: nil, assume_model_exists: false, context: nil)
  if assume_model_exists && !provider
    raise ArgumentError, 'Provider must be specified if assume_model_exists is true'
  end

  @context = context
  @config = context&.config || RubyLLM.config
  model_id = model || @config.default_model
  with_model(model_id, provider: provider, assume_exists: assume_model_exists)
  @temperature = nil
  @messages = []
  @tools = {}
  @params = {}
  @headers = {}
  @schema = nil
  @thinking = nil
  @on = {
    new_message: nil,
    end_message: nil,
    tool_call: nil,
    tool_result: nil
  }
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def headers
  @headers
end

#messagesObject (readonly)

Returns the value of attribute messages.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def messages
  @messages
end

#modelObject (readonly)

Returns the value of attribute model.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def model
  @model
end

#paramsObject (readonly)

Returns the value of attribute params.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def params
  @params
end

#schemaObject (readonly)

Returns the value of attribute schema.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def schema
  @schema
end

#toolsObject (readonly)

Returns the value of attribute tools.



8
9
10
# File 'lib/ruby_llm/chat.rb', line 8

def tools
  @tools
end

Instance Method Details

#add_message(message_or_attributes) ⇒ Object



165
166
167
168
169
# File 'lib/ruby_llm/chat.rb', line 165

def add_message(message_or_attributes)
  message = message_or_attributes.is_a?(Message) ? message_or_attributes : Message.new(message_or_attributes)
  messages << message
  message
end

#ask(message = nil, with: nil) ⇒ Object Also known as: say



34
35
36
37
# File 'lib/ruby_llm/chat.rb', line 34

def ask(message = nil, with: nil, &)
  add_message role: :user, content: build_content(message, with)
  complete(&)
end

#completeObject

rubocop:disable Metrics/PerceivedComplexity



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
# File 'lib/ruby_llm/chat.rb', line 132

def complete(&) # rubocop:disable Metrics/PerceivedComplexity
  response = @provider.complete(
    messages,
    tools: @tools,
    temperature: @temperature,
    model: @model,
    params: @params,
    headers: @headers,
    schema: @schema,
    thinking: @thinking,
    &wrap_streaming_block(&)
  )

  @on[:new_message]&.call unless block_given?

  if @schema && response.content.is_a?(String)
    begin
      response.content = JSON.parse(response.content)
    rescue JSON::ParserError
      # If parsing fails, keep content as string
    end
  end

  add_message response
  @on[:end_message]&.call(response)

  if response.tool_call?
    handle_tool_calls(response, &)
  else
    response
  end
end

#eachObject



128
129
130
# File 'lib/ruby_llm/chat.rb', line 128

def each(&)
  messages.each(&)
end

#instance_variablesObject



175
176
177
# File 'lib/ruby_llm/chat.rb', line 175

def instance_variables
  super - %i[@connection @config]
end

#on_end_message(&block) ⇒ Object



113
114
115
116
# File 'lib/ruby_llm/chat.rb', line 113

def on_end_message(&block)
  @on[:end_message] = block
  self
end

#on_new_message(&block) ⇒ Object



108
109
110
111
# File 'lib/ruby_llm/chat.rb', line 108

def on_new_message(&block)
  @on[:new_message] = block
  self
end

#on_tool_call(&block) ⇒ Object



118
119
120
121
# File 'lib/ruby_llm/chat.rb', line 118

def on_tool_call(&block)
  @on[:tool_call] = block
  self
end

#on_tool_result(&block) ⇒ Object



123
124
125
126
# File 'lib/ruby_llm/chat.rb', line 123

def on_tool_result(&block)
  @on[:tool_result] = block
  self
end

#reset_messages!Object



171
172
173
# File 'lib/ruby_llm/chat.rb', line 171

def reset_messages!
  @messages.clear
end

#with_context(context) ⇒ Object



78
79
80
81
82
83
# File 'lib/ruby_llm/chat.rb', line 78

def with_context(context)
  @context = context
  @config = context.config
  with_model(@model.id, provider: @provider.slug, assume_exists: true)
  self
end

#with_headers(**headers) ⇒ Object



90
91
92
93
# File 'lib/ruby_llm/chat.rb', line 90

def with_headers(**headers)
  @headers = headers
  self
end

#with_instructions(instructions, replace: false) ⇒ Object



41
42
43
44
45
46
# File 'lib/ruby_llm/chat.rb', line 41

def with_instructions(instructions, replace: false)
  @messages = @messages.reject { |msg| msg.role == :system } if replace

  add_message role: :system, content: instructions
  self
end

#with_model(model_id, provider: nil, assume_exists: false) ⇒ Object



60
61
62
63
64
# File 'lib/ruby_llm/chat.rb', line 60

def with_model(model_id, provider: nil, assume_exists: false)
  @model, @provider = Models.resolve(model_id, provider:, assume_exists:, config: @config)
  @connection = @provider.connection
  self
end

#with_params(**params) ⇒ Object



85
86
87
88
# File 'lib/ruby_llm/chat.rb', line 85

def with_params(**params)
  @params = params
  self
end

#with_schema(schema) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ruby_llm/chat.rb', line 95

def with_schema(schema)
  schema_instance = schema.is_a?(Class) ? schema.new : schema

  # Accept both RubyLLM::Schema instances and plain JSON schemas
  @schema = if schema_instance.respond_to?(:to_json_schema)
              schema_instance.to_json_schema[:schema]
            else
              schema_instance
            end

  self
end

#with_temperature(temperature) ⇒ Object



66
67
68
69
# File 'lib/ruby_llm/chat.rb', line 66

def with_temperature(temperature)
  @temperature = temperature
  self
end

#with_thinking(effort: nil, budget: nil) ⇒ Object

Raises:

  • (ArgumentError)


71
72
73
74
75
76
# File 'lib/ruby_llm/chat.rb', line 71

def with_thinking(effort: nil, budget: nil)
  raise ArgumentError, 'with_thinking requires :effort or :budget' if effort.nil? && budget.nil?

  @thinking = Thinking::Config.new(effort: effort, budget: budget)
  self
end

#with_tool(tool) ⇒ Object



48
49
50
51
52
# File 'lib/ruby_llm/chat.rb', line 48

def with_tool(tool)
  tool_instance = tool.is_a?(Class) ? tool.new : tool
  @tools[tool_instance.name.to_sym] = tool_instance
  self
end

#with_tools(*tools, replace: false) ⇒ Object



54
55
56
57
58
# File 'lib/ruby_llm/chat.rb', line 54

def with_tools(*tools, replace: false)
  @tools.clear if replace
  tools.compact.each { |tool| with_tool tool }
  self
end