Class: Legion::Extensions::Llm::Canonical::Chunk

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

Overview

Canonical streaming chunk with full lifecycle support. Per R4: block_index/item_id/signature lifecycle, multi-tool-call deltas. Per G20d: strict on produce, ignore-unknown on consume.

Constant Summary collapse

CHUNK_TYPES =
%i[text_delta thinking_delta tool_call_delta usage done error].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#block_indexObject (readonly)

Returns the value of attribute block_index

Returns:

  • (Object)

    the current value of block_index



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def block_index
  @block_index
end

#conversation_idObject (readonly)

Returns the value of attribute conversation_id

Returns:

  • (Object)

    the current value of conversation_id



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def conversation_id
  @conversation_id
end

#deltaObject (readonly)

Returns the value of attribute delta

Returns:

  • (Object)

    the current value of delta



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def delta
  @delta
end

#exchange_idObject (readonly)

Returns the value of attribute exchange_id

Returns:

  • (Object)

    the current value of exchange_id



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def exchange_id
  @exchange_id
end

#indexObject (readonly)

Returns the value of attribute index

Returns:

  • (Object)

    the current value of index



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def index
  @index
end

#item_idObject (readonly)

Returns the value of attribute item_id

Returns:

  • (Object)

    the current value of item_id



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def item_id
  @item_id
end

#metadataObject (readonly)

Returns the value of attribute metadata

Returns:

  • (Object)

    the current value of metadata



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def 
  @metadata
end

#request_idObject (readonly)

Returns the value of attribute request_id

Returns:

  • (Object)

    the current value of request_id



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def request_id
  @request_id
end

#signatureObject (readonly)

Returns the value of attribute signature

Returns:

  • (Object)

    the current value of signature



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def signature
  @signature
end

#stop_reasonObject (readonly)

Returns the value of attribute stop_reason

Returns:

  • (Object)

    the current value of stop_reason



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def stop_reason
  @stop_reason
end

#timestampObject (readonly)

Returns the value of attribute timestamp

Returns:

  • (Object)

    the current value of timestamp



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def timestamp
  @timestamp
end

#tool_callObject (readonly)

Returns the value of attribute tool_call

Returns:

  • (Object)

    the current value of tool_call



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def tool_call
  @tool_call
end

#typeObject (readonly)

Returns the value of attribute type

Returns:

  • (Object)

    the current value of type



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def type
  @type
end

#usageObject (readonly)

Returns the value of attribute usage

Returns:

  • (Object)

    the current value of usage



11
12
13
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 11

def usage
  @usage
end

Class Method Details

.done(request_id:, usage: nil, stop_reason: nil, conversation_id: nil, exchange_id: nil) ⇒ Object

Build a done chunk.



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

def self.done(request_id:, usage: nil, stop_reason: nil, conversation_id: nil, exchange_id: nil)
  new(
    type: :done, request_id: request_id,
    conversation_id: conversation_id, exchange_id: exchange_id,
    index: nil, block_index: nil, item_id: nil,
    delta: nil, tool_call: nil, signature: nil,
    usage: usage, stop_reason: stop_reason, metadata: {},
    timestamp: ::Time.now
  )
end

.error_chunk(error:, request_id:, conversation_id: nil, exchange_id: nil, metadata: nil) ⇒ Object

Build an error chunk.



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 81

def self.error_chunk(error:, request_id:, conversation_id: nil, exchange_id: nil, metadata: nil)
  new(
    type: :error, request_id: request_id,
    conversation_id: conversation_id, exchange_id: exchange_id,
    index: nil, block_index: nil, item_id: nil,
    delta: nil, tool_call: nil, signature: nil,
    usage: nil, stop_reason: :error,
    metadata: ( || {}).merge(error: error),
    timestamp: ::Time.now
  )
end

.from_hash(source) ⇒ Object

Build from a Hash (raw provider response or deserialized wire payload). Per G20d: ignore-unknown on consume — unknown chunk types are passed through.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 95

def self.from_hash(source)
  return nil if source.nil?

  h = source.transform_keys(&:to_sym)

  # Normalize type
  type_raw = h.delete(:type)
  type_sym = type_raw&.to_sym if type_raw

  # Normalize nested objects
  tool_call_raw = h.delete(:tool_call)
  h[:tool_call] = if tool_call_raw.is_a?(ToolCall)
                    tool_call_raw
                  elsif tool_call_raw.is_a?(Hash)
                    ToolCall.from_hash(tool_call_raw)
                  end

  usage_raw = h.delete(:usage)
  h[:usage] = if usage_raw.is_a?(Usage)
                usage_raw
              elsif usage_raw.is_a?(Hash)
                Usage.from_hash(usage_raw)
              end

  # Normalize stop_reason
  stop_reason_raw = h.delete(:stop_reason) || h.delete(:finish_reason)
  h[:stop_reason] = stop_reason_raw&.to_sym if stop_reason_raw

  # Ensure metadata is a Hash
  h[:metadata] = h[:metadata] || {}

  # Provide defaults for missing fields
  new(
    request_id: h[:request_id],
    conversation_id: h[:conversation_id],
    exchange_id: h[:exchange_id],
    index: h[:index],
    type: type_sym,
    block_index: h[:block_index],
    item_id: h[:item_id],
    delta: h[:delta],
    tool_call: h[:tool_call],
    signature: h[:signature],
    usage: h[:usage],
    stop_reason: h[:stop_reason],
    metadata: h[:metadata],
    timestamp: h[:timestamp] || ::Time.now
  )
end

.text_delta(delta:, request_id:, conversation_id: nil, exchange_id: nil, index: 0, block_index: nil, item_id: nil) ⇒ Object

Build a text delta chunk.



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 18

def self.text_delta(delta:, request_id:, conversation_id: nil, exchange_id: nil,
                    index: 0, block_index: nil, item_id: nil)
  new(
    type: :text_delta, delta: delta, index: index,
    request_id: request_id, conversation_id: conversation_id,
    exchange_id: exchange_id, block_index: block_index,
    item_id: item_id, tool_call: nil, signature: nil,
    usage: nil, stop_reason: nil, metadata: {},
    timestamp: ::Time.now
  )
end

.thinking_delta(delta:, request_id:, conversation_id: nil, exchange_id: nil, index: 0, block_index: nil, item_id: nil, signature: nil) ⇒ Object

Build a thinking delta chunk.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 31

def self.thinking_delta(delta:, request_id:, conversation_id: nil, exchange_id: nil,
                        index: 0, block_index: nil, item_id: nil, signature: nil)
  new(
    type: :thinking_delta, delta: delta, index: index,
    request_id: request_id, conversation_id: conversation_id,
    exchange_id: exchange_id, block_index: block_index,
    item_id: item_id, tool_call: nil, signature: signature,
    usage: nil, stop_reason: nil, metadata: {},
    timestamp: ::Time.now
  )
end

.tool_call_delta(tool_call:, request_id:, conversation_id: nil, exchange_id: nil, index: 0, block_index: nil, item_id: nil) ⇒ Object

Build a tool_call_delta chunk (supports multiple in-flight tool calls via tool_call.id).



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 44

def self.tool_call_delta(tool_call:, request_id:, conversation_id: nil, exchange_id: nil,
                         index: 0, block_index: nil, item_id: nil)
  new(
    type: :tool_call_delta, index: index,
    request_id: request_id, conversation_id: conversation_id,
    exchange_id: exchange_id, block_index: block_index,
    item_id: item_id, delta: nil, tool_call: tool_call, signature: nil,
    usage: nil, stop_reason: nil, metadata: {},
    timestamp: ::Time.now
  )
end

.usage_chunk(usage:, request_id:, conversation_id: nil, exchange_id: nil) ⇒ Object

Build a usage chunk.



57
58
59
60
61
62
63
64
65
66
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 57

def self.usage_chunk(usage:, request_id:, conversation_id: nil, exchange_id: nil)
  new(
    type: :usage, request_id: request_id,
    conversation_id: conversation_id, exchange_id: exchange_id,
    index: nil, block_index: nil, item_id: nil,
    delta: nil, tool_call: nil, signature: nil,
    usage: usage, stop_reason: nil, metadata: {},
    timestamp: ::Time.now
  )
end

Instance Method Details

#content?Boolean

Whether this chunk carries content (text or thinking).

Returns:

  • (Boolean)


174
175
176
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 174

def content?
  %i[text_delta thinking_delta].include?(type)
end

#done?Boolean

Returns:

  • (Boolean)


170
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 170

def done? = type == :done

#error?Boolean

Returns:

  • (Boolean)


171
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 171

def error? = type == :error

#text_delta?Boolean

Type predicate helpers.

Returns:

  • (Boolean)


166
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 166

def text_delta? = type == :text_delta

#thinking_delta?Boolean

Returns:

  • (Boolean)


167
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 167

def thinking_delta? = type == :thinking_delta

#to_hObject

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



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 146

def to_h
  {
    request_id: request_id,
    conversation_id: conversation_id,
    exchange_id: exchange_id,
    index: index,
    type: type,
    block_index: block_index,
    item_id: item_id,
    delta: delta,
    tool_call: tool_call&.to_h,
    signature: signature,
    usage: usage&.to_h,
    stop_reason: stop_reason,
    metadata: ,
    timestamp: timestamp
  }.compact
end

#tool_call_delta?Boolean

Returns:

  • (Boolean)


168
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 168

def tool_call_delta? = type == :tool_call_delta

#usage?Boolean

Returns:

  • (Boolean)


169
# File 'lib/legion/extensions/llm/canonical/chunk.rb', line 169

def usage? = type == :usage