llm.rb 12.3.1 → 12.5.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 +395 -0
- data/README.md +103 -16
- data/data/anthropic.json +249 -249
- data/data/bedrock.json +2038 -1879
- data/data/deepinfra.json +591 -591
- data/data/deepseek.json +31 -31
- data/data/google.json +332 -329
- data/data/mistral.json +381 -381
- data/data/openai.json +1132 -1132
- data/data/xai.json +138 -138
- data/data/zai.json +165 -165
- data/lib/llm/agent.rb +12 -7
- data/lib/llm/buffer.rb +15 -0
- data/lib/llm/context/deserializer.rb +2 -5
- data/lib/llm/context.rb +4 -5
- data/lib/llm/function.rb +2 -35
- data/lib/llm/message.rb +12 -2
- data/lib/llm/provider.rb +11 -1
- data/lib/llm/providers/anthropic/stream_parser.rb +3 -12
- data/lib/llm/providers/anthropic.rb +11 -0
- data/lib/llm/providers/bedrock/stream_parser.rb +4 -13
- data/lib/llm/providers/google/stream_parser.rb +3 -12
- data/lib/llm/providers/google.rb +7 -0
- data/lib/llm/providers/mistral.rb +11 -0
- data/lib/llm/providers/ollama/stream_parser.rb +4 -4
- data/lib/llm/providers/ollama.rb +11 -0
- data/lib/llm/providers/openai/responses/stream_parser.rb +4 -14
- data/lib/llm/providers/openai/responses.rb +10 -0
- data/lib/llm/providers/openai/stream_parser.rb +5 -15
- data/lib/llm/providers/openai.rb +11 -0
- data/lib/llm/repl/command.rb +201 -0
- data/lib/llm/repl/commands/exit.rb +23 -0
- data/lib/llm/repl/commands/help.rb +24 -0
- data/lib/llm/repl/input.rb +118 -35
- data/lib/llm/repl/stream.rb +43 -8
- data/lib/llm/repl/transcript.rb +6 -0
- data/lib/llm/repl/window.rb +28 -6
- data/lib/llm/repl.rb +125 -27
- data/lib/llm/stream.rb +2 -7
- data/lib/llm/tools/ls.rb +30 -0
- data/lib/llm/tools/which.rb +38 -0
- data/lib/llm/version.rb +1 -1
- data/resources/deepdive.md +67 -1
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 665281b1c81541ff2f9621138cee510e473dfbda2c7dcff7d1a324e5fe558c89
|
|
4
|
+
data.tar.gz: c3ee596e41885038dc831ef6459da330d1984fea0125a9dbc5aa7d0ff8e21061
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cecf7fa0a2b1c6aff010c537b6741c74e537104eb9a67e3c2cd2840d06963040834c87263f71f6a1f815a4be831efa7740b2c03eb3f5fde9bbb274be4ee69c5c
|
|
7
|
+
data.tar.gz: 8b695e7c1656bf427bb095a257e954437b5b2dfc46e4d22349eb91dab9981eac1c5fc6b46bca89ecfec14986d386a0fba6303ef4dcf39a82345d3a136e944092
|
data/CHANGELOG.md
CHANGED
|
@@ -15,8 +15,403 @@
|
|
|
15
15
|
|
|
16
16
|
## What's next
|
|
17
17
|
|
|
18
|
+
Changes since `v12.5.0`.
|
|
19
|
+
|
|
20
|
+
## v12.5.0
|
|
21
|
+
|
|
22
|
+
Changes since `v12.4.0`.
|
|
23
|
+
|
|
24
|
+
This release extends the REPL command system with typed parameters, a
|
|
25
|
+
built-in `/help` command, command aliases (`/quit`), and cancellation
|
|
26
|
+
via the 'Esc' key.
|
|
27
|
+
|
|
28
|
+
The default HTTP timeout is increased to 15 minutes (900s) to better
|
|
29
|
+
accommodate reasoning models and large structured outputs.
|
|
30
|
+
`LLM::Agent#deserialize` and `LLM::Agent#restore` now return `self` for
|
|
31
|
+
method chaining, and `LLM::Buffer#pop` is added for tail-end message
|
|
32
|
+
removal.
|
|
33
|
+
|
|
34
|
+
Tool resolution gains a fallback to the global `LLM::Function` registry
|
|
35
|
+
before raising `LLM::NoSuchToolError`, and `pending_functions` aliases
|
|
36
|
+
are added on both contexts and agents for a consistent interface.
|
|
37
|
+
|
|
38
|
+
Several REPL bugs are fixed including parameter state leakage across
|
|
39
|
+
turns and invalid tool-call error routing.
|
|
40
|
+
|
|
41
|
+
Model metadata is refreshed across all providers with new Anthropic,
|
|
42
|
+
OpenAI, Google, DeepInfra, DeepSeek, and xAI model entries.
|
|
43
|
+
|
|
44
|
+
### Add
|
|
45
|
+
|
|
46
|
+
#### Buffer & function internals
|
|
47
|
+
|
|
48
|
+
* **buffer: add `LLM::Buffer#pop`** <br>
|
|
49
|
+
Add `LLM::Buffer#pop` for removing the last message from the tail
|
|
50
|
+
of the buffer, complementing the existing `#<<` and array-style
|
|
51
|
+
message management.
|
|
52
|
+
|
|
53
|
+
* **function: add registry fallback for tool resolution** <br>
|
|
54
|
+
When resolving tool calls from a message, if the tool is not found
|
|
55
|
+
in the available tools list, it now also looks up the global
|
|
56
|
+
`LLM::Function` registry via `LLM::Function.find_by_name` before
|
|
57
|
+
creating a placeholder function. This improves tool resolution for
|
|
58
|
+
tools that are registered globally but not passed directly through
|
|
59
|
+
the request tool set.
|
|
60
|
+
|
|
61
|
+
#### Consistent `pending_functions` aliases
|
|
62
|
+
|
|
63
|
+
* **context: alias `LLM::Context#functions` as `LLM::Context#pending_functions`** <br>
|
|
64
|
+
Add `LLM::Context#pending_functions` as an alias for `LLM::Context#functions`,
|
|
65
|
+
so callers that prefer the more descriptive `pending_functions` name can use
|
|
66
|
+
it instead of `functions` when checking for unresolved tool work.
|
|
67
|
+
|
|
68
|
+
* **agent: alias `LLM::Agent#functions` as `LLM::Agent#pending_functions`** <br>
|
|
69
|
+
Add `LLM::Agent#pending_functions` as an alias for `LLM::Agent#functions`,
|
|
70
|
+
matching the same alias on `LLM::Context`, so callers have a consistent
|
|
71
|
+
`pending_functions` interface across both contexts and agents.
|
|
72
|
+
|
|
73
|
+
#### REPL command system
|
|
74
|
+
|
|
75
|
+
* **repl: extend command system with parameter support** <br>
|
|
76
|
+
Commands can now declare typed parameters using the `parameter`
|
|
77
|
+
DSL, modelled after `LLM::Tool` and `LLM::Schema` conventions.
|
|
78
|
+
Parameters can be marked as required with `required %i[...]`,
|
|
79
|
+
and values are type-checked before being passed to `call`.
|
|
80
|
+
Argument parsing is handled by the repl: arguments are split
|
|
81
|
+
from the input string and assigned to parameters by position.
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
class Greeter < LLM::Command
|
|
85
|
+
name "greet"
|
|
86
|
+
description "Greets the given name"
|
|
87
|
+
parameter :name, String, "The person's name"
|
|
88
|
+
required %i[name]
|
|
89
|
+
|
|
90
|
+
def call(name:)
|
|
91
|
+
write("Welcome #{name}!\n")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
* **repl: add `help` command** <br>
|
|
97
|
+
Add `LLM::Repl::Help` as a new built-in command, registered
|
|
98
|
+
automatically via the command registry. Typing `/help` shows
|
|
99
|
+
the `help` command's own name, description, and parameters,
|
|
100
|
+
while `/help <name>` shows details for a specific command,
|
|
101
|
+
including its parameters and whether each is required or
|
|
102
|
+
optional. Unknown command names produce an error message.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
class Help < Command
|
|
106
|
+
name "help"
|
|
107
|
+
description "show help for a given command"
|
|
108
|
+
parameter :name, String, "The name of a command"
|
|
109
|
+
|
|
110
|
+
def call(name: nil)
|
|
111
|
+
if name.nil?
|
|
112
|
+
write("\n#{self.class.help}\n\n")
|
|
113
|
+
elsif command = LLM::Command.find_by(name:)
|
|
114
|
+
write("\n#{command.help}\n\n")
|
|
115
|
+
else
|
|
116
|
+
write "\nNo help for #{name} was found" \
|
|
117
|
+
"\nThat command doesn't exist.\n\n"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
* **repl: add support for command aliases** <br>
|
|
124
|
+
Commands can now be aliased by creating a subclass of another
|
|
125
|
+
command (with `LLM::Command` as an indirect ancestor). The
|
|
126
|
+
first alias introduced is `/quit` as an alias of `/exit`.
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
class Quit < Command::Exit
|
|
130
|
+
name "quit"
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
* **repl: add `Command::Parameter#optional?`** <br>
|
|
135
|
+
Parameters now expose an `#optional?` method that returns `true`
|
|
136
|
+
when a parameter has not been marked as required, making it
|
|
137
|
+
possible to query parameter optionality programmatically.
|
|
138
|
+
|
|
139
|
+
* **repl: add `LLM::Repl::Command#write`** <br>
|
|
140
|
+
Commands can now write output to the transcript via the `write`
|
|
141
|
+
method. Commands also receive a reference to the active repl
|
|
142
|
+
through their `#initialize` method, making it possible to
|
|
143
|
+
interact with the repl window from within a command.
|
|
144
|
+
|
|
145
|
+
* **repl: display command errors in the curses UI** <br>
|
|
146
|
+
Commands invoked with too few arguments now display an error
|
|
147
|
+
message — `command(<name>): too few arguments` — directly in
|
|
148
|
+
the curses transcript area, giving immediate feedback instead
|
|
149
|
+
of silently failing.
|
|
150
|
+
|
|
151
|
+
* **repl: add `LLM::Command` convenience constant** <br>
|
|
152
|
+
Add `LLM::Command = LLM::Repl::Command` as a shorter alias,
|
|
153
|
+
available once `"llm/repl"` is required.
|
|
154
|
+
|
|
155
|
+
#### Misc
|
|
156
|
+
|
|
157
|
+
* **repl: implement cancellation with the 'Esc' key** <br>
|
|
158
|
+
The curses-based REPL now supports cancelling an active model
|
|
159
|
+
request by pressing the 'Esc' key. When a request is in progress,
|
|
160
|
+
the status line shows `thinking • Esc to cancel`, and pressing
|
|
161
|
+
Esc calls `LLM::Agent#cancel!` to interrupt the request. The
|
|
162
|
+
transcript displays `request cancelled!` to confirm the
|
|
163
|
+
cancellation.
|
|
164
|
+
|
|
165
|
+
### Change
|
|
166
|
+
|
|
167
|
+
#### Misc
|
|
168
|
+
|
|
169
|
+
* **provider: increase default timeout to 900s** <br>
|
|
170
|
+
The default HTTP timeout for all providers has been increased from
|
|
171
|
+
180 to 900 seconds (15 minutes) to better accommodate long-running
|
|
172
|
+
requests such as reasoning models and large structured outputs.
|
|
173
|
+
|
|
174
|
+
* **agent: `deserialize` and `restore` return `self`** <br>
|
|
175
|
+
`LLM::Agent#deserialize` and `LLM::Agent#restore` now return `self`
|
|
176
|
+
(the agent instance) instead of forwarding the context's return
|
|
177
|
+
value, enabling method chaining after restoring agent state.
|
|
178
|
+
|
|
179
|
+
* **context: discard all messages from a cancelled turn** <br>
|
|
180
|
+
When `LLM::Context#cancel!` is called, all messages added during
|
|
181
|
+
that turn are now discarded via `Buffer#slice!`, preventing edge
|
|
182
|
+
cases where dangling tool calls between turns caused repeated
|
|
183
|
+
cancellation loops. The `#repair!` method now handles tool call
|
|
184
|
+
cancellations on the next turn instead of mutating the conversation
|
|
185
|
+
buffer directly at cancellation time.
|
|
186
|
+
|
|
187
|
+
* **stream: drop the `error` argument from `on_tool_call`** <br>
|
|
188
|
+
The `on_tool_call` callback no longer accepts an `error` argument.
|
|
189
|
+
Previously, stream parsers passed both a tool and an optional error,
|
|
190
|
+
requiring boilerplate like `if error; queue << error; end` in every
|
|
191
|
+
callback. Error handling is now pushed directly onto the stream queue
|
|
192
|
+
inside each provider's stream parser, so `on_tool_call(tool)` is the
|
|
193
|
+
only signature. The REPL stream and base `LLM::Stream` class have
|
|
194
|
+
been updated accordingly.
|
|
195
|
+
|
|
196
|
+
#### REPL internals
|
|
197
|
+
|
|
198
|
+
* **repl: pass the repl instance to command constructors** <br>
|
|
199
|
+
`LLM::Repl::Command` subclasses now receive the active repl
|
|
200
|
+
instance via `initialize(repl)`, enabling commands to write
|
|
201
|
+
to the transcript and interact with the repl window.
|
|
202
|
+
|
|
203
|
+
* **repl: `Command#write` prefixes messages with the command name** <br>
|
|
204
|
+
The `#write` method now prefixes output with `command(<name>): `
|
|
205
|
+
so command messages are consistent with the `user:` and `agent:`
|
|
206
|
+
labels in the transcript. The prefix can be customised with the
|
|
207
|
+
`who:` keyword argument, or set to `who: nil` to disable it
|
|
208
|
+
entirely.
|
|
209
|
+
|
|
210
|
+
### Fix
|
|
211
|
+
|
|
212
|
+
#### Misc
|
|
213
|
+
|
|
214
|
+
* **function: avoid silent skip of tools not found in available tools** <br>
|
|
215
|
+
When a model calls a tool that is not present in the available tools
|
|
216
|
+
list, instead of silently skipping the tool call (via `next`), a
|
|
217
|
+
`LLM::NoSuchToolError` is now raised so the model receives feedback
|
|
218
|
+
about the invalid tool call and can correct course.
|
|
219
|
+
<br><br>
|
|
220
|
+
An additional fallback to the global `LLM::Function` registry is
|
|
221
|
+
tried before raising, so globally registered tools are still
|
|
222
|
+
resolved even when not in the per-request tool set.
|
|
223
|
+
|
|
224
|
+
#### REPL bugs
|
|
225
|
+
|
|
226
|
+
* **repl: don't persist parameter state between turns** <br>
|
|
227
|
+
Parameter state (such as `Parameter#value`) was leaking across
|
|
228
|
+
turns because the same parameter objects were being mutated
|
|
229
|
+
in place. A duplicate set of parameters is now created for each
|
|
230
|
+
turn, keeping the original parameter definitions intact and
|
|
231
|
+
preventing stale state from carrying over.
|
|
232
|
+
|
|
233
|
+
* **repl: reply with error when given an invalid tool** <br>
|
|
234
|
+
When the model tries to call a tool that does not exist, the
|
|
235
|
+
error is now pushed onto the stream queue so the model can
|
|
236
|
+
see the error and correct course, instead of silently dropping
|
|
237
|
+
the invalid tool call and leaving it to `Context#repair` to
|
|
238
|
+
remove it from history.
|
|
239
|
+
|
|
240
|
+
* **repl: fix save of initial runtime state** <br>
|
|
241
|
+
Fix a bug in `LLM::Repl#configure` where a non-existent path
|
|
242
|
+
argument was treated as no path at all, preventing the initial
|
|
243
|
+
runtime state from being saved after the first turn. The correct
|
|
244
|
+
behavior is to create the file so it can be written to after
|
|
245
|
+
the first turn completes.
|
|
246
|
+
|
|
247
|
+
### Refresh
|
|
248
|
+
|
|
249
|
+
* **Refresh model metadata across all providers** <br>
|
|
250
|
+
Update model listings, pricing, capabilities, reasoning options,
|
|
251
|
+
modality support, context limits, and release dates across all
|
|
252
|
+
provider registries (Anthropic, AWS Bedrock, DeepInfra, DeepSeek,
|
|
253
|
+
Google, Mistral, OpenAI, xAI, and ZAI). Notable changes include
|
|
254
|
+
Anthropic claude-opus-4-8 and claude-sonnet-4-6 additions with
|
|
255
|
+
effort-based reasoning, OpenAI gpt-5.6-sol/terra/luna and
|
|
256
|
+
gpt-5-codex additions, Google gemini-3-pro-preview and
|
|
257
|
+
gemini-3-flash-preview additions, DeepInfra Qwen3.5 and DeepSeek
|
|
258
|
+
V4 model additions, and updated xAI Grok model entries.
|
|
259
|
+
|
|
260
|
+
## v12.4.0
|
|
261
|
+
|
|
18
262
|
Changes since `v12.3.1`.
|
|
19
263
|
|
|
264
|
+
This release brings major improvements to the curses-based REPL
|
|
265
|
+
(`LLM::Agent#repl`). The REPL now supports saving and restoring runtime
|
|
266
|
+
state across sessions, automatic paste-mode detection for fast bulk input,
|
|
267
|
+
a command system foundation with the `/exit` command, and several new
|
|
268
|
+
keybindings (Ctrl+F, Ctrl+K, Ctrl+Y). Tool calls are rendered with a
|
|
269
|
+
compact function-call syntax in the status bar.
|
|
270
|
+
|
|
271
|
+
Two new built-in tools — `LLM::Tool::Ls` and `LLM::Tool::Which` — are
|
|
272
|
+
available as opt-in additions for file listing and executable lookup.
|
|
273
|
+
|
|
274
|
+
Model metadata has been refreshed across providers, the REPL loop
|
|
275
|
+
internals have been refactored to use `catch`/`throw` for cleaner command
|
|
276
|
+
routing, and several bugs have been fixed including a tracer restoration
|
|
277
|
+
issue in the agent ensure clause and a missing cursor in the REPL input
|
|
278
|
+
area.
|
|
279
|
+
|
|
280
|
+
### Add
|
|
281
|
+
|
|
282
|
+
* **repl: allow runtime state to be saved and restored** <br>
|
|
283
|
+
`LLM::Agent#repl` now accepts a `path:` option that serializes
|
|
284
|
+
runtime state to the filesystem. When the path already exists,
|
|
285
|
+
runtime state is restored when the read-eval-print loop starts.
|
|
286
|
+
Otherwise the path is written after the first turn, making it
|
|
287
|
+
possible to resume a session across process restarts.
|
|
288
|
+
|
|
289
|
+
* **repl: scroll to the bottom on submit** <br>
|
|
290
|
+
The curses-based REPL now scrolls the transcript to the bottom when
|
|
291
|
+
the user submits their input, so the latest response is visible
|
|
292
|
+
without needing to scroll down manually.
|
|
293
|
+
|
|
294
|
+
* **repl: add Ctrl+F to move the cursor forward** <br>
|
|
295
|
+
The curses-based REPL input now supports Ctrl+F to move the cursor
|
|
296
|
+
forward by one column, matching common terminal editing conventions
|
|
297
|
+
found in shells like `/bin/sh`.
|
|
298
|
+
|
|
299
|
+
* **repl: add Ctrl+K to erase from cursor to end of line** <br>
|
|
300
|
+
The curses-based REPL input now supports Ctrl+K to erase all text
|
|
301
|
+
from the cursor position to the end of the input buffer, matching
|
|
302
|
+
common terminal editing conventions found in shells like `/bin/sh`.
|
|
303
|
+
|
|
304
|
+
* **repl: add Ctrl+Y to paste previously killed text** <br>
|
|
305
|
+
The curses-based REPL input now supports Ctrl+Y to insert the most
|
|
306
|
+
recently killed text (via Ctrl+K) at the current cursor position,
|
|
307
|
+
matching the yank/paste convention found in shells like `/bin/sh`.
|
|
308
|
+
The killed text is stored in an internal copy buffer so it can be
|
|
309
|
+
pasted multiple times or at different cursor positions.
|
|
310
|
+
|
|
311
|
+
* **repl: add command system foundation** <br>
|
|
312
|
+
Add `LLM::Repl::Command` as a new base class for REPL commands,
|
|
313
|
+
along with the first built-in command `LLM::Repl::Command::Exit`
|
|
314
|
+
which exits the read-eval-print loop via `throw(:exit)`.
|
|
315
|
+
Commands are identified by a name and can be looked up through
|
|
316
|
+
`Command.find_by`. This is the foundation for the `/` command
|
|
317
|
+
syntax used in the REPL input line.
|
|
318
|
+
|
|
319
|
+
* **repl: connect the command system to user input** <br>
|
|
320
|
+
The curses-based REPL now routes user input through the command
|
|
321
|
+
system. Any input string beginning with `"/"` is matched against
|
|
322
|
+
the command registry via `Command.find_by`, and the corresponding
|
|
323
|
+
command is executed instead of being forwarded to the model.
|
|
324
|
+
This makes built-in commands like `/exit` functional from the
|
|
325
|
+
input line. Command arguments are not yet supported.
|
|
326
|
+
|
|
327
|
+
* **repl: add `LLM::Repl::Command.registry`** <br>
|
|
328
|
+
Add `LLM::Repl::Command.registry` for auto-registering command
|
|
329
|
+
subclasses. The `inherited` hook captures each new subclass and
|
|
330
|
+
stores it in the registry, making it possible to enumerate all
|
|
331
|
+
available commands at runtime. Built-in commands like Exit are
|
|
332
|
+
automatically registered when the command file is loaded.
|
|
333
|
+
|
|
334
|
+
* **repl: detect and handle paste mode in the input line** <br>
|
|
335
|
+
The curses-based REPL input now detects paste operations by tracking
|
|
336
|
+
the rate at which characters arrive. A paste rate of ≤50ms is
|
|
337
|
+
assumed to be a burst of characters that could only be explained by
|
|
338
|
+
a paste — no human types that fast. Multiline pastes are supported
|
|
339
|
+
through internal refactoring of the input handling logic.
|
|
340
|
+
|
|
341
|
+
* **repl: optimize paste mode rendering** <br>
|
|
342
|
+
Track the paste state with an internal `@paste` variable and switch
|
|
343
|
+
to a faster input path during paste operations. While in paste mode,
|
|
344
|
+
the input buffer is drained via `Curses.getch`, bypassing the more
|
|
345
|
+
expensive char-by-char render path used for ordinary interactive
|
|
346
|
+
input. This makes pasting large amounts of text noticeably faster.
|
|
347
|
+
|
|
348
|
+
* **Add `LLM::Tool::Ls`** <br>
|
|
349
|
+
Add a built-in tool for listing files and directories, with optional
|
|
350
|
+
glob pattern filtering to narrow results. <br>
|
|
351
|
+
It must be required explicitly with `require "llm/tools/ls"`.
|
|
352
|
+
|
|
353
|
+
* **Add `LLM::Tool::Which`** <br>
|
|
354
|
+
Add a built-in tool for locating an executable on the system PATH.
|
|
355
|
+
This lets an agent check whether a command is available before
|
|
356
|
+
attempting to run it, avoiding failed subprocess calls. <br>
|
|
357
|
+
It must be required explicitly with `require "llm/tools/which"`.
|
|
358
|
+
|
|
359
|
+
* **repl: render tool calls in a function-call syntax** <br>
|
|
360
|
+
The curses-based REPL status bar now renders tool calls with a
|
|
361
|
+
compact function-call syntax — `tool(key: value)` instead of
|
|
362
|
+
`tool: name`. Strings are quoted and truncated, arrays show their
|
|
363
|
+
first two elements, and hashes collapse to `{…}`, making it easier
|
|
364
|
+
to see what arguments the model is passing. The `tool done` status
|
|
365
|
+
message has been removed since the tool call itself conveys
|
|
366
|
+
completion information.
|
|
367
|
+
|
|
368
|
+
### Change
|
|
369
|
+
|
|
370
|
+
* **Refresh model metadata** <br>
|
|
371
|
+
Update model listings, pricing, and capabilities across providers.
|
|
372
|
+
Fix GPT-5.6 model family names in the OpenAI registry (`gpt` to
|
|
373
|
+
`gpt-sol`, `gpt-nano` to `gpt-luna`, `gpt-mini` to `gpt-terra`).
|
|
374
|
+
Add OpenAI models (`gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`)
|
|
375
|
+
to the AWS Bedrock registry. Update DeepInfra pricing for
|
|
376
|
+
`DeepSeek-V3` and `Sky-T1-32B-Preview`. Fix Google model knowledge
|
|
377
|
+
cutoff dates.
|
|
378
|
+
|
|
379
|
+
* **repl: control the loop with catch & throw** <br>
|
|
380
|
+
The curses-based REPL input loop now uses `catch(:exit)` and
|
|
381
|
+
`throw(:exit)` instead of returning the `:exit` symbol and
|
|
382
|
+
breaking out of the loop. This enables the `/command` syntax
|
|
383
|
+
without requiring an `:exit` return value to be propagated
|
|
384
|
+
through a potentially deeply nested call path.
|
|
385
|
+
|
|
386
|
+
* **repl: replace Ctrl+D with shell-like delete-at-cursor** <br>
|
|
387
|
+
The curses-based REPL input now treats Ctrl+D as a delete action
|
|
388
|
+
that removes the character at the current cursor position, matching
|
|
389
|
+
the shell/Emacs convention where Ctrl+D deletes the character under
|
|
390
|
+
the cursor instead of signalling end-of-file. The previous Ctrl+D
|
|
391
|
+
behaviour (exiting the REPL) is superseded by the `/exit` command.
|
|
392
|
+
|
|
393
|
+
* **repl: switch to 'Thinking' mode after tool return** <br>
|
|
394
|
+
The curses-based REPL status line now switches to "Thinking" mode
|
|
395
|
+
after a tool returns, so the user can see the agent is processing
|
|
396
|
+
the tool result rather than showing a stale tool-call status.
|
|
397
|
+
|
|
398
|
+
### Fix
|
|
399
|
+
|
|
400
|
+
* **agent: fix a subtle typo in the ensure clause** <br>
|
|
401
|
+
Fix a subtle typo in `LLM::Agent` where the deprecated `trace` local
|
|
402
|
+
variable was given preference over `tracer` (the preferred local name)
|
|
403
|
+
in an `ensure` clause. The `trace` local was supported for backward
|
|
404
|
+
compatibility but the ensure clause still referenced `trace` instead of
|
|
405
|
+
`tracer`, which meant the previous tracer was never restored when the
|
|
406
|
+
REPL session ended.
|
|
407
|
+
|
|
408
|
+
* **repl: restore the cursor in the input area** <br>
|
|
409
|
+
Remove the `Curses.curs_set(0)` call from the REPL redraw method,
|
|
410
|
+
which was inadvertently hiding the cursor and making it impossible
|
|
411
|
+
to see the current position in the input area. The input field is
|
|
412
|
+
now always drawn at its full height so the cursor position is
|
|
413
|
+
correctly maintained after each redraw.
|
|
414
|
+
|
|
20
415
|
## v12.3.1
|
|
21
416
|
|
|
22
417
|
Changes since `v12.3.0`.
|
data/README.md
CHANGED
|
@@ -129,28 +129,56 @@ This feature requires that the [curses](https://github.com/ruby/curses)
|
|
|
129
129
|
and [kramdown](https://github.com/gettalong/kramdown) libraries are
|
|
130
130
|
installed and available to require.
|
|
131
131
|
|
|
132
|
+
The TUI displays a status line with a context-usage bar and cost
|
|
133
|
+
counter, a scrollable transcript with markdown rendering, and a
|
|
134
|
+
multi-line input area. The UI stays responsive while the model
|
|
135
|
+
is generating a response.
|
|
136
|
+
|
|
137
|
+
##### REPL: Agent
|
|
138
|
+
|
|
139
|
+
A REPL session is started by calling `repl` on any agent
|
|
140
|
+
instance. The session inherits the agent's model, tools,
|
|
141
|
+
skills, and instructions.
|
|
142
|
+
|
|
132
143
|
```ruby
|
|
144
|
+
require "llm"
|
|
145
|
+
|
|
133
146
|
llm = LLM.deepseek(key: ENV["KEY"])
|
|
134
147
|
agent = LLM::Agent.new(llm)
|
|
135
148
|
agent.repl
|
|
136
149
|
```
|
|
137
150
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
151
|
+
##### REPL: State
|
|
152
|
+
|
|
153
|
+
The `path:` option accepts a file path where runtime state
|
|
154
|
+
is read from and written to. This lets you resume a
|
|
155
|
+
conversation across REPL sessions.
|
|
143
156
|
|
|
144
157
|
```ruby
|
|
158
|
+
require "llm"
|
|
159
|
+
|
|
145
160
|
llm = LLM.deepseek(key: ENV["KEY"])
|
|
146
161
|
agent = LLM::Agent.new(llm)
|
|
147
|
-
agent.repl(
|
|
162
|
+
agent.repl(path: "session.json")
|
|
148
163
|
```
|
|
149
164
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
for
|
|
165
|
+
##### REPL: Tools
|
|
166
|
+
|
|
167
|
+
The `tools` option lets you attach additional tools
|
|
168
|
+
for the duration of the session. This is in addition to
|
|
169
|
+
any tools that might already be associated with an agent.
|
|
170
|
+
|
|
171
|
+
A number of optional tools are distributed as part of
|
|
172
|
+
llm.rb. They power the agents that can be found in the
|
|
173
|
+
[agents/](agents/) directory.
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
require "llm"
|
|
177
|
+
|
|
178
|
+
llm = LLM.deepseek(key: ENV["KEY"])
|
|
179
|
+
agent = LLM::Agent.new(llm)
|
|
180
|
+
agent.repl(tools: [Debugger])
|
|
181
|
+
```
|
|
154
182
|
|
|
155
183
|
The following example starts a read-eval-print loop
|
|
156
184
|
with all of the builtin tools available.
|
|
@@ -164,18 +192,77 @@ agent = LLM::Agent.new(llm)
|
|
|
164
192
|
agent.repl(tools: LLM::Tool.subclasses)
|
|
165
193
|
```
|
|
166
194
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`
|
|
170
|
-
|
|
171
|
-
of [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html).
|
|
195
|
+
##### REPL: Skills
|
|
196
|
+
|
|
197
|
+
The `skills` option lets you load extra skill directories
|
|
198
|
+
without attaching them to an agent permanently.
|
|
172
199
|
|
|
173
200
|
```ruby
|
|
201
|
+
require "llm"
|
|
202
|
+
|
|
174
203
|
llm = LLM.deepseek(key: ENV["KEY"])
|
|
175
|
-
agent = LLM::Agent.new(llm
|
|
204
|
+
agent = LLM::Agent.new(llm)
|
|
205
|
+
agent.repl(skills: [__dir__])
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
##### REPL: Tracer
|
|
209
|
+
|
|
210
|
+
By default the tracer is disabled for the duration of the
|
|
211
|
+
session. Setting `tracer: true` configures the REPL to use
|
|
212
|
+
the tracer associated with an instance of
|
|
213
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html).
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
require "llm"
|
|
217
|
+
|
|
218
|
+
llm = LLM.deepseek(key: ENV["KEY"])
|
|
219
|
+
tracer = LLM.logger(llm, path: "agent.log")
|
|
220
|
+
agent = LLM::Agent.new(llm, tracer:)
|
|
176
221
|
agent.repl(tracer: true, tools: [Debugger])
|
|
177
222
|
```
|
|
178
223
|
|
|
224
|
+
##### REPL: Commands
|
|
225
|
+
|
|
226
|
+
Commands are recognized by a `/` prefix and are backed by the
|
|
227
|
+
[`LLM::Repl::Command`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Command.html)
|
|
228
|
+
class, which can be subclassed to add custom commands. Once you
|
|
229
|
+
create a subclass, it is automatically added to the repl. A command
|
|
230
|
+
can have zero or more parameters, and all parameters are presumed
|
|
231
|
+
to be a String (at least for now).
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
require "llm"
|
|
235
|
+
require "llm/repl"
|
|
236
|
+
|
|
237
|
+
class Greeter < LLM::Command
|
|
238
|
+
name "greet"
|
|
239
|
+
description "Greets the given name"
|
|
240
|
+
parameter :name, String, "The person's name"
|
|
241
|
+
required %i[name]
|
|
242
|
+
|
|
243
|
+
def call(name:)
|
|
244
|
+
write("Welcome #{name}!\n")
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
##### REPL: Input
|
|
250
|
+
|
|
251
|
+
The input area supports several keyboard shortcuts:
|
|
252
|
+
|
|
253
|
+
| Key | Action |
|
|
254
|
+
|---|---|
|
|
255
|
+
| `Enter` | Submit the current prompt |
|
|
256
|
+
| `Ctrl+A` | Jump to the start of the line |
|
|
257
|
+
| `Ctrl+E` | Jump to the end of the line |
|
|
258
|
+
| `Ctrl+F` | Move the cursor forward |
|
|
259
|
+
| `Ctrl+K` | Erase from cursor to the end of the line |
|
|
260
|
+
| `Ctrl+Y` | Paste previously killed text |
|
|
261
|
+
| `Ctrl+D` | Delete the character at the cursor |
|
|
262
|
+
| `Left / Right` | Move the cursor |
|
|
263
|
+
| `Up / Down` | Scroll the transcript |
|
|
264
|
+
| `/exit` | Leave the REPL |
|
|
265
|
+
|
|
179
266
|
#### LLM::MCP
|
|
180
267
|
|
|
181
268
|
The Model Context Protocol (MCP) has first-class support
|