llm.rb 12.6.0 → 13.1.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 +571 -13
- data/LICENSE +21 -93
- data/README.md +183 -167
- data/bin/llm.rb +124 -0
- data/data/deepinfra.json +3 -0
- data/data/xai.json +1 -1
- data/lib/llm/a2a.rb +1 -1
- data/lib/llm/active_record/acts_as_llm.rb +6 -6
- data/lib/llm/agent.rb +136 -27
- data/lib/llm/buffer.rb +85 -3
- data/lib/llm/compactor/null.rb +19 -0
- data/lib/llm/compactor/truncate.rb +80 -0
- data/lib/llm/compactor.rb +42 -124
- data/lib/llm/context.rb +31 -37
- data/lib/llm/contract.rb +4 -25
- data/lib/llm/function/array.rb +18 -17
- data/lib/llm/function/async/group.rb +54 -0
- data/lib/llm/function/async/reactor.rb +48 -0
- data/lib/llm/function/async/task.rb +83 -0
- data/lib/llm/function/fiber/group.rb +46 -0
- data/lib/llm/function/fiber/task.rb +62 -0
- data/lib/llm/function/{fork_group.rb → fork/group.rb} +14 -5
- data/lib/llm/function/fork/job.rb +2 -2
- data/lib/llm/function/fork/task.rb +19 -10
- data/lib/llm/function/group.rb +40 -0
- data/lib/llm/function/{ractor_group.rb → ractor/group.rb} +13 -5
- data/lib/llm/function/ractor/job.rb +9 -3
- data/lib/llm/function/ractor/mailbox.rb +2 -0
- data/lib/llm/function/ractor/task.rb +23 -15
- data/lib/llm/function/{call_group.rb → sequential/group.rb} +12 -8
- data/lib/llm/function/sequential/task.rb +49 -0
- data/lib/llm/function/task.rb +25 -48
- data/lib/llm/function/thread/group.rb +46 -0
- data/lib/llm/function/thread/task.rb +60 -0
- data/lib/llm/function.rb +54 -65
- data/lib/llm/loop_guard.rb +1 -2
- data/lib/llm/mcp.rb +22 -0
- data/lib/llm/object.rb +2 -1
- data/lib/llm/provider.rb +6 -3
- data/lib/llm/providers/anthropic.rb +1 -1
- data/lib/llm/providers/bedrock/request_adapter.rb +1 -1
- data/lib/llm/providers/google.rb +2 -2
- data/lib/llm/providers/mistral.rb +1 -1
- data/lib/llm/providers/ollama.rb +1 -1
- data/lib/llm/providers/openai/responses.rb +1 -1
- data/lib/llm/providers/openai.rb +1 -1
- data/lib/llm/repl/{transcript.rb → buffer.rb} +34 -21
- data/lib/llm/repl/command.rb +47 -13
- data/lib/llm/repl/commands/compact.rb +33 -0
- data/lib/llm/repl/commands/help.rb +3 -5
- data/lib/llm/repl/input.rb +80 -15
- data/lib/llm/repl/markdown/table.rb +80 -0
- data/lib/llm/repl/markdown.rb +33 -3
- data/lib/llm/repl/node.rb +37 -0
- data/lib/llm/repl/status.rb +4 -4
- data/lib/llm/repl/stream.rb +12 -5
- data/lib/llm/repl/walker.rb +46 -0
- data/lib/llm/repl/window.rb +31 -32
- data/lib/llm/repl.rb +70 -38
- data/lib/llm/response.rb +10 -0
- data/lib/llm/schema/leaf.rb +5 -0
- data/lib/llm/schema/object.rb +11 -5
- data/lib/llm/sequel/plugin.rb +6 -6
- data/lib/llm/skill.rb +20 -4
- data/lib/llm/stream.rb +24 -17
- data/lib/llm/tool.rb +20 -4
- data/lib/llm/tools/chdir.rb +0 -2
- data/lib/llm/tools/{swap_text.rb → edit-file.rb} +3 -3
- data/lib/llm/tools/git.rb +11 -4
- data/lib/llm/tools/mkdir.rb +4 -1
- data/lib/llm/tools/pwd.rb +0 -2
- data/lib/llm/tools/read_file.rb +0 -2
- data/lib/llm/tools/rg.rb +11 -4
- data/lib/llm/tools/ruby.rb +46 -0
- data/lib/llm/tools/shell.rb +11 -4
- data/lib/llm/tools/utils.rb +31 -0
- data/lib/llm/tracer/pretty_logger.rb +127 -0
- data/lib/llm/tracer.rb +1 -0
- data/lib/llm/version.rb +1 -1
- data/lib/llm.rb +25 -5
- data/llm.gemspec +11 -5
- data/resources/deepdive.md +45 -1198
- metadata +39 -17
- data/lib/llm/function/call_task.rb +0 -46
- data/lib/llm/function/fiber_group.rb +0 -105
- data/lib/llm/function/task_group.rb +0 -97
- data/lib/llm/function/thread_group.rb +0 -102
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bb5c6136080e0136309987a4e042e6f646c26de39e38d6422bb3904fc665bf5f
|
|
4
|
+
data.tar.gz: d832b9c19f4173ba6e5631ffdc57f495eb4a9a8fb0b657801de185707bc4085e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ba4417a8c5b48a28b2baf04a2960374eae28c44dc2ec19e8f79da9a95f75fdf8cb5f1c749e6bfa1b1f6d1c790723e2005cb576f94f118997bb5e8b0f5d53a63
|
|
7
|
+
data.tar.gz: 0105af6bcaaec50930546e3a5a7207b8cf65e30bbea33359784061159748a3e2f3afb6e2b599eaad904e0c477d9827bb444c698315e56d43572be6ba86fe98b8
|
data/CHANGELOG.md
CHANGED
|
@@ -15,11 +15,569 @@
|
|
|
15
15
|
|
|
16
16
|
## What's next
|
|
17
17
|
|
|
18
|
+
*No unreleased changes yet. Check back after the next release.*
|
|
19
|
+
|
|
20
|
+
## v13.1.0
|
|
21
|
+
|
|
22
|
+
Changes since `v13.0.0`.
|
|
23
|
+
|
|
24
|
+
This release adds `LLM::Agent` class DSL attributes (`path`, `description`),
|
|
25
|
+
extends skills with file-path loading and the `tools: all` directive, adds new
|
|
26
|
+
built-in tools (`LLM::Tool::Ruby`, `LLM::Tool::EditFile`), introduces the
|
|
27
|
+
`LLM::Tracer::PrettyLogger` for human-readable tracing, renames `Transcript`
|
|
28
|
+
to `Buffer` across the REPL, ships a `bin/llm.rb` CLI entry point, and fixes
|
|
29
|
+
several agent and tool bugs around persistence, interruption, and naming.
|
|
30
|
+
|
|
31
|
+
### Core
|
|
32
|
+
|
|
33
|
+
* **add post install message with deepdive link** <br>
|
|
34
|
+
The gemspec now includes a `post_install_message` that points users to
|
|
35
|
+
the deepdive guide at `https://r.uby.dev/llm/deepdive` after installation,
|
|
36
|
+
making it easier for new users to discover the project documentation.
|
|
37
|
+
|
|
38
|
+
### Agent
|
|
39
|
+
|
|
40
|
+
* **add `description` class DSL and instance method** <br>
|
|
41
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
|
|
42
|
+
has a `description` class DSL (`description "release engineer"`) and a
|
|
43
|
+
corresponding `#description` instance method. The description is an
|
|
44
|
+
optional self-documenting string that serves as a brief summary of the
|
|
45
|
+
agent's purpose. It can be set via the class DSL,
|
|
46
|
+
`LLM::Agent.set(description: ...)`, or `LLM::Agent.new(description: ...)`.
|
|
47
|
+
|
|
48
|
+
* **add `path` class DSL and instance method** <br>
|
|
49
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
|
|
50
|
+
has a `path` class DSL (`path "contexts/admin.json"`) and a
|
|
51
|
+
corresponding `#path` instance method. When a path is set, the agent
|
|
52
|
+
automatically restores its conversation history from that file on
|
|
53
|
+
initialization and saves it back after each `talk` or `ask` turn,
|
|
54
|
+
making session persistence across process restarts transparent.
|
|
55
|
+
|
|
56
|
+
### Skills
|
|
57
|
+
|
|
58
|
+
* **accept a path to a markdown file** <br>
|
|
59
|
+
[`LLM::Skill.load`](https://r.uby.dev/api-docs/llm.rb/LLM/Skill.html#load-class_method)
|
|
60
|
+
now accepts a path to a markdown file in addition to a directory path.
|
|
61
|
+
When given a file path, the file is read directly instead of looking for
|
|
62
|
+
a `SKILL.md` inside a directory. This makes it possible to load a single
|
|
63
|
+
markdown file as a skill without placing it in a dedicated directory.
|
|
64
|
+
|
|
65
|
+
* **extend with `all` keyword for loading the full tool registry** <br>
|
|
66
|
+
`LLM::Skill` now supports `tools: all` (or `tools: "*"`) in the frontmatter
|
|
67
|
+
to load all tools from the global
|
|
68
|
+
[`LLM::Tool.registry`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html#registry-class_method).
|
|
69
|
+
Previously, the `tools:` frontmatter only accepted `inherit`, an array of tool
|
|
70
|
+
names, or nothing. The new `all` keyword makes it possible to give a skill
|
|
71
|
+
access to every registered tool without listing them individually.
|
|
72
|
+
|
|
73
|
+
### Tools
|
|
74
|
+
|
|
75
|
+
* **add `LLM::Tool::Ruby` for executing Ruby code in a subprocess** <br>
|
|
76
|
+
[`LLM::Tool::Ruby`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Ruby.html)
|
|
77
|
+
is a new built-in tool that runs a string of Ruby code in a separate
|
|
78
|
+
Ruby process with a configurable timeout (default 15s). The code runs
|
|
79
|
+
in an isolated address space unaware of its parent, making it useful
|
|
80
|
+
for safe(ish) dynamic code execution. It must be required explicitly
|
|
81
|
+
with `require "llm/tools/ruby"` and requires the `test-cmd.rb` gem.
|
|
82
|
+
|
|
83
|
+
* **rename `LLM::Tool::SwapText` to `LLM::Tool::EditFile`** <br>
|
|
84
|
+
The `SwapText` tool has been renamed to
|
|
85
|
+
[`LLM::Tool::EditFile`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/EditFile.html)
|
|
86
|
+
to better match the naming of sibling tools (`ReadFile`, `WriteFile`).
|
|
87
|
+
The old `require "llm/tools/swap_text"` path no longer exists; use
|
|
88
|
+
`require "llm/tools/edit-file"` instead.
|
|
89
|
+
|
|
90
|
+
### Tracer
|
|
91
|
+
|
|
92
|
+
* **add `LLM::Tracer::PrettyLogger` for human-readable tracing** <br>
|
|
93
|
+
[`LLM::Tracer::PrettyLogger`](https://r.uby.dev/api-docs/llm.rb/LLM/Tracer/PrettyLogger.html)
|
|
94
|
+
is a new tracer that writes human-readable request and tool-call logs to a
|
|
95
|
+
console or file. Unlike the structured JSON output of
|
|
96
|
+
`LLM::Tracer::Logger`, the pretty logger emits single-line entries with
|
|
97
|
+
inline context, making it easier to follow agent activity at a glance.
|
|
98
|
+
It writes to `$stderr` by default and accepts an `io:` option for file
|
|
99
|
+
output.
|
|
100
|
+
|
|
101
|
+
### Repl
|
|
102
|
+
|
|
103
|
+
* **rename `LLM::Repl::Transcript` to `LLM::Repl::Buffer`** <br>
|
|
104
|
+
`LLM::Repl::Transcript` has been renamed to
|
|
105
|
+
[`LLM::Repl::Buffer`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Buffer.html)
|
|
106
|
+
to better reflect its role as a conversation state manager. The old
|
|
107
|
+
`start` and `finish` methods have been renamed to `open` and `close`
|
|
108
|
+
respectively. The public accessor on
|
|
109
|
+
[`LLM::Repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html) has been
|
|
110
|
+
renamed from `transcript` to `buffer`.
|
|
111
|
+
|
|
112
|
+
* **add `write_message` for formatted message writing** <br>
|
|
113
|
+
[`LLM::Repl::Buffer#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Buffer.html#write_message-instance_method)
|
|
114
|
+
and
|
|
115
|
+
[`LLM::Repl#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html#write_message-instance_method)
|
|
116
|
+
provide a convenience method that takes a username and content string,
|
|
117
|
+
formatting the output with a bold `user:` label and a trailing newline.
|
|
118
|
+
This is simpler than the equivalent sequence of `write` calls.
|
|
119
|
+
|
|
120
|
+
* **add `Command#write_message` and refactor `Command#write`** <br>
|
|
121
|
+
[`LLM::Command#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Command.html#write_message-instance_method)
|
|
122
|
+
provides a convenience method that takes a username and content string,
|
|
123
|
+
matching the same interface on `LLM::Repl` and `LLM::Buffer`. The
|
|
124
|
+
`Command#write` method is now implemented on top of `write_message`,
|
|
125
|
+
always prefixing output with `command(<name>): `. The `who:` keyword
|
|
126
|
+
argument previously accepted by `write` has been removed; use
|
|
127
|
+
`write_message` instead.
|
|
128
|
+
|
|
129
|
+
* **display pre-existing agent messages when the repl starts** <br>
|
|
130
|
+
When
|
|
131
|
+
[`LLM::Agent#repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
|
|
132
|
+
starts, any messages already in the agent's buffer are now rendered
|
|
133
|
+
in the REPL window. Previously the REPL started with an empty
|
|
134
|
+
transcript even when the agent carried prior conversation history,
|
|
135
|
+
making it harder to resume a session. Tool-call and tool-return
|
|
136
|
+
messages are skipped to avoid visual noise.
|
|
137
|
+
|
|
138
|
+
### CLI
|
|
139
|
+
|
|
140
|
+
* **add `bin/llm.rb` for launching the REPL from the command line** <br>
|
|
141
|
+
A new executable script (`bin/llm.rb`) provides a convenient way to start
|
|
142
|
+
an interactive REPL session directly from the terminal. It auto-detects
|
|
143
|
+
the provider from environment variables like `OPENAI_API_KEY`, supports
|
|
144
|
+
a `-p PROVIDER` flag for explicit provider selection, a `-t` flag for
|
|
145
|
+
temporary (non-persistent) sessions, and `-h` for help. Sessions are
|
|
146
|
+
automatically saved to `~/.llm.rb/` by default.
|
|
147
|
+
|
|
148
|
+
### Fix
|
|
149
|
+
|
|
150
|
+
* **agent: fix `path` restore on first run** <br>
|
|
151
|
+
Fix a bug where [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html)
|
|
152
|
+
called `@ctx.restore(path:)` even when the path's file did not exist.
|
|
153
|
+
The fix checks `File.readable?(@path)` before attempting to restore,
|
|
154
|
+
so the agent starts with a blank conversation on first use instead of
|
|
155
|
+
failing with a file-not-found error.
|
|
156
|
+
|
|
157
|
+
* **tools: re-raise `LLM::Interrupt` to abort the turn** <br>
|
|
158
|
+
[`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html),
|
|
159
|
+
[`LLM::Tool::Mkdir`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Mkdir.html),
|
|
160
|
+
[`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html),
|
|
161
|
+
[`LLM::Tool::Ruby`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Ruby.html),
|
|
162
|
+
and
|
|
163
|
+
[`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html)
|
|
164
|
+
now re-raise `LLM::Interrupt` after killing their running command. The
|
|
165
|
+
previous behavior rescued the interrupt and killed the child process but
|
|
166
|
+
let the turn continue, which meant a cancelled tool call did not abort
|
|
167
|
+
the conversation turn. Re-raising ensures the entire turn is interrupted.
|
|
168
|
+
|
|
169
|
+
* **tools: rescue `LLM::Interrupt` in shell-based tools** <br>
|
|
170
|
+
[`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html),
|
|
171
|
+
[`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html),
|
|
172
|
+
[`LLM::Tool::Mkdir`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Mkdir.html),
|
|
173
|
+
and
|
|
174
|
+
[`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html)
|
|
175
|
+
now rescue `LLM::Interrupt` and kill their running command, preventing
|
|
176
|
+
orphaned child processes when a tool is interrupted during execution.
|
|
177
|
+
|
|
178
|
+
* **agent: fix default name derivation** <br>
|
|
179
|
+
Fix a bug where `LLM::Agent` used without a subclass derived its default
|
|
180
|
+
name as `"l-lm-agent"` instead of `"agent"`. The fix replaces the
|
|
181
|
+
regex-based parameterization with a pattern that correctly handles
|
|
182
|
+
single-word class names and multi-word namespaced names.
|
|
183
|
+
|
|
184
|
+
* **function: `#params` always returns an `LLM::Object`** <br>
|
|
185
|
+
[`LLM::Function#params`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#params-instance_method)
|
|
186
|
+
now always returns an `LLM::Object` representing the function's parameter
|
|
187
|
+
schema. Previously it returned `nil` when a function defined no parameters,
|
|
188
|
+
forcing every caller to guard against `nil`. All provider adapters now use
|
|
189
|
+
`fn.params.to_h` instead of `fn.params || {type: "object", properties: {}}`.
|
|
190
|
+
|
|
191
|
+
## v13.0.0
|
|
192
|
+
|
|
193
|
+
v13.0.0 relicenses the project under the MIT license, replacing
|
|
194
|
+
the Business Source License that was introduced in v12.0.0. No
|
|
195
|
+
commercial license is needed. Commercial, personal, educational, and
|
|
196
|
+
all other uses are now permitted under the standard MIT terms.
|
|
197
|
+
|
|
198
|
+
Seven breaking changes. Concurrency strategies have been renamed
|
|
199
|
+
(`:call` → `:sequential`, `:task` → `:async`), `spawn` is now
|
|
200
|
+
`task`, and the `:async` strategy has been rebuilt from the ground
|
|
201
|
+
up. It no longer blocks and now supports interruption. The compactor
|
|
202
|
+
has been refactored into pluggable strategies. Interruption is now
|
|
203
|
+
reliable across all six concurrency backends. The `functions` and
|
|
204
|
+
`functions?` methods have been renamed to `pending_functions` and
|
|
205
|
+
`pending_functions?`.
|
|
206
|
+
|
|
207
|
+
### Migration from v12.6.0
|
|
208
|
+
|
|
209
|
+
| Old | New |
|
|
210
|
+
|-----|-----|
|
|
211
|
+
| `fn.spawn(:call)` | `fn.task(:sequential)` |
|
|
212
|
+
| `fn.spawn(:task)` | `fn.task(:async)` |
|
|
213
|
+
| `ctx.wait(:call)` | `ctx.wait(:sequential)` |
|
|
214
|
+
| `agent.concurrency :task` | `agent.concurrency :async` |
|
|
215
|
+
| `LLM::Function::FiberGroup` | `LLM::Function::Fiber::Group` |
|
|
216
|
+
| `LLM::Function::CallGroup` | `LLM::Function::Sequential::Group` |
|
|
217
|
+
| `LLM::Function::TaskGroup` | `LLM::Function::Async::Group` |
|
|
218
|
+
| `Compactor.new(model:, token_threshold:)` | `Compactor::Truncate.new(ctx)` |
|
|
219
|
+
| `on_compaction(ctx, compactor)` | `on_compaction(compactor)` |
|
|
220
|
+
| `ctx.functions` / `ctx.functions?` | `ctx.pending_functions` / `ctx.pending_functions?` |
|
|
221
|
+
| `agent.functions` / `agent.functions?` | `agent.pending_functions` / `agent.pending_functions?` |
|
|
222
|
+
|
|
223
|
+
### Breaking
|
|
224
|
+
|
|
225
|
+
* **rename `LLM::Function#spawn` as `LLM::Function#task`** <br>
|
|
226
|
+
[`LLM::Function#task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#task-instance_method)
|
|
227
|
+
(previously `spawn`) now consistently returns a
|
|
228
|
+
[`LLM::Function::Task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Task.html)
|
|
229
|
+
object that can be spawned, waited on, and passed to
|
|
230
|
+
[`LLM::Function::Group`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Group.html).
|
|
231
|
+
The old implementation alternated between spawning immediately or
|
|
232
|
+
returning a raw thread or fiber.
|
|
233
|
+
|
|
234
|
+
* **rename concurrency strategies (`:call` → `:sequential`,**
|
|
235
|
+
**`:task` → `:async`)** <br>
|
|
236
|
+
The `:call` concurrency strategy is now `:sequential`, and the `:task`
|
|
237
|
+
strategy is now `:async`.
|
|
238
|
+
[`LLM::Agent.concurrency`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#concurrency-class_method),
|
|
239
|
+
[`LLM::Context#wait`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#wait-instance_method),
|
|
240
|
+
`LLM::Function::Array#task`, and
|
|
241
|
+
[`LLM::Function#task`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#task-instance_method)
|
|
242
|
+
all accept the new names. The old names raise `ArgumentError`.
|
|
243
|
+
|
|
244
|
+
* **rename group classes** <br>
|
|
245
|
+
Group classes have been moved into their strategy's namespace:
|
|
246
|
+
`FiberGroup` → `Fiber::Group`, `ThreadGroup` → `Thread::Group`,
|
|
247
|
+
`CallGroup` → `Sequential::Group`, `TaskGroup` → `Async::Group`,
|
|
248
|
+
`Fork::Group` → `Fork::Group`, `Ractor::Group` → `Ractor::Group`.
|
|
249
|
+
|
|
250
|
+
* **repurpose `LLM::Function::Task` as a task interface superclass** <br>
|
|
251
|
+
`LLM::Function::Task` has been repurposed from a general-purpose class
|
|
252
|
+
that tried to support multiple concurrency strategies into an abstract
|
|
253
|
+
base class that defines the task interface. Individual strategies
|
|
254
|
+
(`Sequential::Task`, `Thread::Task`, `Fiber::Task`, `Async::Task`,
|
|
255
|
+
`Fork::Task`, `Ractor::Task`) now subclass it and implement
|
|
256
|
+
`spawn`, `alive?`, `interrupt!`, and `wait`.
|
|
257
|
+
|
|
258
|
+
* **fix `:async` concurrency (now backed by a managed**
|
|
259
|
+
**`LLM::Function::Async::Reactor` on a background thread)** <br>
|
|
260
|
+
The `:async` strategy previously used `Async {}` which blocked the
|
|
261
|
+
caller until all tasks completed and did not support interruption.
|
|
262
|
+
The fix replaces it with a per-turn
|
|
263
|
+
`LLM::Function::Async::Reactor` on a background thread. Work is
|
|
264
|
+
submitted via `submit(&block)` and consumed by the reactor's event
|
|
265
|
+
loop through a thread-safe `Queue`. `Async::Group` manages the
|
|
266
|
+
reactor lifecycle and spawns tasks lazily on `wait`.
|
|
267
|
+
<br><br>
|
|
268
|
+
Interruption pushes [`LLM::Interrupt`](https://r.uby.dev/api-docs/llm.rb/LLM/Interrupt.html)
|
|
269
|
+
to the task's result queue instead of using `Fiber#raise`, and
|
|
270
|
+
results are bridged back to the caller through a second `Queue`.
|
|
271
|
+
This work drove the broader refactor of strategy naming, the
|
|
272
|
+
spawn/wait split, and the `Task` superclass. The `:async` strategy
|
|
273
|
+
needed the same interface the other strategies already had.
|
|
274
|
+
|
|
275
|
+
* **compactor: refactor to strategy-based interface** <br>
|
|
276
|
+
[`LLM::Compactor`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor.html)
|
|
277
|
+
has been refactored from a single class that performed LLM-based
|
|
278
|
+
summarization into a strategy-based superclass. Each subclass
|
|
279
|
+
implements a different compaction strategy via `call(**opts)`. The old
|
|
280
|
+
summarization approach (using `model:`, `token_threshold:`,
|
|
281
|
+
`message_threshold:`, and `retention_window:` options) has been removed.
|
|
282
|
+
The built-in
|
|
283
|
+
[`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html)
|
|
284
|
+
strategy drops the oldest messages when the conversation exceeds a
|
|
285
|
+
configured size.
|
|
286
|
+
|
|
287
|
+
* **rename `LLM::Context#{functions,functions?}` and `LLM::Agent#{functions,functions?}`** <br>
|
|
288
|
+
[`LLM::Context#functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#functions-instance_method)
|
|
289
|
+
and
|
|
290
|
+
[`LLM::Context#functions?`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#functions%3F-instance_method)
|
|
291
|
+
have been renamed to
|
|
292
|
+
[`LLM::Context#pending_functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#pending_functions-instance_method)
|
|
293
|
+
and
|
|
294
|
+
[`LLM::Context#pending_functions?`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#pending_functions%3F-instance_method)
|
|
295
|
+
respectively. The same rename applies to
|
|
296
|
+
[`LLM::Agent#functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#functions-instance_method)
|
|
297
|
+
(now
|
|
298
|
+
[`LLM::Agent#pending_functions`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#pending_functions-instance_method)).
|
|
299
|
+
The `pending_functions` name was already available as an alias in
|
|
300
|
+
v12.5.0; this change removes the old `functions` name entirely.
|
|
301
|
+
|
|
302
|
+
### Core
|
|
303
|
+
|
|
304
|
+
* **extend `LLM.require` with an optional version argument** <br>
|
|
305
|
+
`LLM.require` now accepts a second `version` parameter that is passed
|
|
306
|
+
to `Kernel#gem` before loading, enabling version constraints for
|
|
307
|
+
optional runtime dependencies. For example,
|
|
308
|
+
`LLM.require "test-cmd.rb", "~> 1.1"` ensures a minimum gem version
|
|
309
|
+
is available. This is used internally by the `Git`, `Rg`, `Mkdir`,
|
|
310
|
+
and `Shell` tools to enforce compatibility with the `test-cmd.rb` gem.
|
|
311
|
+
|
|
312
|
+
### Compactor
|
|
313
|
+
|
|
314
|
+
* **add `Truncate` strategy for dropping oldest messages** <br>
|
|
315
|
+
[`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html)
|
|
316
|
+
is a new built-in compaction strategy that drops the oldest messages
|
|
317
|
+
when the conversation exceeds a configured size. It preserves tool
|
|
318
|
+
call/return pairs so the algorithm never breaks in the middle of a
|
|
319
|
+
sequence. Configured with `keep:` (default 64), it emits the standard
|
|
320
|
+
`on_compaction` and `on_compaction_finish`
|
|
321
|
+
[`LLM::Stream`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html)
|
|
322
|
+
lifecycle callbacks. No LLM call is made; the strategy is purely
|
|
323
|
+
lossy but fast and requires no network.
|
|
324
|
+
|
|
325
|
+
* **raise when given an unparseable `keep:` value** <br>
|
|
326
|
+
`LLM::Compactor::Truncate` now raises `ArgumentError` when the `keep:`
|
|
327
|
+
parameter cannot be parsed as an integer or percentage string, instead
|
|
328
|
+
of failing with an obscure error later during execution.
|
|
329
|
+
|
|
330
|
+
* **accept percentage string for the `keep:` parameter** <br>
|
|
331
|
+
`LLM::Compactor::Truncate#call` now accepts a percentage string such
|
|
332
|
+
as `"80%"` for the `keep:` parameter, which keeps approximately 80%
|
|
333
|
+
of the most recent messages. Integer values continue to work as
|
|
334
|
+
before. This makes it easy to trim proportionally rather than to an
|
|
335
|
+
absolute number of messages.
|
|
336
|
+
|
|
337
|
+
* **add `Null` strategy for no-op compaction** <br>
|
|
338
|
+
[`LLM::Compactor::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Null.html)
|
|
339
|
+
is a new built-in compaction strategy that does nothing. It is used as
|
|
340
|
+
the default compactor when no strategy is configured on a context,
|
|
341
|
+
ensuring the compactor interface is always present without requiring a
|
|
342
|
+
separate nil check.
|
|
343
|
+
|
|
344
|
+
* **accept both `LLM::Agent` and `LLM::Context`** <br>
|
|
345
|
+
[`LLM::Compactor#initialize`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor.html#initialize-instance_method)
|
|
346
|
+
now accepts both `LLM::Agent` and `LLM::Context` instances. When given
|
|
347
|
+
an agent, the internal context is unwrapped automatically, making the
|
|
348
|
+
compactor API more flexible when working with agents.
|
|
349
|
+
|
|
350
|
+
#### Context integration
|
|
351
|
+
|
|
352
|
+
* **accept `compactor` and `compactor_options` parameters** <br>
|
|
353
|
+
[`LLM::Context`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html)
|
|
354
|
+
now accepts `compactor:` (a compactor class defaulting to
|
|
355
|
+
[`LLM::Compactor::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Null.html))
|
|
356
|
+
and `compactor_options:` (a hash of options forwarded to the
|
|
357
|
+
compactor's `call` method) parameters. The compactor is automatically
|
|
358
|
+
invoked at the beginning of each `talk` turn. The previous `compactor=`
|
|
359
|
+
setter has been removed in favour of constructor-driven configuration.
|
|
360
|
+
|
|
361
|
+
* **`on_compaction` and `on_compaction_finish` receive a single argument** <br>
|
|
362
|
+
[`LLM::Stream#on_compaction`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_compaction-instance_method)
|
|
363
|
+
and
|
|
364
|
+
[`LLM::Stream#on_compaction_finish`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_compaction_finish-instance_method)
|
|
365
|
+
now accept a single argument (the compactor instance) instead of two
|
|
366
|
+
arguments (context and compactor). The context is still available via
|
|
367
|
+
`LLM::Compactor#ctx`, so access to the context is not lost. This
|
|
368
|
+
simplifies the callback interface for compaction lifecycle observers.
|
|
369
|
+
|
|
370
|
+
### Tools
|
|
371
|
+
|
|
372
|
+
* **add `LLM::Tool::Utils` module for shared command execution logic** <br>
|
|
373
|
+
A new
|
|
374
|
+
[`LLM::Tool::Utils`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Utils.html)
|
|
375
|
+
module provides shared `wait(command:, timeout:)` and `now` helper
|
|
376
|
+
methods for tools that execute commands. Tools that include `Utils` can
|
|
377
|
+
wait on a running command and automatically kill it when it exceeds the
|
|
378
|
+
configured timeout, using `Process.clock_gettime` with `CLOCK_MONOTONIC`
|
|
379
|
+
for precise timing. The module is used by both the `Shell` and `Rg`
|
|
380
|
+
tools internally.
|
|
381
|
+
|
|
382
|
+
* **shell: add `timeout` parameter for command execution deadlines** <br>
|
|
383
|
+
The
|
|
384
|
+
[`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html)
|
|
385
|
+
tool now accepts a `timeout` parameter (default 60s) that automatically
|
|
386
|
+
kills commands exceeding the specified time limit, preventing hung
|
|
387
|
+
processes from blocking the agent indefinitely.
|
|
388
|
+
|
|
389
|
+
* **rg: add `timeout` parameter for search execution deadlines** <br>
|
|
390
|
+
The
|
|
391
|
+
[`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html)
|
|
392
|
+
tool now accepts a `timeout` parameter (default 5s) that automatically
|
|
393
|
+
kills search commands exceeding the specified time limit, preventing
|
|
394
|
+
long-running searches from blocking the agent indefinitely.
|
|
395
|
+
|
|
396
|
+
* **git: add `timeout` parameter for command execution deadlines** <br>
|
|
397
|
+
The
|
|
398
|
+
[`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html)
|
|
399
|
+
tool now accepts a `timeout` parameter (default 5s) that automatically
|
|
400
|
+
kills git commands exceeding the specified time limit, preventing hung
|
|
401
|
+
processes from blocking the agent indefinitely.
|
|
402
|
+
|
|
403
|
+
### Schema
|
|
404
|
+
|
|
405
|
+
* **properties are now ordered and support indifferent access** <br>
|
|
406
|
+
[`LLM::Schema::Leaf`](https://r.uby.dev/api-docs/llm.rb/LLM/Schema/Leaf.html)
|
|
407
|
+
tracks property definition order in a new `index` attribute, matching
|
|
408
|
+
the convention already used by
|
|
409
|
+
[`LLM::Command::Parameter`](https://r.uby.dev/api-docs/llm.rb/LLM/Command/Parameter.html).
|
|
410
|
+
Internally, `@properties` is stored as an
|
|
411
|
+
[`LLM::Object`](https://r.uby.dev/api-docs/llm.rb/LLM/Object.html)
|
|
412
|
+
instead of a plain `Hash`, so lookups with both string and symbol keys
|
|
413
|
+
work.
|
|
414
|
+
|
|
415
|
+
### Buffer
|
|
416
|
+
|
|
417
|
+
* **more array-like message management** <br>
|
|
418
|
+
[`LLM::Buffer`](https://r.uby.dev/api-docs/llm.rb/LLM/Buffer.html)
|
|
419
|
+
now exposes `first`, `reject!`, `select!`, `shift`, `clear`, `drop`,
|
|
420
|
+
`take`, and `reverse`, making it easier to query and mutate
|
|
421
|
+
`LLM::Context#messages` like an ordinary Array. `reject!` is aliased
|
|
422
|
+
as `delete_if` for familiarity.
|
|
423
|
+
|
|
424
|
+
* **`last(nil)` no longer returns the last message** <br>
|
|
425
|
+
`LLM::Buffer#last` now uses an internal `UNDEFINED` sentinel to
|
|
426
|
+
distinguish between no argument (`last` returns the last message)
|
|
427
|
+
and `nil` (`last(nil)` is treated as an argument). Previously `nil`
|
|
428
|
+
was indistinguishable from no argument.
|
|
429
|
+
|
|
430
|
+
### Function
|
|
431
|
+
|
|
432
|
+
* **consolidate `call` and `call!` into one method** <br>
|
|
433
|
+
The private `call!` method has been merged into the public
|
|
434
|
+
[`LLM::Function#call`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#call-instance_method).
|
|
435
|
+
The separate `call!` method existed for tracer-scoping logic now
|
|
436
|
+
handled directly inside `call`. All internal call sites now use
|
|
437
|
+
`function.call` instead of `function.call!`.
|
|
438
|
+
|
|
439
|
+
* **add `LLM::Function::Group` as an abstract base class** <br>
|
|
440
|
+
A new abstract base class
|
|
441
|
+
([`LLM::Function::Group`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Group.html))
|
|
442
|
+
defines the interface that all concurrency strategy groups must
|
|
443
|
+
implement: `alive?`, `interrupt!`, and `wait`. Each strategy group
|
|
444
|
+
(`Sequential::Group`, `Thread::Group`, `Fiber::Group`,
|
|
445
|
+
`Async::Group`, `Fork::Group`, `Ractor::Group`) now subclasses
|
|
446
|
+
this base.
|
|
447
|
+
|
|
448
|
+
* **split `spawn` and `wait` across all strategies** <br>
|
|
449
|
+
`spawn` now starts execution without blocking, and `wait` collects
|
|
450
|
+
the result. `on_tool_start` moved into each task's `spawn` so the
|
|
451
|
+
tracer span covers execution rather than construction. Each task and
|
|
452
|
+
group now exposes a public `spawn` method alongside the existing
|
|
453
|
+
`wait`/`value` methods.
|
|
454
|
+
|
|
455
|
+
* **spawn tasks lazily in `Group#wait`** <br>
|
|
456
|
+
All concurrency strategy groups (Fiber::Group, Fork::Group,
|
|
457
|
+
Ractor::Group, Thread::Group) now automatically spawn their tasks
|
|
458
|
+
when `wait` is called if they haven't been spawned yet, matching
|
|
459
|
+
the existing `Async::Group` behavior. This makes the spawn/wait
|
|
460
|
+
contract consistent across all six concurrency backends.
|
|
461
|
+
|
|
462
|
+
### Agent
|
|
463
|
+
|
|
464
|
+
* **add `name` class DSL and instance method** <br>
|
|
465
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
|
|
466
|
+
has a `name` class DSL (`name "admin"`) and a corresponding `#name`
|
|
467
|
+
instance method. The name is resolved through the same lazy-resolution
|
|
468
|
+
path as other agent attributes. It can be set via
|
|
469
|
+
`LLM::Agent.set(name: ...)`, `LLM::Agent.new(name: ...)`, or the class
|
|
470
|
+
DSL. When no name is given, a default is derived from the class name
|
|
471
|
+
(e.g., `SystemAdmin` becomes `system-admin`). The REPL uses the name
|
|
472
|
+
as the prompt label and transcript prefix, making it easier to
|
|
473
|
+
distinguish multiple sessions.
|
|
474
|
+
|
|
475
|
+
### REPL
|
|
476
|
+
|
|
477
|
+
* **agent identity in the prompt** <br>
|
|
478
|
+
[`LLM::Agent#repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
|
|
479
|
+
and
|
|
480
|
+
[`LLM::Repl.new`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html#initialize-instance_method)
|
|
481
|
+
accept a `name:` parameter (defaulting to `LLM::Agent#name`) that sets
|
|
482
|
+
the input prompt to `provider(name)> ` and labels transcript messages
|
|
483
|
+
with the agent's name instead of a hardcoded `agent:`. Useful when
|
|
484
|
+
running multiple sessions.
|
|
485
|
+
|
|
486
|
+
* **`/compact` command** <br>
|
|
487
|
+
New built-in `/compact` command frees context window space by dropping
|
|
488
|
+
the oldest messages via
|
|
489
|
+
[`LLM::Compactor::Truncate`](https://r.uby.dev/api-docs/llm.rb/LLM/Compactor/Truncate.html).
|
|
490
|
+
Supports both integer (`/compact 32`) and percentage (`/compact 75%`)
|
|
491
|
+
arguments. Defaults to keeping the last 128 messages.
|
|
492
|
+
|
|
493
|
+
* **tab-completion for `/` commands** <br>
|
|
494
|
+
Pressing Tab on an input line starting with `/` autocompletes the
|
|
495
|
+
command name. Repeated Tab presses cycle through matching commands.
|
|
496
|
+
Powered by
|
|
497
|
+
[`LLM::Command.complete(str)`](https://r.uby.dev/api-docs/llm.rb/LLM/Command.html#complete-class_method)
|
|
498
|
+
which is available outside the REPL too.
|
|
499
|
+
|
|
500
|
+
* **command system enhancements** <br>
|
|
501
|
+
Commands can set parameter defaults in their `call` method signature
|
|
502
|
+
(e.g., `def call(n: 128)`). Aliases like `/quit` now inherit their
|
|
503
|
+
parent's description and parameters. Commands also have access to
|
|
504
|
+
the active `agent` and `repl` via public readers.
|
|
505
|
+
|
|
506
|
+
* **tool argument sorting** <br>
|
|
507
|
+
Tool parameters in the status bar are now displayed in definition
|
|
508
|
+
order (using the new `index` attribute), regardless of the order
|
|
509
|
+
the model returns them.
|
|
510
|
+
|
|
511
|
+
* **expanded markdown rendering** <br>
|
|
512
|
+
The curses-based markdown renderer now handles lists (`<ul>`, `<ol>`),
|
|
513
|
+
blockquotes, horizontal rules, hyperlinks (underline), images
|
|
514
|
+
(`[image: alt text]`), and tables (aligned columns).
|
|
515
|
+
|
|
516
|
+
* **input improvements** <br>
|
|
517
|
+
Ctrl+P and Ctrl+N walk through conversation history (user messages
|
|
518
|
+
only, managed by
|
|
519
|
+
[`LLM::Repl::Walker`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Walker.html)).
|
|
520
|
+
Page Up/Down scroll the transcript by a page. ENTER and BACKSPACE are
|
|
521
|
+
now mapped to raw character codes from `Curses.getch` instead of
|
|
522
|
+
`Curses::Key` constants.
|
|
523
|
+
|
|
524
|
+
### Object
|
|
525
|
+
|
|
526
|
+
* **preserve the original key name in `KeyError` messages** <br>
|
|
527
|
+
`LLM::Object#fetch` now preserves the original key name when a key
|
|
528
|
+
is not found, instead of raising `KeyError` with `key not found: nil`.
|
|
529
|
+
The previous behavior occurred when the given key was not found in
|
|
530
|
+
the stored hash, causing internal lookup to return `nil` and lose
|
|
531
|
+
the original key reference.
|
|
532
|
+
|
|
533
|
+
### Registry
|
|
534
|
+
|
|
535
|
+
* **refresh model metadata across providers** <br>
|
|
536
|
+
Update `data/*.json` files with current provider model listings and
|
|
537
|
+
pricing. Mark several DeepInfra models as deprecated (`meta-llama/
|
|
538
|
+
Meta-Llama-3.1-8B-Instruct`, `Qwen/Qwen1.5-110B-Chat`, and
|
|
539
|
+
`mistralai/Mixtral-8x7B-Instruct-v0.1`). Correct xAI cache-read
|
|
540
|
+
pricing from $0.50 to $0.30 per million input tokens.
|
|
541
|
+
|
|
542
|
+
### Fix
|
|
543
|
+
|
|
544
|
+
* **agent: fix default name resolution when name is not explicitly set** <br>
|
|
545
|
+
Fix a bug where `LLM::Agent` derived its default name from
|
|
546
|
+
`self.class` instead of `self`, causing the name to be `"class"`
|
|
547
|
+
instead of a parameterized version of the actual class name
|
|
548
|
+
(e.g., `"system-admin"` for `SystemAdmin`). The fix uses `self`
|
|
549
|
+
directly, which correctly resolves the class name at the instance
|
|
550
|
+
level.
|
|
551
|
+
|
|
552
|
+
* **function: make Fork::Task and Ractor::Task inherit LLM::Function::Task** <br>
|
|
553
|
+
`LLM::Function::Fork::Task` and `LLM::Function::Ractor::Task` now
|
|
554
|
+
explicitly subclass `LLM::Function::Task` and accept an options hash
|
|
555
|
+
as their second argument, matching the constructor signature used
|
|
556
|
+
by the other four task classes. The interface was already compatible
|
|
557
|
+
but the inheritance was missing by mistake. It is now consistent across
|
|
558
|
+
all six concurrency backends.
|
|
559
|
+
|
|
560
|
+
* **google: fix `stream` parameter leakage that broke the provider** <br>
|
|
561
|
+
Fix a bug in the Google provider where `stream: stream.enabled?` was
|
|
562
|
+
being merged into request parameters, causing API-level errors. The
|
|
563
|
+
Google provider does not use a `stream` parameter. Streaming is
|
|
564
|
+
controlled via the URL path (`streamGenerateContent` vs
|
|
565
|
+
`generateContent`). The fix removes the leaked parameter and correctly
|
|
566
|
+
routes streaming requests through the appropriate path.
|
|
567
|
+
|
|
568
|
+
* **fork: fix deadlock on xchan.rb channel** <br>
|
|
569
|
+
Fix a deadlock in the `:fork` concurrency strategy where both the
|
|
570
|
+
writer and reader could get stuck on the xchan channel, preventing the
|
|
571
|
+
reader from draining the channel. The deadlock surfaced as an errno
|
|
572
|
+
failure, especially with large tool returns. The fix requires xchan.rb
|
|
573
|
+
v0.22.0 and uses the `SOCK_STREAM` socket type for communicating a
|
|
574
|
+
tool's return value.
|
|
575
|
+
|
|
18
576
|
## v12.6.0
|
|
19
577
|
|
|
20
578
|
Changes since `v12.5.1`.
|
|
21
579
|
|
|
22
|
-
This release adds bulk defaults for tools and agents
|
|
580
|
+
This release adds bulk defaults for tools and agents: `LLM::Tool.defaults`
|
|
23
581
|
for setting parameter defaults and `LLM::Agent.set` for mass-assigning
|
|
24
582
|
class-level defaults, both mirrored on ActiveRecord and Sequel agent models.
|
|
25
583
|
|
|
@@ -55,7 +613,7 @@ prior call.
|
|
|
55
613
|
On cancel, `LLM::Interrupt` is now raised on the thread that is
|
|
56
614
|
running a tool. The tool can rescue `LLM::Interrupt` and gracefully
|
|
57
615
|
terminate (e.g., clean up resources). The previous approach used
|
|
58
|
-
`Thread#interrupt` which was less reliable
|
|
616
|
+
`Thread#interrupt` which was less reliable. It did not interrupt a
|
|
59
617
|
sleeping thread.
|
|
60
618
|
|
|
61
619
|
* **function: suppress thread exception reporting in `:thread` concurrency** <br>
|
|
@@ -81,15 +639,15 @@ prior call.
|
|
|
81
639
|
`LLM::Interrupt` is now raised on the active fiber via `Fiber#raise`
|
|
82
640
|
when interrupting `:fiber`-concurrency tools.
|
|
83
641
|
<br><br>
|
|
84
|
-
`Task#interrupt!` now dispatches by task type
|
|
85
|
-
threads, `Fiber#raise` for fibers
|
|
642
|
+
`Task#interrupt!` now dispatches by task type: `Thread#raise` for
|
|
643
|
+
threads, `Fiber#raise` for fibers. Making interruption reliable
|
|
86
644
|
across all concurrency strategies.
|
|
87
645
|
|
|
88
646
|
* **function: raise `LLM::Interrupt` on fork-backed tool tasks** <br>
|
|
89
647
|
`LLM::Interrupt` is now raised on the main thread of a fork child
|
|
90
648
|
process via `Thread.main.raise(LLM::Interrupt)` when interrupting
|
|
91
649
|
`:fork`-concurrency tools, and the fork `Task#wait` re-raises the
|
|
92
|
-
interrupt on the parent side
|
|
650
|
+
interrupt on the parent side. Making interruption reliable across
|
|
93
651
|
all concurrency strategies including `:fork`.
|
|
94
652
|
|
|
95
653
|
* **function: raise `LLM::Interrupt` on `Async::Task`-backed tool tasks** <br>
|
|
@@ -107,7 +665,7 @@ prior call.
|
|
|
107
665
|
raises `LLM::Interrupt` on the ractor's main thread.
|
|
108
666
|
<br><br>
|
|
109
667
|
`Task#interrupt!` delegates to the mailbox to send the interrupt
|
|
110
|
-
message
|
|
668
|
+
message. Extending reliable interruption to the `:ractor`
|
|
111
669
|
concurrency strategy.
|
|
112
670
|
|
|
113
671
|
## v12.5.1
|
|
@@ -254,7 +812,7 @@ OpenAI, Google, DeepInfra, DeepSeek, and xAI model entries.
|
|
|
254
812
|
|
|
255
813
|
* **repl: display command errors in the curses UI** <br>
|
|
256
814
|
Commands invoked with too few arguments now display an error
|
|
257
|
-
message
|
|
815
|
+
message: `command(<name>): too few arguments`. Displayed directly in
|
|
258
816
|
the curses transcript area, giving immediate feedback instead
|
|
259
817
|
of silently failing.
|
|
260
818
|
|
|
@@ -378,7 +936,7 @@ a command system foundation with the `/exit` command, and several new
|
|
|
378
936
|
keybindings (Ctrl+F, Ctrl+K, Ctrl+Y). Tool calls are rendered with a
|
|
379
937
|
compact function-call syntax in the status bar.
|
|
380
938
|
|
|
381
|
-
Two new built-in tools
|
|
939
|
+
Two new built-in tools: `LLM::Tool::Ls` and `LLM::Tool::Which` are
|
|
382
940
|
available as opt-in additions for file listing and executable lookup.
|
|
383
941
|
|
|
384
942
|
Model metadata has been refreshed across providers, the REPL loop
|
|
@@ -445,7 +1003,7 @@ area.
|
|
|
445
1003
|
The curses-based REPL input now detects paste operations by tracking
|
|
446
1004
|
the rate at which characters arrive. A paste rate of ≤50ms is
|
|
447
1005
|
assumed to be a burst of characters that could only be explained by
|
|
448
|
-
a paste
|
|
1006
|
+
a paste. No human types that fast. Multiline pastes are supported
|
|
449
1007
|
through internal refactoring of the input handling logic.
|
|
450
1008
|
|
|
451
1009
|
* **repl: optimize paste mode rendering** <br>
|
|
@@ -468,7 +1026,7 @@ area.
|
|
|
468
1026
|
|
|
469
1027
|
* **repl: render tool calls in a function-call syntax** <br>
|
|
470
1028
|
The curses-based REPL status bar now renders tool calls with a
|
|
471
|
-
compact function-call syntax
|
|
1029
|
+
compact function-call syntax: `tool(key: value)` instead of
|
|
472
1030
|
`tool: name`. Strings are quoted and truncated, arrays show their
|
|
473
1031
|
first two elements, and hashes collapse to `{…}`, making it easier
|
|
474
1032
|
to see what arguments the model is passing. The `tool done` status
|
|
@@ -596,8 +1154,8 @@ tracer logger instances with less verbosity.
|
|
|
596
1154
|
streamed content via `#<<`. `LLM::Stream::Disabled` represents an explicitly
|
|
597
1155
|
disabled stream with no-op callbacks.
|
|
598
1156
|
|
|
599
|
-
This is part of an internal refactoring that lets all stream values
|
|
600
|
-
objects, `true`, `false`, `nil`, and `LLM::Stream` instances themselves
|
|
1157
|
+
This is part of an internal refactoring that lets all stream values: IO
|
|
1158
|
+
objects, `true`, `false`, `nil`, and `LLM::Stream` instances themselves
|
|
601
1159
|
be represented by the same `LLM::Stream` interface via the new
|
|
602
1160
|
`LLM::Stream.try` factory method.
|
|
603
1161
|
|
|
@@ -666,7 +1224,7 @@ tracer logger instances with less verbosity.
|
|
|
666
1224
|
|
|
667
1225
|
* **repl: add extra padding between markdown nodes** <br>
|
|
668
1226
|
The curses-based REPL markdown renderer now adds extra vertical spacing
|
|
669
|
-
between certain markdown elements
|
|
1227
|
+
between certain markdown elements: paragraphs, headers, and codeblocks
|
|
670
1228
|
for improved readability of model responses.
|
|
671
1229
|
|
|
672
1230
|
* **repl: add a visual divider between transcript and the rows below it** <br>
|