Class: Ask::Conversation

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ask/conversation.rb

Overview

Ordered collection of messages comprising a conversation with an LLM. Provides role normalization, serialization helpers, and Enumerable access.

conv = Ask::Conversation.new
conv << Ask::Message.new(role: :user, content: "Hello")
conv.system("Be helpful")
conv.to_a  # => [{ role: :user, content: "Hello" }, ...]

Instance Method Summary collapse

Constructor Details

#initialize(messages = []) ⇒ Conversation

Returns a new instance of Conversation.

Parameters:

  • messages (Array<Ask::Message>) (defaults to: [])

    initial messages



249
250
251
252
# File 'lib/ask/conversation.rb', line 249

def initialize(messages = [])
  @messages = []
  messages.each { |m| self << m }
end

Instance Method Details

#<<(message) ⇒ self Also known as: add

Add a message by object or by attributes.

Parameters:

  • message (Ask::Message, Hash, String)

    message or attributes

Returns:

  • (self)


257
258
259
260
261
# File 'lib/ask/conversation.rb', line 257

def <<(message)
  msg = message.is_a?(Message) ? message : build_message(message)
  @messages << msg
  self
end

#[](index) ⇒ Ask::Message?

Access message by index.

Parameters:

  • index (Integer)

    zero-based index

Returns:



330
331
332
# File 'lib/ask/conversation.rb', line 330

def [](index)
  @messages[index]
end

#assistant(text = nil, tool_calls: nil, **options) ⇒ self

Add an assistant message.

Parameters:

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

    message content (nil when tool_calls are present)

  • tool_calls (Array<Hash>, nil) (defaults to: nil)

    tool call invocations

Returns:

  • (self)


290
291
292
# File 'lib/ask/conversation.rb', line 290

def assistant(text = nil, tool_calls: nil, **options)
  self << Message.new(role: :assistant, content: text, tool_calls: tool_calls, **options)
end

#assistant_messagesArray<Ask::Message>

Returns assistant messages.

Returns:



352
# File 'lib/ask/conversation.rb', line 352

def assistant_messages = by_role(:assistant)

#by_role(role) ⇒ Array<Ask::Message>

Returns messages with the given role.

Parameters:

  • role (Symbol, String)

    role to filter by

Returns:



341
342
343
# File 'lib/ask/conversation.rb', line 341

def by_role(role)
  @messages.select { |m| m.role == role.to_sym }
end

#clearself

Remove all messages.

Returns:

  • (self)


322
323
324
325
# File 'lib/ask/conversation.rb', line 322

def clear
  @messages.clear
  self
end

#dupAsk::Conversation

Deep copy of this conversation.

Returns:



368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/ask/conversation.rb', line 368

def dup
  Conversation.new(@messages.map { |m|
    opts = { role: m.role, name: m.name, tool_call_id: m.tool_call_id,
             tool_calls: m.tool_calls, metadata: m. }
    if m.content_blocks
      opts[:content] = m.content_blocks.dup
    else
      opts[:content] = m.content
    end
    Message.new(**opts)
  })
end

#each {|Message| ... } ⇒ Enumerator

Returns if no block given.

Yields:

  • (Message)

    yields each message in order

Returns:

  • (Enumerator)

    if no block given



304
305
306
# File 'lib/ask/conversation.rb', line 304

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

#empty?Boolean

Returns true if there are no messages.

Returns:

  • (Boolean)

    true if there are no messages



318
# File 'lib/ask/conversation.rb', line 318

def empty? = @messages.empty?

#find_matching_tool_call(tool_call_id) ⇒ Object

Walk message history to find a matching assistant tool call for a tool result. Returns the assistant message that contains the tool call, or nil.



359
360
361
362
363
364
# File 'lib/ask/conversation.rb', line 359

def find_matching_tool_call(tool_call_id)
  @messages.reverse.find do |m|
    next unless m.role == :assistant && m.tool_calls.is_a?(Hash)
    m.tool_calls.key?(tool_call_id)
  end
end

#inspectString

Returns:

  • (String)


382
383
384
# File 'lib/ask/conversation.rb', line 382

def inspect
  "#<Ask::Conversation messages=#{@messages.length}>"
end

#last(n = nil) ⇒ Ask::Message+

Returns last message or last n messages.

Returns:



309
310
311
# File 'lib/ask/conversation.rb', line 309

def last(n = nil)
  n ? @messages.last(n) : @messages.last
end

#lengthInteger Also known as: size

Returns number of messages.

Returns:

  • (Integer)

    number of messages



314
# File 'lib/ask/conversation.rb', line 314

def length = @messages.length

#system(text, **options) ⇒ self

Add a system message.

Parameters:

  • text (String, Array<Ask::Content>)

    message content or content blocks

Returns:

  • (self)


267
268
269
# File 'lib/ask/conversation.rb', line 267

def system(text, **options)
  self << Message.new(role: :system, content: text, **options)
end

#system_messagesArray<Ask::Message>

Returns system messages.

Returns:



346
# File 'lib/ask/conversation.rb', line 346

def system_messages = by_role(:system)

#to_aArray<Hash>

Returns messages as an array of hashes.

Returns:

  • (Array<Hash>)

    messages as an array of hashes



335
336
337
# File 'lib/ask/conversation.rb', line 335

def to_a
  @messages.map(&:to_h)
end

#tool_messagesArray<Ask::Message>

Returns tool messages.

Returns:



355
# File 'lib/ask/conversation.rb', line 355

def tool_messages = by_role(:tool)

#tool_result(content, tool_call_id:, **options) ⇒ self

Add a tool result message.

Parameters:

  • content (String)

    tool output

  • tool_call_id (String)

    ID of the tool call this result is for

Returns:

  • (self)


298
299
300
# File 'lib/ask/conversation.rb', line 298

def tool_result(content, tool_call_id:, **options)
  self << Message.new(role: :tool, content: content, tool_call_id: tool_call_id, **options)
end

#user(text, **options) ⇒ self

Add a user message.

Examples:

Plain text

conv.user("Hello")

Multi-modal

conv.user([
  Ask::Content::Text.new("What's in this image?"),
  Ask::Content::Image.new(url: "https://example.com/photo.jpg", mime_type: "image/jpeg")
])

Parameters:

  • text (String, Array<Ask::Content>)

    message content or content blocks. Pass an Array of Ask::Content objects for multi-modal messages.

Returns:

  • (self)


282
283
284
# File 'lib/ask/conversation.rb', line 282

def user(text, **options)
  self << Message.new(role: :user, content: text, **options)
end

#user_messagesArray<Ask::Message>

Returns user messages.

Returns:



349
# File 'lib/ask/conversation.rb', line 349

def user_messages = by_role(:user)