shared_tools 0.2.1 → 0.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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +594 -42
  4. data/lib/shared_tools/{ruby_llm/mcp → mcp}/github_mcp_server.rb +31 -24
  5. data/lib/shared_tools/mcp/imcp.rb +28 -0
  6. data/lib/shared_tools/mcp/tavily_mcp_server.rb +44 -0
  7. data/lib/shared_tools/mcp.rb +24 -0
  8. data/lib/shared_tools/tools/browser/base_driver.rb +64 -0
  9. data/lib/shared_tools/tools/browser/base_tool.rb +50 -0
  10. data/lib/shared_tools/tools/browser/click_tool.rb +54 -0
  11. data/lib/shared_tools/tools/browser/elements/element_grouper.rb +73 -0
  12. data/lib/shared_tools/tools/browser/elements/nearby_element_detector.rb +109 -0
  13. data/lib/shared_tools/tools/browser/formatters/action_formatter.rb +37 -0
  14. data/lib/shared_tools/tools/browser/formatters/data_entry_formatter.rb +135 -0
  15. data/lib/shared_tools/tools/browser/formatters/element_formatter.rb +52 -0
  16. data/lib/shared_tools/tools/browser/formatters/input_formatter.rb +59 -0
  17. data/lib/shared_tools/tools/browser/inspect_tool.rb +87 -0
  18. data/lib/shared_tools/tools/browser/inspect_utils.rb +51 -0
  19. data/lib/shared_tools/tools/browser/page_inspect/button_summarizer.rb +140 -0
  20. data/lib/shared_tools/tools/browser/page_inspect/form_summarizer.rb +98 -0
  21. data/lib/shared_tools/tools/browser/page_inspect/html_summarizer.rb +37 -0
  22. data/lib/shared_tools/tools/browser/page_inspect/link_summarizer.rb +103 -0
  23. data/lib/shared_tools/tools/browser/page_inspect_tool.rb +55 -0
  24. data/lib/shared_tools/tools/browser/page_screenshot_tool.rb +39 -0
  25. data/lib/shared_tools/tools/browser/selector_generator/base_selectors.rb +28 -0
  26. data/lib/shared_tools/tools/browser/selector_generator/contextual_selectors.rb +140 -0
  27. data/lib/shared_tools/tools/browser/selector_generator.rb +73 -0
  28. data/lib/shared_tools/tools/browser/selector_inspect_tool.rb +67 -0
  29. data/lib/shared_tools/tools/browser/text_field_area_set_tool.rb +45 -0
  30. data/lib/shared_tools/tools/browser/visit_tool.rb +43 -0
  31. data/lib/shared_tools/tools/browser/watir_driver.rb +132 -0
  32. data/lib/shared_tools/tools/browser.rb +27 -0
  33. data/lib/shared_tools/tools/browser_tool.rb +255 -0
  34. data/lib/shared_tools/tools/calculator_tool.rb +169 -0
  35. data/lib/shared_tools/tools/composite_analysis_tool.rb +520 -0
  36. data/lib/shared_tools/tools/computer/base_driver.rb +177 -0
  37. data/lib/shared_tools/tools/computer/mac_driver.rb +103 -0
  38. data/lib/shared_tools/tools/computer.rb +21 -0
  39. data/lib/shared_tools/tools/computer_tool.rb +207 -0
  40. data/lib/shared_tools/tools/data_science_kit.rb +707 -0
  41. data/lib/shared_tools/tools/database/base_driver.rb +17 -0
  42. data/lib/shared_tools/tools/database/postgres_driver.rb +30 -0
  43. data/lib/shared_tools/tools/database/sqlite_driver.rb +29 -0
  44. data/lib/shared_tools/tools/database.rb +9 -0
  45. data/lib/shared_tools/tools/database_query_tool.rb +313 -0
  46. data/lib/shared_tools/tools/database_tool.rb +99 -0
  47. data/lib/shared_tools/tools/devops_toolkit.rb +420 -0
  48. data/lib/shared_tools/tools/disk/base_driver.rb +91 -0
  49. data/lib/shared_tools/tools/disk/base_tool.rb +20 -0
  50. data/lib/shared_tools/tools/disk/directory_create_tool.rb +39 -0
  51. data/lib/shared_tools/tools/disk/directory_delete_tool.rb +39 -0
  52. data/lib/shared_tools/tools/disk/directory_list_tool.rb +37 -0
  53. data/lib/shared_tools/tools/disk/directory_move_tool.rb +40 -0
  54. data/lib/shared_tools/tools/disk/file_create_tool.rb +38 -0
  55. data/lib/shared_tools/tools/disk/file_delete_tool.rb +40 -0
  56. data/lib/shared_tools/tools/disk/file_move_tool.rb +43 -0
  57. data/lib/shared_tools/tools/disk/file_read_tool.rb +40 -0
  58. data/lib/shared_tools/tools/disk/file_replace_tool.rb +44 -0
  59. data/lib/shared_tools/tools/disk/file_write_tool.rb +40 -0
  60. data/lib/shared_tools/tools/disk/local_driver.rb +91 -0
  61. data/lib/shared_tools/tools/disk.rb +17 -0
  62. data/lib/shared_tools/tools/disk_tool.rb +132 -0
  63. data/lib/shared_tools/tools/doc/pdf_reader_tool.rb +79 -0
  64. data/lib/shared_tools/tools/doc.rb +8 -0
  65. data/lib/shared_tools/tools/doc_tool.rb +109 -0
  66. data/lib/shared_tools/tools/docker/base_tool.rb +56 -0
  67. data/lib/shared_tools/tools/docker/compose_run_tool.rb +77 -0
  68. data/lib/shared_tools/tools/docker.rb +8 -0
  69. data/lib/shared_tools/tools/error_handling_tool.rb +403 -0
  70. data/lib/shared_tools/tools/eval/python_eval_tool.rb +209 -0
  71. data/lib/shared_tools/tools/eval/ruby_eval_tool.rb +93 -0
  72. data/lib/shared_tools/tools/eval/shell_eval_tool.rb +64 -0
  73. data/lib/shared_tools/tools/eval.rb +10 -0
  74. data/lib/shared_tools/tools/eval_tool.rb +139 -0
  75. data/lib/shared_tools/tools/secure_tool_template.rb +353 -0
  76. data/lib/shared_tools/tools/version.rb +7 -0
  77. data/lib/shared_tools/tools/weather_tool.rb +197 -0
  78. data/lib/shared_tools/tools/workflow_manager_tool.rb +312 -0
  79. data/lib/shared_tools/tools.rb +16 -0
  80. data/lib/shared_tools/version.rb +1 -1
  81. data/lib/shared_tools.rb +9 -33
  82. metadata +189 -68
  83. data/lib/shared_tools/llm_rb/run_shell_command.rb +0 -23
  84. data/lib/shared_tools/llm_rb.rb +0 -9
  85. data/lib/shared_tools/omniai.rb +0 -9
  86. data/lib/shared_tools/raix/what_is_the_weather.rb +0 -18
  87. data/lib/shared_tools/raix.rb +0 -9
  88. data/lib/shared_tools/ruby_llm/edit_file.rb +0 -71
  89. data/lib/shared_tools/ruby_llm/incomplete/calculator_tool.rb +0 -70
  90. data/lib/shared_tools/ruby_llm/incomplete/composite_analysis_tool.rb +0 -89
  91. data/lib/shared_tools/ruby_llm/incomplete/data_science_kit.rb +0 -128
  92. data/lib/shared_tools/ruby_llm/incomplete/database_query_tool.rb +0 -100
  93. data/lib/shared_tools/ruby_llm/incomplete/devops_toolkit.rb +0 -112
  94. data/lib/shared_tools/ruby_llm/incomplete/error_handling_tool.rb +0 -109
  95. data/lib/shared_tools/ruby_llm/incomplete/secure_tool_template.rb +0 -117
  96. data/lib/shared_tools/ruby_llm/incomplete/weather_tool.rb +0 -110
  97. data/lib/shared_tools/ruby_llm/incomplete/workflow_manager_tool.rb +0 -145
  98. data/lib/shared_tools/ruby_llm/list_files.rb +0 -49
  99. data/lib/shared_tools/ruby_llm/mcp/imcp.rb +0 -33
  100. data/lib/shared_tools/ruby_llm/mcp.rb +0 -10
  101. data/lib/shared_tools/ruby_llm/pdf_page_reader.rb +0 -59
  102. data/lib/shared_tools/ruby_llm/python_eval.rb +0 -194
  103. data/lib/shared_tools/ruby_llm/read_file.rb +0 -40
  104. data/lib/shared_tools/ruby_llm/ruby_eval.rb +0 -77
  105. data/lib/shared_tools/ruby_llm/run_shell_command.rb +0 -49
  106. data/lib/shared_tools/ruby_llm.rb +0 -12
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharedTools
4
+ module Tools
5
+ module Computer
6
+ # A driver for interacting with a Mac. Be careful with using as it can perform actions on your computer!
7
+ class MacDriver < BaseDriver
8
+ def initialize(keyboard: MacOS.keyboard, mouse: MacOS.mouse, display: MacOS.display)
9
+ @keyboard = keyboard
10
+ @mouse = mouse
11
+ @display = display
12
+
13
+ super(display_width: display.wide, display_height: display.high, display_number: display.id)
14
+ end
15
+
16
+ # @param text [String]
17
+ def key(text:)
18
+ @keyboard.keys(text)
19
+ end
20
+
21
+ # @param text [String]
22
+ # @param duration [Integer]
23
+ def hold_key(text:, duration:)
24
+ raise NotImplementedError, "#{self.class.name}##{__method__} undefined"
25
+ end
26
+
27
+ # @return [Hash<{ x: Integer, y: Integer }>]
28
+ def mouse_position
29
+ position = @mouse.position
30
+ x = position.x
31
+ y = position.y
32
+
33
+ {
34
+ x:,
35
+ y:,
36
+ }
37
+ end
38
+
39
+ def mouse_move(coordinate:)
40
+ x = coordinate[:x]
41
+ y = coordinate[:y]
42
+
43
+ @mouse.move(x:, y:)
44
+ end
45
+
46
+ # @param coordinate [Hash<{ x: Integer, y: Integer }>]
47
+ # @param button [String] e.g. "left", "middle", "right"
48
+ def mouse_click(coordinate:, button:)
49
+ x = coordinate[:x]
50
+ y = coordinate[:y]
51
+
52
+ case button
53
+ when "left" then @mouse.left_click(x:, y:)
54
+ when "middle" then @mouse.middle_click(x:, y:)
55
+ when "right" then @mouse.right_click(x:, y:)
56
+ end
57
+ end
58
+
59
+ # @param coordinate [Hash<{ x: Integer, y: Integer }>]
60
+ def mouse_down(coordinate:, button: DEFAULT_MOUSE_BUTTON)
61
+ x = coordinate[:x]
62
+ y = coordinate[:y]
63
+
64
+ case button
65
+ when "left" then @mouse.left_down(x:, y:)
66
+ when "middle" then @mouse.middle_down(x:, y:)
67
+ when "right" then @mouse.right_down(x:, y:)
68
+ end
69
+ end
70
+
71
+ # @param coordinate [Hash<{ x: Integer, y: Integer }>]
72
+ # @param button [String] e.g. "left", "middle", "right"
73
+ def mouse_up(coordinate:, button: DEFAULT_MOUSE_BUTTON)
74
+ x = coordinate[:x]
75
+ y = coordinate[:y]
76
+
77
+ case button
78
+ when "left" then @mouse.left_up(x:, y:)
79
+ when "middle" then @mouse.middle_up(x:, y:)
80
+ when "right" then @mouse.right_up(x:, y:)
81
+ end
82
+ end
83
+
84
+ # @param text [String]
85
+ def type(text:)
86
+ @keyboard.type(text)
87
+ end
88
+
89
+ # @param amount [Integer]
90
+ # @param direction [String] e.g. "up", "down", "left", "right"
91
+ def scroll(amount:, direction:)
92
+ raise NotImplementedError, "#{self.class.name}##{__method__} undefined"
93
+ end
94
+
95
+ # @yield [file]
96
+ # @yieldparam file [File]
97
+ def screenshot(&)
98
+ @display.screenshot(&)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Collection loader for computer tools
4
+ # Usage: require 'shared_tools/tools/computer'
5
+
6
+ require 'shared_tools'
7
+
8
+ # Load driver base class
9
+ require_relative 'computer/base_driver'
10
+
11
+ # Try to load platform-specific dependencies and drivers
12
+ begin
13
+ if RUBY_PLATFORM.include?('darwin')
14
+ require 'macos'
15
+ require_relative 'computer/mac_driver'
16
+ end
17
+ rescue LoadError
18
+ # MacOS gem not installed, ComputerTool will require manual driver
19
+ end
20
+
21
+ require_relative 'computer_tool'
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../shared_tools'
4
+
5
+ module SharedTools
6
+ module Tools
7
+ # A tool for interacting with a computer. Be careful with using as it can perform actions on your computer!
8
+ #
9
+ # @example
10
+ # computer = SharedTools::Tools::ComputerTool.new
11
+ # computer.execute(action: 'mouse_position')
12
+ # computer.execute(action: 'type', text: 'Hello')
13
+ class ComputerTool < ::RubyLLM::Tool
14
+ def self.name = 'computer_tool'
15
+ description "A tool for interacting with a computer."
16
+
17
+ module Action
18
+ KEY = "key" # press a key
19
+ HOLD_KEY = "hold_key" # hold a key
20
+ MOUSE_POSITION = "mouse_position" # get the current (x, y) pixel coordinate of the cursor on the screen
21
+ MOUSE_MOVE = "mouse_move" # move the cursor to a specific (x, y) pixel coordinate on the screen
22
+ MOUSE_CLICK = "mouse_click" # click at a specific x / y coordinate
23
+ MOUSE_DOWN = "mouse_down" # press the mouse button down
24
+ MOUSE_DRAG = "mouse_drag" # drag the mouse to a specific x / y coordinate
25
+ MOUSE_UP = "mouse_up" # release the mouse button
26
+ MOUSE_DOUBLE_CLICK = "mouse_double_click" # double click at a specific x / y coordinate
27
+ MOUSE_TRIPLE_CLICK = "mouse_triple_click" # triple click at a specific x / y coordinate
28
+ TYPE = "type" # type a string
29
+ SCROLL = "scroll"
30
+ WAIT = "wait"
31
+ end
32
+
33
+ module MouseButton
34
+ LEFT = "left"
35
+ MIDDLE = "middle"
36
+ RIGHT = "right"
37
+ end
38
+
39
+ module ScrollDirection
40
+ UP = "up"
41
+ DOWN = "down"
42
+ LEFT = "left"
43
+ RIGHT = "right"
44
+ end
45
+
46
+ ACTIONS = [
47
+ Action::KEY,
48
+ Action::HOLD_KEY,
49
+ Action::MOUSE_POSITION,
50
+ Action::MOUSE_MOVE,
51
+ Action::MOUSE_CLICK,
52
+ Action::MOUSE_DOWN,
53
+ Action::MOUSE_DRAG,
54
+ Action::MOUSE_UP,
55
+ Action::TYPE,
56
+ Action::SCROLL,
57
+ Action::WAIT,
58
+ ].freeze
59
+
60
+ MOUSE_BUTTON_OPTIONS = [
61
+ MouseButton::LEFT,
62
+ MouseButton::MIDDLE,
63
+ MouseButton::RIGHT,
64
+ ].freeze
65
+
66
+ SCROLL_DIRECTION_OPTIONS = [
67
+ ScrollDirection::UP,
68
+ ScrollDirection::DOWN,
69
+ ScrollDirection::LEFT,
70
+ ScrollDirection::RIGHT,
71
+ ].freeze
72
+
73
+ params do
74
+ string :action, description: <<~TEXT.strip
75
+ Options:
76
+ * `#{Action::KEY}`: Press a single key / combination of keys on the keyboard:
77
+ - supports xdotool's `key` syntax (e.g. "alt+Tab", "Return", "ctrl+s", etc)
78
+ * `#{Action::HOLD_KEY}`: Hold down a key or multiple keys for a specified duration (in seconds):
79
+ - supports xdotool's `key` syntax (e.g. "alt+Tab", "Return", "ctrl+s", etc)
80
+ * `#{Action::MOUSE_POSITION}`: Get the current (x,y) pixel coordinate of the cursor on the screen.
81
+ * `#{Action::MOUSE_MOVE}`: Move the cursor to a specified (x,y) pixel coordinate on the screen.
82
+ * `#{Action::MOUSE_CLICK}`: Click the mouse button at the specified (x,y) pixel coordinate on the screen.
83
+ * `#{Action::MOUSE_DOUBLE_CLICK}`: Double click at the specified (x,y) pixel coordinate on the screen.
84
+ * `#{Action::MOUSE_TRIPLE_CLICK}`: Triple click at the specified (x,y) pixel coordinate on the screen.
85
+ * `#{Action::MOUSE_DOWN}`: Press the mouse button at the specified (x,y) pixel coordinate on the screen.
86
+ * `#{Action::MOUSE_DRAG}`: Click and drag the cursor to a specified (x, y) pixel coordinate on the screen.
87
+ * `#{Action::MOUSE_UP}`: Release the mouse button at the specified (x,y) pixel coordinate on the screen.
88
+ * `#{Action::TYPE}`: Type a string of text on the keyboard.
89
+ * `#{Action::SCROLL}`: Scroll the screen in a specified direction by a specified amount of clicks of the scroll wheel.
90
+ * `#{Action::WAIT}`: Wait for a specified duration (in seconds).
91
+ TEXT
92
+
93
+ object :coordinate, description: <<~TEXT.strip, required: false do
94
+ An (x,y) coordinate hash with integer values (e.g. {x: 100, y: 200}). Required for the following actions:
95
+ * `#{Action::MOUSE_MOVE}`
96
+ * `#{Action::MOUSE_CLICK}`
97
+ * `#{Action::MOUSE_DOWN}`
98
+ * `#{Action::MOUSE_DRAG}`
99
+ * `#{Action::MOUSE_UP}`
100
+ * `#{Action::MOUSE_DOUBLE_CLICK}`
101
+ * `#{Action::MOUSE_TRIPLE_CLICK}`
102
+ TEXT
103
+ integer :x, description: "The x pixel coordinate on the screen"
104
+ integer :y, description: "The y pixel coordinate on the screen"
105
+ end
106
+
107
+ string :text, description: <<~TEXT.strip, required: false
108
+ The text to type. Required for the following actions:
109
+ * `#{Action::KEY}`
110
+ * `#{Action::HOLD_KEY}`
111
+ * `#{Action::TYPE}`
112
+ TEXT
113
+
114
+ integer :duration, description: <<~TEXT.strip, required: false
115
+ A duration in seconds. Required for the following actions:
116
+ * `#{Action::HOLD_KEY}`
117
+ * `#{Action::WAIT}`
118
+ TEXT
119
+
120
+ string :mouse_button, description: <<~TEXT.strip, required: false
121
+ The mouse button to use. Required for the following actions:
122
+ * `#{Action::MOUSE_CLICK}`
123
+ * `#{Action::MOUSE_DOWN}`
124
+ * `#{Action::MOUSE_DRAG}`
125
+ * `#{Action::MOUSE_UP}`
126
+ * `#{Action::MOUSE_DOUBLE_CLICK}`
127
+ * `#{Action::MOUSE_TRIPLE_CLICK}`
128
+ TEXT
129
+
130
+ string :scroll_direction, description: <<~TEXT.strip, required: false
131
+ The direction to scroll. Required for the following actions:
132
+ * `#{Action::SCROLL}`
133
+ TEXT
134
+
135
+ integer :scroll_amount, description: <<~TEXT.strip, required: false
136
+ The amount of clicks to scroll. Required for the following actions:
137
+ * `#{Action::SCROLL}`
138
+ TEXT
139
+ end
140
+
141
+
142
+ # @param driver [Computer::BaseDriver] optional, will attempt to create platform-specific driver if not provided
143
+ # @param logger [Logger] optional logger
144
+ def initialize(driver: nil, logger: nil)
145
+ @logger = logger || RubyLLM.logger
146
+ @driver = driver || default_driver
147
+ end
148
+
149
+ # @param action [String]
150
+ # @param coordinate [Hash<{ width: Integer, height: Integer }>] the (x,y) coordinate
151
+ # @param text [String]
152
+ # @param duration [Integer] the duration in seconds
153
+ # @param mouse_button [String] e.g. "left", "middle", "right"
154
+ # @param scroll_direction [String] e.g. "up", "down", "left", "right"
155
+ # @param scroll_amount [Integer] the amount of clicks to scroll
156
+ def execute(
157
+ action:,
158
+ coordinate: nil,
159
+ text: nil,
160
+ duration: nil,
161
+ mouse_button: nil,
162
+ scroll_direction: nil,
163
+ scroll_amount: nil
164
+ )
165
+ @logger.info({
166
+ action:,
167
+ coordinate:,
168
+ text:,
169
+ duration:,
170
+ mouse_button:,
171
+ scroll_direction:,
172
+ scroll_amount:,
173
+ }.compact.map { |key, value| "#{key}=#{value.inspect}" }.join(" "))
174
+
175
+ # Convert coordinate hash keys to symbols if coordinate is provided
176
+ coordinate = coordinate&.transform_keys(&:to_sym)
177
+
178
+ case action
179
+ when Action::KEY then @driver.key(text:)
180
+ when Action::HOLD_KEY then @driver.hold_key(text:, duration:)
181
+ when Action::MOUSE_POSITION then @driver.mouse_position
182
+ when Action::MOUSE_MOVE then @driver.mouse_move(coordinate:)
183
+ when Action::MOUSE_CLICK then @driver.mouse_click(coordinate:, button: mouse_button)
184
+ when Action::MOUSE_DOUBLE_CLICK then @driver.mouse_double_click(coordinate:, button: mouse_button)
185
+ when Action::MOUSE_TRIPLE_CLICK then @driver.mouse_triple_click(coordinate:, button: mouse_button)
186
+ when Action::MOUSE_DOWN then @driver.mouse_down(coordinate:, button: mouse_button)
187
+ when Action::MOUSE_UP then @driver.mouse_up(coordinate:, button: mouse_button)
188
+ when Action::MOUSE_DRAG then @driver.mouse_drag(coordinate:, button: mouse_button)
189
+ when Action::TYPE then @driver.type(text:)
190
+ when Action::SCROLL then @driver.scroll(amount: scroll_amount, direction: scroll_direction)
191
+ when Action::WAIT then @driver.wait(duration:)
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ # @return [Computer::BaseDriver]
198
+ def default_driver
199
+ if RUBY_PLATFORM.include?('darwin') && defined?(MacOS)
200
+ Computer::MacDriver.new
201
+ else
202
+ raise LoadError, "ComputerTool requires a platform-specific driver. Either install the required gem for your platform or pass a driver: parameter"
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end