llm.rb 13.0.0 → 14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +505 -14
- data/README.md +484 -50
- data/bin/llm.rb +148 -0
- data/data/anthropic.json +206 -263
- data/data/bedrock.json +2138 -1860
- data/data/deepinfra.json +1003 -624
- data/data/deepseek.json +38 -34
- data/data/google.json +1079 -371
- data/data/mistral.json +448 -368
- data/data/moonshot.json +384 -0
- data/data/openai.json +974 -1343
- data/data/xai.json +154 -126
- data/data/zai.json +191 -191
- data/lib/llm/agent.rb +123 -20
- data/lib/llm/context.rb +71 -88
- data/lib/llm/cost.rb +23 -17
- data/lib/llm/error.rb +0 -8
- data/lib/llm/function/array.rb +3 -3
- data/lib/llm/function/async/task.rb +2 -0
- data/lib/llm/function/fiber/task.rb +2 -0
- data/lib/llm/function/fork/task.rb +2 -0
- data/lib/llm/function/ractor/task.rb +2 -0
- data/lib/llm/function/sequential/group.rb +4 -1
- data/lib/llm/function/sequential/task.rb +1 -1
- data/lib/llm/function/task.rb +4 -0
- data/lib/llm/function/thread/task.rb +2 -0
- data/lib/llm/function.rb +33 -6
- data/lib/llm/guard/loop.rb +89 -0
- data/lib/llm/guard/null.rb +19 -0
- data/lib/llm/guard.rb +61 -0
- data/lib/llm/provider.rb +36 -0
- data/lib/llm/providers/anthropic/stream_parser.rb +1 -0
- data/lib/llm/providers/anthropic.rb +2 -9
- data/lib/llm/providers/bedrock/request_adapter.rb +1 -1
- data/lib/llm/providers/bedrock/stream_parser.rb +1 -0
- data/lib/llm/providers/bedrock.rb +1 -8
- data/lib/llm/providers/google/stream_parser.rb +1 -0
- data/lib/llm/providers/google.rb +1 -8
- data/lib/llm/providers/mistral.rb +1 -1
- data/lib/llm/providers/moonshot.rb +76 -0
- data/lib/llm/providers/ollama.rb +2 -9
- data/lib/llm/providers/openai/responses/stream_parser.rb +1 -0
- data/lib/llm/providers/openai/responses.rb +7 -9
- data/lib/llm/providers/openai/stream_parser.rb +1 -0
- data/lib/llm/providers/openai.rb +4 -11
- data/lib/llm/repl/bar.rb +4 -3
- data/lib/llm/repl/{transcript.rb → buffer.rb} +69 -29
- data/lib/llm/repl/color.rb +78 -0
- data/lib/llm/repl/command.rb +12 -5
- data/lib/llm/repl/commands/compact.rb +2 -2
- data/lib/llm/repl/commands/help.rb +3 -5
- data/lib/llm/repl/input/char.rb +46 -0
- data/lib/llm/repl/input/row.rb +39 -0
- data/lib/llm/repl/input.rb +251 -66
- data/lib/llm/repl/markdown/table.rb +11 -3
- data/lib/llm/repl/markdown.rb +34 -8
- data/lib/llm/repl/node.rb +37 -0
- data/lib/llm/repl/status.rb +42 -7
- data/lib/llm/repl/stream.rb +18 -6
- data/lib/llm/repl/walker.rb +3 -2
- data/lib/llm/repl/window.rb +54 -35
- data/lib/llm/repl.rb +74 -32
- data/lib/llm/skill.rb +20 -4
- data/lib/llm/stream.rb +8 -7
- data/lib/llm/tool.rb +29 -0
- data/lib/llm/tools/{swap_text.rb → edit-file.rb} +3 -3
- data/lib/llm/tools/git.rb +3 -0
- data/lib/llm/tools/mkdir.rb +3 -0
- data/lib/llm/tools/rg.rb +3 -0
- data/lib/llm/tools/ruby.rb +46 -0
- data/lib/llm/tools/shell.rb +3 -0
- data/lib/llm/tracer/pretty_logger.rb +127 -0
- data/lib/llm/tracer.rb +1 -0
- data/lib/llm/transformer/null.rb +21 -0
- data/lib/llm/transformer.rb +55 -0
- data/lib/llm/version.rb +1 -1
- data/lib/llm.rb +12 -2
- data/llm.gemspec +9 -2
- data/resources/deepdive/advanced/cancellation.md +74 -0
- data/resources/deepdive/advanced/compaction.md +83 -0
- data/resources/deepdive/advanced/context.md +267 -0
- data/resources/deepdive/advanced/guard.md +371 -0
- data/resources/deepdive/advanced/tracer.md +180 -0
- data/resources/deepdive/advanced/transformer.md +67 -0
- data/resources/deepdive/advanced/transports.md +45 -0
- data/resources/deepdive/everything_else/audio.md +122 -0
- data/resources/deepdive/everything_else/cost.md +99 -0
- data/resources/deepdive/everything_else/images.md +89 -0
- data/resources/deepdive/everything_else/object.md +108 -0
- data/resources/deepdive/everything_else/ocr.md +48 -0
- data/resources/deepdive/fundamentals/agents.md +202 -0
- data/resources/deepdive/fundamentals/builtin_tools.md +191 -0
- data/resources/deepdive/fundamentals/concurrency.md +104 -0
- data/resources/deepdive/fundamentals/database.md +449 -0
- data/resources/deepdive/fundamentals/embeddings.md +157 -0
- data/resources/deepdive/fundamentals/repl.md +87 -0
- data/resources/deepdive/fundamentals/schema.md +61 -0
- data/resources/deepdive/fundamentals/skills.md +106 -0
- data/resources/deepdive/fundamentals/stream.md +110 -0
- data/resources/deepdive/fundamentals/tools.md +265 -0
- data/resources/deepdive/protocols/a2a.md +106 -0
- data/resources/deepdive/protocols/mcp.md +111 -0
- data/resources/deepdive.md +58 -1792
- metadata +51 -7
- data/lib/llm/loop_guard.rb +0 -107
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 80d9ecf944df7561e9a0ac70bb37225dac11f18b13fba94d689b672da3b27e6f
|
|
4
|
+
data.tar.gz: d3986e29989bcd415c40cd26fd4361ac8b3f92461cf81f2f5abf5a9d291cd068
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 702cd38c23fa817b068dd9b7c8942f3641915c874e1ed9bef6526127767092f138fd09c320cd54fafc265e2b33131d0cca8b7376f2c7b5e9e3203e66b1f4a513
|
|
7
|
+
data.tar.gz: f5eebb31abe9349e451bb1410b01a35353dd466fc66b6df230c5cb6be469856be234dea3351f885eb9c616375c0b84bf18e72dc268b88454997919f475a89774
|
data/CHANGELOG.md
CHANGED
|
@@ -15,7 +15,498 @@
|
|
|
15
15
|
|
|
16
16
|
## What's next
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
*No unreleased changes yet. Check back after the next release.*
|
|
19
|
+
|
|
20
|
+
## v14.0.0
|
|
21
|
+
|
|
22
|
+
Changes since `v13.1.0`.
|
|
23
|
+
|
|
24
|
+
This release replaces the `transformer=` setter with the new
|
|
25
|
+
`LLM::Transformer` class hierarchy, refactors guards into the
|
|
26
|
+
`LLM::Guard` superclass with per-tool-call interception, and replaces
|
|
27
|
+
the agent `tool_attempts` parameter with the `tool_budget` class DSL.
|
|
28
|
+
It also adds the Moonshot (Kimi) provider, the `LLM::Tool.set`
|
|
29
|
+
bulk-assignment DSL, a `LLM::Function#return` shorthand, and a wide
|
|
30
|
+
range of REPL improvements.
|
|
31
|
+
|
|
32
|
+
### Breaking
|
|
33
|
+
|
|
34
|
+
#### Migration
|
|
35
|
+
|
|
36
|
+
| Old | New |
|
|
37
|
+
|-----|-----|
|
|
38
|
+
| `ctx.transformer = MyTransformer` | `LLM::Context.new(transformer: MyTransformer)` |
|
|
39
|
+
| `transformer.call(ctx, prompt, params)` | `transformer.call(message:, **opts)` |
|
|
40
|
+
| `~/.llm.rb/session.json` (shared across providers) | `~/.llm.rb/<provider>/<uuid>.json` (scoped per provider and directory) |
|
|
41
|
+
| `agent.talk(tool_attempts: 25)` | `set :tool_budget => 50` (disabled by default) |
|
|
42
|
+
| `LLM::LoopGuard` | `LLM::Guard::Loop` |
|
|
43
|
+
| `guard: true` / `ctx.guard = MyGuard` | `guard: MyGuard, guard_options: {}` |
|
|
44
|
+
| `guard.call(ctx)` (warning string) | `guard.call(function:)` (`LLM::Function::Return` or nil) |
|
|
45
|
+
| `LLM::GuardError` | `"guard_error"` |
|
|
46
|
+
|
|
47
|
+
* **replace the transformer setter with `LLM::Transformer`** <br>
|
|
48
|
+
The previous `transformer=` setter and 3-argument
|
|
49
|
+
`call(ctx, prompt, params)` interface on `LLM::Context` have been
|
|
50
|
+
replaced by the new
|
|
51
|
+
[`LLM::Transformer`](https://r.uby.dev/api-docs/llm.rb/LLM/Transformer.html)
|
|
52
|
+
class interface. Configure a transformer class through `transformer:`
|
|
53
|
+
and options through `transformer_options:` instead.
|
|
54
|
+
|
|
55
|
+
* **cli: scope session persistence per provider and directory** <br>
|
|
56
|
+
`bin/llm.rb` no longer shares a single session file between providers.
|
|
57
|
+
Each provider now has a `~/.llm.rb/<provider>.json` file that maps the
|
|
58
|
+
current working directory to a UUID-scoped session file under
|
|
59
|
+
`~/.llm.rb/<provider>/<uuid>.json`, so sessions are scoped to both the
|
|
60
|
+
provider and the directory they were started in.
|
|
61
|
+
|
|
62
|
+
* **cli: harden the executable against bad inputs** <br>
|
|
63
|
+
`bin/llm.rb` now prints an error message followed by the help menu and
|
|
64
|
+
exits with status 1 when the `-p` switch is given without an argument or
|
|
65
|
+
when an unknown option is passed. Previously unknown options produced a
|
|
66
|
+
warning but the run continued. The session-file lookup also no longer
|
|
67
|
+
rewrites `~/.llm.rb/<provider>.json` when it already exists.
|
|
68
|
+
|
|
69
|
+
* **agent: replace `tool_attempts` with the `tool_budget` class DSL** <br>
|
|
70
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#tool_budget-class_method)
|
|
71
|
+
replaces the `tool_attempts` parameter with a `tool_budget` class DSL
|
|
72
|
+
(`tool_budget { 50 }`) that caps the number of tool calls allowed in a
|
|
73
|
+
single turn. Once the budget is spent, the agent sends an in-band
|
|
74
|
+
advisory message back through the model telling it to solve the problem
|
|
75
|
+
with fewer tool calls.
|
|
76
|
+
<br><br>
|
|
77
|
+
The feature is now disabled by default; the old `tool_attempts`
|
|
78
|
+
parameter defaulted to 25, which long-horizon agents could easily
|
|
79
|
+
exhaust in a single turn.
|
|
80
|
+
|
|
81
|
+
* **guard: replace `LLM::LoopGuard` with the `LLM::Guard` class hierarchy** <br>
|
|
82
|
+
[`LLM::Guard`](https://r.uby.dev/api-docs/llm.rb/LLM/Guard.html)
|
|
83
|
+
is a new superclass for context-level supervisors, with
|
|
84
|
+
[`LLM::Guard::Loop`](https://r.uby.dev/api-docs/llm.rb/LLM/Guard/Loop.html)
|
|
85
|
+
(replacing `LLM::LoopGuard`) and
|
|
86
|
+
[`LLM::Guard::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Guard/Null.html)
|
|
87
|
+
as the built-in implementations.
|
|
88
|
+
[`LLM::Context`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html)
|
|
89
|
+
now accepts `guard:` (a guard class defaulting to `LLM::Guard::Null`)
|
|
90
|
+
and `guard_options:` (a hash forwarded to the guard's `call` method),
|
|
91
|
+
matching the transformer and compactor interfaces. The old boolean and
|
|
92
|
+
hash forms of `guard` and the `guard=` setter are removed. `LLM::Agent`
|
|
93
|
+
enables `LLM::Guard::Loop` by default.
|
|
94
|
+
|
|
95
|
+
* **guard: block individual tool calls instead of the whole batch** <br>
|
|
96
|
+
[`LLM::Guard#call`](https://r.uby.dev/api-docs/llm.rb/LLM/Guard.html#call-instance_method)
|
|
97
|
+
now receives the pending `function:` and returns an
|
|
98
|
+
[`LLM::Function::Return`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Return.html)
|
|
99
|
+
(or nil) instead of a warning string for the entire batch, so a guard
|
|
100
|
+
can block a single tool call while the rest of the batch still
|
|
101
|
+
executes. Custom guards that implemented the old `call(ctx)`
|
|
102
|
+
warning-string interface must be updated to return a
|
|
103
|
+
`LLM::Function::Return` instead.
|
|
104
|
+
|
|
105
|
+
* **errors: drop `LLM::GuardError`** <br>
|
|
106
|
+
Remove `LLM::GuardError`. The constant was never raised as an
|
|
107
|
+
exception; it only named the in-band error type for guarded tool
|
|
108
|
+
returns. Guarded tool returns now use the string `"guard_error"` as
|
|
109
|
+
their error type.
|
|
110
|
+
|
|
111
|
+
### Core
|
|
112
|
+
|
|
113
|
+
* **add `LLM::Provider#build_messages` for assembling outgoing messages** <br>
|
|
114
|
+
[`LLM::Provider#build_messages`](https://r.uby.dev/api-docs/llm.rb/LLM/Provider.html#build_messages-instance_method)
|
|
115
|
+
normalizes a prompt into `LLM::Message` objects and prepends the existing
|
|
116
|
+
history, replacing the per-provider `build_complete_messages`
|
|
117
|
+
implementation. The method is idempotent: prompts that are already
|
|
118
|
+
[`LLM::Message`](https://r.uby.dev/api-docs/llm.rb/LLM/Message.html)
|
|
119
|
+
instances or arrays of messages are returned as-is.
|
|
120
|
+
|
|
121
|
+
* **copy the `params` hash in `LLM::Context` and `LLM::Agent`** <br>
|
|
122
|
+
[`LLM::Context`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html) and
|
|
123
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now copy
|
|
124
|
+
the `params` hash in their constructors before mutating it, leaving the
|
|
125
|
+
caller's hash untouched. Previously the constructors deleted keys from
|
|
126
|
+
the caller's hash in place.
|
|
127
|
+
|
|
128
|
+
* **gemspec: ship the deepdive sub-files in the gem** <br>
|
|
129
|
+
The gemspec now includes `resources/deepdive/*/*.md` in the gem
|
|
130
|
+
package, so the full deepdive guide (fundamentals, advanced,
|
|
131
|
+
protocols, and everything-else chapters) is available after
|
|
132
|
+
installation.
|
|
133
|
+
|
|
134
|
+
* **add short aliases to `LLM::Cost`** <br>
|
|
135
|
+
[`LLM::Cost`](https://r.uby.dev/api-docs/llm.rb/LLM/Cost.html) now
|
|
136
|
+
offers short aliases for its cost accessors: `input`, `output`,
|
|
137
|
+
`input_audio`, `output_audio`, `input_image`, `cache_read`,
|
|
138
|
+
`cache_write`, and `reasoning`. Each alias matches the key used by
|
|
139
|
+
`#to_h`, so `cost.input` reads the same value as `cost.input_costs`.
|
|
140
|
+
|
|
141
|
+
### Provider
|
|
142
|
+
|
|
143
|
+
* **add `LLM::Moonshot` for the Moonshot AI provider** <br>
|
|
144
|
+
[`LLM::Moonshot`](https://r.uby.dev/api-docs/llm.rb/LLM/Moonshot.html)
|
|
145
|
+
is a new provider that talks to
|
|
146
|
+
[Moonshot AI](https://platform.moonshot.ai) through its
|
|
147
|
+
OpenAI-compatible Kimi API. Create an instance with
|
|
148
|
+
[`LLM.moonshot`](https://r.uby.dev/api-docs/llm.rb/LLM.html#moonshot-class_method),
|
|
149
|
+
which accepts the same `key:`, `host:`, and `base_path:` options as the
|
|
150
|
+
OpenAI provider. The provider defaults to the `kimi-k3` model and
|
|
151
|
+
supports chat completions, streaming, tool calls, and structured output
|
|
152
|
+
through the shared OpenAI-compatible path; image, audio, moderation,
|
|
153
|
+
responses, and vector store endpoints raise `NotImplementedError`.
|
|
154
|
+
Model metadata ships in `data/moonshot.json` for the registry.
|
|
155
|
+
|
|
156
|
+
### Transformer
|
|
157
|
+
|
|
158
|
+
* **add `LLM::Transformer` for rewriting messages before they reach the provider** <br>
|
|
159
|
+
[`LLM::Transformer`](https://r.uby.dev/api-docs/llm.rb/LLM/Transformer.html)
|
|
160
|
+
is a new superclass for message transformers. A transformer is bound to a
|
|
161
|
+
context and rewrites a single message before it is sent to the provider,
|
|
162
|
+
which makes it possible to redact personal information or rewrite any
|
|
163
|
+
message before it goes out over the wire. Each subclass implements
|
|
164
|
+
`call(message:, **opts)` and returns the message to send, either by
|
|
165
|
+
mutating it in place or returning a new one.
|
|
166
|
+
[`LLM::Transformer::Null`](https://r.uby.dev/api-docs/llm.rb/LLM/Transformer/Null.html)
|
|
167
|
+
is a no-op transformer used as the default.
|
|
168
|
+
|
|
169
|
+
* **hook the transformer API into `LLM::Context`** <br>
|
|
170
|
+
[`LLM::Context`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html) now
|
|
171
|
+
accepts `transformer:` (a transformer class defaulting to
|
|
172
|
+
`LLM::Transformer::Null`) and `transformer_options:` (a hash forwarded to
|
|
173
|
+
the transformer's `call` method). The transformer runs on the most recent
|
|
174
|
+
message in both chat and responses turns.
|
|
175
|
+
[`LLM::Stream#on_transform`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_transform-instance_method)
|
|
176
|
+
and
|
|
177
|
+
[`LLM::Stream#on_transform_finish`](https://r.uby.dev/api-docs/llm.rb/LLM/Stream.html#on_transform_finish-instance_method)
|
|
178
|
+
now receive the transformer instance as their single argument.
|
|
179
|
+
|
|
180
|
+
### Tool
|
|
181
|
+
|
|
182
|
+
* **add `LLM::Tool.set` for bulk-assigning tool properties** <br>
|
|
183
|
+
[`LLM::Tool.set`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html#set-class_method)
|
|
184
|
+
accepts a hash of `name`, `description`, `parameters`, `required`, and
|
|
185
|
+
`defaults` to configure a tool subclass in a single call. Parameters are
|
|
186
|
+
defined as tuples of `[name, type, description, options]`, matching the
|
|
187
|
+
same interface as the existing `parameter` DSL. Unknown keys raise
|
|
188
|
+
`KeyError`.
|
|
189
|
+
|
|
190
|
+
### Function
|
|
191
|
+
|
|
192
|
+
* **add `LLM::Function#return` for building tool returns** <br>
|
|
193
|
+
[`LLM::Function#return`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#return-instance_method)
|
|
194
|
+
returns an
|
|
195
|
+
[`LLM::Function::Return`](https://r.uby.dev/api-docs/llm.rb/LLM/Function/Return.html)
|
|
196
|
+
built from the function's own id and name, using the given hash as its
|
|
197
|
+
value. It is a shorthand mainly useful inside a
|
|
198
|
+
[`LLM::Guard`](https://r.uby.dev/api-docs/llm.rb/LLM/Guard.html)
|
|
199
|
+
subclass and is defined via `define_method` because `return` is a Ruby
|
|
200
|
+
keyword.
|
|
201
|
+
|
|
202
|
+
### Guard
|
|
203
|
+
|
|
204
|
+
* **run the guard for streamed tool calls** <br>
|
|
205
|
+
Fix a gap where the guard was not consulted when a tool call was queued
|
|
206
|
+
while a response was still streaming. The guard is now stamped onto the
|
|
207
|
+
functions a context binds, so it runs wherever a task is spawned,
|
|
208
|
+
including tool calls queued from a stream. A blocked call yields its
|
|
209
|
+
`guard_error` return without executing.
|
|
210
|
+
|
|
211
|
+
### Agent
|
|
212
|
+
|
|
213
|
+
* **add `LLM::Agent#compacted?`** <br>
|
|
214
|
+
[`LLM::Agent#compacted?`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#compacted%3F-instance_method)
|
|
215
|
+
delegates to the wrapped
|
|
216
|
+
[`LLM::Context#compacted?`](https://r.uby.dev/api-docs/llm.rb/LLM/Context.html#compacted%3F-instance_method)
|
|
217
|
+
and reports whether the conversation has been compacted, so callers
|
|
218
|
+
can detect when history was trimmed.
|
|
219
|
+
|
|
220
|
+
### Change
|
|
221
|
+
|
|
222
|
+
* **openai: default to `gpt-5.6-luna`** <br>
|
|
223
|
+
The default OpenAI chat model has changed from `gpt-5.4-mini` to
|
|
224
|
+
`gpt-5.6-luna`. The new model is OpenAI's fastest and most affordable
|
|
225
|
+
option, matching the kind of default llm.rb aims for.
|
|
226
|
+
|
|
227
|
+
### Repl
|
|
228
|
+
|
|
229
|
+
* **show an unknown context state after `/compact`** <br>
|
|
230
|
+
After running `/compact`, the REPL status line now renders `Context
|
|
231
|
+
compacted` and the context-usage bar shows `???` instead of a percentage,
|
|
232
|
+
because the used context is unknown until the next response.
|
|
233
|
+
|
|
234
|
+
* **land on a blank line after Ctrl+N at the end of history** <br>
|
|
235
|
+
When recalling history with Ctrl+P and Ctrl+N, Ctrl+N at the last item
|
|
236
|
+
now advances to a blank line so you can start typing new input, instead
|
|
237
|
+
of staying stuck on the last item in history (the previous behavior).
|
|
238
|
+
Recalling with Ctrl+P or Ctrl+N also no longer overwrites the input when
|
|
239
|
+
there is no history to show.
|
|
240
|
+
|
|
241
|
+
* **restore history wrap for Ctrl+P and Ctrl+N** <br>
|
|
242
|
+
Fix a regression where Ctrl+P and Ctrl+N recalled history text without
|
|
243
|
+
reflowing it into rows, so recalled lines wider than the terminal were
|
|
244
|
+
clipped. Recalled text now flows through the same word-wrap path as
|
|
245
|
+
typed input and wraps at the terminal width.
|
|
246
|
+
|
|
247
|
+
* **restore Ctrl+D deletion across rows** <br>
|
|
248
|
+
Fix a bug where Ctrl+D at the end of an input row was a no-op, so
|
|
249
|
+
multiline input could not be joined by deleting a row break. Deleting
|
|
250
|
+
at the end of a row now consumes the break and pulls the next row up,
|
|
251
|
+
restoring the split space so merged words do not run together.
|
|
252
|
+
|
|
253
|
+
* **center the buffer with 20% gutters** <br>
|
|
254
|
+
The curses-based REPL now centers
|
|
255
|
+
[`LLM::Repl::Buffer`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Buffer.html)
|
|
256
|
+
in a content area that is 60% of the terminal width, with an unused 20%
|
|
257
|
+
gutter on each side. The drawing area is based on the available rows and
|
|
258
|
+
columns instead of a fixed 80-column width, and `Buffer#wrap` now
|
|
259
|
+
hard-breaks words that overflow the width onto the next row, fixing a
|
|
260
|
+
bug where a word could be cut off between rows.
|
|
261
|
+
|
|
262
|
+
* **apply markdown to previous messages** <br>
|
|
263
|
+
The curses-based REPL now renders every message in the buffer with
|
|
264
|
+
markdown styling, including messages that were already present when
|
|
265
|
+
the session started or restored from disk. Previously only newly
|
|
266
|
+
streamed responses were styled; older messages fell back to plain
|
|
267
|
+
text.
|
|
268
|
+
|
|
269
|
+
* **add `LLM::Repl#sender` for the user label** <br>
|
|
270
|
+
[`LLM::Repl#sender`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html#sender-instance_method)
|
|
271
|
+
returns the label used for user messages in the curses-based REPL. It
|
|
272
|
+
defaults to `"You"` (previously `"user"`), and the buffer layout now
|
|
273
|
+
places each label on its own line followed by the message content and a
|
|
274
|
+
blank line.
|
|
275
|
+
|
|
276
|
+
* **add `LLM::Repl::Color` for coloring the curses UI** <br>
|
|
277
|
+
Add
|
|
278
|
+
[`LLM::Repl::Color`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Color.html)
|
|
279
|
+
as a new module that returns Curses color bitmasks. `Color.enable`
|
|
280
|
+
initializes 8 color pairs, and methods like `Color.blue` return the
|
|
281
|
+
corresponding `Curses.color_pair(X)` bitmask, which can be bitwise
|
|
282
|
+
OR'ed with other attributes such as `Curses::A_BOLD`. User labels in
|
|
283
|
+
the REPL are now rendered in blue instead of plain bold text.
|
|
284
|
+
|
|
285
|
+
* **split on words rather than characters** <br>
|
|
286
|
+
`LLM::Repl::Buffer#wrap` now breaks text on word boundaries instead of
|
|
287
|
+
wrapping one character at a time. A word that does not fit on the
|
|
288
|
+
current row moves to the next, and only a single word longer than the
|
|
289
|
+
whole width is hard-broken, so text is never clipped by the window.
|
|
290
|
+
|
|
291
|
+
* **render kramdown typographic symbols and smart quotes** <br>
|
|
292
|
+
Fix a bug where certain character sequences such as `...` were not
|
|
293
|
+
rendered at all in the curses-based REPL. Kramdown parses them into
|
|
294
|
+
`:typographic_sym` and `:smart_quote` nodes, which previously fell
|
|
295
|
+
through to the children clause and were dropped. The markdown renderer
|
|
296
|
+
now maps them to their unicode equivalents: ellipsis, en and em
|
|
297
|
+
dashes, guillemets, and single and double quotation marks.
|
|
298
|
+
|
|
299
|
+
* **apply colors to the markdown renderer** <br>
|
|
300
|
+
The curses-based REPL now renders markdown with the `LLM::Repl::Color`
|
|
301
|
+
palette: headers and strong text in white, code spans and code blocks
|
|
302
|
+
in green, and links in underlined green, on the black background.
|
|
303
|
+
Previously markdown styling used bold, underline, and reverse video
|
|
304
|
+
attributes only.
|
|
305
|
+
|
|
306
|
+
* **wrap the input line at word boundaries** <br>
|
|
307
|
+
The curses-based REPL input line now wraps words whole onto the next
|
|
308
|
+
row at the terminal width instead of cutting them in half. A word that
|
|
309
|
+
does not fit on the current row moves to the next row, and only a
|
|
310
|
+
single word longer than the whole width is hard-broken, so typed text
|
|
311
|
+
is never clipped by the window.
|
|
312
|
+
|
|
313
|
+
* **distinguish the connecting and thinking status bar phases** <br>
|
|
314
|
+
The curses-based REPL status bar now shows `Connecting • Esc to
|
|
315
|
+
cancel` while the model is establishing a connection, then switches
|
|
316
|
+
to `Thinking • Esc to cancel` once a tool call or text fragment
|
|
317
|
+
arrives on the stream. Active tool calls appear in the status bar
|
|
318
|
+
with a lambda indicator.
|
|
319
|
+
|
|
320
|
+
* **add emoji to the status bar phases** <br>
|
|
321
|
+
The curses-based REPL status bar now uses emoji to identify each
|
|
322
|
+
phase at a glance: a globe (`🌐`) while the model is connecting, and
|
|
323
|
+
a brain (`🧠`) while it is thinking. The text after the emoji still
|
|
324
|
+
reads `Connecting • Esc to cancel` and `Thinking • Esc to cancel`
|
|
325
|
+
respectively.
|
|
326
|
+
|
|
327
|
+
* **render the status bar with color and attributes** <br>
|
|
328
|
+
The curses-based REPL status bar now supports colored and attributed
|
|
329
|
+
status text, so the lambda indicator for active tool calls is drawn
|
|
330
|
+
in bold red.
|
|
331
|
+
|
|
332
|
+
### Registry
|
|
333
|
+
|
|
334
|
+
* **refresh model metadata across providers** <br>
|
|
335
|
+
Update `data/*.json` files with current provider model listings and
|
|
336
|
+
pricing. Remove the deprecated Claude Opus 4.1 entries from the
|
|
337
|
+
Anthropic registry, add `Qwen/Qwen3.8-Max` to DeepInfra, and add a
|
|
338
|
+
`low` reasoning-effort option to DeepSeek.
|
|
339
|
+
|
|
340
|
+
## v13.1.0
|
|
341
|
+
|
|
342
|
+
Changes since `v13.0.0`.
|
|
343
|
+
|
|
344
|
+
This release adds `LLM::Agent` class DSL attributes (`path`, `description`),
|
|
345
|
+
extends skills with file-path loading and the `tools: all` directive, adds new
|
|
346
|
+
built-in tools (`LLM::Tool::Ruby`, `LLM::Tool::EditFile`), introduces the
|
|
347
|
+
`LLM::Tracer::PrettyLogger` for human-readable tracing, renames `Transcript`
|
|
348
|
+
to `Buffer` across the REPL, ships a `bin/llm.rb` CLI entry point, and fixes
|
|
349
|
+
several agent and tool bugs around persistence, interruption, and naming.
|
|
350
|
+
|
|
351
|
+
### Core
|
|
352
|
+
|
|
353
|
+
* **add post install message with deepdive link** <br>
|
|
354
|
+
The gemspec now includes a `post_install_message` that points users to
|
|
355
|
+
the deepdive guide at `https://r.uby.dev/llm/deepdive` after installation,
|
|
356
|
+
making it easier for new users to discover the project documentation.
|
|
357
|
+
|
|
358
|
+
### Agent
|
|
359
|
+
|
|
360
|
+
* **add `description` class DSL and instance method** <br>
|
|
361
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
|
|
362
|
+
has a `description` class DSL (`description "release engineer"`) and a
|
|
363
|
+
corresponding `#description` instance method. The description is an
|
|
364
|
+
optional self-documenting string that serves as a brief summary of the
|
|
365
|
+
agent's purpose. It can be set via the class DSL,
|
|
366
|
+
`LLM::Agent.set(description: ...)`, or `LLM::Agent.new(description: ...)`.
|
|
367
|
+
|
|
368
|
+
* **add `path` class DSL and instance method** <br>
|
|
369
|
+
[`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html) now
|
|
370
|
+
has a `path` class DSL (`path "contexts/admin.json"`) and a
|
|
371
|
+
corresponding `#path` instance method. When a path is set, the agent
|
|
372
|
+
automatically restores its conversation history from that file on
|
|
373
|
+
initialization and saves it back after each `talk` or `ask` turn,
|
|
374
|
+
making session persistence across process restarts transparent.
|
|
375
|
+
|
|
376
|
+
### Skills
|
|
377
|
+
|
|
378
|
+
* **accept a path to a markdown file** <br>
|
|
379
|
+
[`LLM::Skill.load`](https://r.uby.dev/api-docs/llm.rb/LLM/Skill.html#load-class_method)
|
|
380
|
+
now accepts a path to a markdown file in addition to a directory path.
|
|
381
|
+
When given a file path, the file is read directly instead of looking for
|
|
382
|
+
a `SKILL.md` inside a directory. This makes it possible to load a single
|
|
383
|
+
markdown file as a skill without placing it in a dedicated directory.
|
|
384
|
+
|
|
385
|
+
* **extend with `all` keyword for loading the full tool registry** <br>
|
|
386
|
+
`LLM::Skill` now supports `tools: all` (or `tools: "*"`) in the frontmatter
|
|
387
|
+
to load all tools from the global
|
|
388
|
+
[`LLM::Tool.registry`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool.html#registry-class_method).
|
|
389
|
+
Previously, the `tools:` frontmatter only accepted `inherit`, an array of tool
|
|
390
|
+
names, or nothing. The new `all` keyword makes it possible to give a skill
|
|
391
|
+
access to every registered tool without listing them individually.
|
|
392
|
+
|
|
393
|
+
### Tools
|
|
394
|
+
|
|
395
|
+
* **add `LLM::Tool::Ruby` for executing Ruby code in a subprocess** <br>
|
|
396
|
+
[`LLM::Tool::Ruby`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Ruby.html)
|
|
397
|
+
is a new built-in tool that runs a string of Ruby code in a separate
|
|
398
|
+
Ruby process with a configurable timeout (default 15s). The code runs
|
|
399
|
+
in an isolated address space unaware of its parent, making it useful
|
|
400
|
+
for safe(ish) dynamic code execution. It must be required explicitly
|
|
401
|
+
with `require "llm/tools/ruby"` and requires the `test-cmd.rb` gem.
|
|
402
|
+
|
|
403
|
+
* **rename `LLM::Tool::SwapText` to `LLM::Tool::EditFile`** <br>
|
|
404
|
+
The `SwapText` tool has been renamed to
|
|
405
|
+
[`LLM::Tool::EditFile`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/EditFile.html)
|
|
406
|
+
to better match the naming of sibling tools (`ReadFile`, `WriteFile`).
|
|
407
|
+
The old `require "llm/tools/swap_text"` path no longer exists; use
|
|
408
|
+
`require "llm/tools/edit-file"` instead.
|
|
409
|
+
|
|
410
|
+
### Tracer
|
|
411
|
+
|
|
412
|
+
* **add `LLM::Tracer::PrettyLogger` for human-readable tracing** <br>
|
|
413
|
+
[`LLM::Tracer::PrettyLogger`](https://r.uby.dev/api-docs/llm.rb/LLM/Tracer/PrettyLogger.html)
|
|
414
|
+
is a new tracer that writes human-readable request and tool-call logs to a
|
|
415
|
+
console or file. Unlike the structured JSON output of
|
|
416
|
+
`LLM::Tracer::Logger`, the pretty logger emits single-line entries with
|
|
417
|
+
inline context, making it easier to follow agent activity at a glance.
|
|
418
|
+
It writes to `$stderr` by default and accepts an `io:` option for file
|
|
419
|
+
output.
|
|
420
|
+
|
|
421
|
+
### Repl
|
|
422
|
+
|
|
423
|
+
* **rename `LLM::Repl::Transcript` to `LLM::Repl::Buffer`** <br>
|
|
424
|
+
`LLM::Repl::Transcript` has been renamed to
|
|
425
|
+
[`LLM::Repl::Buffer`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Buffer.html)
|
|
426
|
+
to better reflect its role as a conversation state manager. The old
|
|
427
|
+
`start` and `finish` methods have been renamed to `open` and `close`
|
|
428
|
+
respectively. The public accessor on
|
|
429
|
+
[`LLM::Repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html) has been
|
|
430
|
+
renamed from `transcript` to `buffer`.
|
|
431
|
+
|
|
432
|
+
* **add `write_message` for formatted message writing** <br>
|
|
433
|
+
[`LLM::Repl::Buffer#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Buffer.html#write_message-instance_method)
|
|
434
|
+
and
|
|
435
|
+
[`LLM::Repl#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl.html#write_message-instance_method)
|
|
436
|
+
provide a convenience method that takes a username and content string,
|
|
437
|
+
formatting the output with a bold `user:` label and a trailing newline.
|
|
438
|
+
This is simpler than the equivalent sequence of `write` calls.
|
|
439
|
+
|
|
440
|
+
* **add `Command#write_message` and refactor `Command#write`** <br>
|
|
441
|
+
[`LLM::Command#write_message`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Command.html#write_message-instance_method)
|
|
442
|
+
provides a convenience method that takes a username and content string,
|
|
443
|
+
matching the same interface on `LLM::Repl` and `LLM::Buffer`. The
|
|
444
|
+
`Command#write` method is now implemented on top of `write_message`,
|
|
445
|
+
always prefixing output with `command(<name>): `. The `who:` keyword
|
|
446
|
+
argument previously accepted by `write` has been removed; use
|
|
447
|
+
`write_message` instead.
|
|
448
|
+
|
|
449
|
+
* **display pre-existing agent messages when the repl starts** <br>
|
|
450
|
+
When
|
|
451
|
+
[`LLM::Agent#repl`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
|
|
452
|
+
starts, any messages already in the agent's buffer are now rendered
|
|
453
|
+
in the REPL window. Previously the REPL started with an empty
|
|
454
|
+
transcript even when the agent carried prior conversation history,
|
|
455
|
+
making it harder to resume a session. Tool-call and tool-return
|
|
456
|
+
messages are skipped to avoid visual noise.
|
|
457
|
+
|
|
458
|
+
### CLI
|
|
459
|
+
|
|
460
|
+
* **add `bin/llm.rb` for launching the REPL from the command line** <br>
|
|
461
|
+
A new executable script (`bin/llm.rb`) provides a convenient way to start
|
|
462
|
+
an interactive REPL session directly from the terminal. It auto-detects
|
|
463
|
+
the provider from environment variables like `OPENAI_API_KEY`, supports
|
|
464
|
+
a `-p PROVIDER` flag for explicit provider selection, a `-t` flag for
|
|
465
|
+
temporary (non-persistent) sessions, and `-h` for help. Sessions are
|
|
466
|
+
automatically saved to `~/.llm.rb/` by default.
|
|
467
|
+
|
|
468
|
+
### Fix
|
|
469
|
+
|
|
470
|
+
* **agent: fix `path` restore on first run** <br>
|
|
471
|
+
Fix a bug where [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html)
|
|
472
|
+
called `@ctx.restore(path:)` even when the path's file did not exist.
|
|
473
|
+
The fix checks `File.readable?(@path)` before attempting to restore,
|
|
474
|
+
so the agent starts with a blank conversation on first use instead of
|
|
475
|
+
failing with a file-not-found error.
|
|
476
|
+
|
|
477
|
+
* **tools: re-raise `LLM::Interrupt` to abort the turn** <br>
|
|
478
|
+
[`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html),
|
|
479
|
+
[`LLM::Tool::Mkdir`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Mkdir.html),
|
|
480
|
+
[`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html),
|
|
481
|
+
[`LLM::Tool::Ruby`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Ruby.html),
|
|
482
|
+
and
|
|
483
|
+
[`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html)
|
|
484
|
+
now re-raise `LLM::Interrupt` after killing their running command. The
|
|
485
|
+
previous behavior rescued the interrupt and killed the child process but
|
|
486
|
+
let the turn continue, which meant a cancelled tool call did not abort
|
|
487
|
+
the conversation turn. Re-raising ensures the entire turn is interrupted.
|
|
488
|
+
|
|
489
|
+
* **tools: rescue `LLM::Interrupt` in shell-based tools** <br>
|
|
490
|
+
[`LLM::Tool::Shell`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Shell.html),
|
|
491
|
+
[`LLM::Tool::Git`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Git.html),
|
|
492
|
+
[`LLM::Tool::Mkdir`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Mkdir.html),
|
|
493
|
+
and
|
|
494
|
+
[`LLM::Tool::Rg`](https://r.uby.dev/api-docs/llm.rb/LLM/Tool/Rg.html)
|
|
495
|
+
now rescue `LLM::Interrupt` and kill their running command, preventing
|
|
496
|
+
orphaned child processes when a tool is interrupted during execution.
|
|
497
|
+
|
|
498
|
+
* **agent: fix default name derivation** <br>
|
|
499
|
+
Fix a bug where `LLM::Agent` used without a subclass derived its default
|
|
500
|
+
name as `"l-lm-agent"` instead of `"agent"`. The fix replaces the
|
|
501
|
+
regex-based parameterization with a pattern that correctly handles
|
|
502
|
+
single-word class names and multi-word namespaced names.
|
|
503
|
+
|
|
504
|
+
* **function: `#params` always returns an `LLM::Object`** <br>
|
|
505
|
+
[`LLM::Function#params`](https://r.uby.dev/api-docs/llm.rb/LLM/Function.html#params-instance_method)
|
|
506
|
+
now always returns an `LLM::Object` representing the function's parameter
|
|
507
|
+
schema. Previously it returned `nil` when a function defined no parameters,
|
|
508
|
+
forcing every caller to guard against `nil`. All provider adapters now use
|
|
509
|
+
`fn.params.to_h` instead of `fn.params || {type: "object", properties: {}}`.
|
|
19
510
|
|
|
20
511
|
## v13.0.0
|
|
21
512
|
|
|
@@ -406,7 +897,7 @@ reliable across all six concurrency backends. The `functions` and
|
|
|
406
897
|
|
|
407
898
|
Changes since `v12.5.1`.
|
|
408
899
|
|
|
409
|
-
This release adds bulk defaults for tools and agents
|
|
900
|
+
This release adds bulk defaults for tools and agents: `LLM::Tool.defaults`
|
|
410
901
|
for setting parameter defaults and `LLM::Agent.set` for mass-assigning
|
|
411
902
|
class-level defaults, both mirrored on ActiveRecord and Sequel agent models.
|
|
412
903
|
|
|
@@ -442,7 +933,7 @@ prior call.
|
|
|
442
933
|
On cancel, `LLM::Interrupt` is now raised on the thread that is
|
|
443
934
|
running a tool. The tool can rescue `LLM::Interrupt` and gracefully
|
|
444
935
|
terminate (e.g., clean up resources). The previous approach used
|
|
445
|
-
`Thread#interrupt` which was less reliable
|
|
936
|
+
`Thread#interrupt` which was less reliable. It did not interrupt a
|
|
446
937
|
sleeping thread.
|
|
447
938
|
|
|
448
939
|
* **function: suppress thread exception reporting in `:thread` concurrency** <br>
|
|
@@ -468,15 +959,15 @@ prior call.
|
|
|
468
959
|
`LLM::Interrupt` is now raised on the active fiber via `Fiber#raise`
|
|
469
960
|
when interrupting `:fiber`-concurrency tools.
|
|
470
961
|
<br><br>
|
|
471
|
-
`Task#interrupt!` now dispatches by task type
|
|
472
|
-
threads, `Fiber#raise` for fibers
|
|
962
|
+
`Task#interrupt!` now dispatches by task type: `Thread#raise` for
|
|
963
|
+
threads, `Fiber#raise` for fibers. Making interruption reliable
|
|
473
964
|
across all concurrency strategies.
|
|
474
965
|
|
|
475
966
|
* **function: raise `LLM::Interrupt` on fork-backed tool tasks** <br>
|
|
476
967
|
`LLM::Interrupt` is now raised on the main thread of a fork child
|
|
477
968
|
process via `Thread.main.raise(LLM::Interrupt)` when interrupting
|
|
478
969
|
`:fork`-concurrency tools, and the fork `Task#wait` re-raises the
|
|
479
|
-
interrupt on the parent side
|
|
970
|
+
interrupt on the parent side. Making interruption reliable across
|
|
480
971
|
all concurrency strategies including `:fork`.
|
|
481
972
|
|
|
482
973
|
* **function: raise `LLM::Interrupt` on `Async::Task`-backed tool tasks** <br>
|
|
@@ -494,7 +985,7 @@ prior call.
|
|
|
494
985
|
raises `LLM::Interrupt` on the ractor's main thread.
|
|
495
986
|
<br><br>
|
|
496
987
|
`Task#interrupt!` delegates to the mailbox to send the interrupt
|
|
497
|
-
message
|
|
988
|
+
message. Extending reliable interruption to the `:ractor`
|
|
498
989
|
concurrency strategy.
|
|
499
990
|
|
|
500
991
|
## v12.5.1
|
|
@@ -641,7 +1132,7 @@ OpenAI, Google, DeepInfra, DeepSeek, and xAI model entries.
|
|
|
641
1132
|
|
|
642
1133
|
* **repl: display command errors in the curses UI** <br>
|
|
643
1134
|
Commands invoked with too few arguments now display an error
|
|
644
|
-
message
|
|
1135
|
+
message: `command(<name>): too few arguments`. Displayed directly in
|
|
645
1136
|
the curses transcript area, giving immediate feedback instead
|
|
646
1137
|
of silently failing.
|
|
647
1138
|
|
|
@@ -765,7 +1256,7 @@ a command system foundation with the `/exit` command, and several new
|
|
|
765
1256
|
keybindings (Ctrl+F, Ctrl+K, Ctrl+Y). Tool calls are rendered with a
|
|
766
1257
|
compact function-call syntax in the status bar.
|
|
767
1258
|
|
|
768
|
-
Two new built-in tools
|
|
1259
|
+
Two new built-in tools: `LLM::Tool::Ls` and `LLM::Tool::Which` are
|
|
769
1260
|
available as opt-in additions for file listing and executable lookup.
|
|
770
1261
|
|
|
771
1262
|
Model metadata has been refreshed across providers, the REPL loop
|
|
@@ -832,7 +1323,7 @@ area.
|
|
|
832
1323
|
The curses-based REPL input now detects paste operations by tracking
|
|
833
1324
|
the rate at which characters arrive. A paste rate of ≤50ms is
|
|
834
1325
|
assumed to be a burst of characters that could only be explained by
|
|
835
|
-
a paste
|
|
1326
|
+
a paste. No human types that fast. Multiline pastes are supported
|
|
836
1327
|
through internal refactoring of the input handling logic.
|
|
837
1328
|
|
|
838
1329
|
* **repl: optimize paste mode rendering** <br>
|
|
@@ -855,7 +1346,7 @@ area.
|
|
|
855
1346
|
|
|
856
1347
|
* **repl: render tool calls in a function-call syntax** <br>
|
|
857
1348
|
The curses-based REPL status bar now renders tool calls with a
|
|
858
|
-
compact function-call syntax
|
|
1349
|
+
compact function-call syntax: `tool(key: value)` instead of
|
|
859
1350
|
`tool: name`. Strings are quoted and truncated, arrays show their
|
|
860
1351
|
first two elements, and hashes collapse to `{…}`, making it easier
|
|
861
1352
|
to see what arguments the model is passing. The `tool done` status
|
|
@@ -983,8 +1474,8 @@ tracer logger instances with less verbosity.
|
|
|
983
1474
|
streamed content via `#<<`. `LLM::Stream::Disabled` represents an explicitly
|
|
984
1475
|
disabled stream with no-op callbacks.
|
|
985
1476
|
|
|
986
|
-
This is part of an internal refactoring that lets all stream values
|
|
987
|
-
objects, `true`, `false`, `nil`, and `LLM::Stream` instances themselves
|
|
1477
|
+
This is part of an internal refactoring that lets all stream values: IO
|
|
1478
|
+
objects, `true`, `false`, `nil`, and `LLM::Stream` instances themselves
|
|
988
1479
|
be represented by the same `LLM::Stream` interface via the new
|
|
989
1480
|
`LLM::Stream.try` factory method.
|
|
990
1481
|
|
|
@@ -1053,7 +1544,7 @@ tracer logger instances with less verbosity.
|
|
|
1053
1544
|
|
|
1054
1545
|
* **repl: add extra padding between markdown nodes** <br>
|
|
1055
1546
|
The curses-based REPL markdown renderer now adds extra vertical spacing
|
|
1056
|
-
between certain markdown elements
|
|
1547
|
+
between certain markdown elements: paragraphs, headers, and codeblocks
|
|
1057
1548
|
for improved readability of model responses.
|
|
1058
1549
|
|
|
1059
1550
|
* **repl: add a visual divider between transcript and the rows below it** <br>
|