llm.rb 16.0.0.pre.1 → 16.0.0.pre.3

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: 89404c839d44cd5a11c59fdd56d396a64f50447996a03c01216eb928aed4c28a
4
- data.tar.gz: f040e94e577c068690b7bae08900468408d1dd0985bd6d40ebc239eab60ea4a8
3
+ metadata.gz: a8bd3b4f303036ba390981de3ec63ea0bb523cc653c4b77b221e4591e9b9a446
4
+ data.tar.gz: 3036ce3c4248e3ddad524657f31ea2c300f98282ad0aa68791848f56cd1b91f5
5
5
  SHA512:
6
- metadata.gz: c466492b003222fd3411b2777aa982663e50330600a2b69c1bd7d2fce9180576ccfc59230140fb392d584a1dddf45307c09fc785b7c7fc06d158aa3ec11230c7
7
- data.tar.gz: 2da69855287105e2926045fdef7ef346be4fc4189f5e8659eb03829e85ae136a4fc5660506dee14ef7c933775e6790bacda9acedf1e4d4c438b61fc4730a584c
6
+ metadata.gz: 604bafd36e8a55405e3fc487957ae97b9e4ffd67777711c071f7bfb9cfe005e0400294c089e72fbec3019538f4706c92cfe5bb15f3d0c2f994a324b9ba1a3322
7
+ data.tar.gz: d3bf4d7e1f9337cd7bdedb40ac4cfb4f95b6195e6df3360d428bfa6c220994edfaf8c5f053256e968c1feb9ae025b29854586dd9834dc84948729644f7a7b8ff
data/CHANGELOG.md CHANGED
@@ -22,6 +22,7 @@
22
22
  | Old | New |
23
23
  |-----|-----|
24
24
  | Ruby 3.3 or later | Ruby 3.4 or later |
25
+ | `record.messages` returns the messages the runtime holds | a `:jsonb` record returns a relation of `LLM::ActiveRecord::Message` rows |
25
26
 
26
27
  * **drop Ruby 3.3 support** <br>
27
28
  The gem now requires Ruby 3.4 or later: `required_ruby_version` is
@@ -30,6 +31,21 @@
30
31
  cancel that arrives before the tool starts is not delivered there, while
31
32
  Ruby 3.4 and 4.0 both deliver it.
32
33
 
34
+ * **activerecord: read a `:jsonb` record's messages from the column** <br>
35
+ [`LLM::ActiveRecord`](https://r.uby.dev/api-docs/llm.rb/LLM/ActiveRecord.html)
36
+ now answers `#messages` for a record whose `format` is `:jsonb` with an
37
+ [`ActiveRecord::Relation`](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html)
38
+ over the column, through
39
+ [`LLM::ActiveRecord::Message`](https://r.uby.dev/api-docs/llm.rb/LLM/ActiveRecord/Message.html),
40
+ so a conversation can be filtered, counted, and ordered in SQL, and reading it
41
+ needs no provider and no credentials. Before this, every record loaded the
42
+ runtime and returned the messages it held, whatever the format. The relation
43
+ is not a drop-in replacement for that buffer: it reads what is persisted
44
+ rather than what a runtime holds in memory, it is unordered, so order by
45
+ `position`, and its rows answer `unwrap!` rather than being
46
+ [`LLM::Message`](https://r.uby.dev/api-docs/llm.rb/LLM/Message.html) objects.
47
+ Every other format, and Sequel, still loads the runtime.
48
+
33
49
  ### Console
34
50
 
35
51
  * **console: erase with the backspace key on OpenBSD** <br>
@@ -39,18 +55,25 @@
39
55
  terminal's terminfo describes the key. All three erase. Before this only 127
40
56
  did, so the backspace key did nothing on the OpenBSD console.
41
57
 
58
+ ### Fix
59
+
60
+ * **fork: require xchan.rb `~> 0.24`** <br>
61
+ The `:fork` concurrency strategy now requires the `xchan.rb` gem at `~> 0.24`
62
+ instead of `~> 0.23`, and the gemspec's development dependency follows. An
63
+ application that uses `:fork` needs `xchan.rb` 0.24 or later.
64
+
42
65
  ### Function
43
66
 
44
67
  * **function: deliver an interrupt to the tool, not to whatever is running** <br>
45
68
  [`LLM::Function::Window`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Window.html)
46
- is the stretch of a call that an interrupt belongs to. The `:fork` and
47
- `:ractor` strategies now raise `LLM::Interrupt` on the thread that runs
48
- the tool, and only while the tool runs: a cancel that arrives before the
49
- tool starts is held until it does, so the tool's own `rescue` can handle
50
- it, and one that arrives after the tool has returned is a no-op, which no
51
- longer throws the result away. Before this, the interrupt was raised on
52
- the child process's or the ractor's main thread wherever that thread had
53
- got to.
69
+ is the stretch of a call that an interrupt belongs to. The `:fork` and `:ractor`
70
+ strategies now raise
71
+ [`LLM::Interrupt`](https://r.uby.dev/api-docs/llm.rb/LLM/Interrupt.html) on the
72
+ thread that runs the tool, and only while the tool runs: a cancel that arrives
73
+ before the tool starts is held until it does, so the tool's own `rescue` can
74
+ handle it, and one that arrives after the tool has returned is a no-op, which
75
+ no longer throws the result away. Before this, the interrupt was raised on the
76
+ child process's or the ractor's main thread wherever that thread had got to.
54
77
 
55
78
  * **function: answer a ractor-backed task once its ractor has gone** <br>
56
79
  A `:ractor` tool's result is handed to a ractor the task holds it in,
@@ -68,6 +91,30 @@
68
91
  error, and a group's cancel stopped at the first task that had already
69
92
  returned, leaving the calls after it uncancelled.
70
93
 
94
+ * **function: tell an `:async` tool it was cancelled** <br>
95
+ A cancel now raises `LLM::Interrupt` on the fiber the tool runs in, through the
96
+ reactor's scheduler, so the tool is told and can answer with its own value. A
97
+ cancel that arrives before the tool started stops it from running, and the
98
+ reactor is stopped by whoever waits. Before this, the cancel pushed an
99
+ interrupt sentinel to the task's result queue and left the tool running, its
100
+ side effects happening and its result written to a queue nobody read, and the
101
+ reactor thread stayed alive until a group's `wait` stopped it.
102
+
103
+ * **function: run the interrupt hook on every strategy** <br>
104
+ A tool that implements
105
+ [`LLM::Tool#on_interrupt`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html#on_interrupt-instance_method)
106
+ or
107
+ [`LLM::Tool#on_cancel`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html#on_cancel-instance_method)
108
+ is now told on every concurrency strategy. `:thread`, `:fiber`, and `:async`
109
+ run the hook on the thread or fiber that ran the call, `:fork` and `:ractor`
110
+ run it inside the child or the ractor before the interrupt is delivered, and
111
+ a sequential group's cancel tells every task it holds. Before this, `:async`,
112
+ `:fork`, and `:ractor` never ran the hook, the others ran it on the thread
113
+ that cancelled, and a class-backed tool ran it on no strategy at all, because
114
+ `interrupt!` read the hook off the tool's definition and a class answers
115
+ `respond_to?` with false for an instance method. A hook that raises becomes
116
+ what the caller sees in place of the call's result.
117
+
71
118
  ### Provider
72
119
 
73
120
  * **deepseek: support image attachments in chat completions** <br>
@@ -88,13 +135,26 @@
88
135
  `qwen3.5-flash`, `qwen3.7-flash`, and `qwen3.8-omni-flash`, and gives
89
136
  `qwen3.7-plus` attachments, structured output, and a lower price; OpenAI adds
90
137
  `gpt-daybreak-blue-latest` and `gpt-daybreak-red-latest`; Bedrock adds
91
- `openai.gpt-6-sol` and `openai.gpt-6-luna`; and DeepInfra adds
92
- `tencent/Hy4-preview` and the Xiaomi MiMo V2.6 Pro and V2.6 Flash models.
138
+ `openai.gpt-6-sol`, `openai.gpt-6-luna`, and
139
+ `global.anthropic.claude-sonnet-5-5`; and DeepInfra adds `tencent/Hy4-preview`
140
+ and the Xiaomi MiMo V2.6 Pro and V2.6 Flash models.
93
141
  Bedrock also corrects the context and output limits of fifteen models, Google
94
142
  lowers the limits of `gemini-2.5-computer-use-preview-10-2025` and
95
- `gemini-3-pro-image`, and OpenRouter adds four models, drops six, and reprices
143
+ `gemini-3-pro-image`, and OpenRouter adds five models, drops six, and reprices
96
144
  many of the DeepSeek, Z.ai, and Qwen entries.
97
145
 
146
+ ### Schema
147
+
148
+ * **schema: apply every `parameter` option to the leaf** <br>
149
+ [`LLM::Tool`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html) now applies each
150
+ option given to `parameter` to the leaf its type resolves to, so settings such
151
+ as `min:`, `max:`, `multiple_of:`, and `const:` reach the schema instead of
152
+ being dropped. Before this only `required`, `default`, and `enum` were read, so
153
+ `parameter :age, Integer, "Age", min: 1, max: 9` sent a plain integer and lost
154
+ the range. A `default:` of `false` survives now as well, where the old code
155
+ discarded a false default, and `required: false` marks the parameter optional
156
+ rather than being ignored.
157
+
98
158
  ## v15.5.0
99
159
 
100
160
  Changes since `v15.4.1`.
data/README.md CHANGED
@@ -18,16 +18,21 @@ llm.rb is a runtime for building agentic AI applications
18
18
  on CRuby. It has zero runtime dependencies by default, supports
19
19
  concurrent and parallel tool execution and has a single coherent API
20
20
  that spans 14+ providers.
21
+ The README covers the common cases. For everything else there is the
22
+ [deepdive](docs/deepdive.md), a reference with a chapter for each
23
+ topic, and for what changes between releases there is the
24
+ [changelog](CHANGELOG.md).
21
25
 
22
- See llm.rb in action on the
23
- [the r.uby.dev website](https://r.uby.dev) where
24
- I am building a platform that supports users who have
25
- personalized agents with access to different services
26
- (eg GitHub, etc). Check it out if curious.
27
- **Still in early development.**
26
+ [The r.uby.dev website](https://r.uby.dev) hosts
27
+ an agentic platform that provides users with
28
+ personalized agents who can access GitHub, and
29
+ other services. It is built with llm.rb. Check it
30
+ out if curious. **Still in early development.**
28
31
 
29
32
  ## Install
30
33
 
34
+ llm.rb requires Ruby 3.4 or later.
35
+
31
36
  ```bash
32
37
  gem install llm.rb
33
38
  ```
data/data/alibaba.json CHANGED
@@ -90,7 +90,8 @@
90
90
  "output": 0.4,
91
91
  "cache_read": 0.01,
92
92
  "cache_write": 0.125
93
- }
93
+ },
94
+ "canonical_model_id": "alibaba/qwen3.5-flash"
94
95
  },
95
96
  "qwen3.7-max": {
96
97
  "id": "qwen3.7-max",
@@ -349,7 +350,8 @@
349
350
  "input": 0.2,
350
351
  "output": 0.4,
351
352
  "cache_read": 0.04
352
- }
353
+ },
354
+ "canonical_model_id": "deepseek/deepseek-v4-flash-0731"
353
355
  },
354
356
  "qwen-max": {
355
357
  "id": "qwen-max",
@@ -470,7 +472,8 @@
470
472
  "output": 6,
471
473
  "cache_read": 0.25,
472
474
  "cache_write": 2.5
473
- }
475
+ },
476
+ "canonical_model_id": "alibaba/qwen3.8-max"
474
477
  },
475
478
  "kimi-k3": {
476
479
  "id": "kimi-k3",
@@ -515,7 +518,8 @@
515
518
  "input": 3,
516
519
  "output": 15,
517
520
  "cache_read": 0.3
518
- }
521
+ },
522
+ "canonical_model_id": "moonshotai/kimi-k3"
519
523
  },
520
524
  "qwen-plus-character-ja": {
521
525
  "id": "qwen-plus-character-ja",
@@ -799,7 +803,8 @@
799
803
  }
800
804
  }
801
805
  ]
802
- }
806
+ },
807
+ "canonical_model_id": "alibaba/qwen3.7-flash"
803
808
  },
804
809
  "qwen3-max": {
805
810
  "id": "qwen3-max",
@@ -1046,7 +1051,8 @@
1046
1051
  "input": 0.15,
1047
1052
  "output": 0.47,
1048
1053
  "cache_read": 0.016
1049
- }
1054
+ },
1055
+ "canonical_model_id": "alibaba/qwen3.8-omni-flash"
1050
1056
  },
1051
1057
  "qvq-max": {
1052
1058
  "id": "qvq-max",
@@ -1685,7 +1691,8 @@
1685
1691
  "output": 0.47,
1686
1692
  "cache_read": 0.016,
1687
1693
  "cache_write": 0.2
1688
- }
1694
+ },
1695
+ "canonical_model_id": "alibaba/qwen3.8-flash"
1689
1696
  },
1690
1697
  "qwen2-5-vl-7b-instruct": {
1691
1698
  "id": "qwen2-5-vl-7b-instruct",
@@ -1956,7 +1963,8 @@
1956
1963
  "output": 4.4,
1957
1964
  "cache_read": 0.28,
1958
1965
  "cache_write": 0
1959
- }
1966
+ },
1967
+ "canonical_model_id": "zhipuai/glm-5.2"
1960
1968
  },
1961
1969
  "qwen-omni-turbo": {
1962
1970
  "id": "qwen-omni-turbo",
data/data/anthropic.json CHANGED
@@ -46,7 +46,8 @@
46
46
  "output": 5,
47
47
  "cache_read": 0.1,
48
48
  "cache_write": 1.25
49
- }
49
+ },
50
+ "canonical_model_id": "anthropic/claude-haiku-4-5"
50
51
  },
51
52
  "claude-opus-4-5": {
52
53
  "id": "claude-opus-4-5",
@@ -95,7 +96,8 @@
95
96
  "output": 25,
96
97
  "cache_read": 0.5,
97
98
  "cache_write": 6.25
98
- }
99
+ },
100
+ "canonical_model_id": "anthropic/claude-opus-4-5"
99
101
  },
100
102
  "claude-sonnet-4-5": {
101
103
  "id": "claude-sonnet-4-5",
@@ -136,7 +138,8 @@
136
138
  "output": 15,
137
139
  "cache_read": 0.3,
138
140
  "cache_write": 3.75
139
- }
141
+ },
142
+ "canonical_model_id": "anthropic/claude-sonnet-4-5"
140
143
  },
141
144
  "claude-opus-5-5": {
142
145
  "id": "claude-opus-5-5",
@@ -203,7 +206,8 @@
203
206
  "output": 20,
204
207
  "cache_read": 0.2,
205
208
  "cache_write": 5
206
- }
209
+ },
210
+ "canonical_model_id": "anthropic/claude-opus-5-5"
207
211
  },
208
212
  "claude-fable-5-1": {
209
213
  "id": "claude-fable-5-1",
@@ -250,7 +254,8 @@
250
254
  "output": 50,
251
255
  "cache_read": 0.25,
252
256
  "cache_write": 12.5
253
- }
257
+ },
258
+ "canonical_model_id": "anthropic/claude-fable-5-1"
254
259
  },
255
260
  "claude-opus-4-5-20251101": {
256
261
  "id": "claude-opus-4-5-20251101",
@@ -366,7 +371,8 @@
366
371
  "output": 25,
367
372
  "cache_read": 0.5,
368
373
  "cache_write": 6.25
369
- }
374
+ },
375
+ "canonical_model_id": "anthropic/claude-opus-5"
370
376
  },
371
377
  "claude-fable-5": {
372
378
  "id": "claude-fable-5",
@@ -713,6 +719,54 @@
713
719
  "cache_write": 3.75
714
720
  }
715
721
  },
722
+ "claude-sonnet-5-5": {
723
+ "id": "claude-sonnet-5-5",
724
+ "name": "Claude Sonnet 5.5",
725
+ "description": "Fast Claude model for everyday coding, agents, and knowledge work",
726
+ "family": "claude-sonnet",
727
+ "attachment": true,
728
+ "reasoning": true,
729
+ "reasoning_options": [
730
+ {
731
+ "type": "effort",
732
+ "values": [
733
+ "low",
734
+ "medium",
735
+ "high",
736
+ "xhigh",
737
+ "max"
738
+ ]
739
+ }
740
+ ],
741
+ "tool_call": true,
742
+ "structured_output": true,
743
+ "temperature": false,
744
+ "knowledge": "2026-06",
745
+ "release_date": "2026-09-28",
746
+ "last_updated": "2026-09-28",
747
+ "modalities": {
748
+ "input": [
749
+ "text",
750
+ "image",
751
+ "pdf"
752
+ ],
753
+ "output": [
754
+ "text"
755
+ ]
756
+ },
757
+ "open_weights": false,
758
+ "limit": {
759
+ "context": 1000000,
760
+ "output": 128000
761
+ },
762
+ "cost": {
763
+ "input": 2,
764
+ "output": 10,
765
+ "cache_read": 0.2,
766
+ "cache_write": 2.5
767
+ },
768
+ "canonical_model_id": "anthropic/claude-sonnet-5-5"
769
+ },
716
770
  "claude-opus-4-7": {
717
771
  "id": "claude-opus-4-7",
718
772
  "name": "Claude Opus 4.7",