llm.rb 13.1.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 +320 -0
- data/README.md +340 -31
- data/bin/llm.rb +36 -12
- 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 +47 -14
- 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/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 +32 -4
- 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 +1 -8
- 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/moonshot.rb +76 -0
- data/lib/llm/providers/ollama.rb +1 -8
- data/lib/llm/providers/openai/responses/stream_parser.rb +1 -0
- data/lib/llm/providers/openai/responses.rb +6 -8
- data/lib/llm/providers/openai/stream_parser.rb +1 -0
- data/lib/llm/providers/openai.rb +3 -10
- data/lib/llm/repl/bar.rb +4 -3
- data/lib/llm/repl/buffer.rb +42 -15
- data/lib/llm/repl/color.rb +78 -0
- 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 +6 -2
- data/lib/llm/repl/markdown.rb +31 -5
- data/lib/llm/repl/status.rb +38 -3
- data/lib/llm/repl/stream.rb +16 -4
- data/lib/llm/repl/walker.rb +3 -2
- data/lib/llm/repl/window.rb +25 -5
- data/lib/llm/repl.rb +29 -13
- data/lib/llm/stream.rb +8 -7
- data/lib/llm/tool.rb +29 -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 +1 -0
- 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 +7 -1
- metadata +36 -3
- 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
|
@@ -17,6 +17,326 @@
|
|
|
17
17
|
|
|
18
18
|
*No unreleased changes yet. Check back after the next release.*
|
|
19
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
|
+
|
|
20
340
|
## v13.1.0
|
|
21
341
|
|
|
22
342
|
Changes since `v13.0.0`.
|