lex-llm 0.4.18 → 0.5.1

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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -2
  3. data/B1b-conformance-kit.md +79 -0
  4. data/CHANGELOG.md +27 -0
  5. data/lex-llm.gemspec +2 -3
  6. data/lib/legion/extensions/llm/attachment.rb +1 -1
  7. data/lib/legion/extensions/llm/canonical/chunk.rb +184 -0
  8. data/lib/legion/extensions/llm/canonical/content_block.rb +126 -0
  9. data/lib/legion/extensions/llm/canonical/message.rb +138 -0
  10. data/lib/legion/extensions/llm/canonical/params.rb +61 -0
  11. data/lib/legion/extensions/llm/canonical/request.rb +117 -0
  12. data/lib/legion/extensions/llm/canonical/response.rb +124 -0
  13. data/lib/legion/extensions/llm/canonical/thinking.rb +81 -0
  14. data/lib/legion/extensions/llm/canonical/tool_call.rb +134 -0
  15. data/lib/legion/extensions/llm/canonical/tool_definition.rb +98 -0
  16. data/lib/legion/extensions/llm/canonical/tool_schema.rb +46 -0
  17. data/lib/legion/extensions/llm/canonical/usage.rb +74 -0
  18. data/lib/legion/extensions/llm/canonical.rb +50 -0
  19. data/lib/legion/extensions/llm/chat.rb +3 -5
  20. data/lib/legion/extensions/llm/connection.rb +5 -1
  21. data/lib/legion/extensions/llm/error.rb +5 -7
  22. data/lib/legion/extensions/llm/fleet/envelope_validation.rb +1 -3
  23. data/lib/legion/extensions/llm/fleet/provider_responder.rb +1 -3
  24. data/lib/legion/extensions/llm/fleet/token_validator.rb +1 -3
  25. data/lib/legion/extensions/llm/model/info.rb +4 -6
  26. data/lib/legion/extensions/llm/models.rb +3 -3
  27. data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +9 -4
  28. data/lib/legion/extensions/llm/provider.rb +21 -4
  29. data/lib/legion/extensions/llm/provider_contract.rb +10 -1
  30. data/lib/legion/extensions/llm/routing/lane_key.rb +1 -3
  31. data/lib/legion/extensions/llm/stream_accumulator.rb +40 -1
  32. data/lib/legion/extensions/llm/streaming.rb +13 -5
  33. data/lib/legion/extensions/llm/tool.rb +1 -3
  34. data/lib/legion/extensions/llm/version.rb +1 -1
  35. data/lib/legion/extensions/llm.rb +118 -35
  36. data/spec/fixtures/ruby.mp3 +0 -0
  37. data/spec/fixtures/ruby.mp4 +0 -0
  38. data/spec/fixtures/ruby.png +0 -0
  39. data/spec/fixtures/ruby.txt +1 -0
  40. data/spec/fixtures/ruby.wav +0 -0
  41. data/spec/fixtures/ruby.xml +1 -0
  42. data/spec/fixtures/sample.pdf +0 -0
  43. data/spec/legion/extensions/llm/agent_spec.rb +179 -0
  44. data/spec/legion/extensions/llm/attachment_spec.rb +25 -0
  45. data/spec/legion/extensions/llm/auto_registration_spec.rb +38 -0
  46. data/spec/legion/extensions/llm/canonical/chunk_spec.rb +285 -0
  47. data/spec/legion/extensions/llm/canonical/content_block_spec.rb +179 -0
  48. data/spec/legion/extensions/llm/canonical/message_spec.rb +203 -0
  49. data/spec/legion/extensions/llm/canonical/params_spec.rb +159 -0
  50. data/spec/legion/extensions/llm/canonical/request_spec.rb +174 -0
  51. data/spec/legion/extensions/llm/canonical/response_spec.rb +234 -0
  52. data/spec/legion/extensions/llm/canonical/thinking_spec.rb +151 -0
  53. data/spec/legion/extensions/llm/canonical/tool_call_spec.rb +191 -0
  54. data/spec/legion/extensions/llm/canonical/tool_definition_spec.rb +221 -0
  55. data/spec/legion/extensions/llm/canonical/tool_schema_spec.rb +83 -0
  56. data/spec/legion/extensions/llm/canonical/usage_spec.rb +178 -0
  57. data/spec/legion/extensions/llm/configuration_spec.rb +38 -0
  58. data/spec/legion/extensions/llm/conformance/client_translator_examples.rb +432 -0
  59. data/spec/legion/extensions/llm/conformance/conformance.rb +51 -0
  60. data/spec/legion/extensions/llm/conformance/echo_translator.rb +56 -0
  61. data/spec/legion/extensions/llm/conformance/echo_translator_spec.rb +13 -0
  62. data/spec/legion/extensions/llm/conformance/fixtures/canonical_empty_response.json +13 -0
  63. data/spec/legion/extensions/llm/conformance/fixtures/canonical_error_response.json +19 -0
  64. data/spec/legion/extensions/llm/conformance/fixtures/canonical_fleet_round_trip.json +81 -0
  65. data/spec/legion/extensions/llm/conformance/fixtures/canonical_metering_audit_events.json +101 -0
  66. data/spec/legion/extensions/llm/conformance/fixtures/canonical_params_mapping_request.json +21 -0
  67. data/spec/legion/extensions/llm/conformance/fixtures/canonical_server_tool_continuation_request.json +43 -0
  68. data/spec/legion/extensions/llm/conformance/fixtures/canonical_server_tool_use_response.json +29 -0
  69. data/spec/legion/extensions/llm/conformance/fixtures/canonical_simple_text_request.json +13 -0
  70. data/spec/legion/extensions/llm/conformance/fixtures/canonical_simple_text_response.json +13 -0
  71. data/spec/legion/extensions/llm/conformance/fixtures/canonical_stop_reason_matrix.json +36 -0
  72. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_accumulated_response.json +20 -0
  73. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_error_chunks.json +26 -0
  74. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_server_tool_chunks.json +52 -0
  75. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_text_chunks.json +33 -0
  76. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_thinking_chunks.json +42 -0
  77. data/spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_tool_call_chunks.json +41 -0
  78. data/spec/legion/extensions/llm/conformance/fixtures/canonical_system_prompt_request.json +14 -0
  79. data/spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_request.json +18 -0
  80. data/spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_response.json +17 -0
  81. data/spec/legion/extensions/llm/conformance/fixtures/canonical_tool_results_continuation_request.json +75 -0
  82. data/spec/legion/extensions/llm/conformance/fixtures/canonical_tool_use_response.json +25 -0
  83. data/spec/legion/extensions/llm/conformance/fixtures/canonical_tools_request.json +34 -0
  84. data/spec/legion/extensions/llm/conformance/provider_tool_rendering_examples.rb +77 -0
  85. data/spec/legion/extensions/llm/conformance/provider_translator_examples.rb +390 -0
  86. data/spec/legion/extensions/llm/connection_logging_spec.rb +53 -0
  87. data/spec/legion/extensions/llm/connection_retry_spec.rb +36 -0
  88. data/spec/legion/extensions/llm/context_spec.rb +127 -0
  89. data/spec/legion/extensions/llm/credential_sources_spec.rb +468 -0
  90. data/spec/legion/extensions/llm/error_middleware_spec.rb +102 -0
  91. data/spec/legion/extensions/llm/error_spec.rb +87 -0
  92. data/spec/legion/extensions/llm/fleet/provider_responder_spec.rb +120 -0
  93. data/spec/legion/extensions/llm/fleet/token_validator_spec.rb +163 -0
  94. data/spec/legion/extensions/llm/fleet/worker_execution_spec.rb +128 -0
  95. data/spec/legion/extensions/llm/fleet_messages_spec.rb +402 -0
  96. data/spec/legion/extensions/llm/gemspec_spec.rb +25 -0
  97. data/spec/legion/extensions/llm/message_spec.rb +64 -0
  98. data/spec/legion/extensions/llm/model/info_spec.rb +222 -0
  99. data/spec/legion/extensions/llm/models_spec.rb +104 -0
  100. data/spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb +203 -0
  101. data/spec/legion/extensions/llm/provider/open_ai_compatible_tool_calls_array_spec.rb +68 -0
  102. data/spec/legion/extensions/llm/provider_contract_spec.rb +60 -0
  103. data/spec/legion/extensions/llm/provider_settings_spec.rb +76 -0
  104. data/spec/legion/extensions/llm/provider_spec.rb +613 -0
  105. data/spec/legion/extensions/llm/registry_event_builder_spec.rb +68 -0
  106. data/spec/legion/extensions/llm/registry_publisher_spec.rb +22 -0
  107. data/spec/legion/extensions/llm/responses/response_objects_spec.rb +75 -0
  108. data/spec/legion/extensions/llm/responses/thinking_extractor_spec.rb +75 -0
  109. data/spec/legion/extensions/llm/routing/model_offering_spec.rb +222 -0
  110. data/spec/legion/extensions/llm/routing/offering_registry_spec.rb +50 -0
  111. data/spec/legion/extensions/llm/routing/registry_event_spec.rb +120 -0
  112. data/spec/legion/extensions/llm/stream_accumulator_spec.rb +155 -0
  113. data/spec/legion/extensions/llm/streaming_spec.rb +108 -0
  114. data/spec/legion/extensions/llm/tool_spec.rb +94 -0
  115. data/spec/legion/extensions/llm/transport/fleet_lane_spec.rb +60 -0
  116. data/spec/legion/extensions/llm/utils_spec.rb +113 -0
  117. data/spec/legion/extensions/llm_base_contract_spec.rb +110 -0
  118. data/spec/legion/extensions/llm_extension_spec.rb +78 -0
  119. data/spec/legion/extensions/llm_root_spec.rb +51 -0
  120. data/spec/spec_helper.rb +24 -0
  121. data/spec/support/fake_llm_provider.rb +148 -0
  122. data/spec/support/llm_configuration.rb +21 -0
  123. data/spec/support/rspec_configuration.rb +19 -0
  124. data/spec/support/simplecov_configuration.rb +20 -0
  125. metadata +103 -15
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/llm'
4
+
5
+ RSpec.describe Legion::Extensions::Llm do
6
+ it 'exposes the Legion-native extension namespace for autoloading' do
7
+ expect(described_class::Types::ModelOffering).to equal(Legion::Extensions::Llm::Routing::ModelOffering)
8
+ expect(described_class::Types::OfferingRegistry).to equal(Legion::Extensions::Llm::Routing::OfferingRegistry)
9
+ expect(described_class::Routing::LaneKey).to equal(Legion::Extensions::Llm::Routing::LaneKey)
10
+ expect(described_class::Routing::OfferingRegistry).to equal(Legion::Extensions::Llm::Routing::OfferingRegistry)
11
+ end
12
+
13
+ it 'provides complete default fleet settings' do
14
+ defaults = described_class.default_settings
15
+
16
+ expect(defaults.dig(:fleet, :consumer, :scheduler)).to eq(:basic_get)
17
+ expect(defaults.dig(:fleet, :consumer, :queue_expires_ms)).to eq(60_000)
18
+ expect(defaults.dig(:fleet, :consumer, :consumer_ack_timeout_ms)).to eq(90_000)
19
+ expect(defaults.dig(:fleet, :auth, :accepted_issuers)).to eq(['legion-llm'])
20
+ expect(defaults.dig(:fleet, :auth, :audience)).to eq('lex-llm-fleet-worker')
21
+ expect(defaults.dig(:fleet, :auth, :algorithm)).to eq('HS256')
22
+ expect(defaults.dig(:fleet, :auth, :replay_ttl_seconds)).to eq(600)
23
+ expect(defaults.dig(:fleet, :responder, :require_idempotency)).to be(true)
24
+ expect(defaults.dig(:fleet, :responder, :idempotency_ttl_seconds)).to eq(600)
25
+ end
26
+
27
+ it 'reads fleet settings from extension settings before falling back to core llm settings' do
28
+ data = {
29
+ extensions: { llm: { fleet: { auth: { accepted_issuers: ['extension'] } } } },
30
+ llm: {
31
+ fleet: {
32
+ auth: { audience: 'core-audience', accepted_issuers: ['core'] },
33
+ responder: { require_auth: false }
34
+ }
35
+ }
36
+ }
37
+ settings = Module.new
38
+ settings.define_singleton_method(:[]) { |key| data[key] }
39
+
40
+ stub_const('Legion::Settings', settings)
41
+
42
+ expect(Legion::Extensions::Llm::Fleet::Settings.value(:fleet, :auth, :accepted_issuers, default: []))
43
+ .to eq(['extension'])
44
+ expect(Legion::Extensions::Llm::Fleet::Settings.value(:fleet, :auth, :audience, default: nil))
45
+ .to eq('core-audience')
46
+ expect(Legion::Extensions::Llm::Fleet::Settings.value(:fleet, :responder, :require_auth, default: true))
47
+ .to be(false)
48
+ end
49
+
50
+ it 'builds provider defaults with shared fleet settings' do
51
+ settings = described_class.provider_settings(
52
+ family: :ollama,
53
+ instance: {
54
+ base_url: 'http://localhost:11434',
55
+ fleet: { enabled: true, consumer_priority: 10 }
56
+ }
57
+ )
58
+
59
+ expect(settings[:provider_family]).to eq(:ollama)
60
+ expect(settings.dig(:discovery, :interval_seconds)).to eq(300)
61
+ expect(settings.dig(:fleet, :consumer, :scheduler)).to eq(:basic_get)
62
+ expect(settings.dig(:instances, :default, :base_url)).to eq('http://localhost:11434')
63
+ expect(settings.dig(:instances, :default, :fleet)).to include(
64
+ enabled: true,
65
+ consumer_priority: 10,
66
+ prefetch: 1
67
+ )
68
+ end
69
+
70
+ it 'deep duplicates provider defaults between calls' do
71
+ first = described_class.provider_settings(family: :vllm)
72
+ second = described_class.provider_settings(family: :vllm)
73
+
74
+ first.dig(:instances, :default, :fleet)[:prefetch] = 99
75
+
76
+ expect(second.dig(:instances, :default, :fleet, :prefetch)).to eq(1)
77
+ end
78
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Llm do
6
+ describe '.logger' do
7
+ let(:logger) { instance_double(Logger) }
8
+ let(:log_file) { double }
9
+ let(:log_level) { double }
10
+
11
+ before do
12
+ described_class.instance_variable_set(:@config, nil)
13
+ described_class.instance_variable_set(:@logger, nil)
14
+ end
15
+
16
+ after do
17
+ described_class.instance_variable_set(:@config, nil)
18
+ described_class.instance_variable_set(:@logger, nil)
19
+ end
20
+
21
+ context 'with configuration options' do
22
+ before do
23
+ described_class.configure do |config|
24
+ config.log_file = log_file
25
+ config.log_level = log_level
26
+ end
27
+ end
28
+
29
+ it 'returns a default Logger' do
30
+ allow(Logger).to receive(:new).with(log_file, progname: 'Legion::Extensions::Llm',
31
+ level: log_level).and_return(logger)
32
+
33
+ expect(described_class.logger).to eq(logger)
34
+ end
35
+ end
36
+
37
+ context 'with a custom logger' do
38
+ before do
39
+ described_class.configure do |config|
40
+ config.logger = logger
41
+ config.log_file = log_file
42
+ config.log_level = log_level
43
+ end
44
+ end
45
+
46
+ it 'returns a the custom Logger' do
47
+ expect(described_class.logger).to eq(logger)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'dotenv/load'
5
+ rescue LoadError
6
+ nil
7
+ end
8
+
9
+ begin
10
+ require 'simplecov'
11
+ require 'simplecov-cobertura'
12
+ require_relative 'support/simplecov_configuration'
13
+ rescue LoadError
14
+ nil
15
+ end
16
+
17
+ require 'bundler/setup'
18
+ require 'fileutils'
19
+ require 'tempfile'
20
+ require 'legion/extensions/llm'
21
+ require 'ruby_llm/schema'
22
+ require_relative 'support/rspec_configuration'
23
+ require_relative 'support/llm_configuration'
24
+ require_relative 'support/fake_llm_provider'
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpecSupport
4
+ class FakeLLMProvider < Legion::Extensions::Llm::Provider
5
+ class << self
6
+ def configuration_options
7
+ %i[fake_llm_api_key fake_llm_api_base]
8
+ end
9
+
10
+ def slug
11
+ 'fake_llm'
12
+ end
13
+
14
+ def configuration_requirements
15
+ []
16
+ end
17
+
18
+ def capabilities
19
+ Module.new do
20
+ def self.chat?(_model) = true
21
+ def self.streaming?(_model) = true
22
+ def self.vision?(_model) = true
23
+ def self.functions?(_model) = true
24
+ end
25
+ end
26
+ end
27
+
28
+ def api_base
29
+ config.fake_llm_api_base || 'https://fake-llm.invalid/v1'
30
+ end
31
+
32
+ # rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument
33
+ def complete(messages, tools:, temperature:, model:, params: {}, headers: {}, schema: nil, thinking: nil,
34
+ tool_prefs: nil)
35
+ if block_given?
36
+ yield Legion::Extensions::Llm::Chunk.new(content: 'streamed ', role: :assistant)
37
+ yield Legion::Extensions::Llm::Chunk.new(content: 'response', role: :assistant)
38
+ end
39
+
40
+ if tools.any? && messages.none?(&:tool_result?)
41
+ tool = tools.values.first
42
+ return Legion::Extensions::Llm::Message.new(
43
+ role: :assistant,
44
+ content: nil,
45
+ model_id: model.id,
46
+ tool_calls: {
47
+ tool.name.to_sym => Legion::Extensions::Llm::ToolCall.new(id: 'tool-call-1', name: tool.name,
48
+ arguments: { value: 21 })
49
+ },
50
+ input_tokens: 12,
51
+ output_tokens: 3
52
+ )
53
+ end
54
+
55
+ content = if schema
56
+ Legion::JSON.generate({ answer: 42 })
57
+ elsif thinking
58
+ 'fake response with thinking enabled'
59
+ elsif messages.any?(&:tool_result?)
60
+ "tool result: #{messages.last.content}"
61
+ else
62
+ "fake response to #{messages.last.content}"
63
+ end
64
+
65
+ Legion::Extensions::Llm::Message.new(
66
+ role: :assistant,
67
+ content: content,
68
+ model_id: model.id,
69
+ input_tokens: 10,
70
+ output_tokens: 5
71
+ )
72
+ end
73
+ # rubocop:enable Metrics/ParameterLists, Lint/UnusedMethodArgument
74
+
75
+ def embed(text:, model:, dimensions: nil)
76
+ size = dimensions || 3
77
+ vectors = Array(text).map { Array.new(size, 0.5) }
78
+ vectors = vectors.first unless text.is_a?(Array)
79
+
80
+ Legion::Extensions::Llm::Embedding.new(vectors: vectors, model: model, input_tokens: Array(text).size)
81
+ end
82
+
83
+ def moderate(_input, model:)
84
+ Legion::Extensions::Llm::Moderation.new(
85
+ id: 'moderation-1',
86
+ model: model,
87
+ results: [{ 'flagged' => false, 'categories' => {}, 'category_scores' => {} }]
88
+ )
89
+ end
90
+
91
+ def paint(_prompt, model:, size:, with: nil, mask: nil, params: {}) # rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument
92
+ Legion::Extensions::Llm::Image.new(data: Base64.strict_encode64('fake-image'), mime_type: 'image/png',
93
+ model_id: model)
94
+ end
95
+
96
+ def transcribe(_audio_file, model:, language:, **)
97
+ Legion::Extensions::Llm::Transcription.new(text: 'fake transcript', model: model, language: language)
98
+ end
99
+ end
100
+
101
+ class BackupFakeLLMProvider < FakeLLMProvider
102
+ class << self
103
+ def configuration_options
104
+ %i[backup_fake_llm_api_key backup_fake_llm_api_base]
105
+ end
106
+
107
+ def slug
108
+ 'backup_fake_llm'
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # Namespace module that mimics a real lex-llm-* provider extension.
115
+ # Models.scan_provider_classes discovers providers via this pattern.
116
+ module Legion
117
+ module Extensions
118
+ module Llm
119
+ module FakeLlmProvider
120
+ PROVIDER_FAMILY = :fake_llm
121
+
122
+ def self.provider_class
123
+ SpecSupport::FakeLLMProvider
124
+ end
125
+ end
126
+
127
+ module BackupFakeLlmProvider
128
+ PROVIDER_FAMILY = :backup_fake_llm
129
+
130
+ def self.provider_class
131
+ SpecSupport::BackupFakeLLMProvider
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ # Register provider-specific configuration options at load time,
139
+ # the same way real lex-llm-* extensions declare their options.
140
+ [SpecSupport::FakeLLMProvider, SpecSupport::BackupFakeLLMProvider].each do |klass|
141
+ Array(klass.configuration_options).each do |key|
142
+ Legion::Extensions::Llm::Configuration.send(:option, key, nil)
143
+ end
144
+ end
145
+
146
+ RSpec.shared_context 'with fake llm provider' do
147
+ # Provider modules are defined at load time above; no runtime registration needed.
148
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Legion::Extensions::Llm.configure do |config|
4
+ config.max_retries = 0
5
+ config.retry_backoff_factor = 0
6
+ config.retry_interval = 0
7
+ config.retry_interval_randomness = 0
8
+ end
9
+
10
+ RSpec.shared_context 'with configured Legion::Extensions::Llm' do
11
+ before do
12
+ Legion::Extensions::Llm.configure do |config|
13
+ # Disable retries in tests for deterministic, fast failures.
14
+ config.max_retries = 0
15
+ config.request_timeout = 600
16
+ config.retry_backoff_factor = 0
17
+ config.retry_interval = 0
18
+ config.retry_interval_randomness = 0
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ # Enable flags like --only-failures and --next-failure
5
+ status_suffix = ENV['TEST_ENV_NUMBER'].to_s
6
+ config.example_status_persistence_file_path = ".rspec_status#{status_suffix}"
7
+
8
+ # Disable RSpec exposing methods globally on `Module` and `main`
9
+ config.disable_monkey_patching!
10
+
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = :expect
13
+ end
14
+
15
+ config.before do
16
+ # Provider lookup is now namespace-based via Models.scan_provider_classes;
17
+ # no mutable hash to clear between examples.
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless ENV['SKIP_COVERAGE']
4
+ SimpleCov.start do
5
+ track_files 'lib/**/*.rb'
6
+
7
+ add_filter '/spec/'
8
+ add_filter '/vendor/'
9
+ add_filter 'acts_as_legacy.rb'
10
+
11
+ enable_coverage :branch
12
+
13
+ formatter SimpleCov::Formatter::MultiFormatter.new(
14
+ [
15
+ SimpleCov::Formatter::SimpleFormatter,
16
+ SimpleCov::Formatter::CoberturaFormatter
17
+ ].compact
18
+ )
19
+ end
20
+ 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.18
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO
@@ -234,20 +234,6 @@ dependencies:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0'
237
- - !ruby/object:Gem::Dependency
238
- name: zeitwerk
239
- requirement: !ruby/object:Gem::Requirement
240
- requirements:
241
- - - "~>"
242
- - !ruby/object:Gem::Version
243
- version: '2'
244
- type: :runtime
245
- prerelease: false
246
- version_requirements: !ruby/object:Gem::Requirement
247
- requirements:
248
- - - "~>"
249
- - !ruby/object:Gem::Version
250
- version: '2'
251
237
  description: Provider-neutral LLM primitives, schemas, routing metadata, and shared
252
238
  codecs for LegionIO LLM provider extensions.
253
239
  email:
@@ -262,6 +248,7 @@ files:
262
248
  - ".gitignore"
263
249
  - ".rubocop.yml"
264
250
  - ".rubocop.yml.new"
251
+ - B1b-conformance-kit.md
265
252
  - CHANGELOG.md
266
253
  - Gemfile
267
254
  - LICENSE
@@ -273,6 +260,18 @@ files:
273
260
  - lib/legion/extensions/llm/aliases.rb
274
261
  - lib/legion/extensions/llm/attachment.rb
275
262
  - lib/legion/extensions/llm/auto_registration.rb
263
+ - lib/legion/extensions/llm/canonical.rb
264
+ - lib/legion/extensions/llm/canonical/chunk.rb
265
+ - lib/legion/extensions/llm/canonical/content_block.rb
266
+ - lib/legion/extensions/llm/canonical/message.rb
267
+ - lib/legion/extensions/llm/canonical/params.rb
268
+ - lib/legion/extensions/llm/canonical/request.rb
269
+ - lib/legion/extensions/llm/canonical/response.rb
270
+ - lib/legion/extensions/llm/canonical/thinking.rb
271
+ - lib/legion/extensions/llm/canonical/tool_call.rb
272
+ - lib/legion/extensions/llm/canonical/tool_definition.rb
273
+ - lib/legion/extensions/llm/canonical/tool_schema.rb
274
+ - lib/legion/extensions/llm/canonical/usage.rb
276
275
  - lib/legion/extensions/llm/chat.rb
277
276
  - lib/legion/extensions/llm/chunk.rb
278
277
  - lib/legion/extensions/llm/configuration.rb
@@ -336,6 +335,95 @@ files:
336
335
  - lib/legion/extensions/llm/transport/messages/registry_event.rb
337
336
  - lib/legion/extensions/llm/utils.rb
338
337
  - lib/legion/extensions/llm/version.rb
338
+ - spec/fixtures/ruby.mp3
339
+ - spec/fixtures/ruby.mp4
340
+ - spec/fixtures/ruby.png
341
+ - spec/fixtures/ruby.txt
342
+ - spec/fixtures/ruby.wav
343
+ - spec/fixtures/ruby.xml
344
+ - spec/fixtures/sample.pdf
345
+ - spec/legion/extensions/llm/agent_spec.rb
346
+ - spec/legion/extensions/llm/attachment_spec.rb
347
+ - spec/legion/extensions/llm/auto_registration_spec.rb
348
+ - spec/legion/extensions/llm/canonical/chunk_spec.rb
349
+ - spec/legion/extensions/llm/canonical/content_block_spec.rb
350
+ - spec/legion/extensions/llm/canonical/message_spec.rb
351
+ - spec/legion/extensions/llm/canonical/params_spec.rb
352
+ - spec/legion/extensions/llm/canonical/request_spec.rb
353
+ - spec/legion/extensions/llm/canonical/response_spec.rb
354
+ - spec/legion/extensions/llm/canonical/thinking_spec.rb
355
+ - spec/legion/extensions/llm/canonical/tool_call_spec.rb
356
+ - spec/legion/extensions/llm/canonical/tool_definition_spec.rb
357
+ - spec/legion/extensions/llm/canonical/tool_schema_spec.rb
358
+ - spec/legion/extensions/llm/canonical/usage_spec.rb
359
+ - spec/legion/extensions/llm/configuration_spec.rb
360
+ - spec/legion/extensions/llm/conformance/client_translator_examples.rb
361
+ - spec/legion/extensions/llm/conformance/conformance.rb
362
+ - spec/legion/extensions/llm/conformance/echo_translator.rb
363
+ - spec/legion/extensions/llm/conformance/echo_translator_spec.rb
364
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_empty_response.json
365
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_error_response.json
366
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_fleet_round_trip.json
367
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_metering_audit_events.json
368
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_params_mapping_request.json
369
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_server_tool_continuation_request.json
370
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_server_tool_use_response.json
371
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_simple_text_request.json
372
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_simple_text_response.json
373
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_stop_reason_matrix.json
374
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_accumulated_response.json
375
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_error_chunks.json
376
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_server_tool_chunks.json
377
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_text_chunks.json
378
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_thinking_chunks.json
379
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_streaming_tool_call_chunks.json
380
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_system_prompt_request.json
381
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_request.json
382
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_response.json
383
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_tool_results_continuation_request.json
384
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_tool_use_response.json
385
+ - spec/legion/extensions/llm/conformance/fixtures/canonical_tools_request.json
386
+ - spec/legion/extensions/llm/conformance/provider_tool_rendering_examples.rb
387
+ - spec/legion/extensions/llm/conformance/provider_translator_examples.rb
388
+ - spec/legion/extensions/llm/connection_logging_spec.rb
389
+ - spec/legion/extensions/llm/connection_retry_spec.rb
390
+ - spec/legion/extensions/llm/context_spec.rb
391
+ - spec/legion/extensions/llm/credential_sources_spec.rb
392
+ - spec/legion/extensions/llm/error_middleware_spec.rb
393
+ - spec/legion/extensions/llm/error_spec.rb
394
+ - spec/legion/extensions/llm/fleet/provider_responder_spec.rb
395
+ - spec/legion/extensions/llm/fleet/token_validator_spec.rb
396
+ - spec/legion/extensions/llm/fleet/worker_execution_spec.rb
397
+ - spec/legion/extensions/llm/fleet_messages_spec.rb
398
+ - spec/legion/extensions/llm/gemspec_spec.rb
399
+ - spec/legion/extensions/llm/message_spec.rb
400
+ - spec/legion/extensions/llm/model/info_spec.rb
401
+ - spec/legion/extensions/llm/models_spec.rb
402
+ - spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb
403
+ - spec/legion/extensions/llm/provider/open_ai_compatible_tool_calls_array_spec.rb
404
+ - spec/legion/extensions/llm/provider_contract_spec.rb
405
+ - spec/legion/extensions/llm/provider_settings_spec.rb
406
+ - spec/legion/extensions/llm/provider_spec.rb
407
+ - spec/legion/extensions/llm/registry_event_builder_spec.rb
408
+ - spec/legion/extensions/llm/registry_publisher_spec.rb
409
+ - spec/legion/extensions/llm/responses/response_objects_spec.rb
410
+ - spec/legion/extensions/llm/responses/thinking_extractor_spec.rb
411
+ - spec/legion/extensions/llm/routing/model_offering_spec.rb
412
+ - spec/legion/extensions/llm/routing/offering_registry_spec.rb
413
+ - spec/legion/extensions/llm/routing/registry_event_spec.rb
414
+ - spec/legion/extensions/llm/stream_accumulator_spec.rb
415
+ - spec/legion/extensions/llm/streaming_spec.rb
416
+ - spec/legion/extensions/llm/tool_spec.rb
417
+ - spec/legion/extensions/llm/transport/fleet_lane_spec.rb
418
+ - spec/legion/extensions/llm/utils_spec.rb
419
+ - spec/legion/extensions/llm_base_contract_spec.rb
420
+ - spec/legion/extensions/llm_extension_spec.rb
421
+ - spec/legion/extensions/llm_root_spec.rb
422
+ - spec/spec_helper.rb
423
+ - spec/support/fake_llm_provider.rb
424
+ - spec/support/llm_configuration.rb
425
+ - spec/support/rspec_configuration.rb
426
+ - spec/support/simplecov_configuration.rb
339
427
  homepage: https://github.com/LegionIO/lex-llm
340
428
  licenses:
341
429
  - MIT