ox-ai-workers 0.1.0 → 0.2.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: 8b8d21359f7e98b3195db02a899f41441dc3ff52765c2ce52a8d3ad459aec13e
4
- data.tar.gz: ae5875a656c07bacc42f5c4ec836607978eb55afb881a6b73e0458d1b898f5d4
3
+ metadata.gz: b6d3516a02ebb121bdf02d3de27e78ca5c71b893efa9a25b69217b9260819f7a
4
+ data.tar.gz: 4ef7a7ef32d76506b5eb4e852d77a0cf979ba40c2ed74d4635081a774bf65d20
5
5
  SHA512:
6
- metadata.gz: 5a00ba9ee3b5c07c4e186731e986f275f54e57cac40d8b37d8cf8376440d32ee18ded43a9a65eeef5fe331e740bea988c7cb88bfab3f1403573187359b4c61d2
7
- data.tar.gz: ce80d29252a85f4856f916eec0e7c734e2808644b41383ca4f2362417ba164ca2740409b7d41b158bb7c556bd5a6e13a401f9a0873e20c5424eb0b01e5aa8046
6
+ metadata.gz: a432bb010d43b81c4041dd01ef5bf141ad3c2a61a44690dad1d4bd20efd2e206d8e28f1618c8f6137517a8366f0e0fe25a446893e3815393599a5ba5bc34434c
7
+ data.tar.gz: 7a3932acb7227a48970deed5f131d016f83340f137a97efc1fb9b9b98ba6a8668f7ce9cf5247d4540d9ecebd3388af82d4a2cb08f31a987ba85b15d208fbb82e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2024-07-30
4
+ - fix missing require 'open3'
5
+ - fix Steps
6
+
7
+ ## [0.1.1] - 2024-07-29
8
+
9
+ - Fix Delayed Requests
10
+ - Configurable model, max_tokens, temperature
11
+
3
12
  ## [0.1.0] - 2024-07-29
4
13
 
5
14
  - Initial release
15
+
data/README.md CHANGED
@@ -32,10 +32,52 @@ I18n.default_locale = :en # for pure Ruby
32
32
  require 'ox-ai-workers'
33
33
 
34
34
  # Initialize the assistant
35
- sysop = OxAiWorkers::Assistant::Sysop.new()
35
+ sysop = OxAiWorkers::Assistant::Sysop.new(delayed: false, model: "gpt-4o")
36
36
 
37
37
  # Add a task
38
- sysop.addTask("Add a cron job to synchronize files daily.")
38
+ sysop.setTask("Add a cron job to synchronize files daily.")
39
+
40
+ # Add a response to the assistant's question.
41
+ sysop.addResponse("blah-blah-blah")
42
+ ```
43
+
44
+ ```ruby
45
+ worker = OxAiWorkers::DelayedRequest.new(model: "gpt-4o-mini", max_tokens: 4096, temperature: 0.7)
46
+ # or
47
+ # worker = OxAiWorkers::Request.new(model: "gpt-4o-mini", max_tokens: 4096, temperature: 0.7)
48
+ my_tool = OxAiWorkers::Tool::Eval.new()
49
+ iterator = OxAiWorkers::Iterator.new(worker: worker, tools: [my_tool])
50
+ iterator.role = "You are a software agent inside my computer"
51
+ iterator.addTask("Show files in current dir")
52
+ ```
53
+
54
+ ### With Config
55
+
56
+ For a more robust setup, you can configure the gem with your API keys, for example in an oxaiworkers.rb initializer file. Never hardcode secrets into your codebase - instead use something like [dotenv](https://github.com/motdotla/dotenv) to pass the keys safely into your environments.
57
+
58
+ ```ruby
59
+ OxAiWorkers.configure do |config|
60
+ config.access_token = ENV.fetch("OPENAI")
61
+ config.model = "gpt-4o"
62
+ config.max_tokens = 4096
63
+ config.temperature = 0.7
64
+ end
65
+ ```
66
+
67
+ Then you can create an assistant like this:
68
+
69
+ ```ruby
70
+ assistant = OxAiWorkers::Assistant::Sysop.new()
71
+ ```
72
+
73
+ ```ruby
74
+ iterator = OxAiWorkers::Iterator.new(
75
+ worker: OxAiWorkers::Request.new,
76
+ tools: [OxAiWorkers::Tool::Eval.new],
77
+ role: "You are a software agent inside my computer"
78
+ )
79
+
80
+ iterator.addTask("Show files in current directory.")
39
81
  ```
40
82
 
41
83
  ## Features
@@ -66,14 +108,12 @@ en:
66
108
  description: "Save facts, nuances, and actions before clearing messages"
67
109
  text: "Listing important facts and nuances"
68
110
  monologue:
69
- steps:
70
- - "Step 1: Develop your own solution to the problem. Take initiative and make assumptions."
71
- - "Step 1.1: Wrap all your work for this step in the innerMonologue function."
72
- - "Step 2: Relate your solution to the task, improve it, and call the necessary functions step by step."
73
- - "Step 2.1: Interact with the user using the outerVoice and actionRequest functions during the process."
74
- - "Step 3: When the solution is ready, report it using the outerVoice function."
75
- - "Step 3.1: Save facts, nuances, and actions using the packHistory function."
76
- - "Step 4: Conclude the work with the actionRequest function, without repeating the response if it was already given with outerVoice."
111
+ - "Step 1: Develop your own solution to the problem. Take initiative and make assumptions."
112
+ - "Step 1.1: Wrap all your work for this step in the innerMonologue function."
113
+ - "Step 2: Relate your solution to the task, improve it, and call the necessary functions step by step."
114
+ - "Step 2.1: Interact with the user using the outerVoice and actionRequest functions during the process."
115
+ - "Step 3: When the solution is ready, report it using the outerVoice function."
116
+ - "Step 4: Save facts, nuances, and actions using the packHistory function."
77
117
  tool:
78
118
  eval:
79
119
  ruby:
data/lib/ox-ai-workers.rb CHANGED
@@ -20,17 +20,28 @@ require_relative "oxaiworkers/iterator.rb"
20
20
  require_relative "oxaiworkers/request.rb"
21
21
  require_relative "oxaiworkers/tool/eval.rb"
22
22
  require_relative "oxaiworkers/version.rb"
23
+
24
+ require_relative "oxaiworkers/assistant/module_base.rb"
23
25
  require_relative "oxaiworkers/assistant/sysop.rb"
24
26
 
25
27
  module OxAiWorkers
28
+ DEFAULT_MODEL = "gpt-4o-mini"
29
+ DEFAULT_MAX_TOKEN = 4096
30
+ DEFAULT_TEMPERATURE = 0.7
31
+
26
32
  class Error < StandardError; end
27
33
  class ConfigurationError < Error; end
28
34
 
29
35
  class Configuration
30
36
  attr_writer :access_token
37
+ attr_accessor :model, :max_tokens, :temperature
31
38
 
32
39
  def initialize
33
40
  @access_token = nil
41
+ @model = DEFAULT_MODEL
42
+ @max_tokens = DEFAULT_MAX_TOKEN
43
+ @temperature = DEFAULT_TEMPERATURE
44
+
34
45
  [Array, NilClass, String, Symbol, Hash].each{|c|
35
46
  c.send(:include, OxAiWorkers::PresentCompat) unless c.method_defined?(:present?)
36
47
  }
@@ -0,0 +1,22 @@
1
+ module OxAiWorkers
2
+ module Assistant
3
+ module ModuleBase
4
+ attr_accessor :iterator
5
+
6
+ def setTask task
7
+ @iterator.cleanup()
8
+ @iterator.addTask task
9
+ end
10
+
11
+ def addResponse text
12
+ @iterator.addTask text
13
+ end
14
+
15
+ def initWorker delayed:, model:
16
+ worker = delayed ? OxAiWorkers::DelayedRequest.new : OxAiWorkers::Request.new
17
+ worker.model = model || OxAiWorkers.configuration.model
18
+ worker
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,13 +1,14 @@
1
1
  module OxAiWorkers
2
2
  module Assistant
3
3
  class Sysop
4
- attr_accessor :iterator
5
- def initialize delayed: false, model: "gpt-4o-mini"
6
- worker = delayed ? OxAiWorkers::DelayedRequest.new : OxAiWorkers::Request.new
7
- worker.model = model
8
- @iterator = OxAiWorkers::Iterator.new(worker: worker, tools: [OxAiWorkers::Tool::Eval.new])
9
- @iterator.role = I18n.t("oxaiworkers.assistant.sysop.role")
10
- # @iterator.addTask("покажи мне файлы на диске")
4
+ include OxAiWorkers::Assistant::ModuleBase
5
+
6
+ def initialize delayed: false, model: nil
7
+ @iterator = OxAiWorkers::Iterator.new(
8
+ worker: initWorker(delayed: delayed, model: model),
9
+ role: I18n.t("oxaiworkers.assistant.sysop.role"),
10
+ tools: [OxAiWorkers::Tool::Eval.new]
11
+ )
11
12
  end
12
13
  end
13
14
  end
@@ -1,11 +1,12 @@
1
1
  class OxAiWorkers::DelayedRequest < OxAiWorkers::StateBatch
2
- def initialize(batch_id: nil, model: DEFAULT_MODEL, max_tokens: DEFAULT_MAX_TOKEN, temperature: DEFAULT_TEMPERATURE)
2
+ def initialize(batch_id: nil, model: nil, max_tokens: nil, temperature: nil)
3
3
  initializeRequests(model: model, max_tokens: max_tokens, temperature: temperature)
4
4
  @custom_id = nil if batch_id.present?
5
5
  @batch_id = batch_id
6
6
  @file_id = nil
7
7
  super()
8
8
  end
9
+
9
10
  def postBatch
10
11
  response = @client.batches.create(
11
12
  parameters: {
@@ -38,7 +39,7 @@ class OxAiWorkers::DelayedRequest < OxAiWorkers::StateBatch
38
39
 
39
40
  def finish
40
41
  @custom_id = SecureRandom.uuid
41
- end_batch!
42
+ end_batch! unless batch_idle?
42
43
  end
43
44
 
44
45
  def uploadToStorage
@@ -86,7 +87,8 @@ class OxAiWorkers::DelayedRequest < OxAiWorkers::StateBatch
86
87
  output = @client.files.content(id: batch["output_file_id"])
87
88
  output.each do |line|
88
89
  @custom_id = line["custom_id"]
89
- @result = line.dig("response", "body", "choices", 0, "message", "content")
90
+ # @result = line.dig("response", "body", "choices", 0, "message", "content")
91
+ parseChoices(line.dig("response", "body"))
90
92
  complete_batch!
91
93
  end
92
94
  elsif !batch["error_file_id"].nil?
@@ -21,18 +21,22 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
21
21
  def initialize(worker:, role: nil, tools: [])
22
22
  puts "call: #{__method__}"
23
23
  @worker = worker
24
- @messages = []
25
24
  @tools = [self] + tools
26
25
  @role = role
27
26
  @context = nil
27
+ @monologue = I18n.t("oxaiworkers.iterator.monologue")
28
+ cleanup()
29
+
30
+ super()
31
+ end
32
+
33
+ def cleanup
28
34
  @result = nil
29
35
  @queue = []
30
- @monologue = I18n.t("oxaiworkers.iterator.monologue")
31
36
  @tasks = []
32
37
  @milestones = []
33
-
34
- # @tools = OxAiWorkers::Tool.constants.map(&OxAiWorkers::Tool.method(:const_get)).select { |c| c.is_a? Class }.map{|c|c.new}
35
- super()
38
+ @messages = []
39
+ completeIteration()
36
40
  end
37
41
 
38
42
  def innerMonologue speach:
@@ -60,7 +64,7 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
60
64
 
61
65
  def packHistory text:
62
66
  puts Rainbow("summarize: #{text}").blue
63
- @milestones << "#{Time.now} #{__method__}: #{text}"
67
+ @milestones << "#{__method__}: #{text}"
64
68
  @messages = []
65
69
  @worker.finish()
66
70
  rebuildWorker()
@@ -110,7 +114,7 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
110
114
  def processResult(transition)
111
115
  puts "call: #{__method__} state: #{state_name}"
112
116
  @result = @worker.result || @worker.errors
113
- if @worker.external_call.present?
117
+ if @worker.tool_calls.present?
114
118
  @queue << {role: :system, content: @worker.tool_calls_raw.to_s}
115
119
  @worker.tool_calls.each do |external_call|
116
120
  tool = @tools.select{|t| t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name]) }.first
@@ -119,6 +123,7 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
119
123
  @queue << {role: :system, content: out.to_s} if out.present?
120
124
  end
121
125
  end
126
+ @worker.finish()
122
127
  iterate! if can_iterate?
123
128
 
124
129
  # tool = @tools.select{|t| t.class.tool_name == @worker.external_call[:class] && t.respond_to?(@worker.external_call[:name]) }.first
@@ -127,19 +132,19 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
127
132
  # @queue << {role: :system, content: out.to_s} if out.present?
128
133
  # iterate!
129
134
  # end
130
- elsif @result.present?
131
- actionRequest action: @result
135
+ elsif @worker.result.present?
136
+ actionRequest action: @worker.result
132
137
  end
133
138
  end
134
139
 
135
140
  def completeIteration
141
+ @queue = []
136
142
  @worker.finish()
137
143
  end
138
144
 
139
145
  def addTask task, auto_execute: true
140
146
  @tasks << task
141
147
  @messages << {role: :user, content: task}
142
- task
143
148
  execute() if auto_execute
144
149
  end
145
150
 
@@ -162,3 +167,21 @@ class OxAiWorkers::Iterator < OxAiWorkers::StateTools
162
167
  end
163
168
 
164
169
  end
170
+
171
+ # r = OxAiWorkers::Iterator.new(worker: OxAiWorkers::Request.new)
172
+ # r.addTask("сколько будет 2+2?")
173
+ # r.execute
174
+ # r.result
175
+
176
+
177
+ # @worker.append(role: "user", content: "сколько будет 2+2?")
178
+ # @worker.request!
179
+ # @worker.completed?
180
+ # @worker.result
181
+ # @worker.finish
182
+ #
183
+ # r = OxAiWorkers::Iterator.new(worker: OxAiWorkers::Request.new)
184
+ # r.role = "ты программный агент внутри моего компьютера"
185
+ # r.tools = [OxAiWorkers::Tool::Eval.new]
186
+ # r.addTask("покажи мне файлы на диске, используй код на ruby")
187
+ # r.execute
@@ -1,16 +1,13 @@
1
1
  class OxAiWorkers::ModuleRequest
2
2
  attr_accessor :result, :client, :messages, :model, :max_tokens, :custom_id, :temperature, :tools, :errors
3
3
  attr_accessor :tool_calls_raw, :tool_calls
4
- DEFAULT_MODEL = "gpt-4o-mini"
5
- DEFAULT_MAX_TOKEN = 4096
6
- DEFAULT_TEMPERATURE = 0.7
7
4
 
8
- def initializeRequests(model: DEFAULT_MODEL, max_tokens: DEFAULT_MAX_TOKEN, temperature: DEFAULT_TEMPERATURE)
5
+ def initializeRequests(model: nil, max_tokens: nil, temperature: nil)
9
6
  puts "call: ModuleRequest::#{__method__}"
10
- @max_tokens = max_tokens
7
+ @max_tokens = max_tokens || OxAiWorkers.configuration.max_tokens
11
8
  @custom_id = SecureRandom.uuid
12
- @model = model
13
- @temperature = temperature
9
+ @model = model || OxAiWorkers.configuration.model
10
+ @temperature = temperature || OxAiWorkers.configuration.temperature
14
11
  @client = nil
15
12
 
16
13
  OxAiWorkers.configuration.access_token ||= ENV["OPENAI"]
@@ -31,6 +28,8 @@ class OxAiWorkers::ModuleRequest
31
28
  @result = nil
32
29
  @errors = nil
33
30
  @messages = []
31
+ @tool_calls = nil
32
+ @tool_calls_raw = nil
34
33
  end
35
34
 
36
35
  def append role: nil, content: nil, messages: nil
@@ -61,7 +60,7 @@ class OxAiWorkers::ModuleRequest
61
60
  end
62
61
 
63
62
  def parseChoices(response)
64
- puts response.inspect
63
+ # puts response.inspect
65
64
  @tool_calls = []
66
65
  @result = response.dig("choices", 0, "message", "content")
67
66
  @tool_calls_raw = response.dig("choices", 0, "message", "tool_calls")
@@ -18,6 +18,6 @@ class OxAiWorkers::Request < OxAiWorkers::ModuleRequest
18
18
  end
19
19
 
20
20
  def completed?
21
- @result.present? or @errors.present? or @external_call.present?
21
+ @result.present? or @errors.present? or @tool_calls.present?
22
22
  end
23
23
  end
@@ -1,16 +1,7 @@
1
1
  # frozen_string_literal: true
2
+ require 'open3'
2
3
 
3
4
  module OxAiWorkers::Tool
4
- #
5
- # A calculator tool that falls back to the Google calculator widget
6
- #
7
- # Gem requirements:
8
- # gem "eqn", "~> 1.6.5"
9
- # gem "google_search_results", "~> 2.0.0"
10
- #
11
- # Usage:
12
- # calculator = OxAiWorkers::Tool::Calculator.new
13
- #
14
5
  class Eval
15
6
  extend OxAiWorkers::ToolDefinition
16
7
  include OxAiWorkers::DependencyHelper
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OxAiWorkers
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
 
@@ -14,14 +14,12 @@ en:
14
14
  description: "Save facts, nuances, and actions before clearing messages"
15
15
  text: "Listing important facts and nuances"
16
16
  monologue:
17
- steps:
18
- - "Step 1: Develop your own solution to the problem. Take initiative and make assumptions."
19
- - "Step 1.1: Wrap all your work for this step in the innerMonologue function."
20
- - "Step 2: Relate your solution to the task, improve it, and call the necessary functions step by step."
21
- - "Step 2.1: Interact with the user using the outerVoice and actionRequest functions during the process."
22
- - "Step 3: When the solution is ready, report it using the outerVoice function."
23
- - "Step 3.1: Save facts, nuances, and actions using the packHistory function."
24
- - "Step 4: Conclude the work with the actionRequest function, without repeating the response if it was already given with outerVoice."
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."
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."
25
23
  tool:
26
24
  eval:
27
25
  ruby:
@@ -15,12 +15,11 @@ ru:
15
15
  text: Перечисление важных фактов и нюансов
16
16
  monologue:
17
17
  - Шаг 1. Разработай собственное решение проблемы. Проявляй инициативу и делай предположения.
18
- - Шаг 1.1. Заключи все свои наработки для этого шага в функцию innerMonologue.
18
+ - Шаг 1.1. Заключи все свои наработки для этого шага в функцию ox_ai_workers_iterator__innerMonologue.
19
19
  - Шаг 2. Соотнеси свое решение с задачей, улучшай его и вызывай необходимые функции шаг за шагом.
20
- - Шаг 2.1. Во время работы используй функции outerVoice и actionRequest.
21
- - Шаг 3. Когда решение готово, сообщи о нем с помощью функции outerVoice.
22
- - Шаг 3.1. Сохрани факты, нюансы и действия с помощью функции packHistory.
23
- - Шаг 4. Заверши работу с помощью функции actionRequest, не повторяя ответ, если он уже был дан.
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.
24
23
  tool:
25
24
  eval:
26
25
  ruby:
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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Smolev
@@ -117,6 +117,7 @@ files:
117
117
  - README.md
118
118
  - Rakefile
119
119
  - lib/ox-ai-workers.rb
120
+ - lib/oxaiworkers/assistant/module_base.rb
120
121
  - lib/oxaiworkers/assistant/sysop.rb
121
122
  - lib/oxaiworkers/compatibility.rb
122
123
  - lib/oxaiworkers/delayed_request.rb