legion-llm 0.14.4 → 0.14.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/legion-llm.gemspec +1 -1
- data/lib/legion/llm/api/client_translators/openai_responses.rb +4 -6
- data/lib/legion/llm/call/lex_llm_adapter.rb +1 -1
- data/lib/legion/llm/inference/executor/context_window.rb +2 -2
- data/lib/legion/llm/inference/executor.rb +1 -1
- data/lib/legion/llm/inference.rb +16 -9
- data/lib/legion/llm/types/message.rb +1 -1
- data/lib/legion/llm/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b12fc37520233aba6bc8b063e0334e5e1abb74970c5ba6a2efd9094bbd3414cf
|
|
4
|
+
data.tar.gz: f52cdb8f4cc7c7c2e67e0a6c8caa55fb842f736418955c4ec20d89a0b677212a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 598310ad96bad4d54ac02802a6d981294d5fb1faec31390fa6375e378f936f47f2336027255e0ca5c49f6db199b606528c8e96b70112325e41ccbb346245db11
|
|
7
|
+
data.tar.gz: 68c89f512cea238a856fdc5930155a7018cb095573f0de5de50bce8f03bb662c2b67abdd0f653a7f201139e3412806beef631f1f46dd80f065c18c0a496c489b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Legion LLM Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.8] - 2026-06-25
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Responses translator (`format_response`) no longer emits a message item with empty `output_text` when the response is pure tool_use (function_call items present). The empty text triggered Codex's `[Your previous response had no visible output]` injection on every tool turn.
|
|
8
|
+
|
|
9
|
+
## [0.14.7] - 2026-06-25
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `step_context_store` stores `typed_msg.text` (extracted string) instead of `typed_msg.content` (raw Array), preventing ContentBlock objects from being serialized as `#inspect` strings in conversation history.
|
|
14
|
+
- `Types::Message#text_from_block` recognizes `output_text`/`input_text` content block types so token estimation and text extraction work for Responses API content.
|
|
15
|
+
- `lex_llm_adapter.rb` `text_part_content` Data struct branch handles `output_text`/`input_text` types (previously only matched `type == 'text'`).
|
|
16
|
+
- `context_window.rb` `compact_to_fit` loops halving until messages fit the target token budget instead of a single halve that leaves payloads 2x over threshold for very large conversations.
|
|
17
|
+
- `emit_non_pipeline_metering` reads tokens from `response.usage.input_tokens` (correct) instead of `response.input_tokens` (non-existent on Canonical::Response), fixing zero-token metering for internal extension LLM calls (lex-apollo, legion-gaia, lex-knowledge, etc.).
|
|
18
|
+
- `emit_non_pipeline_metering` reads `response.metadata` instead of `response.meta`, passes `messages` and `response_content` to metering events.
|
|
19
|
+
|
|
20
|
+
## [0.14.5] - 2026-06-24
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Non-pipeline metering (`emit_non_pipeline_metering`) now correctly reads token counts from `response.usage` instead of the non-existent top-level `input_tokens`/`output_tokens` on `Canonical::Response`. Previously all internal LLM calls (via `Legion::LLM.structured`, `chat_single_native`) emitted zero-token metering events.
|
|
25
|
+
- Non-pipeline metering now includes `messages` and `response_content` fields, fixing null request/response JSON columns in the ledger for internal extension calls (lex-apollo, lex-agentic-self, legion-gaia, etc.).
|
|
26
|
+
- Non-pipeline metering reads `response.metadata` (correct field) instead of `response.meta` (does not exist on `Canonical::Response`) for latency/timing extraction.
|
|
27
|
+
|
|
3
28
|
## [0.14.4] - 2026-06-23
|
|
4
29
|
|
|
5
30
|
### Fixed
|
data/legion-llm.gemspec
CHANGED
|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency 'legion-settings', '>= 1.4.0'
|
|
35
35
|
spec.add_dependency 'legion-transport', '>= 1.4.14'
|
|
36
36
|
spec.add_dependency 'lex-knowledge'
|
|
37
|
-
spec.add_dependency 'lex-llm', '>= 0.6.
|
|
37
|
+
spec.add_dependency 'lex-llm', '>= 0.6.3'
|
|
38
38
|
spec.add_dependency 'pdf-reader'
|
|
39
39
|
spec.add_dependency 'sinatra-contrib', '>= 2.0'
|
|
40
40
|
spec.add_dependency 'tzinfo', '>= 2.0'
|
|
@@ -151,18 +151,16 @@ module Legion
|
|
|
151
151
|
server_tool_items = build_output_server_tool_items(pipeline_response)
|
|
152
152
|
reasoning = build_output_reasoning(pipeline_response)
|
|
153
153
|
|
|
154
|
-
output = [
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*actionable_tool_calls,
|
|
158
|
-
{
|
|
154
|
+
output = [*reasoning, *server_tool_items, *actionable_tool_calls]
|
|
155
|
+
unless content.to_s.strip.empty? && (actionable_tool_calls.any? || server_tool_items.any?)
|
|
156
|
+
output << {
|
|
159
157
|
type: 'message',
|
|
160
158
|
id: "msg_#{SecureRandom.hex(12)}",
|
|
161
159
|
role: 'assistant',
|
|
162
160
|
content: [{ type: 'output_text', text: content }],
|
|
163
161
|
status: 'completed'
|
|
164
162
|
}
|
|
165
|
-
|
|
163
|
+
end
|
|
166
164
|
|
|
167
165
|
# Responses protocol: a turn is always status `completed`. Both
|
|
168
166
|
# client-callable calls (actionable_tool_calls) and LegionIO-run
|
|
@@ -753,7 +753,7 @@ module Legion
|
|
|
753
753
|
if part.respond_to?(:type) || part.respond_to?(:text)
|
|
754
754
|
type = (part.respond_to?(:type) ? part.type.to_s : '')
|
|
755
755
|
text = part.respond_to?(:text) ? part.text : nil
|
|
756
|
-
return text.to_s if
|
|
756
|
+
return text.to_s if %w[text output_text input_text].include?(type) || (type.empty? && !text.nil?)
|
|
757
757
|
|
|
758
758
|
return nil
|
|
759
759
|
end
|
|
@@ -83,8 +83,8 @@ module Legion
|
|
|
83
83
|
|
|
84
84
|
return messages if estimate_message_tokens(messages) <= target_tokens
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
messages
|
|
86
|
+
messages = messages.last(messages.size / 2) while messages.size > 2 && estimate_message_tokens(messages) > target_tokens
|
|
87
|
+
messages
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def resolved_context_window
|
data/lib/legion/llm/inference.rb
CHANGED
|
@@ -605,7 +605,7 @@ module Legion
|
|
|
605
605
|
Call::Dispatch.call(provider: provider, instance: instance, capability: :chat, model: model,
|
|
606
606
|
messages: messages, **)
|
|
607
607
|
end
|
|
608
|
-
emit_non_pipeline_metering(result, model: model, provider: provider, caller: caller)
|
|
608
|
+
emit_non_pipeline_metering(result, model: model, provider: provider, caller: caller, messages: messages)
|
|
609
609
|
result
|
|
610
610
|
end
|
|
611
611
|
|
|
@@ -890,14 +890,13 @@ module Legion
|
|
|
890
890
|
esc[:quality_threshold] || 50
|
|
891
891
|
end
|
|
892
892
|
|
|
893
|
-
def emit_non_pipeline_metering(response, model:, provider:, caller: nil)
|
|
893
|
+
def emit_non_pipeline_metering(response, model:, provider:, caller: nil, messages: nil)
|
|
894
894
|
return unless response
|
|
895
895
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
thinking = (usage_hash[:thinking_tokens] || usage_hash[:thinking] || 0).to_i
|
|
896
|
+
usage = response.respond_to?(:usage) ? response.usage : nil
|
|
897
|
+
input = usage.respond_to?(:input_tokens) ? usage.input_tokens.to_i : 0
|
|
898
|
+
output = usage.respond_to?(:output_tokens) ? usage.output_tokens.to_i : 0
|
|
899
|
+
thinking = usage.respond_to?(:thinking_tokens) ? usage.thinking_tokens.to_i : 0
|
|
901
900
|
|
|
902
901
|
finish = nil
|
|
903
902
|
if response.respond_to?(:stop_reason)
|
|
@@ -906,11 +905,17 @@ module Legion
|
|
|
906
905
|
finish = response.stop[:reason]&.to_s
|
|
907
906
|
end
|
|
908
907
|
|
|
909
|
-
meta = response.respond_to?(:
|
|
908
|
+
meta = response.respond_to?(:metadata) ? response.metadata : {}
|
|
910
909
|
meta_hash = meta.is_a?(Hash) ? meta : {}
|
|
911
910
|
latency = (meta_hash[:latency_ms] || meta_hash.dig(:timing, :latency_ms) || 0).to_i
|
|
912
911
|
wall_clock = (meta_hash[:wall_clock_ms] || meta_hash.dig(:timing, :wall_clock_ms) || 0).to_i
|
|
913
912
|
|
|
913
|
+
response_content = if response.respond_to?(:text)
|
|
914
|
+
response.text
|
|
915
|
+
elsif response.respond_to?(:content)
|
|
916
|
+
response.content
|
|
917
|
+
end
|
|
918
|
+
|
|
914
919
|
Legion::LLM::Metering.emit(
|
|
915
920
|
provider: provider,
|
|
916
921
|
model_id: model,
|
|
@@ -926,7 +931,9 @@ module Legion
|
|
|
926
931
|
wall_clock_ms: wall_clock,
|
|
927
932
|
caller: caller,
|
|
928
933
|
event_type: 'llm_completion',
|
|
929
|
-
status: 'success'
|
|
934
|
+
status: 'success',
|
|
935
|
+
messages: messages,
|
|
936
|
+
response_content: response_content
|
|
930
937
|
)
|
|
931
938
|
rescue StandardError => e
|
|
932
939
|
handle_exception(e, level: :warn, operation: 'llm.inference.non_pipeline_metering')
|
|
@@ -93,7 +93,7 @@ module Legion
|
|
|
93
93
|
return nil unless block.is_a?(Hash)
|
|
94
94
|
|
|
95
95
|
type = block[:type] || block['type']
|
|
96
|
-
return nil unless type.nil? || type.to_s
|
|
96
|
+
return nil unless type.nil? || %w[text output_text input_text].include?(type.to_s)
|
|
97
97
|
|
|
98
98
|
block[:text] || block['text'] || block[:content] || block['content']
|
|
99
99
|
end
|
data/lib/legion/llm/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-llm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.14.
|
|
4
|
+
version: 0.14.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -141,14 +141,14 @@ dependencies:
|
|
|
141
141
|
requirements:
|
|
142
142
|
- - ">="
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: 0.6.
|
|
144
|
+
version: 0.6.3
|
|
145
145
|
type: :runtime
|
|
146
146
|
prerelease: false
|
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
148
148
|
requirements:
|
|
149
149
|
- - ">="
|
|
150
150
|
- !ruby/object:Gem::Version
|
|
151
|
-
version: 0.6.
|
|
151
|
+
version: 0.6.3
|
|
152
152
|
- !ruby/object:Gem::Dependency
|
|
153
153
|
name: pdf-reader
|
|
154
154
|
requirement: !ruby/object:Gem::Requirement
|