llm.rb 12.4.0 → 12.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/llm/repl.rb CHANGED
@@ -33,7 +33,7 @@ module LLM
33
33
  # @param [Array<String>] skills
34
34
  # Zero or more skills
35
35
  # @return [LLM::Repl]
36
- def initialize(agent:, tools:, skills:, path:)
36
+ def initialize(agent:, tools: [], skills: [], path: nil)
37
37
  @path = path
38
38
  @agent = configure(agent:, path:)
39
39
  @provider = agent.llm.name
@@ -101,6 +101,12 @@ module LLM
101
101
  window.redraw
102
102
  end
103
103
 
104
+ ##
105
+ # @return [String]
106
+ def thinking_text
107
+ "thinking • Esc to cancel"
108
+ end
109
+
104
110
  private
105
111
 
106
112
  ##
@@ -112,9 +118,12 @@ module LLM
112
118
  # When given an unusable path
113
119
  # @return [LLM::Agent]
114
120
  def configure(agent:, path:)
115
- if path.nil? or !File.exist?(path)
121
+ if path.nil?
116
122
  agent
117
- elsif path?
123
+ elsif !File.exist?(path)
124
+ File.write path, "{}"
125
+ agent
126
+ elsif restore?
118
127
  agent.restore(path:)
119
128
  else
120
129
  raise LLM::Error, "I can't use '#{path}' - " \
@@ -131,19 +140,24 @@ module LLM
131
140
  def submit
132
141
  return if thread&.alive? || (text = input.take).empty?
133
142
  case on_text(text)
134
- in [:command, Command => command]
135
- command.call
143
+ in [:command, Command => command, Hash => parameters]
144
+ command.call(**parameters)
145
+ in [:error, String => who, String => text]
146
+ write(who, Curses::A_BOLD)
147
+ write(text)
136
148
  in [:input, String => text]
137
149
  window.scroll_to_bottom
138
- status.text = "thinking"
150
+ status.text = thinking_text
139
151
  write("user: ", Curses::A_BOLD)
140
152
  markdown(text)
141
153
  write("\nagent: ", Curses::A_BOLD)
142
154
  @thread = Thread.new do
143
155
  @queue << [:start]
144
156
  agent.talk(text, tools:, stream:)
145
- agent.save(path:) if path?
157
+ agent.save(path:) if save?
146
158
  @queue << [:done]
159
+ rescue LLM::Interrupt => e
160
+ @queue << [:cancel, e]
147
161
  rescue => e
148
162
  @queue << [:error, e]
149
163
  end
@@ -158,7 +172,25 @@ module LLM
158
172
  # @return [[Symbol, Command|String]]
159
173
  def on_text(text)
160
174
  command = Command.find_by(input: text)
161
- command ? [:command, command.new] : [:input, text]
175
+ if command
176
+ parameters = command.parameters.map { [_1, _2.dup] }.to_h
177
+ args = text.split(" ")[1..].reject(&:empty?)
178
+ reqc = parameters.values.count(&:required?)
179
+ if args.size < reqc
180
+ [:error,
181
+ "command(#{command.name}): ",
182
+ "too few arguments: expected #{reqc} but got #{args.size}\n\n"]
183
+ else
184
+ parameters.each_value do |parameter|
185
+ if args[parameter.index]
186
+ parameter.value = args[parameter.index]
187
+ end
188
+ end
189
+ [:command, command.new(self), parameters.transform_values(&:value)]
190
+ end
191
+ else
192
+ [:input, text]
193
+ end
162
194
  end
163
195
 
164
196
  ##
@@ -179,14 +211,21 @@ module LLM
179
211
  self.status = value
180
212
  when :done
181
213
  status.text = "idle"
182
- @thread = nil
214
+ write("\n\n")
183
215
  transcript.finish
216
+ @thread = nil
217
+ when :cancel
218
+ status.text = "Idle"
219
+ write("\n\nagent: ", Curses::A_BOLD)
220
+ write("request cancelled!")
184
221
  write("\n\n")
222
+ transcript.finish
223
+ @thread = nil
185
224
  when :error
186
225
  # Do this better
187
226
  status.text = "error"
188
- transcript.finish
189
227
  write("\nerror: #{value.message}\n", Curses::A_BOLD)
228
+ transcript.finish
190
229
  @thread = nil
191
230
  end
192
231
  end
@@ -195,9 +234,16 @@ module LLM
195
234
 
196
235
  ##
197
236
  # @return [Boolean]
198
- def path?
237
+ def restore?
238
+ return false if path.nil?
239
+ File.writable?(path)
240
+ end
241
+
242
+ ##
243
+ # @return [Boolean]
244
+ def save?
199
245
  return false if path.nil?
200
- File.readable?(path) and File.writable?(path)
246
+ File.readable?(path)
201
247
  end
202
248
 
203
249
  attr_reader :agent, :provider, :stream,
data/lib/llm/stream.rb CHANGED
@@ -114,20 +114,15 @@ module LLM
114
114
  # `ctx.spawn(tool, :fiber)`, or `ctx.spawn(tool, :task)` onto {#queue}.
115
115
  # Mixed strategies can also be selected per tool, such as
116
116
  # `tool.mcp? ? ctx.spawn(tool, :task) : ctx.spawn(tool, :ractor)`.
117
- # When a streamed tool cannot be resolved, `error` is passed as an
118
- # {LLM::Function::Return}. It can be sent back to the model, allowing
119
- # the tool-call path to recover and the session to continue. Streamed
120
- # tool resolution now prefers the current request tools, so
117
+ # Streamed tool resolution now prefers the current request tools, so
121
118
  # {LLM.function}, MCP tools, bound tool instances, and normal
122
119
  # {LLM::Tool LLM::Tool} classes can all resolve through the same
123
120
  # request-local path. The current `:ractor` mode is for class-based
124
121
  # tools and does not support MCP tools.
125
122
  # @param [LLM::Function] tool
126
123
  # The parsed tool call.
127
- # @param [LLM::Function::Return, nil] error
128
- # An in-band tool error for unresolved tool calls.
129
124
  # @return [nil]
130
- def on_tool_call(tool, error)
125
+ def on_tool_call(tool)
131
126
  nil
132
127
  end
133
128
 
data/lib/llm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LLM
4
- VERSION = "12.4.0"
4
+ VERSION = "12.5.0"
5
5
  end
@@ -563,7 +563,7 @@ class Stream < LLM::Stream
563
563
  puts content
564
564
  end
565
565
 
566
- def on_tool_call(tool, error)
566
+ def on_tool_call(tool)
567
567
  # this callback can be used to either log a tool call,
568
568
  # or execute a tool call during a stream.
569
569
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.4.0
4
+ version: 12.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - robert
@@ -470,6 +470,7 @@ files:
470
470
  - lib/llm/repl/bar.rb
471
471
  - lib/llm/repl/command.rb
472
472
  - lib/llm/repl/commands/exit.rb
473
+ - lib/llm/repl/commands/help.rb
473
474
  - lib/llm/repl/input.rb
474
475
  - lib/llm/repl/markdown.rb
475
476
  - lib/llm/repl/status.rb