llm.rb 12.2.0 → 12.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20d8c7c9c3d9d270f371781b28e7537a5c6921cff138cfc895bdbf0042003d07
4
- data.tar.gz: 11b1abd397f1b13afadf4fe56e9670037a7c6ee586e945fd6a909505a4114122
3
+ metadata.gz: a1be1cd2af0cc8a817e510b04d1d74efd08cedf714b3faff4bdb7a58345fe14f
4
+ data.tar.gz: 3768fdf7f131d30c04d0ba83514bec31eb8d64de661980aa811a4e804a4df1e5
5
5
  SHA512:
6
- metadata.gz: d99ad697a3b3d5d13a0804ab3cea569ffbf5dc88d853aabe7461c4ae59020519e140aa0de1c2b26336b03998212410449da238ea8df5f6a190012f026093464c
7
- data.tar.gz: dd6314a5e1e7ba3899d1ab13ba4f076508481bc2e24d3502bfa5cc4ebfb66a2203772ffc9acb4987b741eea413997493b8f85a2a7a841cf768e80d9b412886a8
6
+ metadata.gz: 667c546559bb199c7381fbea97171b5e82e874098c40a763004db85667038aa430fa98592c4d42b1426e4536e288e70c018278b9e7af9fcf9b6d972eabd65cbe
7
+ data.tar.gz: 0163f85848ce7292905396458755d9ccb23298c6f7c6f06cf0532fb3bdb3517e1b188a022937eb540b823d82d7bc8d869549bc17c8d79767c5efe027bf5ae9be
data/CHANGELOG.md CHANGED
@@ -15,8 +15,195 @@
15
15
 
16
16
  ## What's next
17
17
 
18
+ Changes since `v12.3.1`.
19
+
20
+ ## v12.3.1
21
+
22
+ Changes since `v12.3.0`.
23
+
24
+ This release fixes a flickering issue in the curses-based REPL redraw.
25
+ The full-screen clear that caused visible flickering has been replaced
26
+ with a targeted cursor-hide approach, and stale rows from a larger
27
+ transcript are now explicitly cleared to prevent ghost text from
28
+ lingering when the transcript shrinks.
29
+
30
+ ### Fix
31
+
32
+ * **repl: fix redraw flicker** <br>
33
+ Replace `Curses.clear` with `Curses.curs_set(0)` in the REPL redraw
34
+ method to avoid a full screen clear that caused visible flickering
35
+ during redraws. The drawing order is also adjusted so the status line
36
+ is drawn before the divider, and stale rows left over from a larger
37
+ transcript are now explicitly cleared to prevent ghost text from
38
+ lingering when the transcript shrinks.
39
+
40
+ ## v12.3.0
41
+
18
42
  Changes since `v12.2.0`.
19
43
 
44
+ This release brings major improvements to the curses-based REPL
45
+ (`LLM::Agent#repl`). The status line now shows a context-usage bar and
46
+ running cost counter, the input field expands to three rows with
47
+ full cursor navigation, model responses are rendered as styled markdown,
48
+ and the UI stays responsive while the agent is working by running
49
+ requests in a separate thread. A new `LLM::Stream::IO` and
50
+ `LLM::Stream::Disabled` provide a uniform stream representation across
51
+ all stream types.
52
+
53
+ Mistral OCR support is added for extracting text from images and
54
+ documents via the `/v1/ocr` endpoint. The `skills:` and `tools:` options
55
+ on `LLM::Agent#repl` let you attach additional tools or skill directories
56
+ for the duration of a session. `LLM::Object#merge!` rounds out the
57
+ in-place merge API, and a new `LLM.logger` convenience method creates
58
+ tracer logger instances with less verbosity.
59
+
60
+ ### Add
61
+
62
+ * **Add `LLM.logger` convenience method** <br>
63
+ Add `LLM.logger(llm, ...)` as a shorter, less verbose way to create an
64
+ `LLM::Tracer::Logger` instance. Takes a provider and optional keyword
65
+ arguments forwarded to the logger constructor.
66
+
67
+ * **Add `skills:` option to `LLM::Agent#repl`** <br>
68
+ `LLM::Agent#repl` now accepts a `skills:` keyword argument that attaches
69
+ one or more skill directories (containing `SKILL.md`) for the duration of
70
+ the repl session. Skills are loaded and converted to tools, combining with
71
+ any tools already configured on the agent, and are discarded when the
72
+ session ends.
73
+
74
+ * **Add `LLM::Provider#ocr` base method** <br>
75
+ Add a base `ocr(...)` method to `LLM::Provider` that raises `NotImplementedError`
76
+ by default, establishing a common interface for providers that support OCR
77
+ (Optical Character Recognition) on images and documents.
78
+
79
+ * **Add Mistral OCR endpoint support** <br>
80
+ The Mistral provider now supports OCR via its `/v1/ocr` endpoint. Call
81
+ `mistral.ocr(image_url: ...)` for images or `mistral.ocr(document_url: ...)`
82
+ for documents (e.g., PDFs). Returns an `LLM::Response` with extracted pages,
83
+ markdown content, and structured block data.
84
+
85
+ * **Add `LLM::Object#merge!`** <br>
86
+ Add `LLM::Object#merge!` for in-place merging of hash data into an
87
+ `LLM::Object` instance, complementing the existing `#merge` method.
88
+
89
+ * **Add `LLM::Stream::IO` and `LLM::Stream::Disabled`** <br>
90
+ `LLM::Stream::IO` wraps IO-like objects as stream targets, forwarding
91
+ streamed content via `#<<`. `LLM::Stream::Disabled` represents an explicitly
92
+ disabled stream with no-op callbacks.
93
+
94
+ This is part of an internal refactoring that lets all stream values — IO
95
+ objects, `true`, `false`, `nil`, and `LLM::Stream` instances themselves —
96
+ be represented by the same `LLM::Stream` interface via the new
97
+ `LLM::Stream.try` factory method.
98
+
99
+ Before this change the codebase had to perform ad-hoc type checks
100
+ (e.g. `if LLM::Stream === stream`) scattered throughout. After this
101
+ change all stream handling goes through a single uniform path, and
102
+ providers check `#enabled?` to decide whether to request streaming
103
+ from the API.
104
+
105
+ ### Change
106
+
107
+ * **repl: rename `trace:` to `tracer:`** <br>
108
+ The `trace:` keyword argument in `LLM::Agent#repl` has been renamed to
109
+ `tracer:` for consistency with the rest of the codebase. The old `trace:`
110
+ name still works with a deprecation warning.
111
+
112
+ * **repl: add context-usage bar and cost counter to the status line** <br>
113
+ The curses-based REPL status line now shows a small progress bar that
114
+ indicates how much of the model's context window remains as a percentage,
115
+ alongside a running cost estimate rendered on the right side of the status
116
+ line. The input line has been updated to show the provider name as a prefix.
117
+ Estimates are best-effort and depend on registry pricing data (see `data/`).
118
+
119
+ * **repl: keep the UI responsive while a request is in progress** <br>
120
+ The curses-based REPL now spawns the agent request in a separate thread
121
+ and communicates streamed output through a queue, so the curses UI stays
122
+ responsive during model processing. Users can continue to scroll through
123
+ the transcript while the agent is working.
124
+
125
+ * **repl: style transcript rows as structured data with bold labels** <br>
126
+ The curses-based REPL transcript now stores rows as structured data with
127
+ style metadata instead of plain strings, enabling bold rendering of the
128
+ `user:` and `agent:` labels for improved readability during interactive
129
+ sessions.
130
+
131
+ * **repl: render a small subset of markdown** <br>
132
+ The curses-based REPL now renders model responses as styled markdown.
133
+ Headers and strong text render in bold, emphasis renders in underline,
134
+ and code spans and blocks are highlighted with inverted colors. Streaming
135
+ content is buffered and re-rendered on each tick so the transcript reads
136
+ cleanly as the agent responds. Requires the optional `kramdown` gem.
137
+
138
+ * **repl: add cursor LEFT/RIGHT movement to the input line** <br>
139
+ The curses-based REPL input now supports cursor movement with the left
140
+ and right arrow keys, enabling in-place text editing before submitting
141
+ a prompt. The cursor position is tracked visually and moves backwards
142
+ on left-arrow and forwards on right-arrow.
143
+
144
+ * **repl: add Ctrl+A and Ctrl+E keybindings to the input line** <br>
145
+ The curses-based REPL input now supports Ctrl+A to jump the cursor to
146
+ the start of the input line and Ctrl+E to jump it to the end, matching
147
+ common terminal editing conventions.
148
+
149
+ * **repl: add `tools:` option to `LLM::Agent#repl`** <br>
150
+ `LLM::Agent#repl` now accepts a `tools:` keyword argument that attaches
151
+ additional tool classes or instances for the duration of the repl session.
152
+ These tools are combined with any tools already configured on the agent,
153
+ and are discarded when the session ends.
154
+
155
+ * **repl: add repl support to ActiveRecord and Sequel agent models** <br>
156
+ `acts_as_agent` (ActiveRecord) and `plugin :agent` (Sequel) models now
157
+ expose a `repl` method that delegates to the underlying agent's
158
+ read-eval-print loop. This allows interactive debugging and inspection
159
+ of persisted agent state at runtime. Note that changes made during a
160
+ repl session do not persist back to the database.
161
+
162
+ * **repl: add extra padding between markdown nodes** <br>
163
+ The curses-based REPL markdown renderer now adds extra vertical spacing
164
+ between certain markdown elements — paragraphs, headers, and codeblocks —
165
+ for improved readability of model responses.
166
+
167
+ * **repl: add a visual divider between transcript and the rows below it** <br>
168
+ The curses-based REPL now draws a horizontal divider line (using a unicode
169
+ `─` character) to separate the transcript area from the status and input
170
+ rows below it. A single empty buffer row is also added between the
171
+ transcript and the divider, preventing transcript text from running too
172
+ close to the status and input rows.
173
+
174
+ * **repl: expand input field to 3 rows** <br>
175
+ The curses-based REPL input field now spans three rows instead of one,
176
+ wrapping text that exceeds the terminal width onto subsequent lines. A
177
+ scrollable viewport follows the cursor so the active line stays visible,
178
+ and common navigation commands (Ctrl+A, Ctrl+E, cursor keys) work across
179
+ all three rows of the expanded input area.
180
+
181
+ * **Refresh OpenAI model metadata** <br>
182
+ Add new OpenAI models to the registry, including `gpt-5.6`,
183
+ `gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`, and
184
+ `gpt-realtime-2.1`, with associated pricing, capabilities, and
185
+ limits.
186
+
187
+ ### Fix
188
+
189
+ * **Fix Ollama non-streaming response handling** <br>
190
+ Fix the Ollama provider to properly handle the non-streaming path. When
191
+ the provider returns a raw NDJSON response body (instead of streaming),
192
+ the response is now parsed and merged into a single `LLM::Object` before
193
+ being returned to the caller. Previously the non-streaming path was
194
+ effectively broken and would fail to produce a valid completion response.
195
+
196
+ * **repl: handle a negative context window allowance in the usage bar** <br>
197
+ Fix a crash in the curses-based REPL context-usage bar when the context
198
+ window allowance is exceeded (used > total). The negative width value that
199
+ resulted from this edge case could cause curses errors; it now gracefully
200
+ defaults to `0%` and zero bar width.
201
+
202
+ * **Fix YARD documentation across provider and tool files** <br>
203
+ Fix unnamed, misnamed, and missing `@param` tags in `LLM::Repl::Status`,
204
+ `LLM::Tool::Git`, `LLM::Tool::Pwd`, `LLM::Tool::Rg`, and
205
+ `LLM::Tool::SwapText`.
206
+
20
207
  ## v12.2.0
21
208
 
22
209
  Changes since `v12.1.0`.
data/README.md CHANGED
@@ -14,11 +14,10 @@
14
14
 
15
15
  Welcome to the canonical llm.rb repository.
16
16
 
17
- llm.rb is not a library, framework or toolkit but an advanced runtime
18
- for building highly capable AI applications on CRuby. By default
19
- it has zero runtime dependencies although certain functionality &ndash;
20
- such as ActiveRecord support &ndash; require optional dependencies
21
- that are opt-in.
17
+ llm.rb is an advanced runtime for building capable AI applications
18
+ on CRuby. By default it has zero runtime dependencies although certain
19
+ functionality &ndash; such as ActiveRecord support &ndash; require
20
+ optional dependencies that are opt-in.
22
21
 
23
22
  ## Features
24
23
 
@@ -121,13 +120,14 @@ agent.talk "Explain Ruby fibers."
121
120
 
122
121
  The [LLM::Agent#repl](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
123
122
  method allows an agent to spawn a read-eval-print loop
124
- that can be useful during the development and operation
125
- of agents. It can be used to debug tool calls, confirm an
126
- agent has done what was expected, or improve the agent
127
- by asking questions about what it has done up to that point.
123
+ that can be useful while developing or operating agents.
124
+ It can be used to debug tool calls, confirm an
125
+ agent has done what was expected, or improve an agent by
126
+ asking questions about what it has done up to that point.
128
127
 
129
128
  This feature requires that the [curses](https://github.com/ruby/curses)
130
- library is installed and available to require.
129
+ and [kramdown](https://github.com/gettalong/kramdown) libraries are
130
+ installed and available to require.
131
131
 
132
132
  ```ruby
133
133
  llm = LLM.deepseek(key: ENV["KEY"])
@@ -135,6 +135,47 @@ agent = LLM::Agent.new(llm)
135
135
  agent.repl
136
136
  ```
137
137
 
138
+ The read-eval-print loop accepts both `tools` and `skills`
139
+ options that lets you attach additional tools or skills
140
+ for the duration of the session. This is in addition to
141
+ any tools or skills that might already be associated with
142
+ an agent.
143
+
144
+ ```ruby
145
+ llm = LLM.deepseek(key: ENV["KEY"])
146
+ agent = LLM::Agent.new(llm)
147
+ agent.repl(tools: [Debugger], skills: [__dir__])
148
+ ```
149
+
150
+ A number of optional tools are distributed as part
151
+ of llm.rb. They power the agents that can be found in
152
+ the [agents/](agents/) directory, so they're optimized
153
+ for developer tasks.
154
+
155
+ The following example starts a read-eval-print loop
156
+ with all of the builtin tools available.
157
+
158
+ ```ruby
159
+ require "llm"
160
+ require "lll/tools"
161
+
162
+ llm = LLM.deepseek(key: ENV["KEY"])
163
+ agent = LLM::Agent.new(llm)
164
+ agent.repl(tools: LLM::Tool.subclasses)
165
+ ```
166
+
167
+ By default the tracer is disabled for the duration of
168
+ the session. This can be configured through the
169
+ `tracer` option. Setting it to `true` will configure
170
+ the REPL to use the tracer associated with an instance
171
+ of [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html).
172
+
173
+ ```ruby
174
+ llm = LLM.deepseek(key: ENV["KEY"])
175
+ agent = LLM::Agent.new(llm, tracer: LLM.logger(llm, path: "agent.log"))
176
+ agent.repl(tracer: true, tools: [Debugger])
177
+ ```
178
+
138
179
  #### LLM::MCP
139
180
 
140
181
  The Model Context Protocol (MCP) has first-class support