Class: Ragents::Context

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ragents/context.rb

Overview

Immutable conversation context. Context is Ractor-shareable when frozen, enabling safe passage between Ractors.

Examples:

context = Ragents::Context.new
context = context.add_message(Message.user("Hello"))
context = context.add_message(Message.assistant("Hi there!"))
context.messages.size  # => 2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(messages: [], metadata: {}) ⇒ Context

Returns a new instance of Context.



18
19
20
21
22
# File 'lib/ragents/context.rb', line 18

def initialize(messages: [], metadata: {})
  @messages = messages.map { |m| ensure_message(m) }.freeze
  @metadata = .freeze
  freeze
end

Instance Attribute Details

#messagesObject (readonly)

Returns the value of attribute messages.



16
17
18
# File 'lib/ragents/context.rb', line 16

def messages
  @messages
end

#metadataObject (readonly)

Returns the value of attribute metadata.



16
17
18
# File 'lib/ragents/context.rb', line 16

def 
  @metadata
end

Class Method Details

.from_h(hash) ⇒ Object

Create from hash



116
117
118
119
120
121
122
123
124
# File 'lib/ragents/context.rb', line 116

def self.from_h(hash)
  messages = (hash[:messages] || hash["messages"] || []).map do |msg|
    Message.new(**symbolize_keys(msg))
  end

   = hash[:metadata] || hash["metadata"] || {}

  new(messages: messages, metadata: symbolize_keys())
end

.make_shareable(context) ⇒ Object

Make Ractor-shareable



150
151
152
# File 'lib/ragents/context.rb', line 150

def self.make_shareable(context)
  Ractor.make_shareable(context)
end

.symbolize_keys(hash) ⇒ Object



167
168
169
# File 'lib/ragents/context.rb', line 167

def self.symbolize_keys(hash)
  hash.transform_keys(&:to_sym)
end

Instance Method Details

#add_message(message) ⇒ Object Also known as: <<

Add a message and return a new Context



25
26
27
28
29
30
31
# File 'lib/ragents/context.rb', line 25

def add_message(message)
  message = ensure_message(message)
  self.class.new(
    messages: @messages + [message],
    metadata: @metadata
  )
end

#add_messages(*new_messages) ⇒ Object

Add multiple messages and return a new Context



36
37
38
39
40
41
42
# File 'lib/ragents/context.rb', line 36

def add_messages(*new_messages)
  new_messages = new_messages.flatten.map { |m| ensure_message(m) }
  self.class.new(
    messages: @messages + new_messages,
    metadata: @metadata
  )
end

#conversation_messagesObject

Get all non-system messages



58
59
60
# File 'lib/ragents/context.rb', line 58

def conversation_messages
  @messages.reject(&:system?)
end

#each(&block) ⇒ Object

Iterate over messages



96
97
98
# File 'lib/ragents/context.rb', line 96

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

#empty?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/ragents/context.rb', line 91

def empty?
  @messages.empty?
end

#fork(**new_metadata) ⇒ Object

Create a fork of this context (for branching conversations)



142
143
144
145
146
147
# File 'lib/ragents/context.rb', line 142

def fork(**)
  self.class.new(
    messages: @messages.dup,
    metadata: @metadata.merge().merge(forked_at: Time.now.iso8601)
  )
end

#last_assistant_messageObject

Get the last assistant message



68
69
70
# File 'lib/ragents/context.rb', line 68

def last_assistant_message
  @messages.reverse.find(&:assistant?)
end

#last_messageObject

Get the last message



63
64
65
# File 'lib/ragents/context.rb', line 63

def last_message
  @messages.last
end

#pending_tool_callsObject

Get pending tool calls from the last assistant message



78
79
80
81
82
# File 'lib/ragents/context.rb', line 78

def pending_tool_calls
  return [] unless pending_tool_calls?

  last_assistant_message.tool_calls
end

#pending_tool_calls?Boolean

Check if the last message has tool calls

Returns:

  • (Boolean)


73
74
75
# File 'lib/ragents/context.rb', line 73

def pending_tool_calls?
  last_assistant_message&.has_tool_calls? || false
end

#sizeObject Also known as: length

Count total messages



85
86
87
# File 'lib/ragents/context.rb', line 85

def size
  @messages.size
end

#system_messageObject

Get the system message if present



53
54
55
# File 'lib/ragents/context.rb', line 53

def system_message
  @messages.find(&:system?)
end

#to_aObject

Convert to array of message hashes



103
104
105
# File 'lib/ragents/context.rb', line 103

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

#to_hObject

Serialize to hash



108
109
110
111
112
113
# File 'lib/ragents/context.rb', line 108

def to_h
  {
    messages: to_a,
    metadata: @metadata
  }
end

#truncate(max_messages:, keep_system: true) ⇒ Object

Truncate context to last N messages (keeping system message)



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/ragents/context.rb', line 127

def truncate(max_messages:, keep_system: true)
  return self if @messages.size <= max_messages

  system_msg = system_message if keep_system
  other_messages = conversation_messages

  kept = other_messages.last(keep_system && system_msg ? max_messages - 1 : max_messages)

  self.class.new(
    messages: system_msg ? [system_msg] + kept : kept,
    metadata: @metadata
  )
end

#with_metadata(**new_metadata) ⇒ Object

Return a new Context with updated metadata



45
46
47
48
49
50
# File 'lib/ragents/context.rb', line 45

def (**)
  self.class.new(
    messages: @messages,
    metadata: @metadata.merge()
  )
end