ox-ai-workers 0.5.3.1 → 0.5.4
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 +4 -0
- data/README.md +12 -10
- data/lib/oxaiworkers/assistant/coder.rb +1 -1
- data/lib/oxaiworkers/assistant/localizer.rb +1 -1
- data/lib/oxaiworkers/assistant/sysop.rb +1 -1
- data/lib/oxaiworkers/iterator.rb +27 -13
- data/lib/oxaiworkers/tool_definition.rb +23 -7
- data/lib/oxaiworkers/version.rb +1 -1
- data/locales/en.iterator.yml +2 -2
- data/locales/ru.iterator.yml +2 -2
- data/template/my_assistant.rb +3 -3
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67dfa0fc5c5cb3c3c223615ec1386324b1a71fdc38d90db9b78c6c94f0136add
|
4
|
+
data.tar.gz: 555689bc0e7d83a854f0614d13aed065b2634bdf4501a9aa2025fc40736db398
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 374c51ea659b98605131b46e1ffbffbfc3ec5d9d6c5718f64952e630e2a14adec56412776eadc4c074ead54c8197fc0195b9590dd76d0737dd7fff347b5ab236
|
7
|
+
data.tar.gz: 21714fc9c30d3159c756ce53840a598c163bca8547e7425e86ffd6ef86c78b5c3563c3a5b5d415420d3141c45d68c87f289d55436796bfa17cc83e4a4b963ab9
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
[](https://rubygems.org/gems/ox-ai-workers)
|
2
|
-
|
3
1
|
# OxAiWorkers (ox-ai-workers)
|
4
2
|
|
3
|
+
[](https://rubygems.org/gems/ox-ai-workers)
|
4
|
+
|
5
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.
|
6
6
|
|
7
7
|
## Installation
|
@@ -96,7 +96,7 @@ Then you can create an assistant like this:
|
|
96
96
|
|
97
97
|
```ruby
|
98
98
|
assistant = OxAiWorkers::Assistant::Sysop.new()
|
99
|
-
assistant.task = "
|
99
|
+
assistant.task = "Remove all cron jobs."
|
100
100
|
|
101
101
|
# Provide a response to the assistant's question
|
102
102
|
assistant.add_response("blah-blah-blah")
|
@@ -115,7 +115,7 @@ iterator = OxAiWorkers::Iterator.new(
|
|
115
115
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
116
116
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
117
117
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
118
|
-
|
118
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
119
119
|
)
|
120
120
|
|
121
121
|
iterator.add_task("Show files in current directory.")
|
@@ -130,9 +130,9 @@ This way, you have the flexibility to choose between a higher-level assistant fo
|
|
130
130
|
```ruby
|
131
131
|
steps = []
|
132
132
|
steps << 'Step 1. Develop your own solution to the problem, taking initiative and making assumptions.'
|
133
|
-
steps <<
|
133
|
+
steps << "Step 2. Enclose all your developments from the previous step in the #{OxAiWorkers::Iterator.full_function_name(:inner_monologue)} function."
|
134
134
|
steps << 'Step 3. Call the necessary functions one after another until the desired result is achieved.'
|
135
|
-
steps <<
|
135
|
+
steps << "Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the #{OxAiWorkers::Iterator.full_function_name(:summarize)} function."
|
136
136
|
steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
|
137
137
|
|
138
138
|
@iterator = OxAiWorkers::Iterator.new(
|
@@ -140,10 +140,12 @@ steps << "Step 5. When the solution is ready, notify about it and wait for the u
|
|
140
140
|
role: 'You are a software agent inside my computer',
|
141
141
|
tools: [MyTool.new],
|
142
142
|
steps: steps,
|
143
|
+
# def_except: [:summarize], # It's except steps with that functions
|
144
|
+
# def_only: [:inner_monologue, :outer_voice], # Use it only with your steps
|
143
145
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
144
146
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
145
147
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
146
|
-
|
148
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
147
149
|
)
|
148
150
|
```
|
149
151
|
|
@@ -165,7 +167,7 @@ As a worker, you can use different classes depending on your needs:
|
|
165
167
|
oxaiworkers init
|
166
168
|
```
|
167
169
|
|
168
|
-
This will create a `.oxaiworkers-local` directory with the necessary initial source code.
|
170
|
+
This will create a `.oxaiworkers-local` directory with the necessary initial source code.
|
169
171
|
|
170
172
|
Additionally, you can initialize a more comprehensive example using the command:
|
171
173
|
|
@@ -199,7 +201,7 @@ OxAiWorkers.logger.level = :debug
|
|
199
201
|
|
200
202
|
## Contributing
|
201
203
|
|
202
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/neonix20b/ox-ai-workers
|
204
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/neonix20b/ox-ai-workers>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
|
203
205
|
|
204
206
|
## License
|
205
207
|
|
@@ -207,4 +209,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
207
209
|
|
208
210
|
## Code of Conduct
|
209
211
|
|
210
|
-
Everyone interacting in the OxAiWorkers project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
|
212
|
+
Everyone interacting in the OxAiWorkers project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
|
@@ -13,7 +13,7 @@ module OxAiWorkers
|
|
13
13
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
14
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
15
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
16
|
-
|
16
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
17
17
|
)
|
18
18
|
end
|
19
19
|
end
|
@@ -13,7 +13,7 @@ module OxAiWorkers
|
|
13
13
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
14
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
15
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
16
|
-
|
16
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
17
17
|
)
|
18
18
|
@iterator.add_context(format(I18n.t('oxaiworkers.assistant.localizer.source'), source))
|
19
19
|
|
@@ -13,7 +13,7 @@ module OxAiWorkers
|
|
13
13
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
14
14
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
15
15
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
16
|
-
|
16
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
17
17
|
)
|
18
18
|
end
|
19
19
|
end
|
data/lib/oxaiworkers/iterator.rb
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
module OxAiWorkers
|
4
4
|
class Iterator < OxAiWorkers::StateTools
|
5
|
+
ITERATOR_FUNCTIONS = %i[inner_monologue outer_voice action_request summarize].freeze
|
6
|
+
|
5
7
|
extend OxAiWorkers::ToolDefinition
|
6
8
|
attr_accessor :worker, :role, :messages, :context, :result, :tools, :queue, :monologue, :tasks, :milestones
|
7
|
-
attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :
|
9
|
+
attr_accessor :on_inner_monologue, :on_outer_voice, :on_action_request, :on_summarize, :def_except, :def_only
|
8
10
|
|
9
11
|
define_function :inner_monologue, description: I18n.t('oxaiworkers.iterator.inner_monologue.description') do
|
10
12
|
property :speach, type: 'string', description: I18n.t('oxaiworkers.iterator.inner_monologue.speach'),
|
@@ -20,22 +22,24 @@ module OxAiWorkers
|
|
20
22
|
required: true
|
21
23
|
end
|
22
24
|
|
23
|
-
define_function :summarize, description: I18n.t('oxaiworkers.iterator.
|
24
|
-
property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.
|
25
|
+
define_function :summarize, description: I18n.t('oxaiworkers.iterator.summarize.description') do
|
26
|
+
property :text, type: 'string', description: I18n.t('oxaiworkers.iterator.summarize.text'), required: true
|
25
27
|
end
|
26
28
|
|
27
29
|
def initialize(worker:, role: nil, tools: [], on_inner_monologue: nil, on_outer_voice: nil, on_action_request: nil,
|
28
|
-
|
30
|
+
on_summarize: nil, steps: nil, def_except: [], def_only: nil)
|
29
31
|
@worker = worker
|
30
|
-
@tools =
|
32
|
+
@tools = tools
|
31
33
|
@role = role
|
32
34
|
@context = []
|
35
|
+
@def_only = def_only || ITERATOR_FUNCTIONS
|
36
|
+
@def_except = def_except
|
33
37
|
@monologue = steps || I18n.t('oxaiworkers.iterator.monologue')
|
34
38
|
|
35
39
|
@on_inner_monologue = on_inner_monologue
|
36
40
|
@on_outer_voice = on_outer_voice
|
37
41
|
@on_action_request = on_action_request
|
38
|
-
@
|
42
|
+
@on_summarize = on_summarize
|
39
43
|
|
40
44
|
cleanup
|
41
45
|
|
@@ -61,6 +65,7 @@ module OxAiWorkers
|
|
61
65
|
def outer_voice(text:)
|
62
66
|
# @queue.pop
|
63
67
|
@queue << { role: :assistant, content: text.to_s }
|
68
|
+
complete! unless available_defs.include?(:action_request)
|
64
69
|
@on_outer_voice&.call(text: text)
|
65
70
|
nil
|
66
71
|
end
|
@@ -77,11 +82,11 @@ module OxAiWorkers
|
|
77
82
|
def summarize(text:)
|
78
83
|
@milestones << text.to_s
|
79
84
|
@messages = []
|
80
|
-
@queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.
|
85
|
+
@queue << { role: :assistant, content: I18n.t('oxaiworkers.iterator.summarize.result') }
|
81
86
|
@worker.finish
|
82
87
|
rebuild_worker
|
83
|
-
|
84
|
-
@
|
88
|
+
complete! if can_complete?
|
89
|
+
@on_summarize&.call(text: text)
|
85
90
|
nil
|
86
91
|
end
|
87
92
|
|
@@ -93,12 +98,21 @@ module OxAiWorkers
|
|
93
98
|
def rebuild_worker
|
94
99
|
@worker.messages = []
|
95
100
|
@worker.append(role: :system, content: @role) if @role.present?
|
96
|
-
@worker.append(role: :system, content:
|
101
|
+
@worker.append(role: :system, content: valid_monologue.join("\n"))
|
97
102
|
@worker.append(messages: @context) if @context.present?
|
98
103
|
@tasks.each { |task| @worker.append(role: :user, content: task) }
|
99
104
|
@milestones.each { |milestone| @worker.append(role: :assistant, content: milestone) }
|
100
105
|
@worker.append(messages: @messages)
|
101
|
-
@worker.tools =
|
106
|
+
@worker.tools = self.class.function_schemas.to_openai_format(only: available_defs)
|
107
|
+
@worker.tools += @tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten if @tools.present?
|
108
|
+
end
|
109
|
+
|
110
|
+
def available_defs
|
111
|
+
@def_only - @def_except
|
112
|
+
end
|
113
|
+
|
114
|
+
def valid_monologue
|
115
|
+
@monologue.reject { |item| @def_except.any? { |fun| item.include?(self.class.full_function_name(fun)) } }
|
102
116
|
end
|
103
117
|
|
104
118
|
def next_iteration
|
@@ -123,12 +137,12 @@ module OxAiWorkers
|
|
123
137
|
if @worker.tool_calls.present?
|
124
138
|
@queue << { role: :assistant, content: @worker.tool_calls_raw.to_s }
|
125
139
|
@worker.tool_calls.each do |external_call|
|
126
|
-
tool = @tools.select do |t|
|
140
|
+
tool = ([self] + @tools).select do |t|
|
127
141
|
t.class.tool_name == external_call[:class] && t.respond_to?(external_call[:name])
|
128
142
|
end.first
|
129
143
|
unless tool.nil?
|
130
144
|
out = tool.send(external_call[:name], **external_call[:args])
|
131
|
-
@queue << { role: :
|
145
|
+
@queue << { role: :system, content: out.to_s } if out.present?
|
132
146
|
end
|
133
147
|
end
|
134
148
|
@worker.finish
|
@@ -63,6 +63,10 @@ module OxAiWorkers::ToolDefinition
|
|
63
63
|
.downcase
|
64
64
|
end
|
65
65
|
|
66
|
+
def full_function_name(fun)
|
67
|
+
function_schemas.function_name(fun)
|
68
|
+
end
|
69
|
+
|
66
70
|
# Manages schemas for functions
|
67
71
|
class FunctionSchemas
|
68
72
|
def initialize(tool_name)
|
@@ -70,6 +74,10 @@ module OxAiWorkers::ToolDefinition
|
|
70
74
|
@tool_name = tool_name
|
71
75
|
end
|
72
76
|
|
77
|
+
def function_name method_name
|
78
|
+
"#{@tool_name}__#{method_name}"
|
79
|
+
end
|
80
|
+
|
73
81
|
# Adds a function to the schemas
|
74
82
|
#
|
75
83
|
# @param method_name [Symbol] Name of the method to add
|
@@ -77,7 +85,7 @@ module OxAiWorkers::ToolDefinition
|
|
77
85
|
# @yield Block that defines the parameters for the function
|
78
86
|
# @raise [ArgumentError] If a block is defined and no parameters are specified for the function
|
79
87
|
def add_function(method_name:, description:, &)
|
80
|
-
name =
|
88
|
+
name = function_name(method_name)
|
81
89
|
|
82
90
|
if block_given?
|
83
91
|
parameters = ParameterBuilder.new(parent_type: "object").build(&)
|
@@ -96,15 +104,23 @@ module OxAiWorkers::ToolDefinition
|
|
96
104
|
# Converts schemas to OpenAI-compatible format
|
97
105
|
#
|
98
106
|
# @return [String] JSON string of schemas in OpenAI format
|
99
|
-
def to_openai_format
|
100
|
-
|
107
|
+
def to_openai_format(only: nil)
|
108
|
+
valid_schemas(only: only).values
|
109
|
+
end
|
110
|
+
|
111
|
+
def valid_schemas(only: nil)
|
112
|
+
if only.nil?
|
113
|
+
@schemas
|
114
|
+
else
|
115
|
+
@schemas.select { |name, schema| only.include?(name) }
|
116
|
+
end
|
101
117
|
end
|
102
118
|
|
103
119
|
# Converts schemas to Anthropic-compatible format
|
104
120
|
#
|
105
121
|
# @return [String] JSON string of schemas in Anthropic format
|
106
|
-
def to_anthropic_format
|
107
|
-
|
122
|
+
def to_anthropic_format(only: nil)
|
123
|
+
valid_schemas(only: only).values.map do |schema|
|
108
124
|
schema[:function].transform_keys("parameters" => "input_schema")
|
109
125
|
end
|
110
126
|
end
|
@@ -112,8 +128,8 @@ module OxAiWorkers::ToolDefinition
|
|
112
128
|
# Converts schemas to Google Gemini-compatible format
|
113
129
|
#
|
114
130
|
# @return [String] JSON string of schemas in Google Gemini format
|
115
|
-
def to_google_gemini_format
|
116
|
-
|
131
|
+
def to_google_gemini_format(only: nil)
|
132
|
+
valid_schemas(only: only).values.map { |schema| schema[:function] }
|
117
133
|
end
|
118
134
|
end
|
119
135
|
|
data/lib/oxaiworkers/version.rb
CHANGED
data/locales/en.iterator.yml
CHANGED
@@ -10,7 +10,7 @@ en:
|
|
10
10
|
action_request:
|
11
11
|
description: A function for interactive interaction with the user. Allows you to ask a clarifying question, request actions, or complete the current step. The function waits for the user's response and returns it.
|
12
12
|
action: Text of the request or action
|
13
|
-
|
13
|
+
summarize:
|
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
|
@@ -18,5 +18,5 @@ en:
|
|
18
18
|
- Step 1. Develop your own solution to the problem, taking initiative and making assumptions.
|
19
19
|
- Step 2. Enclose all your developments from the previous step in the ox_ai_workers_iterator__inner_monologue function.
|
20
20
|
- Step 3. Call the necessary functions one after another until the desired result is achieved.
|
21
|
-
- Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the
|
21
|
+
- Step 4. 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
22
|
- Step 5. When the solution is ready, notify about it and wait for the user's response.
|
data/locales/ru.iterator.yml
CHANGED
@@ -10,7 +10,7 @@ ru:
|
|
10
10
|
action_request:
|
11
11
|
description: Функция для интерактивного взаимодействия с пользователем. Позволяет задать уточняющий вопрос, запросить выполнение действий или завершить текущий шаг. Функция ожидает ответ пользователя и возвращает его.
|
12
12
|
action: Текст запроса или действия
|
13
|
-
|
13
|
+
summarize:
|
14
14
|
description: Функция сохраняет ключевые факты, нюансы и действия из предыдущих сообщений, включая предоставленный ответ. После вызова этой функции все предыдущие сообщения будут удалены. Используйте её только после завершения всех промежуточных шагов и когда точное содержание предыдущих сообщений больше не имеет значения.
|
15
15
|
text: Перечисление важных фактов и нюансов
|
16
16
|
result: Сообщения удалены
|
@@ -18,5 +18,5 @@ ru:
|
|
18
18
|
- Шаг 1. Разработай собственное решение проблемы, проявляя инициативу и делая предположения.
|
19
19
|
- Шаг 2. Заключи все свои наработки из предыдущего шага в функцию ox_ai_workers_iterator__inner_monologue.
|
20
20
|
- Шаг 3. Вызывай необходимые функции друг за другом, пока желаемый результат не будет достигнут.
|
21
|
-
- Шаг 4. Когда все промежуточные шаги завершены и точное содержание предыдущих сообщений больше не имеет значения, используй функцию
|
21
|
+
- Шаг 4. Когда все промежуточные шаги завершены и точное содержание предыдущих сообщений больше не имеет значения, используй функцию ox_ai_workers_iterator__summarize.
|
22
22
|
- Шаг 5. Когда решение готово, сообщи об этом и ожидай ответ пользователя.
|
data/template/my_assistant.rb
CHANGED
@@ -10,9 +10,9 @@ class MyAssistant
|
|
10
10
|
# Optional instructions
|
11
11
|
# steps = []
|
12
12
|
# steps << 'Step 1. Develop your own solution to the problem, taking initiative and making assumptions.'
|
13
|
-
# steps <<
|
13
|
+
# steps << "Step 2. Enclose all your developments from the previous step in the #{OxAiWorkers::Iterator.full_function_name(:inner_monologue)} function."
|
14
14
|
# steps << 'Step 3. Call the necessary functions one after another until the desired result is achieved.'
|
15
|
-
# steps <<
|
15
|
+
# steps << "Step 4. When all intermediate steps are completed and the exact content of previous messages is no longer relevant, use the #{OxAiWorkers::Iterator.full_function_name(:summarize)} function."
|
16
16
|
# steps << "Step 5. When the solution is ready, notify about it and wait for the user's response."
|
17
17
|
|
18
18
|
@iterator = OxAiWorkers::Iterator.new(
|
@@ -23,7 +23,7 @@ class MyAssistant
|
|
23
23
|
on_inner_monologue: ->(text:) { puts "monologue: #{text}".colorize(:yellow) },
|
24
24
|
on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) },
|
25
25
|
on_action_request: ->(text:) { puts "action: #{text}".colorize(:red) },
|
26
|
-
|
26
|
+
on_summarize: ->(text:) { puts "summary: #{text}".colorize(:blue) }
|
27
27
|
)
|
28
28
|
end
|
29
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ox-ai-workers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Smolev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -108,17 +108,17 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1'
|
111
|
-
description: |
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
111
|
+
description: |2
|
112
|
+
OxAiWorkers (ox-ai-workers) is a Ruby gem that provides a powerful and flexible state machine with
|
113
|
+
integration of generative intelligence using the ruby-openai gem. This gem allows you to create state
|
114
|
+
machines for solving complex tasks, enhancing the final result by leveraging internal logic (state machine)
|
115
|
+
and external tools (OpenAI generative intelligence).
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
Features:
|
118
|
+
- State Machine: Easily create and manage state machines to model various states and transitions in your application.
|
119
|
+
- OpenAI Integration: Utilize the capabilities of generative intelligence to make decisions and perform tasks, improving the quality and accuracy of results.
|
120
|
+
- Flexibility and Extensibility: Customize the behavior of the state machine and OpenAI integration according to your needs.
|
121
|
+
- Ease of Use: Intuitive syntax and documentation make it easy to get started with the gem.
|
122
122
|
email:
|
123
123
|
- smolev@me.com
|
124
124
|
executables:
|