legion-llm 0.9.29 → 0.9.30

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 914f95fd880bbb73c043d16612bbf22fc22569455b721fe9052b5ee4c55e83b3
4
- data.tar.gz: 0a2f12babcae95cab6c9f2e0ee8b5207c26d998aafcee464d457af7ebea4dc16
3
+ metadata.gz: 221d8482faa90a3fa8e4bbefe90999838a56b96bc34d6506956f6b8ac90ab290
4
+ data.tar.gz: a3c3ce4cde046e8cd1af18874e04da1698d4527549fc70df274d14c0830f3803
5
5
  SHA512:
6
- metadata.gz: 52a9853e3c2337d19a0e4517d0472143e9aa809dd94363655db76a94ed924041b95b20a1038442053fc8b30f4c035782335a6edc0ad9634cb17e7f6c59c81f4b
7
- data.tar.gz: bd2f8b50e52e0653cedcb44c0c18105c212151b64baab5dd62248a456e917bdae8e8347d83d7c8c4dd535da354f00795d938643e94e95ec03657c03d2bfa33a2
6
+ metadata.gz: fd2fdd7bce06cd6efa9a8b583072b947f14ffdaa5a1898b65f2027da8693c79bdd56b3553d04f6f6329f2f3a9d71c0699947f371aa5715708fd538a144819363
7
+ data.tar.gz: 7c3c36ca8b7db0075b18ea656e3c13c9235d873362d8febbe663c96eb07a1fa562a16d754f1bfed42d909698b466c303d7395e79caa0093ad1d1008c64389f69
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Legion LLM Changelog
2
2
 
3
+ ## [0.9.30] - 2026-05-16
4
+
5
+ ### Fixed
6
+ - Tools: API-submitted client tools are no longer advertised to providers unless callers explicitly opt into client-tool passthrough, preventing incomplete tool calls from ending streaming responses.
7
+
3
8
  ## [0.9.29] - 2026-05-16
4
9
 
5
10
  ### Added
@@ -149,7 +149,7 @@ module Legion
149
149
  name: tname,
150
150
  description: tdesc,
151
151
  parameters: tschema,
152
- source: { type: :client, executable: false }
152
+ source: { type: :client, executable: true }
153
153
  )
154
154
  rescue StandardError => e
155
155
  log.warn("[llm][api][anthropic][messages] build_tool_classes failed name=#{tname} error=#{e.message}")
@@ -28,6 +28,7 @@ module Legion
28
28
  conversation_id = body[:conversation_id]
29
29
  request_id = body[:request_id] || SecureRandom.uuid
30
30
  include_thinking = body[:include_thinking] == true
31
+ client_tool_passthrough = body[:client_tool_passthrough] == true
31
32
 
32
33
  unless messages.is_a?(Array)
33
34
  halt 400, { 'Content-Type' => 'application/json' },
@@ -103,6 +104,9 @@ module Legion
103
104
 
104
105
  extra = {}
105
106
  extra[:tier] = tier.to_sym if tier
107
+ metadata = { requested_tools: requested_tools }
108
+ metadata[:client_tool_passthrough] = true if client_tool_passthrough
109
+ metadata[:client_tool_request_count] = tools.size if tools.any?
106
110
 
107
111
  pipeline_request = Legion::LLM::Inference::Request.build(
108
112
  id: request_id,
@@ -112,7 +116,7 @@ module Legion
112
116
  tools: tool_declarations,
113
117
  caller: effective_caller,
114
118
  conversation_id: conversation_id,
115
- metadata: { requested_tools: requested_tools },
119
+ metadata: metadata,
116
120
  stream: streaming,
117
121
  cache: { strategy: :default, cacheable: true },
118
122
  extra: extra
@@ -123,7 +123,7 @@ module Legion
123
123
  name: t[:name].to_s,
124
124
  description: t[:description].to_s,
125
125
  parameters: t[:parameters] || {},
126
- source: { type: :client, executable: false }
126
+ source: { type: :client, executable: true }
127
127
  )
128
128
  rescue StandardError => e
129
129
  tool_name = t.is_a?(Hash) ? t[:name] : nil
@@ -939,6 +939,23 @@ module Legion
939
939
  !(@request.respond_to?(:suppress_tools) && @request.suppress_tools)
940
940
  end
941
941
 
942
+ def client_tool_passthrough_enabled?
943
+ return false unless @request.respond_to?(:metadata)
944
+
945
+ metadata = @request.metadata || {}
946
+ value = metadata[:client_tool_passthrough] || metadata['client_tool_passthrough']
947
+ value == true
948
+ end
949
+
950
+ def non_executable_client_tool?(definition)
951
+ source = definition.respond_to?(:source) ? definition.source : {}
952
+ return false unless source.is_a?(Hash)
953
+
954
+ source_type = source[:type] || source['type']
955
+ executable = source.key?(:executable) ? source[:executable] : source['executable']
956
+ source_type.respond_to?(:to_sym) && source_type.to_sym == :client && executable != true
957
+ end
958
+
942
959
  def add_pinned_special_tool_definitions(definitions)
943
960
  Tools::Special.pinned_definitions.each do |definition|
944
961
  next if definitions.any? { |existing| existing.name == definition.name }
@@ -957,6 +974,14 @@ module Legion
957
974
  else
958
975
  Types::ToolDefinition.from_tool_class(tool)
959
976
  end
977
+ if non_executable_client_tool?(definition) && !client_tool_passthrough_enabled?
978
+ log.info(
979
+ "[llm][tools][inject] action=client_tool_skipped request_id=#{request_log_value(:id, 'unknown')} " \
980
+ "conversation_id=#{request_log_value(:conversation_id, 'none') || 'none'} name=#{definition.name} " \
981
+ 'reason=client_passthrough_not_enabled'
982
+ )
983
+ return
984
+ end
960
985
  return if gaia_tool_suppressed?(definition.name)
961
986
  return if definitions.any? { |existing| existing.name == definition.name }
962
987
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module LLM
5
- VERSION = '0.9.29'
5
+ VERSION = '0.9.30'
6
6
  end
7
7
  end
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.9.29
4
+ version: 0.9.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity