ox-ai-workers 0.5.4 → 0.5.5

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: ca54c1ff9c1f4360ddfe986c4b5bc6fb6b7c0cde0484d1b2f88bfe4d8c5707b7
4
+ data.tar.gz: 2c54e55fedd99af36f7a510ab923c54581faecfc8b36caa4d228f14349e293a8
5
5
  SHA512:
6
- metadata.gz: 374c51ea659b98605131b46e1ffbffbfc3ec5d9d6c5718f64952e630e2a14adec56412776eadc4c074ead54c8197fc0195b9590dd76d0737dd7fff347b5ab236
7
- data.tar.gz: 21714fc9c30d3159c756ce53840a598c163bca8547e7425e86ffd6ef86c78b5c3563c3a5b5d415420d3141c45d68c87f289d55436796bfa17cc83e4a4b963ab9
6
+ metadata.gz: b8915a64826c118706328c89a87c01fdf49f13b63408c64d5af1ea53a2f92dbb326b9e537f36aa755297a5c919239d426da1f38a83b3cd5fdfbc5a9ebc4146f7
7
+ data.tar.gz: 8614ed16d7771b594bda52de36f87bbd211adfc8c579fff752634fc4ce44a7d554cd25cf7b32bfaa80954830f835a7b3c1f61d0e237c930bc043f433e98534c1
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
 
@@ -102,11 +102,20 @@ assistant.task = "Remove all cron jobs."
102
102
  assistant.add_response("blah-blah-blah")
103
103
  ```
104
104
 
105
+ Besides, you can create assistants with different locales
106
+
107
+ ```ruby
108
+ I18n.with_locale(:en) { @sysop_en = OxAiWorkers::Assistant::Sysop.new() }
109
+
110
+ # Assign tasks and responses in different languages
111
+ @sysop_en.task = "Remove all cron jobs."
112
+ ```
113
+
105
114
  Or you can create a lower-level iterator for more control:
106
115
 
107
116
  ```ruby
108
117
  my_worker = OxAiWorkers::Request.new
109
- my_tool = OxAiWorkers::Tool::Eval.new
118
+ my_tool = OxAiWorkers::Tool::Eval.new(only: [:sh])
110
119
 
111
120
  iterator = OxAiWorkers::Iterator.new(
112
121
  worker: my_worker,
@@ -135,10 +144,14 @@ steps << 'Step 3. Call the necessary functions one after another until the desir
135
144
  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
145
  steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
137
146
 
147
+ # To retain the locale if you have assistants in different languages in your project.
148
+ store_locale # Optional
149
+
138
150
  @iterator = OxAiWorkers::Iterator.new(
139
151
  worker: init_worker(delayed: delayed, model: model),
140
152
  role: 'You are a software agent inside my computer',
141
153
  tools: [MyTool.new],
154
+ locale: @locale || I18n.locale,
142
155
  steps: steps,
143
156
  # def_except: [:summarize], # It's except steps with that functions
144
157
  # 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'
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) },
@@ -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
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