lex-llm 0.4.13 → 0.4.15

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: 6d60f78c459fb43344897e6fdba10730b881f698229058a50a1c1be2564539cf
4
- data.tar.gz: d7fcedadb69266af972caf1a51d1153bd5270f1fd5e9b45f65d51076fafa07aa
3
+ metadata.gz: 0d1285ba64b40e878ef58be2e434d7a9090a38c7e9a6a9a12c85fe756096196b
4
+ data.tar.gz: 646974d7c04db898d1f1bbf251dd1c4f74df3d8c7b5b66803358b00e7d2663d4
5
5
  SHA512:
6
- metadata.gz: c60726bfac3eff11cf37d8035ad78c7437b627f465bad31efdac1be3061fe410dc176d805bd168389859fa94773cd994578d265a6534a8e3feed1d37db517988
7
- data.tar.gz: 40439ec46e06530b9e5d287fe8d5980d57b87c2700343b3282c30deb9cd1b241862812e4264a9842d6a1fea20aa9bcb4f580cf08ed31cc61b73c00c2c753c9ce
6
+ metadata.gz: 85d596886b1809404194d7394d5a727bc39464adfd7e847d5d510323d6b777d8831a1a4a2343ba3f814e15415a648afdb78821eb42401b0353f1803bd3ff446f
7
+ data.tar.gz: 5778d0da0bf25dc6acf52553f956dc15eed37efd2de31143006026f3833287a7d872d2640ee260ab4292d16a8c0e04a0b9cde27a1b6f9ff9293d68ecfe17b155
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.15 - 2026-05-21
4
+
5
+ - Add `identity_headers` to base provider — all API calls now include x-legion-identity-* headers when Identity is resolved
6
+ - Add `offering_transport` and `offering_tier` instance methods with class-level `default_transport`/`default_tier` overrides
7
+ - Add `runtime_provider_setting` fallback for model_whitelist/blacklist from Legion::Settings
8
+ - Remove duplicate `offering_transport`/`offering_tier` definitions
9
+
10
+
11
+ ## 0.4.14 - 2026-05-16
12
+
13
+ - Normalize `function_calling`, `functions`, and related tool-use capability aliases to include canonical `:tools` on model metadata and routing offerings.
14
+ - Keep provider compatibility aliases while allowing capability filters to reliably match tool-capable models.
15
+
3
16
  ## 0.4.13 - 2026-05-15
4
17
 
5
18
  - Strip provider thinking from OpenAI-compatible responses when local models emit `<thinking>` tags or untagged initial reasoning preambles, and keep those hidden from live streaming content deltas.
data/Gemfile CHANGED
@@ -20,6 +20,7 @@ group :development do
20
20
  gem 'reline'
21
21
  gem 'rspec', '~> 3.12'
22
22
  gem 'rubocop', '>= 1.0'
23
+ gem 'rubocop-legion'
23
24
  gem 'rubocop-performance'
24
25
  gem 'rubocop-rake', '>= 0.6'
25
26
  gem 'rubocop-rspec'
@@ -4,6 +4,15 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Model
7
+ CAPABILITY_ALIASES = {
8
+ function_calling: :tools,
9
+ functions: :tools,
10
+ tool: :tools,
11
+ tool_use: :tools,
12
+ stream: :streaming,
13
+ stream_chat: :streaming
14
+ }.freeze
15
+
7
16
  Info = ::Data.define(
8
17
  :id, :name, :provider, :instance, :family,
9
18
  :capabilities, :context_length, :parameter_count,
@@ -171,7 +180,14 @@ module Legion
171
180
  private
172
181
 
173
182
  def normalize_symbols(value)
174
- Array(value).map { |v| v.to_s.downcase.strip.to_sym }.uniq
183
+ Array(value).compact.each_with_object([]) do |item, normalized|
184
+ symbol = item.to_s.downcase.strip.to_sym
185
+ next if symbol.to_s.empty?
186
+
187
+ normalized << symbol
188
+ alias_symbol = CAPABILITY_ALIASES[symbol]
189
+ normalized << alias_symbol if alias_symbol
190
+ end.uniq
175
191
  end
176
192
 
177
193
  def to_int(value)
@@ -43,6 +43,25 @@ module Legion
43
43
  end
44
44
 
45
45
  def headers
46
+ identity_headers
47
+ end
48
+
49
+ def identity_headers
50
+ return {} unless defined?(Legion::Identity::Process) && Legion::Identity::Process.respond_to?(:identity_hash)
51
+
52
+ id = Legion::Identity::Process.identity_hash
53
+ hdrs = {
54
+ 'x-legion-identity-canonical-name' => id[:canonical_name].to_s,
55
+ 'x-legion-identity-trust' => id[:trust].to_s,
56
+ 'x-legion-identity-id' => id[:id].to_s,
57
+ 'x-legion-identity-kind' => id[:kind].to_s,
58
+ 'x-legion-identity-mode' => id[:mode].to_s,
59
+ 'x-legion-identity-source' => id[:source].to_s
60
+ }
61
+ hdrs['x-legion-identity-db-principal-id'] = id[:db_principal_id].to_s if id[:db_principal_id]
62
+ hdrs['x-legion-identity-db-identity-id'] = id[:db_identity_id].to_s if id[:db_identity_id]
63
+ hdrs
64
+ rescue StandardError
46
65
  {}
47
66
  end
48
67
 
@@ -292,16 +311,33 @@ module Legion
292
311
 
293
312
  def model_whitelist
294
313
  wl = config.model_whitelist if config.respond_to?(:model_whitelist)
295
- wl ||= settings[:model_whitelist] if respond_to?(:settings)
314
+ wl ||= settings[:model_whitelist] if respond_to?(:settings) && settings.is_a?(Hash)
315
+ wl ||= runtime_provider_setting(:model_whitelist)
296
316
  Array(wl).map { |p| p.to_s.downcase }
297
317
  end
298
318
 
299
319
  def model_blacklist
300
320
  bl = config.model_blacklist if config.respond_to?(:model_blacklist)
301
- bl ||= settings[:model_blacklist] if respond_to?(:settings)
321
+ bl ||= settings[:model_blacklist] if respond_to?(:settings) && settings.is_a?(Hash)
322
+ bl ||= runtime_provider_setting(:model_blacklist)
302
323
  Array(bl).map { |p| p.to_s.downcase }
303
324
  end
304
325
 
326
+ def runtime_provider_setting(key)
327
+ return nil unless defined?(Legion::Settings)
328
+
329
+ ext = Legion::Settings[:extensions]
330
+ return nil unless ext.is_a?(Hash) && ext[:llm].is_a?(Hash)
331
+
332
+ provider_key = self.class.respond_to?(:slug) ? self.class.slug.to_sym : nil
333
+ return nil unless provider_key
334
+
335
+ provider_conf = ext[:llm][provider_key]
336
+ provider_conf.is_a?(Hash) ? provider_conf[key] : nil
337
+ rescue StandardError
338
+ nil
339
+ end
340
+
305
341
  def model_allowed?(model_name)
306
342
  name = model_name.to_s.downcase
307
343
  wl = model_whitelist
@@ -313,6 +349,16 @@ module Legion
313
349
  true
314
350
  end
315
351
 
352
+ # ── Offering defaults ─────────────────────────────────────────────
353
+
354
+ def offering_transport
355
+ config.respond_to?(:transport) ? config.transport : self.class.default_transport
356
+ end
357
+
358
+ def offering_tier
359
+ config.respond_to?(:tier) ? config.tier : self.class.default_tier
360
+ end
361
+
316
362
  # ── Multi-host base_url resolution ────────────────────────────────
317
363
 
318
364
  def resolve_base_url
@@ -437,6 +483,14 @@ module Legion
437
483
  []
438
484
  end
439
485
 
486
+ def default_transport
487
+ :http
488
+ end
489
+
490
+ def default_tier
491
+ :frontier
492
+ end
493
+
440
494
  def local?
441
495
  false
442
496
  end
@@ -503,14 +557,6 @@ module Legion
503
557
  )
504
558
  end
505
559
 
506
- def offering_transport
507
- local? ? :local : :http
508
- end
509
-
510
- def offering_tier
511
- local? ? :local : :direct
512
- end
513
-
514
560
  def offering_usage_type(model)
515
561
  model.embedding? ? :embedding : :inference
516
562
  end
@@ -6,6 +6,15 @@ module Legion
6
6
  module Routing
7
7
  # Describes one concrete model made available by one provider instance.
8
8
  class ModelOffering
9
+ CAPABILITY_ALIASES = {
10
+ function_calling: :tools,
11
+ functions: :tools,
12
+ tool: :tools,
13
+ tool_use: :tools,
14
+ stream: :streaming,
15
+ stream_chat: :streaming
16
+ }.freeze
17
+
9
18
  attr_reader :offering_id, :provider_family, :model_family, :provider_instance, :instance_id, :transport,
10
19
  :tier, :model, :canonical_model_alias, :routing_metadata, :usage_type, :capabilities, :limits,
11
20
  :credentials, :health, :cost, :policy_tags, :metadata
@@ -27,7 +36,7 @@ module Legion
27
36
  fetch_value(data, :type) ||
28
37
  fetch_value(data, :kind) ||
29
38
  infer_usage_type(data)))
30
- @capabilities = normalize_array(fetch_value(data, :capabilities))
39
+ @capabilities = normalize_capabilities(fetch_value(data, :capabilities))
31
40
  @limits = normalize_hash(fetch_value(data, :limits))
32
41
  @credentials = fetch_value(data, :credentials)
33
42
  @health = normalize_hash(fetch_value(data, :health))
@@ -57,7 +66,7 @@ module Legion
57
66
  end
58
67
 
59
68
  def supports?(capability)
60
- capabilities.include?(capability.to_sym)
69
+ normalize_capabilities([capability]).any? { |candidate| capabilities.include?(candidate) }
61
70
  end
62
71
 
63
72
  def eligible_for?(usage_type: nil, required_capabilities: [], min_context_window: nil, policy_tags: [])
@@ -120,7 +129,7 @@ module Legion
120
129
  end
121
130
 
122
131
  def infer_usage_type(data)
123
- capabilities = normalize_array(fetch_value(data, :capabilities))
132
+ capabilities = normalize_capabilities(fetch_value(data, :capabilities))
124
133
  return :embedding if capabilities.include?(:embedding) || capabilities.include?(:embed)
125
134
 
126
135
  :inference
@@ -147,6 +156,17 @@ module Legion
147
156
  Array(value).compact.map(&:to_sym)
148
157
  end
149
158
 
159
+ def normalize_capabilities(value)
160
+ Array(value).compact.each_with_object([]) do |item, normalized|
161
+ symbol = item.to_s.downcase.strip.to_sym
162
+ next if symbol.to_s.empty?
163
+
164
+ normalized << symbol
165
+ alias_symbol = CAPABILITY_ALIASES[symbol]
166
+ normalized << alias_symbol if alias_symbol
167
+ end.uniq
168
+ end
169
+
150
170
  def normalize_hash(value)
151
171
  (value || {}).to_h.transform_keys(&:to_sym)
152
172
  end
@@ -165,7 +185,7 @@ module Legion
165
185
  end
166
186
 
167
187
  def capabilities_match?(required)
168
- Array(required).all? { |capability| supports?(capability) }
188
+ normalize_capabilities(required).all? { |capability| capabilities.include?(capability) }
169
189
  end
170
190
 
171
191
  def context_window_matches?(minimum)
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Llm
6
- VERSION = '0.4.13'
6
+ VERSION = '0.4.15'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.13
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO