lex-llm 0.6.16 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/lex-llm.gemspec +1 -1
  4. data/lib/legion/extensions/llm/auto_registration.rb +3 -0
  5. data/lib/legion/extensions/llm/canonical/message.rb +5 -1
  6. data/lib/legion/extensions/llm/fleet/protocol.rb +12 -0
  7. data/lib/legion/extensions/llm/fleet/provider_responder.rb +40 -5
  8. data/lib/legion/extensions/llm/fleet/token_validator.rb +15 -0
  9. data/lib/legion/extensions/llm/fleet/worker_execution.rb +166 -2
  10. data/lib/legion/extensions/llm/inventory/callable_handle.rb +144 -0
  11. data/lib/legion/extensions/llm/inventory/errors.rb +34 -0
  12. data/lib/legion/extensions/llm/inventory/evidence.rb +134 -0
  13. data/lib/legion/extensions/llm/inventory/identity.rb +141 -0
  14. data/lib/legion/extensions/llm/inventory/immutable_value.rb +96 -0
  15. data/lib/legion/extensions/llm/inventory/probe_coordinator.rb +117 -0
  16. data/lib/legion/extensions/llm/inventory/probe_token.rb +146 -0
  17. data/lib/legion/extensions/llm/inventory/publisher.rb +116 -0
  18. data/lib/legion/extensions/llm/inventory/records.rb +599 -0
  19. data/lib/legion/extensions/llm/inventory/registry.rb +636 -0
  20. data/lib/legion/extensions/llm/inventory/scoped_refresher.rb +206 -0
  21. data/lib/legion/extensions/llm/inventory/snapshot.rb +91 -0
  22. data/lib/legion/extensions/llm/provider.rb +55 -29
  23. data/lib/legion/extensions/llm/routing/lane_key.rb +4 -0
  24. data/lib/legion/extensions/llm/routing/model_offering.rb +3 -0
  25. data/lib/legion/extensions/llm/routing/offering_registry.rb +2 -0
  26. data/lib/legion/extensions/llm/routing/provider_outcome.rb +54 -0
  27. data/lib/legion/extensions/llm/routing/records.rb +288 -0
  28. data/lib/legion/extensions/llm/settings_cascade.rb +120 -0
  29. data/lib/legion/extensions/llm/taxonomies.rb +90 -0
  30. data/lib/legion/extensions/llm/transport/messages/fleet_error.rb +3 -1
  31. data/lib/legion/extensions/llm/transport/messages/fleet_response.rb +3 -1
  32. data/lib/legion/extensions/llm/version.rb +1 -1
  33. data/lib/legion/extensions/llm.rb +18 -0
  34. data/spec/legion/extensions/llm/canonical/message_spec.rb +24 -0
  35. data/spec/legion/extensions/llm/conformance/fixtures/canonical_params_mapping_request.json +1 -0
  36. data/spec/legion/extensions/llm/conformance/fixtures/canonical_simple_text_request.json +1 -0
  37. data/spec/legion/extensions/llm/conformance/fixtures/canonical_system_prompt_request.json +1 -0
  38. data/spec/legion/extensions/llm/conformance/fixtures/canonical_thinking_request.json +1 -0
  39. data/spec/legion/extensions/llm/conformance/fixtures/canonical_tool_results_continuation_request.json +1 -0
  40. data/spec/legion/extensions/llm/conformance/fixtures/canonical_tools_request.json +1 -0
  41. data/spec/legion/extensions/llm/conformance/fixtures/ssot_identity_vectors.json +84 -0
  42. data/spec/legion/extensions/llm/conformance/ssot_provider_conformance_spec.rb +13 -0
  43. data/spec/legion/extensions/llm/conformance/ssot_provider_examples.rb +196 -0
  44. data/spec/legion/extensions/llm/fleet/exact_offering_spec.rb +179 -0
  45. data/spec/legion/extensions/llm/fleet/provider_responder_spec.rb +26 -0
  46. data/spec/legion/extensions/llm/fleet_messages_spec.rb +14 -0
  47. data/spec/legion/extensions/llm/inventory/boot_spec.rb +80 -0
  48. data/spec/legion/extensions/llm/inventory/callable_handle_spec.rb +127 -0
  49. data/spec/legion/extensions/llm/inventory/evidence_spec.rb +138 -0
  50. data/spec/legion/extensions/llm/inventory/identity_spec.rb +280 -0
  51. data/spec/legion/extensions/llm/inventory/immutable_value_spec.rb +132 -0
  52. data/spec/legion/extensions/llm/inventory/probe_coordinator_spec.rb +107 -0
  53. data/spec/legion/extensions/llm/inventory/probe_token_spec.rb +107 -0
  54. data/spec/legion/extensions/llm/inventory/publisher_spec.rb +144 -0
  55. data/spec/legion/extensions/llm/inventory/records_spec.rb +300 -0
  56. data/spec/legion/extensions/llm/inventory/registry_activation_spec.rb +140 -0
  57. data/spec/legion/extensions/llm/inventory/registry_availability_spec.rb +152 -0
  58. data/spec/legion/extensions/llm/inventory/registry_callable_spec.rb +63 -0
  59. data/spec/legion/extensions/llm/inventory/registry_replacement_spec.rb +69 -0
  60. data/spec/legion/extensions/llm/inventory/scoped_refresher_spec.rb +128 -0
  61. data/spec/legion/extensions/llm/inventory/snapshot_spec.rb +109 -0
  62. data/spec/legion/extensions/llm/provider_contract_spec.rb +20 -0
  63. data/spec/legion/extensions/llm/provider_spec.rb +83 -0
  64. data/spec/legion/extensions/llm/routing/provider_outcome_spec.rb +73 -0
  65. data/spec/legion/extensions/llm/routing/records_spec.rb +173 -0
  66. data/spec/legion/extensions/llm/settings_cascade_spec.rb +208 -0
  67. data/spec/legion/extensions/llm/taxonomies_spec.rb +51 -0
  68. data/spec/support/fake_llm_provider.rb +11 -0
  69. data/spec/support/fake_ssot_harness.rb +137 -0
  70. data/spec/support/ssot_registry_helpers.rb +75 -0
  71. metadata +40 -3
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/logging'
4
+ require 'legion/extensions/llm/inventory/errors'
5
+ require 'legion/extensions/llm/inventory/identity'
6
+ require 'legion/extensions/llm/inventory/registry'
7
+
8
+ module Legion
9
+ module Extensions
10
+ module Llm
11
+ module Inventory
12
+ # Provider-facing direct wrapper over the local Registry. It constructs
13
+ # and validates the exact InstanceKey from its fixed provider family and
14
+ # delegates to the registry with the exact kwargs. It does no retries,
15
+ # selection, scheduling, defaulting, provider discovery, or exception
16
+ # swallowing beyond the explicitly injected, best-effort post-commit
17
+ # old-coordinator projection. See phase-1-lex-llm-additive.md section 13.1.
18
+ class Publisher
19
+ include Legion::Logging::Helper
20
+
21
+ def initialize(provider_family:, registry: Registry, compatibility_adapter: nil)
22
+ @provider_family = provider_family
23
+ @registry = registry
24
+ @compatibility_adapter = compatibility_adapter
25
+ end
26
+
27
+ # Every instance operation takes `instance_id:` — the operator's
28
+ # CONFIG NAME (the identity the router keys by) — and an optional
29
+ # `physical_id:` carrying the physical/derived id (host:port/ak) for
30
+ # dedup and diagnostics only. See Identity::InstanceKey.
31
+ def claim_instance(instance_id:, callable:, probe_request_handle:, physical_id: nil)
32
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
33
+ token = @registry.claim_instance(instance_key: key, callable: callable, probe_request_handle: probe_request_handle)
34
+ sync_compatibility(key, :claimed)
35
+ token
36
+ end
37
+
38
+ def readiness_probe_started(instance_id:, publisher_token:, physical_id: nil)
39
+ @registry.readiness_probe_started(
40
+ instance_key: instance_key(instance_id: instance_id, physical_id: physical_id), publisher_token: publisher_token
41
+ )
42
+ end
43
+
44
+ def activate_instance_snapshot(instance_id:, publisher_token:, offerings:, sequence:, probe_token:, physical_id: nil) # rubocop:disable Metrics/ParameterLists
45
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
46
+ result = @registry.activate_instance_snapshot(
47
+ publisher_token: publisher_token, instance_key: key, offerings: offerings,
48
+ sequence: sequence, probe_token: probe_token
49
+ )
50
+ sync_applied(key, result)
51
+ end
52
+
53
+ def replace_instance_snapshot(instance_id:, publisher_token:, offerings:, sequence:, physical_id: nil)
54
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
55
+ result = @registry.replace_instance_snapshot(
56
+ publisher_token: publisher_token, instance_key: key, offerings: offerings, sequence: sequence
57
+ )
58
+ sync_applied(key, result)
59
+ end
60
+
61
+ def readiness_succeeded(instance_id:, probe_token:, physical_id: nil)
62
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
63
+ sync_applied(key, @registry.readiness_succeeded(instance_key: key, probe_token: probe_token))
64
+ end
65
+
66
+ def readiness_failed(instance_id:, probe_token:, reason:, physical_id: nil)
67
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
68
+ sync_applied(key, @registry.readiness_failed(instance_key: key, probe_token: probe_token, reason: reason))
69
+ end
70
+
71
+ def remove_instance(instance_id:, publisher_token:, physical_id: nil)
72
+ key = instance_key(instance_id: instance_id, physical_id: physical_id)
73
+ sync_applied(key, @registry.remove_instance(instance_key: key, publisher_token: publisher_token))
74
+ end
75
+
76
+ def snapshot
77
+ @registry.snapshot
78
+ end
79
+
80
+ private
81
+
82
+ def instance_key(instance_id:, physical_id: nil)
83
+ Identity::InstanceKey.new(provider_family: @provider_family, instance_id: instance_id, physical_id: physical_id)
84
+ 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
+ end
113
+ end
114
+ end
115
+ end
116
+ end