Class: Pikuri::Agent::History::Message

Inherits:
Data
  • Object
show all
Defined in:
lib/pikuri/agent/history.rb

Overview

One message. id and kind are pikuri's own and never reach a provider; everything else is what the model saw.

content is always a String (empty on a pure tool-call turn, which is what ruby_llm stores); anything the model was shown beyond text is an Attachment in attachments.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, role:, content:, kind: 'user', attachments: [], tool_calls: [], tool_call_id: nil, model_id: nil, thinking: nil, tokens: nil) ⇒ Message

Returns a new instance of Message.

Parameters:

  • id (String)
  • role (String)

    one of ROLES

  • kind (String) (defaults to: 'user')

    one of KINDS; defaults to "user"

  • content (String)

    the text the model saw; "" is legal

  • attachments (Array<Attachment>) (defaults to: [])
  • tool_calls (Array<ToolCall>) (defaults to: [])

    empty unless the assistant asked for tools

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

    set exactly on a tool message

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

    which model produced this

  • thinking (Thinking, nil) (defaults to: nil)
  • tokens (Tokens, nil) (defaults to: nil)


158
159
160
161
# File 'lib/pikuri/agent/history.rb', line 158

def initialize(id:, role:, content:, kind: 'user', attachments: [], tool_calls: [],
               tool_call_id: nil, model_id: nil, thinking: nil, tokens: nil)
  super
end

Instance Attribute Details

#attachmentsObject (readonly)

Returns the value of attribute attachments

Returns:

  • (Object)

    the current value of attachments



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def attachments
  @attachments
end

#contentObject (readonly)

Returns the value of attribute content

Returns:

  • (Object)

    the current value of content



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def content
  @content
end

#idObject (readonly)

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def id
  @id
end

#kindObject (readonly)

Returns the value of attribute kind

Returns:

  • (Object)

    the current value of kind



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def kind
  @kind
end

#model_idObject (readonly)

Returns the value of attribute model_id

Returns:

  • (Object)

    the current value of model_id



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def model_id
  @model_id
end

#roleObject (readonly)

Returns the value of attribute role

Returns:

  • (Object)

    the current value of role



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def role
  @role
end

#thinkingObject (readonly)

Returns the value of attribute thinking

Returns:

  • (Object)

    the current value of thinking



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def thinking
  @thinking
end

#tokensObject (readonly)

Returns the value of attribute tokens

Returns:

  • (Object)

    the current value of tokens



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def tokens
  @tokens
end

#tool_call_idObject (readonly)

Returns the value of attribute tool_call_id

Returns:

  • (Object)

    the current value of tool_call_id



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def tool_call_id
  @tool_call_id
end

#tool_callsObject (readonly)

Returns the value of attribute tool_calls

Returns:

  • (Object)

    the current value of tool_calls



143
144
145
# File 'lib/pikuri/agent/history.rb', line 143

def tool_calls
  @tool_calls
end

Class Method Details

.from_ruby_llm(msg, id:, kind: 'user') ⇒ Message

Snapshot a live RubyLLM::Message. Attachment bytes are read now — the file a tool showed the model may be gone or changed by the time anyone loads this back.

Parameters:

Returns:



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/pikuri/agent/history.rb', line 174

def self.from_ruby_llm(msg, id:, kind: 'user')
  text, attachments = split_content(msg.content)
  new(
    id: id, role: msg.role.to_s, kind: kind, content: text, attachments: attachments,
    tool_calls: (msg.tool_calls || {}).values.map do |c|
      ToolCall.new(id: c.id, name: c.name, arguments: c.arguments || {})
    end,
    tool_call_id: msg.tool_call_id,
    model_id: msg.model_id,
    thinking: msg.thinking && Thinking.new(text: msg.thinking.text, signature: msg.thinking.signature),
    tokens: msg.tokens && Tokens.new(
      input: msg.tokens.input, output: msg.tokens.output, cached: msg.tokens.cached,
      cache_creation: msg.tokens.cache_creation, thinking: msg.tokens.thinking
    )
  )
end

Instance Method Details

#to_ruby_llm(keep_thinking: true) ⇒ RubyLLM::Message

Rebuild the RubyLLM::Message this was taken from.

Parameters:

  • keep_thinking (Boolean) (defaults to: true)

    false replays the turn without its Thinking block at all — what Pikuri::Agent passes for a turn some other model produced, since a thinking block lands in a slot the receiving model reads as its own scratchpad. Dropped from the message, not from the record: Pikuri::Agent#export_history still writes it. See DECISIONS.md D_thinking_block_replay.

Returns:

  • (RubyLLM::Message)


213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/pikuri/agent/history.rb', line 213

def to_ruby_llm(keep_thinking: true)
  calls = tool_calls.to_h do |c|
    [c.id, RubyLLM::ToolCall.new(id: c.id, name: c.name, arguments: c.arguments)]
  end
  replayed = thinking if keep_thinking
  RubyLLM::Message.new(
    role: role.to_sym,
    content: ruby_llm_content,
    tool_calls: calls.empty? ? nil : calls,
    tool_call_id: tool_call_id,
    model_id: model_id,
    thinking: replayed && RubyLLM::Thinking.build(
      text: replayed.text, signature: replayed.signature
    ),
    tokens: tokens && RubyLLM::Tokens.build(**tokens.to_h)
  )
end

#tool_call?Boolean

Returns whether this message asked for tools.

Returns:

  • (Boolean)

    whether this message asked for tools.



164
# File 'lib/pikuri/agent/history.rb', line 164

def tool_call? = !tool_calls.empty?