llm.rb 12.6.0 → 13.0.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +387 -0
  3. data/LICENSE +21 -93
  4. data/README.md +46 -155
  5. data/data/deepinfra.json +3 -0
  6. data/data/xai.json +1 -1
  7. data/lib/llm/a2a.rb +1 -1
  8. data/lib/llm/active_record/acts_as_llm.rb +6 -6
  9. data/lib/llm/agent.rb +62 -23
  10. data/lib/llm/buffer.rb +85 -3
  11. data/lib/llm/compactor/null.rb +19 -0
  12. data/lib/llm/compactor/truncate.rb +80 -0
  13. data/lib/llm/compactor.rb +42 -124
  14. data/lib/llm/context.rb +31 -37
  15. data/lib/llm/contract.rb +4 -25
  16. data/lib/llm/function/array.rb +15 -14
  17. data/lib/llm/function/async/group.rb +54 -0
  18. data/lib/llm/function/async/reactor.rb +48 -0
  19. data/lib/llm/function/async/task.rb +83 -0
  20. data/lib/llm/function/fiber/group.rb +46 -0
  21. data/lib/llm/function/fiber/task.rb +62 -0
  22. data/lib/llm/function/{fork_group.rb → fork/group.rb} +14 -5
  23. data/lib/llm/function/fork/job.rb +2 -2
  24. data/lib/llm/function/fork/task.rb +19 -10
  25. data/lib/llm/function/group.rb +40 -0
  26. data/lib/llm/function/{ractor_group.rb → ractor/group.rb} +13 -5
  27. data/lib/llm/function/ractor/job.rb +9 -3
  28. data/lib/llm/function/ractor/mailbox.rb +2 -0
  29. data/lib/llm/function/ractor/task.rb +23 -15
  30. data/lib/llm/function/{call_group.rb → sequential/group.rb} +12 -8
  31. data/lib/llm/function/sequential/task.rb +49 -0
  32. data/lib/llm/function/task.rb +25 -48
  33. data/lib/llm/function/thread/group.rb +46 -0
  34. data/lib/llm/function/thread/task.rb +60 -0
  35. data/lib/llm/function.rb +54 -64
  36. data/lib/llm/loop_guard.rb +1 -2
  37. data/lib/llm/mcp.rb +22 -0
  38. data/lib/llm/object.rb +2 -1
  39. data/lib/llm/provider.rb +6 -3
  40. data/lib/llm/providers/google.rb +2 -2
  41. data/lib/llm/repl/command.rb +35 -8
  42. data/lib/llm/repl/commands/compact.rb +33 -0
  43. data/lib/llm/repl/input.rb +80 -15
  44. data/lib/llm/repl/markdown/table.rb +76 -0
  45. data/lib/llm/repl/markdown.rb +31 -1
  46. data/lib/llm/repl/status.rb +1 -1
  47. data/lib/llm/repl/stream.rb +10 -3
  48. data/lib/llm/repl/transcript.rb +1 -1
  49. data/lib/llm/repl/walker.rb +46 -0
  50. data/lib/llm/repl.rb +18 -12
  51. data/lib/llm/response.rb +10 -0
  52. data/lib/llm/schema/leaf.rb +5 -0
  53. data/lib/llm/schema/object.rb +11 -5
  54. data/lib/llm/sequel/plugin.rb +6 -6
  55. data/lib/llm/stream.rb +24 -17
  56. data/lib/llm/tool.rb +20 -4
  57. data/lib/llm/tools/chdir.rb +0 -2
  58. data/lib/llm/tools/git.rb +8 -4
  59. data/lib/llm/tools/mkdir.rb +1 -1
  60. data/lib/llm/tools/pwd.rb +0 -2
  61. data/lib/llm/tools/read_file.rb +0 -2
  62. data/lib/llm/tools/rg.rb +8 -4
  63. data/lib/llm/tools/shell.rb +8 -4
  64. data/lib/llm/tools/utils.rb +31 -0
  65. data/lib/llm/version.rb +1 -1
  66. data/lib/llm.rb +25 -5
  67. data/llm.gemspec +3 -3
  68. data/resources/deepdive.md +645 -58
  69. metadata +24 -13
  70. data/lib/llm/function/call_task.rb +0 -46
  71. data/lib/llm/function/fiber_group.rb +0 -105
  72. data/lib/llm/function/task_group.rb +0 -97
  73. data/lib/llm/function/thread_group.rb +0 -102
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1660ea34a112d4c31eb8c9a51000ecd244b0f5629a4f763eceecd734d96f765b
4
- data.tar.gz: 8040eefe13ffc48a40181642dad749d6abd7d16950f5d9e379ef006a0bb5af0c
3
+ metadata.gz: a0304f2a840c94209256729edf114209ffab0bdd309d1a25172818458e4c3f4f
4
+ data.tar.gz: 46c695d1722ef6e618f27eb9b433f77774bf9140bfd31983589946be3ce53c1e
5
5
  SHA512:
6
- metadata.gz: cc1821c04eb0f996ca3e5d86d1722565e1fe2bc13351f3771c57de556d7ee9e97d930b3516ec70dea9686fad6443498c40d50584c6065a95242318f054a98d83
7
- data.tar.gz: 3cc468ef1332c6f39d6b34a6a11fafe91eaf459ed80d5e79709f8106278fcb6fa1ba4f67b701a38539c3cba4d6967ad88858cccb4bb6b5b12690290036ad2afb
6
+ metadata.gz: 0a9da53406a6e612f68412005d33b0e85bf6064c9c38ff70e5cd2290f8b381bbba9ae9becd6ca71b15fed399e1d84bdd55972301d0cdb51c10d528d00f5a5d8f
7
+ data.tar.gz: 882a041334ad21b83397792e3921510c0298b0c623b6c05441117f5655ac1fbe35b560cb015b29bcbd0aad526cc772d9e58596567c72d456d3ee77adc372f397
data/CHANGELOG.md CHANGED
@@ -15,6 +15,393 @@
15
15
 
16
16
  ## What's next
17
17
 
18
+ _No unreleased changes yet._
19
+
20
+ ## v13.0.0
21
+
22
+ v13.0.0 relicenses the project under the MIT license, replacing
23
+ the Business Source License that was introduced in v12.0.0. No
24
+ commercial license is needed. Commercial, personal, educational, and
25
+ all other uses are now permitted under the standard MIT terms.
26
+
27
+ Seven breaking changes. Concurrency strategies have been renamed
28
+ (`:call` → `:sequential`, `:task` → `:async`), `spawn` is now
29
+ `task`, and the `:async` strategy has been rebuilt from the ground
30
+ up. It no longer blocks and now supports interruption. The compactor
31
+ has been refactored into pluggable strategies. Interruption is now
32
+ reliable across all six concurrency backends. The `functions` and
33
+ `functions?` methods have been renamed to `pending_functions` and
34
+ `pending_functions?`.
35
+
36
+ ### Migration from v12.6.0
37
+
38
+ | Old | New |
39
+ |-----|-----|
40
+ | `fn.spawn(:call)` | `fn.task(:sequential)` |
41
+ | `fn.spawn(:task)` | `fn.task(:async)` |
42
+ | `ctx.wait(:call)` | `ctx.wait(:sequential)` |
43
+ | `agent.concurrency :task` | `agent.concurrency :async` |
44
+ | `LLM::Function::FiberGroup` | `LLM::Function::Fiber::Group` |
45
+ | `LLM::Function::CallGroup` | `LLM::Function::Sequential::Group` |
46
+ | `LLM::Function::TaskGroup` | `LLM::Function::Async::Group` |
47
+ | `Compactor.new(model:, token_threshold:)` | `Compactor::Truncate.new(ctx)` |
48
+ | `on_compaction(ctx, compactor)` | `on_compaction(compactor)` |
49
+ | `ctx.functions` / `ctx.functions?` | `ctx.pending_functions` / `ctx.pending_functions?` |
50
+ | `agent.functions` / `agent.functions?` | `agent.pending_functions` / `agent.pending_functions?` |
51
+
52
+ ### Breaking
53
+
54
+ * **rename `LLM::Function#spawn` as `LLM::Function#task`** <br>
55
+ [`LLM::Function#task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#task-instance_method)
56
+ (previously `spawn`) now consistently returns a
57
+ [`LLM::Function::Task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Task.html)
58
+ object that can be spawned, waited on, and passed to
59
+ [`LLM::Function::Group`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Group.html).
60
+ The old implementation alternated between spawning immediately or
61
+ returning a raw thread or fiber.
62
+
63
+ * **rename concurrency strategies (`:call` → `:sequential`,**
64
+ **`:task` → `:async`)** <br>
65
+ The `:call` concurrency strategy is now `:sequential`, and the `:task`
66
+ strategy is now `:async`.
67
+ [`LLM::Agent.concurrency`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#concurrency-class_method),
68
+ [`LLM::Context#wait`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#wait-instance_method),
69
+ `LLM::Function::Array#task`, and
70
+ [`LLM::Function#task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#task-instance_method)
71
+ all accept the new names. The old names raise `ArgumentError`.
72
+
73
+ * **rename group classes** <br>
74
+ Group classes have been moved into their strategy's namespace:
75
+ `FiberGroup` → `Fiber::Group`, `ThreadGroup` → `Thread::Group`,
76
+ `CallGroup` → `Sequential::Group`, `TaskGroup` → `Async::Group`,
77
+ `Fork::Group` → `Fork::Group`, `Ractor::Group` → `Ractor::Group`.
78
+
79
+ * **repurpose `LLM::Function::Task` as a task interface superclass** <br>
80
+ `LLM::Function::Task` has been repurposed from a general-purpose class
81
+ that tried to support multiple concurrency strategies into an abstract
82
+ base class that defines the task interface. Individual strategies
83
+ (`Sequential::Task`, `Thread::Task`, `Fiber::Task`, `Async::Task`,
84
+ `Fork::Task`, `Ractor::Task`) now subclass it and implement
85
+ `spawn`, `alive?`, `interrupt!`, and `wait`.
86
+
87
+ * **fix `:async` concurrency (now backed by a managed**
88
+ **`LLM::Function::Async::Reactor` on a background thread)** <br>
89
+ The `:async` strategy previously used `Async {}` which blocked the
90
+ caller until all tasks completed and did not support interruption.
91
+ The fix replaces it with a per-turn
92
+ `LLM::Function::Async::Reactor` on a background thread. Work is
93
+ submitted via `submit(&block)` and consumed by the reactor's event
94
+ loop through a thread-safe `Queue`. `Async::Group` manages the
95
+ reactor lifecycle and spawns tasks lazily on `wait`.
96
+ <br><br>
97
+ Interruption pushes [`LLM::Interrupt`](https://r.uby.dev/api-docs/llm.rb/LLM/Interrupt.html)
98
+ to the task's result queue instead of using `Fiber#raise`, and
99
+ results are bridged back to the caller through a second `Queue`.
100
+ This work drove the broader refactor of strategy naming, the
101
+ spawn/wait split, and the `Task` superclass. The `:async` strategy
102
+ needed the same interface the other strategies already had.
103
+
104
+ * **compactor: refactor to strategy-based interface** <br>
105
+ [`LLM::Compactor`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor.html)
106
+ has been refactored from a single class that performed LLM-based
107
+ summarization into a strategy-based superclass. Each subclass
108
+ implements a different compaction strategy via `call(**opts)`. The old
109
+ summarization approach (using `model:`, `token_threshold:`,
110
+ `message_threshold:`, and `retention_window:` options) has been removed.
111
+ The built-in
112
+ [`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html)
113
+ strategy drops the oldest messages when the conversation exceeds a
114
+ configured size.
115
+
116
+ * **rename `LLM::Context#{functions,functions?}` and `LLM::Agent#{functions,functions?}`** <br>
117
+ [`LLM::Context#functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#functions-instance_method)
118
+ and
119
+ [`LLM::Context#functions?`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#functions%3F-instance_method)
120
+ have been renamed to
121
+ [`LLM::Context#pending_functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#pending_functions-instance_method)
122
+ and
123
+ [`LLM::Context#pending_functions?`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#pending_functions%3F-instance_method)
124
+ respectively. The same rename applies to
125
+ [`LLM::Agent#functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#functions-instance_method)
126
+ (now
127
+ [`LLM::Agent#pending_functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#pending_functions-instance_method)).
128
+ The `pending_functions` name was already available as an alias in
129
+ v12.5.0; this change removes the old `functions` name entirely.
130
+
131
+ ### Core
132
+
133
+ * **extend `LLM.require` with an optional version argument** <br>
134
+ `LLM.require` now accepts a second `version` parameter that is passed
135
+ to `Kernel#gem` before loading, enabling version constraints for
136
+ optional runtime dependencies. For example,
137
+ `LLM.require "test-cmd.rb", "~> 1.1"` ensures a minimum gem version
138
+ is available. This is used internally by the `Git`, `Rg`, `Mkdir`,
139
+ and `Shell` tools to enforce compatibility with the `test-cmd.rb` gem.
140
+
141
+ ### Compactor
142
+
143
+ * **add `Truncate` strategy for dropping oldest messages** <br>
144
+ [`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html)
145
+ is a new built-in compaction strategy that drops the oldest messages
146
+ when the conversation exceeds a configured size. It preserves tool
147
+ call/return pairs so the algorithm never breaks in the middle of a
148
+ sequence. Configured with `keep:` (default 64), it emits the standard
149
+ `on_compaction` and `on_compaction_finish`
150
+ [`LLM::Stream`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html)
151
+ lifecycle callbacks. No LLM call is made; the strategy is purely
152
+ lossy but fast and requires no network.
153
+
154
+ * **raise when given an unparseable `keep:` value** <br>
155
+ `LLM::Compactor::Truncate` now raises `ArgumentError` when the `keep:`
156
+ parameter cannot be parsed as an integer or percentage string, instead
157
+ of failing with an obscure error later during execution.
158
+
159
+ * **accept percentage string for the `keep:` parameter** <br>
160
+ `LLM::Compactor::Truncate#call` now accepts a percentage string such
161
+ as `"80%"` for the `keep:` parameter, which keeps approximately 80%
162
+ of the most recent messages. Integer values continue to work as
163
+ before. This makes it easy to trim proportionally rather than to an
164
+ absolute number of messages.
165
+
166
+ * **add `Null` strategy for no-op compaction** <br>
167
+ [`LLM::Compactor::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Null.html)
168
+ is a new built-in compaction strategy that does nothing. It is used as
169
+ the default compactor when no strategy is configured on a context,
170
+ ensuring the compactor interface is always present without requiring a
171
+ separate nil check.
172
+
173
+ * **accept both `LLM::Agent` and `LLM::Context`** <br>
174
+ [`LLM::Compactor#initialize`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor.html#initialize-instance_method)
175
+ now accepts both `LLM::Agent` and `LLM::Context` instances. When given
176
+ an agent, the internal context is unwrapped automatically, making the
177
+ compactor API more flexible when working with agents.
178
+
179
+ #### Context integration
180
+
181
+ * **accept `compactor` and `compactor_options` parameters** <br>
182
+ [`LLM::Context`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html)
183
+ now accepts `compactor:` (a compactor class defaulting to
184
+ [`LLM::Compactor::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Null.html))
185
+ and `compactor_options:` (a hash of options forwarded to the
186
+ compactor's `call` method) parameters. The compactor is automatically
187
+ invoked at the beginning of each `talk` turn. The previous `compactor=`
188
+ setter has been removed in favour of constructor-driven configuration.
189
+
190
+ * **`on_compaction` and `on_compaction_finish` receive a single argument** <br>
191
+ [`LLM::Stream#on_compaction`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_compaction-instance_method)
192
+ and
193
+ [`LLM::Stream#on_compaction_finish`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_compaction_finish-instance_method)
194
+ now accept a single argument (the compactor instance) instead of two
195
+ arguments (context and compactor). The context is still available via
196
+ `LLM::Compactor#ctx`, so access to the context is not lost. This
197
+ simplifies the callback interface for compaction lifecycle observers.
198
+
199
+ ### Tools
200
+
201
+ * **add `LLM::Tool::Utils` module for shared command execution logic** <br>
202
+ A new
203
+ [`LLM::Tool::Utils`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Utils.html)
204
+ module provides shared `wait(command:, timeout:)` and `now` helper
205
+ methods for tools that execute commands. Tools that include `Utils` can
206
+ wait on a running command and automatically kill it when it exceeds the
207
+ configured timeout, using `Process.clock_gettime` with `CLOCK_MONOTONIC`
208
+ for precise timing. The module is used by both the `Shell` and `Rg`
209
+ tools internally.
210
+
211
+ * **shell: add `timeout` parameter for command execution deadlines** <br>
212
+ The
213
+ [`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html)
214
+ tool now accepts a `timeout` parameter (default 60s) that automatically
215
+ kills commands exceeding the specified time limit, preventing hung
216
+ processes from blocking the agent indefinitely.
217
+
218
+ * **rg: add `timeout` parameter for search execution deadlines** <br>
219
+ The
220
+ [`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html)
221
+ tool now accepts a `timeout` parameter (default 5s) that automatically
222
+ kills search commands exceeding the specified time limit, preventing
223
+ long-running searches from blocking the agent indefinitely.
224
+
225
+ * **git: add `timeout` parameter for command execution deadlines** <br>
226
+ The
227
+ [`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html)
228
+ tool now accepts a `timeout` parameter (default 5s) that automatically
229
+ kills git commands exceeding the specified time limit, preventing hung
230
+ processes from blocking the agent indefinitely.
231
+
232
+ ### Schema
233
+
234
+ * **properties are now ordered and support indifferent access** <br>
235
+ [`LLM::Schema::Leaf`](https://r.uby.dev/api-docs/llm.rb/LLM/Schema/Leaf.html)
236
+ tracks property definition order in a new `index` attribute, matching
237
+ the convention already used by
238
+ [`LLM::Command::Parameter`](https://r.uby.dev/api-docs/llm.rb/LLM/Command/Parameter.html).
239
+ Internally, `@properties` is stored as an
240
+ [`LLM::Object`](https://r.uby.dev/api-docs/llm.rb/LLM/Object.html)
241
+ instead of a plain `Hash`, so lookups with both string and symbol keys
242
+ work.
243
+
244
+ ### Buffer
245
+
246
+ * **more array-like message management** <br>
247
+ [`LLM::Buffer`](https://r.uby.dev/api-docs/llm.rb/LLM/Buffer.html)
248
+ now exposes `first`, `reject!`, `select!`, `shift`, `clear`, `drop`,
249
+ `take`, and `reverse`, making it easier to query and mutate
250
+ `LLM::Context#messages` like an ordinary Array. `reject!` is aliased
251
+ as `delete_if` for familiarity.
252
+
253
+ * **`last(nil)` no longer returns the last message** <br>
254
+ `LLM::Buffer#last` now uses an internal `UNDEFINED` sentinel to
255
+ distinguish between no argument (`last` returns the last message)
256
+ and `nil` (`last(nil)` is treated as an argument). Previously `nil`
257
+ was indistinguishable from no argument.
258
+
259
+ ### Function
260
+
261
+ * **consolidate `call` and `call!` into one method** <br>
262
+ The private `call!` method has been merged into the public
263
+ [`LLM::Function#call`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#call-instance_method).
264
+ The separate `call!` method existed for tracer-scoping logic now
265
+ handled directly inside `call`. All internal call sites now use
266
+ `function.call` instead of `function.call!`.
267
+
268
+ * **add `LLM::Function::Group` as an abstract base class** <br>
269
+ A new abstract base class
270
+ ([`LLM::Function::Group`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Group.html))
271
+ defines the interface that all concurrency strategy groups must
272
+ implement: `alive?`, `interrupt!`, and `wait`. Each strategy group
273
+ (`Sequential::Group`, `Thread::Group`, `Fiber::Group`,
274
+ `Async::Group`, `Fork::Group`, `Ractor::Group`) now subclasses
275
+ this base.
276
+
277
+ * **split `spawn` and `wait` across all strategies** <br>
278
+ `spawn` now starts execution without blocking, and `wait` collects
279
+ the result. `on_tool_start` moved into each task's `spawn` so the
280
+ tracer span covers execution rather than construction. Each task and
281
+ group now exposes a public `spawn` method alongside the existing
282
+ `wait`/`value` methods.
283
+
284
+ * **spawn tasks lazily in `Group#wait`** <br>
285
+ All concurrency strategy groups (Fiber::Group, Fork::Group,
286
+ Ractor::Group, Thread::Group) now automatically spawn their tasks
287
+ when `wait` is called if they haven't been spawned yet, matching
288
+ the existing `Async::Group` behavior. This makes the spawn/wait
289
+ contract consistent across all six concurrency backends.
290
+
291
+ ### Agent
292
+
293
+ * **add `name` class DSL and instance method** <br>
294
+ [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
295
+ has a `name` class DSL (`name "admin"`) and a corresponding `#name`
296
+ instance method. The name is resolved through the same lazy-resolution
297
+ path as other agent attributes. It can be set via
298
+ `LLM::Agent.set(name: ...)`, `LLM::Agent.new(name: ...)`, or the class
299
+ DSL. When no name is given, a default is derived from the class name
300
+ (e.g., `SystemAdmin` becomes `system-admin`). The REPL uses the name
301
+ as the prompt label and transcript prefix, making it easier to
302
+ distinguish multiple sessions.
303
+
304
+ ### REPL
305
+
306
+ * **agent identity in the prompt** <br>
307
+ [`LLM::Agent#repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
308
+ and
309
+ [`LLM::Repl.new`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html#initialize-instance_method)
310
+ accept a `name:` parameter (defaulting to `LLM::Agent#name`) that sets
311
+ the input prompt to `provider(name)> ` and labels transcript messages
312
+ with the agent's name instead of a hardcoded `agent:`. Useful when
313
+ running multiple sessions.
314
+
315
+ * **`/compact` command** <br>
316
+ New built-in `/compact` command frees context window space by dropping
317
+ the oldest messages via
318
+ [`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html).
319
+ Supports both integer (`/compact 32`) and percentage (`/compact 75%`)
320
+ arguments. Defaults to keeping the last 128 messages.
321
+
322
+ * **tab-completion for `/` commands** <br>
323
+ Pressing Tab on an input line starting with `/` autocompletes the
324
+ command name. Repeated Tab presses cycle through matching commands.
325
+ Powered by
326
+ [`LLM::Command.complete(str)`](https://r.uby.dev/api-docs/llm.rb/LLM/Command.html#complete-class_method)
327
+ which is available outside the REPL too.
328
+
329
+ * **command system enhancements** <br>
330
+ Commands can set parameter defaults in their `call` method signature
331
+ (e.g., `def call(n: 128)`). Aliases like `/quit` now inherit their
332
+ parent's description and parameters. Commands also have access to
333
+ the active `agent` and `repl` via public readers.
334
+
335
+ * **tool argument sorting** <br>
336
+ Tool parameters in the status bar are now displayed in definition
337
+ order (using the new `index` attribute), regardless of the order
338
+ the model returns them.
339
+
340
+ * **expanded markdown rendering** <br>
341
+ The curses-based markdown renderer now handles lists (`<ul>`, `<ol>`),
342
+ blockquotes, horizontal rules, hyperlinks (underline), images
343
+ (`[image: alt text]`), and tables (aligned columns).
344
+
345
+ * **input improvements** <br>
346
+ Ctrl+P and Ctrl+N walk through conversation history (user messages
347
+ only, managed by
348
+ [`LLM::Repl::Walker`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Walker.html)).
349
+ Page Up/Down scroll the transcript by a page. ENTER and BACKSPACE are
350
+ now mapped to raw character codes from `Curses.getch` instead of
351
+ `Curses::Key` constants.
352
+
353
+ ### Object
354
+
355
+ * **preserve the original key name in `KeyError` messages** <br>
356
+ `LLM::Object#fetch` now preserves the original key name when a key
357
+ is not found, instead of raising `KeyError` with `key not found: nil`.
358
+ The previous behavior occurred when the given key was not found in
359
+ the stored hash, causing internal lookup to return `nil` and lose
360
+ the original key reference.
361
+
362
+ ### Registry
363
+
364
+ * **refresh model metadata across providers** <br>
365
+ Update `data/*.json` files with current provider model listings and
366
+ pricing. Mark several DeepInfra models as deprecated (`meta-llama/
367
+ Meta-Llama-3.1-8B-Instruct`, `Qwen/Qwen1.5-110B-Chat`, and
368
+ `mistralai/Mixtral-8x7B-Instruct-v0.1`). Correct xAI cache-read
369
+ pricing from $0.50 to $0.30 per million input tokens.
370
+
371
+ ### Fix
372
+
373
+ * **agent: fix default name resolution when name is not explicitly set** <br>
374
+ Fix a bug where `LLM::Agent` derived its default name from
375
+ `self.class` instead of `self`, causing the name to be `"class"`
376
+ instead of a parameterized version of the actual class name
377
+ (e.g., `"system-admin"` for `SystemAdmin`). The fix uses `self`
378
+ directly, which correctly resolves the class name at the instance
379
+ level.
380
+
381
+ * **function: make Fork::Task and Ractor::Task inherit LLM::Function::Task** <br>
382
+ `LLM::Function::Fork::Task` and `LLM::Function::Ractor::Task` now
383
+ explicitly subclass `LLM::Function::Task` and accept an options hash
384
+ as their second argument, matching the constructor signature used
385
+ by the other four task classes. The interface was already compatible
386
+ but the inheritance was missing by mistake. It is now consistent across
387
+ all six concurrency backends.
388
+
389
+ * **google: fix `stream` parameter leakage that broke the provider** <br>
390
+ Fix a bug in the Google provider where `stream: stream.enabled?` was
391
+ being merged into request parameters, causing API-level errors. The
392
+ Google provider does not use a `stream` parameter. Streaming is
393
+ controlled via the URL path (`streamGenerateContent` vs
394
+ `generateContent`). The fix removes the leaked parameter and correctly
395
+ routes streaming requests through the appropriate path.
396
+
397
+ * **fork: fix deadlock on xchan.rb channel** <br>
398
+ Fix a deadlock in the `:fork` concurrency strategy where both the
399
+ writer and reader could get stuck on the xchan channel, preventing the
400
+ reader from draining the channel. The deadlock surfaced as an errno
401
+ failure, especially with large tool returns. The fix requires xchan.rb
402
+ v0.22.0 and uses the `SOCK_STREAM` socket type for communicating a
403
+ tool's return value.
404
+
18
405
  ## v12.6.0
19
406
 
20
407
  Changes since `v12.5.1`.
data/LICENSE CHANGED
@@ -1,93 +1,21 @@
1
- Business Source License 1.1
2
-
3
- License text copyright (c) 2024 MariaDB plc, All Rights Reserved.
4
- "Business Source License" is a trademark of MariaDB plc.
5
-
6
- Parameters
7
-
8
- Licensor: Robert Gleeson
9
-
10
- Licensed Work: llm.rb
11
-
12
- Additional Use Grant:
13
- - Free for personal use
14
- - Free for students and their teachers
15
- - Free for evaluation, development, and testing
16
- - Free for non-profits and charities
17
- - Free for companies with less than or equal to 50 employees
18
-
19
- Change Date:
20
- Four years after the first public release of each specific version of the
21
- Licensed Work.
22
-
23
- Change License:
24
- BSD Zero Clause License (0BSD)
25
-
26
- Terms
27
-
28
- The Licensor hereby grants you the right to copy, modify, create derivative
29
- works, redistribute, and make non-production use of the Licensed Work. The
30
- Licensor may make an Additional Use Grant, above, permitting limited
31
- production use.
32
-
33
- Effective on the Change Date, or the fourth anniversary of the first publicly
34
- available distribution of a specific version of the Licensed Work under this
35
- License, whichever comes first, the Licensor hereby grants you rights under
36
- the terms of the Change License, and the rights granted in the paragraph
37
- above terminate.
38
-
39
- If your use of the Licensed Work does not comply with the requirements
40
- currently in effect as described in this License, you must purchase a
41
- commercial license from the Licensor, its affiliated entities, or authorized
42
- resellers, or you must refrain from using the Licensed Work.
43
-
44
- All copies of the original and modified Licensed Work, and derivative works
45
- of the Licensed Work, are subject to this License. This License applies
46
- separately for each version of the Licensed Work and the Change Date may vary
47
- for each version of the Licensed Work released by Licensor.
48
-
49
- You must conspicuously display this License on each original or modified copy
50
- of the Licensed Work. If you receive the Licensed Work in original or
51
- modified form from a third party, the terms and conditions set forth in this
52
- License apply to your use of that work.
53
-
54
- Any use of the Licensed Work in violation of this License will automatically
55
- terminate your rights under this License for the current and all other
56
- versions of the Licensed Work.
57
-
58
- This License does not grant you any right in any trademark or logo of
59
- Licensor or its affiliates (provided that you may use a trademark or logo of
60
- Licensor as expressly required by this License).
61
-
62
- TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
63
- AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
64
- EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
65
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
66
- TITLE.
67
-
68
- MariaDB hereby grants you permission to use this License's text to license
69
- your works, and to refer to it using the trademark "Business Source
70
- License", as long as you comply with the Covenants of Licensor below.
71
-
72
- Covenants of Licensor
73
-
74
- In consideration of the right to use this License's text and the "Business
75
- Source License" name and trademark, Licensor covenants to MariaDB, and to all
76
- other recipients of the licensed work to be provided by Licensor:
77
-
78
- To specify as the Change License the GPL Version 2.0 or any later version, or
79
- a license that is compatible with GPL Version 2.0 or a later version, where
80
- "compatible" means that software provided under the Change License can be
81
- included in a program with software provided under GPL Version 2.0 or a later
82
- version. Licensor may specify additional Change Licenses without limitation.
83
-
84
- To either: (a) specify an additional grant of rights to use that does not
85
- impose any additional restriction on the right granted in this License, as
86
- the Additional Use Grant; or (b) insert the text "None" to specify a Change
87
- Date. Not to modify this License in any other way.
88
-
89
- Notice
90
-
91
- The Business Source License (this document, or the "License") is not an Open
92
- Source license. However, the Licensed Work will eventually be made available
93
- under an Open Source License, as stated in this License.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Gleeson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.