class RubyLLM::Chat

rubocop:disable Metrics/ClassLength
chat.ask “Can you elaborate on that?”
chat.ask “What’s the best way to learn Ruby?”
chat = RubyLLM.chat
Example:
streaming responses, and tool integration with a simple, conversational API.
Represents a conversation with an AI model. Handles message history,

def add_message(message_or_attributes)

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

def add_tool_result(tool_use_id, result)

def add_tool_result(tool_use_id, result)
  add_message(
    role: :tool,
    content: result.is_a?(Hash) && result[:error] ? result[:error] : result.to_s,
    tool_call_id: tool_use_id
  )
end

def ask(message = nil, with: {}, &block)

def ask(message = nil, with: {}, &block)
  add_message role: :user, content: Content.new(message, with)
  complete(&block)
end

def complete(&)

def complete(&)
  @on[:new_message]&.call
  response = @provider.complete(messages, tools: @tools, temperature: @temperature, model: @model.id, &)
  @on[:end_message]&.call(response)
  add_message response
  if response.tool_call?
    handle_tool_calls(response, &)
  else
    response
  end
end

def each(&)

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

def execute_tool(tool_call)

def execute_tool(tool_call)
  tool = tools[tool_call.name.to_sym]
  args = tool_call.arguments
  tool.call(args)
end

def handle_tool_calls(response, &)

def handle_tool_calls(response, &)
  response.tool_calls.each_value do |tool_call|
    @on[:new_message]&.call
    result = execute_tool tool_call
    message = add_tool_result tool_call.id, result
    @on[:end_message]&.call(message)
  end
  complete(&)
end

def initialize(model: nil, provider: nil, assume_model_exists: false) # rubocop:disable Metrics/MethodLength

rubocop:disable Metrics/MethodLength
def initialize(model: nil, provider: nil, assume_model_exists: false) # rubocop:disable Metrics/MethodLength
  if assume_model_exists && !provider
    raise ArgumentError, 'Provider must be specified if assume_model_exists is true'
  end
  model_id = model || RubyLLM.config.default_model
  with_model(model_id, provider: provider, assume_exists: assume_model_exists)
  @temperature = 0.7
  @messages = []
  @tools = {}
  @on = {
    new_message: nil,
    end_message: nil
  }
end

def on_end_message(&block)

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

def on_new_message(&block)

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

def with_instructions(instructions, replace: false)

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

def with_model(model_id, provider: nil, assume_exists: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength

rubocop:disable Metrics/AbcSize,Metrics/MethodLength
def with_model(model_id, provider: nil, assume_exists: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
  if assume_exists
    raise ArgumentError, 'Provider must be specified if assume_exists is true' unless provider
    @provider = Provider.providers[provider.to_sym] || raise(Error, "Unknown provider: #{provider.to_sym}")
    @model = Struct.new(:id, :provider, :supports_functions, :supports_vision).new(model_id, provider, true, true)
    RubyLLM.logger.warn "Assuming model '#{model_id}' exists for provider '#{provider}'. " \
                        'Capabilities may not be accurately reflected.'
  else
    @model = Models.find model_id, provider
    @provider = Provider.providers[@model.provider.to_sym] || raise(Error, "Unknown provider: #{@model.provider}")
  end
  self
end

def with_temperature(temperature)

def with_temperature(temperature)
  @temperature = temperature
  self
end

def with_tool(tool)

def with_tool(tool)
  unless @model.supports_functions
    raise UnsupportedFunctionsError, "Model #{@model.id} doesn't support function calling"
  end
  tool_instance = tool.is_a?(Class) ? tool.new : tool
  @tools[tool_instance.name.to_sym] = tool_instance
  self
end

def with_tools(*tools)

def with_tools(*tools)
  tools.each { |tool| with_tool tool }
  self
end