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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67dfa0fc5c5cb3c3c223615ec1386324b1a71fdc38d90db9b78c6c94f0136add
4
- data.tar.gz: 555689bc0e7d83a854f0614d13aed065b2634bdf4501a9aa2025fc40736db398
3
+ metadata.gz: cd23611eb845a63cc6bd0142480645aff071bd569e748cb5aa394f461e360073
4
+ data.tar.gz: 1b8049ea7ed0a74ddf350bce0e7f9a7b88e0feb16626e7c6eb8891b55fec3995
5
5
  SHA512:
6
- metadata.gz: 374c51ea659b98605131b46e1ffbffbfc3ec5d9d6c5718f64952e630e2a14adec56412776eadc4c074ead54c8197fc0195b9590dd76d0737dd7fff347b5ab236
7
- data.tar.gz: 21714fc9c30d3159c756ce53840a598c163bca8547e7425e86ffd6ef86c78b5c3563c3a5b5d415420d3141c45d68c87f289d55436796bfa17cc83e4a4b963ab9
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
@@ -17,4 +17,8 @@ end
17
17
 
18
18
  @assistant = OxAiWorkers::Assistant::Sysop.new
19
19
 
20
+ # Anything you want
21
+
22
+ puts 'Type and Run: @assistant.task = "show files in current directory"'
23
+
20
24
  IRB.start(__FILE__)
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) },
@@ -3,6 +3,8 @@
3
3
  module OxAiWorkers
4
4
  module Assistant
5
5
  module ModuleBase
6
+ include OxAiWorkers::LoadI18n
7
+
6
8
  attr_accessor :iterator
7
9
 
8
10
  def task=(task)
@@ -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) },
@@ -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
- extend OxAiWorkers::ToolDefinition
8
- attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones
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
- define_function :inner_monologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
12
- property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
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
- define_function :outer_voice, description: I18n.t('oxaiworkers.iterator.outer_voice.description') do
17
- property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.outer_voice.text'), required: true
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
- define_function :action_request, description: I18n.t('oxaiworkers.iterator.action_request.description') do
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
- define_function :summarize, description: I18n.t('oxaiworkers.iterator.summarize.description') do
26
- property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.summarize.text'), required: true
27
- end
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
- @queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.summarize.result') }
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 = self.class.function_schemas.to_openai_format(only: available_defs)
107
- @worker.tools += @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.present?
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
- t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name])
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
- extend OxAiWorkers::ToolDefinition
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
- extend OxAiWorkers::ToolDefinition
8
+ include OxAiWorkers::ToolDefinition
9
9
  include OxAiWorkers::DependencyHelper
10
+ include OxAiWorkers::LoadI18n
10
11
 
11
- # define_function :ruby, description: I18n.t('oxaiworkers.tool.eval.ruby.description') do
12
- # property :input, type: 'string', description: I18n.t('oxaiworkers.tool.eval.ruby.input'), required: true
13
- # end
12
+ def initialize(only: nil)
13
+ store_locale
14
14
 
15
- define_function :sh, description: I18n.t('oxaiworkers.tool.eval.sh.description') do
16
- property :input, type: 'string', description: I18n.t('oxaiworkers.tool.eval.sh.input'), required: true
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
- # def ruby(input:)
20
- # puts "Executing ruby: \"#{input}\"".colorize(:red)
21
- # eval(input)
22
- # end
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
- extend OxAiWorkers::ToolDefinition
14
+ include OxAiWorkers::ToolDefinition
15
15
  include OxAiWorkers::DependencyHelper
16
+ include OxAiWorkers::LoadI18n
16
17
 
17
- define_function :list_directory,
18
- description: I18n.t('oxaiworkers.tool.file_system.list_directory.description') do
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
- define_function :read_file, description: I18n.t('oxaiworkers.tool.file_system.read_file.description') do
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
- define_function :write_to_file, description: I18n.t('oxaiworkers.tool.file_system.write_to_file.description') do
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
- def initialize
37
- depends_on 'ptools'
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
- function_schemas.add_function(method_name:, description:, &)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OxAiWorkers
4
- VERSION = '0.5.4'
4
+ VERSION = '0.5.5.1'
5
5
  end
@@ -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__)
@@ -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
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-01 00:00:00.000000000 Z
11
+ date: 2024-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize