ox-ai-workers 0.7.2 → 0.7.5
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/.cursorrules +69 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -4
- data/app/models/task.rb +10 -0
- data/config/locales/en.oxaiworkers.iterator.yml +3 -1
- data/config/locales/ru.oxaiworkers.iterator.yml +4 -4
- data/lib/oxaiworkers/delayed_request.rb +6 -1
- data/lib/oxaiworkers/iterator.rb +15 -10
- data/lib/oxaiworkers/module_request.rb +9 -1
- data/lib/oxaiworkers/request.rb +4 -0
- data/lib/oxaiworkers/state_helper.rb +1 -1
- data/lib/oxaiworkers/version.rb +1 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a6d42d123d2331ff4ebe6fde17c6cd64759933f64940dcf453eca6dc5efb402
|
4
|
+
data.tar.gz: 19bfa6c66009d2856ecb983d7375beceb40a9d1edf0cf7cd304cfa61529450e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 638dea1186324159ebbcacd5f3714aa302ba2e6b5a8a4883cda35feb06ae327f96a0e783ff7c007be090de99f157cf2e35b0d0287f228719c278f1dd8cf9c616
|
7
|
+
data.tar.gz: 0713c7d9f42db7873d70023cabafc4b7e0647e2fe59f76f0d469de530d405d67c8677a989d967bad0317891de9a609293995ab5d68ea7382f39d92aaaa739f4d
|
data/.cursorrules
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
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.
|
2
|
+
|
3
|
+
## Architecture Principles
|
4
|
+
- The library is built on the finite state machine (FSM) pattern using the 'state_machine' gem
|
5
|
+
- Integration with generative models is implemented using the 'ruby-openai' gem
|
6
|
+
- DRY (Don't Repeat Yourself) principle is applied throughout all components
|
7
|
+
- Modular structure with clear separation of responsibilities between classes
|
8
|
+
- Encapsulation of states and transitions in separate classes
|
9
|
+
- Implementation of the "Composition" pattern for flexible tool integration
|
10
|
+
|
11
|
+
## Core Components
|
12
|
+
- `Request` and `DelayedRequest` - classes for executing API requests (immediate and delayed)
|
13
|
+
- `Iterator` - main class for iterative task execution with tools
|
14
|
+
- `Assistant` - high-level wrappers over Iterator (Sysop, Coder, Localizer, etc.)
|
15
|
+
- `Tool` - tools that can be used during task execution (Eval, FileSystem, Database)
|
16
|
+
- `ToolDefinition` - module for declaring functions and methods for tools
|
17
|
+
- `StateTools` - base class for managing states and transitions
|
18
|
+
- `ContextualLogger` - logging system with contextual information support
|
19
|
+
|
20
|
+
## Code Conventions
|
21
|
+
- Use `snake_case` for method and variable names
|
22
|
+
- Functions for generative models should also be in `snake_case` (inner_monologue, outer_voice, etc.)
|
23
|
+
- All public methods must have documentation with usage examples
|
24
|
+
- Tests are mandatory for all new functions
|
25
|
+
- All code comments, CHANGELOG, README, and other documentation must be written in English
|
26
|
+
- Use YARD-style documentation for all public methods
|
27
|
+
- Maintain a unified code formatting style (Rubocop is recommended)
|
28
|
+
- Follow the "Fail fast" principle for early error detection
|
29
|
+
|
30
|
+
## Interaction Patterns
|
31
|
+
- The system uses internal monologue (inner_monologue) for planning actions
|
32
|
+
- External voice (outer_voice) is used for communication with the user
|
33
|
+
- Actions (action_request) are executed through tools
|
34
|
+
- Summary (summarize) is used to compress dialog history
|
35
|
+
- Execution flow management through finite state machine
|
36
|
+
- Implementation of callback mechanisms for flexible event handling
|
37
|
+
- Isolation of error handling functions at the tool level
|
38
|
+
|
39
|
+
## Integration
|
40
|
+
- CLI interface through `oxaiworkers init` and `oxaiworkers run` commands
|
41
|
+
- Rails support via ActiveRecord for storing delayed requests
|
42
|
+
- Configuration through the `OxAiWorkers.configure` block
|
43
|
+
- Multilingual support via standard I18n
|
44
|
+
- Integration with external APIs through request client templates
|
45
|
+
- Delayed execution mechanism via DelayedRequest
|
46
|
+
- Support for various language models (OpenAI, Anthropic, Gemini)
|
47
|
+
|
48
|
+
## Best Practices
|
49
|
+
- Use callbacks to handle various states (on_inner_monologue, on_outer_voice)
|
50
|
+
- Handle errors at the tool level, preventing them from interrupting the main execution flow
|
51
|
+
- When creating new assistants, inherit from the base Assistant class
|
52
|
+
- Use the white_list mechanism to restrict available functions
|
53
|
+
- Separate language model requests from result processing logic
|
54
|
+
- Practice dependency injection to improve code testability
|
55
|
+
- Use localization mechanisms for multilingual support
|
56
|
+
|
57
|
+
## Tools Architecture
|
58
|
+
- Each tool should be a self-contained module
|
59
|
+
- Tools are registered through the `define_function` interface
|
60
|
+
- All tools should handle their own errors and return readable messages
|
61
|
+
- Use parameter validation at the function definition level
|
62
|
+
- Maintain a unified format for return values
|
63
|
+
|
64
|
+
## Performance and Scaling
|
65
|
+
- Cache API request results when possible
|
66
|
+
- Use asynchronous processing for long operations
|
67
|
+
- Apply backoff strategies for repeated requests
|
68
|
+
- Break large tasks into atomic operations
|
69
|
+
- Provide monitoring and profiling mechanisms
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.4.1
|
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,31 @@
|
|
1
|
-
## [0.7.
|
1
|
+
## [0.7.5] - 2024-08-26
|
2
|
+
|
3
|
+
- Improved handling of truncated responses in Iterator
|
4
|
+
- Updated dependencies
|
5
|
+
|
6
|
+
## [0.7.4] - 2024-08-25
|
7
|
+
|
8
|
+
- Fixed `finish_it` for `Iterator`
|
9
|
+
|
10
|
+
## [0.7.2] - 2024-08-25
|
11
|
+
|
12
|
+
- Fixed tool calls in `Iterator`
|
13
|
+
|
14
|
+
## [0.7.1] - 2024-08-24
|
2
15
|
|
3
16
|
- Added retry for `Iterator`
|
4
17
|
|
5
|
-
## [0.7.0] - 2024-08-
|
18
|
+
## [0.7.0] - 2024-08-24
|
6
19
|
|
7
20
|
- Added `finish` for `Iterator`
|
8
21
|
- Added `after_finish` for `Iterator`
|
9
22
|
|
10
|
-
## [0.6.3] - 2024-08-
|
23
|
+
## [0.6.3] - 2024-08-24
|
11
24
|
|
12
25
|
- Added `add_raw_context` for `Iterator`
|
13
26
|
- Fixed `requested?`
|
14
27
|
|
15
|
-
## [0.6.2] - 2024-08-
|
28
|
+
## [0.6.2] - 2024-08-24
|
16
29
|
|
17
30
|
- Rails ActiveRecord support
|
18
31
|
|
data/app/models/task.rb
ADDED
@@ -14,10 +14,12 @@ en:
|
|
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
|
17
|
+
finish_it:
|
18
|
+
description: Function to complete steps
|
17
19
|
monologue:
|
18
20
|
- Step %d. Develop your own solution to the problem, taking initiative and making assumptions.
|
19
21
|
- Step %d. Enclose all your developments from the previous step in the ox_ai_workers_iterator__inner_monologue function.
|
20
22
|
- Step %d. Call the necessary functions one after another until the desired result is achieved.
|
21
23
|
- Step %d. 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
24
|
- Step %d. When the solution is ready, notify about it and wait for the user's response.
|
23
|
-
- Step %d. In the end, call the
|
25
|
+
- Step %d. In the end, call the ox_ai_workers_iterator__finish_it function.
|
@@ -14,12 +14,12 @@ ru:
|
|
14
14
|
description: Функция сохраняет ключевые факты, нюансы и действия из предыдущих сообщений, включая предоставленный ответ. После вызова этой функции все предыдущие сообщения будут удалены. Используйте её только после завершения всех промежуточных шагов и когда точное содержание предыдущих сообщений больше не имеет значения.
|
15
15
|
text: Перечисление важных фактов и нюансов
|
16
16
|
result: Сообщения удалены
|
17
|
-
|
18
|
-
description: Функция для завершения
|
17
|
+
finish_it:
|
18
|
+
description: Функция для завершения шагов
|
19
19
|
monologue:
|
20
20
|
- Шаг %d. Разработай собственное решение проблемы, проявляй инициативу и делай предположения.
|
21
21
|
- Шаг %d. Заключи все свои наработки из предыдущего шага в функцию ox_ai_workers_iterator__inner_monologue.
|
22
|
-
- Шаг %d. Вызывай необходимые функции друг за другом, пока
|
22
|
+
- Шаг %d. Вызывай необходимые функции друг за другом, пока результат не будет достигнут.
|
23
23
|
- Шаг %d. Когда все промежуточные шаги завершены и точное содержание предыдущих сообщений больше не имеет значения, используй функцию ox_ai_workers_iterator__summarize.
|
24
24
|
- Шаг %d. Когда решение готово, сообщи об этом с помощью функции ox_ai_workers_iterator__action_request и ожидай ответ пользователя.
|
25
|
-
- Шаг %d. В конце вызови функцию
|
25
|
+
- Шаг %d. В конце вызови функцию ox_ai_workers_iterator__finish_it.
|
@@ -97,12 +97,17 @@ module OxAiWorkers
|
|
97
97
|
@custom_id = line['custom_id']
|
98
98
|
# @result = line.dig("response", "body", "choices", 0, "message", "content")
|
99
99
|
parse_choices(line.dig('response', 'body'))
|
100
|
-
|
100
|
+
# Don't complete the batch if the response is truncated due to max_tokens
|
101
|
+
complete_batch! unless @is_truncated
|
101
102
|
end
|
102
103
|
elsif !batch['error_file_id'].nil?
|
103
104
|
@errors = @client.files.content(id: batch['error_file_id'])
|
104
105
|
fail_batch!
|
105
106
|
end
|
107
|
+
|
108
|
+
# Truncated response is not considered complete
|
109
|
+
return false if @is_truncated
|
110
|
+
|
106
111
|
true
|
107
112
|
end
|
108
113
|
end
|
data/lib/oxaiworkers/iterator.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module OxAiWorkers
|
4
4
|
class Iterator < OxAiWorkers::StateTools
|
5
|
-
ITERATOR_FUNCTIONS = %i[inner_monologue outer_voice action_request summarize].freeze
|
5
|
+
ITERATOR_FUNCTIONS = %i[inner_monologue outer_voice action_request summarize finish_it].freeze
|
6
6
|
|
7
7
|
include OxAiWorkers::ToolDefinition
|
8
8
|
include OxAiWorkers::LoadI18n
|
@@ -34,7 +34,7 @@ module OxAiWorkers
|
|
34
34
|
property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.summarize.text'), required: true
|
35
35
|
end
|
36
36
|
|
37
|
-
define_function :
|
37
|
+
define_function :finish_it, description: I18n.t('oxaiworkers.iterator.finish_it.description')
|
38
38
|
|
39
39
|
@monologue = steps || I18n.t('oxaiworkers.iterator.monologue')
|
40
40
|
end
|
@@ -102,7 +102,7 @@ module OxAiWorkers
|
|
102
102
|
nil
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
105
|
+
def finish_it
|
106
106
|
complete! if can_complete?
|
107
107
|
@after_finish&.call
|
108
108
|
nil
|
@@ -185,12 +185,6 @@ module OxAiWorkers
|
|
185
185
|
OxAiWorkers.logger.warn "Iterator::ServerError #{e.message}. Waiting 10 seconds..."
|
186
186
|
sleep(10)
|
187
187
|
external_request
|
188
|
-
# rescue Faraday::ForbiddenError => e
|
189
|
-
# OxAiWorkers.logger.error "Iterator::ForbiddenError #{e.inspect}", for: self.class
|
190
|
-
# rescue StandardError => e
|
191
|
-
# OxAiWorkers.logger.error "Iterator::StandardError #{e.inspect}", for: self.class
|
192
|
-
# rescue OpenAI::Error => e
|
193
|
-
# OxAiWorkers.logger.error "Iterator::OpenAI::Error #{e.inspect}", for: self.class
|
194
188
|
end
|
195
189
|
|
196
190
|
def tick_or_wait
|
@@ -212,10 +206,21 @@ module OxAiWorkers
|
|
212
206
|
return unless requested?
|
213
207
|
|
214
208
|
sleep(60) unless ticker
|
215
|
-
analyze!
|
216
209
|
end
|
217
210
|
|
218
211
|
def process_result(_transition)
|
212
|
+
# If the response is truncated due to max_tokens, repeat the request
|
213
|
+
if @worker.is_truncated && @worker.result.present?
|
214
|
+
# Save the partial response and continue the dialogue with AI
|
215
|
+
OxAiWorkers.logger.info(
|
216
|
+
"Truncated response detected (finish_reason: #{@worker.finish_reason}). Repeating request to get complete response.", for: self.class
|
217
|
+
)
|
218
|
+
@queue << { role: :assistant, content: @worker.result }
|
219
|
+
# Request continuation
|
220
|
+
next_iteration
|
221
|
+
return
|
222
|
+
end
|
223
|
+
|
219
224
|
@result = @worker.result || @worker.errors
|
220
225
|
if @worker.tool_calls.present?
|
221
226
|
@queue << { role: :assistant, content: @worker.tool_calls_raw.to_s }
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module OxAiWorkers
|
4
4
|
class ModuleRequest
|
5
5
|
attr_accessor :result, :client, :messages, :model, :max_tokens, :custom_id, :temperature, :tools, :errors,
|
6
|
-
:tool_calls_raw, :tool_calls
|
6
|
+
:tool_calls_raw, :tool_calls, :is_truncated, :finish_reason
|
7
7
|
|
8
8
|
def initialize_requests(model: nil, max_tokens: nil, temperature: nil)
|
9
9
|
@max_tokens = max_tokens || OxAiWorkers.configuration.max_tokens
|
@@ -11,6 +11,8 @@ module OxAiWorkers
|
|
11
11
|
@model = model || OxAiWorkers.configuration.model
|
12
12
|
@temperature = temperature || OxAiWorkers.configuration.temperature
|
13
13
|
@client = nil
|
14
|
+
@is_truncated = false
|
15
|
+
@finish_reason = nil
|
14
16
|
|
15
17
|
OxAiWorkers.configuration.access_token ||= ENV['OPENAI']
|
16
18
|
if OxAiWorkers.configuration.access_token.nil?
|
@@ -31,6 +33,8 @@ module OxAiWorkers
|
|
31
33
|
@messages = []
|
32
34
|
@tool_calls = nil
|
33
35
|
@tool_calls_raw = nil
|
36
|
+
@is_truncated = false
|
37
|
+
@finish_reason = nil
|
34
38
|
end
|
35
39
|
|
36
40
|
def append(role: nil, content: nil, messages: nil)
|
@@ -62,6 +66,10 @@ module OxAiWorkers
|
|
62
66
|
@tool_calls = []
|
63
67
|
@result = response.dig('choices', 0, 'message', 'content')
|
64
68
|
@tool_calls_raw = response.dig('choices', 0, 'message', 'tool_calls')
|
69
|
+
@finish_reason = response.dig('choices', 0, 'finish_reason')
|
70
|
+
@is_truncated = @finish_reason == 'length'
|
71
|
+
|
72
|
+
return @tool_calls if @tool_calls_raw.nil?
|
65
73
|
|
66
74
|
@tool_calls_raw.each do |tool|
|
67
75
|
function = tool['function']
|
data/lib/oxaiworkers/request.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module OxAiWorkers
|
4
4
|
module StateHelper
|
5
5
|
def log_me(transition)
|
6
|
-
# OxAiWorkers.logger.
|
6
|
+
# OxAiWorkers.logger.info("`#{transition.event}` was called to transition from :#{transition.from} to :#{transition.to}")
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/lib/oxaiworkers/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ox-ai-workers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Smolev
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-01 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: colorize
|
@@ -124,12 +123,14 @@ executables:
|
|
124
123
|
extensions: []
|
125
124
|
extra_rdoc_files: []
|
126
125
|
files:
|
126
|
+
- ".cursorrules"
|
127
127
|
- ".ruby-version"
|
128
128
|
- CHANGELOG.md
|
129
129
|
- CODE_OF_CONDUCT.md
|
130
130
|
- LICENSE
|
131
131
|
- README.md
|
132
132
|
- Rakefile
|
133
|
+
- app/models/task.rb
|
133
134
|
- config/locales/en.oxaiworkers.assistant.yml
|
134
135
|
- config/locales/en.oxaiworkers.iterator.yml
|
135
136
|
- config/locales/en.oxaiworkers.tool.yml
|
@@ -173,7 +174,6 @@ metadata:
|
|
173
174
|
homepage_uri: https://ai.oxteam.me
|
174
175
|
source_code_uri: https://github.com/neonix20b/ox-ai-workers
|
175
176
|
changelog_uri: https://github.com/neonix20b/ox-ai-workers/blob/main/CHANGELOG.md
|
176
|
-
post_install_message:
|
177
177
|
rdoc_options: []
|
178
178
|
require_paths:
|
179
179
|
- lib
|
@@ -188,8 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
188
|
- !ruby/object:Gem::Version
|
189
189
|
version: '0'
|
190
190
|
requirements: []
|
191
|
-
rubygems_version: 3.
|
192
|
-
signing_key:
|
191
|
+
rubygems_version: 3.6.3
|
193
192
|
specification_version: 4
|
194
193
|
summary: A powerful state machine with OpenAI generative intelligence integration
|
195
194
|
test_files: []
|