Class: Legion::Extensions::Llm::Canonical::Message

Inherits:
Data
  • Object
show all
Defined in:
lib/legion/extensions/llm/canonical/message.rb

Overview

Canonical message in a conversation. Ports field vocabulary from Legion::LLM::Types::Message. Unknown keys fold into the metadata member (04 L5) — never dropped. :cache_control (prompt-cache breakpoints) IS a member and survives build/to_h/JSON round-trips, including the fleet wire.

Constant Summary collapse

ROLES =
%i[system user assistant tool].freeze
BUILD_SITE =
'Canonical::Message.build'
FROM_HASH_SITE =
'Canonical::Message.from_hash'
NEW_SITE =
'Canonical::Message.new'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cache_controlObject (readonly)

Returns the value of attribute cache_control

Returns:

  • (Object)

    the current value of cache_control



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def cache_control
  @cache_control
end

#contentObject (readonly)

Returns the value of attribute content

Returns:

  • (Object)

    the current value of content



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def content
  @content
end

#conversation_idObject (readonly)

Returns the value of attribute conversation_id

Returns:

  • (Object)

    the current value of conversation_id



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def conversation_id
  @conversation_id
end

#idObject (readonly)

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def id
  @id
end

#input_tokensObject (readonly)

Returns the value of attribute input_tokens

Returns:

  • (Object)

    the current value of input_tokens



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def input_tokens
  @input_tokens
end

#metadataObject (readonly)

Returns the value of attribute metadata

Returns:

  • (Object)

    the current value of metadata



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def 
  @metadata
end

#modelObject (readonly)

Returns the value of attribute model

Returns:

  • (Object)

    the current value of model



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def model
  @model
end

#nameObject (readonly)

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def name
  @name
end

#output_tokensObject (readonly)

Returns the value of attribute output_tokens

Returns:

  • (Object)

    the current value of output_tokens



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def output_tokens
  @output_tokens
end

#parent_idObject (readonly)

Returns the value of attribute parent_id

Returns:

  • (Object)

    the current value of parent_id



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def parent_id
  @parent_id
end

#providerObject (readonly)

Returns the value of attribute provider

Returns:

  • (Object)

    the current value of provider



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def provider
  @provider
end

#roleObject (readonly)

Returns the value of attribute role

Returns:

  • (Object)

    the current value of role



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def role
  @role
end

#seqObject (readonly)

Returns the value of attribute seq

Returns:

  • (Object)

    the current value of seq



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def seq
  @seq
end

#statusObject (readonly)

Returns the value of attribute status

Returns:

  • (Object)

    the current value of status



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def status
  @status
end

#task_idObject (readonly)

Returns the value of attribute task_id

Returns:

  • (Object)

    the current value of task_id



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def task_id
  @task_id
end

#timestampObject (readonly)

Returns the value of attribute timestamp

Returns:

  • (Object)

    the current value of timestamp



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def timestamp
  @timestamp
end

#tool_call_idObject (readonly)

Returns the value of attribute tool_call_id

Returns:

  • (Object)

    the current value of tool_call_id



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

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



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def tool_calls
  @tool_calls
end

#versionObject (readonly)

Returns the value of attribute version

Returns:

  • (Object)

    the current value of version



16
17
18
# File 'lib/legion/extensions/llm/canonical/message.rb', line 16

def version
  @version
end

Class Method Details

.build(id: nil, parent_id: nil, role: :user, content: nil, tool_calls: nil, tool_call_id: nil, name: nil, status: :created, version: 1, timestamp: nil, seq: nil, provider: nil, model: nil, input_tokens: nil, output_tokens: nil, conversation_id: nil, task_id: nil, cache_control: nil, metadata: {}) ⇒ Object

Build from keyword args (primary constructor).



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/legion/extensions/llm/canonical/message.rb', line 23

def self.build(
  id: nil, parent_id: nil, role: :user, content: nil, tool_calls: nil,
  tool_call_id: nil, name: nil, status: :created, version: 1,
  timestamp: nil, seq: nil, provider: nil, model: nil,
  input_tokens: nil, output_tokens: nil, conversation_id: nil, task_id: nil,
  cache_control: nil, metadata: {}
)
  new(
    id: id || "msg_#{SecureRandom.hex(12)}",
    parent_id: parent_id,
    role: normalize_role!(role, self::BUILD_SITE),
    content: normalize_content!(content, self::BUILD_SITE),
    tool_calls: normalize_tool_calls!(tool_calls, self::BUILD_SITE),
    tool_call_id: tool_call_id,
    name: name,
    status: status,
    version: version,
    timestamp: timestamp || ::Time.now,
    seq: seq,
    provider: provider,
    model: model,
    input_tokens: input_tokens,
    output_tokens: output_tokens,
    conversation_id: conversation_id,
    task_id: task_id,
    cache_control: cache_control.nil? ? nil : Strict.expect_type!(cache_control, [::Hash], self::BUILD_SITE, :cache_control),
    metadata: Strict.metadata!(, self::BUILD_SITE)
  )
end

.from_hash(source) ⇒ Object

Build from a Hash (raw provider response or deserialized wire payload).



54
55
56
57
58
59
# File 'lib/legion/extensions/llm/canonical/message.rb', line 54

def self.from_hash(source)
  Strict.require_hash!(source, self::FROM_HASH_SITE)
  hash = Strict.symbolize_keys(source)
   = Strict.fold_unknowns!(self, self::FROM_HASH_SITE, hash)
  build(**hash, metadata:)
end

.normalize_content!(content, site) ⇒ Object

L2: one content normalizer shared by build and from_hash. String | ContentBlock | Array | nil — anything else raises.

Raises:

  • (ArgumentError)


69
70
71
72
73
74
75
# File 'lib/legion/extensions/llm/canonical/message.rb', line 69

def self.normalize_content!(content, site)
  return nil if content.nil?
  return content if content.is_a?(::String) || content.is_a?(ContentBlock)
  raise ArgumentError, "#{site}: content expected String | ContentBlock | Array, got #{content.class}" unless content.is_a?(::Array)

  content.map { |block| block.is_a?(ContentBlock) ? block : ContentBlock.from_hash(block) }
end

.normalize_role!(role, site) ⇒ Object

L6: role validated at construction, in both factories.



62
63
64
65
# File 'lib/legion/extensions/llm/canonical/message.rb', line 62

def self.normalize_role!(role, site)
  role_sym = role.is_a?(::String) ? role.to_sym : role
  Strict.enum!(role_sym, self::ROLES, site, :role)
end

.normalize_tool_calls!(tool_calls, site) ⇒ Object

L2: one tool-call normalizer shared by build and from_hash. Array | nil (Array is canonical; the legacy Hash shape is gone).



79
80
81
82
83
84
# File 'lib/legion/extensions/llm/canonical/message.rb', line 79

def self.normalize_tool_calls!(tool_calls, site)
  return nil if tool_calls.nil?

  Strict.expect_type!(tool_calls, [::Array], site, :tool_calls)
  tool_calls.map { |tc| tc.is_a?(ToolCall) ? tc : ToolCall.from_hash(tc) }
end

Instance Method Details

#as_jsonObject

MultiJson/Oj/::JSON callback — prevents Data.define #inspect leak into JSON.



106
107
108
# File 'lib/legion/extensions/llm/canonical/message.rb', line 106

def as_json(*)
  to_h
end

#textObject

Extract plain text from content (String or ContentBlock array).



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/legion/extensions/llm/canonical/message.rb', line 87

def text
  case content
  when String then content
  when Array
    content.filter_map do |block|
      block.is_a?(ContentBlock) && block.text? ? block.text : nil
    end.join
  when ContentBlock then content.text if content.text?
  else
    content.to_s
  end
end

#to_hObject

Serialize to a Hash for AMQP/fleet/wire transport.



101
102
103
# File 'lib/legion/extensions/llm/canonical/message.rb', line 101

def to_h
  super.compact
end

#to_jsonObject



110
111
112
# File 'lib/legion/extensions/llm/canonical/message.rb', line 110

def to_json(*)
  to_h.to_json(*)
end

#to_sObject

Human-readable string — prevents #inspect leaking into user-facing output.



115
116
117
# File 'lib/legion/extensions/llm/canonical/message.rb', line 115

def to_s
  text
end