lex-llm 0.7.6 → 0.8.4
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 +139 -0
- data/RULES.md +97 -0
- data/lib/legion/extensions/llm/auto_registration.rb +4 -13
- data/lib/legion/extensions/llm/canonical/chunk.rb +107 -94
- data/lib/legion/extensions/llm/canonical/content_block.rb +65 -75
- data/lib/legion/extensions/llm/canonical/message.rb +53 -69
- data/lib/legion/extensions/llm/canonical/params.rb +58 -34
- data/lib/legion/extensions/llm/canonical/request.rb +68 -56
- data/lib/legion/extensions/llm/canonical/response.rb +62 -78
- data/lib/legion/extensions/llm/canonical/strict.rb +105 -0
- data/lib/legion/extensions/llm/canonical/thinking.rb +36 -84
- data/lib/legion/extensions/llm/canonical/thinking_config.rb +149 -0
- data/lib/legion/extensions/llm/canonical/tool_call.rb +43 -53
- 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 +7 -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 -156
- data/lib/legion/extensions/llm/fleet/token_validator.rb +15 -21
- data/lib/legion/extensions/llm/fleet/worker_execution.rb +107 -154
- 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 +36 -100
- data/lib/legion/extensions/llm/inventory/registry.rb +54 -48
- data/lib/legion/extensions/llm/inventory/snapshot.rb +7 -21
- data/lib/legion/extensions/llm/inventory/weight_reconciler.rb +13 -6
- data/lib/legion/extensions/llm/inventory/weight_schema.rb +47 -8
- data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +178 -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 +48 -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 +14 -26
- 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 +8 -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 +55 -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/config_spec.rb +222 -0
- data/spec/legion/extensions/llm/canonical/thinking_spec.rb +23 -171
- 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/client_translator_examples.rb +1 -2
- data/spec/legion/extensions/llm/conformance/conformance.rb +10 -2
- data/spec/legion/extensions/llm/conformance/fixtures/canonical_fleet_round_trip.json +1 -1
- data/spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_request.json +2 -2
- data/spec/legion/extensions/llm/conformance/provider_translator_examples.rb +1 -1
- data/spec/legion/extensions/llm/conformance/ssot_contract_conformance_spec.rb +128 -0
- data/spec/legion/extensions/llm/conformance/ssot_contract_examples.rb +505 -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 +173 -95
- data/spec/legion/extensions/llm/fleet/token_validator_spec.rb +7 -2
- data/spec/legion/extensions/llm/fleet/worker_execution_spec.rb +93 -74
- data/spec/legion/extensions/llm/fleet_messages_spec.rb +119 -125
- data/spec/legion/extensions/llm/gemspec_spec.rb +1 -2
- 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 +82 -47
- data/spec/legion/extensions/llm/inventory/registry_activation_spec.rb +49 -16
- 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 +7 -3
- data/spec/legion/extensions/llm/inventory/weight_schema_spec.rb +60 -10
- data/spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb +128 -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 +97 -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 -43
- 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
- metadata +13 -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 -310
- 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 -340
- 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
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.describe Legion::Extensions::Llm::Routing::RegistryEvent do
|
|
6
|
-
subject(:event) do
|
|
7
|
-
described_class.new(
|
|
8
|
-
event_id: 'evt-123',
|
|
9
|
-
event_type: :offering_available,
|
|
10
|
-
occurred_at: Time.utc(2026, 4, 28, 14, 30, 15, 123_456),
|
|
11
|
-
offering: offering,
|
|
12
|
-
runtime: { host_id: 'macbook-m4-max', process: { pid: 12_345 } },
|
|
13
|
-
capacity: { concurrency: 4, queued: 0 },
|
|
14
|
-
health: { ready: true, latency_ms: 180 },
|
|
15
|
-
lane: 'llm.fleet.inference.qwen3-6.ctx32768',
|
|
16
|
-
metadata: { observed_by: :lex_llm_ollama }
|
|
17
|
-
)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
let(:offering) do
|
|
21
|
-
Legion::Extensions::Llm::Routing::ModelOffering.new(
|
|
22
|
-
provider_family: :ollama,
|
|
23
|
-
provider_instance: :'macbook-m4-max',
|
|
24
|
-
transport: :rabbitmq,
|
|
25
|
-
model: 'qwen3.6',
|
|
26
|
-
capabilities: %i[chat tools],
|
|
27
|
-
limits: { context_window: 32_768 },
|
|
28
|
-
credentials: { api_key: 'secret' },
|
|
29
|
-
metadata: { enabled: true, api_key: 'secret' }
|
|
30
|
-
)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it 'serializes a provider-neutral registry envelope' do
|
|
34
|
-
expect(event).to have_attributes(
|
|
35
|
-
event_id: 'evt-123',
|
|
36
|
-
event_type: :offering_available,
|
|
37
|
-
occurred_at: Time.utc(2026, 4, 28, 14, 30, 15, 123_456)
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
expect(event.to_h).to include(
|
|
41
|
-
event_id: 'evt-123',
|
|
42
|
-
event_type: :offering_available,
|
|
43
|
-
occurred_at: '2026-04-28T14:30:15.123456Z',
|
|
44
|
-
runtime: { host_id: 'macbook-m4-max', process: { pid: 12_345 } },
|
|
45
|
-
capacity: { concurrency: 4, queued: 0 },
|
|
46
|
-
health: { ready: true, latency_ms: 180 },
|
|
47
|
-
lane: 'llm.fleet.inference.qwen3-6.ctx32768',
|
|
48
|
-
metadata: { observed_by: :lex_llm_ollama }
|
|
49
|
-
)
|
|
50
|
-
expect(event.to_h[:offering]).to include(
|
|
51
|
-
offering_id: 'ollama:macbook-m4-max:inference:qwen3-6',
|
|
52
|
-
provider_family: :ollama,
|
|
53
|
-
provider_instance: :'macbook-m4-max',
|
|
54
|
-
model: 'qwen3.6',
|
|
55
|
-
capabilities: %i[chat tools],
|
|
56
|
-
limits: { context_window: 32_768 },
|
|
57
|
-
metadata: { enabled: true }
|
|
58
|
-
)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it 'omits sensitive offering fields before publishing' do
|
|
62
|
-
envelope = event.to_h
|
|
63
|
-
|
|
64
|
-
expect(envelope[:offering]).not_to have_key(:credentials)
|
|
65
|
-
expect(envelope[:offering][:metadata]).not_to have_key(:api_key)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'normalizes hash offerings through ModelOffering' do
|
|
69
|
-
event = described_class.heartbeat(
|
|
70
|
-
{
|
|
71
|
-
'provider_family' => 'bedrock',
|
|
72
|
-
'provider_instance' => 'us-east-1',
|
|
73
|
-
'model' => 'amazon.titan-embed-text-v2:0',
|
|
74
|
-
'usage_type' => 'embedding',
|
|
75
|
-
'capabilities' => ['embedding']
|
|
76
|
-
},
|
|
77
|
-
event_id: 'evt-heartbeat',
|
|
78
|
-
occurred_at: '2026-04-28T14:31:00Z'
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
expect(event.to_h).to include(
|
|
82
|
-
event_id: 'evt-heartbeat',
|
|
83
|
-
event_type: :offering_heartbeat,
|
|
84
|
-
occurred_at: '2026-04-28T14:31:00.000000Z'
|
|
85
|
-
)
|
|
86
|
-
expect(event.to_h[:offering]).to include(
|
|
87
|
-
provider_family: :bedrock,
|
|
88
|
-
provider_instance: :'us-east-1',
|
|
89
|
-
usage_type: :embedding,
|
|
90
|
-
capabilities: [:embedding]
|
|
91
|
-
)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it 'provides event-type helpers' do
|
|
95
|
-
expect(described_class.available(offering).event_type).to eq(:offering_available)
|
|
96
|
-
expect(described_class.unavailable(offering).event_type).to eq(:offering_unavailable)
|
|
97
|
-
expect(described_class.degraded(offering).event_type).to eq(:offering_degraded)
|
|
98
|
-
expect(described_class.heartbeat(offering).event_type).to eq(:offering_heartbeat)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it 'rejects unknown event types' do
|
|
102
|
-
expect do
|
|
103
|
-
described_class.new(event_type: :available, offering: offering)
|
|
104
|
-
end.to raise_error(ArgumentError, /unsupported registry event type/)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it 'rejects sensitive runtime, capacity, health, lane, and metadata keys' do
|
|
108
|
-
%i[runtime capacity health lane metadata].each do |field|
|
|
109
|
-
attributes = {
|
|
110
|
-
event_type: :offering_degraded,
|
|
111
|
-
offering: offering,
|
|
112
|
-
field => { 'nested' => { 'api_key' => 'secret' } }
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
expect do
|
|
116
|
-
described_class.new(**attributes)
|
|
117
|
-
end.to raise_error(ArgumentError, /#{field} contains sensitive key: nested.api_key/)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|