rubik 0.1.1 → 0.1.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/ATTRIBUTION.md +10 -1
- data/CHANGELOG.md +29 -0
- data/README.md +16 -1
- data/lib/rubik/llm/anthropic.rb +42 -6
- data/lib/rubik/llm/registry.rb +4 -4
- data/lib/rubik/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a0ec56cafd854c2e2999c68cdfdf787322ca4d7d2a2866fac4b4e8ce9f1efac7
|
|
4
|
+
data.tar.gz: ec584d8ac5ee2039423d71968cce852afb65fcb072cbdbb87325ef94693e6a5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a535d5c0f45c74363387e7df47da8c87b1296be897fdd09adc17e4adfcc576b48555066cb0b3618d27f1eeeba052c53fe1ccb7a670598a43cad57bb8a4cc942
|
|
7
|
+
data.tar.gz: d75bb114c57fb2221f17f9d89a1a0fe1811b9e36ba52289337030b822210ef5373118e7d8438c4000da9dfca65fb4dadf3b5f85bdb8ad117ee50d56469c1a782
|
data/ATTRIBUTION.md
CHANGED
|
@@ -54,6 +54,15 @@ SOFTWARE.
|
|
|
54
54
|
- **Spatial Composability:** Reactive Coeffect Dependency DAG ($\Sigma \vdash C : \tau$) implemented in [`Rubik::Runtime::ComponentFiber`](lib/rubik/runtime/fiber.rb) and [`Rubik::Runtime::Manager`](lib/rubik/runtime/manager.rb).
|
|
55
55
|
- Zero-downtime hot reloading, atomic rollback on activation failure, and leak-free lifecycle management.
|
|
56
56
|
|
|
57
|
+
### SKILL.state (Structured Execution State)
|
|
58
|
+
- **Paper:** *"SKILL.state: Scalable Long-Horizon Agent Skills"* ([arXiv:2608.26263](https://arxiv.org/abs/2608.26263))
|
|
59
|
+
- **Authors:** Sanket Badhe, Priyanka Tiwari, Jonghyun Chung
|
|
60
|
+
- **Rubik Implementation:**
|
|
61
|
+
- The structured goal ledger ([`orchestrator/goal_ledger/`](lib/rubik/orchestrator/goal_ledger/), 2026-10-10): the `!goal` loop replaces append-only conversation memory with an explicit, mutable, rev-guarded execution state Σ (objective, tasks, findings, decisions, open questions, environment notes) — the model sees the current state, not an ever-growing history.
|
|
62
|
+
- Validated JSON-patch intake (RFC 6902 subset) with the `:syntax` / `:schema` / `:conflict` rejection taxonomy and bounded-retry model feedback (`GoalLedger::Patch` / `Schema` / `Validator`).
|
|
63
|
+
- The paper's world-drift recovery, coded as tri-state FS re-verification: declarative `verify` assertions are re-checked at step boundaries; a failed assertion flips the task to `stale` with an internal rev bump, so the `:conflict` the model then hits IS the drift signal (`GoalLedger::Verifier` / `VerifySpec` / `DriftNote`).
|
|
64
|
+
- Observation projection: banked tool results compact into per-row `<absorbed_into_ledger>` tombstones while the last K turns stay raw (`GoalLedger::ObservationProjection`).
|
|
65
|
+
|
|
57
66
|
---
|
|
58
67
|
|
|
59
68
|
## 🌳 3. AST Parsing & Multi-Language Ecosystem
|
|
@@ -112,7 +121,7 @@ SOFTWARE.
|
|
|
112
121
|
| **`strings-ansi`** | Piotr Murach | MIT | ANSI-aware string truncation and alignment for REPL formatters. |
|
|
113
122
|
| **`reline`** | Hiroshi SHIBATA & Ruby Team | Ruby License / BSD-2-Clause | Line-editing, history navigation, autocompletion hooks, and headless terminal adaptation. |
|
|
114
123
|
| **`prism`** | Kevin Newton & Ruby Core Team | MIT | High-performance Ruby parsing and AST extraction ([`Rubik::AST::RubyExtractor`](lib/rubik/ast/ruby_extractor.rb)). |
|
|
115
|
-
| **`minitest`** | Ryan Davis & seattlerb | MIT | Fast, modular test suite powering Rubik's
|
|
124
|
+
| **`minitest`** | Ryan Davis & seattlerb | MIT | Fast, modular test suite powering Rubik's 3,400+ unit, integration, and contract tests. |
|
|
116
125
|
| **`rubocop`** | Bozhidar Batsov & contributors | MIT | Static code analysis, style enforcement, and architectural hygiene gates. |
|
|
117
126
|
| **`benchmark`, `logger`, `pstore`, `reline`, `fiddle`** | Ruby core / rubygems teams | Ruby License / BSD-2-Clause | Ruby stdlib gems pinned explicitly in `rubik.gemspec` as they are unbundled from the default set in Ruby 3.4/3.5. |
|
|
118
127
|
|
data/CHANGELOG.md
CHANGED
|
@@ -10,8 +10,37 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
10
10
|
|
|
11
11
|
Nothing yet.
|
|
12
12
|
|
|
13
|
+
## [0.1.2] - 2026-10-11
|
|
14
|
+
|
|
15
|
+
The Anthropic correctness release: the provider now speaks the modern
|
|
16
|
+
extended-thinking contract, so pinning any current Claude model works
|
|
17
|
+
instead of failing with HTTP 400.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Anthropic provider speaks the modern thinking contract:** the
|
|
22
|
+
default model pin moves from the stale `claude-3-7-sonnet-20250219`
|
|
23
|
+
to `claude-sonnet-5-5`, and the extended-thinking payload follows the
|
|
24
|
+
model line ? 4.6+ and the 5.x/Fable models get the adaptive form
|
|
25
|
+
(`thinking: {type: "adaptive"}` with an `output_config` effort),
|
|
26
|
+
3-7-sonnet through the 4.5 line keep the `budget_tokens` math, and
|
|
27
|
+
pre-thinking lines get nothing attached. 0.1.1 sent the legacy form
|
|
28
|
+
to every Anthropic model, which Claude 4.7+ rejects with HTTP 400.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Extended thinking auto-enables on every thinking-capable Anthropic
|
|
33
|
+
model line (previously only claude-3-7-sonnet); `thinking: false`
|
|
34
|
+
still disables it everywhere and `thinking_budget_ratio` shapes the
|
|
35
|
+
legacy form only. Requests that carry thinking still force
|
|
36
|
+
`temperature` to 1.0.
|
|
37
|
+
- README quick start documents the native Anthropic provider
|
|
38
|
+
(`ANTHROPIC_API_KEY` + `!model anthropic/<model>`) next to the
|
|
39
|
+
OpenAI-compatible example.
|
|
40
|
+
|
|
13
41
|
## [0.1.1] - 2026-10-11
|
|
14
42
|
|
|
43
|
+
|
|
15
44
|
The Linux surface release: CI now proves Linux on Ruby 3.4 and 4.0
|
|
16
45
|
(`linux-test` is a required check), and the host seams that surface
|
|
17
46
|
exposed are fixed. Ships the structured goal ledger, the default-on
|
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@ English | [Türkçe](README.tr.md)
|
|
|
11
11
|
[](AGENTS.md)
|
|
12
12
|
[](COMMANDS.md)
|
|
13
13
|
[](CONFIG.md)
|
|
14
|
-
[]()
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -31,6 +31,12 @@ Requires **Ruby 3.4+**:
|
|
|
31
31
|
gem install rubik
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
The installer puts the `rubik` launcher into RubyGems' bin directory (already on your `PATH`), so you can start it from any project directory:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
rubik
|
|
38
|
+
```
|
|
39
|
+
|
|
34
40
|
or with Bundler:
|
|
35
41
|
|
|
36
42
|
```ruby
|
|
@@ -73,6 +79,9 @@ ln -sf $(pwd)/bin/rubik ~/.local/bin/rubik
|
|
|
73
79
|
rubik
|
|
74
80
|
```
|
|
75
81
|
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> **The gem and a clone can coexist.** On POSIX the symlink always runs your clone: `bin/rubik` resolves `lib/` from its own real path, so a `git pull` is live on the very next launch — even while the `rubik` gem stays installed. The gem-installed `rubik` keeps serving the last released version until you run `gem update rubik`. On Windows, whichever `bin` folder comes first in `PATH` wins — `where.exe rubik` shows the winner.
|
|
84
|
+
|
|
76
85
|
#### 🪟 Windows (PowerShell / Command Prompt)
|
|
77
86
|
|
|
78
87
|
Rubik ships with built-in `.cmd`, `.bat`, and `.ps1` wrappers for Windows:
|
|
@@ -105,6 +114,12 @@ rubik > !provider add deepseek openai_compatible https://api.deepseek.com/v1/cha
|
|
|
105
114
|
rubik > !model deepseek/deepseek-coder
|
|
106
115
|
```
|
|
107
116
|
|
|
117
|
+
Anthropic talks over its **native Messages API** (not an OpenAI shim): the `anthropic` provider is registered out of the box — set `ANTHROPIC_API_KEY` and pick a model:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
rubik > !model anthropic/claude-sonnet-5-5
|
|
121
|
+
```
|
|
122
|
+
|
|
108
123
|
### First Session Example
|
|
109
124
|
|
|
110
125
|
```text
|
data/lib/rubik/llm/anthropic.rb
CHANGED
|
@@ -9,7 +9,32 @@ module Rubik
|
|
|
9
9
|
class AnthropicProvider < BaseProvider
|
|
10
10
|
attr_reader :name, :model, :formatter, :headers, :api_key, :api_key_env
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Extended-thinking support by model line (Anthropic docs, 2026-10):
|
|
13
|
+
# :adaptive — 4.6+ and the 5.x/Fable lines: `thinking: {type: "adaptive"}`
|
|
14
|
+
# with an `output_config` effort; the legacy budget_tokens form is
|
|
15
|
+
# REJECTED with a 400 from 4.7 onward.
|
|
16
|
+
# :legacy — claude-3-7-sonnet through the 4.5 line: the manual
|
|
17
|
+
# `thinking: {type: "enabled", budget_tokens: N}` form is the only
|
|
18
|
+
# accepted mode.
|
|
19
|
+
# nil — 3.5-and-earlier lines accept no thinking at all, and
|
|
20
|
+
# unrecognized names (custom aliases/proxies) get no auto thinking.
|
|
21
|
+
def self.thinking_mode_for(model_name)
|
|
22
|
+
s = model_name.to_s
|
|
23
|
+
return :legacy if s.include?("claude-3-7-sonnet")
|
|
24
|
+
return nil if s.match?(/\Aclaude-[23]/) # number-first 2.x/3.x lines (3-7 handled above)
|
|
25
|
+
|
|
26
|
+
# Single-digit captures: Anthropic versions are one digit per segment,
|
|
27
|
+
# so a snapshot date suffix (claude-sonnet-4-20250514) can never be
|
|
28
|
+
# swallowed as the minor version.
|
|
29
|
+
version = s.match(/\Aclaude-(?:sonnet|opus|haiku|fable)-(\d)(?:-(\d))?/)
|
|
30
|
+
return nil unless version
|
|
31
|
+
|
|
32
|
+
major = version[1].to_i
|
|
33
|
+
minor = version[2].to_i
|
|
34
|
+
major > 4 || (major == 4 && minor >= 6) ? :adaptive : :legacy
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize(name: nil, model: "claude-sonnet-5-5", formatter: AnthropicFormatter.new, headers: {},
|
|
13
38
|
api_key: nil, api_key_env: nil)
|
|
14
39
|
super()
|
|
15
40
|
@name = name.to_s.downcase
|
|
@@ -170,14 +195,25 @@ module Rubik
|
|
|
170
195
|
thinking_opt = opts[:thinking]
|
|
171
196
|
thinking_disabled = [false, :disabled].include?(thinking_opt)
|
|
172
197
|
ratio = (opts[:thinking_budget_ratio] || 0.5).to_f
|
|
198
|
+
# Thinking is on for every model line that supports it unless
|
|
199
|
+
# explicitly disabled; thinking_budget_ratio only shapes the legacy
|
|
200
|
+
# budget form — adaptive models reason as they see fit.
|
|
201
|
+
mode = self.class.thinking_mode_for(target_model)
|
|
173
202
|
|
|
174
203
|
if thinking_opt.is_a?(Hash)
|
|
175
204
|
payload[:thinking] = thinking_opt
|
|
176
|
-
elsif !thinking_disabled && (thinking_opt == true ||
|
|
177
|
-
if
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
205
|
+
elsif !thinking_disabled && (thinking_opt == true || mode)
|
|
206
|
+
if mode == :legacy
|
|
207
|
+
if max_tokens > 2048
|
|
208
|
+
budget = [(max_tokens * ratio).to_i, 1024].max
|
|
209
|
+
budget = [budget, max_tokens - 1024].min
|
|
210
|
+
payload[:thinking] = { type: "enabled", budget_tokens: budget } if budget >= 1024
|
|
211
|
+
end
|
|
212
|
+
else
|
|
213
|
+
# Adaptive models reject the legacy form outright, and for
|
|
214
|
+
# unrecognized names adaptive is the modern-generation default.
|
|
215
|
+
payload[:thinking] = { type: "adaptive" }
|
|
216
|
+
payload[:output_config] = { effort: "high" }
|
|
181
217
|
end
|
|
182
218
|
end
|
|
183
219
|
|
data/lib/rubik/llm/registry.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Rubik
|
|
|
38
38
|
@providers = {
|
|
39
39
|
"ollama" => OllamaProvider.new(model: "qwen2.5-coder:7b", headers: global_headers),
|
|
40
40
|
"openai" => OpenAIProvider.new(model: "gpt-4o", headers: global_headers),
|
|
41
|
-
"anthropic" => AnthropicProvider.new(model: "claude-
|
|
41
|
+
"anthropic" => AnthropicProvider.new(model: "claude-sonnet-5-5", headers: global_headers)
|
|
42
42
|
}
|
|
43
43
|
@models_catalog = {}
|
|
44
44
|
load_from_config(config) if config
|
|
@@ -82,7 +82,7 @@ module Rubik
|
|
|
82
82
|
end
|
|
83
83
|
if @providers["anthropic"].instance_of?(AnthropicProvider)
|
|
84
84
|
@providers["anthropic"] = AnthropicProvider.new(
|
|
85
|
-
model: @providers["anthropic"]&.model || "claude-
|
|
85
|
+
model: @providers["anthropic"]&.model || "claude-sonnet-5-5",
|
|
86
86
|
headers: global_headers
|
|
87
87
|
)
|
|
88
88
|
end
|
|
@@ -132,7 +132,7 @@ module Rubik
|
|
|
132
132
|
when "anthropic"
|
|
133
133
|
AnthropicProvider.new(
|
|
134
134
|
name: p_name,
|
|
135
|
-
model: default_model || "claude-
|
|
135
|
+
model: default_model || "claude-sonnet-5-5",
|
|
136
136
|
# Honor the same api_key / api_key_env that
|
|
137
137
|
# openai-compatible specs already forward;
|
|
138
138
|
# otherwise Anthropic auth fails silently.
|
|
@@ -257,7 +257,7 @@ module Rubik
|
|
|
257
257
|
when "anthropic"
|
|
258
258
|
anthropic_headers = (custom.respond_to?(:headers) ? custom.headers : nil) || global_headers
|
|
259
259
|
AnthropicProvider.new(
|
|
260
|
-
model: model_name || "claude-
|
|
260
|
+
model: model_name || "claude-sonnet-5-5",
|
|
261
261
|
headers: anthropic_headers,
|
|
262
262
|
api_key: custom.respond_to?(:api_key) ? custom.api_key : nil,
|
|
263
263
|
api_key_env: custom.respond_to?(:api_key_env) ? custom.api_key_env : nil
|
data/lib/rubik/version.rb
CHANGED