legion-llm 0.8.18 → 0.8.21
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 +18 -0
- data/lib/legion/llm/api/native/helpers.rb +4 -2
- data/lib/legion/llm/api/native/inference.rb +2 -0
- data/lib/legion/llm/inference/executor.rb +28 -0
- data/lib/legion/llm/settings.rb +1 -1
- data/lib/legion/llm/skills/base.rb +1 -1
- data/lib/legion/llm/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fdd5beb0c0e3a464cd06848369ec4cf9c07beab7a9c1560cfc0d13e1a6dc721
|
|
4
|
+
data.tar.gz: 2539e7e1a1cebcd9ba363ac66f79c08f9314d7477d482f1d17a7bf6185e1fd0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 377c8498427bbe07d0dd171ce8fba340683ac8fb0286b781092caa24eb19c038fc9e621115bfcbfe12aee25c1f84aa267b4c289b03cd9424a2beee0d31ccf128
|
|
7
|
+
data.tar.gz: 611ab93b2732f10aaac6015b2fc042af6de8963b23012c73a00a6c6a36477639a61763ace1be0e65eb2f38c815cd0418c9d118a644090324a6de53b98cc2f5a6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Legion LLM Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.21] - 2026-04-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Tool audit events are now published to `llm.audit` exchange via `Audit.emit_tools` after each tool execution completes. Previously `emit_tools` was defined but never called — the `llm.audit.tools` queue was always empty.
|
|
7
|
+
- Metering events now include `request_type: 'chat'` so the routing key is `metering.chat` instead of `metering.` (empty suffix).
|
|
8
|
+
|
|
9
|
+
## [0.8.20] - 2026-04-22
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `tool_trigger_defaults[:tool_limit]` raised from 10 to 25. The v0.8.19 reduction from 50→10 was too aggressive — extension tools (Teams, etc.) are only injected via trigger matching, and a limit of 10 crowded them out when multiple extensions matched.
|
|
13
|
+
|
|
14
|
+
## [0.8.19] - 2026-04-22
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `Skills::Base#emit_event` passed a positional Hash to `Legion::Events.emit(**payload)`, causing `ArgumentError` on every skill activation. Now uses keyword splat correctly.
|
|
18
|
+
- `file_edit` client tool crashed with `TypeError: no implicit conversion of nil into String` when the LLM passed nil `old_text`/`new_text`. Now returns an error message to the LLM instead of crashing.
|
|
19
|
+
- `tool_trigger_defaults[:tool_limit]` reduced from 50 to 10 to prevent trigger word matching from injecting dozens of unrelated extension tools on normal user messages.
|
|
20
|
+
|
|
3
21
|
## [0.8.18] - 2026-04-22
|
|
4
22
|
|
|
5
23
|
### Fixed
|
|
@@ -37,7 +37,7 @@ module Legion
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def dispatch_client_tool(ref, **kwargs) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
|
|
40
|
+
def dispatch_client_tool(ref, **kwargs) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
41
41
|
case ref
|
|
42
42
|
when 'sh'
|
|
43
43
|
cmd = kwargs[:command] || kwargs[:cmd] || kwargs.values.first.to_s
|
|
@@ -55,8 +55,10 @@ module Legion
|
|
|
55
55
|
path = kwargs[:path] || kwargs[:file_path]
|
|
56
56
|
old_text = kwargs[:old_text] || kwargs[:search]
|
|
57
57
|
new_text = kwargs[:new_text] || kwargs[:replace]
|
|
58
|
+
return 'file_edit error: old_text is required' if old_text.nil? || old_text.empty?
|
|
59
|
+
|
|
58
60
|
content = ::File.read(path, encoding: 'utf-8')
|
|
59
|
-
content.sub!(old_text, new_text)
|
|
61
|
+
content.sub!(old_text, new_text || '')
|
|
60
62
|
::File.write(path, content)
|
|
61
63
|
"Edited #{path}"
|
|
62
64
|
when 'list_directory'
|
|
@@ -179,6 +179,7 @@ module Legion
|
|
|
179
179
|
"conversation_id=#{pipeline_response.conversation_id || conversation_id || 'none'} " \
|
|
180
180
|
"provider=#{routing[:provider] || routing['provider'] || 'unknown'} " \
|
|
181
181
|
"model=#{routing[:model] || routing['model'] || 'unknown'} " \
|
|
182
|
+
"input_tokens=#{token_value(tokens, :input) || 0} output_tokens=#{token_value(tokens, :output) || 0} " \
|
|
182
183
|
"tool_calls=#{extract_tool_calls(pipeline_response).size} " \
|
|
183
184
|
"tool_executions=#{Array(pipeline_response.timeline).count { |event| event[:key].to_s.start_with?('tool:execute:') }} " \
|
|
184
185
|
"stop_reason=#{pipeline_response.stop&.dig(:reason) || 'unknown'} stream=true"
|
|
@@ -204,6 +205,7 @@ module Legion
|
|
|
204
205
|
"conversation_id=#{pipeline_response.conversation_id || conversation_id || 'none'} " \
|
|
205
206
|
"provider=#{routing[:provider] || routing['provider'] || 'unknown'} " \
|
|
206
207
|
"model=#{routing[:model] || routing['model'] || 'unknown'} " \
|
|
208
|
+
"input_tokens=#{token_value(tokens, :input) || 0} output_tokens=#{token_value(tokens, :output) || 0} " \
|
|
207
209
|
"tool_calls=#{tool_calls.size} " \
|
|
208
210
|
"tool_executions=#{Array(pipeline_response.timeline).count { |event| event[:key].to_s.start_with?('tool:execute:') }} " \
|
|
209
211
|
"stop_reason=#{pipeline_response.stop&.dig(:reason) || 'unknown'} stream=false"
|
|
@@ -842,6 +842,33 @@ module Legion
|
|
|
842
842
|
result: result_str[0, 4096], result_size: result_str.bytesize,
|
|
843
843
|
started_at: started_at, finished_at: finished_at, duration_ms: duration_ms
|
|
844
844
|
)
|
|
845
|
+
|
|
846
|
+
publish_tool_audit(tc_id, tc_name, result_str, is_error, duration_ms, started_at, finished_at)
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
def publish_tool_audit(tc_id, tc_name, result_str, is_error, duration_ms, started_at, finished_at)
|
|
850
|
+
Legion::LLM::Audit.emit_tools(
|
|
851
|
+
request_id: @request.id,
|
|
852
|
+
conversation_id: @request.conversation_id,
|
|
853
|
+
exchange_id: @exchange_id,
|
|
854
|
+
tool_name: tc_name,
|
|
855
|
+
tool_call: {
|
|
856
|
+
id: tc_id,
|
|
857
|
+
name: tc_name,
|
|
858
|
+
status: is_error ? :error : :success,
|
|
859
|
+
duration_ms: duration_ms,
|
|
860
|
+
started_at: started_at,
|
|
861
|
+
finished_at: finished_at
|
|
862
|
+
},
|
|
863
|
+
result: result_str[0, 4096],
|
|
864
|
+
caller: @request.caller,
|
|
865
|
+
classification: @request.classification,
|
|
866
|
+
tracing: @tracing,
|
|
867
|
+
timestamp: finished_at,
|
|
868
|
+
request_type: 'tool'
|
|
869
|
+
)
|
|
870
|
+
rescue StandardError => e
|
|
871
|
+
handle_exception(e, level: :warn, operation: 'llm.pipeline.publish_tool_audit', tool_name: tc_name)
|
|
845
872
|
end
|
|
846
873
|
|
|
847
874
|
def tool_call_field(tool_call, field)
|
|
@@ -1004,6 +1031,7 @@ module Legion
|
|
|
1004
1031
|
provider: @resolved_provider,
|
|
1005
1032
|
model_id: @resolved_model,
|
|
1006
1033
|
tier: tier,
|
|
1034
|
+
request_type: 'chat',
|
|
1007
1035
|
input_tokens: input_tokens,
|
|
1008
1036
|
output_tokens: output_tokens,
|
|
1009
1037
|
latency_ms: latency_ms
|
data/lib/legion/llm/settings.rb
CHANGED
|
@@ -246,7 +246,7 @@ module Legion
|
|
|
246
246
|
def emit_event(conv_id, event, **payload)
|
|
247
247
|
return unless conv_id
|
|
248
248
|
|
|
249
|
-
Legion::Events.emit(event,
|
|
249
|
+
Legion::Events.emit(event, conversation_id: conv_id, **payload)
|
|
250
250
|
end
|
|
251
251
|
|
|
252
252
|
protected
|
data/lib/legion/llm/version.rb
CHANGED