llm.rb 12.0.0 → 12.1.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 +112 -1
- data/LICENSE +5 -4
- data/README.md +30 -1
- data/data/anthropic.json +83 -371
- data/data/bedrock.json +451 -3
- data/data/deepinfra.json +566 -46
- data/data/deepseek.json +4 -0
- data/data/google.json +22 -0
- data/data/openai.json +51 -0
- data/data/xai.json +8 -0
- data/data/zai.json +14 -0
- data/lib/llm/agent.rb +25 -1
- data/lib/llm/context.rb +8 -0
- data/lib/llm/json_adapter.rb +29 -3
- data/lib/llm/provider.rb +1 -1
- data/lib/llm/providers/llamacpp.rb +5 -5
- data/lib/llm/repl/input.rb +64 -0
- data/lib/llm/repl/status.rb +30 -0
- data/lib/llm/repl/stream.rb +46 -0
- data/lib/llm/repl/transcript.rb +61 -0
- data/lib/llm/repl/window.rb +107 -0
- data/lib/llm/repl.rb +78 -0
- data/lib/llm/tools/chdir.rb +23 -0
- data/lib/llm/tools/git.rb +41 -0
- data/lib/llm/tools/mkdir.rb +32 -0
- data/lib/llm/tools/pwd.rb +20 -0
- data/lib/llm/tools/read_file.rb +40 -0
- data/lib/llm/tools/rg.rb +46 -0
- data/lib/llm/tools/shell.rb +48 -0
- data/lib/llm/tools/swap_text.rb +25 -0
- data/lib/llm/tools/write_file.rb +24 -0
- data/lib/llm/tools.rb +5 -0
- data/lib/llm/version.rb +1 -1
- data/resources/deepdive.md +32 -0
- metadata +17 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal
|
|
4
|
+
|
|
5
|
+
class LLM::Tool
|
|
6
|
+
##
|
|
7
|
+
# The {LLM::Tool::Git LLM::Tool::Git} class implements
|
|
8
|
+
# a tool that can perform a select number of git actions.
|
|
9
|
+
# The actions it can perform are read-only - at least for
|
|
10
|
+
# the time being.
|
|
11
|
+
class Git < self
|
|
12
|
+
name "git"
|
|
13
|
+
description "perform an action with git"
|
|
14
|
+
parameter :action, Enum["log", "diff", "commit", "checkout", "branch", "show"], "the git operation to perform"
|
|
15
|
+
parameter :arguments, Array[String], "one or more arguments for the git action"
|
|
16
|
+
required %i[action]
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# @param [String] path
|
|
20
|
+
# @param [Integer] start
|
|
21
|
+
# @param [Integer] stop
|
|
22
|
+
# @return [Hash]
|
|
23
|
+
def call(action:, arguments: nil)
|
|
24
|
+
command = spawn(action:, arguments:)
|
|
25
|
+
{ok: command.success?, stdout: command.stdout, stderr: command.stderr}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def spawn(action:, arguments:)
|
|
31
|
+
Command
|
|
32
|
+
.new("git")
|
|
33
|
+
.argv(action)
|
|
34
|
+
.argv(*[*arguments])
|
|
35
|
+
.spawn
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
LLM.require "test-cmd.rb"
|
|
39
|
+
Command = Test::Cmd
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class LLM::Tool
|
|
4
|
+
##
|
|
5
|
+
# The {LLM::Tool::Mkdir LLM::Tool::Mkdir} class implements
|
|
6
|
+
# a tool that can create a tree of new directories.
|
|
7
|
+
class Mkdir < self
|
|
8
|
+
name "mkdir"
|
|
9
|
+
description "create a new directory"
|
|
10
|
+
parameter :path, String, "the path to the directory"
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# @param [String] path
|
|
14
|
+
# @return [Hash]
|
|
15
|
+
def call(path:)
|
|
16
|
+
command = spawn(path:)
|
|
17
|
+
{ok: command.success?, stdout: command.stdout, stderr: command.stderr}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def spawn(path:)
|
|
23
|
+
Command
|
|
24
|
+
.new("mkdir")
|
|
25
|
+
.argv("-p", path)
|
|
26
|
+
.spawn
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
LLM.require "test-cmd.rb"
|
|
30
|
+
Command = Test::Cmd
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal
|
|
4
|
+
|
|
5
|
+
class LLM::Tool
|
|
6
|
+
##
|
|
7
|
+
# The {LLM::Tool::Pwd LLM::Tool::Pwd} class implements
|
|
8
|
+
# a tool that can reveal the current working directory.
|
|
9
|
+
class Pwd < self
|
|
10
|
+
name "pwd"
|
|
11
|
+
description "returns the current working directory"
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# @param [String] path
|
|
15
|
+
# @return [Hash]
|
|
16
|
+
def call
|
|
17
|
+
{ok: true, cwd: Dir.getwd}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal
|
|
4
|
+
|
|
5
|
+
class LLM::Tool
|
|
6
|
+
##
|
|
7
|
+
# The {LLM::Tool::ReadFile LLM::Tool::ReadFile} class implements
|
|
8
|
+
# a tool that can read the contents of a file. The tool accepts
|
|
9
|
+
# two optional offsets: a start line, and a stop line. Without
|
|
10
|
+
# either the entire file contents are read into memory.
|
|
11
|
+
class ReadFile < self
|
|
12
|
+
name "read-file"
|
|
13
|
+
description "read the contents of a file"
|
|
14
|
+
parameter :path, String, "the path to the file"
|
|
15
|
+
parameter :start, Integer, "start line number"
|
|
16
|
+
parameter :stop, Integer, "stop line number"
|
|
17
|
+
required %i[path]
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# @param [String] path
|
|
21
|
+
# @param [Integer] start
|
|
22
|
+
# @param [Integer] stop
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
def call(path:, start: 1, stop: -1)
|
|
25
|
+
content, cursor = nil, 1
|
|
26
|
+
File.open(path, "r") do |f|
|
|
27
|
+
while cursor < start
|
|
28
|
+
f.gets
|
|
29
|
+
cursor += 1
|
|
30
|
+
end
|
|
31
|
+
if stop == -1
|
|
32
|
+
content = f.read
|
|
33
|
+
else
|
|
34
|
+
content = start.upto(stop).map { f.gets }.join
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
{ok: true, content:}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/llm/tools/rg.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal
|
|
4
|
+
|
|
5
|
+
class LLM::Tool
|
|
6
|
+
##
|
|
7
|
+
# The {LLM::Tool::Rg LLM::Tool::Rg} class implements
|
|
8
|
+
# a frontend to the popular 'rg' tool. The tool can
|
|
9
|
+
# recursively search the current working directory
|
|
10
|
+
# for one or more patterns.
|
|
11
|
+
class Rg < self
|
|
12
|
+
name "rg"
|
|
13
|
+
description "recursively search the current directory for lines matching a pattern"
|
|
14
|
+
parameter :patterns, Array[String], "one or more search patterns"
|
|
15
|
+
parameter :path, String, "the path where the search is performed (default is cwd)"
|
|
16
|
+
required %i[patterns]
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# @param [String] pattern
|
|
20
|
+
# @return [Hash]
|
|
21
|
+
def call(patterns:, path: Dir.getwd)
|
|
22
|
+
validate!(patterns:, path:)
|
|
23
|
+
command = spawn(patterns:, path:)
|
|
24
|
+
{ok: command.success?, stdout: command.stdout, stderr: command.stderr}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def validate!(patterns:, path:)
|
|
30
|
+
if path == "/"
|
|
31
|
+
raise RuntimeError, "you can't search from the root of the filesystem"
|
|
32
|
+
elsif patterns == ["."]
|
|
33
|
+
raise RuntimeError, "narrow your search"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def spawn(patterns:, path:)
|
|
38
|
+
Command.new("rg")
|
|
39
|
+
.argv(*[*patterns].flat_map { ["-e", _1] }, path)
|
|
40
|
+
.spawn
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
LLM.require "test-cmd.rb"
|
|
44
|
+
Command = Test::Cmd
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal
|
|
4
|
+
|
|
5
|
+
class LLM::Tool
|
|
6
|
+
##
|
|
7
|
+
# The {LLM::Tool::Shell} class implements a tool that can
|
|
8
|
+
# spawn a command. That can be dangerous given a low-quality
|
|
9
|
+
# model, or a high-quality model that simply makes a bad
|
|
10
|
+
# decision. The risk can be reduced through a confirmation
|
|
11
|
+
# step such as {LLM::Agent.confirm LLM::Agent.confirm}, or
|
|
12
|
+
# by managing the tool loop manually through
|
|
13
|
+
# {LLM::Context LLM::Context}.
|
|
14
|
+
class Shell < self
|
|
15
|
+
name "shell"
|
|
16
|
+
description "run a shell command"
|
|
17
|
+
parameter :name, String, "the command name"
|
|
18
|
+
parameter :arguments, Array[String], "one or more command arguments"
|
|
19
|
+
required %i[name]
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# @param [String] name
|
|
23
|
+
# The name of a command
|
|
24
|
+
# @param [Array<String>] arguments
|
|
25
|
+
# One or more command-line arguments
|
|
26
|
+
# @return [Hash]
|
|
27
|
+
def call(name:, arguments: nil)
|
|
28
|
+
command = spawn(name:, arguments:)
|
|
29
|
+
{ok: command.success?, stdout: command.stdout, stderr: command.stderr}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# @param [String] name
|
|
36
|
+
# @param [Array<String>] arguments
|
|
37
|
+
# @return [Command]
|
|
38
|
+
def spawn(name:, arguments:)
|
|
39
|
+
Command
|
|
40
|
+
.new(name)
|
|
41
|
+
.argv(*[*arguments])
|
|
42
|
+
.spawn
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
LLM.require "test-cmd.rb"
|
|
46
|
+
Command = Test::Cmd
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class LLM::Tool
|
|
4
|
+
##
|
|
5
|
+
# The {LLM::Tool::SwapText LLM::Tool::SwapText} class
|
|
6
|
+
# implements a tool that can substitute one piece of
|
|
7
|
+
# text for another piece of text in a given file.
|
|
8
|
+
class SwapText < self
|
|
9
|
+
name "swap-text"
|
|
10
|
+
description "Replace an exact snippet in a file"
|
|
11
|
+
parameter :path, String, "Path to file"
|
|
12
|
+
parameter :before, String, "Exact text to replace"
|
|
13
|
+
parameter :after, String, "Replacement text"
|
|
14
|
+
parameter :expected_count, Integer, "How many matches should be replaced"
|
|
15
|
+
required %i[path before after]
|
|
16
|
+
|
|
17
|
+
def call(path:, before:, after:, expected_count: 1)
|
|
18
|
+
content = File.read(path)
|
|
19
|
+
count = content.scan(before).length
|
|
20
|
+
raise "expected #{expected_count} match(es), found #{count}" unless count == expected_count.to_i
|
|
21
|
+
File.write(path, content.sub(before, after))
|
|
22
|
+
{ok: true, replaced: count}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class LLM::Tool
|
|
4
|
+
##
|
|
5
|
+
# The {LLM::Tool::WriteFile LLM::Tool::WriteFile} class
|
|
6
|
+
# implements a tool that can write a given string to a
|
|
7
|
+
# given file path.
|
|
8
|
+
class WriteFile < self
|
|
9
|
+
name "write-file"
|
|
10
|
+
description "write to a file"
|
|
11
|
+
parameter :path, String, "The file path"
|
|
12
|
+
parameter :content, String, "The file content"
|
|
13
|
+
required %i[path content]
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# @param [String] path
|
|
17
|
+
# @param [String] content
|
|
18
|
+
# @return [Hash]
|
|
19
|
+
def call(path:, content:)
|
|
20
|
+
File.open(path, "w") { _1.write(content) }
|
|
21
|
+
{ok: true}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/llm/tools.rb
ADDED
data/lib/llm/version.rb
CHANGED
data/resources/deepdive.md
CHANGED
|
@@ -54,6 +54,8 @@ features that didn't make it into the homepage documentation.
|
|
|
54
54
|
- [Tracer](#tracer)
|
|
55
55
|
- [Provider-wide tracer](#provider-wide-tracer)
|
|
56
56
|
- [Agent-local tracer](#agent-local-tracer)
|
|
57
|
+
- [REPL](#repl)
|
|
58
|
+
- [LLM::Agent](#llmagent)
|
|
57
59
|
- [Images](#images)
|
|
58
60
|
- [Generation](#generation)
|
|
59
61
|
- [Edits](#edits)
|
|
@@ -802,6 +804,36 @@ agent = LLM::Agent.new(llm, tracer: LLM::Tracer::Logger.new(llm, path: "deepseek
|
|
|
802
804
|
|
|
803
805
|
[Back to top](#table-of-contents)
|
|
804
806
|
|
|
807
|
+
## REPL
|
|
808
|
+
|
|
809
|
+
During the development and operation of agents it can often
|
|
810
|
+
be helpful to drop into a read-eval-print loop. This gives
|
|
811
|
+
you a simple way to confirm the work was successful, inspect
|
|
812
|
+
anything that went wrong (for example, tool call errors), and
|
|
813
|
+
keep talking to the same agent so you can learn about its
|
|
814
|
+
decision-making process and make improvements for future runs.
|
|
815
|
+
It can also be used to ask the agent to correct any errors
|
|
816
|
+
that might have made.
|
|
817
|
+
|
|
818
|
+
##### LLM::Agent
|
|
819
|
+
|
|
820
|
+
The [LLM::Agent#repl](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
|
|
821
|
+
method requires the [curses](https://github.com/ruby/curses)
|
|
822
|
+
gem to be installed and available for require. It is an
|
|
823
|
+
optional dependency that only becomes required when you
|
|
824
|
+
call the [LLM::Agent#repl](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html#repl-instance_method)
|
|
825
|
+
method.
|
|
826
|
+
|
|
827
|
+
```ruby
|
|
828
|
+
require "llm"
|
|
829
|
+
|
|
830
|
+
llm = LLM.deepseek(key: ENV["KEY"])
|
|
831
|
+
agent = LLM::Agent.new(llm)
|
|
832
|
+
agent.repl
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
[Back to top](#table-of-contents)
|
|
836
|
+
|
|
805
837
|
## Images
|
|
806
838
|
|
|
807
839
|
The OpenAI, Google, xAI, DeepInfra, and DeepSeek providers have
|
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
|
+
version: 12.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- bsdrobert
|
|
@@ -459,6 +459,12 @@ files:
|
|
|
459
459
|
- lib/llm/providers/xai/images.rb
|
|
460
460
|
- lib/llm/providers/zai.rb
|
|
461
461
|
- lib/llm/registry.rb
|
|
462
|
+
- lib/llm/repl.rb
|
|
463
|
+
- lib/llm/repl/input.rb
|
|
464
|
+
- lib/llm/repl/status.rb
|
|
465
|
+
- lib/llm/repl/stream.rb
|
|
466
|
+
- lib/llm/repl/transcript.rb
|
|
467
|
+
- lib/llm/repl/window.rb
|
|
462
468
|
- lib/llm/response.rb
|
|
463
469
|
- lib/llm/schema.rb
|
|
464
470
|
- lib/llm/schema/all_of.rb
|
|
@@ -485,6 +491,16 @@ files:
|
|
|
485
491
|
- lib/llm/stream/queue.rb
|
|
486
492
|
- lib/llm/tool.rb
|
|
487
493
|
- lib/llm/tool/param.rb
|
|
494
|
+
- lib/llm/tools.rb
|
|
495
|
+
- lib/llm/tools/chdir.rb
|
|
496
|
+
- lib/llm/tools/git.rb
|
|
497
|
+
- lib/llm/tools/mkdir.rb
|
|
498
|
+
- lib/llm/tools/pwd.rb
|
|
499
|
+
- lib/llm/tools/read_file.rb
|
|
500
|
+
- lib/llm/tools/rg.rb
|
|
501
|
+
- lib/llm/tools/shell.rb
|
|
502
|
+
- lib/llm/tools/swap_text.rb
|
|
503
|
+
- lib/llm/tools/write_file.rb
|
|
488
504
|
- lib/llm/tracer.rb
|
|
489
505
|
- lib/llm/tracer/logger.rb
|
|
490
506
|
- lib/llm/tracer/null.rb
|