ox-ai-workers 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c6a4642d2f20a5544eb56eb31b2ecb26a190565711f6257793fc5320f4c46ef
4
- data.tar.gz: 480d67e601de4af89a947cb1951aa81ab04be079073cb6d50fc0b353e780300b
3
+ metadata.gz: e39a685e524452b7b7aa6547817f9e81c522c8fa8f48c35c4745322986e57e5e
4
+ data.tar.gz: 5f1fd1aaa0c019be6fc06cc607d963909a3e244c371b03ecb74aa5b48c7e507d
5
5
  SHA512:
6
- metadata.gz: 6dfbee661da05077107165b65130ef4540aec31e9bfd7b94052f6ce0e068de593651bdcedaae6e3cdebec289d4d9011ddc0da3a8445b0ea0bce52d797e2a7041
7
- data.tar.gz: e915d590643c6db03154384e66def40bc3e8b8dd91965dade1c6f3706fc3a874bd7d54301a3de4120b25da8f80f363204b08d8172676750fcb9c6cc965d39e49
6
+ metadata.gz: 1ae293da7bd885026371f173336efaa6de81714c86607c4013bee836222722c0be19f9b77099b3ffab0b064b8e954c60f8de64d65fb9afd99950ac98a5be2053
7
+ data.tar.gz: b0a9bb36f6b9ec5b123934f698017ac65306212ef9467b9623b1de3fad43cf3e1e4c3a2b78069ba35de72e94d197e0f05cf20bc33c2c1fb902a370b8483b489a
data/CHANGELOG.md CHANGED
@@ -1,9 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2024-07-30
4
+
5
+ - snake_cased function names
6
+
3
7
  ## [0.4.2] - 2024-07-30
4
8
 
5
9
  - Binary reading is suppressed
6
10
  - Command output code is returned if the command output is empty
11
+ - Fixed roles when calling functions.
7
12
 
8
13
  ## [0.4.0] - 2024-07-30
9
14
 
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/ox-ai-workers.svg)](https://rubygems.org/gems/ox-ai-workers)
2
+
1
3
  # OxAiWorkers (ox-ai-workers)
2
4
 
3
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.
@@ -39,10 +41,10 @@ require 'ox-ai-workers'
39
41
  sysop = OxAiWorkers::Assistant::Sysop.new(delayed: false, model: "gpt-4o")
40
42
 
41
43
  # Add a task to the assistant
42
- sysop.setTask("Add a cron job to synchronize files daily.")
44
+ sysop.task = "Add a cron job to synchronize files daily."
43
45
 
44
46
  # Provide a response to the assistant's question
45
- sysop.addResponse("blah-blah-blah")
47
+ sysop.add_response("blah-blah-blah")
46
48
  ```
47
49
 
48
50
  Alternatively, you can use a lower-level approach for more control:
@@ -70,10 +72,10 @@ iterator = OxAiWorkers::Iterator.new(
70
72
  iterator.role = "You are a software agent inside my computer"
71
73
 
72
74
  # Add a task to the iterator
73
- iterator.addTask("Show files in current dir")
75
+ iterator.add_task("Show files in current dir")
74
76
 
75
77
  # Provide a response to the gpt's question
76
- iterator.addTask("linux")
78
+ iterator.add_task("linux")
77
79
  ```
78
80
 
79
81
  ### With Config
@@ -93,10 +95,10 @@ Then you can create an assistant like this:
93
95
 
94
96
  ```ruby
95
97
  assistant = OxAiWorkers::Assistant::Sysop.new()
96
- assistant.setTask("your task")
98
+ assistant.task = "your task"
97
99
 
98
100
  # Provide a response to the assistant's question
99
- assistant.addResponse("blah-blah-blah")
101
+ assistant.add_response("blah-blah-blah")
100
102
  ```
101
103
 
102
104
  Or you can create a lower-level iterator for more control:
@@ -115,9 +117,9 @@ iterator = OxAiWorkers::Iterator.new(
115
117
  on_pack_history: ->(text:) { puts Rainbow("summary: #{text}").blue }
116
118
  )
117
119
 
118
- iterator.addTask("Show files in current directory.")
120
+ iterator.add_task("Show files in current directory.")
119
121
  # ...
120
- iterator.addTask("linux")
122
+ iterator.add_task("linux")
121
123
  ```
122
124
 
123
125
  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.
@@ -185,11 +187,11 @@ en:
185
187
  text: "Listing important facts and nuances"
186
188
  monologue:
187
189
  - "Step 1: Develop your own solution to the problem. Take initiative and make assumptions."
188
- - "Step 1.1: Wrap all your work for this step in the innerMonologue function."
190
+ - "Step 1.1: Wrap all your work for this step in the inner_monologue function."
189
191
  - "Step 2: Relate your solution to the task, improve it, and call the necessary functions step by step."
190
- - "Step 2.1: Interact with the user using the outerVoice and actionRequest functions during the process."
191
- - "Step 3: When the solution is ready, report it using the outerVoice function."
192
- - "Step 4: Save facts, nuances, and actions using the packHistory function."
192
+ - "Step 2.1: Interact with the user using the outer_voice and action_request functions during the process."
193
+ - "Step 3: When the solution is ready, report it using the outer_voice function."
194
+ - "Step 4: Save facts, nuances, and actions using the summarize function."
193
195
  tool:
194
196
  eval:
195
197
  ruby:
data/exe/start CHANGED
@@ -5,7 +5,6 @@
5
5
  # require 'oxaiworkers/load_i18n'
6
6
  # I18n.default_locale = :ru
7
7
 
8
- # Start your code here
9
8
  require 'ox-ai-workers'
10
9
  require 'irb'
11
10
 
@@ -7,7 +7,7 @@ module OxAiWorkers
7
7
 
8
8
  def initialize(delayed: false, model: nil, language: 'ruby')
9
9
  @iterator = Iterator.new(
10
- worker: initWorker(delayed: delayed, model: model),
10
+ worker: init_worker(delayed: delayed, model: model),
11
11
  role: format(I18n.t('oxaiworkers.assistant.coder.role'), language),
12
12
  tools: [Tool::Eval.new, Tool::FileSystem.new],
13
13
  on_inner_monologue: ->(text:) { puts Rainbow("monologue: #{text}").yellow },
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OxAiWorkers
2
4
  module Assistant
3
5
  module ModuleBase
4
6
  attr_accessor :iterator
5
7
 
6
- def setTask(task)
8
+ def task=(task)
7
9
  @iterator.cleanup
8
- @iterator.addTask task
10
+ @iterator.add_task task
9
11
  end
10
12
 
11
- def addResponse(text)
12
- @iterator.addTask text
13
+ def add_response(text)
14
+ @iterator.add_task text
13
15
  end
14
16
 
15
- def initWorker(delayed:, model:)
17
+ def init_worker(delayed:, model:)
16
18
  worker = delayed ? DelayedRequest.new : Request.new
17
19
  worker.model = model || OxAiWorkers.configuration.model
18
20
  worker
@@ -7,7 +7,7 @@ module OxAiWorkers
7
7
 
8
8
  def initialize(delayed: false, model: nil)
9
9
  @iterator = Iterator.new(
10
- worker: initWorker(delayed: delayed, model: model),
10
+ worker: init_worker(delayed: delayed, model: model),
11
11
  role: I18n.t('oxaiworkers.assistant.sysop.role'),
12
12
  tools: [Tool::Eval.new],
13
13
  on_inner_monologue: ->(text:) { puts Rainbow("monologue: #{text}").yellow },
@@ -3,14 +3,14 @@
3
3
  module OxAiWorkers
4
4
  class DelayedRequest < OxAiWorkers::StateBatch
5
5
  def initialize(batch_id: nil, model: nil, max_tokens: nil, temperature: nil)
6
- initializeRequests(model: model, max_tokens: max_tokens, temperature: temperature)
6
+ initialize_requests(model: model, max_tokens: max_tokens, temperature: temperature)
7
7
  @custom_id = nil if batch_id.present?
8
8
  @batch_id = batch_id
9
9
  @file_id = nil
10
10
  super()
11
11
  end
12
12
 
13
- def postBatch
13
+ def post_batch
14
14
  response = @client.batches.create(
15
15
  parameters: {
16
16
  input_file_id: @file_id,
@@ -21,11 +21,11 @@ module OxAiWorkers
21
21
  @batch_id = response['id']
22
22
  end
23
23
 
24
- def cancelBatch
24
+ def cancel_batch
25
25
  not_found_is_ok { @client.batches.cancel(id: @batch_id) }
26
26
  end
27
27
 
28
- def cleanStorage
28
+ def clean_storage
29
29
  if @batch_id.present?
30
30
  batch = @client.batches.retrieve(id: @batch_id)
31
31
  if !batch['output_file_id'].nil?
@@ -49,7 +49,7 @@ module OxAiWorkers
49
49
  end_batch! unless batch_idle?
50
50
  end
51
51
 
52
- def uploadToStorage
52
+ def upload_to_storage
53
53
  item = {
54
54
  "custom_id": @custom_id,
55
55
  "method": 'POST',
@@ -96,7 +96,7 @@ module OxAiWorkers
96
96
  output.each do |line|
97
97
  @custom_id = line['custom_id']
98
98
  # @result = line.dig("response", "body", "choices", 0, "message", "content")
99
- parseChoices(line.dig('response', 'body'))
99
+ parse_choices(line.dig('response', 'body'))
100
100
  complete_batch!
101
101
  end
102
102
  elsif !batch['error_file_id'].nil?
@@ -6,21 +6,21 @@ module OxAiWorkers
6
6
  attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones
7
7
  attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :on_pack_history
8
8
 
9
- define_function :innerMonologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
9
+ define_function :inner_monologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
10
10
  property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
11
11
  required: true
12
12
  end
13
13
 
14
- define_function :outerVoice, description: I18n.t('oxaiworkers.iterator.outer_voice.description') do
14
+ define_function :outer_voice, description: I18n.t('oxaiworkers.iterator.outer_voice.description') do
15
15
  property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.outer_voice.text'), required: true
16
16
  end
17
17
 
18
- define_function :actionRequest, description: I18n.t('oxaiworkers.iterator.action_request.description') do
18
+ define_function :action_request, description: I18n.t('oxaiworkers.iterator.action_request.description') do
19
19
  property :action, type: 'string', description: I18n.t('oxaiworkers.iterator.action_request.action'),
20
20
  required: true
21
21
  end
22
22
 
23
- define_function :packHistory, description: I18n.t('oxaiworkers.iterator.pack_history.description') do
23
+ define_function :summarize, description: I18n.t('oxaiworkers.iterator.pack_history.description') do
24
24
  property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.pack_history.text'), required: true
25
25
  end
26
26
 
@@ -49,24 +49,24 @@ module OxAiWorkers
49
49
  @tasks = []
50
50
  @milestones = []
51
51
  @messages = []
52
- completeIteration
52
+ complete_iteration
53
53
  end
54
54
 
55
- def innerMonologue(speach:)
55
+ def inner_monologue(speach:)
56
56
  # @queue.pop
57
57
  @queue << { role: :system, content: speach.to_s }
58
58
  @on_inner_monologue&.call(text: speach)
59
59
  nil
60
60
  end
61
61
 
62
- def outerVoice(text:)
62
+ def outer_voice(text:)
63
63
  # @queue.pop
64
64
  @queue << { role: :system, content: text.to_s }
65
65
  @on_outer_voice&.call(text: text)
66
66
  nil
67
67
  end
68
68
 
69
- def actionRequest(action:)
69
+ def action_request(action:)
70
70
  @result = action
71
71
  # @queue.pop
72
72
  @messages << { role: :system, content: action.to_s }
@@ -75,11 +75,11 @@ module OxAiWorkers
75
75
  nil
76
76
  end
77
77
 
78
- def packHistory(text:)
78
+ def summarize(text:)
79
79
  @milestones << text.to_s
80
80
  @messages = []
81
81
  @worker.finish
82
- rebuildWorker
82
+ rebuild_worker
83
83
  complete! if can_complete?
84
84
  @on_pack_history&.call(text: text)
85
85
  nil
@@ -87,11 +87,11 @@ module OxAiWorkers
87
87
 
88
88
  def init
89
89
  puts "call: #{__method__} state: #{state_name}"
90
- rebuildWorker
90
+ rebuild_worker
91
91
  request!
92
92
  end
93
93
 
94
- def rebuildWorker
94
+ def rebuild_worker
95
95
  @worker.messages = []
96
96
  @worker.append(role: :system, content: @role) if !@role.nil? && @role.present?
97
97
  @worker.append(role: :system, content: @monologue.join("\n"))
@@ -102,7 +102,7 @@ module OxAiWorkers
102
102
  @worker.tools = @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.any?
103
103
  end
104
104
 
105
- def nextIteration
105
+ def next_iteration
106
106
  puts "call: #{__method__} state: #{state_name}"
107
107
  @worker.append(messages: @queue)
108
108
  @messages += @queue
@@ -110,7 +110,7 @@ module OxAiWorkers
110
110
  request!
111
111
  end
112
112
 
113
- def externalRequest
113
+ def external_request
114
114
  puts "call: #{__method__} state: #{state_name}"
115
115
  @worker.request!
116
116
  ticker
@@ -122,7 +122,7 @@ module OxAiWorkers
122
122
  analyze!
123
123
  end
124
124
 
125
- def processResult(_transition)
125
+ def process_result(_transition)
126
126
  puts "call: #{__method__} state: #{state_name}"
127
127
  @result = @worker.result || @worker.errors
128
128
  if @worker.tool_calls.present?
@@ -146,22 +146,22 @@ module OxAiWorkers
146
146
  # iterate!
147
147
  # end
148
148
  elsif @worker.result.present?
149
- actionRequest action: @worker.result
149
+ action_request action: @worker.result
150
150
  end
151
151
  end
152
152
 
153
- def completeIteration
153
+ def complete_iteration
154
154
  @queue = []
155
155
  @worker.finish
156
156
  end
157
157
 
158
- def addTask(task, auto_execute: true)
158
+ def add_task(task, auto_execute: true)
159
159
  @tasks << task
160
160
  @messages << { role: :user, content: task }
161
161
  execute if auto_execute
162
162
  end
163
163
 
164
- def appendContext(text, role: :system)
164
+ def append_context(text, role: :system)
165
165
  @context << { role: role, content: text }
166
166
  end
167
167
 
@@ -5,7 +5,7 @@ module OxAiWorkers
5
5
  attr_accessor :result, :client, :messages, :model, :max_tokens, :custom_id, :temperature, :tools, :errors,
6
6
  :tool_calls_raw, :tool_calls
7
7
 
8
- def initializeRequests(model: nil, max_tokens: nil, temperature: nil)
8
+ def initialize_requests(model: nil, max_tokens: nil, temperature: nil)
9
9
  # puts "call: ModuleRequest::#{__method__}"
10
10
  @max_tokens = max_tokens || OxAiWorkers.configuration.max_tokens
11
11
  @custom_id = SecureRandom.uuid
@@ -60,7 +60,7 @@ module OxAiWorkers
60
60
  nil
61
61
  end
62
62
 
63
- def parseChoices(response)
63
+ def parse_choices(response)
64
64
  # puts response.inspect
65
65
  @tool_calls = []
66
66
  @result = response.dig('choices', 0, 'message', 'content')
@@ -11,9 +11,9 @@ module OxAiWorkers
11
11
  def camelize(first_letter = :upper)
12
12
  string = dup
13
13
  string = if first_letter == :upper
14
- string.sub(/^[a-z\d]*/) { |match| match.capitalize }
14
+ string.sub(/^[a-z\d]*/, &:capitalize)
15
15
  else
16
- string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
16
+ string.sub(/^(?:(?=\b|[A-Z_])|\w)/, &:downcase)
17
17
  end
18
18
  string.gsub(%r{(?:_|(/))([a-z\d]*)}) do
19
19
  "#{::Regexp.last_match(1)}#{::Regexp.last_match(2).capitalize}"
@@ -2,7 +2,7 @@
2
2
 
3
3
  module OxAiWorkers
4
4
  class Request < OxAiWorkers::ModuleRequest
5
- alias initialize initializeRequests
5
+ alias initialize initialize_requests
6
6
 
7
7
  def finish
8
8
  @custom_id = SecureRandom.uuid
@@ -11,7 +11,7 @@ module OxAiWorkers
11
11
 
12
12
  def request!
13
13
  response = @client.chat(parameters: params)
14
- parseChoices(response)
14
+ parse_choices(response)
15
15
  # @result = response.dig("choices", 0, "message", "content")
16
16
  # puts response.inspect
17
17
  rescue OpenAI::Error => e
@@ -14,10 +14,10 @@ module OxAiWorkers
14
14
  before_transition from: any, do: :log_me
15
15
 
16
16
  after_transition on: :end, do: :cleanup
17
- before_transition on: :process, do: :postBatch
18
- after_transition on: :cancel, do: %i[cancelBatch complete_batch!]
19
- after_transition on: :complete, do: [:cleanStorage]
20
- after_transition on: :prepare, do: :uploadToStorage
17
+ before_transition on: :process, do: :post_batch
18
+ after_transition on: :cancel, do: %i[cancel_batch complete_batch!]
19
+ after_transition on: :complete, do: [:clean_storage]
20
+ after_transition on: :prepare, do: :upload_to_storage
21
21
 
22
22
  event :end do
23
23
  transition %i[finished canceled] => :idle
@@ -10,11 +10,11 @@ module OxAiWorkers
10
10
  state_machine :state, initial: :idle do
11
11
  before_transition from: any, do: :log_me
12
12
 
13
- after_transition on: :iterate, do: :nextIteration
14
- after_transition on: :request, do: :externalRequest
13
+ after_transition on: :iterate, do: :next_iteration
14
+ after_transition on: :request, do: :external_request
15
15
  after_transition on: :prepare, do: :init
16
- after_transition on: :analyze, do: :processResult
17
- after_transition on: :complete, do: :completeIteration
16
+ after_transition on: :analyze, do: :process_result
17
+ after_transition on: :complete, do: :complete_iteration
18
18
 
19
19
  event :prepare do
20
20
  transition %i[idle finished] => :prepared
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OxAiWorkers
4
- VERSION = '0.4.2'
4
+ VERSION = '0.5.0'
5
5
  end
@@ -15,8 +15,8 @@ en:
15
15
  text: "Listing important facts and nuances"
16
16
  monologue:
17
17
  - "Step 1: Develop your own solution to the problem. Take initiative and make assumptions."
18
- - "Step 1.1: Wrap all your work for this step in the ox_ai_workers_iterator__innerMonologue function."
18
+ - "Step 1.1: Wrap all your work for this step in the ox_ai_workers_iterator__inner_monologue function."
19
19
  - "Step 2: Relate your solution to the task, improve it, and call the necessary functions step by step."
20
- - "Step 2.1: Interact with the user using the ox_ai_workers_iterator__outerVoice and ox_ai_workers_iterator__actionRequest functions during the process."
21
- - "Step 3: When the solution is ready, report it using the ox_ai_workers_iterator__outerVoice function."
22
- - "Step 4: Save facts, nuances, and actions using the ox_ai_workers_iterator__packHistory function."
20
+ - "Step 2.1: Interact with the user using the ox_ai_workers_iterator__outer_voice and ox_ai_workers_iterator__action_request functions during the process."
21
+ - "Step 3: When the solution is ready, report it using the ox_ai_workers_iterator__outer_voice function."
22
+ - "Step 4: Save facts, nuances, and actions using the ox_ai_workers_iterator__summarize function."
@@ -15,8 +15,8 @@ ru:
15
15
  text: Перечисление важных фактов и нюансов
16
16
  monologue:
17
17
  - Шаг 1. Разработай собственное решение проблемы. Проявляй инициативу и делай предположения.
18
- - Шаг 1.1. Заключи все свои наработки для этого шага в функцию ox_ai_workers_iterator__innerMonologue.
18
+ - Шаг 1.1. Заключи все свои наработки для этого шага в функцию ox_ai_workers_iterator__inner_monologue.
19
19
  - Шаг 2. Соотнеси свое решение с задачей, улучшай его и вызывай необходимые функции шаг за шагом.
20
- - Шаг 2.1. Во время работы используй функции ox_ai_workers_iterator__outerVoice и ox_ai_workers_iterator__actionRequest.
21
- - Шаг 3. Когда решение готово, сообщи о нем с помощью функции ox_ai_workers_iterator__outerVoice
22
- - Шаг 4. Сохрани факты, нюансы и действия с помощью функции ox_ai_workers_iterator__packHistory и предложи дальнейшие действия с помощью функции ox_ai_workers_iterator__actionRequest.
20
+ - Шаг 2.1. Во время работы используй функции ox_ai_workers_iterator__outer_voice и ox_ai_workers_iterator__action_request.
21
+ - Шаг 3. Когда решение готово, сообщи о нем с помощью функции ox_ai_workers_iterator__outer_voice
22
+ - Шаг 4. Сохрани факты, нюансы и действия с помощью функции ox_ai_workers_iterator__summarize и предложи дальнейшие действия с помощью функции ox_ai_workers_iterator__action_request.
@@ -8,7 +8,7 @@ class MyAssistant
8
8
 
9
9
  def initialize(delayed: false, model: nil)
10
10
  @iterator = OxAiWorkers::Iterator.new(
11
- worker: initWorker(delayed: delayed, model: model),
11
+ worker: init_worker(delayed: delayed, model: model),
12
12
  role: 'You are a software agent inside my computer',
13
13
  tools: [MyTool.new],
14
14
  on_inner_monologue: ->(text:) { puts Rainbow("monologue: #{text}").yellow },
data/template/start CHANGED
@@ -24,5 +24,6 @@ end
24
24
 
25
25
  # Main algorithm
26
26
  @assistant = MyAssistant.new
27
+ @assistant.task = '2 + 2 is ?'
27
28
 
28
29
  IRB.start(__FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ox-ai-workers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Smolev
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ptools
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rainbow
57
71
  requirement: !ruby/object:Gem::Requirement