ox-ai-workers 0.2.5 → 0.3.1

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.
@@ -1,187 +1,182 @@
1
- class OxAiWorkers::Iterator < OxAiWorkers::StateTools
2
- extend OxAiWorkers::ToolDefinition
3
- attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones
1
+ # frozen_string_literal: true
4
2
 
5
- define_function :innerMonologue, description: I18n.t("oxaiworkers.iterator.inner_monologue.description") do
6
- property :speach, type: "string", description: I18n.t("oxaiworkers.iterator.inner_monologue.speach"), required: true
7
- end
3
+ module OxAiWorkers
4
+ class Iterator < OxAiWorkers::StateTools
5
+ extend OxAiWorkers::ToolDefinition
6
+ 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
8
8
 
9
- define_function :outerVoice, description: I18n.t("oxaiworkers.iterator.outer_voice.description") do
10
- property :text, type: "string", description: I18n.t("oxaiworkers.iterator.outer_voice.text"), required: true
11
- end
9
+ define_function :innerMonologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
10
+ property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
11
+ required: true
12
+ end
12
13
 
13
- define_function :actionRequest, description: I18n.t("oxaiworkers.iterator.action_request.description") do
14
- property :action, type: "string", description: I18n.t("oxaiworkers.iterator.action_request.action"), required: true
15
- end
14
+ define_function :outerVoice, description: I18n.t('oxaiworkers.iterator.outer_voice.description') do
15
+ property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.outer_voice.text'), required: true
16
+ end
16
17
 
17
- define_function :packHistory, description: I18n.t("oxaiworkers.iterator.pack_history.description") do
18
- property :text, type: "string", description: I18n.t("oxaiworkers.iterator.pack_history.text"), required: true
19
- end
18
+ define_function :actionRequest, description: I18n.t('oxaiworkers.iterator.action_request.description') do
19
+ property :action, type: 'string', description: I18n.t('oxaiworkers.iterator.action_request.action'),
20
+ required: true
21
+ end
20
22
 
21
- def initialize(worker:, role: nil, tools: [])
22
- puts "call: #{__method__}"
23
- @worker = worker
24
- @tools = [self] + tools
25
- @role = role
26
- @context = nil
27
- @monologue = I18n.t("oxaiworkers.iterator.monologue")
28
- cleanup()
23
+ define_function :packHistory, 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
+ end
29
26
 
30
- super()
31
- end
27
+ def initialize(worker:, role: nil, tools: [], on_inner_monologue: nil, on_outer_voice: nil, on_action_request: nil,
28
+ on_pack_history: nil)
29
+ puts "call: #{__method__}"
30
+ @worker = worker
31
+ @tools = [self] + tools
32
+ @role = role
33
+ @context = nil
34
+ @monologue = I18n.t('oxaiworkers.iterator.monologue')
32
35
 
33
- def cleanup
34
- @result = nil
35
- @queue = []
36
- @tasks = []
37
- @milestones = []
38
- @messages = []
39
- completeIteration()
40
- end
36
+ @on_inner_monologue = on_inner_monologue
37
+ @on_outer_voice = on_outer_voice
38
+ @on_action_request = on_action_request
39
+ @on_pack_history = on_pack_history
41
40
 
42
- def innerMonologue speach:
43
- puts Rainbow("monologue: #{speach}").yellow
44
- @queue.pop
45
- @queue << {role: :system, content: "#{__method__}: #{speach}"}
46
- return nil
47
- end
41
+ cleanup
48
42
 
49
- def outerVoice text:
50
- puts Rainbow("voice: #{text}").green
51
- @queue.pop
52
- @queue << {role: :system, content: "#{__method__}: #{text}"}
53
- return nil
54
- end
43
+ super()
44
+ end
55
45
 
56
- def actionRequest action:
57
- puts Rainbow("action: #{action}").red
58
- @result = action
59
- @queue.pop
60
- @messages << {role: :system, content: "#{__method__}: #{action}"}
61
- complete! if can_complete?
62
- return nil
63
- end
46
+ def cleanup
47
+ @result = nil
48
+ @queue = []
49
+ @tasks = []
50
+ @milestones = []
51
+ @messages = []
52
+ completeIteration
53
+ end
64
54
 
65
- def packHistory text:
66
- puts Rainbow("summarize: #{text}").blue
67
- @milestones << "#{__method__}: #{text}"
68
- @messages = []
69
- @worker.finish()
70
- rebuildWorker()
71
- complete! if can_complete?
72
- return nil
73
- end
55
+ def innerMonologue(speach:)
56
+ @queue.pop
57
+ @queue << { role: :system, content: "#{__method__}: #{speach}" }
58
+ @on_inner_monologue&.call(text: speach)
59
+ nil
60
+ end
74
61
 
75
- def init
76
- puts "call: #{__method__} state: #{state_name}"
77
- rebuildWorker()
78
- request!
79
- end
62
+ def outerVoice(text:)
63
+ @queue.pop
64
+ @queue << { role: :system, content: "#{__method__}: #{text}" }
65
+ @on_outer_voice&.call(text: text)
66
+ nil
67
+ end
80
68
 
81
- def rebuildWorker
82
- @worker.messages = []
83
- @worker.append(role: :system, content: @role) if !@role.nil? && @role.present?
84
- @worker.append(role: :system, content: @monologue.join("\n"))
85
- @worker.append(messages: @context) if !@context.nil? and @context.any?
86
- @tasks.each { |task| @worker.append(role: :user, content: task) }
87
- @milestones.each { |milestone| @worker.append(role: :system, content: milestone) }
88
- @worker.append(messages: @messages)
89
- @worker.tools = @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.any?
90
- end
69
+ def actionRequest(action:)
70
+ @result = action
71
+ @queue.pop
72
+ @messages << { role: :system, content: "#{__method__}: #{action}" }
73
+ complete! if can_complete?
74
+ @on_action_request&.call(text: action)
75
+ nil
76
+ end
91
77
 
92
- def nextIteration
93
- puts "call: #{__method__} state: #{state_name}"
94
- @worker.append(messages: @queue)
95
- @messages += @queue
96
- @queue = []
97
- request!
98
- end
78
+ def packHistory(text:)
79
+ @milestones << "#{__method__}: #{text}"
80
+ @messages = []
81
+ @worker.finish
82
+ rebuildWorker
83
+ complete! if can_complete?
84
+ @on_pack_history&.call(text: text)
85
+ nil
86
+ end
99
87
 
100
- def externalRequest
101
- puts "call: #{__method__} state: #{state_name}"
102
- @worker.request!()
103
- ticker()
104
- end
88
+ def init
89
+ puts "call: #{__method__} state: #{state_name}"
90
+ rebuildWorker
91
+ request!
92
+ end
105
93
 
106
- def ticker
107
- puts "call: #{__method__} state: #{state_name}"
108
- while !@worker.completed? do
109
- sleep(60)
94
+ def rebuildWorker
95
+ @worker.messages = []
96
+ @worker.append(role: :system, content: @role) if !@role.nil? && @role.present?
97
+ @worker.append(role: :system, content: @monologue.join("\n"))
98
+ @worker.append(messages: @context) if !@context.nil? and @context.any?
99
+ @tasks.each { |task| @worker.append(role: :user, content: task) }
100
+ @milestones.each { |milestone| @worker.append(role: :system, content: milestone) }
101
+ @worker.append(messages: @messages)
102
+ @worker.tools = @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.any?
103
+ end
104
+
105
+ def nextIteration
106
+ puts "call: #{__method__} state: #{state_name}"
107
+ @worker.append(messages: @queue)
108
+ @messages += @queue
109
+ @queue = []
110
+ request!
111
+ end
112
+
113
+ def externalRequest
114
+ puts "call: #{__method__} state: #{state_name}"
115
+ @worker.request!
116
+ ticker
117
+ end
118
+
119
+ def ticker
120
+ puts "call: #{__method__} state: #{state_name}"
121
+ sleep(60) until @worker.completed?
122
+ analyze!
110
123
  end
111
- analyze!
112
- end
113
124
 
114
- def processResult(transition)
115
- puts "call: #{__method__} state: #{state_name}"
116
- @result = @worker.result || @worker.errors
117
- if @worker.tool_calls.present?
118
- @queue << {role: :system, content: @worker.tool_calls_raw.to_s}
119
- @worker.tool_calls.each do |external_call|
120
- tool = @tools.select{|t| t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name]) }.first
121
- unless tool.nil?
122
- out = tool.send(external_call[:name], **external_call[:args])
123
- @queue << {role: :system, content: out.to_s} if out.present?
125
+ def processResult(_transition)
126
+ puts "call: #{__method__} state: #{state_name}"
127
+ @result = @worker.result || @worker.errors
128
+ if @worker.tool_calls.present?
129
+ @queue << { role: :system, content: @worker.tool_calls_raw.to_s }
130
+ @worker.tool_calls.each do |external_call|
131
+ tool = @tools.select do |t|
132
+ t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name])
133
+ end.first
134
+ unless tool.nil?
135
+ out = tool.send(external_call[:name], **external_call[:args])
136
+ @queue << { role: :system, content: out.to_s } if out.present?
137
+ end
124
138
  end
125
- end
126
- @worker.finish()
127
- iterate! if can_iterate?
128
-
129
- # tool = @tools.select{|t| t.class.tool_name == @worker.external_call[:class] && t.respond_to?(@worker.external_call[:name]) }.first
130
- # out = tool.send(@worker.external_call[:name], **@worker.external_call[:args])
131
- # if can_iterate?
132
- # @queue << {role: :system, content: out.to_s} if out.present?
133
- # iterate!
134
- # end
135
- elsif @worker.result.present?
139
+ @worker.finish
140
+ iterate! if can_iterate?
141
+
142
+ # tool = @tools.select{|t| t.class.tool_name == @worker.external_call[:class] && t.respond_to?(@worker.external_call[:name]) }.first
143
+ # out = tool.send(@worker.external_call[:name], **@worker.external_call[:args])
144
+ # if can_iterate?
145
+ # @queue << {role: :system, content: out.to_s} if out.present?
146
+ # iterate!
147
+ # end
148
+ elsif @worker.result.present?
136
149
  actionRequest action: @worker.result
150
+ end
137
151
  end
138
- end
139
152
 
140
- def completeIteration
141
- @queue = []
142
- @worker.finish()
143
- end
144
-
145
- def addTask task, auto_execute: true
146
- @tasks << task
147
- @messages << {role: :user, content: task}
148
- execute() if auto_execute
149
- end
153
+ def completeIteration
154
+ @queue = []
155
+ @worker.finish
156
+ end
150
157
 
151
- def appendContext text, role: :system
152
- @context << {role: role, content: text}
153
- end
158
+ def addTask(task, auto_execute: true)
159
+ @tasks << task
160
+ @messages << { role: :user, content: task }
161
+ execute if auto_execute
162
+ end
154
163
 
155
- def execute
156
- puts "call: #{__method__} state: #{state_name}"
157
- prepare! if valid?
158
- end
164
+ def appendContext(text, role: :system)
165
+ @context << { role: role, content: text }
166
+ end
159
167
 
160
- def cancel
161
- puts "call: #{__method__} state: #{state_name}"
162
- @worker.cancel if @worker.respond_to?(:cancel)
163
- end
168
+ def execute
169
+ puts "call: #{__method__} state: #{state_name}"
170
+ prepare! if valid?
171
+ end
164
172
 
165
- def valid?
166
- @messages.any?
167
- end
173
+ def cancel
174
+ puts "call: #{__method__} state: #{state_name}"
175
+ @worker.cancel if @worker.respond_to?(:cancel)
176
+ end
168
177
 
178
+ def valid?
179
+ @messages.any?
180
+ end
181
+ end
169
182
  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
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'i18n'
4
+ I18n.load_path += Dir["#{File.expand_path('locales')}/*.yml"]
@@ -1,82 +1,82 @@
1
- class OxAiWorkers::ModuleRequest
2
- attr_accessor :result, :client, :messages, :model, :max_tokens, :custom_id, :temperature, :tools, :errors
3
- attr_accessor :tool_calls_raw, :tool_calls
1
+ # frozen_string_literal: true
4
2
 
5
- def initializeRequests(model: nil, max_tokens: nil, temperature: nil)
6
- puts "call: ModuleRequest::#{__method__}"
7
- @max_tokens = max_tokens || OxAiWorkers.configuration.max_tokens
8
- @custom_id = SecureRandom.uuid
9
- @model = model || OxAiWorkers.configuration.model
10
- @temperature = temperature || OxAiWorkers.configuration.temperature
11
- @client = nil
12
-
13
- OxAiWorkers.configuration.access_token ||= ENV["OPENAI"]
14
- if OxAiWorkers.configuration.access_token.nil?
15
- error_text = "OpenAi access token missing!"
16
- raise OxAiWorkers::ConfigurationError, error_text
17
- end
3
+ module OxAiWorkers
4
+ class ModuleRequest
5
+ attr_accessor :result, :client, :messages, :model, :max_tokens, :custom_id, :temperature, :tools, :errors,
6
+ :tool_calls_raw, :tool_calls
18
7
 
19
- cleanup()
20
- end
8
+ def initializeRequests(model: nil, max_tokens: nil, temperature: nil)
9
+ puts "call: ModuleRequest::#{__method__}"
10
+ @max_tokens = max_tokens || OxAiWorkers.configuration.max_tokens
11
+ @custom_id = SecureRandom.uuid
12
+ @model = model || OxAiWorkers.configuration.model
13
+ @temperature = temperature || OxAiWorkers.configuration.temperature
14
+ @client = nil
21
15
 
22
- def cleanup
23
- puts "call: ModuleRequest::#{__method__}"
24
- @client ||= OpenAI::Client.new(
25
- access_token: OxAiWorkers.configuration.access_token,
26
- log_errors: true # Highly recommended in development, so you can see what errors OpenAI is returning. Not recommended in production because it could leak private data to your logs.
27
- )
28
- @result = nil
29
- @errors = nil
30
- @messages = []
31
- @tool_calls = nil
32
- @tool_calls_raw = nil
33
- end
16
+ OxAiWorkers.configuration.access_token ||= ENV['OPENAI']
17
+ if OxAiWorkers.configuration.access_token.nil?
18
+ error_text = 'OpenAi access token missing!'
19
+ raise OxAiWorkers::ConfigurationError, error_text
20
+ end
34
21
 
35
- def append role: nil, content: nil, messages: nil
36
- @messages << {role: role, content: content} if role.present? and content.present?
37
- @messages += messages if messages.present?
38
- end
22
+ cleanup
23
+ end
24
+
25
+ def cleanup
26
+ puts "call: ModuleRequest::#{__method__}"
27
+ @client ||= OpenAI::Client.new(
28
+ access_token: OxAiWorkers.configuration.access_token,
29
+ log_errors: true # Highly recommended in development, so you can see what errors OpenAI is returning. Not recommended in production because it could leak private data to your logs.
30
+ )
31
+ @result = nil
32
+ @errors = nil
33
+ @messages = []
34
+ @tool_calls = nil
35
+ @tool_calls_raw = nil
36
+ end
39
37
 
40
- def params
41
- parameters = {
38
+ def append(role: nil, content: nil, messages: nil)
39
+ @messages << { role: role, content: content } if role.present? and content.present?
40
+ @messages += messages if messages.present?
41
+ end
42
+
43
+ def params
44
+ parameters = {
42
45
  model: @model,
43
46
  messages: @messages,
44
47
  temperature: @temperature,
45
48
  max_tokens: @max_tokens
46
49
  }
47
- if @tools.present?
48
- parameters[:tools] = @tools
49
- parameters[:tool_choice] = "required"
50
+ if @tools.present?
51
+ parameters[:tools] = @tools
52
+ parameters[:tool_choice] = 'required'
53
+ end
54
+ parameters
50
55
  end
51
- parameters
52
- end
53
56
 
54
- def not_found_is_ok &block
55
- begin
57
+ def not_found_is_ok
56
58
  yield
57
59
  rescue Faraday::ResourceNotFound => e
58
60
  nil
59
61
  end
60
- end
61
62
 
62
- def parseChoices(response)
63
- # puts response.inspect
64
- @tool_calls = []
65
- @result = response.dig("choices", 0, "message", "content")
66
- @tool_calls_raw = response.dig("choices", 0, "message", "tool_calls")
63
+ def parseChoices(response)
64
+ # puts response.inspect
65
+ @tool_calls = []
66
+ @result = response.dig('choices', 0, 'message', 'content')
67
+ @tool_calls_raw = response.dig('choices', 0, 'message', 'tool_calls')
67
68
 
68
- @tool_calls_raw.each do |tool|
69
- function = tool["function"]
70
- args = JSON.parse(YAML.load(function["arguments"]).to_json, { symbolize_names: true } )
71
- @tool_calls << {
72
- class: function["name"].split("__").first,
73
- name: function["name"].split("__").last,
74
- args: args
75
- }
76
- end
77
-
78
- @tool_calls
69
+ @tool_calls_raw.each do |tool|
70
+ function = tool['function']
71
+ args = JSON.parse(YAML.load(function['arguments']).to_json, { symbolize_names: true })
72
+ @tool_calls << {
73
+ class: function['name'].split('__').first,
74
+ name: function['name'].split('__').last,
75
+ args: args
76
+ }
77
+ end
79
78
 
80
- # Assistant.send(function_name, **args)
79
+ @tool_calls
80
+ end
81
81
  end
82
- end
82
+ end
@@ -1,29 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OxAiWorkers
2
- module PresentCompat
3
- def present?
4
- !self.nil? and !self.empty?
5
- end
6
- end
4
+ module PresentCompat
5
+ def present?
6
+ !nil? and !empty?
7
+ end
8
+ end
9
+
10
+ module CamelizeCompat
11
+ def camelize(first_letter = :upper)
12
+ string = dup
13
+ string = if first_letter == :upper
14
+ string.sub(/^[a-z\d]*/) { |match| match.capitalize }
15
+ else
16
+ string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
17
+ end
18
+ string.gsub(%r{(?:_|(/))([a-z\d]*)}) do
19
+ "#{::Regexp.last_match(1)}#{::Regexp.last_match(2).capitalize}"
20
+ end.gsub('/', '::')
21
+ end
7
22
 
8
- module CamelizeCompat
9
- def camelize(first_letter = :upper)
10
- string = self.dup
11
- if first_letter == :upper
12
- string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
13
- else
14
- string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
15
- end
16
- string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub("/", "::")
17
- end
18
-
19
- def underscore
20
- word = self.dup
21
- word.gsub!(/::/, '/')
22
- word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
23
- word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
24
- word.tr!("-", "_")
25
- word.downcase!
26
- word
27
- end
28
- end
29
- end
23
+ def underscore
24
+ word = dup
25
+ word.gsub!(/::/, '/')
26
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
27
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
28
+ word.tr!('-', '_')
29
+ word.downcase!
30
+ word
31
+ end
32
+ end
33
+ end
@@ -1,23 +1,25 @@
1
- class OxAiWorkers::Request < OxAiWorkers::ModuleRequest
2
- alias_method :initialize, :initializeRequests
1
+ # frozen_string_literal: true
3
2
 
4
- def finish
5
- @custom_id = SecureRandom.uuid
6
- cleanup()
7
- end
3
+ module OxAiWorkers
4
+ class Request < OxAiWorkers::ModuleRequest
5
+ alias initialize initializeRequests
6
+
7
+ def finish
8
+ @custom_id = SecureRandom.uuid
9
+ cleanup
10
+ end
8
11
 
9
- def request!
10
- begin
12
+ def request!
11
13
  response = @client.chat(parameters: params)
12
14
  parseChoices(response)
13
- #@result = response.dig("choices", 0, "message", "content")
14
- #puts response.inspect
15
+ # @result = response.dig("choices", 0, "message", "content")
16
+ # puts response.inspect
15
17
  rescue OpenAI::Error => e
16
18
  puts e.inspect
17
19
  end
18
- end
19
20
 
20
- def completed?
21
- @result.present? or @errors.present? or @tool_calls.present?
21
+ def completed?
22
+ @result.present? or @errors.present? or @tool_calls.present?
23
+ end
22
24
  end
23
25
  end