ruby_llm_mesh 0.1.0 → 2.2.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.
@@ -5,7 +5,8 @@ module RubyLlmMesh
5
5
  PROVIDER_MAP = {
6
6
  openai: Providers::Openai,
7
7
  anthropic: Providers::Anthropic,
8
- local_node: Providers::LocalNode
8
+ local_node: Providers::LocalNode,
9
+ local_mesh: Providers::LocalNode # alias — multi-peer aware via PeerRegistry
9
10
  }.freeze
10
11
 
11
12
  class << self
@@ -19,16 +20,43 @@ module RubyLlmMesh
19
20
  def reset_circuit_breaker!
20
21
  @circuit_breaker = nil
21
22
  end
23
+
24
+ def semantic_cache
25
+ Cache::SemanticCache.instance
26
+ end
27
+
28
+ def peer_registry
29
+ Mesh::PeerRegistry.instance
30
+ end
31
+
32
+ def health_monitor
33
+ Mesh::HealthMonitor.instance
34
+ end
22
35
  end
23
36
 
24
- def initialize(config: RubyLlmMesh.configuration, circuit_breaker: self.class.circuit_breaker)
37
+ def initialize(config: RubyLlmMesh.configuration, circuit_breaker: self.class.circuit_breaker,
38
+ semantic_cache: nil, budget: nil)
25
39
  @config = config
26
40
  @circuit_breaker = circuit_breaker
41
+ @semantic_cache = semantic_cache
42
+ @budget = budget
27
43
  end
28
44
 
29
45
  def complete(prompt:, providers: nil, fallback: nil, system: nil, model: nil, **options)
30
46
  raise ArgumentError, "prompt is required" if prompt.nil? || prompt.to_s.strip.empty?
31
47
 
48
+ skip_cache = options.delete(:skip_cache)
49
+ cache = resolve_cache
50
+ unless skip_cache
51
+ cached = cache&.lookup(prompt, system: system)
52
+ if cached
53
+ log(:info, "Semantic cache hit")
54
+ return cached
55
+ end
56
+ end
57
+
58
+ maybe_refresh_peer_health!
59
+
32
60
  provider_list = Array(providers || @config.default_providers).map(&:to_sym)
33
61
  raise ArgumentError, "providers list cannot be empty" if provider_list.empty?
34
62
 
@@ -37,37 +65,66 @@ module RubyLlmMesh
37
65
  attempted = 0
38
66
 
39
67
  provider_list.each_with_index do |provider_name, index|
68
+ circuit_key = circuit_key_for(provider_name)
69
+
40
70
  unless PROVIDER_MAP.key?(provider_name)
41
71
  errors[provider_name] = ProviderError.new("Unknown provider: #{provider_name}", provider: provider_name)
72
+ break unless use_fallback
42
73
  next
43
74
  end
44
75
 
45
- unless @circuit_breaker.allow?(provider_name)
76
+ unless @circuit_breaker.allow?(circuit_key)
46
77
  errors[provider_name] = CircuitOpenError.new(
47
78
  "Circuit open for #{provider_name}",
48
79
  provider: provider_name
49
80
  )
50
81
  log(:warn, "Skipping #{provider_name} — circuit open")
82
+ break unless use_fallback
51
83
  next
52
84
  end
53
85
 
54
86
  begin
55
87
  attempted += 1
56
88
  log(:info, "Routing to #{provider_name}")
89
+ budget = resolve_budget
90
+ estimated_tokens = Budget.estimate_tokens(prompt: prompt, system: system, max_tokens: options[:max_tokens])
91
+ estimated_usd = Budget.estimate_usd(tokens: estimated_tokens, model: model, config: @config)
92
+ budget.check!(estimated_tokens: estimated_tokens, estimated_usd: estimated_usd)
93
+
57
94
  provider = PROVIDER_MAP[provider_name].new(@config)
58
- response = provider.complete(prompt: prompt, system: system, model: model, **options)
59
- @circuit_breaker.record_success(provider_name)
60
- return Response.new(
95
+ response = with_retries(provider_name) do
96
+ provider.complete(prompt: prompt, system: system, model: model, **options)
97
+ end
98
+ budget.consume!(usage: response.usage, provider: provider_name, model: response.model || model)
99
+ @circuit_breaker.record_success(circuit_key)
100
+
101
+ result = Response.new(
61
102
  content: response.content,
62
103
  provider: response.provider,
63
104
  model: response.model,
64
105
  usage: response.usage,
65
106
  raw: response.raw,
66
107
  latency_ms: response.latency_ms,
67
- fallback_used: index.positive?
108
+ fallback_used: index.positive?,
109
+ cache_hit: false
68
110
  )
111
+ cache&.store_response(prompt, result, system: system) unless skip_cache
112
+ return result
113
+ rescue BudgetExceededError
114
+ raise
115
+ rescue AuthenticationError => e
116
+ @circuit_breaker.record_failure(circuit_key)
117
+ errors[provider_name] = e
118
+ log(:error, "#{provider_name} authentication failed: #{e.message}")
119
+ break unless use_fallback
120
+ rescue RateLimitError => e
121
+ # Trip circuit immediately so subsequent requests skip this provider
122
+ force_open_circuit!(circuit_key)
123
+ errors[provider_name] = e
124
+ log(:error, "#{provider_name} rate limited: #{e.message}")
125
+ break unless use_fallback
69
126
  rescue ProviderError => e
70
- @circuit_breaker.record_failure(provider_name)
127
+ @circuit_breaker.record_failure(circuit_key)
71
128
  errors[provider_name] = e
72
129
  log(:error, "#{provider_name} failed: #{e.message}")
73
130
  break unless use_fallback
@@ -79,6 +136,74 @@ module RubyLlmMesh
79
136
 
80
137
  private
81
138
 
139
+ def resolve_cache
140
+ return @semantic_cache if @semantic_cache
141
+ return nil unless @config.semantic_cache_enabled
142
+
143
+ Cache::SemanticCache.instance(config: @config)
144
+ end
145
+
146
+ def resolve_budget
147
+ return @budget if @budget
148
+
149
+ Budget.instance(config: @config)
150
+ end
151
+
152
+ def circuit_key_for(provider_name)
153
+ provider_name == :local_mesh ? :local_node : provider_name
154
+ end
155
+
156
+ def maybe_refresh_peer_health!
157
+ return unless @config.peer_discovery_enabled
158
+
159
+ monitor = Mesh::HealthMonitor.instance(config: @config)
160
+ monitor.start!
161
+ # Opportunistic sync check so first request after enable sees fresh state
162
+ monitor.check_all!
163
+ end
164
+
165
+ def force_open_circuit!(circuit_key)
166
+ threshold = @config.circuit_failure_threshold
167
+ threshold.times { @circuit_breaker.record_failure(circuit_key) }
168
+ end
169
+
170
+ def with_retries(provider_name)
171
+ attempts = 1 + [Integer(@config.max_retries || 0), 0].max
172
+ last_error = nil
173
+
174
+ attempts.times do |index|
175
+ return yield
176
+ rescue AuthenticationError, BudgetExceededError
177
+ raise
178
+ rescue RateLimitError, TimeoutError, ProviderError => error
179
+ last_error = error
180
+ remaining = attempts - index - 1
181
+ unless retryable_error?(error) && remaining.positive?
182
+ raise error
183
+ end
184
+
185
+ delay = retry_delay(index)
186
+ log(:warn, "#{provider_name} attempt #{index + 1}/#{attempts} failed (#{error.class}): #{error.message}; retrying in #{delay}s")
187
+ sleep(delay) if delay.positive?
188
+ end
189
+
190
+ raise last_error
191
+ end
192
+
193
+ def retryable_error?(error)
194
+ return false if error.is_a?(AuthenticationError)
195
+ return true if error.is_a?(TimeoutError) || error.is_a?(RateLimitError)
196
+ return false unless error.is_a?(ProviderError)
197
+
198
+ status = error.status
199
+ status.nil? || status >= 500 || status == 429
200
+ end
201
+
202
+ def retry_delay(attempt)
203
+ base = Float(@config.retry_backoff || 0)
204
+ base * (2**attempt)
205
+ end
206
+
82
207
  def log(level, message)
83
208
  logger = @config.logger
84
209
  return unless logger
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module RubyLlmMesh
6
+ # Sovereign mesh orchestrator — native P2P node + cloud failover strategies.
7
+ class SovereignMesh
8
+ STRATEGIES = %i[auto p2p_mesh cloud openai anthropic local_node local_mesh].freeze
9
+
10
+ def initialize(config: RubyLlmMesh.configuration, router: nil)
11
+ @config = config
12
+ @router = router || Router.new(config: config)
13
+ end
14
+
15
+ def boot!(port: @config.mesh_port)
16
+ NativeCore.start_node(port)
17
+ end
18
+
19
+ def shutdown!
20
+ NativeCore.stop_node
21
+ end
22
+
23
+ def alive?
24
+ NativeCore.node_alive?
25
+ end
26
+
27
+ # Execute an intent with a routing strategy.
28
+ #
29
+ # Strategies:
30
+ # - +:auto+ — native mesh when alive (or auto-boot), else cloud ladder
31
+ # - +:p2p_mesh+ — native chimera_core only
32
+ # - +:cloud+ — real HTTP via +fallback_providers+ / +default_providers+
33
+ # - +:openai+ / +:anthropic+ / +:local_node+ / +:local_mesh+ — single-provider cloud/local
34
+ def execute(intent:, strategy: :auto, **options)
35
+ raise ArgumentError, "intent is required" if intent.nil? || intent.to_s.strip.empty?
36
+
37
+ strategy = strategy.to_sym
38
+ unless STRATEGIES.include?(strategy)
39
+ raise ArgumentError, "Unknown strategy: #{strategy.inspect} (expected one of #{STRATEGIES.join(', ')})"
40
+ end
41
+
42
+ started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
43
+ result = case strategy
44
+ when :p2p_mesh
45
+ execute_p2p(intent)
46
+ when :cloud
47
+ execute_cloud(intent, **options)
48
+ when :openai, :anthropic, :local_node, :local_mesh
49
+ execute_cloud(intent, providers: [strategy], **options)
50
+ else # :auto
51
+ execute_auto(intent, **options)
52
+ end
53
+
54
+ latency_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started) * 1000).round
55
+ normalize_result(result, latency_ms: latency_ms, strategy: strategy)
56
+ end
57
+
58
+ private
59
+
60
+ def execute_auto(intent, **options)
61
+ if @config.auto_boot_mesh && !NativeCore.node_alive?
62
+ NativeCore.start_node(@config.mesh_port)
63
+ end
64
+
65
+ if NativeCore.node_alive?
66
+ begin
67
+ return execute_p2p(intent)
68
+ rescue ProviderError
69
+ # fall through to cloud
70
+ end
71
+ end
72
+
73
+ execute_cloud(intent, **options)
74
+ end
75
+
76
+ def execute_p2p(intent)
77
+ unless NativeCore.node_alive?
78
+ booted = NativeCore.start_node(@config.mesh_port)
79
+ unless booted && NativeCore.node_alive?
80
+ raise ProviderError.new(
81
+ "Native mesh node is not alive (compile chimera_core or enable fallback)",
82
+ provider: :p2p_mesh
83
+ )
84
+ end
85
+ end
86
+
87
+ payload = NativeCore.execute_wasm_payload(intent)
88
+ if payload["ok"] == false
89
+ raise ProviderError.new(
90
+ payload["error"] || "native execute failed",
91
+ provider: :p2p_mesh,
92
+ body: payload
93
+ )
94
+ end
95
+
96
+ Response.new(
97
+ content: payload["output"].to_s,
98
+ provider: :p2p_mesh,
99
+ model: payload["engine"] || "chimera_core",
100
+ usage: {},
101
+ raw: payload,
102
+ latency_ms: nil,
103
+ fallback_used: false,
104
+ cache_hit: false
105
+ )
106
+ end
107
+
108
+ def execute_cloud(intent, providers: nil, **options)
109
+ providers ||= @config.fallback_providers
110
+ providers = Array(providers).map(&:to_sym)
111
+ providers = @config.default_providers if providers.empty?
112
+
113
+ @router.complete(
114
+ prompt: intent,
115
+ providers: providers,
116
+ fallback: options.key?(:fallback) ? options[:fallback] : @config.fallback,
117
+ system: options[:system],
118
+ model: options[:model],
119
+ **options.reject { |k, _| %i[system model fallback providers].include?(k) }
120
+ )
121
+ end
122
+
123
+ def normalize_result(response, latency_ms:, strategy:)
124
+ return response if response.is_a?(Response) && response.latency_ms
125
+
126
+ Response.new(
127
+ content: response.content,
128
+ provider: response.provider,
129
+ model: response.model,
130
+ usage: response.usage,
131
+ raw: (response.raw.is_a?(Hash) ? response.raw : { data: response.raw }).merge("strategy" => strategy.to_s),
132
+ latency_ms: response.latency_ms || latency_ms,
133
+ fallback_used: response.fallback_used,
134
+ cache_hit: response.cache_hit
135
+ )
136
+ end
137
+ end
138
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLlmMesh
4
- VERSION = "0.1.0"
4
+ VERSION = "2.2.0"
5
5
  end
data/lib/ruby_llm_mesh.rb CHANGED
@@ -5,14 +5,22 @@ require_relative "ruby_llm_mesh/errors"
5
5
  require_relative "ruby_llm_mesh/configuration"
6
6
  require_relative "ruby_llm_mesh/response"
7
7
  require_relative "ruby_llm_mesh/circuit_breaker"
8
+ require_relative "ruby_llm_mesh/budget"
8
9
  require_relative "ruby_llm_mesh/providers/base"
9
10
  require_relative "ruby_llm_mesh/providers/openai"
10
11
  require_relative "ruby_llm_mesh/providers/anthropic"
11
12
  require_relative "ruby_llm_mesh/providers/local_node"
12
- require_relative "ruby_llm_mesh/router"
13
13
  require_relative "ruby_llm_mesh/rag/chunker"
14
14
  require_relative "ruby_llm_mesh/rag/embeddings"
15
15
  require_relative "ruby_llm_mesh/rag/tools"
16
+ require_relative "ruby_llm_mesh/cache/memory_store"
17
+ require_relative "ruby_llm_mesh/cache/redis_store"
18
+ require_relative "ruby_llm_mesh/cache/semantic_cache"
19
+ require_relative "ruby_llm_mesh/mesh/peer_registry"
20
+ require_relative "ruby_llm_mesh/mesh/health_monitor"
21
+ require_relative "ruby_llm_mesh/native_core"
22
+ require_relative "ruby_llm_mesh/router"
23
+ require_relative "ruby_llm_mesh/sovereign_mesh"
16
24
 
17
25
  # Optional Rails integration — only load railtie when Rails is already present
18
26
  if defined?(Rails::Railtie)
@@ -28,6 +36,23 @@ module RubyLlmMesh
28
36
  def chat(**)
29
37
  complete(**)
30
38
  end
39
+
40
+ # Sovereign mesh entrypoint — native P2P and/or real cloud failover.
41
+ def execute(intent:, strategy: :auto, **options)
42
+ SovereignMesh.new.execute(intent: intent, strategy: strategy, **options)
43
+ end
44
+
45
+ def boot_mesh!(port: configuration.mesh_port)
46
+ NativeCore.start_node(port)
47
+ end
48
+
49
+ def mesh_alive?
50
+ NativeCore.node_alive?
51
+ end
52
+
53
+ def budget_status
54
+ Budget.instance(config: configuration).status
55
+ end
31
56
  end
32
57
  end
33
58
 
@@ -37,6 +62,10 @@ module AiAgentRouter
37
62
  RubyLlmMesh.complete(...)
38
63
  end
39
64
 
65
+ def self.execute(...)
66
+ RubyLlmMesh.execute(...)
67
+ end
68
+
40
69
  def self.configure(&)
41
70
  RubyLlmMesh.configure(&)
42
71
  end
@@ -44,4 +73,16 @@ module AiAgentRouter
44
73
  def self.configuration
45
74
  RubyLlmMesh.configuration
46
75
  end
76
+
77
+ def self.boot_mesh!(...)
78
+ RubyLlmMesh.boot_mesh!(...)
79
+ end
80
+
81
+ def self.mesh_alive?
82
+ RubyLlmMesh.mesh_alive?
83
+ end
84
+
85
+ def self.budget_status
86
+ RubyLlmMesh.budget_status
87
+ end
47
88
  end
@@ -8,11 +8,15 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["theworker02"]
9
9
  spec.email = ["theworker02@users.noreply.github.com"]
10
10
 
11
- spec.summary = "Unified multi-provider AI routing with circuit-breaking and local fallback for Ruby & Rails"
11
+ spec.summary = "Sovereign multi-provider AI mesh with native FFI core, circuit-breaking, and cloud failover for Ruby & Rails"
12
12
  spec.description = <<~DESC
13
- ruby_llm_mesh (AiAgentRouter) is a drop-in Ruby gem that routes AI prompts across
14
- OpenAI, Anthropic, and local node runtimes with automatic circuit-breaking,
15
- fallback ladders, lightweight RAG helpers, and optional ActiveRecord hooks.
13
+ ruby_llm_mesh (AiAgentRouter) is a Ruby gem that routes AI intents across a native
14
+ chimera_core mesh (Rust FFI), OpenAI, Anthropic, and local node runtimes with
15
+ automatic circuit-breaking, fallback ladders, optional semantic caching, peer health
16
+ monitoring, lightweight RAG helpers, and optional ActiveRecord hooks.
17
+
18
+ Gem name uses underscores (ruby_llm_mesh) to match the GitHub repository and
19
+ RubyGems listing at https://rubygems.org/gems/ruby_llm_mesh.
16
20
  DESC
17
21
  spec.homepage = "https://github.com/theworker02/ruby_llm_mesh"
18
22
  spec.license = "MIT"
@@ -29,13 +33,14 @@ Gem::Specification.new do |spec|
29
33
  spec.files = Dir.chdir(__dir__) do
30
34
  `git ls-files -z`.split("\x0").reject do |f|
31
35
  f.start_with?(*%w[test/ spec/ features/ .git .github docs/]) ||
32
- f.end_with?(".gem")
36
+ f.end_with?(".gem") ||
37
+ f.include?("/target/")
33
38
  end
34
39
  end
35
- # Ensure packaging works before the first commit
36
40
  if spec.files.empty?
37
41
  spec.files = Dir[
38
42
  "lib/**/*",
43
+ "ext/**/*",
39
44
  "sig/**/*",
40
45
  "exe/**/*",
41
46
  "assets/**/*",
@@ -43,14 +48,22 @@ Gem::Specification.new do |spec|
43
48
  "README*",
44
49
  "CHANGELOG*",
45
50
  "CODE_OF_CONDUCT*",
46
- "*.gemspec"
47
- ]
51
+ "PRIVACY*",
52
+ "CONTRIBUTING*",
53
+ "*.gemspec",
54
+ "Rakefile"
55
+ ].reject { |f| f.include?("/target/") || f.end_with?(".gem") }
48
56
  end
49
57
 
50
58
  spec.bindir = "exe"
51
59
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
52
60
  spec.require_paths = ["lib"]
53
61
 
62
+ # Optional native compile — documented via `rake compile`; gem works without it.
63
+ # spec.extensions = [] # cargo-based; use rake compile instead of mkmf
64
+
65
+ spec.add_dependency "ffi", "~> 1.17"
66
+
54
67
  spec.add_development_dependency "minitest", "~> 5.25"
55
68
  spec.add_development_dependency "rake", "~> 13.2"
56
69
  spec.add_development_dependency "webmock", "~> 3.24"
@@ -8,6 +8,7 @@ module RubyLlmMesh
8
8
  attr_accessor fallback: bool
9
9
  attr_accessor timeout: Integer
10
10
  attr_accessor max_retries: Integer
11
+ attr_accessor retry_backoff: Float
11
12
  attr_accessor openai_api_key: String?
12
13
  attr_accessor openai_base_url: String
13
14
  attr_accessor openai_model: String
@@ -19,6 +20,12 @@ module RubyLlmMesh
19
20
  attr_accessor circuit_failure_threshold: Integer
20
21
  attr_accessor circuit_reset_timeout: Integer
21
22
  attr_accessor logger: untyped
23
+ attr_accessor mesh_port: Integer
24
+ attr_accessor fallback_providers: Array[Symbol]
25
+ attr_accessor auto_boot_mesh: bool
26
+ attr_accessor semantic_cache_enabled: bool
27
+ attr_accessor peer_discovery_enabled: bool
28
+ attr_accessor peer_urls: Array[String]
22
29
  end
23
30
 
24
31
  def self.configuration: () -> Configuration
@@ -31,6 +38,9 @@ module RubyLlmMesh
31
38
  **untyped
32
39
  ) -> Response
33
40
  def self.chat: (**untyped) -> Response
41
+ def self.execute: (intent: String, ?strategy: Symbol, **untyped) -> Response
42
+ def self.boot_mesh!: (?port: Integer) -> bool
43
+ def self.mesh_alive?: () -> bool
34
44
 
35
45
  class Response
36
46
  attr_reader content: String
@@ -40,6 +50,7 @@ module RubyLlmMesh
40
50
  attr_reader raw: untyped
41
51
  attr_reader latency_ms: Integer?
42
52
  attr_reader fallback_used: bool
53
+ attr_reader cache_hit: bool
43
54
 
44
55
  def initialize: (
45
56
  content: String,
@@ -48,7 +59,8 @@ module RubyLlmMesh
48
59
  ?usage: Hash[untyped, untyped],
49
60
  ?raw: untyped,
50
61
  ?latency_ms: Integer?,
51
- ?fallback_used: bool
62
+ ?fallback_used: bool,
63
+ ?cache_hit: bool
52
64
  ) -> void
53
65
  def text: () -> String
54
66
  def to_s: () -> String
@@ -66,6 +78,20 @@ module RubyLlmMesh
66
78
  ) -> Response
67
79
  end
68
80
 
81
+ class SovereignMesh
82
+ def execute: (intent: String, ?strategy: Symbol, **untyped) -> Response
83
+ def boot!: (?port: Integer) -> bool
84
+ def alive?: () -> bool
85
+ end
86
+
87
+ module NativeCore
88
+ def self.available?: () -> bool
89
+ def self.start_node: (?Integer) -> bool
90
+ def self.stop_node: () -> bool
91
+ def self.node_alive?: () -> bool
92
+ def self.execute_wasm_payload: (String) -> Hash[String, untyped]
93
+ end
94
+
69
95
  class CircuitBreaker
70
96
  def allow?: (Symbol) -> bool
71
97
  def record_success: (Symbol) -> void
@@ -77,6 +103,9 @@ end
77
103
 
78
104
  module AiAgentRouter
79
105
  def self.complete: (**untyped) -> RubyLlmMesh::Response
106
+ def self.execute: (**untyped) -> RubyLlmMesh::Response
80
107
  def self.configure: () { (RubyLlmMesh::Configuration) -> void } -> void
81
108
  def self.configuration: () -> RubyLlmMesh::Configuration
109
+ def self.boot_mesh!: (**untyped) -> bool
110
+ def self.mesh_alive?: () -> bool
82
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm_mesh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - theworker02
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ffi
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.17'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.17'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: minitest
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -52,9 +66,13 @@ dependencies:
52
66
  - !ruby/object:Gem::Version
53
67
  version: '3.24'
54
68
  description: |
55
- ruby_llm_mesh (AiAgentRouter) is a drop-in Ruby gem that routes AI prompts across
56
- OpenAI, Anthropic, and local node runtimes with automatic circuit-breaking,
57
- fallback ladders, lightweight RAG helpers, and optional ActiveRecord hooks.
69
+ ruby_llm_mesh (AiAgentRouter) is a Ruby gem that routes AI intents across a native
70
+ chimera_core mesh (Rust FFI), OpenAI, Anthropic, and local node runtimes with
71
+ automatic circuit-breaking, fallback ladders, optional semantic caching, peer health
72
+ monitoring, lightweight RAG helpers, and optional ActiveRecord hooks.
73
+
74
+ Gem name uses underscores (ruby_llm_mesh) to match the GitHub repository and
75
+ RubyGems listing at https://rubygems.org/gems/ruby_llm_mesh.
58
76
  email:
59
77
  - theworker02@users.noreply.github.com
60
78
  executables: []
@@ -66,14 +84,24 @@ files:
66
84
  - CONTRIBUTING.md
67
85
  - Gemfile
68
86
  - LICENSE.txt
87
+ - PRIVACY.md
69
88
  - README.md
70
89
  - Rakefile
71
90
  - assets/logo.png
91
+ - ext/chimera_core/Cargo.toml
92
+ - ext/chimera_core/src/lib.rs
72
93
  - lib/ruby_llm_mesh.rb
73
94
  - lib/ruby_llm_mesh/active_record/acts_as_ai_agent.rb
95
+ - lib/ruby_llm_mesh/budget.rb
96
+ - lib/ruby_llm_mesh/cache/memory_store.rb
97
+ - lib/ruby_llm_mesh/cache/redis_store.rb
98
+ - lib/ruby_llm_mesh/cache/semantic_cache.rb
74
99
  - lib/ruby_llm_mesh/circuit_breaker.rb
75
100
  - lib/ruby_llm_mesh/configuration.rb
76
101
  - lib/ruby_llm_mesh/errors.rb
102
+ - lib/ruby_llm_mesh/mesh/health_monitor.rb
103
+ - lib/ruby_llm_mesh/mesh/peer_registry.rb
104
+ - lib/ruby_llm_mesh/native_core.rb
77
105
  - lib/ruby_llm_mesh/providers/anthropic.rb
78
106
  - lib/ruby_llm_mesh/providers/base.rb
79
107
  - lib/ruby_llm_mesh/providers/local_node.rb
@@ -84,6 +112,7 @@ files:
84
112
  - lib/ruby_llm_mesh/railtie.rb
85
113
  - lib/ruby_llm_mesh/response.rb
86
114
  - lib/ruby_llm_mesh/router.rb
115
+ - lib/ruby_llm_mesh/sovereign_mesh.rb
87
116
  - lib/ruby_llm_mesh/version.rb
88
117
  - ruby_llm_mesh.gemspec
89
118
  - sig/ruby_llm_mesh.rbs
@@ -114,6 +143,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
143
  requirements: []
115
144
  rubygems_version: 4.0.16
116
145
  specification_version: 4
117
- summary: Unified multi-provider AI routing with circuit-breaking and local fallback
118
- for Ruby & Rails
146
+ summary: Sovereign multi-provider AI mesh with native FFI core, circuit-breaking,
147
+ and cloud failover for Ruby & Rails
119
148
  test_files: []