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