Class: Legion::Extensions::Llm::Canonical::Response
- Inherits:
-
Data
- Object
- Data
- Legion::Extensions::Llm::Canonical::Response
- Defined in:
- lib/legion/extensions/llm/canonical/response.rb
Overview
rubocop:disable Lint/ConstantDefinitionInBlock – required for Data.define block scope Canonical response shape — the provider-boundary contract. Per R2: does NOT replace Inference::Response (the pipeline envelope). Per Amendment A: immutable Data.define with strict factory.
Constant Summary collapse
- STOP_REASONS =
%i[end_turn tool_use max_tokens stop_sequence content_filter error].freeze
Instance Attribute Summary collapse
-
#metadata ⇒ Object
readonly
Returns the value of attribute metadata.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#routing ⇒ Object
readonly
Returns the value of attribute routing.
-
#stop_reason ⇒ Object
readonly
Returns the value of attribute stop_reason.
-
#text ⇒ Object
readonly
Returns the value of attribute text.
-
#thinking ⇒ Object
readonly
Returns the value of attribute thinking.
-
#tool_calls ⇒ Object
readonly
Returns the value of attribute tool_calls.
-
#usage ⇒ Object
readonly
Returns the value of attribute usage.
Class Method Summary collapse
-
.build(text: '', thinking: nil, tool_calls: nil, usage: nil, stop_reason: nil, model: nil, routing: nil, metadata: nil) ⇒ Object
Build from keyword args (primary constructor).
-
.from_hash(source) ⇒ Object
Build from a Hash (raw provider response or deserialized wire payload).
Instance Method Summary collapse
-
#error? ⇒ Boolean
Whether the response ended due to an error.
-
#to_h ⇒ Object
Serialize to a Hash for AMQP/fleet/wire transport.
-
#tool_call? ⇒ Boolean
Whether the response includes tool calls.
Instance Attribute Details
#metadata ⇒ Object (readonly)
Returns the value of attribute metadata
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def @metadata end |
#model ⇒ Object (readonly)
Returns the value of attribute model
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def model @model end |
#routing ⇒ Object (readonly)
Returns the value of attribute routing
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def routing @routing end |
#stop_reason ⇒ Object (readonly)
Returns the value of attribute stop_reason
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def stop_reason @stop_reason end |
#text ⇒ Object (readonly)
Returns the value of attribute text
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def text @text end |
#thinking ⇒ Object (readonly)
Returns the value of attribute thinking
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def thinking @thinking end |
#tool_calls ⇒ Object (readonly)
Returns the value of attribute tool_calls
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def tool_calls @tool_calls end |
#usage ⇒ Object (readonly)
Returns the value of attribute usage
12 13 14 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 12 def usage @usage end |
Class Method Details
.build(text: '', thinking: nil, tool_calls: nil, usage: nil, stop_reason: nil, model: nil, routing: nil, metadata: nil) ⇒ Object
Build from keyword args (primary constructor).
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 68 def self.build( text: '', thinking: nil, tool_calls: nil, usage: nil, stop_reason: nil, model: nil, routing: nil, metadata: nil ) stop_reason_sym = stop_reason&.to_sym unless stop_reason_sym.nil? || STOP_REASONS.include?(stop_reason_sym) raise ArgumentError, "Invalid stop_reason: #{stop_reason_sym.inspect}. Must be one of: #{STOP_REASONS.join(', ')}" end new( text: text.to_s, thinking: thinking, tool_calls: tool_calls || [], usage: usage, stop_reason: stop_reason_sym, model: model, routing: routing || {}, metadata: || {} ) end |
.from_hash(source) ⇒ Object
Build from a Hash (raw provider response or deserialized wire payload). Unknown keys go to metadata, never silently dropped.
20 21 22 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 20 def self.from_hash(source) return nil if source.nil? h = source.transform_keys(&:to_sym) # Extract known fields text = h.delete(:text) || h.delete(:content) || '' text = text.to_s if text thinking_raw = h.delete(:thinking) thinking = thinking_raw.is_a?(Thinking) ? thinking_raw : Thinking.from_hash(thinking_raw) tool_calls_raw = h.delete(:tool_calls) tool_calls = Array(tool_calls_raw).filter_map do |tc| tc.is_a?(ToolCall) ? tc : ToolCall.from_hash(tc) end usage_raw = h.delete(:usage) usage = usage_raw.is_a?(Usage) ? usage_raw : Usage.from_hash(usage_raw) # Normalize stop_reason stop_reason_raw = h.delete(:stop_reason) || h.delete(:finish_reason) stop_reason = stop_reason_raw&.to_sym if stop_reason_raw unless stop_reason.nil? || STOP_REASONS.include?(stop_reason) raise ArgumentError, "Invalid stop_reason: #{stop_reason.inspect}. Must be one of: #{STOP_REASONS.join(', ')}" end model = h.delete(:model) routing = h.delete(:routing) || {} # Remaining keys become metadata = h.delete(:metadata) || {} = .merge(h).compact new( text: text, thinking: thinking, tool_calls: tool_calls, usage: usage, stop_reason: stop_reason, model: model, routing: routing, metadata: ) end |
Instance Method Details
#error? ⇒ Boolean
Whether the response ended due to an error.
113 114 115 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 113 def error? stop_reason == :error end |
#to_h ⇒ Object
Serialize to a Hash for AMQP/fleet/wire transport.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 91 def to_h { text: text, thinking: thinking&.to_h, tool_calls: tool_calls&.map { |tc| tc.is_a?(ToolCall) ? tc.to_h : tc }, usage: usage&.to_h, stop_reason: stop_reason, model: model, routing: routing, metadata: }.compact.reject do |k, v| %i[tool_calls routing metadata].include?(k) && v.is_a?(Enumerable) && v.empty? end end |
#tool_call? ⇒ Boolean
Whether the response includes tool calls.
108 109 110 |
# File 'lib/legion/extensions/llm/canonical/response.rb', line 108 def tool_call? !tool_calls.nil? && !tool_calls.empty? end |