lex-llm-ledger 0.1.10 → 0.1.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a595a76ee91def4ec66dc3ec9b1daa0c40f872704a73659981b8eecebf5bd48e
4
- data.tar.gz: 2f1c5ff38e83093df3c88e39a9a6c376f13f9af97fa000126a2d24c51324e3f3
3
+ metadata.gz: c2578f6543e89f6517dd169b738f11ef3c0a8e3793ff53db790e57856be4c3be
4
+ data.tar.gz: 066ad9113ab48db944c88cc9d6eb9bf182ed54e236e2d4da6f3a0c67bd0cb6af
5
5
  SHA512:
6
- metadata.gz: dd1e3ae7439152285ee97d681d72bf98131504ab81e0107bd1a4c3f254c6dc2b4738a8562725bfc8e16b2a3c5d2fe44eb94e8df418b422f9fb48d1f746a8d026
7
- data.tar.gz: aebc36c406ece5b8c4c51e315eccd771dcca1d70589e776c2a64d5e24d7dd4c59ada66139760b5d8874fa6cbbb6ace87cb846cc8a22092daee77afab0272d6d9
6
+ metadata.gz: 66a82c200a5065aa1940f46a88d1ec362d6e33b2d0ad0de03f24e8676deaa50bd05feef840cd56ca3b111c5ddec4a8008cf728ac137471e946bdbbea046cc27e
7
+ data.tar.gz: a11134e1bd78a4bcca41494e1fc1b119c56be21525ab180c92332cce0ea4f457f51b5c4ac092b40f6f88a63f058dd3857b72598daa51c9cc14abb31daf3c2f32
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.12] - 2026-04-28
4
+
5
+ ### Added
6
+ - Persist provider-neutral `llm.registry` availability event envelopes for offering, worker, lane, model, runtime, capacity, and health diagnostics
7
+ - Add ledger-owned passive `llm.registry` transport exchange, durable registry availability queue, and subscription actor
8
+
9
+ ## [0.1.11] - 2026-04-28
10
+
11
+ ### Fixed
12
+ - Replace the retired `legion-llm` runtime dependency with `lex-llm`
13
+ - Define ledger-owned passive `llm.metering` and `llm.audit` exchange classes for transport bindings
14
+
3
15
  ## [0.1.10] - 2026-04-27
4
16
 
5
17
  ### Fixed
data/Gemfile CHANGED
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  source 'https://rubygems.org'
4
+
5
+ group :test do
6
+ llm_base_path = ENV.fetch('LEX_LLM_PATH', File.expand_path('../lex-llm', __dir__))
7
+ gem 'lex-llm', path: llm_base_path if File.directory?(llm_base_path)
8
+ end
9
+
4
10
  gemspec
5
11
 
6
12
  gem 'rubocop-legion', '~> 0.1', require: false
@@ -30,10 +30,10 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  spec.add_dependency 'legion-data', '>= 1.6'
32
32
  spec.add_dependency 'legion-json', '>= 1.2'
33
- spec.add_dependency 'legion-llm', '>= 0.6'
34
33
  spec.add_dependency 'legion-logging', '>= 1.3'
35
34
  spec.add_dependency 'legion-settings', '>= 1.3'
36
35
  spec.add_dependency 'legion-transport', '>= 1.4'
36
+ spec.add_dependency 'lex-llm', '>= 0.1.5'
37
37
 
38
38
  spec.add_development_dependency 'rspec'
39
39
  spec.add_development_dependency 'rubocop'
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/subscription'
4
+ require_relative '../helpers/subscription_message'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Llm
9
+ module Ledger
10
+ module Actor
11
+ class RegistryAvailabilityWriter < Legion::Extensions::Actors::Subscription
12
+ def runner_class = Legion::Extensions::Llm::Ledger::Runners::RegistryAvailability
13
+
14
+ def runner_function
15
+ 'write_registry_availability_record'
16
+ end
17
+
18
+ def use_runner?
19
+ false
20
+ end
21
+
22
+ def process_message(message, metadata, delivery_info)
23
+ Helpers::SubscriptionMessage.decode_payload(message, metadata, delivery_info)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do # rubocop:disable Metrics/BlockLength
4
+ change do
5
+ create_table(:registry_availability_records) do
6
+ primary_key :id
7
+
8
+ String :event_id, null: false, unique: true
9
+ String :message_id
10
+ String :correlation_id
11
+ String :routing_key
12
+ String :event_type, null: false
13
+ String :occurred_at, null: false
14
+ String :offering_id
15
+ String :provider_family
16
+ String :provider_instance
17
+ String :instance_id
18
+ String :model_family
19
+ String :model_id
20
+ String :canonical_model
21
+ String :provider_model
22
+ String :usage_type
23
+ String :transport
24
+ String :lane_key
25
+ String :worker_id
26
+ String :node_id
27
+ String :offering_json, null: false, text: true
28
+ String :runtime_json, null: false, text: true
29
+ String :capacity_json, null: false, text: true
30
+ String :health_json, null: false, text: true
31
+ String :lane_json, null: false, text: true
32
+ String :metadata_json, null: false, text: true
33
+ DateTime :inserted_at, null: false, default: Sequel::CURRENT_TIMESTAMP
34
+
35
+ index [:event_type]
36
+ index [:occurred_at]
37
+ index [:offering_id]
38
+ index [:provider_family]
39
+ index [:provider_instance]
40
+ index %i[provider_family model_id]
41
+ index [:lane_key]
42
+ index [:worker_id]
43
+ index [:node_id]
44
+ index [:inserted_at]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Llm
6
+ module Ledger
7
+ module Runners
8
+ module RegistryAvailability
9
+ extend self
10
+
11
+ def write_registry_availability_record(payload = nil, metadata = {}, **message)
12
+ payload, metadata = normalize_runner_args(payload, metadata, message)
13
+ props = metadata[:properties] || {}
14
+
15
+ body = symbolize(payload)
16
+ record = build_registry_availability_record(body, props)
17
+ ::Legion::Data::DB[:registry_availability_records].insert(record)
18
+ { result: :ok }
19
+ rescue Sequel::UniqueConstraintViolation => _e
20
+ { result: :duplicate }
21
+ rescue StandardError => e
22
+ Legion::Logging.error("[lex-llm-ledger] write_registry_availability_record failed: #{e.message}") # rubocop:disable Legion/HelperMigration/DirectLogging
23
+ { result: :error, error: e.message }
24
+ end
25
+
26
+ private
27
+
28
+ def normalize_runner_args(payload, metadata, message)
29
+ Helpers::SubscriptionMessage.runner_args(payload, metadata, message)
30
+ end
31
+
32
+ def build_registry_availability_record(body, props)
33
+ offering = body[:offering] || {}
34
+ runtime = body[:runtime] || {}
35
+ lane = body[:lane]
36
+
37
+ {
38
+ event_id: body[:event_id],
39
+ message_id: props[:message_id],
40
+ correlation_id: props[:correlation_id],
41
+ routing_key: props[:routing_key],
42
+ event_type: body[:event_type].to_s,
43
+ occurred_at: body[:occurred_at],
44
+ offering_id: offering[:offering_id],
45
+ provider_family: offering[:provider_family]&.to_s,
46
+ provider_instance: offering[:provider_instance]&.to_s,
47
+ instance_id: offering[:instance_id]&.to_s,
48
+ model_family: offering[:model_family]&.to_s,
49
+ model_id: offering[:model],
50
+ canonical_model: offering[:canonical_model_alias],
51
+ provider_model: offering[:provider_model],
52
+ usage_type: offering[:usage_type]&.to_s,
53
+ transport: offering[:transport]&.to_s,
54
+ lane_key: lane_key(lane),
55
+ worker_id: runtime[:worker_id] || runtime[:worker],
56
+ node_id: runtime[:node_id] || runtime[:host_id],
57
+ offering_json: json_dump(offering),
58
+ runtime_json: json_dump(runtime),
59
+ capacity_json: json_dump(body[:capacity] || {}),
60
+ health_json: json_dump(body[:health] || {}),
61
+ lane_json: json_dump(lane || {}),
62
+ metadata_json: json_dump(body[:metadata] || {}),
63
+ inserted_at: Time.now.utc
64
+ }
65
+ end
66
+
67
+ def lane_key(lane)
68
+ if lane.is_a?(String)
69
+ lane
70
+ elsif lane.is_a?(Hash)
71
+ lane[:key] || lane[:lane_key]
72
+ end
73
+ end
74
+
75
+ def json_dump(value)
76
+ Legion::JSON.dump(json_safe(value)) # rubocop:disable Legion/HelperMigration/DirectJson
77
+ end
78
+
79
+ def json_safe(value)
80
+ case value
81
+ when Hash
82
+ value.to_h { |key, nested| [key.to_s, json_safe(nested)] }
83
+ when Array
84
+ value.map { |nested| json_safe(nested) }
85
+ when Symbol
86
+ value.to_s
87
+ else
88
+ value
89
+ end
90
+ end
91
+
92
+ def symbolize(value)
93
+ case value
94
+ when Hash
95
+ value.to_h { |key, nested| [key.to_sym, symbolize(nested)] }
96
+ when Array
97
+ value.map { |nested| symbolize(nested) }
98
+ else
99
+ value
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Llm
6
+ module Ledger
7
+ module Transport
8
+ module Exchanges
9
+ class Audit < ::Legion::Transport::Exchange
10
+ def exchange_name
11
+ 'llm.audit'
12
+ end
13
+
14
+ def default_type
15
+ 'topic'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Llm
6
+ module Ledger
7
+ module Transport
8
+ module Exchanges
9
+ class Metering < ::Legion::Transport::Exchange
10
+ def exchange_name
11
+ 'llm.metering'
12
+ end
13
+
14
+ def default_type
15
+ 'topic'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Llm
6
+ module Ledger
7
+ module Transport
8
+ module Exchanges
9
+ class Registry < ::Legion::Transport::Exchange
10
+ def exchange_name
11
+ 'llm.registry'
12
+ end
13
+
14
+ def default_type
15
+ 'topic'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Llm
6
+ module Ledger
7
+ module Transport
8
+ module Queues
9
+ class RegistryAvailability < Legion::Transport::Queue
10
+ def queue_name
11
+ 'llm.registry.availability'
12
+ end
13
+
14
+ def queue_options
15
+ { durable: true }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/transport'
4
- require 'legion/llm/transport/exchanges/metering'
5
- require 'legion/llm/transport/exchanges/audit'
4
+ require_relative 'exchanges/metering'
5
+ require_relative 'exchanges/audit'
6
+ require_relative 'exchanges/registry'
6
7
 
7
8
  module Legion
8
9
  module Extensions
@@ -14,19 +15,24 @@ module Legion
14
15
  def self.additional_e_to_q
15
16
  [
16
17
  {
17
- from: Legion::LLM::Transport::Exchanges::Metering,
18
+ from: Legion::Extensions::Llm::Ledger::Transport::Exchanges::Metering,
18
19
  to: Legion::Extensions::Llm::Ledger::Transport::Queues::MeteringWrite,
19
20
  routing_key: 'metering.#'
20
21
  },
21
22
  {
22
- from: Legion::LLM::Transport::Exchanges::Audit,
23
+ from: Legion::Extensions::Llm::Ledger::Transport::Exchanges::Audit,
23
24
  to: Legion::Extensions::Llm::Ledger::Transport::Queues::AuditPrompts,
24
25
  routing_key: 'audit.prompt.#'
25
26
  },
26
27
  {
27
- from: Legion::LLM::Transport::Exchanges::Audit,
28
+ from: Legion::Extensions::Llm::Ledger::Transport::Exchanges::Audit,
28
29
  to: Legion::Extensions::Llm::Ledger::Transport::Queues::AuditTools,
29
30
  routing_key: 'audit.tool.#'
31
+ },
32
+ {
33
+ from: Legion::Extensions::Llm::Ledger::Transport::Exchanges::Registry,
34
+ to: Legion::Extensions::Llm::Ledger::Transport::Queues::RegistryAvailability,
35
+ routing_key: '#'
30
36
  }
31
37
  ]
32
38
  end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Ledger
7
- VERSION = '0.1.10'
7
+ VERSION = '0.1.12'
8
8
  end
9
9
  end
10
10
  end
@@ -10,21 +10,21 @@ require_relative 'ledger/runners/prompts'
10
10
  require_relative 'ledger/runners/tools'
11
11
  require_relative 'ledger/runners/usage_reporter'
12
12
  require_relative 'ledger/runners/provider_stats'
13
+ require_relative 'ledger/runners/registry_availability'
13
14
 
14
15
  if Legion::Extensions.const_defined?(:Core, false)
15
- begin
16
- require 'legion/llm/transport/exchanges/metering'
17
- require 'legion/llm/transport/exchanges/audit'
18
- rescue LoadError => _e
19
- nil
20
- end
16
+ require_relative 'ledger/transport/exchanges/metering'
17
+ require_relative 'ledger/transport/exchanges/audit'
18
+ require_relative 'ledger/transport/exchanges/registry'
21
19
  require_relative 'ledger/transport/queues/metering_write'
22
20
  require_relative 'ledger/transport/queues/audit_prompts'
23
21
  require_relative 'ledger/transport/queues/audit_tools'
22
+ require_relative 'ledger/transport/queues/registry_availability'
24
23
  require_relative 'ledger/transport/transport'
25
24
  require_relative 'ledger/actors/metering_writer'
26
25
  require_relative 'ledger/actors/prompt_writer'
27
26
  require_relative 'ledger/actors/tool_writer'
27
+ require_relative 'ledger/actors/registry_availability_writer'
28
28
  require_relative 'ledger/actors/spool_flush'
29
29
  end
30
30
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm-ledger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -38,21 +38,21 @@ dependencies:
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.2'
40
40
  - !ruby/object:Gem::Dependency
41
- name: legion-llm
41
+ name: legion-logging
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '0.6'
46
+ version: '1.3'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '0.6'
53
+ version: '1.3'
54
54
  - !ruby/object:Gem::Dependency
55
- name: legion-logging
55
+ name: legion-settings
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="
@@ -66,33 +66,33 @@ dependencies:
66
66
  - !ruby/object:Gem::Version
67
67
  version: '1.3'
68
68
  - !ruby/object:Gem::Dependency
69
- name: legion-settings
69
+ name: legion-transport
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '1.3'
74
+ version: '1.4'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '1.3'
81
+ version: '1.4'
82
82
  - !ruby/object:Gem::Dependency
83
- name: legion-transport
83
+ name: lex-llm
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '1.4'
88
+ version: 0.1.5
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: '1.4'
95
+ version: 0.1.5
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: rspec
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -193,6 +193,7 @@ files:
193
193
  - lib/legion/extensions/llm/ledger.rb
194
194
  - lib/legion/extensions/llm/ledger/actors/metering_writer.rb
195
195
  - lib/legion/extensions/llm/ledger/actors/prompt_writer.rb
196
+ - lib/legion/extensions/llm/ledger/actors/registry_availability_writer.rb
196
197
  - lib/legion/extensions/llm/ledger/actors/spool_flush.rb
197
198
  - lib/legion/extensions/llm/ledger/actors/tool_writer.rb
198
199
  - lib/legion/extensions/llm/ledger/helpers/decryption.rb
@@ -202,14 +203,20 @@ files:
202
203
  - lib/legion/extensions/llm/ledger/migrations/001_create_metering_records.rb
203
204
  - lib/legion/extensions/llm/ledger/migrations/002_create_prompt_records.rb
204
205
  - lib/legion/extensions/llm/ledger/migrations/003_create_tool_records.rb
206
+ - lib/legion/extensions/llm/ledger/migrations/004_create_registry_availability_records.rb
205
207
  - lib/legion/extensions/llm/ledger/runners/metering.rb
206
208
  - lib/legion/extensions/llm/ledger/runners/prompts.rb
207
209
  - lib/legion/extensions/llm/ledger/runners/provider_stats.rb
210
+ - lib/legion/extensions/llm/ledger/runners/registry_availability.rb
208
211
  - lib/legion/extensions/llm/ledger/runners/tools.rb
209
212
  - lib/legion/extensions/llm/ledger/runners/usage_reporter.rb
213
+ - lib/legion/extensions/llm/ledger/transport/exchanges/audit.rb
214
+ - lib/legion/extensions/llm/ledger/transport/exchanges/metering.rb
215
+ - lib/legion/extensions/llm/ledger/transport/exchanges/registry.rb
210
216
  - lib/legion/extensions/llm/ledger/transport/queues/audit_prompts.rb
211
217
  - lib/legion/extensions/llm/ledger/transport/queues/audit_tools.rb
212
218
  - lib/legion/extensions/llm/ledger/transport/queues/metering_write.rb
219
+ - lib/legion/extensions/llm/ledger/transport/queues/registry_availability.rb
213
220
  - lib/legion/extensions/llm/ledger/transport/transport.rb
214
221
  - lib/legion/extensions/llm/ledger/version.rb
215
222
  - lib/lex-llm-ledger.rb