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,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'legion/logging'
|
|
4
3
|
require 'legion/extensions/llm/inventory/errors'
|
|
5
4
|
require 'legion/extensions/llm/inventory/identity'
|
|
6
5
|
require 'legion/extensions/llm/inventory/registry'
|
|
@@ -12,16 +11,14 @@ module Legion
|
|
|
12
11
|
# Provider-facing direct wrapper over the local Registry. It constructs
|
|
13
12
|
# and validates the exact InstanceKey from its fixed provider family and
|
|
14
13
|
# delegates to the registry with the exact kwargs. It does no retries,
|
|
15
|
-
# selection, scheduling, defaulting, provider discovery
|
|
16
|
-
#
|
|
17
|
-
#
|
|
14
|
+
# selection, scheduling, defaulting, or provider discovery. M7: the
|
|
15
|
+
# legacy dual-sink seam (compatibility_adapter / old-coordinator
|
|
16
|
+
# projection) is deleted — one representation, one routing authority;
|
|
17
|
+
# the SSOT registry is the only inventory sink.
|
|
18
18
|
class Publisher
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def initialize(provider_family:, registry: Registry, compatibility_adapter: nil)
|
|
19
|
+
def initialize(provider_family:, registry: Registry)
|
|
22
20
|
@provider_family = provider_family
|
|
23
21
|
@registry = registry
|
|
24
|
-
@compatibility_adapter = compatibility_adapter
|
|
25
22
|
end
|
|
26
23
|
|
|
27
24
|
# Every instance operation takes `instance_id:` — the operator's
|
|
@@ -30,9 +27,7 @@ module Legion
|
|
|
30
27
|
# dedup and diagnostics only. See Identity::InstanceKey.
|
|
31
28
|
def claim_instance(instance_id:, callable:, probe_request_handle:, physical_id: nil)
|
|
32
29
|
key = instance_key(instance_id: instance_id, physical_id: physical_id)
|
|
33
|
-
|
|
34
|
-
sync_compatibility(key, :claimed)
|
|
35
|
-
token
|
|
30
|
+
@registry.claim_instance(instance_key: key, callable: callable, probe_request_handle: probe_request_handle)
|
|
36
31
|
end
|
|
37
32
|
|
|
38
33
|
def readiness_probe_started(instance_id:, publisher_token:, physical_id: nil)
|
|
@@ -42,35 +37,29 @@ module Legion
|
|
|
42
37
|
end
|
|
43
38
|
|
|
44
39
|
def activate_instance_snapshot(instance_id:, publisher_token:, offerings:, sequence:, probe_token:, physical_id: nil) # rubocop:disable Metrics/ParameterLists
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
sequence: sequence, probe_token: probe_token
|
|
40
|
+
@registry.activate_instance_snapshot(
|
|
41
|
+
publisher_token: publisher_token, instance_key: instance_key(instance_id: instance_id, physical_id: physical_id),
|
|
42
|
+
offerings: offerings, sequence: sequence, probe_token: probe_token
|
|
49
43
|
)
|
|
50
|
-
sync_applied(key, result)
|
|
51
44
|
end
|
|
52
45
|
|
|
53
46
|
def replace_instance_snapshot(instance_id:, publisher_token:, offerings:, sequence:, physical_id: nil)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
@registry.replace_instance_snapshot(
|
|
48
|
+
publisher_token: publisher_token, instance_key: instance_key(instance_id: instance_id, physical_id: physical_id),
|
|
49
|
+
offerings: offerings, sequence: sequence
|
|
57
50
|
)
|
|
58
|
-
sync_applied(key, result)
|
|
59
51
|
end
|
|
60
52
|
|
|
61
53
|
def readiness_succeeded(instance_id:, probe_token:, physical_id: nil)
|
|
62
|
-
|
|
63
|
-
sync_applied(key, @registry.readiness_succeeded(instance_key: key, probe_token: probe_token))
|
|
54
|
+
@registry.readiness_succeeded(instance_key: instance_key(instance_id: instance_id, physical_id: physical_id), probe_token: probe_token)
|
|
64
55
|
end
|
|
65
56
|
|
|
66
57
|
def readiness_failed(instance_id:, probe_token:, reason:, physical_id: nil)
|
|
67
|
-
|
|
68
|
-
sync_applied(key, @registry.readiness_failed(instance_key: key, probe_token: probe_token, reason: reason))
|
|
58
|
+
@registry.readiness_failed(instance_key: instance_key(instance_id: instance_id, physical_id: physical_id), probe_token: probe_token, reason: reason)
|
|
69
59
|
end
|
|
70
60
|
|
|
71
61
|
def remove_instance(instance_id:, publisher_token:, physical_id: nil)
|
|
72
|
-
|
|
73
|
-
sync_applied(key, @registry.remove_instance(instance_key: key, publisher_token: publisher_token))
|
|
62
|
+
@registry.remove_instance(instance_key: instance_key(instance_id: instance_id, physical_id: physical_id), publisher_token: publisher_token)
|
|
74
63
|
end
|
|
75
64
|
|
|
76
65
|
def snapshot
|
|
@@ -82,33 +71,6 @@ module Legion
|
|
|
82
71
|
def instance_key(instance_id:, physical_id: nil)
|
|
83
72
|
Identity::InstanceKey.new(provider_family: @provider_family, instance_id: instance_id, physical_id: physical_id)
|
|
84
73
|
end
|
|
85
|
-
|
|
86
|
-
def sync_applied(instance_key, result)
|
|
87
|
-
sync_compatibility(instance_key, result.reason) if result.applied
|
|
88
|
-
result
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Best-effort, post-commit projection into the old coordinator. It never
|
|
92
|
-
# changes the local return and can never roll back or authorize the SSOT.
|
|
93
|
-
def sync_compatibility(instance_key, mutation_reason)
|
|
94
|
-
return if @compatibility_adapter.nil?
|
|
95
|
-
|
|
96
|
-
outcome = @compatibility_adapter.sync_snapshot(
|
|
97
|
-
snapshot: @registry.snapshot, instance_key: instance_key, mutation_reason: mutation_reason
|
|
98
|
-
)
|
|
99
|
-
return unless outcome == :failed
|
|
100
|
-
|
|
101
|
-
log.warn(
|
|
102
|
-
'[llm][inventory][publisher] action=compatibility_sync result=failed ' \
|
|
103
|
-
"provider_family=#{instance_key.provider_family} instance=#{instance_key.instance_id} reason=#{mutation_reason}"
|
|
104
|
-
)
|
|
105
|
-
rescue StandardError => e
|
|
106
|
-
handle_exception(
|
|
107
|
-
e, handled: true, level: :warn, operation: 'llm.inventory.publisher.compatibility_sync',
|
|
108
|
-
provider_family: instance_key.provider_family, instance_id: instance_key.instance_id,
|
|
109
|
-
mutation_reason: mutation_reason
|
|
110
|
-
)
|
|
111
|
-
end
|
|
112
74
|
end
|
|
113
75
|
end
|
|
114
76
|
end
|
|
@@ -13,10 +13,10 @@ module Legion
|
|
|
13
13
|
module Llm
|
|
14
14
|
module Inventory
|
|
15
15
|
# Documentation namespace anchor for the immutable inventory records
|
|
16
|
-
# defined in this file: OfferingDraft,
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
16
|
+
# defined in this file: OfferingDraft, LaneRecord, AvailabilityFact,
|
|
17
|
+
# ReadinessResult, InstanceRecord, PublicationStatus, and
|
|
18
|
+
# MutationResult. The records themselves live directly under Inventory
|
|
19
|
+
# so their canonical constant paths stay flat.
|
|
20
20
|
module Records; end
|
|
21
21
|
|
|
22
22
|
# Shared normalization/validation used by the immutable inventory and
|
|
@@ -151,7 +151,7 @@ module Legion
|
|
|
151
151
|
|
|
152
152
|
normalized = {}
|
|
153
153
|
evidence.each do |key, value|
|
|
154
|
-
op = Taxonomies.normalize_operation(value: key
|
|
154
|
+
op = Taxonomies.normalize_operation(value: key)
|
|
155
155
|
raise Errors::ValidationError, "operation_evidence[#{op}] must be an OperationEvidence" unless value.is_a?(OperationEvidence)
|
|
156
156
|
raise Errors::ValidationError, "operation_evidence[#{op}] operation must match key" unless value.operation == op
|
|
157
157
|
raise Errors::ValidationError, "duplicate operation_evidence key #{op}" if normalized.key?(op)
|
|
@@ -184,7 +184,7 @@ module Legion
|
|
|
184
184
|
|
|
185
185
|
normalized = {}
|
|
186
186
|
quota_domains.each do |key, value|
|
|
187
|
-
op = Taxonomies.normalize_operation(value: key
|
|
187
|
+
op = Taxonomies.normalize_operation(value: key)
|
|
188
188
|
normalized[op] = validate_quota_domain_value!(value: value, field: "quota_domains[#{op}]")
|
|
189
189
|
end
|
|
190
190
|
normalized.freeze
|
|
@@ -197,7 +197,7 @@ module Legion
|
|
|
197
197
|
end
|
|
198
198
|
|
|
199
199
|
# Validates and returns the five scalar ValueEvidence fields shared by
|
|
200
|
-
# OfferingDraft
|
|
200
|
+
# OfferingDraft and LaneRecord as a member Hash.
|
|
201
201
|
def scalar_value_evidences(kwargs)
|
|
202
202
|
{
|
|
203
203
|
context_evidence: positive_int_value_evidence!(kwargs[:context_evidence], :context_evidence),
|
|
@@ -312,81 +312,15 @@ module Legion
|
|
|
312
312
|
end
|
|
313
313
|
end
|
|
314
314
|
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
#
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
:model_revision_evidence, :tokenizer_evidence, :quota_domains, :metadata, :callable_handle,
|
|
322
|
-
:publication_source, :weight_inputs, :base_weight
|
|
323
|
-
) do
|
|
324
|
-
def initialize(**kwargs)
|
|
325
|
-
RecordSupport.check_unknown_kwargs!(kwargs: kwargs, members: self.class.members)
|
|
326
|
-
weight_inputs, base_weight = RecordSupport.validated_weight_pair(
|
|
327
|
-
weight_inputs: kwargs[:weight_inputs], base_weight: kwargs[:base_weight]
|
|
328
|
-
)
|
|
329
|
-
instance_key = kwargs[:instance_key]
|
|
330
|
-
callable_handle = kwargs[:callable_handle]
|
|
331
|
-
raise Errors::ValidationError, 'instance_key must be an InstanceKey' unless instance_key.is_a?(Identity::InstanceKey)
|
|
332
|
-
raise Errors::ValidationError, 'callable_handle must be a CallableHandle' unless callable_handle.is_a?(CallableHandle)
|
|
333
|
-
|
|
334
|
-
native_key = Identity.normalize_text(value: kwargs[:provider_native_key], field: :provider_native_key)
|
|
335
|
-
Identity.validate_offering_id!(value: kwargs[:offering_id], instance_key: instance_key, provider_native_key: native_key)
|
|
336
|
-
|
|
337
|
-
super(
|
|
338
|
-
offering_id: kwargs[:offering_id].dup.freeze,
|
|
339
|
-
provider_native_key: native_key,
|
|
340
|
-
instance_key: instance_key,
|
|
341
|
-
model: Identity.normalize_text(value: kwargs[:model], field: :model),
|
|
342
|
-
tier: Identity.normalize_enum(value: kwargs[:tier], field: :tier, allowed: Taxonomies::TIERS),
|
|
343
|
-
operation_evidence: RecordSupport.validate_operation_evidence!(kwargs[:operation_evidence]),
|
|
344
|
-
capability_evidence: RecordSupport.validate_capability_evidence!(kwargs[:capability_evidence]),
|
|
345
|
-
quota_domains: RecordSupport.validate_quota_domains!(kwargs[:quota_domains]),
|
|
346
|
-
metadata: RecordSupport.frozen_metadata(value: kwargs[:metadata]),
|
|
347
|
-
callable_handle: callable_handle,
|
|
348
|
-
publication_source: RecordSupport.publication_source!(value: kwargs[:publication_source]),
|
|
349
|
-
weight_inputs: weight_inputs,
|
|
350
|
-
base_weight: base_weight,
|
|
351
|
-
**RecordSupport.scalar_value_evidences(kwargs)
|
|
352
|
-
)
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
def supported_operations
|
|
356
|
-
operation_evidence.select { |_op, evidence| evidence.supported? }.keys.sort
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
def unsupported_operations
|
|
360
|
-
operation_evidence.select { |_op, evidence| evidence.unsupported? }.keys.sort
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
def unknown_operations
|
|
364
|
-
operation_evidence.select { |_op, evidence| evidence.unknown? }.keys.sort
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
def operation_status(operation:)
|
|
368
|
-
operation_evidence.fetch(Taxonomies.normalize_operation(value: operation, allow_aliases: false)).status
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
def capability_evidence_for(capability:)
|
|
372
|
-
capability_evidence[Legion::Extensions::Llm::Capabilities.canonical(capability)]
|
|
373
|
-
end
|
|
374
|
-
|
|
375
|
-
def capability_status(capability:)
|
|
376
|
-
evidence = capability_evidence_for(capability: capability)
|
|
377
|
-
evidence.nil? ? :unknown : evidence.status
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
def quota_domain(operation:)
|
|
381
|
-
quota_domains[Taxonomies.normalize_operation(value: operation, allow_aliases: false)]
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
# An executable lane derived by the registry from one supported operation
|
|
386
|
-
# of an OfferingRecord, with its write-time weight pair copied unchanged.
|
|
315
|
+
# An executable lane: the ONE stored inventory unit, keyed by the
|
|
316
|
+
# 5-tuple id `tier:provider_family:instance_id:type:model`. Derived by
|
|
317
|
+
# the registry from one supported operation of an OfferingDraft, with
|
|
318
|
+
# its write-time weight pair copied unchanged. The 5 tuple is composed
|
|
319
|
+
# at validation from the record's own fields; there is no separate
|
|
320
|
+
# offering id (D2 — in the one bucket an offering IS a lane).
|
|
387
321
|
# See section 10.3.
|
|
388
322
|
LaneRecord = ::Data.define(
|
|
389
|
-
:lane_id, :
|
|
323
|
+
:lane_id, :instance_key, :provider_family, :instance_id, :model, :tier, :operation,
|
|
390
324
|
:capability_evidence, :context_evidence, :max_output_evidence, :embedding_dimensions_evidence,
|
|
391
325
|
:model_revision_evidence, :tokenizer_evidence, :quota_domain, :metadata, :callable_handle,
|
|
392
326
|
:publication_source, :weight_inputs, :base_weight
|
|
@@ -407,21 +341,24 @@ module Legion
|
|
|
407
341
|
raise Errors::ValidationError, 'provider_family and instance_id must equal instance_key'
|
|
408
342
|
end
|
|
409
343
|
|
|
344
|
+
canonical_tier = Identity.normalize_enum(value: kwargs[:tier], field: :tier, allowed: Taxonomies::TIERS)
|
|
410
345
|
canonical_model = Identity.normalize_text(value: kwargs[:model], field: :model)
|
|
411
|
-
canonical_operation = Taxonomies.normalize_operation(value: kwargs[:operation]
|
|
412
|
-
Identity.validate_lane_id!(
|
|
413
|
-
|
|
414
|
-
|
|
346
|
+
canonical_operation = Taxonomies.normalize_operation(value: kwargs[:operation])
|
|
347
|
+
Identity.validate_lane_id!(value: kwargs[:lane_id])
|
|
348
|
+
expected_lane_id = Identity.compose_lane_id(
|
|
349
|
+
tier: canonical_tier, provider_family: family, instance_id: resolved_instance,
|
|
350
|
+
type: Taxonomies.lane_type_for(operation: canonical_operation), model: canonical_model
|
|
415
351
|
)
|
|
352
|
+
raise Errors::ValidationError, 'lane_id does not reproduce from its identity fields' \
|
|
353
|
+
unless kwargs[:lane_id].to_s == expected_lane_id
|
|
416
354
|
|
|
417
355
|
super(
|
|
418
|
-
lane_id: kwargs[:lane_id].dup.freeze,
|
|
419
|
-
offering_id: kwargs[:offering_id].dup.freeze,
|
|
356
|
+
lane_id: kwargs[:lane_id].to_s.dup.freeze,
|
|
420
357
|
instance_key: instance_key,
|
|
421
358
|
provider_family: family,
|
|
422
359
|
instance_id: resolved_instance,
|
|
423
360
|
model: canonical_model,
|
|
424
|
-
tier:
|
|
361
|
+
tier: canonical_tier,
|
|
425
362
|
operation: canonical_operation,
|
|
426
363
|
capability_evidence: RecordSupport.validate_capability_evidence!(kwargs[:capability_evidence]),
|
|
427
364
|
quota_domain: kwargs[:quota_domain].nil? ? nil : RecordSupport.validate_quota_domain_value!(value: kwargs[:quota_domain], field: :quota_domain),
|
|
@@ -507,10 +444,11 @@ module Legion
|
|
|
507
444
|
end
|
|
508
445
|
end
|
|
509
446
|
|
|
510
|
-
# An activated exact instance's complete published state. Its
|
|
511
|
-
#
|
|
447
|
+
# An activated exact instance's complete published state. Its lanes are
|
|
448
|
+
# keyed by the 5-tuple lane id; its availability is available or
|
|
449
|
+
# unavailable, never initializing. See section 10.6.
|
|
512
450
|
InstanceRecord = ::Data.define(
|
|
513
|
-
:instance_key, :callable_handle, :availability, :
|
|
451
|
+
:instance_key, :callable_handle, :availability, :lanes_by_id,
|
|
514
452
|
:publisher_id, :publisher_token_id, :published_sequence, :published_at
|
|
515
453
|
) do
|
|
516
454
|
def initialize(**kwargs)
|
|
@@ -528,7 +466,7 @@ module Legion
|
|
|
528
466
|
instance_key: instance_key,
|
|
529
467
|
callable_handle: callable_handle,
|
|
530
468
|
availability: availability,
|
|
531
|
-
|
|
469
|
+
lanes_by_id: validate_lanes!(kwargs[:lanes_by_id], instance_key, callable_handle),
|
|
532
470
|
publisher_id: nonempty_id!(kwargs[:publisher_id], :publisher_id),
|
|
533
471
|
publisher_token_id: nonempty_id!(kwargs[:publisher_token_id], :publisher_token_id),
|
|
534
472
|
published_sequence: RecordSupport.nonnegative_integer(value: kwargs[:published_sequence], field: :published_sequence),
|
|
@@ -536,17 +474,15 @@ module Legion
|
|
|
536
474
|
)
|
|
537
475
|
end
|
|
538
476
|
|
|
539
|
-
def
|
|
540
|
-
raise Errors::ValidationError, '
|
|
477
|
+
def validate_lanes!(lanes_by_id, instance_key, callable_handle)
|
|
478
|
+
raise Errors::ValidationError, 'lanes_by_id must be a Hash' unless lanes_by_id.is_a?(::Hash)
|
|
541
479
|
|
|
542
|
-
|
|
543
|
-
raise Errors::ValidationError, "
|
|
544
|
-
raise Errors::ValidationError, "
|
|
545
|
-
unless
|
|
546
|
-
raise Errors::ValidationError, "offering #{offering_id} must share the instance callable/key"
|
|
547
|
-
end
|
|
480
|
+
lanes_by_id.each do |lane_id, lane|
|
|
481
|
+
raise Errors::ValidationError, "lane #{lane_id} must be a LaneRecord" unless lane.is_a?(LaneRecord)
|
|
482
|
+
raise Errors::ValidationError, "lane #{lane_id} key mismatch" unless lane.lane_id == lane_id
|
|
483
|
+
raise Errors::ValidationError, "lane #{lane_id} must share the instance callable/key" unless lane.instance_key == instance_key && lane.callable_handle.equal?(callable_handle)
|
|
548
484
|
end
|
|
549
|
-
|
|
485
|
+
lanes_by_id.dup.freeze
|
|
550
486
|
end
|
|
551
487
|
|
|
552
488
|
def nonempty_id!(value, field)
|
|
@@ -9,6 +9,7 @@ require 'legion/extensions/llm/inventory/callable_handle'
|
|
|
9
9
|
require 'legion/extensions/llm/inventory/probe_token'
|
|
10
10
|
require 'legion/extensions/llm/inventory/records'
|
|
11
11
|
require 'legion/extensions/llm/inventory/snapshot'
|
|
12
|
+
require 'legion/extensions/llm/taxonomies'
|
|
12
13
|
|
|
13
14
|
module Legion
|
|
14
15
|
module Extensions
|
|
@@ -21,7 +22,7 @@ module Legion
|
|
|
21
22
|
# Private per-instance state. Never leaves registry.rb.
|
|
22
23
|
ScopeState = ::Data.define(
|
|
23
24
|
:instance_key, :publisher_token, :callable, :callable_handle, :probe_request_handle,
|
|
24
|
-
:publication_status, :last_sequence, :availability, :
|
|
25
|
+
:publication_status, :last_sequence, :availability, :lanes,
|
|
25
26
|
:availability_revision, :unavailable_revision, :published_at
|
|
26
27
|
)
|
|
27
28
|
|
|
@@ -196,7 +197,7 @@ module Legion
|
|
|
196
197
|
@scopes[instance_key] = ScopeState.new(
|
|
197
198
|
instance_key: instance_key, publisher_token: token, callable: callable, callable_handle: handle,
|
|
198
199
|
probe_request_handle: probe_request_handle, publication_status: status,
|
|
199
|
-
last_sequence: -1, availability: nil,
|
|
200
|
+
last_sequence: -1, availability: nil, lanes: {},
|
|
200
201
|
availability_revision: prior&.availability_revision || 0,
|
|
201
202
|
unavailable_revision: prior&.unavailable_revision, published_at: nil
|
|
202
203
|
)
|
|
@@ -218,7 +219,7 @@ module Legion
|
|
|
218
219
|
status = complete_status(scope, sequence, probe_token, now, :success)
|
|
219
220
|
new_scope = scope.with(
|
|
220
221
|
publication_status: status, last_sequence: sequence, availability: availability,
|
|
221
|
-
|
|
222
|
+
lanes: prepared[1], availability_revision: new_rev,
|
|
222
223
|
unavailable_revision: nil, published_at: now
|
|
223
224
|
)
|
|
224
225
|
@scopes[instance_key] = new_scope
|
|
@@ -237,7 +238,7 @@ module Legion
|
|
|
237
238
|
|
|
238
239
|
def apply_replacement(scope, instance_key, prepared, sequence)
|
|
239
240
|
status = scope.publication_status.with(published_sequence: sequence)
|
|
240
|
-
new_scope = scope.with(
|
|
241
|
+
new_scope = scope.with(lanes: prepared[1], last_sequence: sequence, publication_status: status)
|
|
241
242
|
@scopes[instance_key] = new_scope
|
|
242
243
|
bump_and_snapshot!
|
|
243
244
|
applied(:snapshot_replaced, new_scope)
|
|
@@ -428,7 +429,6 @@ module Legion
|
|
|
428
429
|
|
|
429
430
|
def build_snapshot_locked
|
|
430
431
|
instances = {}
|
|
431
|
-
offerings = {}
|
|
432
432
|
lanes = {}
|
|
433
433
|
statuses = {}
|
|
434
434
|
@scopes.each_pair do |key, scope|
|
|
@@ -436,11 +436,10 @@ module Legion
|
|
|
436
436
|
next if scope.availability.nil?
|
|
437
437
|
|
|
438
438
|
instances[key] = instance_record_for(scope)
|
|
439
|
-
offerings.merge!(scope.offerings)
|
|
440
439
|
lanes.merge!(scope.lanes)
|
|
441
440
|
end
|
|
442
441
|
Snapshot.new(
|
|
443
|
-
generation: @generation, instances_by_key: instances,
|
|
442
|
+
generation: @generation, instances_by_key: instances,
|
|
444
443
|
lanes_by_id: lanes, publication_status_by_key: statuses
|
|
445
444
|
)
|
|
446
445
|
end
|
|
@@ -448,7 +447,7 @@ module Legion
|
|
|
448
447
|
def instance_record_for(scope)
|
|
449
448
|
InstanceRecord.new(
|
|
450
449
|
instance_key: scope.instance_key, callable_handle: scope.callable_handle, availability: scope.availability,
|
|
451
|
-
|
|
450
|
+
lanes_by_id: scope.lanes, publisher_id: scope.publisher_token.publisher_id,
|
|
452
451
|
publisher_token_id: scope.publisher_token.publisher_token_id, published_sequence: scope.last_sequence,
|
|
453
452
|
published_at: scope.published_at
|
|
454
453
|
)
|
|
@@ -460,69 +459,76 @@ module Legion
|
|
|
460
459
|
scope = @scopes[instance_key]
|
|
461
460
|
return nil if scope.nil?
|
|
462
461
|
|
|
463
|
-
|
|
464
|
-
[scope.callable_handle, offerings_by_id, lanes_by_id]
|
|
462
|
+
[scope.callable_handle, build_records(instance_key, scope.callable_handle, drafts)]
|
|
465
463
|
end
|
|
466
464
|
|
|
467
465
|
def prepared_matches?(prepared, scope)
|
|
468
466
|
!prepared.nil? && prepared[0].equal?(scope.callable_handle)
|
|
469
467
|
end
|
|
470
468
|
|
|
469
|
+
# The stored inventory is lanes ONLY, keyed by the 5 tuple
|
|
470
|
+
# tier:provider_family:instance_id:type:model. The 4th part is the
|
|
471
|
+
# COARSE type, not the fine operation: the operations a draft
|
|
472
|
+
# supports collapse to one lane per distinct type (chat +
|
|
473
|
+
# stream_chat + count_tokens are ONE inference lane — the v0.15.2
|
|
474
|
+
# model, where the operation is a request property matched against
|
|
475
|
+
# the lane type, not a lane identity part). The LaneRecord's
|
|
476
|
+
# operation member is the first supported operation of the lane's
|
|
477
|
+
# type in canonical order — the representative, not the identity.
|
|
478
|
+
# A duplicate (operation, model) published under a conflicting
|
|
479
|
+
# tier, or a second draft claiming an already-published 5 tuple,
|
|
480
|
+
# raises — never a silent merge (D1).
|
|
471
481
|
def build_records(instance_key, handle, drafts)
|
|
472
|
-
|
|
482
|
+
lanes = {}
|
|
473
483
|
native_keys = {}
|
|
484
|
+
op_model_tiers = {}
|
|
474
485
|
drafts.each do |draft|
|
|
475
|
-
offering_id = Identity.offering_id(instance_key: instance_key, provider_native_key: draft.provider_native_key)
|
|
476
486
|
raise Errors::ValidationError, 'duplicate provider_native_key' if native_keys.key?(draft.provider_native_key)
|
|
477
|
-
raise Errors::ValidationError, 'duplicate offering_id' if offerings_by_id.key?(offering_id)
|
|
478
487
|
|
|
479
488
|
native_keys[draft.provider_native_key] = true
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
[offerings_by_id.freeze, build_lanes(instance_key, handle, offerings_by_id).freeze]
|
|
483
|
-
end
|
|
489
|
+
draft.operation_evidence.each_value do |evidence|
|
|
490
|
+
next unless evidence.supported?
|
|
484
491
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
offering_id: offering_id, provider_native_key: draft.provider_native_key, instance_key: instance_key,
|
|
488
|
-
model: draft.model, tier: draft.tier, operation_evidence: draft.operation_evidence,
|
|
489
|
-
capability_evidence: draft.capability_evidence, context_evidence: draft.context_evidence,
|
|
490
|
-
max_output_evidence: draft.max_output_evidence,
|
|
491
|
-
embedding_dimensions_evidence: draft.embedding_dimensions_evidence,
|
|
492
|
-
model_revision_evidence: draft.model_revision_evidence, tokenizer_evidence: draft.tokenizer_evidence,
|
|
493
|
-
quota_domains: draft.quota_domains, metadata: draft.metadata, callable_handle: handle,
|
|
494
|
-
publication_source: draft.publication_source,
|
|
495
|
-
weight_inputs: draft.weight_inputs, base_weight: draft.base_weight
|
|
496
|
-
)
|
|
497
|
-
end
|
|
492
|
+
op_model = [evidence.operation, draft.model]
|
|
493
|
+
raise Errors::ValidationError, 'duplicate (operation, model) published under a conflicting tier' if op_model_tiers.key?(op_model) && op_model_tiers[op_model] != draft.tier
|
|
498
494
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
495
|
+
op_model_tiers[op_model] = draft.tier
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
# One lane per distinct type the draft supports.
|
|
499
|
+
draft.operation_evidence.each_value
|
|
500
|
+
.select(&:supported?)
|
|
501
|
+
.group_by { |evidence| Taxonomies.lane_type_for(operation: evidence.operation) }
|
|
502
|
+
.each do |type, evidences|
|
|
503
|
+
representative = evidences.min_by { |evidence| Taxonomies::OPERATIONS.index(evidence.operation) }
|
|
504
|
+
lane_id = Identity.compose_lane_id(
|
|
505
|
+
tier: draft.tier, provider_family: instance_key.provider_family,
|
|
506
|
+
instance_id: instance_key.instance_id, type: type, model: draft.model
|
|
505
507
|
)
|
|
506
508
|
raise Errors::ValidationError, 'duplicate lane_id' if lanes.key?(lane_id)
|
|
507
509
|
|
|
508
|
-
lanes[lane_id] = build_lane_record(instance_key, handle,
|
|
510
|
+
lanes[lane_id] = build_lane_record(instance_key, handle, draft, type, representative.operation)
|
|
509
511
|
end
|
|
510
512
|
end
|
|
511
|
-
lanes
|
|
513
|
+
lanes.freeze
|
|
512
514
|
end
|
|
513
515
|
|
|
514
|
-
def build_lane_record(instance_key, handle,
|
|
516
|
+
def build_lane_record(instance_key, handle, draft, type, operation)
|
|
515
517
|
LaneRecord.new(
|
|
516
|
-
lane_id:
|
|
518
|
+
lane_id: Identity.compose_lane_id(
|
|
519
|
+
tier: draft.tier, provider_family: instance_key.provider_family,
|
|
520
|
+
instance_id: instance_key.instance_id, type: type, model: draft.model
|
|
521
|
+
),
|
|
522
|
+
instance_key: instance_key,
|
|
517
523
|
provider_family: instance_key.provider_family, instance_id: instance_key.instance_id,
|
|
518
|
-
model:
|
|
519
|
-
capability_evidence:
|
|
520
|
-
max_output_evidence:
|
|
521
|
-
embedding_dimensions_evidence:
|
|
522
|
-
model_revision_evidence:
|
|
523
|
-
quota_domain:
|
|
524
|
-
callable_handle: handle, publication_source:
|
|
525
|
-
weight_inputs:
|
|
524
|
+
model: draft.model, tier: draft.tier, operation: operation,
|
|
525
|
+
capability_evidence: draft.capability_evidence, context_evidence: draft.context_evidence,
|
|
526
|
+
max_output_evidence: draft.max_output_evidence,
|
|
527
|
+
embedding_dimensions_evidence: draft.embedding_dimensions_evidence,
|
|
528
|
+
model_revision_evidence: draft.model_revision_evidence, tokenizer_evidence: draft.tokenizer_evidence,
|
|
529
|
+
quota_domain: draft.quota_domains[operation], metadata: draft.metadata,
|
|
530
|
+
callable_handle: handle, publication_source: draft.publication_source,
|
|
531
|
+
weight_inputs: draft.weight_inputs, base_weight: draft.base_weight
|
|
526
532
|
)
|
|
527
533
|
end
|
|
528
534
|
|
|
@@ -11,20 +11,20 @@ module Legion
|
|
|
11
11
|
# A structurally immutable, generation-tagged read model of the registry.
|
|
12
12
|
# Lookups return the frozen record or nil and never synthesize a default.
|
|
13
13
|
# `instances_by_key` contains only activated instances;
|
|
14
|
-
# `publication_status_by_key` also contains initializing claims.
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
14
|
+
# `publication_status_by_key` also contains initializing claims. Lanes
|
|
15
|
+
# are keyed by the 5-tuple lane id and iterate in lexicographic id
|
|
16
|
+
# order (readable iteration). A caller cannot observe a later
|
|
17
|
+
# inventory-record or generation mutation through an older snapshot;
|
|
18
|
+
# the captured CallableHandle lifecycle is the single intentional
|
|
19
|
+
# exception. See phase-1-lex-llm-additive.md section 11.3.
|
|
18
20
|
class Snapshot
|
|
19
21
|
attr_reader :generation
|
|
20
22
|
|
|
21
|
-
def initialize(generation:, instances_by_key:,
|
|
23
|
+
def initialize(generation:, instances_by_key:, lanes_by_id:, publication_status_by_key:)
|
|
22
24
|
@generation = generation
|
|
23
25
|
@instances_by_key = order_instances(instances_by_key).freeze
|
|
24
|
-
@offerings_by_id = offerings_by_id.dup.freeze
|
|
25
26
|
@lanes_by_id = lanes_by_id.dup.freeze
|
|
26
27
|
@publication_status_by_key = order_instances(publication_status_by_key).freeze
|
|
27
|
-
@ordered_offerings = @offerings_by_id.keys.sort.map { |id| @offerings_by_id[id] }.freeze
|
|
28
28
|
@ordered_lanes = @lanes_by_id.keys.sort.map { |id| @lanes_by_id[id] }.freeze
|
|
29
29
|
freeze
|
|
30
30
|
end
|
|
@@ -33,10 +33,6 @@ module Legion
|
|
|
33
33
|
@instances_by_key[instance_key]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def offering(offering_id:)
|
|
37
|
-
@offerings_by_id[offering_id]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
36
|
def lane(lane_id:)
|
|
41
37
|
@lanes_by_id[lane_id]
|
|
42
38
|
end
|
|
@@ -45,10 +41,6 @@ module Legion
|
|
|
45
41
|
@ordered_lanes.select { |lane| lane.instance_key == instance_key }.freeze
|
|
46
42
|
end
|
|
47
43
|
|
|
48
|
-
def offerings_for(instance_key:)
|
|
49
|
-
@ordered_offerings.select { |offering| offering.instance_key == instance_key }.freeze
|
|
50
|
-
end
|
|
51
|
-
|
|
52
44
|
def publication_status(instance_key:)
|
|
53
45
|
@publication_status_by_key[instance_key]
|
|
54
46
|
end
|
|
@@ -59,12 +51,6 @@ module Legion
|
|
|
59
51
|
@ordered_lanes.each(&block)
|
|
60
52
|
end
|
|
61
53
|
|
|
62
|
-
def each_offering(&block)
|
|
63
|
-
return to_enum(:each_offering) unless block
|
|
64
|
-
|
|
65
|
-
@ordered_offerings.each(&block)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
54
|
def each_instance(&block)
|
|
69
55
|
return to_enum(:each_instance) unless block
|
|
70
56
|
|
|
@@ -5,6 +5,7 @@ Kernel.require 'set'
|
|
|
5
5
|
require 'legion/extensions/llm/inventory/weight_schema'
|
|
6
6
|
require 'legion/extensions/llm/settings_cascade'
|
|
7
7
|
require 'legion/extensions/llm/inventory/identity'
|
|
8
|
+
require 'legion/extensions/llm/taxonomies'
|
|
8
9
|
|
|
9
10
|
module Legion
|
|
10
11
|
module Extensions
|
|
@@ -37,9 +38,9 @@ module Legion
|
|
|
37
38
|
inputs = WeightSchema.weight_inputs(
|
|
38
39
|
settings: settings,
|
|
39
40
|
instance_key: instance_key,
|
|
40
|
-
provider_native_key: draft.provider_native_key,
|
|
41
41
|
model: draft.model,
|
|
42
|
-
tier: draft.tier
|
|
42
|
+
tier: draft.tier,
|
|
43
|
+
operation_evidence: draft.operation_evidence
|
|
43
44
|
)
|
|
44
45
|
draft.with(weight_inputs: inputs, base_weight: WeightSchema.base_weight(inputs))
|
|
45
46
|
end.freeze
|
|
@@ -209,10 +210,16 @@ module Legion
|
|
|
209
210
|
provider_family, :instance, instance_key.instance_id.to_s,
|
|
210
211
|
:model, draft.model.to_s
|
|
211
212
|
)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
draft.operation_evidence.each_value do |evidence|
|
|
214
|
+
next unless evidence.supported?
|
|
215
|
+
|
|
216
|
+
lane_id = Identity.compose_lane_id(
|
|
217
|
+
tier: draft.tier, provider_family: instance_key.provider_family,
|
|
218
|
+
instance_id: instance_key.instance_id,
|
|
219
|
+
type: Taxonomies.lane_type_for(operation: evidence.operation), model: draft.model
|
|
220
|
+
)
|
|
221
|
+
keys << canonical_key(provider_family, :offering, lane_id)
|
|
222
|
+
end
|
|
216
223
|
end
|
|
217
224
|
end
|
|
218
225
|
keys
|