ox-ai-workers 0.5.3 → 0.5.4

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: b83e9d2c4e62f4e457a1cb4cf041da04bb0af0abb324bc6138ffa528b39a9a0b
4
- data.tar.gz: fc6ee779728aebe0507d58a576968f5f8f4c1c57da8863d95d78420fe7616ff8
3
+ metadata.gz: 67dfa0fc5c5cb3c3c223615ec1386324b1a71fdc38d90db9b78c6c94f0136add
4
+ data.tar.gz: 555689bc0e7d83a854f0614d13aed065b2634bdf4501a9aa2025fc40736db398
5
5
  SHA512:
6
- metadata.gz: 5a6395486f158fb8a8f1ed302e2fe17484a551426a050448f0112fb851457afcb0c3a11523ec1a6d70f4bf02c2b7b884744d0926b16d2ce4cd53a0b6e74f576f
7
- data.tar.gz: cb6532ed38d70d74a5c50526324b00e33514d524ac222921015fc3695c83952b3a219603c5b27890089f71f26f33a65ed0498e2c740fb2357e6abb5701bb0ac4
6
+ metadata.gz: 374c51ea659b98605131b46e1ffbffbfc3ec5d9d6c5718f64952e630e2a14adec56412776eadc4c074ead54c8197fc0195b9590dd76d0737dd7fff347b5ab236
7
+ data.tar.gz: 21714fc9c30d3159c756ce53840a598c163bca8547e7425e86ffd6ef86c78b5c3563c3a5b5d415420d3141c45d68c87f289d55436796bfa17cc83e4a4b963ab9
data/CHANGELOG.md CHANGED
@@ -1,8 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ - def_except and def_only for `Iterator`
4
+ - Renamed on_pack_history to on_summarize
5
+ - Renamed all "pack_history" to "summarize"
6
+
3
7
  ## [0.5.3] - 2024-07-31
4
8
 
5
9
  - Fixed summarize state
10
+ - Added `auto_execute` for `Iterator`
11
+ - Added `steps` for `Iterator`
6
12
 
7
13
  ## [0.5.2] - 2024-07-31
8
14
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
- [![Gem Version](https://badge.fury.io/rb/ox-ai-workers.svg)](https://rubygems.org/gems/ox-ai-workers)
2
-
3
1
  # OxAiWorkers (ox-ai-workers)
4
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/ox-ai-workers.svg)](https://rubygems.org/gems/ox-ai-workers)
4
+
5
5
  OxAiWorkers is a Ruby gem that implements a finite state machine (using the `state_machine` gem) to solve tasks using generative intelligence (with the `ruby-openai` gem). This approach enhances the final result by utilizing internal monologue and external tools.
6
6
 
7
7
  ## Installation
@@ -88,6 +88,7 @@ OxAiWorkers.configure do |config|
88
88
  config.model = "gpt-4o"
89
89
  config.max_tokens = 4096
90
90
  config.temperature = 0.7
91
+ config.auto_execute = true
91
92
  end
92
93
  ```
93
94
 
@@ -95,7 +96,7 @@ Then you can create an assistant like this:
95
96
 
96
97
  ```ruby
97
98
  assistant = OxAiWorkers::Assistant::Sysop.new()
98
- assistant.task = "your task"
99
+ assistant.task = "Remove all cron jobs."
99
100
 
100
101
  # Provide a response to the assistant's question
101
102
  assistant.add_response("blah-blah-blah")
@@ -114,7 +115,7 @@ iterator = OxAiWorkers::Iterator.new(
114
115
  on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
115
116
  on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
116
117
  on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
117
- on_pack_history: ->(text:) { puts "summary: #{text}".colorize(:blue) }
118
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
118
119
  )
119
120
 
120
121
  iterator.add_task("Show files in current directory.")
@@ -124,6 +125,30 @@ iterator.add_task("linux")
124
125
 
125
126
  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.
126
127
 
128
+ ### Advanced instructions for your Assistant
129
+
130
+ ```ruby
131
+ steps = []
132
+ steps << 'Step 1. Develop your own solution to the problem, taking initiative and making assumptions.'
133
+ steps << "Step 2. Enclose all your developments from the previous step in the #{OxAiWorkers::Iterator.full_function_name(:inner_monologue)} function."
134
+ steps << 'Step 3. Call the necessary functions one after another until the desired result is achieved.'
135
+ 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
+ steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
137
+
138
+ @iterator = OxAiWorkers::Iterator.new(
139
+ worker: init_worker(delayed: delayed, model: model),
140
+ role: 'You are a software agent inside my computer',
141
+ tools: [MyTool.new],
142
+ steps: steps,
143
+ # def_except: [:summarize], # It's except steps with that functions
144
+ # def_only: [:inner_monologue, :outer_voice], # Use it only with your steps
145
+ on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
146
+ on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
147
+ on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
148
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
149
+ )
150
+ ```
151
+
127
152
  ### Worker Options
128
153
 
129
154
  As a worker, you can use different classes depending on your needs:
@@ -142,7 +167,7 @@ As a worker, you can use different classes depending on your needs:
142
167
  oxaiworkers init
143
168
  ```
144
169
 
145
- This will create a `.oxaiworkers-local` directory with the necessary initial source code.
170
+ This will create a `.oxaiworkers-local` directory with the necessary initial source code.
146
171
 
147
172
  Additionally, you can initialize a more comprehensive example using the command:
148
173
 
@@ -176,7 +201,7 @@ OxAiWorkers.logger.level = :debug
176
201
 
177
202
  ## Contributing
178
203
 
179
- Bug reports and pull requests are welcome on GitHub at https://github.com/neonix20b/ox-ai-workers. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
204
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/neonix20b/ox-ai-workers>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
180
205
 
181
206
  ## License
182
207
 
@@ -184,4 +209,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
184
209
 
185
210
  ## Code of Conduct
186
211
 
187
- Everyone interacting in the OxAiWorkers project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
212
+ Everyone interacting in the OxAiWorkers project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
data/lib/ox-ai-workers.rb CHANGED
@@ -39,13 +39,14 @@ module OxAiWorkers
39
39
  class ConfigurationError < Error; end
40
40
 
41
41
  class Configuration
42
- attr_accessor :model, :max_tokens, :temperature, :access_token
42
+ attr_accessor :model, :max_tokens, :temperature, :access_token, :auto_execute
43
43
 
44
44
  def initialize
45
45
  @access_token = nil
46
46
  @model = DEFAULT_MODEL
47
47
  @max_tokens = DEFAULT_MAX_TOKEN
48
48
  @temperature = DEFAULT_TEMPERATURE
49
+ @auto_execute = true
49
50
 
50
51
  [Array, NilClass, String, Symbol, Hash].each do |c|
51
52
  c.send(:include, OxAiWorkers::PresentCompat) unless c.method_defined?(:present?)
@@ -13,7 +13,7 @@ module OxAiWorkers
13
13
  on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
14
14
  on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
15
15
  on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
16
- on_pack_history: ->(text:) { puts "summary: #{text}".colorize(:blue) }
16
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
17
17
  )
18
18
  end
19
19
  end
@@ -13,7 +13,7 @@ module OxAiWorkers
13
13
  on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
14
14
  on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
15
15
  on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
16
- on_pack_history: ->(text:) { puts "summary: #{text}".colorize(:blue) }
16
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
17
17
  )
18
18
  @iterator.add_context(format(I18n.t('oxaiworkers.assistant.localizer.source'), source))
19
19
 
@@ -14,6 +14,10 @@ module OxAiWorkers
14
14
  @iterator.add_task text
15
15
  end
16
16
 
17
+ def execute
18
+ @iterator.execute
19
+ end
20
+
17
21
  def init_worker(delayed:, model:)
18
22
  worker = delayed ? DelayedRequest.new : Request.new
19
23
  worker.model = model || OxAiWorkers.configuration.model
@@ -13,7 +13,7 @@ module OxAiWorkers
13
13
  on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
14
14
  on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
15
15
  on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
16
- on_pack_history: ->(text:) { puts "summary: #{text}".colorize(:blue) }
16
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
17
17
  )
18
18
  end
19
19
  end
@@ -2,9 +2,11 @@
2
2
 
3
3
  module OxAiWorkers
4
4
  class Iterator < OxAiWorkers::StateTools
5
+ ITERATOR_FUNCTIONS = %i[inner_monologue outer_voice action_request summarize].freeze
6
+
5
7
  extend OxAiWorkers::ToolDefinition
6
8
  attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones
7
- attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :on_pack_history
9
+ attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :on_summarize, :def_except, :def_only
8
10
 
9
11
  define_function :inner_monologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
10
12
  property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
@@ -20,22 +22,24 @@ module OxAiWorkers
20
22
  required: true
21
23
  end
22
24
 
23
- define_function :summarize, description: I18n.t('oxaiworkers.iterator.pack_history.description') do
24
- property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.pack_history.text'), required: true
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
25
27
  end
26
28
 
27
29
  def initialize(worker:, role: nil, tools: [], on_inner_monologue: nil, on_outer_voice: nil, on_action_request: nil,
28
- on_pack_history: nil)
30
+ on_summarize: nil, steps: nil, def_except: [], def_only: nil)
29
31
  @worker = worker
30
- @tools = [self] + tools
32
+ @tools = tools
31
33
  @role = role
32
34
  @context = []
33
- @monologue = I18n.t('oxaiworkers.iterator.monologue')
35
+ @def_only = def_only || ITERATOR_FUNCTIONS
36
+ @def_except = def_except
37
+ @monologue = steps || I18n.t('oxaiworkers.iterator.monologue')
34
38
 
35
39
  @on_inner_monologue = on_inner_monologue
36
40
  @on_outer_voice = on_outer_voice
37
41
  @on_action_request = on_action_request
38
- @on_pack_history = on_pack_history
42
+ @on_summarize = on_summarize
39
43
 
40
44
  cleanup
41
45
 
@@ -61,6 +65,7 @@ module OxAiWorkers
61
65
  def outer_voice(text:)
62
66
  # @queue.pop
63
67
  @queue << { role: :assistant, content: text.to_s }
68
+ complete! unless available_defs.include?(:action_request)
64
69
  @on_outer_voice&.call(text: text)
65
70
  nil
66
71
  end
@@ -77,11 +82,11 @@ module OxAiWorkers
77
82
  def summarize(text:)
78
83
  @milestones << text.to_s
79
84
  @messages = []
80
- @queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.pack_history.result') }
85
+ @queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.summarize.result') }
81
86
  @worker.finish
82
87
  rebuild_worker
83
- # complete! if can_complete?
84
- @on_pack_history&.call(text: text)
88
+ complete! if can_complete?
89
+ @on_summarize&.call(text: text)
85
90
  nil
86
91
  end
87
92
 
@@ -93,12 +98,21 @@ module OxAiWorkers
93
98
  def rebuild_worker
94
99
  @worker.messages = []
95
100
  @worker.append(role: :system, content: @role) if @role.present?
96
- @worker.append(role: :system, content: @monologue.join("\n"))
101
+ @worker.append(role: :system, content: valid_monologue.join("\n"))
97
102
  @worker.append(messages: @context) if @context.present?
98
103
  @tasks.each { |task| @worker.append(role: :user, content: task) }
99
104
  @milestones.each { |milestone| @worker.append(role: :assistant, content: milestone) }
100
105
  @worker.append(messages: @messages)
101
- @worker.tools = @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.present?
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?
108
+ end
109
+
110
+ def available_defs
111
+ @def_only - @def_except
112
+ end
113
+
114
+ def valid_monologue
115
+ @monologue.reject { |item| @def_except.any? { |fun| item.include?(self.class.full_function_name(fun)) } }
102
116
  end
103
117
 
104
118
  def next_iteration
@@ -123,12 +137,12 @@ module OxAiWorkers
123
137
  if @worker.tool_calls.present?
124
138
  @queue << { role: :assistant, content: @worker.tool_calls_raw.to_s }
125
139
  @worker.tool_calls.each do |external_call|
126
- tool = @tools.select do |t|
140
+ tool = ([self] + @tools).select do |t|
127
141
  t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name])
128
142
  end.first
129
143
  unless tool.nil?
130
144
  out = tool.send(external_call[:name], **external_call[:args])
131
- @queue << { role: :user, content: out.to_s } if out.present?
145
+ @queue << { role: :system, content: out.to_s } if out.present?
132
146
  end
133
147
  end
134
148
  @worker.finish
@@ -143,10 +157,10 @@ module OxAiWorkers
143
157
  @worker.finish
144
158
  end
145
159
 
146
- def add_task(task, auto_execute: true)
160
+ def add_task(task)
147
161
  @tasks << task
148
162
  @messages << { role: :user, content: task }
149
- execute if auto_execute
163
+ execute if OxAiWorkers.configuration.auto_execute
150
164
  end
151
165
 
152
166
  def add_context(text, role: :system)
@@ -63,6 +63,10 @@ module OxAiWorkers::ToolDefinition
63
63
  .downcase
64
64
  end
65
65
 
66
+ def full_function_name(fun)
67
+ function_schemas.function_name(fun)
68
+ end
69
+
66
70
  # Manages schemas for functions
67
71
  class FunctionSchemas
68
72
  def initialize(tool_name)
@@ -70,6 +74,10 @@ module OxAiWorkers::ToolDefinition
70
74
  @tool_name = tool_name
71
75
  end
72
76
 
77
+ def function_name method_name
78
+ "#{@tool_name}__#{method_name}"
79
+ end
80
+
73
81
  # Adds a function to the schemas
74
82
  #
75
83
  # @param method_name [Symbol] Name of the method to add
@@ -77,7 +85,7 @@ module OxAiWorkers::ToolDefinition
77
85
  # @yield Block that defines the parameters for the function
78
86
  # @raise [ArgumentError] If a block is defined and no parameters are specified for the function
79
87
  def add_function(method_name:, description:, &)
80
- name = "#{@tool_name}__#{method_name}"
88
+ name = function_name(method_name)
81
89
 
82
90
  if block_given?
83
91
  parameters = ParameterBuilder.new(parent_type: "object").build(&)
@@ -96,15 +104,23 @@ module OxAiWorkers::ToolDefinition
96
104
  # Converts schemas to OpenAI-compatible format
97
105
  #
98
106
  # @return [String] JSON string of schemas in OpenAI format
99
- def to_openai_format
100
- @schemas.values#.map { |schema| schema[:function] }
107
+ def to_openai_format(only: nil)
108
+ valid_schemas(only: only).values
109
+ end
110
+
111
+ def valid_schemas(only: nil)
112
+ if only.nil?
113
+ @schemas
114
+ else
115
+ @schemas.select { |name, schema| only.include?(name) }
116
+ end
101
117
  end
102
118
 
103
119
  # Converts schemas to Anthropic-compatible format
104
120
  #
105
121
  # @return [String] JSON string of schemas in Anthropic format
106
- def to_anthropic_format
107
- @schemas.values.map do |schema|
122
+ def to_anthropic_format(only: nil)
123
+ valid_schemas(only: only).values.map do |schema|
108
124
  schema[:function].transform_keys("parameters" => "input_schema")
109
125
  end
110
126
  end
@@ -112,8 +128,8 @@ module OxAiWorkers::ToolDefinition
112
128
  # Converts schemas to Google Gemini-compatible format
113
129
  #
114
130
  # @return [String] JSON string of schemas in Google Gemini format
115
- def to_google_gemini_format
116
- @schemas.values.map { |schema| schema[:function] }
131
+ def to_google_gemini_format(only: nil)
132
+ valid_schemas(only: only).values.map { |schema| schema[:function] }
117
133
  end
118
134
  end
119
135
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OxAiWorkers
4
- VERSION = '0.5.3'
4
+ VERSION = '0.5.4'
5
5
  end
@@ -10,7 +10,7 @@ en:
10
10
  action_request:
11
11
  description: A function for interactive interaction with the user. Allows you to ask a clarifying question, request actions, or complete the current step. The function waits for the user's response and returns it.
12
12
  action: Text of the request or action
13
- pack_history:
13
+ summarize:
14
14
  description: The function saves key facts, nuances, and actions from previous messages, including the provided response. After calling this function, all previous messages will be deleted. Use it only after all intermediate steps are completed and when the exact content of previous messages is no longer relevant.
15
15
  text: Enumeration of important facts and nuances
16
16
  result: Messages deleted
@@ -18,5 +18,5 @@ en:
18
18
  - Step 1. Develop your own solution to the problem, taking initiative and making assumptions.
19
19
  - Step 2. Enclose all your developments from the previous step in the ox_ai_workers_iterator__inner_monologue function.
20
20
  - Step 3. Call the necessary functions one after another until the desired result is achieved.
21
- - Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the ox_ai_workers_iterator__pack_history function.
21
+ - Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the ox_ai_workers_iterator__summarize function.
22
22
  - Step 5. When the solution is ready, notify about it and wait for the user's response.
@@ -10,7 +10,7 @@ ru:
10
10
  action_request:
11
11
  description: Функция для интерактивного взаимодействия с пользователем. Позволяет задать уточняющий вопрос, запросить выполнение действий или завершить текущий шаг. Функция ожидает ответ пользователя и возвращает его.
12
12
  action: Текст запроса или действия
13
- pack_history:
13
+ summarize:
14
14
  description: Функция сохраняет ключевые факты, нюансы и действия из предыдущих сообщений, включая предоставленный ответ. После вызова этой функции все предыдущие сообщения будут удалены. Используйте её только после завершения всех промежуточных шагов и когда точное содержание предыдущих сообщений больше не имеет значения.
15
15
  text: Перечисление важных фактов и нюансов
16
16
  result: Сообщения удалены
@@ -18,5 +18,5 @@ ru:
18
18
  - Шаг 1. Разработай собственное решение проблемы, проявляя инициативу и делая предположения.
19
19
  - Шаг 2. Заключи все свои наработки из предыдущего шага в функцию ox_ai_workers_iterator__inner_monologue.
20
20
  - Шаг 3. Вызывай необходимые функции друг за другом, пока желаемый результат не будет достигнут.
21
- - Шаг 4. Когда все промежуточные шаги завершены и точное содержание предыдущих сообщений больше не имеет значения, используй функцию ox_ai_workers_iterator__pack_history.
21
+ - Шаг 4. Когда все промежуточные шаги завершены и точное содержание предыдущих сообщений больше не имеет значения, используй функцию ox_ai_workers_iterator__summarize.
22
22
  - Шаг 5. Когда решение готово, сообщи об этом и ожидай ответ пользователя.
@@ -7,14 +7,23 @@ class MyAssistant
7
7
  include OxAiWorkers::Assistant::ModuleBase
8
8
 
9
9
  def initialize(delayed: false, model: nil)
10
+ # Optional instructions
11
+ # steps = []
12
+ # steps << 'Step 1. Develop your own solution to the problem, taking initiative and making assumptions.'
13
+ # steps << "Step 2. Enclose all your developments from the previous step in the #{OxAiWorkers::Iterator.full_function_name(:inner_monologue)} function."
14
+ # steps << 'Step 3. Call the necessary functions one after another until the desired result is achieved.'
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
+ # steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
17
+
10
18
  @iterator = OxAiWorkers::Iterator.new(
11
19
  worker: init_worker(delayed: delayed, model: model),
12
20
  role: 'You are a software agent inside my computer',
13
21
  tools: [MyTool.new],
22
+ # steps: steps,
14
23
  on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
15
24
  on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
16
25
  on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
17
- on_pack_history: ->(text:) { puts "summary: #{text}".colorize(:blue) }
26
+ on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
18
27
  )
19
28
  end
20
29
  end
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.3
4
+ version: 0.5.4
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-07-31 00:00:00.000000000 Z
11
+ date: 2024-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize