ollama_chat 0.0.62 → 0.0.63
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/CHANGES.md +35 -0
- data/lib/ollama_chat/chat.rb +46 -16
- data/lib/ollama_chat/env_config.rb +18 -0
- data/lib/ollama_chat/follow_chat.rb +31 -28
- data/lib/ollama_chat/message_list.rb +3 -1
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +35 -3
- data/lib/ollama_chat/tool_calling.rb +26 -1
- data/lib/ollama_chat/tools/browse.rb +86 -0
- data/lib/ollama_chat/tools/concern.rb +16 -0
- data/lib/ollama_chat/tools/endoflife.rb +0 -74
- data/lib/ollama_chat/tools/{grep.rb → execute_grep.rb} +24 -4
- data/lib/ollama_chat/tools/file_context.rb +34 -21
- data/lib/ollama_chat/tools/gem_path_lookup.rb +96 -0
- data/lib/ollama_chat/tools/{weather.rb → get_current_weather.rb} +4 -2
- data/lib/ollama_chat/tools/{cve.rb → get_cve.rb} +5 -8
- data/lib/ollama_chat/tools/get_endoflife.rb +74 -0
- data/lib/ollama_chat/tools/{location.rb → get_location.rb} +1 -1
- data/lib/ollama_chat/tools/import_url.rb +81 -0
- data/lib/ollama_chat/tools/read_file.rb +43 -0
- data/lib/ollama_chat/tools/run_tests.rb +84 -0
- data/lib/ollama_chat/tools/search_web.rb +75 -0
- data/lib/ollama_chat/tools/vim_open_file.rb +93 -0
- data/lib/ollama_chat/tools/write_file.rb +91 -0
- data/lib/ollama_chat/tools.rb +25 -7
- data/lib/ollama_chat/utils/path_validator.rb +55 -0
- data/lib/ollama_chat/utils.rb +1 -0
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat/vim.rb +84 -10
- data/lib/ollama_chat.rb +19 -2
- data/ollama_chat.gemspec +5 -5
- data/spec/ollama_chat/message_list_spec.rb +1 -0
- data/spec/ollama_chat/tools/browse_spec.rb +131 -0
- data/spec/ollama_chat/tools/directory_structure_spec.rb +3 -3
- data/spec/ollama_chat/tools/{grep_spec.rb → execute_grep_spec.rb} +72 -20
- data/spec/ollama_chat/tools/file_context_spec.rb +6 -94
- data/spec/ollama_chat/tools/gem_path_lookup_spec.rb +82 -0
- data/spec/ollama_chat/tools/{weather_spec.rb → get_current_weather_spec.rb} +6 -6
- data/spec/ollama_chat/tools/{cve_spec.rb → get_cve_spec.rb} +10 -9
- data/spec/ollama_chat/tools/{endoflife_spec.rb → get_endoflife_spec.rb} +12 -10
- data/spec/ollama_chat/tools/{location_spec.rb → get_location_spec.rb} +5 -5
- data/spec/ollama_chat/tools/import_url_spec.rb +97 -0
- data/spec/ollama_chat/tools/read_file_spec.rb +85 -0
- data/spec/ollama_chat/tools/run_tests_spec.rb +113 -0
- data/spec/ollama_chat/tools/search_web_spec.rb +104 -0
- data/spec/ollama_chat/tools/vim_open_file_spec.rb +86 -0
- data/spec/ollama_chat/tools/write_file_spec.rb +136 -0
- data/spec/spec_helper.rb +44 -7
- metadata +55 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d207c29d7838f0cb8bb885dfc93038d2c246eb63d829d0af2e0cdef4c404d3f
|
|
4
|
+
data.tar.gz: 3b70df18f2d302506614a56556ec0f98d2e814a3558a7bc141b73cc0716c5158
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b2647b7371490991e879f6f48682a7e7e2a2c3d7ab0fafd41fc7275cd204f9bb288b0ca0e8b11d5be9b0c23b54c93d141e418f0495ce4782de2b0165df1a703
|
|
7
|
+
data.tar.gz: 83fa7ff6da22352d5d5af335e98975d423641ab3969e51f311068fd0912f4fb3494c22058c1a66e892cf1d11574cc705d9dc3c714ef50123ad555ca67011311b
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-02-09 v0.0.63
|
|
4
|
+
|
|
5
|
+
- Added `OllamaChat::Utils::PathValidator` module with `assert_valid_path`
|
|
6
|
+
helper and `OllamaChat::InvalidPathError` exception
|
|
7
|
+
- Refactored `FileContext`, `ReadFile`, and `WriteFile` tools to use new path
|
|
8
|
+
validation logic
|
|
9
|
+
- Simplified `OllamaChat::Tools::FileContext` to use glob pattern only,
|
|
10
|
+
removing the `path` parameter
|
|
11
|
+
- Added `ignore_case` flag to `execute_grep` tool with dynamic command
|
|
12
|
+
construction using `eval_template`
|
|
13
|
+
- Renamed tool classes and files to more descriptive names:
|
|
14
|
+
- `browser.rb` → `browse.rb` (class `Browser` → `Browse`)
|
|
15
|
+
- `grep.rb` → `execute_grep.rb` (class `Grep` → `ExecuteGrep`)
|
|
16
|
+
- `weather.rb` → `get_current_weather.rb` (class `Weather` → `GetCurrentWeather`)
|
|
17
|
+
- `cve.rb` → `get_cve.rb` (class `CVE` → `GetCVE`)
|
|
18
|
+
- `endoflife.rb` → `get_endoflife.rb` (class `EndOfLife` → `GetEndoflife`)
|
|
19
|
+
- `location.rb` → `get_location.rb` (class `Location` → `GetLocation`)
|
|
20
|
+
- `file_reader.rb` → `read_file.rb` (class `FileReader` → `ReadFile`)
|
|
21
|
+
- `file_writer.rb` → `write_file.rb` (class `FileWriter` → `WriteFile`)
|
|
22
|
+
- Updated `follow_chat.rb` to use `require_confirmation?` instead of `confirm?`
|
|
23
|
+
when checking tool confirmation
|
|
24
|
+
- Added scheme whitelist to `ImportURL` tool with `schemes: [http, https]`
|
|
25
|
+
configuration
|
|
26
|
+
- Introduced `read_file` tool with path validation and error handling
|
|
27
|
+
- Added `run_tests` tool for executing RSpec or Test-Unit test suites with
|
|
28
|
+
configurable runner and coverage reporting
|
|
29
|
+
- Added `vim_open_file` tool for remote Vim file opening with line range
|
|
30
|
+
support
|
|
31
|
+
- Enhanced `OllamaChat::Vim` class with file opening and line/range selection
|
|
32
|
+
capabilities
|
|
33
|
+
- Added `GemPathLookup` tool to find gem installation paths using Bundler
|
|
34
|
+
- Added `valid_json?` method to `OllamaChat::Tools::Concern` for consistent
|
|
35
|
+
JSON validation
|
|
36
|
+
- Implemented `ImportURL` tool for fetching web content
|
|
37
|
+
|
|
3
38
|
## 2026-02-07 v0.0.62
|
|
4
39
|
|
|
5
40
|
**Tool Execution**
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -95,27 +95,21 @@ class OllamaChat::Chat
|
|
|
95
95
|
connect_ollama
|
|
96
96
|
@model = choose_model(@opts[?m], config.model.name)
|
|
97
97
|
@model_options = Ollama::Options[config.model.options]
|
|
98
|
-
model_system
|
|
99
|
-
embedding_enabled.set(config.embedding.enabled && !@opts[?E])
|
|
98
|
+
@model_system = pull_model_unless_present(@model, @model_options)
|
|
100
99
|
if @opts[?c]
|
|
101
100
|
messages.load_conversation(@opts[?c])
|
|
102
101
|
else
|
|
103
|
-
|
|
104
|
-
if @opts[?s] =~ /\A\?/
|
|
105
|
-
change_system_prompt(default, system: @opts[?s])
|
|
106
|
-
else
|
|
107
|
-
system = OllamaChat::Utils::FileArgument.get_file_argument(@opts[?s], default:)
|
|
108
|
-
system.present? and messages.set_system_prompt(system)
|
|
109
|
-
end
|
|
102
|
+
setup_system_prompt
|
|
110
103
|
end
|
|
104
|
+
embedding_enabled.set(config.embedding.enabled && !@opts[?E])
|
|
111
105
|
@documents = setup_documents
|
|
112
106
|
@cache = setup_cache
|
|
113
107
|
@images = []
|
|
114
108
|
@kramdown_ansi_styles = configure_kramdown_ansi_styles
|
|
109
|
+
@enabled_tools = default_enabled_tools
|
|
110
|
+
@tool_call_results = {}
|
|
115
111
|
init_chat_history
|
|
116
112
|
@opts[?S] and init_server_socket
|
|
117
|
-
@enabled_tools = config.tools.to_h.map { |n, v| n.to_s if v[:default] }.compact
|
|
118
|
-
@tool_call_results = {}
|
|
119
113
|
rescue ComplexConfig::AttributeMissing, ComplexConfig::ConfigurationSyntaxError => e
|
|
120
114
|
fix_config(e)
|
|
121
115
|
end
|
|
@@ -208,6 +202,25 @@ class OllamaChat::Chat
|
|
|
208
202
|
interact_with_user
|
|
209
203
|
end
|
|
210
204
|
|
|
205
|
+
# The vim method creates and returns a new Vim instance for interacting with
|
|
206
|
+
# a Vim server.
|
|
207
|
+
#
|
|
208
|
+
# This method initializes a Vim client that can be used to insert text into
|
|
209
|
+
# Vim buffers or open files in a running Vim server. It derives the server
|
|
210
|
+
# name from the provided argument or uses a default server name based on the
|
|
211
|
+
# current working directory.
|
|
212
|
+
#
|
|
213
|
+
# @param server_name [ String, nil ] the name of the Vim server to connect to
|
|
214
|
+
# If nil or empty, a default server name is derived from the current
|
|
215
|
+
# working directory
|
|
216
|
+
#
|
|
217
|
+
# @return [ OllamaChat::Vim ] a new Vim instance configured with the
|
|
218
|
+
# specified server name
|
|
219
|
+
def vim(server_name = nil)
|
|
220
|
+
clientserver = config.vim?&.clientserver
|
|
221
|
+
OllamaChat::Vim.new(server_name, clientserver:)
|
|
222
|
+
end
|
|
223
|
+
|
|
211
224
|
private
|
|
212
225
|
|
|
213
226
|
# Handles user input commands and processes chat interactions.
|
|
@@ -248,7 +261,7 @@ class OllamaChat::Chat
|
|
|
248
261
|
messages.list_conversation(n)
|
|
249
262
|
:next
|
|
250
263
|
when %r(^/last(?:\s+(\d*))?$)
|
|
251
|
-
n = $1.to_i
|
|
264
|
+
n = $1.to_i.clamp(1..)
|
|
252
265
|
messages.show_last(n)
|
|
253
266
|
:next
|
|
254
267
|
when %r(^/clear(?:\s+(messages|links|history|tags|all))?$)
|
|
@@ -370,8 +383,7 @@ class OllamaChat::Chat
|
|
|
370
383
|
:next
|
|
371
384
|
when %r(^/vim(?:\s+(.+))?$)
|
|
372
385
|
if message = messages.last
|
|
373
|
-
|
|
374
|
-
OllamaChat::Vim.new($1, clientserver:).insert message.content
|
|
386
|
+
vim($1).insert message.content
|
|
375
387
|
else
|
|
376
388
|
STDERR.puts "Warning: No message found to insert into Vim"
|
|
377
389
|
end
|
|
@@ -702,8 +714,6 @@ class OllamaChat::Chat
|
|
|
702
714
|
save_history
|
|
703
715
|
end
|
|
704
716
|
|
|
705
|
-
private
|
|
706
|
-
|
|
707
717
|
# The base_url method returns the Ollama server URL from command-line options
|
|
708
718
|
# or environment configuration.
|
|
709
719
|
#
|
|
@@ -738,6 +748,26 @@ class OllamaChat::Chat
|
|
|
738
748
|
@ollama
|
|
739
749
|
end
|
|
740
750
|
|
|
751
|
+
# Sets up the system prompt for the chat session.
|
|
752
|
+
#
|
|
753
|
+
# This method determines whether to use a default system prompt or a custom
|
|
754
|
+
# one specified via command-line options. If a custom system prompt is
|
|
755
|
+
# provided with a regex selector (starting with ?), it invokes the
|
|
756
|
+
# change_system_prompt method to handle the selection. Otherwise, it
|
|
757
|
+
# retrieves the system prompt from a file or uses the default value, then
|
|
758
|
+
# sets it in the message history.
|
|
759
|
+
#
|
|
760
|
+
# @return [ void ] this method returns nil after setting up the system prompt
|
|
761
|
+
def setup_system_prompt
|
|
762
|
+
default = config.system_prompts.default? || @model_system
|
|
763
|
+
if @opts[?s] =~ /\A\?/
|
|
764
|
+
change_system_prompt(default, system: @opts[?s])
|
|
765
|
+
else
|
|
766
|
+
system = OllamaChat::Utils::FileArgument.get_file_argument(@opts[?s], default:)
|
|
767
|
+
system.present? and messages.set_system_prompt(system)
|
|
768
|
+
end
|
|
769
|
+
end
|
|
770
|
+
|
|
741
771
|
# The setup_documents method initializes the document processing pipeline by
|
|
742
772
|
# configuring the embedding model and database connection.
|
|
743
773
|
# It then loads specified documents into the system and returns the
|
|
@@ -51,6 +51,14 @@ module OllamaChat
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
BROWSER = set do
|
|
55
|
+
description 'Browser to use'
|
|
56
|
+
|
|
57
|
+
default do
|
|
58
|
+
%w[ open xdg-open ].find { `which #{_1}` }.full?(:chomp)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
54
62
|
DIFF_TOOL = set do
|
|
55
63
|
description 'Diff tool to apply changes with'
|
|
56
64
|
|
|
@@ -128,6 +136,16 @@ module OllamaChat
|
|
|
128
136
|
description 'File to save the chat history in'
|
|
129
137
|
default XDG_CACHE_HOME + 'history.json'
|
|
130
138
|
end
|
|
139
|
+
|
|
140
|
+
module TOOLS
|
|
141
|
+
description 'Tool specific configuration settings'
|
|
142
|
+
|
|
143
|
+
RUN_TESTS_TEST_RUNNER = set do
|
|
144
|
+
description 'Configured test runner for run_tests tool function'
|
|
145
|
+
default 'rspec'
|
|
146
|
+
required true
|
|
147
|
+
end
|
|
148
|
+
end
|
|
131
149
|
end
|
|
132
150
|
end
|
|
133
151
|
end
|
|
@@ -103,43 +103,46 @@ class OllamaChat::FollowChat
|
|
|
103
103
|
response.message.tool_calls.each do |tool_call|
|
|
104
104
|
name = tool_call.function.name
|
|
105
105
|
unless @chat.config.tools.attribute_set?(name)
|
|
106
|
-
STDERR.printf("
|
|
106
|
+
STDERR.printf("Unconfigured tool named %s ignored => Skip.\n", name)
|
|
107
|
+
next
|
|
108
|
+
end
|
|
109
|
+
unless OllamaChat::Tools.registered?(name)
|
|
110
|
+
STDERR.printf("Unregistered tool named %s ignored => Skip.\n", name)
|
|
107
111
|
next
|
|
108
112
|
end
|
|
109
113
|
STDOUT.puts
|
|
110
114
|
confirmed = true
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
args = JSON.pretty_generate(tool_call.function.arguments)
|
|
116
|
+
if @chat.config.tools[name].require_confirmation?
|
|
117
|
+
prompt = "I want to execute tool %s\n%s\nConfirm? (y/n) " % [
|
|
113
118
|
bold { name },
|
|
114
|
-
italic {
|
|
119
|
+
italic { args },
|
|
115
120
|
]
|
|
116
121
|
confirmed = @chat.ask?(prompt:) =~ /\Ay/i
|
|
122
|
+
else
|
|
123
|
+
STDOUT.puts "Executing tool %s\n%s" % [
|
|
124
|
+
bold { name },
|
|
125
|
+
italic { args },
|
|
126
|
+
]
|
|
117
127
|
end
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
result =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
result = JSON(
|
|
135
|
-
message: 'User denied confirmation!',
|
|
136
|
-
resolve: 'You **MUST** ask the user for instructions on how to proceed!!!',
|
|
137
|
-
)
|
|
138
|
-
end
|
|
139
|
-
@chat.tool_call_results[name] = result
|
|
128
|
+
result = nil
|
|
129
|
+
if confirmed
|
|
130
|
+
STDOUT.printf(
|
|
131
|
+
"\n%s Execution of tool %s confirmed.\n\n", ?✅, bold { name }
|
|
132
|
+
)
|
|
133
|
+
result = OllamaChat::Tools.registered[name].
|
|
134
|
+
execute(tool_call, chat: @chat, config: @chat.config)
|
|
135
|
+
else
|
|
136
|
+
result = JSON(
|
|
137
|
+
message: 'User denied confirmation!',
|
|
138
|
+
resolve: 'You **MUST** ask the user for instructions on how to proceed!!!',
|
|
139
|
+
)
|
|
140
|
+
STDOUT.printf(
|
|
141
|
+
"\n%s Execution of tool %s denied by user.\n", ?🚫, bold { name }
|
|
142
|
+
)
|
|
143
|
+
sleep 1
|
|
140
144
|
end
|
|
141
|
-
|
|
142
|
-
infobar.newline
|
|
145
|
+
@chat.tool_call_results[name] = result
|
|
143
146
|
end
|
|
144
147
|
end
|
|
145
148
|
|
|
@@ -113,7 +113,9 @@ class OllamaChat::MessageList
|
|
|
113
113
|
end
|
|
114
114
|
@messages =
|
|
115
115
|
File.open(filename, 'r') do |output|
|
|
116
|
-
JSON(output.read).map {
|
|
116
|
+
JSON(output.read).map {
|
|
117
|
+
Ollama::Message.from_hash(_1 | { 'content' => nil })
|
|
118
|
+
}
|
|
117
119
|
end
|
|
118
120
|
self
|
|
119
121
|
end
|
|
@@ -98,13 +98,45 @@ tools:
|
|
|
98
98
|
default: true
|
|
99
99
|
file_context:
|
|
100
100
|
default: false
|
|
101
|
-
|
|
101
|
+
require_confirmation: true
|
|
102
|
+
allowed:
|
|
103
|
+
- ./spec
|
|
102
104
|
directory_structure:
|
|
103
105
|
default: false
|
|
104
|
-
|
|
106
|
+
require_confirmation: true
|
|
105
107
|
exclude:
|
|
106
108
|
- corpus
|
|
107
109
|
- pkg
|
|
108
110
|
execute_grep:
|
|
109
111
|
default: true
|
|
110
|
-
cmd:
|
|
112
|
+
cmd: |
|
|
113
|
+
grep #{'-i' if ignore_case} -m #{max_results} -r #{pattern} #{path}
|
|
114
|
+
browse:
|
|
115
|
+
default: false
|
|
116
|
+
write_file:
|
|
117
|
+
default: false
|
|
118
|
+
require_confirmation: true
|
|
119
|
+
allowed:
|
|
120
|
+
- ./tmp
|
|
121
|
+
read_file:
|
|
122
|
+
default: false
|
|
123
|
+
require_confirmation: false
|
|
124
|
+
allowed:
|
|
125
|
+
- ./tmp
|
|
126
|
+
- ./lib
|
|
127
|
+
- ./spec
|
|
128
|
+
search_web:
|
|
129
|
+
default: true
|
|
130
|
+
import_url:
|
|
131
|
+
default: true
|
|
132
|
+
require_confirmation: true
|
|
133
|
+
schemes:
|
|
134
|
+
- http
|
|
135
|
+
- https
|
|
136
|
+
gem_path_lookup:
|
|
137
|
+
default: true
|
|
138
|
+
vim_open_file:
|
|
139
|
+
default: true
|
|
140
|
+
run_tests:
|
|
141
|
+
require_confirmation: true
|
|
142
|
+
default: true
|
|
@@ -13,6 +13,27 @@ module OllamaChat::ToolCalling
|
|
|
13
13
|
@enabled_tools.map { OllamaChat::Tools.registered[it]&.to_hash }.compact
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# The default_enabled_tools method returns an array of tool names that are
|
|
17
|
+
# configured as default tools.
|
|
18
|
+
#
|
|
19
|
+
# This method iterates through the configured tools and collects those that
|
|
20
|
+
# are registered and have the default flag set to true. Unregistered tools
|
|
21
|
+
# are skipped with a warning message.
|
|
22
|
+
#
|
|
23
|
+
# @return [Array<String>] a sorted array of tool names that are configured as
|
|
24
|
+
# default tools
|
|
25
|
+
def default_enabled_tools
|
|
26
|
+
result = []
|
|
27
|
+
config.tools.each { |n, v|
|
|
28
|
+
if OllamaChat::Tools.registered?(n)
|
|
29
|
+
result << n.to_s if v.default
|
|
30
|
+
else
|
|
31
|
+
STDERR.puts "Skipping configuration for unregistered tool %s" % bold { n }
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
|
|
16
37
|
# The configured_tools method returns an array of tool names configured for
|
|
17
38
|
# the chat session.
|
|
18
39
|
#
|
|
@@ -39,7 +60,11 @@ module OllamaChat::ToolCalling
|
|
|
39
60
|
def list_tools
|
|
40
61
|
configured_tools.each do |tool|
|
|
41
62
|
enabled = @enabled_tools.member?(tool) ? ?✓ : ?☐
|
|
42
|
-
|
|
63
|
+
require_confirmation = config.tools[tool].require_confirmation? ? ?? : ?☐
|
|
64
|
+
printf(
|
|
65
|
+
"%s %s %s\n",
|
|
66
|
+
enabled, require_confirmation, (enabled ? bold { tool } : tool)
|
|
67
|
+
)
|
|
43
68
|
end
|
|
44
69
|
end
|
|
45
70
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require "shellwords"
|
|
2
|
+
|
|
3
|
+
# A tool for opening URLs/files in the user's default browser application.
|
|
4
|
+
#
|
|
5
|
+
# This tool enables the chat client to open web URLs or local files in the
|
|
6
|
+
# user's default browser, allowing users to view content directly in their
|
|
7
|
+
# browser environment. It integrates with the Ollama tool calling system to
|
|
8
|
+
# provide
|
|
9
|
+
# seamless web browsing capabilities during chat interactions.
|
|
10
|
+
class OllamaChat::Tools::Browse
|
|
11
|
+
include OllamaChat::Tools::Concern
|
|
12
|
+
|
|
13
|
+
def self.register_name = 'browse'
|
|
14
|
+
|
|
15
|
+
# Creates and returns a tool definition for opening URLs/files in the browser.
|
|
16
|
+
#
|
|
17
|
+
# This method constructs the function signature that describes what the tool
|
|
18
|
+
# does, its parameters, and required fields. The tool expects a URL parameter
|
|
19
|
+
# to be provided.
|
|
20
|
+
#
|
|
21
|
+
# @return [Ollama::Tool] a tool definition for opening URLs/files in the browser
|
|
22
|
+
def tool
|
|
23
|
+
Tool.new(
|
|
24
|
+
type: 'function',
|
|
25
|
+
function: Tool::Function.new(
|
|
26
|
+
name:,
|
|
27
|
+
description: <<~EOT,
|
|
28
|
+
Open a URL or file in the user\'s default browser application so they
|
|
29
|
+
can view the content directly
|
|
30
|
+
EOT
|
|
31
|
+
parameters: Tool::Function::Parameters.new(
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
url: Tool::Function::Parameters::Property.new(
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: <<~EOT,
|
|
37
|
+
The URL or file to open in the user\'s browser for them to view
|
|
38
|
+
directly
|
|
39
|
+
EOT
|
|
40
|
+
),
|
|
41
|
+
},
|
|
42
|
+
required: %w[url]
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Executes the browser opening operation.
|
|
49
|
+
#
|
|
50
|
+
# This method opens the specified URL or file in the user's default browser
|
|
51
|
+
# application. It handles the system call and returns the result status.
|
|
52
|
+
#
|
|
53
|
+
# @param tool_call [Ollama::Tool::Call] the tool call object containing function details
|
|
54
|
+
# @param opts [Hash] additional options
|
|
55
|
+
# @return [String] the execution result as JSON string
|
|
56
|
+
# @raise [StandardError] if there's an issue with opening the URL/file
|
|
57
|
+
def execute(tool_call, **opts)
|
|
58
|
+
url = tool_call.function.arguments.url
|
|
59
|
+
result = browse_url(url)
|
|
60
|
+
{
|
|
61
|
+
success: result.success?,
|
|
62
|
+
exitstatus: result.exitstatus,
|
|
63
|
+
message: 'opening URL/file',
|
|
64
|
+
url: ,
|
|
65
|
+
}.to_json
|
|
66
|
+
rescue => e
|
|
67
|
+
{ error: e.class, message: e.message }.to_json
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Opens a URL or file in the system browser.
|
|
73
|
+
#
|
|
74
|
+
# This method uses the system's default browser to open the provided URL or file.
|
|
75
|
+
# It respects the BROWSER environment variable if set, otherwise defaults to "open".
|
|
76
|
+
#
|
|
77
|
+
# @param url [String] the URL or file path to open
|
|
78
|
+
# @return [Process::Status] the process status of the system call
|
|
79
|
+
def browse_url(url)
|
|
80
|
+
browser = OllamaChat::EnvConfig::BROWSER? || "open"
|
|
81
|
+
system %{#{browser} #{Shellwords.escape(url)}}
|
|
82
|
+
$?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
self
|
|
86
|
+
end.register
|
|
@@ -34,6 +34,22 @@ module OllamaChat::Tools::Concern
|
|
|
34
34
|
self.class.register_name
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# The valid_json? method returns a proc that validates JSON data from a
|
|
38
|
+
# temporary file.
|
|
39
|
+
#
|
|
40
|
+
# @return [Proc] a proc that takes a temporary file and returns its JSON
|
|
41
|
+
# content or raises an error
|
|
42
|
+
def valid_json?
|
|
43
|
+
-> tmp {
|
|
44
|
+
if data = tmp.read.full?
|
|
45
|
+
JSON.parse(data)
|
|
46
|
+
return data
|
|
47
|
+
else
|
|
48
|
+
raise JSON::ParserError, 'require JSON data'
|
|
49
|
+
end
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
37
53
|
# The to_hash method converts the tool to a hash representation.
|
|
38
54
|
#
|
|
39
55
|
# @return [ Hash ] a hash representation of the tool
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# A tool for fetching endoflife.date product information.
|
|
2
|
-
#
|
|
3
|
-
# This tool allows the chat client to retrieve endoflife.date information
|
|
4
|
-
# for software products by ID. It integrates with the Ollama tool calling
|
|
5
|
-
# system to provide lifecycle and support information to the language model.
|
|
6
|
-
class OllamaChat::Tools::EndOfLife
|
|
7
|
-
include OllamaChat::Tools::Concern
|
|
8
|
-
|
|
9
|
-
def self.register_name = 'get_endoflife'
|
|
10
|
-
|
|
11
|
-
# Creates and returns a tool definition for getting endoflife information.
|
|
12
|
-
#
|
|
13
|
-
# This method constructs the function signature that describes what the tool
|
|
14
|
-
# does, its parameters, and required fields. The tool expects a product name
|
|
15
|
-
# parameter to be provided.
|
|
16
|
-
#
|
|
17
|
-
# @return [Ollama::Tool] a tool definition for retrieving endoflife information
|
|
18
|
-
def tool
|
|
19
|
-
Tool.new(
|
|
20
|
-
type: 'function',
|
|
21
|
-
function: Tool::Function.new(
|
|
22
|
-
name:,
|
|
23
|
-
description: 'Get the endoflife information for a product as JSON',
|
|
24
|
-
parameters: Tool::Function::Parameters.new(
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
product: Tool::Function::Parameters::Property.new(
|
|
28
|
-
type: 'string',
|
|
29
|
-
description: 'The product name to get endoflife information for'
|
|
30
|
-
),
|
|
31
|
-
},
|
|
32
|
-
required: %w[product]
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Executes the endoflife lookup operation.
|
|
39
|
-
#
|
|
40
|
-
# This method fetches endoflife data from the endoflife.date API using the
|
|
41
|
-
# provided product name. It handles the HTTP request, parses the JSON response,
|
|
42
|
-
# and returns the structured data.
|
|
43
|
-
#
|
|
44
|
-
# @param tool_call [Ollama::Tool::Call] the tool call object containing function details
|
|
45
|
-
# @param opts [Hash] additional options
|
|
46
|
-
# @option opts [ComplexConfig::Settings] :config the configuration object
|
|
47
|
-
# @return [Hash, String] the parsed endoflife data as a hash or an error message
|
|
48
|
-
# @raise [StandardError] if there's an issue with the HTTP request or JSON parsing
|
|
49
|
-
def execute(tool_call, **opts)
|
|
50
|
-
config = opts[:config]
|
|
51
|
-
product = tool_call.function.arguments.product
|
|
52
|
-
|
|
53
|
-
# Construct the URL for the endoflife API
|
|
54
|
-
url = config.tools.get_endoflife.url % { product: }
|
|
55
|
-
|
|
56
|
-
# Fetch the data from endoflife.date API
|
|
57
|
-
OllamaChat::Utils::Fetcher.get(
|
|
58
|
-
url,
|
|
59
|
-
headers: {
|
|
60
|
-
'Accept' => 'application/json',
|
|
61
|
-
'User-Agent' => OllamaChat::Chat.user_agent
|
|
62
|
-
},
|
|
63
|
-
debug: OllamaChat::EnvConfig::OLLAMA::CHAT::DEBUG
|
|
64
|
-
) do |tmp|
|
|
65
|
-
# Parse the JSON response
|
|
66
|
-
data = JSON.parse(tmp.read, object_class: JSON::GenericObject)
|
|
67
|
-
return data
|
|
68
|
-
end
|
|
69
|
-
rescue => e
|
|
70
|
-
"Failed to fetch endoflife data for #{product}: #{e.class}: #{e.message}"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
self
|
|
74
|
-
end.register
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# This tool allows the chat client to execute grep commands to search for
|
|
4
4
|
# patterns in files. It integrates with the Ollama tool calling system to
|
|
5
5
|
# provide file search capabilities within the language model's context.
|
|
6
|
-
class OllamaChat::Tools::
|
|
6
|
+
class OllamaChat::Tools::ExecuteGrep
|
|
7
7
|
include OllamaChat::Tools::Concern
|
|
8
8
|
|
|
9
9
|
def self.register_name = 'execute_grep'
|
|
@@ -34,6 +34,10 @@ class OllamaChat::Tools::Grep
|
|
|
34
34
|
max_results: Tool::Function::Parameters::Property.new(
|
|
35
35
|
type: 'integer',
|
|
36
36
|
description: 'Maximum number of matches to return (optional)'
|
|
37
|
+
),
|
|
38
|
+
ignore_case: Tool::Function::Parameters::Property.new(
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Matches ignore case if true, (default: false)'
|
|
37
41
|
)
|
|
38
42
|
},
|
|
39
43
|
required: %w[pattern]
|
|
@@ -54,20 +58,36 @@ class OllamaChat::Tools::Grep
|
|
|
54
58
|
# @param tool_call [OllamaChat::Tool::Call] The tool call with arguments
|
|
55
59
|
# @param opts [Hash] Additional options
|
|
56
60
|
# @option opts [Hash] :config Configuration options including tool settings
|
|
57
|
-
# @return [
|
|
58
|
-
# @raise [StandardError] If the command execution fails
|
|
61
|
+
# @return [String] The execution result with command and output as JSON string
|
|
59
62
|
def execute(tool_call, **opts)
|
|
60
63
|
config = opts[:config]
|
|
61
64
|
args = tool_call.function.arguments
|
|
62
65
|
pattern = Shellwords.escape(args.pattern)
|
|
63
66
|
path = Shellwords.escape(Pathname.new(args.path || '.').expand_path)
|
|
64
67
|
max_results = args.max_results || 100
|
|
65
|
-
|
|
68
|
+
ignore_case = args.ignore_case || false
|
|
69
|
+
cmd = eval_template(config, pattern, path, max_results, ignore_case)
|
|
66
70
|
result = OllamaChat::Utils::Fetcher.execute(cmd, &:read)
|
|
67
71
|
{ cmd:, result: }.to_json
|
|
68
72
|
rescue => e
|
|
69
73
|
{ error: e.class, message: e.message }.to_json
|
|
70
74
|
end
|
|
71
75
|
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# Evaluates a template string using the provided configuration and
|
|
79
|
+
# parameters.
|
|
80
|
+
#
|
|
81
|
+
# @param config [Object] the configuration object containing tool settings
|
|
82
|
+
# @param pattern [String] the regex pattern to search for
|
|
83
|
+
# @param path [String] the file or directory path to search in
|
|
84
|
+
# @param max_results [Integer] the maximum number of matches to return
|
|
85
|
+
# @param ignore_case [Boolean] whether to ignore case when searching
|
|
86
|
+
#
|
|
87
|
+
# @return [String] the evaluated template string with substituted variables
|
|
88
|
+
def eval_template(config, pattern, path, max_results, ignore_case)
|
|
89
|
+
eval('"%s"' % config.tools.execute_grep.cmd.chomp)
|
|
90
|
+
end
|
|
91
|
+
|
|
72
92
|
self
|
|
73
93
|
end.register
|