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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +50 -10
- data/lib/ox-ai-workers.rb +11 -0
- data/lib/oxaiworkers/assistant/module_base.rb +22 -0
- data/lib/oxaiworkers/assistant/sysop.rb +8 -7
- data/lib/oxaiworkers/delayed_request.rb +5 -3
- data/lib/oxaiworkers/iterator.rb +33 -10
- data/lib/oxaiworkers/module_request.rb +7 -8
- data/lib/oxaiworkers/request.rb +1 -1
- data/lib/oxaiworkers/tool/eval.rb +1 -10
- data/lib/oxaiworkers/version.rb +1 -1
- data/locales/en.system.yml +6 -8
- data/locales/ru.system.yml +4 -5
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6d3516a02ebb121bdf02d3de27e78ca5c71b893efa9a25b69217b9260819f7a
|
4
|
+
data.tar.gz: 4ef7a7ef32d76506b5eb4e852d77a0cf979ba40c2ed74d4635081a774bf65d20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a432bb010d43b81c4041dd01ef5bf141ad3c2a61a44690dad1d4bd20efd2e206d8e28f1618c8f6137517a8366f0e0fe25a446893e3815393599a5ba5bc34434c
|
7
|
+
data.tar.gz: 7a3932acb7227a48970deed5f131d016f83340f137a97efc1fb9b9b98ba6a8668f7ce9cf5247d4540d9ecebd3388af82d4a2cb08f31a987ba85b15d208fbb82e
|
data/CHANGELOG.md
CHANGED
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.
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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:
|
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?
|
data/lib/oxaiworkers/iterator.rb
CHANGED
@@ -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
|
-
|
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 << "#{
|
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.
|
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:
|
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")
|
data/lib/oxaiworkers/request.rb
CHANGED
@@ -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
|
data/lib/oxaiworkers/version.rb
CHANGED
data/locales/en.system.yml
CHANGED
@@ -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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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:
|
data/locales/ru.system.yml
CHANGED
@@ -15,12 +15,11 @@ ru:
|
|
15
15
|
text: Перечисление важных фактов и нюансов
|
16
16
|
monologue:
|
17
17
|
- Шаг 1. Разработай собственное решение проблемы. Проявляй инициативу и делай предположения.
|
18
|
-
- Шаг 1.1. Заключи все свои наработки для этого шага в функцию
|
18
|
+
- Шаг 1.1. Заключи все свои наработки для этого шага в функцию ox_ai_workers_iterator__innerMonologue.
|
19
19
|
- Шаг 2. Соотнеси свое решение с задачей, улучшай его и вызывай необходимые функции шаг за шагом.
|
20
|
-
- Шаг 2.1. Во время работы используй функции
|
21
|
-
- Шаг 3. Когда решение готово, сообщи о нем с помощью функции
|
22
|
-
- Шаг
|
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.
|
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
|