silas 0.6.1 → 0.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +7 -3
- data/docs/configuration.md +4 -0
- data/docs/providers.md +171 -0
- data/lib/generators/silas/install/templates/ruby_llm.rb +3 -1
- data/lib/silas/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a34eec0f8444f42ef91b1db155bc2786c28ce0de5ed345d9e63b39af9b29756
|
|
4
|
+
data.tar.gz: 94c9b0464629b6f23eab8f4811e5dd63cdec63d480388cf01c8b0b9111a43376
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 62c5e530ccc6cfbc3cbfa7b1388b72e53545172acc054b7565930eef56541f8e839846435435585db3fcc3161d40994345b0da5e24fcdc0de1710988efc7ab35
|
|
7
|
+
data.tar.gz: e8c83c1733efd76810fe2d0cd5e5e57c8b1d929d1a5556d685e376c704108c550494f07e6eb332d6968e458f1bfbb85b5fc024016d1f951dfb1d6a351b6b4683
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.2 (2026-07-26)
|
|
4
|
+
|
|
5
|
+
The providers guide and the remaining community files.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`docs/providers.md` — Providers & gateways.** How a model id picks a
|
|
10
|
+
provider (and why Silas stamps the resolved provider on every step row),
|
|
11
|
+
the OpenRouter recipe — one key, 300+ models, slash-form ids, with cost
|
|
12
|
+
lines and `compact_at` following the registry entry for the route you
|
|
13
|
+
actually run — plus OpenAI-compatible gateways (LiteLLM, Vercel AI
|
|
14
|
+
Gateway) via `openai_api_base`/`openrouter_api_base`, the
|
|
15
|
+
Bedrock/Vertex/Azure key map, local runtimes with the honest
|
|
16
|
+
cost-unavailable story, and `around_model_call` for failover. Every
|
|
17
|
+
mechanical claim verified against ruby_llm 1.16 source and a live
|
|
18
|
+
resolution run; Vercel endpoint details from their docs as of 2026-07-07.
|
|
19
|
+
Ships in the gem; linked from the configuration reference, the README,
|
|
20
|
+
and the installer's `ruby_llm.rb` initializer comment.
|
|
21
|
+
- **`CODE_OF_CONDUCT.md`** (Contributor Covenant 2.1), linked from
|
|
22
|
+
CONTRIBUTING and the README.
|
|
23
|
+
- **A pull request template** mirroring CONTRIBUTING's actual gates: both
|
|
24
|
+
stores, RuboCop, the chaos gate when the loop is touched, the
|
|
25
|
+
templates-smoke run when generators change, and a durability-notes
|
|
26
|
+
section for replay-path changes.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- README's status line claimed 0.5.x.
|
|
31
|
+
|
|
3
32
|
## 0.6.1 (2026-07-26)
|
|
4
33
|
|
|
5
34
|
Two live-inbox fixes found by driving real apps, a security hardening pass,
|
data/README.md
CHANGED
|
@@ -100,9 +100,11 @@ release): [guarantees](https://danielstpaul.github.io/silas/guarantees).
|
|
|
100
100
|
|
|
101
101
|
## Status
|
|
102
102
|
|
|
103
|
-
Early (0.
|
|
103
|
+
Early (0.6.x) and moving fast. Requires Rails >= 8.1 (Active Job
|
|
104
104
|
Continuations) and Solid Queue >= 1.2; any model provider
|
|
105
|
-
[RubyLLM](https://rubyllm.com) supports
|
|
105
|
+
[RubyLLM](https://rubyllm.com) supports — Anthropic direct, OpenRouter,
|
|
106
|
+
OpenAI-compatible gateways, local runtimes
|
|
107
|
+
([providers guide](https://github.com/danielstpaul/silas/blob/main/docs/providers.md)).
|
|
106
108
|
|
|
107
109
|
## Community
|
|
108
110
|
|
|
@@ -113,7 +115,9 @@ Questions, ideas, and bug reports →
|
|
|
113
115
|
|
|
114
116
|
See [CONTRIBUTING.md](https://github.com/danielstpaul/silas/blob/main/CONTRIBUTING.md)
|
|
115
117
|
— including the short list of things Silas deliberately doesn't do, and the
|
|
116
|
-
chaos gate that protects the durability contract.
|
|
118
|
+
chaos gate that protects the durability contract. Everyone interacting here
|
|
119
|
+
is expected to follow the
|
|
120
|
+
[code of conduct](https://github.com/danielstpaul/silas/blob/main/CODE_OF_CONDUCT.md).
|
|
117
121
|
|
|
118
122
|
## Security
|
|
119
123
|
|
data/docs/configuration.md
CHANGED
|
@@ -18,6 +18,10 @@ end
|
|
|
18
18
|
| `around_model_call` | `nil` | Wrap every model call — e.g. `->(ctx, &call) { RubyLLM::Resilience.chain(:anthropic) { call.() } }`. |
|
|
19
19
|
| `queue_name` | `:default` | Active Job queue for agent turns. |
|
|
20
20
|
|
|
21
|
+
Which provider serves a turn is decided by the model id — OpenRouter,
|
|
22
|
+
OpenAI-compatible gateways, Bedrock/Vertex/Azure, and local runtimes are all
|
|
23
|
+
recipes in [providers](providers.md).
|
|
24
|
+
|
|
21
25
|
## The loop
|
|
22
26
|
|
|
23
27
|
| Option | Default | Meaning |
|
data/docs/providers.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Providers & gateways
|
|
2
|
+
|
|
3
|
+
Silas has exactly one inference seam: the `:ruby_llm` adapter. Every model
|
|
4
|
+
call goes through [RubyLLM](https://rubyllm.com), so every provider RubyLLM
|
|
5
|
+
speaks — Anthropic, OpenAI, Gemini, Bedrock, Vertex AI, Azure, Mistral,
|
|
6
|
+
DeepSeek, Perplexity, xAI, OpenRouter, local runtimes — is available to your
|
|
7
|
+
agents with zero Silas-specific glue. Keys live in
|
|
8
|
+
`config/initializers/ruby_llm.rb`; **which provider serves a turn is decided
|
|
9
|
+
by the model id**. Nothing in `app/agent/` changes when the provider does.
|
|
10
|
+
|
|
11
|
+
## How a model id picks a provider
|
|
12
|
+
|
|
13
|
+
RubyLLM ships a model registry (1,100+ entries, refreshed upstream from
|
|
14
|
+
[models.dev](https://models.dev)). Silas resolves the agent's `model:` — from
|
|
15
|
+
`agent.yml`, falling back to `config.default_model` — against that registry;
|
|
16
|
+
the matching entry names the provider, and the adapter builds that provider's
|
|
17
|
+
client. The same entry supplies the numbers Silas runs on, per
|
|
18
|
+
(model, provider):
|
|
19
|
+
|
|
20
|
+
- **pricing** — the cost lines in the inbox and the `max_cost` budget;
|
|
21
|
+
- **context window** — the `compact_at` compaction threshold.
|
|
22
|
+
|
|
23
|
+
So switching provider is switching model id. A model the registry doesn't
|
|
24
|
+
know fails fast at the first step with the fix in the error
|
|
25
|
+
(`RubyLLM.models.refresh!`, or pick a registry model). And because a
|
|
26
|
+
registry's tie-breaks can change across upgrades, Silas stamps the resolved
|
|
27
|
+
provider on every step row — historical cost lines price against the
|
|
28
|
+
(model, provider) that actually served them, forever.
|
|
29
|
+
|
|
30
|
+
## Direct providers
|
|
31
|
+
|
|
32
|
+
The installer's `config/initializers/ruby_llm.rb` maps environment keys in —
|
|
33
|
+
RubyLLM never reads provider keys from the environment by itself:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
RubyLLM.configure do |c|
|
|
37
|
+
c.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Every provider follows the same pattern (`openai_api_key`,
|
|
42
|
+
`gemini_api_key`, …— the full list is in
|
|
43
|
+
[RubyLLM's configuration docs](https://rubyllm.com/configuration/)). For
|
|
44
|
+
cloud-platform shops the "enterprise gateway" is usually just the native
|
|
45
|
+
provider:
|
|
46
|
+
|
|
47
|
+
| Platform | Keys |
|
|
48
|
+
|---|---|
|
|
49
|
+
| AWS Bedrock | `bedrock_api_key`, `bedrock_secret_key`, `bedrock_region` (+ optional `bedrock_session_token`) |
|
|
50
|
+
| GCP Vertex AI | `vertexai_project_id`, `vertexai_location` (+ optional `vertexai_service_account_key`) |
|
|
51
|
+
| Azure OpenAI | `azure_api_base`, `azure_api_key` (or `azure_ai_auth_token`) |
|
|
52
|
+
|
|
53
|
+
Verify any of this with `bin/rails silas:doctor` — it reports which providers
|
|
54
|
+
have credentials configured and resolves your default model with its price:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
✓ provider credentials — anthropic
|
|
58
|
+
✓ model claude-sonnet-4-5 — anthropic · $3/$15 per MTok
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## OpenRouter: one key, 300+ models
|
|
62
|
+
|
|
63
|
+
[OpenRouter](https://openrouter.ai) is a first-class RubyLLM provider, and
|
|
64
|
+
the registry ships its catalog (341 models as of ruby_llm 1.16) — one key
|
|
65
|
+
buys your agents Claude, GPT, Gemini, Llama, DeepSeek and the rest, billed
|
|
66
|
+
in one place.
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# config/initializers/ruby_llm.rb
|
|
70
|
+
RubyLLM.configure do |c|
|
|
71
|
+
c.openrouter_api_key = ENV["OPENROUTER_API_KEY"]
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Routed models use slash-form ids — `creator/model`, exactly as OpenRouter
|
|
76
|
+
lists them:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# app/agent/agent.yml
|
|
80
|
+
model: anthropic/claude-sonnet-4.5 # via OpenRouter
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
or globally:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
Silas.configure do |c|
|
|
87
|
+
c.default_model = "anthropic/claude-sonnet-4.5"
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The two id families never collide: `claude-sonnet-4-5` is Anthropic direct,
|
|
92
|
+
`anthropic/claude-sonnet-4.5` is the same model via OpenRouter, and each
|
|
93
|
+
resolves to its own registry entry. That per-route entry is the one your
|
|
94
|
+
cost lines and compaction thresholds follow — the route you run, not the
|
|
95
|
+
origin provider. Concretely, in the shipped registry the direct entry lists
|
|
96
|
+
a 200K context window while OpenRouter's route lists 1M, so `compact_at`
|
|
97
|
+
triggers where the route actually overflows.
|
|
98
|
+
|
|
99
|
+
`silas:doctor` confirms the whole chain:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
✓ provider credentials — openrouter
|
|
103
|
+
✓ model anthropic/claude-sonnet-4.5 — openrouter · $3/$15 per MTok
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## OpenAI-compatible gateways
|
|
107
|
+
|
|
108
|
+
Self-hosted and enterprise gateways (LiteLLM, Vercel AI Gateway, an internal
|
|
109
|
+
proxy) mostly speak the OpenAI chat-completions dialect. Two shapes:
|
|
110
|
+
|
|
111
|
+
**The gateway serves OpenAI model ids** (`gpt-5.2`, …) — point the OpenAI
|
|
112
|
+
provider at it:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
RubyLLM.configure do |c|
|
|
116
|
+
c.openai_api_key = ENV["GATEWAY_API_KEY"]
|
|
117
|
+
c.openai_api_base = "https://gateway.internal/v1"
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**The gateway serves models.dev slash ids** (`anthropic/claude-sonnet-4.5`,
|
|
122
|
+
…, as Vercel's AI Gateway does) — repoint the OpenRouter provider, which
|
|
123
|
+
already speaks plain chat-completions against exactly those ids:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
RubyLLM.configure do |c|
|
|
127
|
+
c.openrouter_api_key = ENV["AI_GATEWAY_API_KEY"]
|
|
128
|
+
c.openrouter_api_base = "https://ai-gateway.vercel.sh/v1"
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Either way the model id must still resolve in the registry — the registry
|
|
133
|
+
entry is where Silas gets pricing and the context window, and a gateway
|
|
134
|
+
that bills differently can be corrected per model with the
|
|
135
|
+
`config.model_prices` override ([configuration](configuration.md)).
|
|
136
|
+
|
|
137
|
+
Two gateway footnotes, both cheap to check with one real turn:
|
|
138
|
+
|
|
139
|
+
- RubyLLM renders system messages as role `developer` (OpenAI's current
|
|
140
|
+
dialect) through these providers. OpenRouter normalises it; if your
|
|
141
|
+
gateway insists on `system`, set `c.openai_use_system_role = true`.
|
|
142
|
+
- Streaming must pass through as SSE. If the operator inbox shows a turn
|
|
143
|
+
completing without live text, the gateway buffered the stream.
|
|
144
|
+
|
|
145
|
+
## Local runtimes
|
|
146
|
+
|
|
147
|
+
Ollama and GPUStack are RubyLLM providers too (`ollama_api_base`,
|
|
148
|
+
`gpustack_api_base`/`gpustack_api_key`). Local models aren't in the shipped
|
|
149
|
+
registry, so refresh it after configuring — `RubyLLM.models.refresh!` asks
|
|
150
|
+
every configured provider for its live model list and merges the results —
|
|
151
|
+
then use the id it lists. Local models carry no registry pricing: the inbox
|
|
152
|
+
shows their token counts with "cost unavailable", and a `max_cost` budget
|
|
153
|
+
can't bind (only priced tokens count toward it) — list the model in
|
|
154
|
+
`config.model_prices` to restore both.
|
|
155
|
+
|
|
156
|
+
## Failover and wrapping
|
|
157
|
+
|
|
158
|
+
Provider outages, rate-limit retries and model failover belong at the
|
|
159
|
+
inference seam, not in your tools. `config.around_model_call` wraps every
|
|
160
|
+
model call the loop makes:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
Silas.configure do |c|
|
|
164
|
+
c.around_model_call = ->(ctx, &call) do
|
|
165
|
+
RubyLLM::Resilience.chain(:anthropic) { call.() }
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Whatever runs inside still lands in the same durable step — a failover
|
|
171
|
+
retry that succeeds is recorded exactly like a first-try success.
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
#
|
|
4
4
|
# export ANTHROPIC_API_KEY=sk-ant-...
|
|
5
5
|
#
|
|
6
|
-
# Any provider RubyLLM supports works the same way (openai_api_key, etc.)
|
|
6
|
+
# Any provider RubyLLM supports works the same way (openai_api_key, etc.) —
|
|
7
|
+
# OpenRouter, OpenAI-compatible gateways, and local runtimes are covered in
|
|
8
|
+
# the Silas guide docs/providers.md (shipped in the gem: `bundle show silas`).
|
|
7
9
|
RubyLLM.configure do |c|
|
|
8
10
|
# Silas never uses RubyLLM's acts_as_* ActiveRecord mixins (it owns its own
|
|
9
11
|
# durable schema), so opt into the new API to silence the legacy deprecation
|
data/lib/silas/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: silas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel St Paul
|
|
@@ -177,6 +177,7 @@ files:
|
|
|
177
177
|
- docs/guarantees.md
|
|
178
178
|
- docs/inbox-and-api.md
|
|
179
179
|
- docs/memory.md
|
|
180
|
+
- docs/providers.md
|
|
180
181
|
- docs/sandbox.md
|
|
181
182
|
- docs/tools.md
|
|
182
183
|
- docs/tutorial.md
|