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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/CODE_OF_CONDUCT.md +77 -3
- data/CONTRIBUTING.md +7 -1
- data/PRIVACY.md +56 -0
- data/README.md +104 -79
- data/Rakefile +28 -0
- data/ext/chimera_core/Cargo.toml +14 -0
- data/ext/chimera_core/src/lib.rs +194 -0
- data/lib/ruby_llm_mesh/budget.rb +150 -0
- data/lib/ruby_llm_mesh/cache/memory_store.rb +47 -0
- data/lib/ruby_llm_mesh/cache/redis_store.rb +110 -0
- data/lib/ruby_llm_mesh/cache/semantic_cache.rb +126 -0
- data/lib/ruby_llm_mesh/circuit_breaker.rb +11 -1
- data/lib/ruby_llm_mesh/configuration.rb +57 -1
- data/lib/ruby_llm_mesh/errors.rb +11 -0
- data/lib/ruby_llm_mesh/mesh/health_monitor.rb +104 -0
- data/lib/ruby_llm_mesh/mesh/peer_registry.rb +112 -0
- data/lib/ruby_llm_mesh/native_core.rb +199 -0
- data/lib/ruby_llm_mesh/providers/base.rb +5 -1
- data/lib/ruby_llm_mesh/providers/local_node.rb +37 -5
- data/lib/ruby_llm_mesh/response.rb +6 -3
- data/lib/ruby_llm_mesh/router.rb +133 -8
- data/lib/ruby_llm_mesh/sovereign_mesh.rb +138 -0
- data/lib/ruby_llm_mesh/version.rb +1 -1
- data/lib/ruby_llm_mesh.rb +42 -1
- data/ruby_llm_mesh.gemspec +21 -8
- data/sig/ruby_llm_mesh.rbs +30 -1
- metadata +35 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31ce7f20e5d73fed9453fd89263d03eda29cff41fc4d4d28da6d815f9870841e
|
|
4
|
+
data.tar.gz: e83f9c1bb73712fa1a89660670d6e20efad8cb9985e21c8a7bd6d4f2bb5b5e7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 605e9074bd646d136d3f8bd68f306d052bb4b71571e6c40f72715d2ebf2b7623088a4b5838e41a04d344e3002dd1992eea7d3d053883c4ffa79c94973c7b7c7c
|
|
7
|
+
data.tar.gz: b69e55002426df41be4cac00907c8c4c1c93dea524614875bf731ee12acb3915c852d380aa12a123585e278d463d5380ed4b37ff3aa620b8cc817579029c03e2
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,59 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.2.0] - 2026-08-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Provider retries with exponential backoff** — `max_retries` now retries transient `TimeoutError`, `RateLimitError`, and 5xx/transport `ProviderError`s before falling over
|
|
13
|
+
- `retry_backoff` (default `0.1s`, env `RUBY_LLM_MESH_RETRY_BACKOFF`) doubles after each failed attempt
|
|
14
|
+
- Authentication failures are never retried; they fail over immediately when fallback is enabled
|
|
15
|
+
|
|
16
|
+
## [2.1.0] - 2026-08-11
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Token/cost budget guard** — opt-in via `budget_enabled`, `budget_max_tokens`, `budget_max_usd`, and `budget_prices`
|
|
21
|
+
- `RubyLlmMesh::Budget` pre-checks estimated usage before provider calls and consumes actual usage from `Response#usage` after success
|
|
22
|
+
- `RubyLlmMesh::BudgetExceededError` when token or USD limits would be exceeded
|
|
23
|
+
- `RubyLlmMesh.budget_status` / `AiAgentRouter.budget_status` for runtime budget telemetry
|
|
24
|
+
- Full Contributor Covenant 2.1 [Code of Conduct](CODE_OF_CONDUCT.md) with enforcement guidelines
|
|
25
|
+
- [Privacy Policy](PRIVACY.md) for the OSS LLM routing gem (no phone-home; data stays with configured endpoints)
|
|
26
|
+
- README, CONTRIBUTING, and docs site links to Code of Conduct and Privacy Policy
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Router now honors `fallback: false` when a provider circuit is open or the provider name is unknown (no longer silently continues the ladder)
|
|
31
|
+
- `PeerRegistry#healthy_urls` no longer reintroduces unhealthy peers when the healthy set is empty (LocalNode uses its primary URL as last resort)
|
|
32
|
+
- Circuit breaker half-open state allows a single probe (not unbounded concurrent probes)
|
|
33
|
+
- HTTP client wraps connection reset / SSL / EOF transport errors as `ProviderError` so failover works
|
|
34
|
+
- Redis semantic-cache index cleans up stale entry IDs after TTL expiry
|
|
35
|
+
|
|
36
|
+
## [2.0.0] - 2026-08-07
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **Sovereign Mesh Core** — optional Rust `chimera_core` cdylib under `ext/chimera_core/` with FFI exports `start_node`, `node_alive`, `execute_wasm_payload`, `stop_node`
|
|
41
|
+
- **`RubyLlmMesh.execute` / `AiAgentRouter.execute`** — strategy-based intent execution (`:auto`, `:p2p_mesh`, `:cloud`, `:openai`, `:anthropic`, `:local_node`, `:local_mesh`)
|
|
42
|
+
- Pure-Ruby **NativeCore fallback** when the shared library or `ffi` load fails (require never hard-crashes)
|
|
43
|
+
- Mesh config: `mesh_port` (default `4233`), `auto_boot_mesh`, `fallback_providers`
|
|
44
|
+
- Optional **semantic cache** (in-memory or Redis when `REDIS_URL` + `redis` gem present)
|
|
45
|
+
- Optional **peer health monitoring** for multi-URL local node meshes (`peer_urls`, `HealthMonitor`)
|
|
46
|
+
- `rake compile` to build chimera_core via cargo
|
|
47
|
+
- Trusted publishing workflow `.github/workflows/release.yml` (OIDC + GitHub Release)
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- Version jump to **2.0.0** (Sovereign Mesh / FFI major)
|
|
52
|
+
- Gem dependency: `ffi ~> 1.17`
|
|
53
|
+
- Cloud failover remains real HTTP (OpenAI / Anthropic / local_node) — not stubbed
|
|
54
|
+
|
|
55
|
+
### Breaking
|
|
56
|
+
|
|
57
|
+
- Major version bump; consumers pinning `~> 0.1` must opt into `2.0.0`
|
|
58
|
+
- New default mesh settings (`auto_boot_mesh: true`, `mesh_port: 4233`) affect `:auto` / `:p2p_mesh` strategies only — `complete` API behavior is unchanged when semantic cache stays off (default)
|
|
59
|
+
- Trusted publisher workflow filename is now **`release.yml`** (was `push_gem.yml`)
|
|
60
|
+
|
|
8
61
|
## [0.1.0] - 2026-08-07
|
|
9
62
|
|
|
10
63
|
### Added
|
|
@@ -16,5 +69,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
69
|
- RAG helpers: text chunker, bag-of-words embeddings, tool schema adapters
|
|
17
70
|
- Optional ActiveRecord `acts_as_ai_agent` for memory, semantic cache, and audit logging
|
|
18
71
|
- Rails railtie that loads only when Rails is present
|
|
72
|
+
- Documentation site on GitHub Pages
|
|
73
|
+
- Trusted publishing workflow for RubyGems OIDC releases
|
|
19
74
|
|
|
75
|
+
[2.2.0]: https://github.com/theworker02/ruby_llm_mesh/releases/tag/v2.2.0
|
|
76
|
+
[2.1.0]: https://github.com/theworker02/ruby_llm_mesh/releases/tag/v2.1.0
|
|
77
|
+
[2.0.0]: https://github.com/theworker02/ruby_llm_mesh/releases/tag/v2.0.0
|
|
20
78
|
[0.1.0]: https://github.com/theworker02/ruby_llm_mesh/releases/tag/v0.1.0
|
data/CODE_OF_CONDUCT.md
CHANGED
|
@@ -43,21 +43,95 @@ acceptable behavior and will take appropriate and fair corrective action in
|
|
|
43
43
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
44
44
|
or harmful.
|
|
45
45
|
|
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
49
|
+
decisions when appropriate.
|
|
50
|
+
|
|
46
51
|
## Scope
|
|
47
52
|
|
|
48
53
|
This Code of Conduct applies within all community spaces, and also applies when
|
|
49
54
|
an individual is officially representing the community in public spaces.
|
|
55
|
+
Examples of representing our community include using an official e-mail address,
|
|
56
|
+
posting via an official social media account, or acting as an appointed
|
|
57
|
+
representative at an online or offline event.
|
|
50
58
|
|
|
51
59
|
## Enforcement
|
|
52
60
|
|
|
53
61
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
54
|
-
reported by
|
|
55
|
-
|
|
62
|
+
reported by:
|
|
63
|
+
|
|
64
|
+
* Opening a [GitHub issue](https://github.com/theworker02/ruby_llm_mesh/issues)
|
|
65
|
+
on this repository (prefer a private report when the matter is sensitive), or
|
|
66
|
+
* Contacting the maintainer via their GitHub profile:
|
|
67
|
+
[theworker02](https://github.com/theworker02)
|
|
68
|
+
|
|
69
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
70
|
+
|
|
71
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
72
|
+
reporter of any incident.
|
|
73
|
+
|
|
74
|
+
## Enforcement Guidelines
|
|
75
|
+
|
|
76
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
|
77
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
|
78
|
+
|
|
79
|
+
### 1. Correction
|
|
80
|
+
|
|
81
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
82
|
+
unprofessional or unwelcome in the community.
|
|
83
|
+
|
|
84
|
+
**Consequence**: A private, written warning from community leaders, providing
|
|
85
|
+
clarity around the nature of the violation and an explanation of why the
|
|
86
|
+
behavior was inappropriate. A public apology may be requested.
|
|
87
|
+
|
|
88
|
+
### 2. Warning
|
|
89
|
+
|
|
90
|
+
**Community Impact**: A violation through a single incident or series of
|
|
91
|
+
actions.
|
|
92
|
+
|
|
93
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
|
94
|
+
interaction with the people involved, including unsolicited interaction with
|
|
95
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
|
96
|
+
includes avoiding interactions in community spaces as well as external channels
|
|
97
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
|
98
|
+
ban.
|
|
99
|
+
|
|
100
|
+
### 3. Temporary Ban
|
|
101
|
+
|
|
102
|
+
**Community Impact**: A serious violation of community standards, including
|
|
103
|
+
sustained inappropriate behavior.
|
|
104
|
+
|
|
105
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
|
106
|
+
communication with the community for a specified period of time. No public or
|
|
107
|
+
private interaction with the people involved, including unsolicited interaction
|
|
108
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
|
109
|
+
Violating these terms may lead to a permanent ban.
|
|
110
|
+
|
|
111
|
+
### 4. Permanent Ban
|
|
112
|
+
|
|
113
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
|
114
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
115
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
|
116
|
+
|
|
117
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
|
118
|
+
community.
|
|
56
119
|
|
|
57
120
|
## Attribution
|
|
58
121
|
|
|
59
122
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
60
123
|
version 2.1, available at
|
|
61
|
-
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
124
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
|
125
|
+
|
|
126
|
+
Community Impact Guidelines were inspired by
|
|
127
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
128
|
+
|
|
129
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
130
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
|
131
|
+
[https://www.contributor-covenant.org/translations][translations].
|
|
62
132
|
|
|
63
133
|
[homepage]: https://www.contributor-covenant.org
|
|
134
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
135
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
136
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
|
137
|
+
[translations]: https://www.contributor-covenant.org/translations
|
data/CONTRIBUTING.md
CHANGED
|
@@ -22,18 +22,24 @@ bundle exec rake test
|
|
|
22
22
|
## Testing
|
|
23
23
|
|
|
24
24
|
Unit tests must not require live provider credentials. Stub HTTP with WebMock or inject stub providers.
|
|
25
|
+
Native FFI tests skip automatically when `chimera_core` is not compiled.
|
|
25
26
|
|
|
26
27
|
```bash
|
|
27
28
|
bundle exec rake test
|
|
29
|
+
bundle exec rake compile # optional — requires Rust/cargo
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
## Releases
|
|
31
33
|
|
|
32
34
|
Maintainers cut releases by tagging `vX.Y.Z` on `main`, which triggers the
|
|
33
|
-
RubyGems Trusted Publisher workflow (`.github/workflows/
|
|
35
|
+
RubyGems Trusted Publisher workflow (`.github/workflows/release.yml`).
|
|
34
36
|
|
|
35
37
|
See the README for Trusted Publisher setup details.
|
|
36
38
|
|
|
37
39
|
## Code of Conduct
|
|
38
40
|
|
|
39
41
|
By participating, you agree to uphold our [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
42
|
+
|
|
43
|
+
## Privacy
|
|
44
|
+
|
|
45
|
+
See [PRIVACY.md](PRIVACY.md) for how this gem handles data (no phone-home telemetry; prompts go only to endpoints you configure).
|
data/PRIVACY.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Privacy Policy
|
|
2
|
+
|
|
3
|
+
**Effective date:** 2026-08-07
|
|
4
|
+
**Applies to:** the open-source `ruby_llm_mesh` Ruby gem and its companion documentation at [github.com/theworker02/ruby_llm_mesh](https://github.com/theworker02/ruby_llm_mesh)
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
`ruby_llm_mesh` is a **library you run in your own Ruby/Rails process**. The maintainers of this project do **not** operate a hosted routing service, do **not** receive your prompts by default, and do **not** collect telemetry, analytics, or crash reports from gem usage.
|
|
9
|
+
|
|
10
|
+
## What this gem does with data
|
|
11
|
+
|
|
12
|
+
When you call APIs such as `AiAgentRouter.execute` / `RubyLlmMesh.complete`, the gem may:
|
|
13
|
+
|
|
14
|
+
1. **Send prompts and related options** to LLM HTTP endpoints **you configure** (for example OpenAI, Anthropic, or a local OpenAI-compatible node such as Ollama / LM Studio), using API keys and base URLs from your environment or configuration.
|
|
15
|
+
2. **Run intents through the optional native mesh / pure-Ruby fallback** entirely **inside your process** (and any peers **you** configure).
|
|
16
|
+
3. **Optionally store prompt/response material** in an in-process or Redis semantic cache **only if you enable** semantic caching and point it at infrastructure you control.
|
|
17
|
+
4. **Optionally record conversational memory / audits** when you use Rails `acts_as_ai_agent` helpers — that data lives in **your** database attributes.
|
|
18
|
+
|
|
19
|
+
The gem does not phone home to the `ruby_llm_mesh` authors.
|
|
20
|
+
|
|
21
|
+
## What we do not collect
|
|
22
|
+
|
|
23
|
+
- No usage analytics or phone-home telemetry from the gem
|
|
24
|
+
- No automatic upload of prompts, completions, embeddings, or API keys to project maintainers
|
|
25
|
+
- No account system or user database operated by this project for gem runtime traffic
|
|
26
|
+
|
|
27
|
+
## Third-party providers
|
|
28
|
+
|
|
29
|
+
If you configure cloud providers, **those providers’ privacy policies apply** to data you send them (prompts, system messages, tools, etc.). Review and configure:
|
|
30
|
+
|
|
31
|
+
- [OpenAI Privacy](https://openai.com/policies/privacy-policy/) (or your compatible endpoint’s policy)
|
|
32
|
+
- [Anthropic Privacy](https://www.anthropic.com/legal/privacy) (or your configured Anthropic-compatible endpoint)
|
|
33
|
+
|
|
34
|
+
Local nodes and peer URLs you list are under **your** operational control and policies.
|
|
35
|
+
|
|
36
|
+
## Credentials and secrets
|
|
37
|
+
|
|
38
|
+
API keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, Redis URLs, etc.) are read from your environment or configuration and used only to talk to endpoints you choose. Do not commit secrets to git. This repository’s tests are designed to run **without** live credentials.
|
|
39
|
+
|
|
40
|
+
## GitHub / project website
|
|
41
|
+
|
|
42
|
+
Visiting the GitHub repository, Issues, Discussions, or GitHub Pages docs is subject to [GitHub’s Privacy Statement](https://docs.github.com/en/site-policy/privacy-policies/github-privacy-statement). Maintainers may see information you voluntarily provide in issues, PRs, or emails (for example contact details in a Code of Conduct report).
|
|
43
|
+
|
|
44
|
+
## Children
|
|
45
|
+
|
|
46
|
+
This project is a developer library and is not directed at children.
|
|
47
|
+
|
|
48
|
+
## Changes
|
|
49
|
+
|
|
50
|
+
Privacy practices for the gem may change as the project evolves. Material updates will be reflected in this file in the repository. Continued use of a newer gem version after an update constitutes awareness of the revised policy for that version’s documented behavior.
|
|
51
|
+
|
|
52
|
+
## Contact
|
|
53
|
+
|
|
54
|
+
Privacy questions about **this open-source project** (not about third-party LLM vendors): open a GitHub issue in [theworker02/ruby_llm_mesh](https://github.com/theworker02/ruby_llm_mesh/issues) or contact the maintainers via the repository.
|
|
55
|
+
|
|
56
|
+
For Code of Conduct enforcement, see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
data/README.md
CHANGED
|
@@ -5,22 +5,32 @@
|
|
|
5
5
|
<h1 align="center">ruby_llm_mesh</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
|
|
9
|
-
<code>AiAgentRouter</code> ·
|
|
8
|
+
Sovereign multi-provider AI mesh for Ruby & Rails<br/>
|
|
9
|
+
<code>AiAgentRouter</code> · native FFI core · circuit breaking · cloud failover
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<a href="https://rubygems.org/gems/ruby_llm_mesh"><img src="https://img.shields.io/gem/v/ruby_llm_mesh?color=9B1B30" alt="Gem Version" /></a>
|
|
14
|
-
<a href="https://github.com/theworker02/ruby_llm_mesh/actions/workflows/ci.yml"><img src="https://
|
|
14
|
+
<a href="https://github.com/theworker02/ruby_llm_mesh/actions/workflows/ci.yml"><img src="https://img.shields.io/badge/CI-GitHub%20Actions-1A1A1A" alt="CI" /></a>
|
|
15
15
|
<a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-E85D4C" alt="License: MIT" /></a>
|
|
16
16
|
<a href="https://theworker02.github.io/ruby_llm_mesh/"><img src="https://img.shields.io/badge/docs-GitHub%20Pages-1A1A1A" alt="GitHub Pages" /></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
<p align="center">
|
|
20
|
+
<strong>Install from RubyGems:</strong>
|
|
21
|
+
<a href="https://rubygems.org/gems/ruby_llm_mesh">https://rubygems.org/gems/ruby_llm_mesh</a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
> **Gem name:** `ruby_llm_mesh` (underscores) — matches this GitHub repo and the official RubyGems listing. Do not confuse with hyphenated names in design sketches.
|
|
25
|
+
|
|
26
|
+
## What it does (v2.0.0)
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
`ruby_llm_mesh` routes intents across:
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
1. A **native sovereign mesh** (`chimera_core` Rust cdylib via FFI) for local P2P-style execution
|
|
31
|
+
2. **Real cloud / local LLM HTTP** — OpenAI, Anthropic, and OpenAI-compatible nodes (Ollama, LM Studio, …)
|
|
32
|
+
|
|
33
|
+
When the native library is not compiled, a pure-Ruby fallback keeps the API working. Circuit breaking, optional semantic cache, peer health for multi-node local meshes, RAG helpers, and Rails hooks remain available.
|
|
24
34
|
|
|
25
35
|
## Install
|
|
26
36
|
|
|
@@ -36,6 +46,19 @@ gem "ruby_llm_mesh"
|
|
|
36
46
|
|
|
37
47
|
Then `bundle install`.
|
|
38
48
|
|
|
49
|
+
Gem page: [rubygems.org/gems/ruby_llm_mesh](https://rubygems.org/gems/ruby_llm_mesh)
|
|
50
|
+
|
|
51
|
+
### Compile the native core (optional)
|
|
52
|
+
|
|
53
|
+
Requires [Rust](https://rustup.rs) / `cargo`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bundle exec rake compile
|
|
57
|
+
# → ext/chimera_core/target/release/libchimera_core.so (or .dylib / .dll)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Without compile, `NativeCore` uses an in-process Ruby fallback. `require "ruby_llm_mesh"` never crashes on a missing `.so`.
|
|
61
|
+
|
|
39
62
|
## Quickstart
|
|
40
63
|
|
|
41
64
|
```ruby
|
|
@@ -44,133 +67,135 @@ require "ruby_llm_mesh"
|
|
|
44
67
|
AiAgentRouter.configure do |c|
|
|
45
68
|
c.openai_api_key = ENV["OPENAI_API_KEY"]
|
|
46
69
|
c.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
|
47
|
-
c.
|
|
48
|
-
c.
|
|
49
|
-
c.
|
|
70
|
+
c.mesh_port = 4233
|
|
71
|
+
c.auto_boot_mesh = true
|
|
72
|
+
c.fallback_providers = %i[openai anthropic local_node]
|
|
50
73
|
end
|
|
51
74
|
|
|
75
|
+
# Strategy-based execution (v2)
|
|
76
|
+
response = AiAgentRouter.execute(
|
|
77
|
+
intent: "Summarize circuit breakers in one sentence.",
|
|
78
|
+
strategy: :auto # :p2p_mesh | :cloud | :openai | :anthropic | :local_node
|
|
79
|
+
)
|
|
80
|
+
puts response.content
|
|
81
|
+
puts response.provider # => :p2p_mesh or a cloud provider
|
|
82
|
+
|
|
83
|
+
# Classic complete API (unchanged shape from 0.1.x)
|
|
52
84
|
response = AiAgentRouter.complete(
|
|
53
|
-
prompt: "
|
|
85
|
+
prompt: "Hello from the mesh",
|
|
54
86
|
providers: %i[anthropic openai local_node],
|
|
55
87
|
fallback: true
|
|
56
88
|
)
|
|
57
|
-
|
|
58
|
-
puts response.content
|
|
59
|
-
puts response.provider # => :anthropic (or next healthy provider)
|
|
60
|
-
puts response.fallback_used # => true if a later provider was used
|
|
61
89
|
```
|
|
62
90
|
|
|
63
|
-
|
|
91
|
+
## Strategies (`execute`)
|
|
92
|
+
|
|
93
|
+
| Strategy | Behavior |
|
|
94
|
+
|----------|----------|
|
|
95
|
+
| `:auto` | Boot native mesh if `auto_boot_mesh`; use P2P when alive, else real cloud ladder |
|
|
96
|
+
| `:p2p_mesh` | Native `chimera_core` (or Ruby fallback) only |
|
|
97
|
+
| `:cloud` | HTTP via `fallback_providers` / `default_providers` |
|
|
98
|
+
| `:openai` / `:anthropic` / `:local_node` / `:local_mesh` | Single-provider routing |
|
|
99
|
+
|
|
100
|
+
Cloud paths call the real provider HTTP clients — they are **not** stubbed simulation strings.
|
|
64
101
|
|
|
65
102
|
## Configuration
|
|
66
103
|
|
|
67
104
|
| Option | Default | Description |
|
|
68
105
|
|--------|---------|-------------|
|
|
69
|
-
| `
|
|
106
|
+
| `mesh_port` | `4233` | Native mesh listen port |
|
|
107
|
+
| `auto_boot_mesh` | `true` | Auto-start node for `:auto` / `:p2p_mesh` |
|
|
108
|
+
| `fallback_providers` | `%i[openai anthropic local_node]` | Ladder for `:cloud` / `:auto` failover |
|
|
109
|
+
| `default_providers` | `%i[openai anthropic local_node]` | Ladder for `complete` |
|
|
70
110
|
| `fallback` | `true` | Continue to next provider on failure |
|
|
71
111
|
| `timeout` | `30` | HTTP open/read timeout (seconds) |
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `circuit_failure_threshold` | `3`
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
## Providers
|
|
112
|
+
| `max_retries` | `1` | Extra attempts on timeout, 5xx, and rate-limit errors |
|
|
113
|
+
| `retry_backoff` | `0.1` | Base delay (seconds) doubled after each retry |
|
|
114
|
+
| `openai_*` / `anthropic_*` / `local_node_*` | env-backed | Provider credentials & endpoints |
|
|
115
|
+
| `circuit_failure_threshold` / `circuit_reset_timeout` | `3` / `60` | Circuit breaker |
|
|
116
|
+
| `semantic_cache_enabled` | `false` | Opt-in vector similarity cache |
|
|
117
|
+
| `semantic_cache_threshold` / `semantic_cache_ttl` | `0.92` / `3600` | Cache match & TTL |
|
|
118
|
+
| `redis_url` | `ENV["REDIS_URL"]` | Optional Redis for distributed cache |
|
|
119
|
+
| `peer_discovery_enabled` / `peer_urls` | off / `[]` | Multi-peer local node health |
|
|
120
|
+
| `logger` | `nil` | `#info` / `#warn` / `#error` or `#call` |
|
|
82
121
|
|
|
83
|
-
|
|
84
|
-
- **`:anthropic`** — Messages API
|
|
85
|
-
- **`:local_node`** — OpenAI-compatible `/v1/chat/completions`, with a fallback to Ollama’s `/api/chat` on 404
|
|
122
|
+
## Native FFI surface
|
|
86
123
|
|
|
87
|
-
|
|
124
|
+
| C export | Ruby |
|
|
125
|
+
|----------|------|
|
|
126
|
+
| `start_node(port)` | `RubyLlmMesh.boot_mesh!` / `NativeCore.start_node` |
|
|
127
|
+
| `node_alive()` | `RubyLlmMesh.mesh_alive?` / `NativeCore.node_alive?` |
|
|
128
|
+
| `execute_wasm_payload(intent)` | `NativeCore.execute_wasm_payload` → Hash |
|
|
129
|
+
| `stop_node()` | `NativeCore.stop_node` |
|
|
88
130
|
|
|
89
|
-
## Circuit breaker &
|
|
131
|
+
## Circuit breaker & providers
|
|
90
132
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
If every provider fails, `RubyLlmMesh::AllProvidersFailedError` is raised with a per-provider error map.
|
|
94
|
-
|
|
95
|
-
```ruby
|
|
96
|
-
breaker = RubyLlmMesh::Router.circuit_breaker
|
|
97
|
-
breaker.state_for(:openai) # => :closed | :open | :half_open
|
|
98
|
-
RubyLlmMesh::Router.reset_circuit_breaker!
|
|
99
|
-
```
|
|
133
|
+
Same as 0.1.x: per-provider circuits, fallback ladders, `AllProvidersFailedError`. Providers: `:openai`, `:anthropic`, `:local_node` (alias `:local_mesh` for peer-aware local routing).
|
|
100
134
|
|
|
101
135
|
## RAG helpers
|
|
102
136
|
|
|
103
137
|
```ruby
|
|
104
138
|
chunks = RubyLlmMesh::Rag::Chunker.new(size: 500, overlap: 50).chunk(long_text)
|
|
105
|
-
|
|
106
139
|
embedder = RubyLlmMesh::Rag::Embeddings.new(dimensions: 256)
|
|
107
140
|
hits = embedder.top_k("billing refunds", documents, k: 3)
|
|
108
|
-
|
|
109
|
-
tool = RubyLlmMesh::Rag::Tools.define(
|
|
110
|
-
name: "lookup_order",
|
|
111
|
-
description: "Fetch an order by id",
|
|
112
|
-
parameters: { order_id: { type: "string" } },
|
|
113
|
-
required: [:order_id]
|
|
114
|
-
)
|
|
115
|
-
openai_tools = RubyLlmMesh::Rag::Tools.for_openai([tool])
|
|
116
141
|
```
|
|
117
142
|
|
|
118
|
-
The built-in embedder is a local bag-of-words helper for prototyping. Swap in a production embedding API when you need higher quality vectors.
|
|
119
|
-
|
|
120
143
|
## Rails: `acts_as_ai_agent`
|
|
121
144
|
|
|
122
|
-
The railtie loads only when Rails is present. On ActiveRecord models:
|
|
123
|
-
|
|
124
145
|
```ruby
|
|
125
146
|
class Conversation < ApplicationRecord
|
|
126
147
|
acts_as_ai_agent
|
|
127
|
-
# expects JSON/text columns: messages, semantic_cache, ai_audits (configurable)
|
|
128
148
|
end
|
|
129
|
-
|
|
130
|
-
conversation = Conversation.create!
|
|
131
|
-
response = conversation.ai_complete("What did we discuss last?", providers: %i[openai])
|
|
132
149
|
```
|
|
133
150
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
## Branding
|
|
137
|
-
|
|
138
|
-
Primary colors from the project logo:
|
|
139
|
-
|
|
140
|
-
| Token | Hex |
|
|
141
|
-
|-------|-----|
|
|
142
|
-
| Ruby | `#9B1B30` |
|
|
143
|
-
| Coral | `#E85D4C` |
|
|
144
|
-
| Charcoal | `#1A1A1A` |
|
|
151
|
+
## Upgrading from 0.1.0 → 2.0.0
|
|
145
152
|
|
|
146
|
-
|
|
153
|
+
- Bump the gem to `2.0.0` (`~> 0.1` will not pick this up).
|
|
154
|
+
- `complete` / `AiAgentRouter.complete` remain; prefer `execute` for mesh strategies.
|
|
155
|
+
- Install `ffi` (declared dependency). Compile native core only if you want the Rust engine.
|
|
156
|
+
- If you configured RubyGems trusted publishing against `push_gem.yml`, update the workflow filename to **`release.yml`**.
|
|
147
157
|
|
|
148
158
|
## Development
|
|
149
159
|
|
|
150
160
|
```bash
|
|
151
161
|
bundle install
|
|
152
|
-
bundle exec rake test
|
|
162
|
+
bundle exec rake test # no Rust required
|
|
163
|
+
bundle exec rake compile # optional native build
|
|
164
|
+
bundle exec rake test:native # cargo test
|
|
153
165
|
```
|
|
154
166
|
|
|
155
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
156
|
-
|
|
157
167
|
## Trusted publishing (RubyGems)
|
|
158
168
|
|
|
159
|
-
Releases
|
|
160
|
-
|
|
161
|
-
Configure a **pending trusted publisher** (first release) or trusted publisher at:
|
|
162
|
-
|
|
163
|
-
[https://rubygems.org/profile/oidc_pending_trusted_publishers](https://rubygems.org/profile/oidc_pending_trusted_publishers)
|
|
169
|
+
Releases publish via [RubyGems Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) using `.github/workflows/release.yml` on tags matching `v*`.
|
|
164
170
|
|
|
165
171
|
| Field | Value |
|
|
166
172
|
|-------|-------|
|
|
167
173
|
| Gem name | `ruby_llm_mesh` |
|
|
168
174
|
| GitHub repository owner | `theworker02` |
|
|
169
175
|
| GitHub repository name | `ruby_llm_mesh` |
|
|
170
|
-
| Workflow filename | `
|
|
176
|
+
| Workflow filename | `release.yml` |
|
|
171
177
|
| Environment name | `release` |
|
|
172
178
|
|
|
173
|
-
|
|
179
|
+
Create a GitHub Environment named `release`. Pushing tag `v2.0.0` runs OIDC publish via `rubygems/release-gem@v1`.
|
|
180
|
+
|
|
181
|
+
## Branding
|
|
182
|
+
|
|
183
|
+
| Token | Hex |
|
|
184
|
+
|-------|-----|
|
|
185
|
+
| Ruby | `#9B1B30` |
|
|
186
|
+
| Coral | `#E85D4C` |
|
|
187
|
+
| Charcoal | `#1A1A1A` |
|
|
188
|
+
|
|
189
|
+
Docs: [https://theworker02.github.io/ruby_llm_mesh/](https://theworker02.github.io/ruby_llm_mesh/)
|
|
190
|
+
|
|
191
|
+
## Built with
|
|
192
|
+
|
|
193
|
+
Designed with [Cursor](https://cursor.com) models Opus and Fable 5.
|
|
194
|
+
|
|
195
|
+
## Community & policies
|
|
196
|
+
|
|
197
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md) — Contributor Covenant 2.1; see also [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
198
|
+
- [Privacy Policy](PRIVACY.md) — no phone-home telemetry; prompts and API keys stay with endpoints you configure
|
|
174
199
|
|
|
175
200
|
## License
|
|
176
201
|
|
data/Rakefile
CHANGED
|
@@ -10,4 +10,32 @@ Rake::TestTask.new(:test) do |t|
|
|
|
10
10
|
t.warning = true
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
desc "Compile chimera_core native library (requires Rust/cargo)"
|
|
14
|
+
task :compile do
|
|
15
|
+
crate = File.expand_path("ext/chimera_core", __dir__)
|
|
16
|
+
unless system("cargo", "--version", out: File::NULL, err: File::NULL)
|
|
17
|
+
abort "cargo not found — install Rust from https://rustup.rs to compile chimera_core"
|
|
18
|
+
end
|
|
19
|
+
Dir.chdir(crate) do
|
|
20
|
+
sh "cargo", "build", "--release"
|
|
21
|
+
end
|
|
22
|
+
puts "chimera_core built under ext/chimera_core/target/release/"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "Compile chimera_core in debug mode"
|
|
26
|
+
task "compile:debug" do
|
|
27
|
+
crate = File.expand_path("ext/chimera_core", __dir__)
|
|
28
|
+
Dir.chdir(crate) do
|
|
29
|
+
sh "cargo", "build"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "Run Rust unit tests for chimera_core"
|
|
34
|
+
task "test:native" do
|
|
35
|
+
crate = File.expand_path("ext/chimera_core", __dir__)
|
|
36
|
+
Dir.chdir(crate) do
|
|
37
|
+
sh "cargo", "test"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
13
41
|
task default: :test
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "chimera_core"
|
|
3
|
+
version = "2.0.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Sovereign mesh core for ruby_llm_mesh — native node + intent execution"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
|
|
8
|
+
[lib]
|
|
9
|
+
name = "chimera_core"
|
|
10
|
+
crate-type = ["cdylib"]
|
|
11
|
+
|
|
12
|
+
[profile.release]
|
|
13
|
+
lto = true
|
|
14
|
+
opt-level = 3
|