meta_workflows 0.7.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 +7 -0
- data/CHANGELOG.md +36 -0
- data/README.md +498 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/meta_workflows/controllers/loading_phrases_controller.js +31 -0
- data/app/assets/javascripts/meta_workflows/controllers/redirect_controller.js +15 -0
- data/app/assets/javascripts/meta_workflows/controllers/response_scroll_controller.js +67 -0
- data/app/assets/javascripts/meta_workflows_manifest.js +13 -0
- data/app/assets/stylesheets/meta_workflows/application.css +161 -0
- data/app/controllers/meta_workflows/application_controller.rb +10 -0
- data/app/controllers/meta_workflows/debug_controller.rb +101 -0
- data/app/controllers/meta_workflows/humans_controller.rb +96 -0
- data/app/controllers/meta_workflows/meta_controller.rb +21 -0
- data/app/helpers/meta_workflows/application_helper.rb +7 -0
- data/app/helpers/meta_workflows/debug_helper.rb +54 -0
- data/app/helpers/meta_workflows/execution_helper.rb +77 -0
- data/app/helpers/meta_workflows/formatting_helper.rb +30 -0
- data/app/helpers/meta_workflows/meta_workflows_helper.rb +41 -0
- data/app/helpers/meta_workflows/status_badge_helper.rb +66 -0
- data/app/jobs/meta_workflows/application_job.rb +14 -0
- data/app/jobs/meta_workflows/human_input_job.rb +35 -0
- data/app/jobs/meta_workflows/meta_job.rb +121 -0
- data/app/jobs/meta_workflows/meta_workflow_job.rb +20 -0
- data/app/jobs/meta_workflows/record_redirect_job.rb +36 -0
- data/app/mailers/meta_workflows/application_mailer.rb +8 -0
- data/app/models/meta_workflows/application_record.rb +7 -0
- data/app/models/meta_workflows/chat.rb +20 -0
- data/app/models/meta_workflows/message.rb +11 -0
- data/app/models/meta_workflows/tool_call.rb +7 -0
- data/app/models/meta_workflows/workflow.rb +32 -0
- data/app/models/meta_workflows/workflow_execution.rb +23 -0
- data/app/models/meta_workflows/workflow_step.rb +49 -0
- data/app/models/meta_workflows.rb +7 -0
- data/app/services/meta_workflows/execution_filter_service.rb +80 -0
- data/app/sidekiq/meta_workflows/tools/meta_workflow_tool.rb +86 -0
- data/app/views/layouts/meta_workflows/application.html.erb +17 -0
- data/app/views/layouts/meta_workflows/debug.html.erb +47 -0
- data/app/views/meta_workflows/_loader.html.erb +22 -0
- data/app/views/meta_workflows/_redirect.html.erb +1 -0
- data/app/views/meta_workflows/_response.html.erb +5 -0
- data/app/views/meta_workflows/_response_form.html.erb +36 -0
- data/app/views/meta_workflows/debug/executions.html.erb +187 -0
- data/app/views/meta_workflows/debug/show_execution.html.erb +283 -0
- data/app/views/meta_workflows/debug/show_workflow.html.erb +148 -0
- data/app/views/meta_workflows/debug/workflows.html.erb +110 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20250530220618_create_meta_workflows_workflows.rb +16 -0
- data/db/migrate/20250530220634_create_meta_workflows_workflow_executions.rb +18 -0
- data/db/migrate/20250530220704_create_meta_workflows_chats.rb +16 -0
- data/db/migrate/20250530220722_create_meta_workflows_messages.rb +19 -0
- data/db/migrate/20250530220737_create_meta_workflows_tool_calls.rb +18 -0
- data/db/migrate/20250530220750_create_meta_workflows_workflow_steps.rb +17 -0
- data/db/migrate/20250613213159_add_error_fields_to_workflow_steps.rb +8 -0
- data/lib/meta_workflows/asset_installer.rb +509 -0
- data/lib/meta_workflows/configuration.rb +39 -0
- data/lib/meta_workflows/engine.rb +47 -0
- data/lib/meta_workflows/export_execution_service.rb +56 -0
- data/lib/meta_workflows/version.rb +5 -0
- data/lib/meta_workflows.rb +9 -0
- data/lib/services/meta_workflows/application_service.rb +11 -0
- data/lib/services/meta_workflows/meta_workflow_service.rb +277 -0
- data/lib/services/meta_workflows/updaters/meta_service.rb +39 -0
- data/lib/tasks/meta_workflows_tasks.rake +153 -0
- metadata +219 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Services
|
4
|
+
module MetaWorkflows
|
5
|
+
class MetaWorkflowService
|
6
|
+
ACTIONS_WITHOUT_CONVERSATION = %w[record_redirect collection_create record_update].freeze
|
7
|
+
|
8
|
+
attr_reader :record, :workflow_name, :user, :inputs, :workflow_params
|
9
|
+
|
10
|
+
# TODO: inputs should be a an empty hash by default
|
11
|
+
# Once everything is working we can change the default value from nil to {}
|
12
|
+
def initialize(record:, workflow_name: nil, user: nil, inputs: nil, workflow_params: nil)
|
13
|
+
@record = record
|
14
|
+
@workflow_name = workflow_name
|
15
|
+
@user = user
|
16
|
+
@inputs = inputs
|
17
|
+
@workflow_params = workflow_params
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
validate_workflow_presence
|
22
|
+
|
23
|
+
workflow, workflow_execution = find_or_create_workflow_execution
|
24
|
+
execution_step, execution_output, workflow_step = prepare_workflow_execution(workflow, workflow_execution)
|
25
|
+
|
26
|
+
if ACTIONS_WITHOUT_CONVERSATION.include?(execution_step['action'])
|
27
|
+
process_action(execution_step, nil, workflow_execution, workflow)
|
28
|
+
else
|
29
|
+
chat = create_and_configure_chat(workflow_step)
|
30
|
+
conversation = create_and_configure_conversation(chat, workflow_execution, execution_output, execution_step)
|
31
|
+
process_action(execution_step, conversation, workflow_execution, workflow)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def process_action(execution_step, conversation, workflow_execution, workflow)
|
38
|
+
case execution_step['action']
|
39
|
+
when 'agent'
|
40
|
+
process_agent_action(conversation, workflow_execution, workflow)
|
41
|
+
when 'human'
|
42
|
+
process_human_action(execution_step, workflow_execution)
|
43
|
+
when 'record_redirect'
|
44
|
+
process_record_redirect_action(workflow_execution, workflow)
|
45
|
+
when 'collection_create'
|
46
|
+
process_collection_create_action(execution_step, workflow_execution, workflow)
|
47
|
+
when 'record_update'
|
48
|
+
process_record_update_action(execution_step, workflow_execution, workflow)
|
49
|
+
else
|
50
|
+
raise ArgumentError, "The action #{execution_step['action']} does not exist"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_agent_action(conversation, workflow_execution, workflow)
|
55
|
+
workflow_step = find_workflow_step(workflow_execution)
|
56
|
+
|
57
|
+
begin
|
58
|
+
clear_previous_errors(workflow_step)
|
59
|
+
execute_llm_call(conversation, workflow_execution)
|
60
|
+
handle_workflow_continuation(workflow_execution, workflow, conversation)
|
61
|
+
rescue StandardError => e
|
62
|
+
handle_agent_error(e, workflow_step, workflow, workflow_execution)
|
63
|
+
raise
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_workflow_step(workflow_execution)
|
68
|
+
workflow_execution.workflow_steps.find_by(step: workflow_execution.current_step)
|
69
|
+
end
|
70
|
+
|
71
|
+
def clear_previous_errors(workflow_step)
|
72
|
+
workflow_step&.clear_error if workflow_step&.error?
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute_llm_call(conversation, workflow_execution)
|
76
|
+
conversation.call_llm
|
77
|
+
workflow_execution.increment_step
|
78
|
+
end
|
79
|
+
|
80
|
+
def handle_workflow_continuation(workflow_execution, workflow, conversation)
|
81
|
+
new_inputs = extract_tool_call_inputs(conversation)
|
82
|
+
|
83
|
+
if workflow_execution.current_step < workflow.total_steps
|
84
|
+
schedule_next_workflow_step_with_inputs(new_inputs)
|
85
|
+
else
|
86
|
+
workflow_execution.update(completed: true)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def schedule_next_workflow_step_with_inputs(new_inputs)
|
91
|
+
::MetaWorkflows::MetaWorkflowJob.perform_later(
|
92
|
+
record_id: record.id,
|
93
|
+
record_type: record.class.name,
|
94
|
+
workflow_name: nil,
|
95
|
+
user_id: user&.id,
|
96
|
+
inputs: new_inputs
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
def handle_agent_error(error, workflow_step, workflow, workflow_execution)
|
101
|
+
Rails.logger.error("LLM Error in MetaWorkflowService: #{error.message}")
|
102
|
+
Rails.logger.error(error.backtrace.join("\n"))
|
103
|
+
|
104
|
+
record_error_details(error, workflow_step, workflow, workflow_execution) if workflow_step
|
105
|
+
end
|
106
|
+
|
107
|
+
def record_error_details(error, workflow_step, workflow, workflow_execution)
|
108
|
+
workflow_step.record_error(error, additional_details: {
|
109
|
+
service_class: self.class.name,
|
110
|
+
workflow_id: workflow.id,
|
111
|
+
workflow_name: workflow.name,
|
112
|
+
current_step: workflow_execution.current_step,
|
113
|
+
record_type: record.class.name,
|
114
|
+
record_id: record.id
|
115
|
+
})
|
116
|
+
end
|
117
|
+
|
118
|
+
def process_human_action(execution_step, workflow_execution)
|
119
|
+
::MetaWorkflows::HumanInputJob.perform_later(
|
120
|
+
user_id: user&.id,
|
121
|
+
record: workflow_execution.record,
|
122
|
+
params: {
|
123
|
+
inputs: inputs,
|
124
|
+
prompt_id: execution_step['prompt_id']
|
125
|
+
}
|
126
|
+
)
|
127
|
+
# the step advancement is handled in the human input job
|
128
|
+
end
|
129
|
+
|
130
|
+
def process_record_redirect_action(workflow_execution, workflow)
|
131
|
+
::MetaWorkflows::RecordRedirectJob.perform_later(workflow_execution: workflow_execution)
|
132
|
+
workflow_execution.increment_step
|
133
|
+
|
134
|
+
return unless workflow_execution.current_step >= workflow.total_steps
|
135
|
+
|
136
|
+
workflow_execution.update(completed: true)
|
137
|
+
end
|
138
|
+
|
139
|
+
def process_collection_create_action(execution_step, workflow_execution, workflow)
|
140
|
+
service = build_collection_service(execution_step, workflow_execution)
|
141
|
+
|
142
|
+
begin
|
143
|
+
service.call
|
144
|
+
workflow_execution.increment_step
|
145
|
+
continue_workflow(workflow_execution, workflow)
|
146
|
+
rescue StandardError => e
|
147
|
+
Rails.logger.error("Error creating collection: #{e.message}")
|
148
|
+
# The workflow should halt on error per requirements - do not increment step
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def process_record_update_action(execution_step, workflow_execution, workflow)
|
153
|
+
service = build_record_update_service(execution_step, workflow_execution)
|
154
|
+
|
155
|
+
begin
|
156
|
+
service.call
|
157
|
+
workflow_execution.increment_step
|
158
|
+
continue_workflow(workflow_execution, workflow)
|
159
|
+
rescue StandardError => e
|
160
|
+
Rails.logger.error("Error updating record: #{e.message}")
|
161
|
+
# Let Sidekiq handle retry - reraise the error
|
162
|
+
raise
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_collection_service(execution_step, workflow_execution)
|
167
|
+
service_class_name = execution_step['collection_creator']
|
168
|
+
service_class = service_class_name.safe_constantize
|
169
|
+
|
170
|
+
raise ArgumentError, "Invalid collection creator class: #{service_class_name}" unless service_class
|
171
|
+
|
172
|
+
parent_record = find_parent_record(workflow_execution)
|
173
|
+
|
174
|
+
service_class.new(
|
175
|
+
parent_record: parent_record,
|
176
|
+
collection: inputs[:collection]
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
def build_record_update_service(execution_step, workflow_execution)
|
181
|
+
service_class_name = execution_step['record_updater']
|
182
|
+
service_class = service_class_name.safe_constantize
|
183
|
+
|
184
|
+
raise ArgumentError, "Invalid record updater class: #{service_class_name}" unless service_class
|
185
|
+
|
186
|
+
target_record = find_parent_record(workflow_execution)
|
187
|
+
attributes_to_update = execution_step['attributes_to_update']
|
188
|
+
|
189
|
+
service_class.new(target_record, attributes_to_update, workflow_execution.workflow_params)
|
190
|
+
end
|
191
|
+
|
192
|
+
def find_parent_record(workflow_execution)
|
193
|
+
record_class = workflow_execution.record.class.name.constantize
|
194
|
+
record_class.find(workflow_execution.workflow_params['record_id'])
|
195
|
+
end
|
196
|
+
|
197
|
+
def continue_workflow(workflow_execution, workflow)
|
198
|
+
if workflow_execution.current_step < workflow.total_steps
|
199
|
+
schedule_next_workflow_step
|
200
|
+
else
|
201
|
+
workflow_execution.update(completed: true)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def schedule_next_workflow_step
|
206
|
+
::MetaWorkflows::MetaWorkflowJob.perform_later(
|
207
|
+
record_id: record.id,
|
208
|
+
record_type: record.class.name,
|
209
|
+
workflow_name: nil,
|
210
|
+
user_id: user&.id,
|
211
|
+
inputs: {}
|
212
|
+
)
|
213
|
+
end
|
214
|
+
|
215
|
+
def create_and_configure_conversation(chat, workflow_execution, execution_output, execution_step)
|
216
|
+
conversation = RubyConversations::Conversation.new(chat: chat)
|
217
|
+
conversation.tool = ::MetaWorkflows::Tools::MetaWorkflowTool.build(workflow_execution, execution_output)
|
218
|
+
conversation.with_prompt(
|
219
|
+
execution_step['prompt_id'],
|
220
|
+
inputs: inputs,
|
221
|
+
description: "Executing step #{workflow_execution.current_step} of " \
|
222
|
+
"workflow #{workflow_execution.workflow.name}"
|
223
|
+
)
|
224
|
+
conversation
|
225
|
+
end
|
226
|
+
|
227
|
+
def create_and_configure_chat(workflow_step)
|
228
|
+
workflow_step.chat = ::MetaWorkflows::Chat.new(model_id: RubyConversations.configuration.default_llm_model,
|
229
|
+
provider: RubyConversations.configuration.default_llm_provider)
|
230
|
+
chat = workflow_step.chat
|
231
|
+
chat.user = @user
|
232
|
+
chat.save!
|
233
|
+
workflow_step.save!
|
234
|
+
chat
|
235
|
+
end
|
236
|
+
|
237
|
+
def validate_workflow_presence
|
238
|
+
return unless workflow_name.nil? && record.workflow_execution.blank?
|
239
|
+
|
240
|
+
raise ArgumentError, 'No workflow specified and record has no workflow attached'
|
241
|
+
end
|
242
|
+
|
243
|
+
def find_or_create_workflow_execution
|
244
|
+
if workflow_name.present?
|
245
|
+
workflow = ::MetaWorkflows::Workflow.find_by(name: workflow_name)
|
246
|
+
workflow_execution = ::MetaWorkflows::WorkflowExecution.create(
|
247
|
+
record: record,
|
248
|
+
workflow: workflow,
|
249
|
+
current_step: 0,
|
250
|
+
completed: false,
|
251
|
+
workflow_params: workflow_params
|
252
|
+
)
|
253
|
+
else
|
254
|
+
workflow_execution = record.workflow_execution
|
255
|
+
workflow = workflow_execution.workflow
|
256
|
+
end
|
257
|
+
|
258
|
+
[workflow, workflow_execution]
|
259
|
+
end
|
260
|
+
|
261
|
+
def prepare_workflow_execution(workflow, workflow_execution)
|
262
|
+
execution_step = workflow.step_data(workflow_execution.current_step)
|
263
|
+
execution_output = workflow.step_output(workflow_execution.current_step)
|
264
|
+
workflow_step = workflow_execution.workflow_steps.find_or_create_by(step: workflow_execution.current_step)
|
265
|
+
|
266
|
+
[execution_step, execution_output, workflow_step]
|
267
|
+
end
|
268
|
+
|
269
|
+
def extract_tool_call_inputs(conversation)
|
270
|
+
# the tool call is always the next to last message in the conversation
|
271
|
+
tool_call_id = JSON.parse(conversation.messages.first.response)[-2]['tool_call_id']
|
272
|
+
tool_call = ::MetaWorkflows::ToolCall.find(tool_call_id)
|
273
|
+
tool_call.arguments.deep_symbolize_keys
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Services
|
4
|
+
module MetaWorkflows
|
5
|
+
module Updaters
|
6
|
+
class MetaService < Services::MetaWorkflows::ApplicationService
|
7
|
+
attr_reader :record, :attributes_to_update, :workflow_params
|
8
|
+
|
9
|
+
def initialize(record, attributes_to_update, workflow_params)
|
10
|
+
super()
|
11
|
+
@record = record
|
12
|
+
@attributes_to_update = attributes_to_update
|
13
|
+
@workflow_params = workflow_params
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
update_attributes = build_update_attributes
|
18
|
+
record.update!(update_attributes)
|
19
|
+
record
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def build_update_attributes
|
25
|
+
attributes_hash = {}
|
26
|
+
|
27
|
+
attributes_to_update.each do |attribute_name|
|
28
|
+
param_value = workflow_params[attribute_name] || workflow_params[attribute_name.to_sym]
|
29
|
+
next if param_value.blank?
|
30
|
+
|
31
|
+
attributes_hash[attribute_name.to_sym] = param_value
|
32
|
+
end
|
33
|
+
|
34
|
+
attributes_hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
require_relative '../meta_workflows/asset_installer'
|
6
|
+
|
7
|
+
namespace :meta_workflows do
|
8
|
+
desc 'Import workflows from YAML files in the workflows directory'
|
9
|
+
task import: :environment do
|
10
|
+
MetaWorkflows::WorkflowImporter.new.import_workflows
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :install do
|
14
|
+
desc 'Install meta_workflows assets (JavaScript controllers and stylesheets) into host application'
|
15
|
+
task assets: :environment do
|
16
|
+
MetaWorkflows::AssetInstallerService.new.install
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Service class to handle workflow import logic
|
22
|
+
module MetaWorkflows
|
23
|
+
class WorkflowImporter
|
24
|
+
def initialize
|
25
|
+
@workflows_path = Rails.root.join('workflows')
|
26
|
+
end
|
27
|
+
|
28
|
+
def import_workflows
|
29
|
+
puts "Importing workflows from #{@workflows_path}..."
|
30
|
+
|
31
|
+
Dir.glob(File.join(@workflows_path, '*.yml')).each do |file_path|
|
32
|
+
import_single_workflow(file_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
puts 'Workflow import completed!'
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def import_single_workflow(file_path)
|
41
|
+
file_name = File.basename(file_path, '.yml')
|
42
|
+
workflow_name = file_name.underscore
|
43
|
+
|
44
|
+
begin
|
45
|
+
yaml_content = YAML.load_file(file_path)
|
46
|
+
save_workflow(workflow_name, yaml_content)
|
47
|
+
rescue StandardError => e
|
48
|
+
puts "Error processing #{file_path}: #{e.message}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def save_workflow(workflow_name, yaml_content)
|
53
|
+
workflow = MetaWorkflows::Workflow.find_or_initialize_by(name: workflow_name)
|
54
|
+
workflow.recipe = yaml_content
|
55
|
+
|
56
|
+
if workflow.save
|
57
|
+
puts "Successfully imported workflow: #{workflow.name}"
|
58
|
+
else
|
59
|
+
puts "Failed to import workflow #{workflow_name}: #{workflow.errors.full_messages.join(', ')}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Service class to handle asset installation
|
65
|
+
class AssetInstallerService
|
66
|
+
def install
|
67
|
+
puts 'Installing meta_workflows assets...'
|
68
|
+
|
69
|
+
installer = MetaWorkflows::AssetInstaller.new
|
70
|
+
|
71
|
+
# Pre-installation validation
|
72
|
+
unless installer.valid_environment?
|
73
|
+
puts 'Installation aborted due to validation errors.'
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
process_asset_installation(installer)
|
79
|
+
rescue MetaWorkflows::AssetInstaller::InstallationError => e
|
80
|
+
handle_installation_error(e)
|
81
|
+
rescue StandardError => e
|
82
|
+
handle_unexpected_error(e)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def process_asset_installation(installer)
|
89
|
+
assets = discover_and_validate_assets(installer)
|
90
|
+
return if assets.empty?
|
91
|
+
|
92
|
+
result = installer.install_assets(assets)
|
93
|
+
display_installation_results(installer, assets, result)
|
94
|
+
end
|
95
|
+
|
96
|
+
def discover_and_validate_assets(installer)
|
97
|
+
assets = installer.discover_assets
|
98
|
+
|
99
|
+
if assets.empty?
|
100
|
+
puts 'No assets found to install.'
|
101
|
+
return []
|
102
|
+
end
|
103
|
+
|
104
|
+
puts "Found #{assets.count} asset(s) to install:"
|
105
|
+
assets.each { |asset| puts " - #{asset[:relative_path]}" }
|
106
|
+
puts
|
107
|
+
|
108
|
+
assets
|
109
|
+
end
|
110
|
+
|
111
|
+
def display_installation_results(installer, assets, result)
|
112
|
+
puts
|
113
|
+
if result[:success]
|
114
|
+
display_successful_installation(installer, assets, result)
|
115
|
+
else
|
116
|
+
display_partial_installation(installer, assets, result)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def display_successful_installation(installer, assets, result)
|
121
|
+
puts 'Installation completed successfully!'
|
122
|
+
puts "#{result[:copied]} file(s) copied, #{result[:skipped]} file(s) skipped."
|
123
|
+
|
124
|
+
return unless result[:copied].positive?
|
125
|
+
|
126
|
+
puts
|
127
|
+
installer.display_integration_instructions(assets, result)
|
128
|
+
end
|
129
|
+
|
130
|
+
def display_partial_installation(installer, assets, result)
|
131
|
+
puts 'Installation completed with errors.'
|
132
|
+
puts "#{result[:copied]} file(s) copied, #{result[:skipped]} file(s) skipped, " \
|
133
|
+
"#{result[:failed]} file(s) failed."
|
134
|
+
puts 'Some files may have been partially installed. Please review the output above.'
|
135
|
+
|
136
|
+
return unless result[:copied].positive?
|
137
|
+
|
138
|
+
puts
|
139
|
+
puts 'For successfully copied files, see integration instructions below:'
|
140
|
+
installer.display_integration_instructions(assets, result)
|
141
|
+
end
|
142
|
+
|
143
|
+
def handle_installation_error(error)
|
144
|
+
puts "Installation failed: #{error.message}"
|
145
|
+
puts 'Installation aborted.'
|
146
|
+
end
|
147
|
+
|
148
|
+
def handle_unexpected_error(error)
|
149
|
+
puts "Unexpected error during asset installation: #{error.message}"
|
150
|
+
puts 'Installation aborted.'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
metadata
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meta_workflows
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leonid Medovyy
|
8
|
+
- Sami Tanquary
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2025-06-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 7.2.0
|
21
|
+
- - "<"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '9.0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 7.2.0
|
31
|
+
- - "<"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '9.0'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: sidekiq
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '6.0'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: ruby_conversations
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: ruby_llm
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: view_component
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: stimulus-rails
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.0'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: turbo-rails
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.0'
|
111
|
+
type: :runtime
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.0'
|
118
|
+
description: MetaWorkflows provides a flexible framework for creating and executing
|
119
|
+
AI-powered workflows with human interaction points, built as a Rails engine for
|
120
|
+
easy integration into existing applications.
|
121
|
+
email:
|
122
|
+
- leonid.medovyy@strongmind.com
|
123
|
+
- samantha.tanquary@strongmind.com
|
124
|
+
executables: []
|
125
|
+
extensions: []
|
126
|
+
extra_rdoc_files: []
|
127
|
+
files:
|
128
|
+
- CHANGELOG.md
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
- app/assets/javascripts/meta_workflows/controllers/loading_phrases_controller.js
|
132
|
+
- app/assets/javascripts/meta_workflows/controllers/redirect_controller.js
|
133
|
+
- app/assets/javascripts/meta_workflows/controllers/response_scroll_controller.js
|
134
|
+
- app/assets/javascripts/meta_workflows_manifest.js
|
135
|
+
- app/assets/stylesheets/meta_workflows/application.css
|
136
|
+
- app/controllers/meta_workflows/application_controller.rb
|
137
|
+
- app/controllers/meta_workflows/debug_controller.rb
|
138
|
+
- app/controllers/meta_workflows/humans_controller.rb
|
139
|
+
- app/controllers/meta_workflows/meta_controller.rb
|
140
|
+
- app/helpers/meta_workflows/application_helper.rb
|
141
|
+
- app/helpers/meta_workflows/debug_helper.rb
|
142
|
+
- app/helpers/meta_workflows/execution_helper.rb
|
143
|
+
- app/helpers/meta_workflows/formatting_helper.rb
|
144
|
+
- app/helpers/meta_workflows/meta_workflows_helper.rb
|
145
|
+
- app/helpers/meta_workflows/status_badge_helper.rb
|
146
|
+
- app/jobs/meta_workflows/application_job.rb
|
147
|
+
- app/jobs/meta_workflows/human_input_job.rb
|
148
|
+
- app/jobs/meta_workflows/meta_job.rb
|
149
|
+
- app/jobs/meta_workflows/meta_workflow_job.rb
|
150
|
+
- app/jobs/meta_workflows/record_redirect_job.rb
|
151
|
+
- app/mailers/meta_workflows/application_mailer.rb
|
152
|
+
- app/models/meta_workflows.rb
|
153
|
+
- app/models/meta_workflows/application_record.rb
|
154
|
+
- app/models/meta_workflows/chat.rb
|
155
|
+
- app/models/meta_workflows/message.rb
|
156
|
+
- app/models/meta_workflows/tool_call.rb
|
157
|
+
- app/models/meta_workflows/workflow.rb
|
158
|
+
- app/models/meta_workflows/workflow_execution.rb
|
159
|
+
- app/models/meta_workflows/workflow_step.rb
|
160
|
+
- app/services/meta_workflows/execution_filter_service.rb
|
161
|
+
- app/sidekiq/meta_workflows/tools/meta_workflow_tool.rb
|
162
|
+
- app/views/layouts/meta_workflows/application.html.erb
|
163
|
+
- app/views/layouts/meta_workflows/debug.html.erb
|
164
|
+
- app/views/meta_workflows/_loader.html.erb
|
165
|
+
- app/views/meta_workflows/_redirect.html.erb
|
166
|
+
- app/views/meta_workflows/_response.html.erb
|
167
|
+
- app/views/meta_workflows/_response_form.html.erb
|
168
|
+
- app/views/meta_workflows/debug/executions.html.erb
|
169
|
+
- app/views/meta_workflows/debug/show_execution.html.erb
|
170
|
+
- app/views/meta_workflows/debug/show_workflow.html.erb
|
171
|
+
- app/views/meta_workflows/debug/workflows.html.erb
|
172
|
+
- config/routes.rb
|
173
|
+
- db/migrate/20250530220618_create_meta_workflows_workflows.rb
|
174
|
+
- db/migrate/20250530220634_create_meta_workflows_workflow_executions.rb
|
175
|
+
- db/migrate/20250530220704_create_meta_workflows_chats.rb
|
176
|
+
- db/migrate/20250530220722_create_meta_workflows_messages.rb
|
177
|
+
- db/migrate/20250530220737_create_meta_workflows_tool_calls.rb
|
178
|
+
- db/migrate/20250530220750_create_meta_workflows_workflow_steps.rb
|
179
|
+
- db/migrate/20250613213159_add_error_fields_to_workflow_steps.rb
|
180
|
+
- lib/meta_workflows.rb
|
181
|
+
- lib/meta_workflows/asset_installer.rb
|
182
|
+
- lib/meta_workflows/configuration.rb
|
183
|
+
- lib/meta_workflows/engine.rb
|
184
|
+
- lib/meta_workflows/export_execution_service.rb
|
185
|
+
- lib/meta_workflows/version.rb
|
186
|
+
- lib/services/meta_workflows/application_service.rb
|
187
|
+
- lib/services/meta_workflows/meta_workflow_service.rb
|
188
|
+
- lib/services/meta_workflows/updaters/meta_service.rb
|
189
|
+
- lib/tasks/meta_workflows_tasks.rake
|
190
|
+
homepage: https://github.com/strongmind/meta_workflows
|
191
|
+
licenses:
|
192
|
+
- None
|
193
|
+
metadata:
|
194
|
+
allowed_push_host: https://rubygems.org
|
195
|
+
homepage_uri: https://github.com/strongmind/meta_workflows
|
196
|
+
source_code_uri: https://github.com/strongmind/meta_workflows
|
197
|
+
changelog_uri: https://github.com/strongmind/meta_workflows/blob/main/CHANGELOG.md
|
198
|
+
documentation_uri: https://github.com/strongmind/meta_workflows/blob/main/README.md
|
199
|
+
rubygems_mfa_required: 'true'
|
200
|
+
post_install_message:
|
201
|
+
rdoc_options: []
|
202
|
+
require_paths:
|
203
|
+
- lib
|
204
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 3.2.0
|
209
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
requirements: []
|
215
|
+
rubygems_version: 3.5.3
|
216
|
+
signing_key:
|
217
|
+
specification_version: 4
|
218
|
+
summary: A Rails engine for managing AI-powered meta workflows
|
219
|
+
test_files: []
|