ox-ai-workers 0.5.4 → 0.5.5.1
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 +7 -0
- data/README.md +26 -5
- data/exe/start +4 -0
- data/lib/ox-ai-workers.rb +3 -2
- data/lib/oxaiworkers/assistant/coder.rb +2 -0
- data/lib/oxaiworkers/assistant/localizer.rb +2 -0
- data/lib/oxaiworkers/assistant/module_base.rb +2 -0
- data/lib/oxaiworkers/assistant/sysop.rb +3 -1
- data/lib/oxaiworkers/iterator.rb +43 -24
- data/lib/oxaiworkers/load_i18n.rb +15 -0
- data/lib/oxaiworkers/tool/database.rb +27 -22
- data/lib/oxaiworkers/tool/eval.rb +17 -10
- data/lib/oxaiworkers/tool/file_system.rb +31 -26
- data/lib/oxaiworkers/tool_definition.rb +10 -2
- data/lib/oxaiworkers/version.rb +1 -1
- data/template/my_assistant.rb +6 -0
- data/template/start +4 -0
- data/template/tools/my_tool.rb +13 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd23611eb845a63cc6bd0142480645aff071bd569e748cb5aa394f461e360073
|
4
|
+
data.tar.gz: 1b8049ea7ed0a74ddf350bce0e7f9a7b88e0feb16626e7c6eb8891b55fec3995
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b91a2846312a4403eb059f075f76ea39f18a1706b85db6bac1b053841e09a5ba901f11ab4c36397162174b9f696aca51b82ea714644a581409957a8ab5be2bbe
|
7
|
+
data.tar.gz: c725fab2dcfaef342000918d9f4a21feceb2196191de27b7d6bf528af41e6db761ceefd439c7bbd3dbc0bb546fb50016b788c22be802f566e61a8f36d114838f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.5.5] - 2024-08-02
|
4
|
+
|
5
|
+
- Added `only` for Tools
|
6
|
+
- Addded `locale` for `Iterator` and `Assistant`
|
7
|
+
|
8
|
+
## [0.5.4] - 2024-08-01
|
9
|
+
|
3
10
|
- def_except and def_only for `Iterator`
|
4
11
|
- Renamed on_pack_history to on_summarize
|
5
12
|
- Renamed all "pack_history" to "summarize"
|
data/README.md
CHANGED
@@ -63,7 +63,7 @@ worker = OxAiWorkers::Request.new(
|
|
63
63
|
temperature: 0.7 )
|
64
64
|
|
65
65
|
# Initialize a tool
|
66
|
-
my_tool = OxAiWorkers::Tool::Eval.new()
|
66
|
+
my_tool = OxAiWorkers::Tool::Eval.new(only: :sh)
|
67
67
|
|
68
68
|
# Create an iterator with the worker and tool
|
69
69
|
iterator = OxAiWorkers::Iterator.new(
|
@@ -86,9 +86,9 @@ For a more robust setup, you can configure the gem with your API keys, for examp
|
|
86
86
|
OxAiWorkers.configure do |config|
|
87
87
|
config.access_token = ENV.fetch("OPENAI")
|
88
88
|
config.model = "gpt-4o"
|
89
|
-
config.max_tokens = 4096
|
90
|
-
config.temperature = 0.7
|
91
|
-
config.auto_execute = true
|
89
|
+
config.max_tokens = 4096 # Default
|
90
|
+
config.temperature = 0.7 # Default
|
91
|
+
config.auto_execute = true # Default
|
92
92
|
end
|
93
93
|
```
|
94
94
|
|
@@ -97,16 +97,27 @@ Then you can create an assistant like this:
|
|
97
97
|
```ruby
|
98
98
|
assistant = OxAiWorkers::Assistant::Sysop.new()
|
99
99
|
assistant.task = "Remove all cron jobs."
|
100
|
+
# assistant.execute # if auto_execute is false
|
100
101
|
|
101
102
|
# Provide a response to the assistant's question
|
102
103
|
assistant.add_response("blah-blah-blah")
|
104
|
+
# assistant.execute # if auto_execute is false
|
105
|
+
```
|
106
|
+
|
107
|
+
Besides, you can create assistants with different locales
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
I18n.with_locale(:en) { @sysop_en = OxAiWorkers::Assistant::Sysop.new() }
|
111
|
+
|
112
|
+
# Assign tasks and responses in different languages
|
113
|
+
@sysop_en.task = "Remove all cron jobs."
|
103
114
|
```
|
104
115
|
|
105
116
|
Or you can create a lower-level iterator for more control:
|
106
117
|
|
107
118
|
```ruby
|
108
119
|
my_worker = OxAiWorkers::Request.new
|
109
|
-
my_tool = OxAiWorkers::Tool::Eval.new
|
120
|
+
my_tool = OxAiWorkers::Tool::Eval.new(only: [:sh])
|
110
121
|
|
111
122
|
iterator = OxAiWorkers::Iterator.new(
|
112
123
|
worker: my_worker,
|
@@ -123,6 +134,12 @@ iterator.add_task("Show files in current directory.")
|
|
123
134
|
iterator.add_task("linux")
|
124
135
|
```
|
125
136
|
|
137
|
+
If `auto_execute` is set to false in the configuration, don't forget to manually execute the iterator or assistant.
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
iterator.execute # if auto_execute is false
|
141
|
+
```
|
142
|
+
|
126
143
|
This way, you have the flexibility to choose between a higher-level assistant for simplicity or a lower-level iterator for finer control over the tasks and tools used.
|
127
144
|
|
128
145
|
### Advanced instructions for your Assistant
|
@@ -135,10 +152,14 @@ steps << 'Step 3. Call the necessary functions one after another until the desir
|
|
135
152
|
steps << "Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the #{OxAiWorkers::Iterator.full_function_name(:summarize)} function."
|
136
153
|
steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
|
137
154
|
|
155
|
+
# To retain the locale if you have assistants in different languages in your project.
|
156
|
+
store_locale # Optional
|
157
|
+
|
138
158
|
@iterator = OxAiWorkers::Iterator.new(
|
139
159
|
worker: init_worker(delayed: delayed, model: model),
|
140
160
|
role: 'You are a software agent inside my computer',
|
141
161
|
tools: [MyTool.new],
|
162
|
+
locale: @locale || I18n.locale,
|
142
163
|
steps: steps,
|
143
164
|
# def_except: [:summarize], # It's except steps with that functions
|
144
165
|
# def_only: [:inner_monologue, :outer_voice], # Use it only with your steps
|
data/exe/start
CHANGED
data/lib/ox-ai-workers.rb
CHANGED
@@ -11,13 +11,14 @@ require_relative 'oxaiworkers/version'
|
|
11
11
|
require_relative 'oxaiworkers/contextual_logger'
|
12
12
|
require_relative 'oxaiworkers/load_i18n'
|
13
13
|
require_relative 'oxaiworkers/present_compat'
|
14
|
+
require_relative 'oxaiworkers/tool_definition'
|
15
|
+
require_relative 'oxaiworkers/dependency_helper'
|
16
|
+
|
14
17
|
require_relative 'oxaiworkers/module_request'
|
15
18
|
require_relative 'oxaiworkers/state_helper'
|
16
19
|
require_relative 'oxaiworkers/state_batch'
|
17
20
|
require_relative 'oxaiworkers/state_tools'
|
18
|
-
require_relative 'oxaiworkers/tool_definition'
|
19
21
|
require_relative 'oxaiworkers/delayed_request'
|
20
|
-
require_relative 'oxaiworkers/dependency_helper'
|
21
22
|
require_relative 'oxaiworkers/iterator'
|
22
23
|
require_relative 'oxaiworkers/request'
|
23
24
|
|
@@ -6,10 +6,12 @@ module OxAiWorkers
|
|
6
6
|
include OxAiWorkers::Assistant::ModuleBase
|
7
7
|
|
8
8
|
def initialize(delayed: false, model: nil, language: 'ruby')
|
9
|
+
store_locale
|
9
10
|
@iterator = Iterator.new(
|
10
11
|
worker: init_worker(delayed: delayed, model: model),
|
11
12
|
role: format(I18n.t('oxaiworkers.assistant.coder.role'), language),
|
12
13
|
tools: [Tool::Eval.new, Tool::FileSystem.new],
|
14
|
+
locale: @locale,
|
13
15
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
16
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
17
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
@@ -6,10 +6,12 @@ module OxAiWorkers
|
|
6
6
|
include OxAiWorkers::Assistant::ModuleBase
|
7
7
|
|
8
8
|
def initialize(delayed: false, model: nil, language: 'русский', locale: :ru, source: 'english')
|
9
|
+
store_locale
|
9
10
|
@iterator = Iterator.new(
|
10
11
|
worker: init_worker(delayed: delayed, model: model),
|
11
12
|
role: format(I18n.t('oxaiworkers.assistant.localizer.role'), language),
|
12
13
|
tools: [Tool::Eval.new, Tool::FileSystem.new],
|
14
|
+
locale: @locale,
|
13
15
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
16
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
17
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
@@ -6,10 +6,12 @@ module OxAiWorkers
|
|
6
6
|
include OxAiWorkers::Assistant::ModuleBase
|
7
7
|
|
8
8
|
def initialize(delayed: false, model: nil)
|
9
|
+
store_locale
|
9
10
|
@iterator = Iterator.new(
|
10
11
|
worker: init_worker(delayed: delayed, model: model),
|
11
12
|
role: I18n.t('oxaiworkers.assistant.sysop.role'),
|
12
|
-
tools: [Tool::Eval.new],
|
13
|
+
tools: [Tool::Eval.new(only: :sh), Tool::FileSystem.new(only: %i[read_file write_to_file])],
|
14
|
+
locale: @locale,
|
13
15
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
16
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
17
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
data/lib/oxaiworkers/iterator.rb
CHANGED
@@ -4,37 +4,45 @@ module OxAiWorkers
|
|
4
4
|
class Iterator < OxAiWorkers::StateTools
|
5
5
|
ITERATOR_FUNCTIONS = %i[inner_monologue outer_voice action_request summarize].freeze
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :on_summarize, :def_except, :def_only
|
7
|
+
include OxAiWorkers::ToolDefinition
|
8
|
+
include OxAiWorkers::LoadI18n
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
required: true
|
14
|
-
end
|
10
|
+
attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones,
|
11
|
+
:on_inner_monologue, :on_outer_voice, :on_action_request, :on_summarize, :def_except, :def_only
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
13
|
+
def initialize(worker:, role: nil, tools: [], on_inner_monologue: nil, on_outer_voice: nil, on_action_request: nil,
|
14
|
+
on_summarize: nil, steps: nil, def_except: [], def_only: nil, locale: nil)
|
19
15
|
|
20
|
-
|
21
|
-
property :action, type: 'string', description: I18n.t('oxaiworkers.iterator.action_request.action'),
|
22
|
-
required: true
|
23
|
-
end
|
16
|
+
@locale = locale || I18n.locale
|
24
17
|
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
with_locale do
|
19
|
+
define_function :inner_monologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
|
20
|
+
property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
|
21
|
+
required: true
|
22
|
+
end
|
23
|
+
|
24
|
+
define_function :outer_voice, description: I18n.t('oxaiworkers.iterator.outer_voice.description') do
|
25
|
+
property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.outer_voice.text'), required: true
|
26
|
+
end
|
27
|
+
|
28
|
+
define_function :action_request, description: I18n.t('oxaiworkers.iterator.action_request.description') do
|
29
|
+
property :action, type: 'string', description: I18n.t('oxaiworkers.iterator.action_request.action'),
|
30
|
+
required: true
|
31
|
+
end
|
32
|
+
|
33
|
+
define_function :summarize, description: I18n.t('oxaiworkers.iterator.summarize.description') do
|
34
|
+
property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.summarize.text'), required: true
|
35
|
+
end
|
36
|
+
|
37
|
+
@monologue = steps || I18n.t('oxaiworkers.iterator.monologue')
|
38
|
+
end
|
28
39
|
|
29
|
-
def initialize(worker:, role: nil, tools: [], on_inner_monologue: nil, on_outer_voice: nil, on_action_request: nil,
|
30
|
-
on_summarize: nil, steps: nil, def_except: [], def_only: nil)
|
31
40
|
@worker = worker
|
32
41
|
@tools = tools
|
33
42
|
@role = role
|
34
43
|
@context = []
|
35
44
|
@def_only = def_only || ITERATOR_FUNCTIONS
|
36
45
|
@def_except = def_except
|
37
|
-
@monologue = steps || I18n.t('oxaiworkers.iterator.monologue')
|
38
46
|
|
39
47
|
@on_inner_monologue = on_inner_monologue
|
40
48
|
@on_outer_voice = on_outer_voice
|
@@ -82,7 +90,9 @@ module OxAiWorkers
|
|
82
90
|
def summarize(text:)
|
83
91
|
@milestones << text.to_s
|
84
92
|
@messages = []
|
85
|
-
|
93
|
+
with_locale do
|
94
|
+
@queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.summarize.result') }
|
95
|
+
end
|
86
96
|
@worker.finish
|
87
97
|
rebuild_worker
|
88
98
|
complete! if can_complete?
|
@@ -103,8 +113,16 @@ module OxAiWorkers
|
|
103
113
|
@tasks.each { |task| @worker.append(role: :user, content: task) }
|
104
114
|
@milestones.each { |milestone| @worker.append(role: :assistant, content: milestone) }
|
105
115
|
@worker.append(messages: @messages)
|
106
|
-
@worker.tools =
|
107
|
-
|
116
|
+
@worker.tools = function_schemas.to_openai_format(only: available_defs)
|
117
|
+
return unless @tools.present?
|
118
|
+
|
119
|
+
@worker.tools += @tools.map do |tool|
|
120
|
+
if tool.respond_to?(:function_schemas)
|
121
|
+
tool.function_schemas.to_openai_format
|
122
|
+
else
|
123
|
+
tool.class.function_schemas.to_openai_format
|
124
|
+
end
|
125
|
+
end.flatten
|
108
126
|
end
|
109
127
|
|
110
128
|
def available_defs
|
@@ -138,7 +156,8 @@ module OxAiWorkers
|
|
138
156
|
@queue << { role: :assistant, content: @worker.tool_calls_raw.to_s }
|
139
157
|
@worker.tool_calls.each do |external_call|
|
140
158
|
tool = ([self] + @tools).select do |t|
|
141
|
-
|
159
|
+
tool_name = t.respond_to?(:tool_name) ? t.tool_name : t.class.tool_name
|
160
|
+
tool_name == external_call[:class] && t.respond_to?(external_call[:name])
|
142
161
|
end.first
|
143
162
|
unless tool.nil?
|
144
163
|
out = tool.send(external_call[:name], **external_call[:args])
|
@@ -2,3 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'i18n'
|
4
4
|
I18n.load_path += Dir["#{File.expand_path('../../locales', __dir__)}/*.yml"]
|
5
|
+
|
6
|
+
module OxAiWorkers
|
7
|
+
module LoadI18n
|
8
|
+
attr_accessor :locale
|
9
|
+
|
10
|
+
def with_locale(&action)
|
11
|
+
# locale = respond_to?(:locale) ? self.locale : OxAiWorkers.configuration.locale
|
12
|
+
I18n.with_locale(@locale, &action)
|
13
|
+
end
|
14
|
+
|
15
|
+
def store_locale
|
16
|
+
@locale = I18n.locale
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -10,28 +10,9 @@ module OxAiWorkers
|
|
10
10
|
# database = OxAiWorkers::Tool::Database.new(connection_string: "postgres://user:password@localhost:5432/db_name")
|
11
11
|
#
|
12
12
|
class Database
|
13
|
-
|
13
|
+
include OxAiWorkers::ToolDefinition
|
14
14
|
include OxAiWorkers::DependencyHelper
|
15
|
-
|
16
|
-
define_function :list_tables,
|
17
|
-
description: I18n.t('oxaiworkers.tool.database_tool.list_tables.description')
|
18
|
-
|
19
|
-
define_function :describe_tables,
|
20
|
-
description: I18n.t('oxaiworkers.tool.database_tool.describe_tables.description') do
|
21
|
-
property :tables, type: 'string',
|
22
|
-
description: I18n.t('oxaiworkers.tool.database_tool.describe_tables.tables'),
|
23
|
-
required: true
|
24
|
-
end
|
25
|
-
|
26
|
-
define_function :dump_schema,
|
27
|
-
description: I18n.t('oxaiworkers.tool.database_tool.dump_schema.description')
|
28
|
-
|
29
|
-
define_function :execute,
|
30
|
-
description: I18n.t('oxaiworkers.tool.database_tool.execute.description') do
|
31
|
-
property :input, type: 'string',
|
32
|
-
description: I18n.t('oxaiworkers.tool.database_tool.execute.input'),
|
33
|
-
required: true
|
34
|
-
end
|
15
|
+
include OxAiWorkers::LoadI18n
|
35
16
|
|
36
17
|
attr_reader :db, :requested_tables, :excluded_tables
|
37
18
|
|
@@ -41,11 +22,35 @@ module OxAiWorkers
|
|
41
22
|
# @param tables [Array<Symbol>] The tables to use. Will use all if empty.
|
42
23
|
# @param except_tables [Array<Symbol>] The tables to exclude. Will exclude none if empty.
|
43
24
|
# @return [Database] Database object
|
44
|
-
def initialize(connection_string:, tables: [], exclude_tables: [])
|
25
|
+
def initialize(connection_string:, tables: [], exclude_tables: [], only: nil)
|
45
26
|
depends_on 'sequel'
|
46
27
|
|
47
28
|
raise StandardError, 'connection_string parameter cannot be blank' if connection_string.empty?
|
48
29
|
|
30
|
+
store_locale
|
31
|
+
|
32
|
+
init_white_list_with only
|
33
|
+
|
34
|
+
define_function :list_tables,
|
35
|
+
description: I18n.t('oxaiworkers.tool.database_tool.list_tables.description')
|
36
|
+
|
37
|
+
define_function :describe_tables,
|
38
|
+
description: I18n.t('oxaiworkers.tool.database_tool.describe_tables.description') do
|
39
|
+
property :tables, type: 'string',
|
40
|
+
description: I18n.t('oxaiworkers.tool.database_tool.describe_tables.tables'),
|
41
|
+
required: true
|
42
|
+
end
|
43
|
+
|
44
|
+
define_function :dump_schema,
|
45
|
+
description: I18n.t('oxaiworkers.tool.database_tool.dump_schema.description')
|
46
|
+
|
47
|
+
define_function :execute,
|
48
|
+
description: I18n.t('oxaiworkers.tool.database_tool.execute.description') do
|
49
|
+
property :input, type: 'string',
|
50
|
+
description: I18n.t('oxaiworkers.tool.database_tool.execute.input'),
|
51
|
+
required: true
|
52
|
+
end
|
53
|
+
|
49
54
|
@db = Sequel.connect(connection_string)
|
50
55
|
@requested_tables = tables
|
51
56
|
@excluded_tables = exclude_tables
|
@@ -5,21 +5,28 @@ require 'open3'
|
|
5
5
|
module OxAiWorkers
|
6
6
|
module Tool
|
7
7
|
class Eval
|
8
|
-
|
8
|
+
include OxAiWorkers::ToolDefinition
|
9
9
|
include OxAiWorkers::DependencyHelper
|
10
|
+
include OxAiWorkers::LoadI18n
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
# end
|
12
|
+
def initialize(only: nil)
|
13
|
+
store_locale
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
init_white_list_with only
|
16
|
+
|
17
|
+
define_function :ruby, description: I18n.t('oxaiworkers.tool.eval.ruby.description') do
|
18
|
+
property :input, type: 'string', description: I18n.t('oxaiworkers.tool.eval.ruby.input'), required: true
|
19
|
+
end
|
20
|
+
|
21
|
+
define_function :sh, description: I18n.t('oxaiworkers.tool.eval.sh.description') do
|
22
|
+
property :input, type: 'string', description: I18n.t('oxaiworkers.tool.eval.sh.input'), required: true
|
23
|
+
end
|
17
24
|
end
|
18
25
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
def ruby(input:)
|
27
|
+
puts "Executing ruby: \"#{input}\"".colorize(:red)
|
28
|
+
eval(input)
|
29
|
+
end
|
23
30
|
|
24
31
|
def sh(input:)
|
25
32
|
OxAiWorkers.logger.info("Executing sh: \"#{input}\"", for: self.class)
|
@@ -11,30 +11,35 @@ module OxAiWorkers
|
|
11
11
|
# file_system = OxAiWorkers::Tool::FileSystem.new
|
12
12
|
#
|
13
13
|
class FileSystem
|
14
|
-
|
14
|
+
include OxAiWorkers::ToolDefinition
|
15
15
|
include OxAiWorkers::DependencyHelper
|
16
|
+
include OxAiWorkers::LoadI18n
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
property :directory_path, type: 'string',
|
20
|
-
description: I18n.t('oxaiworkers.tool.file_system.list_directory.directory_path'),
|
21
|
-
required: true
|
22
|
-
end
|
18
|
+
def initialize(only: nil)
|
19
|
+
depends_on 'ptools'
|
23
20
|
|
24
|
-
|
25
|
-
property :file_path, type: 'string', description: I18n.t('oxaiworkers.tool.file_system.read_file.file_path'),
|
26
|
-
required: true
|
27
|
-
end
|
21
|
+
store_locale
|
28
22
|
|
29
|
-
|
30
|
-
property :file_path, type: 'string',
|
31
|
-
description: I18n.t('oxaiworkers.tool.file_system.write_to_file.file_path'), required: true
|
32
|
-
property :content, type: 'string', description: I18n.t('oxaiworkers.tool.file_system.write_to_file.content'),
|
33
|
-
required: true
|
34
|
-
end
|
23
|
+
init_white_list_with only
|
35
24
|
|
36
|
-
|
37
|
-
|
25
|
+
define_function :list_directory,
|
26
|
+
description: I18n.t('oxaiworkers.tool.file_system.list_directory.description') do
|
27
|
+
property :directory_path, type: 'string',
|
28
|
+
description: I18n.t('oxaiworkers.tool.file_system.list_directory.directory_path'),
|
29
|
+
required: true
|
30
|
+
end
|
31
|
+
|
32
|
+
define_function :read_file, description: I18n.t('oxaiworkers.tool.file_system.read_file.description') do
|
33
|
+
property :file_path, type: 'string', description: I18n.t('oxaiworkers.tool.file_system.read_file.file_path'),
|
34
|
+
required: true
|
35
|
+
end
|
36
|
+
|
37
|
+
define_function :write_to_file, description: I18n.t('oxaiworkers.tool.file_system.write_to_file.description') do
|
38
|
+
property :file_path, type: 'string',
|
39
|
+
description: I18n.t('oxaiworkers.tool.file_system.write_to_file.file_path'), required: true
|
40
|
+
property :content, type: 'string', description: I18n.t('oxaiworkers.tool.file_system.write_to_file.content'),
|
41
|
+
required: true
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def list_directory(directory_path:)
|
@@ -42,31 +47,31 @@ module OxAiWorkers
|
|
42
47
|
list = Dir.entries(directory_path)
|
43
48
|
list.delete_if { |f| f.start_with?('.') }
|
44
49
|
if list.present?
|
45
|
-
"Contents of directory \"#{directory_path}\":\n #{list.join("\n")}"
|
50
|
+
with_locale { "Contents of directory \"#{directory_path}\":\n #{list.join("\n")}" }
|
46
51
|
else
|
47
|
-
"Directory is empty: #{directory_path}"
|
52
|
+
with_locale { "Directory is empty: #{directory_path}" }
|
48
53
|
end
|
49
54
|
rescue Errno::ENOENT
|
50
|
-
"No such directory: #{directory_path}"
|
55
|
+
with_locale { "No such directory: #{directory_path}" }
|
51
56
|
end
|
52
57
|
|
53
58
|
def read_file(file_path:)
|
54
59
|
OxAiWorkers.logger.info("Reading file: #{file_path}", for: self.class)
|
55
60
|
if File.binary?(file_path)
|
56
|
-
"File is binary: #{file_path}"
|
61
|
+
with_locale { "File is binary: #{file_path}" }
|
57
62
|
else
|
58
63
|
File.read(file_path).to_s
|
59
64
|
end
|
60
65
|
rescue Errno::ENOENT
|
61
|
-
"No such file: #{file_path}"
|
66
|
+
with_locale { "No such file: #{file_path}" }
|
62
67
|
end
|
63
68
|
|
64
69
|
def write_to_file(file_path:, content:)
|
65
70
|
OxAiWorkers.logger.info("Writing to file: #{file_path}", for: self.class)
|
66
71
|
File.write(file_path, content)
|
67
|
-
"Content was successfully written to the file: #{file_path}"
|
72
|
+
with_locale { "Content was successfully written to the file: #{file_path}" }
|
68
73
|
rescue Errno::EACCES
|
69
|
-
"Permission denied: #{file_path}"
|
74
|
+
with_locale { "Permission denied: #{file_path}" }
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
@@ -37,13 +37,21 @@ require "json"
|
|
37
37
|
# end
|
38
38
|
#
|
39
39
|
module OxAiWorkers::ToolDefinition
|
40
|
+
attr_accessor :white_list
|
41
|
+
|
42
|
+
def init_white_list_with only
|
43
|
+
@white_list = only.is_a?(Array) ? only : [only]
|
44
|
+
end
|
45
|
+
|
40
46
|
# Defines a function for the tool
|
41
47
|
#
|
42
48
|
# @param method_name [Symbol] Name of the method to define
|
43
49
|
# @param description [String] Description of the function
|
44
50
|
# @yield Block that defines the parameters for the function
|
45
51
|
def define_function(method_name, description:, &)
|
46
|
-
|
52
|
+
if @white_list.nil? || @white_list == method_name || @white_list.include?(method_name)
|
53
|
+
function_schemas.add_function(method_name:, description:, &)
|
54
|
+
end
|
47
55
|
end
|
48
56
|
|
49
57
|
# Returns the FunctionSchemas instance for this tool
|
@@ -57,7 +65,7 @@ module OxAiWorkers::ToolDefinition
|
|
57
65
|
#
|
58
66
|
# @return [String] The snake_case version of the class name
|
59
67
|
def tool_name
|
60
|
-
@tool_name ||= name
|
68
|
+
@tool_name ||= (self.respond_to?(:name) ? name : self.class.name)
|
61
69
|
.gsub("::", "_")
|
62
70
|
.gsub(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
|
63
71
|
.downcase
|
data/lib/oxaiworkers/version.rb
CHANGED
data/template/my_assistant.rb
CHANGED
@@ -15,11 +15,17 @@ class MyAssistant
|
|
15
15
|
# steps << "Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the #{OxAiWorkers::Iterator.full_function_name(:summarize)} function."
|
16
16
|
# steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
|
17
17
|
|
18
|
+
# To retain the locale if you have assistants in different languages in your project.
|
19
|
+
# store_locale # Optional
|
20
|
+
|
18
21
|
@iterator = OxAiWorkers::Iterator.new(
|
19
22
|
worker: init_worker(delayed: delayed, model: model),
|
20
23
|
role: 'You are a software agent inside my computer',
|
21
24
|
tools: [MyTool.new],
|
25
|
+
# locale: @locale || I18n.locale,
|
22
26
|
# steps: steps,
|
27
|
+
# def_except: [:summarize], # It's except steps with that functions
|
28
|
+
# def_only: [:inner_monologue, :outer_voice], # Use it only with your steps
|
23
29
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
24
30
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
25
31
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
data/template/start
CHANGED
@@ -20,6 +20,7 @@ puts "OxAiWorkers #{OxAiWorkers::VERSION}"
|
|
20
20
|
OxAiWorkers.configure do |config|
|
21
21
|
config.access_token = ENV.fetch('OPENAI')
|
22
22
|
config.model = 'gpt-4o-mini'
|
23
|
+
# config.auto_execute = false
|
23
24
|
end
|
24
25
|
|
25
26
|
# OxAiWorkers.logger.level = :debug
|
@@ -28,4 +29,7 @@ end
|
|
28
29
|
@assistant = MyAssistant.new
|
29
30
|
@assistant.task = '2 + 2 is ?'
|
30
31
|
|
32
|
+
# Uncomment this if auto_execute is false
|
33
|
+
# @assistant.execute
|
34
|
+
|
31
35
|
IRB.start(__FILE__)
|
data/template/tools/my_tool.rb
CHANGED
@@ -1,13 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class MyTool
|
4
|
-
extend OxAiWorkers::ToolDefinition
|
5
|
-
include OxAiWorkers::DependencyHelper
|
4
|
+
extend OxAiWorkers::ToolDefinition # (!) extend
|
6
5
|
|
7
6
|
define_function :sh, description: 'Execute a sh command and get the result (stdout + stderr)' do
|
8
7
|
property :input, type: 'string', description: 'Source command', required: true
|
9
8
|
end
|
10
9
|
|
10
|
+
# Alternative implementation if you need to filter functions during initialization.
|
11
|
+
# include OxAiWorkers::ToolDefinition # (!) include
|
12
|
+
# include OxAiWorkers::LoadI18n # to support multiple languages
|
13
|
+
#
|
14
|
+
# def initialize(only: nil)
|
15
|
+
# store_locale # To retain the locale if you have MyTool in different languages.
|
16
|
+
# init_white_list_with only
|
17
|
+
# define_function :sh, description: I18n.t('Execute a sh command and get the result (stdout + stderr)') do
|
18
|
+
# property :input, type: 'string', description: I18n.t('Source command'), required: true
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
11
22
|
def sh(input:)
|
12
23
|
OxAiWorkers.logger.info("Executing sh: \"#{input}\"", for: self.class)
|
13
24
|
stdout_and_stderr_s, = Open3.capture2e(input)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ox-ai-workers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Smolev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|