lex-llm 0.7.3 → 0.8.0
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 +106 -0
- data/RULES.md +97 -0
- data/lib/legion/extensions/llm/auto_registration.rb +4 -13
- data/lib/legion/extensions/llm/canonical/chunk.rb +106 -92
- data/lib/legion/extensions/llm/canonical/content_block.rb +66 -75
- data/lib/legion/extensions/llm/canonical/message.rb +52 -67
- data/lib/legion/extensions/llm/canonical/params.rb +59 -33
- data/lib/legion/extensions/llm/canonical/request.rb +67 -54
- data/lib/legion/extensions/llm/canonical/response.rb +61 -76
- data/lib/legion/extensions/llm/canonical/strict.rb +105 -0
- data/lib/legion/extensions/llm/canonical/thinking.rb +99 -51
- data/lib/legion/extensions/llm/canonical/tool_call.rb +42 -51
- data/lib/legion/extensions/llm/canonical/tool_definition.rb +56 -46
- data/lib/legion/extensions/llm/canonical/tool_schema.rb +15 -22
- data/lib/legion/extensions/llm/canonical/usage.rb +47 -40
- data/lib/legion/extensions/llm/canonical.rb +6 -5
- data/lib/legion/extensions/llm/configuration.rb +40 -10
- data/lib/legion/extensions/llm/connection.rb +8 -30
- data/lib/legion/extensions/llm/credential_sources.rb +32 -49
- data/lib/legion/extensions/llm/discovery/actor.rb +92 -0
- data/lib/legion/extensions/llm/discovery/pipeline.rb +604 -0
- data/lib/legion/extensions/llm/error.rb +0 -14
- data/lib/legion/extensions/llm/fleet/contract_error.rb +15 -0
- data/lib/legion/extensions/llm/fleet/envelope_validation.rb +7 -6
- data/lib/legion/extensions/llm/fleet/fleet_envelope.rb +66 -0
- data/lib/legion/extensions/llm/fleet/protocol.rb +18 -5
- data/lib/legion/extensions/llm/fleet/provider_responder.rb +58 -153
- data/lib/legion/extensions/llm/fleet/token_validator.rb +15 -21
- data/lib/legion/extensions/llm/fleet/worker_execution.rb +107 -150
- data/lib/legion/extensions/llm/inventory/errors.rb +0 -1
- data/lib/legion/extensions/llm/inventory/evidence.rb +1 -1
- data/lib/legion/extensions/llm/inventory/identity.rb +55 -39
- data/lib/legion/extensions/llm/inventory/probe_token.rb +9 -12
- data/lib/legion/extensions/llm/inventory/publisher.rb +15 -53
- data/lib/legion/extensions/llm/inventory/records.rb +82 -99
- data/lib/legion/extensions/llm/inventory/registry.rb +54 -46
- data/lib/legion/extensions/llm/inventory/snapshot.rb +7 -21
- data/lib/legion/extensions/llm/inventory/weight_reconciler.rb +249 -0
- data/lib/legion/extensions/llm/inventory/weight_schema.rb +146 -0
- data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +172 -182
- data/lib/legion/extensions/llm/provider.rb +192 -315
- data/lib/legion/extensions/llm/provider_contract.rb +25 -8
- data/lib/legion/extensions/llm/provider_settings.rb +5 -26
- data/lib/legion/extensions/llm/responses/thinking_extractor.rb +8 -1
- data/lib/legion/extensions/llm/responses/tool_arguments.rb +34 -0
- data/lib/legion/extensions/llm/routing/provider_outcome.rb +25 -0
- data/lib/legion/extensions/llm/routing/records.rb +34 -17
- data/lib/legion/extensions/llm/stream_accumulator.rb +186 -270
- data/lib/legion/extensions/llm/streaming.rb +50 -35
- data/lib/legion/extensions/llm/taxonomies.rb +29 -17
- data/lib/legion/extensions/llm/transport/fleet_lane.rb +8 -10
- data/lib/legion/extensions/llm/transport/messages/fleet_error.rb +3 -2
- data/lib/legion/extensions/llm/transport/messages/fleet_request.rb +6 -8
- data/lib/legion/extensions/llm/transport/messages/fleet_response.rb +10 -9
- data/lib/legion/extensions/llm/utils.rb +23 -5
- data/lib/legion/extensions/llm/version.rb +1 -1
- data/lib/legion/extensions/llm.rb +10 -98
- data/spec/legion/extensions/llm/auto_registration_spec.rb +4 -9
- data/spec/legion/extensions/llm/canonical/chunk_spec.rb +66 -252
- data/spec/legion/extensions/llm/canonical/content_block_spec.rb +52 -197
- data/spec/legion/extensions/llm/canonical/message_spec.rb +89 -204
- data/spec/legion/extensions/llm/canonical/params_spec.rb +57 -136
- data/spec/legion/extensions/llm/canonical/request_spec.rb +81 -143
- data/spec/legion/extensions/llm/canonical/response_spec.rb +68 -204
- data/spec/legion/extensions/llm/canonical/thinking_spec.rb +68 -148
- data/spec/legion/extensions/llm/canonical/tool_call_spec.rb +59 -162
- data/spec/legion/extensions/llm/canonical/tool_definition_spec.rb +55 -191
- data/spec/legion/extensions/llm/canonical/tool_schema_spec.rb +26 -67
- data/spec/legion/extensions/llm/canonical/usage_spec.rb +46 -155
- data/spec/legion/extensions/llm/configuration_spec.rb +31 -5
- data/spec/legion/extensions/llm/conformance/canonical_type_examples.rb +106 -0
- data/spec/legion/extensions/llm/conformance/conformance.rb +10 -2
- data/spec/legion/extensions/llm/conformance/provider_translator_examples.rb +1 -1
- data/spec/legion/extensions/llm/conformance/ssot_contract_conformance_spec.rb +130 -0
- data/spec/legion/extensions/llm/conformance/ssot_contract_examples.rb +507 -0
- data/spec/legion/extensions/llm/conformance/ssot_provider_examples.rb +11 -10
- data/spec/legion/extensions/llm/credential_sources_spec.rb +12 -13
- data/spec/legion/extensions/llm/error_spec.rb +2 -12
- data/spec/legion/extensions/llm/fleet/exact_offering_spec.rb +59 -45
- data/spec/legion/extensions/llm/fleet/provider_responder_spec.rb +178 -67
- data/spec/legion/extensions/llm/fleet/token_validator_spec.rb +7 -2
- data/spec/legion/extensions/llm/fleet/worker_execution_spec.rb +101 -62
- data/spec/legion/extensions/llm/fleet_messages_spec.rb +118 -123
- data/spec/legion/extensions/llm/inventory/boot_spec.rb +4 -4
- data/spec/legion/extensions/llm/inventory/identity_spec.rb +127 -110
- data/spec/legion/extensions/llm/inventory/probe_token_spec.rb +4 -4
- data/spec/legion/extensions/llm/inventory/publisher_spec.rb +8 -61
- data/spec/legion/extensions/llm/inventory/records_spec.rb +129 -41
- data/spec/legion/extensions/llm/inventory/registry_activation_spec.rb +55 -4
- data/spec/legion/extensions/llm/inventory/registry_replacement_spec.rb +5 -4
- data/spec/legion/extensions/llm/inventory/snapshot_spec.rb +11 -5
- data/spec/legion/extensions/llm/inventory/weight_reconciler_spec.rb +312 -0
- data/spec/legion/extensions/llm/inventory/weight_schema_spec.rb +141 -0
- data/spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb +105 -68
- data/spec/legion/extensions/llm/provider/open_ai_compatible_tool_calls_array_spec.rb +7 -31
- data/spec/legion/extensions/llm/provider_contract_spec.rb +10 -15
- data/spec/legion/extensions/llm/provider_spec.rb +98 -78
- data/spec/legion/extensions/llm/routing/records_spec.rb +38 -5
- data/spec/legion/extensions/llm/stream_accumulator_spec.rb +174 -144
- data/spec/legion/extensions/llm/streaming_spec.rb +27 -0
- data/spec/legion/extensions/llm/taxonomies_spec.rb +43 -16
- data/spec/legion/extensions/llm/transport/fleet_lane_spec.rb +1 -1
- data/spec/legion/extensions/llm/utils_spec.rb +26 -7
- data/spec/legion/extensions/llm_base_contract_spec.rb +55 -90
- data/spec/legion/extensions/llm_extension_spec.rb +5 -5
- data/spec/support/fake_llm_provider.rb +45 -39
- data/spec/support/fake_ssot_harness.rb +7 -2
- data/spec/support/ssot_registry_helpers.rb +3 -2
- metadata +15 -54
- data/lib/legion/extensions/llm/agent.rb +0 -366
- data/lib/legion/extensions/llm/aliases.json +0 -436
- data/lib/legion/extensions/llm/aliases.rb +0 -67
- data/lib/legion/extensions/llm/attachment.rb +0 -229
- data/lib/legion/extensions/llm/chat.rb +0 -354
- data/lib/legion/extensions/llm/chunk.rb +0 -10
- data/lib/legion/extensions/llm/content.rb +0 -81
- data/lib/legion/extensions/llm/context.rb +0 -33
- data/lib/legion/extensions/llm/embedding.rb +0 -33
- data/lib/legion/extensions/llm/image.rb +0 -109
- data/lib/legion/extensions/llm/inventory/capabilities.rb +0 -40
- data/lib/legion/extensions/llm/inventory/scoped_refresher.rb +0 -311
- data/lib/legion/extensions/llm/message.rb +0 -118
- data/lib/legion/extensions/llm/mime_type.rb +0 -75
- data/lib/legion/extensions/llm/model/info.rb +0 -286
- data/lib/legion/extensions/llm/model/modalities.rb +0 -26
- data/lib/legion/extensions/llm/model/pricing.rb +0 -52
- data/lib/legion/extensions/llm/model/pricing_category.rb +0 -50
- data/lib/legion/extensions/llm/model/pricing_tier.rb +0 -37
- data/lib/legion/extensions/llm/model.rb +0 -11
- data/lib/legion/extensions/llm/models.json +0 -57313
- data/lib/legion/extensions/llm/models.rb +0 -530
- data/lib/legion/extensions/llm/models_schema.json +0 -168
- data/lib/legion/extensions/llm/moderation.rb +0 -60
- data/lib/legion/extensions/llm/registry_event_builder.rb +0 -141
- data/lib/legion/extensions/llm/registry_publisher.rb +0 -107
- data/lib/legion/extensions/llm/responses/chat_response.rb +0 -43
- data/lib/legion/extensions/llm/responses/embedding_response.rb +0 -38
- data/lib/legion/extensions/llm/responses/stream_chunk.rb +0 -43
- data/lib/legion/extensions/llm/routing/lane_key.rb +0 -66
- data/lib/legion/extensions/llm/routing/model_offering.rb +0 -241
- data/lib/legion/extensions/llm/routing/offering_registry.rb +0 -101
- data/lib/legion/extensions/llm/routing/registry_event.rb +0 -167
- data/lib/legion/extensions/llm/thinking.rb +0 -53
- data/lib/legion/extensions/llm/tokens.rb +0 -51
- data/lib/legion/extensions/llm/tool_call.rb +0 -34
- data/lib/legion/extensions/llm/transcription.rb +0 -39
- data/lib/legion/extensions/llm/transport/messages/registry_event.rb +0 -44
- data/spec/legion/extensions/llm/agent_spec.rb +0 -179
- data/spec/legion/extensions/llm/attachment_spec.rb +0 -25
- data/spec/legion/extensions/llm/conformance/fixtures/ssot_identity_vectors.json +0 -84
- data/spec/legion/extensions/llm/context_spec.rb +0 -127
- data/spec/legion/extensions/llm/inventory/capabilities_spec.rb +0 -43
- data/spec/legion/extensions/llm/inventory/scoped_refresher_spec.rb +0 -337
- data/spec/legion/extensions/llm/message_spec.rb +0 -64
- data/spec/legion/extensions/llm/model/info_spec.rb +0 -222
- data/spec/legion/extensions/llm/models_spec.rb +0 -104
- data/spec/legion/extensions/llm/registry_event_builder_spec.rb +0 -68
- data/spec/legion/extensions/llm/registry_publisher_spec.rb +0 -22
- data/spec/legion/extensions/llm/responses/response_objects_spec.rb +0 -75
- data/spec/legion/extensions/llm/routing/model_offering_spec.rb +0 -281
- data/spec/legion/extensions/llm/routing/offering_registry_spec.rb +0 -50
- data/spec/legion/extensions/llm/routing/registry_event_spec.rb +0 -120
|
@@ -5,106 +5,71 @@ require 'spec_helper'
|
|
|
5
5
|
RSpec.describe Legion::Extensions::Llm do
|
|
6
6
|
include_context 'with fake llm provider'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def execute(value:)
|
|
16
|
-
"echo #{value}"
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'loads and discovers provider classes from the namespace' do
|
|
23
|
-
provider_classes = Legion::Extensions::Llm::Models.scan_provider_classes
|
|
24
|
-
expect(provider_classes).to include(fake_llm: SpecSupport::FakeLLMProvider)
|
|
25
|
-
expect(Legion::Extensions::Llm::Routing::ModelOffering).to be_a(Class)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'lets a provider gem register options and satisfy chat through the shared API' do
|
|
29
|
-
chat = described_class.chat(model: 'fake-chat-model', provider: :fake_llm, assume_model_exists: true)
|
|
30
|
-
response = chat.ask('hello')
|
|
31
|
-
|
|
32
|
-
expect(response).to have_attributes(
|
|
33
|
-
role: :assistant,
|
|
34
|
-
content: 'fake response to hello',
|
|
35
|
-
model_id: 'fake-chat-model',
|
|
36
|
-
input_tokens: 10,
|
|
37
|
-
output_tokens: 5
|
|
38
|
-
)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it 'runs shared tool orchestration without provider-specific payload code' do
|
|
42
|
-
response = described_class.chat(model: 'fake-chat-model', provider: :fake_llm, assume_model_exists: true)
|
|
43
|
-
.with_tool(SpecSupport::EchoTool)
|
|
44
|
-
.ask('use the tool')
|
|
45
|
-
|
|
46
|
-
expect(response.content).to eq('tool result: echo 21')
|
|
8
|
+
it 'exposes the AutoRegistration discovery contract from the provider namespace' do
|
|
9
|
+
# Registration into Legion::LLM is owned by legion-llm (R12); lex-llm owns
|
|
10
|
+
# the namespace contract the scanner reads: PROVIDER_FAMILY (Symbol) plus
|
|
11
|
+
# a provider_class singleton returning the Provider subclass.
|
|
12
|
+
expect(Legion::Extensions::Llm::FakeLlmProvider.const_get(:PROVIDER_FAMILY)).to eq(:fake_llm)
|
|
13
|
+
expect(Legion::Extensions::Llm::FakeLlmProvider.provider_class).to be < Legion::Extensions::Llm::Provider
|
|
47
14
|
end
|
|
48
15
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
response = described_class.chat(model: 'fake-chat-model', provider: :fake_llm, assume_model_exists: true)
|
|
60
|
-
.with_schema(schema)
|
|
61
|
-
.ask('structured')
|
|
62
|
-
|
|
63
|
-
expect(response.content).to eq({ 'answer' => 42 })
|
|
64
|
-
end
|
|
16
|
+
describe 'provider funnel contract (0.8.0)' do
|
|
17
|
+
let(:provider) do
|
|
18
|
+
SpecSupport::FakeLLMProvider.new(
|
|
19
|
+
Legion::Extensions::Llm::Configuration.new.tap do |config|
|
|
20
|
+
config.fake_llm_api_key = 'fake-key'
|
|
21
|
+
end
|
|
22
|
+
)
|
|
23
|
+
end
|
|
65
24
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
25
|
+
let(:user_message) do
|
|
26
|
+
Legion::Extensions::Llm::Canonical::Message.build(role: :user, content: 'hello')
|
|
27
|
+
end
|
|
69
28
|
|
|
70
|
-
|
|
71
|
-
.
|
|
29
|
+
it 'completes with canonical input and returns a Canonical::Response' do
|
|
30
|
+
response = provider.complete([user_message], model: 'fake-chat-model')
|
|
31
|
+
expect(response).to be_a(Legion::Extensions::Llm::Canonical::Response)
|
|
32
|
+
expect(response.text).to eq('fake response to hello')
|
|
33
|
+
expect(response.usage).to be_a(Legion::Extensions::Llm::Canonical::Usage)
|
|
34
|
+
end
|
|
72
35
|
|
|
73
|
-
|
|
74
|
-
|
|
36
|
+
it 'streams canonical chunks ending in exactly one done chunk (05 O5)' do
|
|
37
|
+
chunks = []
|
|
38
|
+
provider.complete([user_message], model: 'fake-chat-model') { |chunk| chunks << chunk }
|
|
75
39
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.to
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
it 'connects model offerings to Legion fleet queue construction end to end' do
|
|
82
|
-
offering = Legion::Extensions::Llm::Routing::ModelOffering.new(
|
|
83
|
-
provider_family: :fake_llm,
|
|
84
|
-
instance_id: :worker_one,
|
|
85
|
-
transport: :rabbitmq,
|
|
86
|
-
model: 'fake-chat-model',
|
|
87
|
-
limits: { context_window: 16_384 }
|
|
88
|
-
)
|
|
89
|
-
exchange_class = Class.new
|
|
90
|
-
base_queue = Class.new do
|
|
91
|
-
attr_reader :bindings
|
|
40
|
+
expect(chunks).to all(be_a(Legion::Extensions::Llm::Canonical::Chunk))
|
|
41
|
+
expect(chunks.count(&:done?)).to eq(1)
|
|
42
|
+
expect(chunks.last).to be_done
|
|
43
|
+
expect(chunks.filter_map(&:delta).join).to eq('streamed response')
|
|
44
|
+
end
|
|
92
45
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
46
|
+
it 'rejects non-canonical messages at the boundary with a typed ArgumentError (08 F2)' do
|
|
47
|
+
expect { provider.complete([{ role: 'user', content: 'hash' }], model: 'fake-chat-model') }
|
|
48
|
+
.to raise_error(ArgumentError, /Canonical::Message/)
|
|
49
|
+
expect { provider.complete([nil], model: 'fake-chat-model') }
|
|
50
|
+
.to raise_error(ArgumentError, /Canonical::Message/)
|
|
51
|
+
expect { provider.complete(['string'], model: 'fake-chat-model') }
|
|
52
|
+
.to raise_error(ArgumentError, /Canonical::Message/)
|
|
53
|
+
end
|
|
96
54
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
55
|
+
it 'keeps the canonical conversation operations on the base' do
|
|
56
|
+
expect(provider).to respond_to(:chat)
|
|
57
|
+
expect(provider).to respond_to(:stream_chat)
|
|
58
|
+
expect(provider).to respond_to(:count_tokens)
|
|
59
|
+
expect(provider).to respond_to(:discover_offerings)
|
|
60
|
+
expect(provider).to respond_to(:health)
|
|
61
|
+
expect(provider).to respond_to(:embed)
|
|
62
|
+
expect(provider).to respond_to(:moderate)
|
|
63
|
+
expect(provider).to respond_to(:image)
|
|
64
|
+
expect(provider).to respond_to(:transcribe)
|
|
100
65
|
end
|
|
101
66
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
base_queue_class: base_queue
|
|
106
|
-
)
|
|
67
|
+
it 'serves discover_offerings from the registry snapshot (07 C5)' do
|
|
68
|
+
expect(provider.discover_offerings).to eq([])
|
|
69
|
+
end
|
|
107
70
|
|
|
108
|
-
|
|
71
|
+
it 'counts tokens for canonical messages' do
|
|
72
|
+
expect(provider.count_tokens(messages: [user_message], model: 'fake-chat-model')).to be_a(Integer)
|
|
73
|
+
end
|
|
109
74
|
end
|
|
110
75
|
end
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
require 'legion/extensions/llm'
|
|
4
4
|
|
|
5
5
|
RSpec.describe Legion::Extensions::Llm do
|
|
6
|
-
it 'exposes
|
|
7
|
-
expect(described_class
|
|
8
|
-
expect(
|
|
9
|
-
expect(
|
|
10
|
-
expect(
|
|
6
|
+
it 'exposes no legacy dual-constant paths after the 0.8.0 rip' do
|
|
7
|
+
expect(described_class.const_defined?(:Types, false)).to be(false)
|
|
8
|
+
expect(Legion::Extensions::Llm::Routing.const_defined?(:ModelOffering, false)).to be(false)
|
|
9
|
+
expect(Legion::Extensions::Llm::Routing.const_defined?(:OfferingRegistry, false)).to be(false)
|
|
10
|
+
expect(Legion::Extensions::Llm::Routing.const_defined?(:LaneKey, false)).to be(false)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it 'provides complete default fleet settings' do
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module SpecSupport
|
|
4
|
+
# Contract-conformant fake provider (0.8.0): canonical in, canonical out.
|
|
5
|
+
# No HTTP — complete is overridden to return canned Canonical::Response
|
|
6
|
+
# objects (and yield Canonical::Chunk for streams).
|
|
4
7
|
class FakeLLMProvider < Legion::Extensions::Llm::Provider
|
|
5
8
|
class << self
|
|
6
9
|
def configuration_options
|
|
@@ -29,26 +32,28 @@ module SpecSupport
|
|
|
29
32
|
config.fake_llm_api_base || 'https://fake-llm.invalid/v1'
|
|
30
33
|
end
|
|
31
34
|
|
|
32
|
-
# rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
def complete(messages, tools: [], model:, params: nil, headers: {}, schema: nil, thinking: nil, # rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument, Style/KeywordParametersOrder
|
|
36
|
+
tool_prefs: nil, &) # rubocop:disable Lint/UnusedMethodArgument
|
|
37
|
+
enforce_canonical_messages!(messages)
|
|
38
|
+
|
|
35
39
|
if block_given?
|
|
36
|
-
yield Legion::Extensions::Llm::Chunk.
|
|
37
|
-
yield Legion::Extensions::Llm::Chunk.
|
|
40
|
+
yield Legion::Extensions::Llm::Canonical::Chunk.text_delta(delta: 'streamed ', request_id: nil)
|
|
41
|
+
yield Legion::Extensions::Llm::Canonical::Chunk.text_delta(delta: 'response', request_id: nil)
|
|
42
|
+
yield Legion::Extensions::Llm::Canonical::Chunk.done(request_id: nil, stop_reason: :end_turn)
|
|
38
43
|
end
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
has_tool_result = messages.any?(&:tool_call_id)
|
|
46
|
+
if tools.any? && !has_tool_result
|
|
41
47
|
tool = tools.values.first
|
|
42
|
-
return Legion::Extensions::Llm::
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
input_tokens: 12,
|
|
51
|
-
output_tokens: 3
|
|
48
|
+
return Legion::Extensions::Llm::Canonical::Response.build(
|
|
49
|
+
text: nil,
|
|
50
|
+
tool_calls: [
|
|
51
|
+
Legion::Extensions::Llm::Canonical::ToolCall.build(name: tool.name, id: 'tool-call-1',
|
|
52
|
+
arguments: { value: 21 })
|
|
53
|
+
],
|
|
54
|
+
stop_reason: :tool_use,
|
|
55
|
+
model: model,
|
|
56
|
+
usage: Legion::Extensions::Llm::Canonical::Usage.build(input_tokens: 12, output_tokens: 3)
|
|
52
57
|
)
|
|
53
58
|
end
|
|
54
59
|
|
|
@@ -56,45 +61,46 @@ module SpecSupport
|
|
|
56
61
|
Legion::JSON.generate({ answer: 42 })
|
|
57
62
|
elsif thinking
|
|
58
63
|
'fake response with thinking enabled'
|
|
59
|
-
elsif
|
|
60
|
-
"tool result: #{messages.last.
|
|
64
|
+
elsif has_tool_result
|
|
65
|
+
"tool result: #{messages.last.text}"
|
|
61
66
|
else
|
|
62
|
-
"fake response to #{messages.last.
|
|
67
|
+
"fake response to #{messages.last.text}"
|
|
63
68
|
end
|
|
64
69
|
|
|
65
|
-
Legion::Extensions::Llm::
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
input_tokens: 10,
|
|
70
|
-
output_tokens: 5
|
|
70
|
+
Legion::Extensions::Llm::Canonical::Response.build(
|
|
71
|
+
text: content,
|
|
72
|
+
model: model,
|
|
73
|
+
stop_reason: :end_turn,
|
|
74
|
+
usage: Legion::Extensions::Llm::Canonical::Usage.build(input_tokens: 10, output_tokens: 5)
|
|
71
75
|
)
|
|
72
76
|
end
|
|
73
|
-
# rubocop:enable Metrics/ParameterLists, Lint/UnusedMethodArgument
|
|
74
77
|
|
|
75
|
-
def embed(text:, model:, dimensions: nil)
|
|
78
|
+
def embed(text:, model:, dimensions: nil, params: nil, headers: {})
|
|
79
|
+
_ = [params, headers]
|
|
76
80
|
size = dimensions || 3
|
|
77
81
|
vectors = Array(text).map { Array.new(size, 0.5) }
|
|
78
82
|
vectors = vectors.first unless text.is_a?(Array)
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
{
|
|
85
|
+
text: text,
|
|
86
|
+
model: model,
|
|
87
|
+
embedding: vectors,
|
|
88
|
+
usage: Legion::Extensions::Llm::Canonical::Usage.build(input_tokens: Array(text).size)
|
|
89
|
+
}
|
|
81
90
|
end
|
|
82
91
|
|
|
83
|
-
def moderate(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
model: model,
|
|
87
|
-
results: [{ 'flagged' => false, 'categories' => {}, 'category_scores' => {} }]
|
|
88
|
-
)
|
|
92
|
+
def moderate(input:, model:)
|
|
93
|
+
_ = input
|
|
94
|
+
{ model: model, result: { flagged: false, categories: {} } }
|
|
89
95
|
end
|
|
90
96
|
|
|
91
|
-
def
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
def image(prompt:, model:, size:, with: nil, mask: nil, params: {}) # rubocop:disable Metrics/ParameterLists
|
|
98
|
+
_ = [prompt, with, mask, params]
|
|
99
|
+
{ model: model, image: Base64.strict_encode64('fake-image'), size: }
|
|
94
100
|
end
|
|
95
101
|
|
|
96
102
|
def transcribe(_audio_file, model:, language:, **)
|
|
97
|
-
|
|
103
|
+
{ model: model, text: 'fake transcript', language: }
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
# Records exactly-once disconnect for the callable-lifecycle contract; does
|
|
@@ -123,7 +129,7 @@ module SpecSupport
|
|
|
123
129
|
end
|
|
124
130
|
|
|
125
131
|
# Namespace module that mimics a real lex-llm-* provider extension.
|
|
126
|
-
#
|
|
132
|
+
# legion-llm's Call::Providers scanner discovers providers via this pattern.
|
|
127
133
|
module Legion
|
|
128
134
|
module Extensions
|
|
129
135
|
module Llm
|
|
@@ -28,9 +28,14 @@ module SpecSupport
|
|
|
28
28
|
true
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
# L11: the fake mimics the 0.8.0 callable contract — chat returns a
|
|
32
|
+
# Canonical::Response (the raw-Hash return violated the contract the
|
|
33
|
+
# harness impersonates; conformance B2 asserts exactly this shape).
|
|
34
|
+
def chat(messages, model:, **rest)
|
|
32
35
|
@inference_calls += 1
|
|
33
|
-
|
|
36
|
+
Legion::Extensions::Llm::Canonical::Response.build(
|
|
37
|
+
text: "fake chat #{model} #{messages.size} #{rest.size}", model: model, stop_reason: :end_turn
|
|
38
|
+
)
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
# Runtime error normalization on the provider callable itself, mirroring the
|
|
@@ -50,14 +50,15 @@ module SsotRegistryHelpers
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def drafts(model: 'gemma4', native: 'gemma4', supported: %i[chat], tier: :local)
|
|
53
|
+
def drafts(model: 'gemma4', native: 'gemma4', supported: %i[chat], tier: :local, **weight_pair)
|
|
54
54
|
[
|
|
55
55
|
Legion::Extensions::Llm::Inventory::OfferingDraft.new(
|
|
56
56
|
provider_native_key: native, model: model, tier: tier,
|
|
57
57
|
operation_evidence: operation_evidence(supported: supported),
|
|
58
58
|
context_evidence: unknown_value, max_output_evidence: unknown_value,
|
|
59
59
|
embedding_dimensions_evidence: unknown_value, model_revision_evidence: unknown_value,
|
|
60
|
-
tokenizer_evidence: unknown_value, publication_source: :provider_catalog
|
|
60
|
+
tokenizer_evidence: unknown_value, publication_source: :provider_catalog,
|
|
61
|
+
**weight_pair
|
|
61
62
|
)
|
|
62
63
|
]
|
|
63
64
|
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
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LegionIO
|
|
@@ -253,13 +253,10 @@ files:
|
|
|
253
253
|
- Gemfile
|
|
254
254
|
- LICENSE
|
|
255
255
|
- README.md
|
|
256
|
+
- RULES.md
|
|
256
257
|
- lex-llm.gemspec
|
|
257
258
|
- lib/legion/extensions/llm.rb
|
|
258
259
|
- lib/legion/extensions/llm/actors/metering_flush.rb
|
|
259
|
-
- lib/legion/extensions/llm/agent.rb
|
|
260
|
-
- lib/legion/extensions/llm/aliases.json
|
|
261
|
-
- lib/legion/extensions/llm/aliases.rb
|
|
262
|
-
- lib/legion/extensions/llm/attachment.rb
|
|
263
260
|
- lib/legion/extensions/llm/auto_registration.rb
|
|
264
261
|
- lib/legion/extensions/llm/canonical.rb
|
|
265
262
|
- lib/legion/extensions/llm/canonical/chunk.rb
|
|
@@ -268,6 +265,7 @@ files:
|
|
|
268
265
|
- lib/legion/extensions/llm/canonical/params.rb
|
|
269
266
|
- lib/legion/extensions/llm/canonical/request.rb
|
|
270
267
|
- lib/legion/extensions/llm/canonical/response.rb
|
|
268
|
+
- lib/legion/extensions/llm/canonical/strict.rb
|
|
271
269
|
- lib/legion/extensions/llm/canonical/thinking.rb
|
|
272
270
|
- lib/legion/extensions/llm/canonical/tool_call.rb
|
|
273
271
|
- lib/legion/extensions/llm/canonical/tool_definition.rb
|
|
@@ -275,18 +273,17 @@ files:
|
|
|
275
273
|
- lib/legion/extensions/llm/canonical/usage.rb
|
|
276
274
|
- lib/legion/extensions/llm/capabilities.rb
|
|
277
275
|
- lib/legion/extensions/llm/capability_policy.rb
|
|
278
|
-
- lib/legion/extensions/llm/chat.rb
|
|
279
|
-
- lib/legion/extensions/llm/chunk.rb
|
|
280
276
|
- lib/legion/extensions/llm/configuration.rb
|
|
281
277
|
- lib/legion/extensions/llm/connection.rb
|
|
282
|
-
- lib/legion/extensions/llm/content.rb
|
|
283
|
-
- lib/legion/extensions/llm/context.rb
|
|
284
278
|
- lib/legion/extensions/llm/credential_sources.rb
|
|
285
|
-
- lib/legion/extensions/llm/
|
|
279
|
+
- lib/legion/extensions/llm/discovery/actor.rb
|
|
280
|
+
- lib/legion/extensions/llm/discovery/pipeline.rb
|
|
286
281
|
- lib/legion/extensions/llm/error.rb
|
|
287
282
|
- lib/legion/extensions/llm/errors/unsupported_capability.rb
|
|
283
|
+
- lib/legion/extensions/llm/fleet/contract_error.rb
|
|
288
284
|
- lib/legion/extensions/llm/fleet/default_exchange_reply.rb
|
|
289
285
|
- lib/legion/extensions/llm/fleet/envelope_validation.rb
|
|
286
|
+
- lib/legion/extensions/llm/fleet/fleet_envelope.rb
|
|
290
287
|
- lib/legion/extensions/llm/fleet/protocol.rb
|
|
291
288
|
- lib/legion/extensions/llm/fleet/provider_responder.rb
|
|
292
289
|
- lib/legion/extensions/llm/fleet/publish_safety.rb
|
|
@@ -294,9 +291,7 @@ files:
|
|
|
294
291
|
- lib/legion/extensions/llm/fleet/token_error.rb
|
|
295
292
|
- lib/legion/extensions/llm/fleet/token_validator.rb
|
|
296
293
|
- lib/legion/extensions/llm/fleet/worker_execution.rb
|
|
297
|
-
- lib/legion/extensions/llm/image.rb
|
|
298
294
|
- lib/legion/extensions/llm/inventory/callable_handle.rb
|
|
299
|
-
- lib/legion/extensions/llm/inventory/capabilities.rb
|
|
300
295
|
- lib/legion/extensions/llm/inventory/errors.rb
|
|
301
296
|
- lib/legion/extensions/llm/inventory/evidence.rb
|
|
302
297
|
- lib/legion/extensions/llm/inventory/identity.rb
|
|
@@ -306,54 +301,30 @@ files:
|
|
|
306
301
|
- lib/legion/extensions/llm/inventory/publisher.rb
|
|
307
302
|
- lib/legion/extensions/llm/inventory/records.rb
|
|
308
303
|
- lib/legion/extensions/llm/inventory/registry.rb
|
|
309
|
-
- lib/legion/extensions/llm/inventory/scoped_refresher.rb
|
|
310
304
|
- lib/legion/extensions/llm/inventory/snapshot.rb
|
|
311
|
-
- lib/legion/extensions/llm/
|
|
312
|
-
- lib/legion/extensions/llm/
|
|
313
|
-
- lib/legion/extensions/llm/model.rb
|
|
314
|
-
- lib/legion/extensions/llm/model/info.rb
|
|
315
|
-
- lib/legion/extensions/llm/model/modalities.rb
|
|
316
|
-
- lib/legion/extensions/llm/model/pricing.rb
|
|
317
|
-
- lib/legion/extensions/llm/model/pricing_category.rb
|
|
318
|
-
- lib/legion/extensions/llm/model/pricing_tier.rb
|
|
319
|
-
- lib/legion/extensions/llm/models.json
|
|
320
|
-
- lib/legion/extensions/llm/models.rb
|
|
321
|
-
- lib/legion/extensions/llm/models_schema.json
|
|
322
|
-
- lib/legion/extensions/llm/moderation.rb
|
|
305
|
+
- lib/legion/extensions/llm/inventory/weight_reconciler.rb
|
|
306
|
+
- lib/legion/extensions/llm/inventory/weight_schema.rb
|
|
323
307
|
- lib/legion/extensions/llm/provider.rb
|
|
324
308
|
- lib/legion/extensions/llm/provider/open_ai_compatible.rb
|
|
325
309
|
- lib/legion/extensions/llm/provider_contract.rb
|
|
326
310
|
- lib/legion/extensions/llm/provider_settings.rb
|
|
327
|
-
- lib/legion/extensions/llm/registry_event_builder.rb
|
|
328
|
-
- lib/legion/extensions/llm/registry_publisher.rb
|
|
329
|
-
- lib/legion/extensions/llm/responses/chat_response.rb
|
|
330
|
-
- lib/legion/extensions/llm/responses/embedding_response.rb
|
|
331
|
-
- lib/legion/extensions/llm/responses/stream_chunk.rb
|
|
332
311
|
- lib/legion/extensions/llm/responses/thinking_extractor.rb
|
|
312
|
+
- lib/legion/extensions/llm/responses/tool_arguments.rb
|
|
333
313
|
- lib/legion/extensions/llm/routing.rb
|
|
334
|
-
- lib/legion/extensions/llm/routing/lane_key.rb
|
|
335
|
-
- lib/legion/extensions/llm/routing/model_offering.rb
|
|
336
|
-
- lib/legion/extensions/llm/routing/offering_registry.rb
|
|
337
314
|
- lib/legion/extensions/llm/routing/provider_outcome.rb
|
|
338
315
|
- lib/legion/extensions/llm/routing/records.rb
|
|
339
|
-
- lib/legion/extensions/llm/routing/registry_event.rb
|
|
340
316
|
- lib/legion/extensions/llm/settings_cascade.rb
|
|
341
317
|
- lib/legion/extensions/llm/stop_reason_mapping.rb
|
|
342
318
|
- lib/legion/extensions/llm/stream_accumulator.rb
|
|
343
319
|
- lib/legion/extensions/llm/streaming.rb
|
|
344
320
|
- lib/legion/extensions/llm/taxonomies.rb
|
|
345
|
-
- lib/legion/extensions/llm/thinking.rb
|
|
346
|
-
- lib/legion/extensions/llm/tokens.rb
|
|
347
321
|
- lib/legion/extensions/llm/tool.rb
|
|
348
|
-
- lib/legion/extensions/llm/tool_call.rb
|
|
349
|
-
- lib/legion/extensions/llm/transcription.rb
|
|
350
322
|
- lib/legion/extensions/llm/transport/exchanges/fleet.rb
|
|
351
323
|
- lib/legion/extensions/llm/transport/exchanges/llm_registry.rb
|
|
352
324
|
- lib/legion/extensions/llm/transport/fleet_lane.rb
|
|
353
325
|
- lib/legion/extensions/llm/transport/messages/fleet_error.rb
|
|
354
326
|
- lib/legion/extensions/llm/transport/messages/fleet_request.rb
|
|
355
327
|
- lib/legion/extensions/llm/transport/messages/fleet_response.rb
|
|
356
|
-
- lib/legion/extensions/llm/transport/messages/registry_event.rb
|
|
357
328
|
- lib/legion/extensions/llm/utils.rb
|
|
358
329
|
- lib/legion/extensions/llm/version.rb
|
|
359
330
|
- spec/fixtures/ruby.mp3
|
|
@@ -364,8 +335,6 @@ files:
|
|
|
364
335
|
- spec/fixtures/ruby.xml
|
|
365
336
|
- spec/fixtures/sample.pdf
|
|
366
337
|
- spec/legion/extensions/llm/actor/metering_flush_spec.rb
|
|
367
|
-
- spec/legion/extensions/llm/agent_spec.rb
|
|
368
|
-
- spec/legion/extensions/llm/attachment_spec.rb
|
|
369
338
|
- spec/legion/extensions/llm/auto_registration_spec.rb
|
|
370
339
|
- spec/legion/extensions/llm/canonical/chunk_spec.rb
|
|
371
340
|
- spec/legion/extensions/llm/canonical/content_block_spec.rb
|
|
@@ -381,6 +350,7 @@ files:
|
|
|
381
350
|
- spec/legion/extensions/llm/capabilities_spec.rb
|
|
382
351
|
- spec/legion/extensions/llm/capability_policy_spec.rb
|
|
383
352
|
- spec/legion/extensions/llm/configuration_spec.rb
|
|
353
|
+
- spec/legion/extensions/llm/conformance/canonical_type_examples.rb
|
|
384
354
|
- spec/legion/extensions/llm/conformance/client_translator_examples.rb
|
|
385
355
|
- spec/legion/extensions/llm/conformance/conformance.rb
|
|
386
356
|
- spec/legion/extensions/llm/conformance/echo_translator.rb
|
|
@@ -407,15 +377,15 @@ files:
|
|
|
407
377
|
- spec/legion/extensions/llm/conformance/fixtures/canonical_tool_results_continuation_request.json
|
|
408
378
|
- spec/legion/extensions/llm/conformance/fixtures/canonical_tool_use_response.json
|
|
409
379
|
- spec/legion/extensions/llm/conformance/fixtures/canonical_tools_request.json
|
|
410
|
-
- spec/legion/extensions/llm/conformance/fixtures/ssot_identity_vectors.json
|
|
411
380
|
- spec/legion/extensions/llm/conformance/provider_tool_rendering_examples.rb
|
|
412
381
|
- spec/legion/extensions/llm/conformance/provider_translator_examples.rb
|
|
382
|
+
- spec/legion/extensions/llm/conformance/ssot_contract_conformance_spec.rb
|
|
383
|
+
- spec/legion/extensions/llm/conformance/ssot_contract_examples.rb
|
|
413
384
|
- spec/legion/extensions/llm/conformance/ssot_provider_conformance_spec.rb
|
|
414
385
|
- spec/legion/extensions/llm/conformance/ssot_provider_examples.rb
|
|
415
386
|
- spec/legion/extensions/llm/connection_close_spec.rb
|
|
416
387
|
- spec/legion/extensions/llm/connection_logging_spec.rb
|
|
417
388
|
- spec/legion/extensions/llm/connection_retry_spec.rb
|
|
418
|
-
- spec/legion/extensions/llm/context_spec.rb
|
|
419
389
|
- spec/legion/extensions/llm/credential_sources_spec.rb
|
|
420
390
|
- spec/legion/extensions/llm/error_middleware_spec.rb
|
|
421
391
|
- spec/legion/extensions/llm/error_spec.rb
|
|
@@ -427,7 +397,6 @@ files:
|
|
|
427
397
|
- spec/legion/extensions/llm/gemspec_spec.rb
|
|
428
398
|
- spec/legion/extensions/llm/inventory/boot_spec.rb
|
|
429
399
|
- spec/legion/extensions/llm/inventory/callable_handle_spec.rb
|
|
430
|
-
- spec/legion/extensions/llm/inventory/capabilities_spec.rb
|
|
431
400
|
- spec/legion/extensions/llm/inventory/evidence_spec.rb
|
|
432
401
|
- spec/legion/extensions/llm/inventory/identity_spec.rb
|
|
433
402
|
- spec/legion/extensions/llm/inventory/immutable_value_spec.rb
|
|
@@ -439,25 +408,17 @@ files:
|
|
|
439
408
|
- spec/legion/extensions/llm/inventory/registry_availability_spec.rb
|
|
440
409
|
- spec/legion/extensions/llm/inventory/registry_callable_spec.rb
|
|
441
410
|
- spec/legion/extensions/llm/inventory/registry_replacement_spec.rb
|
|
442
|
-
- spec/legion/extensions/llm/inventory/scoped_refresher_spec.rb
|
|
443
411
|
- spec/legion/extensions/llm/inventory/snapshot_spec.rb
|
|
444
|
-
- spec/legion/extensions/llm/
|
|
445
|
-
- spec/legion/extensions/llm/
|
|
446
|
-
- spec/legion/extensions/llm/models_spec.rb
|
|
412
|
+
- spec/legion/extensions/llm/inventory/weight_reconciler_spec.rb
|
|
413
|
+
- spec/legion/extensions/llm/inventory/weight_schema_spec.rb
|
|
447
414
|
- spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb
|
|
448
415
|
- spec/legion/extensions/llm/provider/open_ai_compatible_tool_calls_array_spec.rb
|
|
449
416
|
- spec/legion/extensions/llm/provider_contract_spec.rb
|
|
450
417
|
- spec/legion/extensions/llm/provider_settings_spec.rb
|
|
451
418
|
- spec/legion/extensions/llm/provider_spec.rb
|
|
452
|
-
- spec/legion/extensions/llm/registry_event_builder_spec.rb
|
|
453
|
-
- spec/legion/extensions/llm/registry_publisher_spec.rb
|
|
454
|
-
- spec/legion/extensions/llm/responses/response_objects_spec.rb
|
|
455
419
|
- spec/legion/extensions/llm/responses/thinking_extractor_spec.rb
|
|
456
|
-
- spec/legion/extensions/llm/routing/model_offering_spec.rb
|
|
457
|
-
- spec/legion/extensions/llm/routing/offering_registry_spec.rb
|
|
458
420
|
- spec/legion/extensions/llm/routing/provider_outcome_spec.rb
|
|
459
421
|
- spec/legion/extensions/llm/routing/records_spec.rb
|
|
460
|
-
- spec/legion/extensions/llm/routing/registry_event_spec.rb
|
|
461
422
|
- spec/legion/extensions/llm/settings_cascade_spec.rb
|
|
462
423
|
- spec/legion/extensions/llm/stop_reason_mapping_spec.rb
|
|
463
424
|
- spec/legion/extensions/llm/stream_accumulator_spec.rb
|