meta_workflows 0.9.7 → 0.9.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f991d24a137d8a8b8f61723e714c5a2e08551d7e49d108a4bef7a434f4b122ad
4
- data.tar.gz: 7832b5db6ac767be220115a98bbd423314416b93176a1a2147249c69735781f8
3
+ metadata.gz: 9932a3a977ad87e5dc4df73df1153bdd55ec50634ca2a7b7e2dfff718682140b
4
+ data.tar.gz: 3cc0fc37cf578f4f4401d6077cdfd5dea1d2673f980581d9b8fcc4642ef1b1bc
5
5
  SHA512:
6
- metadata.gz: f0102f3753d5570e5f4cc8009699d99ee52e0994842d129666c390cb1047415713b142663ace02396997ec5bb6c392323a24958407fdfb54fee840cab14ffb94
7
- data.tar.gz: 4ea71acd1ea97348f0ea9a1713f6542a693662b42f44ffc01abc1813c688a2ae2f82a5e7c7d2597a9fde25aaff1ccbe8606472b481ef06622c7fc2f74044ac96
6
+ metadata.gz: 868f9f58a148e118ff77bb23a175de2fcebc400afbf680e72c04f2888dea99ea816d736ff0124f539f807483dbab4e9b84b601a32c37d578232707b60810187c
7
+ data.tar.gz: 81a1e87cf5b6099521de598132cd8c68d010607b9f8bad437ef3a1e2f609a257e4f9721394216e542f84838a0caaa9d78adee69b0952c9f03012c45852aa79da
@@ -1,18 +1,30 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
3
  export default class extends Controller {
4
- connect() {
5
- this.element.addEventListener('keydown', this.handleKeyDown);
6
- }
4
+ static targets = ['textarea', 'form'];
7
5
 
8
- disconnect() {
9
- this.element.removeEventListener('keydown', this.handleKeyDown);
6
+ connect() {
7
+ this.submitted = false;
10
8
  }
11
9
 
12
- handleKeyDown = (event) => {
10
+ handleKeyDown(event) {
13
11
  if (event.key === 'Enter' && !event.shiftKey) {
14
12
  event.preventDefault();
15
- this.element.requestSubmit();
13
+ event.stopPropagation();
14
+ this.handleSubmit();
15
+ }
16
+ }
17
+
18
+ handleSubmit() {
19
+ if (this.submitted) {
20
+ return;
21
+ }
22
+
23
+ if (!this.hasTextareaTarget || this.textareaTarget.value.trim() === '') {
24
+ return;
16
25
  }
17
- };
26
+
27
+ this.submitted = true;
28
+ this.formTarget.requestSubmit();
29
+ }
18
30
  }
@@ -10,18 +10,18 @@ module MetaWorkflows
10
10
  @record = @workflow_execution.record
11
11
  @workflow = @workflow_execution.workflow
12
12
  @workflow_step = @workflow_execution.workflow_steps.find_by(step: @workflow_execution.current_step)
13
- @prompt_id = @workflow.prompt_id(@workflow_execution.current_step)
13
+ @prompt_id = @workflow_execution.prompt_id(@workflow_execution.current_step)
14
14
  end
15
15
 
16
16
  protected
17
17
 
18
18
  def fetch_step_progress
19
- @workflow.step_progress(@workflow_execution.current_step) || ['Processing your request...',
20
- 'Talking to the LLM...']
19
+ @workflow_execution.step_progress(@workflow_execution.current_step) || ['Processing your request...',
20
+ 'Talking to the LLM...']
21
21
  end
22
22
 
23
23
  def current_step_repetitions
24
- @workflow.step_repetitions(@workflow_execution.current_step)
24
+ @workflow_execution.step_repetitions(@workflow_execution.current_step)
25
25
  end
26
26
  end
27
27
  end
@@ -26,9 +26,9 @@ module MetaWorkflows
26
26
  class: 'cursor-help'
27
27
  end
28
28
 
29
- # Helper to safely get step data from workflow
30
- def safe_step_data(workflow, step_number)
31
- workflow.step_data(step_number)
29
+ # Helper to safely get step data from workflow execution
30
+ def safe_step_data(workflow_execution, step_number)
31
+ workflow_execution.step_data(step_number)
32
32
  rescue StandardError => e
33
33
  { 'error' => e.message }
34
34
  end
@@ -4,16 +4,16 @@ module MetaWorkflows
4
4
  module ExecutionHelper
5
5
  # Helper to calculate execution progress percentage
6
6
  def execution_progress_percentage(execution)
7
- return 0 if execution.workflow.total_steps.zero?
7
+ return 0 if execution.total_steps.zero?
8
8
 
9
- ((execution.current_step.to_f / execution.workflow.total_steps) * 100).round(1)
9
+ ((execution.current_step.to_f / execution.total_steps) * 100).round(1)
10
10
  rescue StandardError
11
11
  0
12
12
  end
13
13
 
14
14
  # Helper to format execution progress display
15
15
  def execution_progress_display(execution)
16
- total_steps = execution.workflow.total_steps
16
+ total_steps = execution.total_steps
17
17
  current_step = execution.current_step
18
18
  percentage = execution_progress_percentage(execution)
19
19
 
@@ -65,7 +65,7 @@ module MetaWorkflows
65
65
  end
66
66
 
67
67
  def current_step_has_repetitions?(workflow_execution)
68
- workflow_execution.workflow.step_repetitions(workflow_execution.current_step).present?
68
+ workflow_execution.step_repetitions(workflow_execution.current_step).present?
69
69
  end
70
70
  end
71
71
  end
@@ -6,31 +6,6 @@ module MetaWorkflows
6
6
  validates :recipe, presence: true
7
7
 
8
8
  has_many :workflow_executions, dependent: :destroy, class_name: 'MetaWorkflows::WorkflowExecution'
9
- has_many :courses, through: :workflow_executions
10
9
  has_many :workflow_steps, through: :workflow_executions, class_name: 'MetaWorkflows::WorkflowStep'
11
-
12
- def step_progress(step)
13
- recipe.dig('steps', step, 'step_progress')
14
- end
15
-
16
- def prompt_id(step)
17
- recipe.dig('steps', step, 'prompt_id')
18
- end
19
-
20
- def step_data(step)
21
- recipe.dig('steps', step)
22
- end
23
-
24
- def step_output(step)
25
- recipe.dig('steps', step, 'output')
26
- end
27
-
28
- def step_repetitions(step)
29
- recipe.dig('steps', step, 'repetitions')
30
- end
31
-
32
- def total_steps
33
- recipe['steps'].size
34
- end
35
10
  end
36
11
  end
@@ -10,6 +10,7 @@ module MetaWorkflows
10
10
  attribute :current_step, :integer, default: 0
11
11
  attribute :completed, :boolean, default: false
12
12
  attribute :workflow_params, :json, default: -> { {} }
13
+ attribute :recipe, :json, default: -> { {} }
13
14
 
14
15
  validates :current_step, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
15
16
  validates :completed, inclusion: { in: [true, false] }
@@ -17,5 +18,29 @@ module MetaWorkflows
17
18
  def increment_step
18
19
  update(current_step: current_step + 1)
19
20
  end
21
+
22
+ def step_progress(step)
23
+ recipe&.dig('steps', step, 'step_progress')
24
+ end
25
+
26
+ def prompt_id(step)
27
+ recipe&.dig('steps', step, 'prompt_id')
28
+ end
29
+
30
+ def step_data(step)
31
+ recipe&.dig('steps', step)
32
+ end
33
+
34
+ def step_output(step)
35
+ recipe&.dig('steps', step, 'output')
36
+ end
37
+
38
+ def step_repetitions(step)
39
+ recipe&.dig('steps', step, 'repetitions')
40
+ end
41
+
42
+ def total_steps
43
+ recipe&.dig('steps')&.size || 0
44
+ end
20
45
  end
21
46
  end
@@ -2,8 +2,8 @@
2
2
  <div>
3
3
  <%= form_with url: (workflow_execution_id.present? ? meta_workflows.human_path(workflow_execution_id) : "#"),
4
4
  method: :patch,
5
- data: { controller: "meta-workflows--lexi-form-submit"},
6
- id: "#{target_frame_id(record, form: true)}_lexi" do |form| %>
5
+ id: "#{target_frame_id(record, form: true)}_lexi",
6
+ data: { controller: "meta-workflows--lexi-form-submit", "meta-workflows--lexi-form-submit-target": "form" } do |form| %>
7
7
  <%= form.hidden_field :chat_id, value: chat_id %>
8
8
  <fieldset>
9
9
  <div class="lexi-form-container">
@@ -11,7 +11,7 @@
11
11
  <div class="lexi-input-container lexi-input-max-height">
12
12
  <!-- Input area with icons -->
13
13
  <div class="lexi-textarea-wrapper">
14
- <%= form.text_area :message, rows: 1, placeholder: random_chat_placeholder, disabled: local_assigns[:responding] || !local_assigns[:response_enabled], class: "lexi-textarea lexi-textarea-min-height" %>
14
+ <%= form.text_area :message, rows: 1, placeholder: random_chat_placeholder, disabled: local_assigns[:responding] || !local_assigns[:response_enabled], class: "lexi-textarea lexi-textarea-min-height", data: { action: "keypress.enter->meta-workflows--lexi-form-submit#handleKeyDown submit->meta-workflows--lexi-form-submit#handleSubmit", "meta-workflows--lexi-form-submit-target": "textarea" } %>
15
15
  </div>
16
16
 
17
17
  <div class="lexi-input-controls">
@@ -142,12 +142,12 @@
142
142
  </td>
143
143
  <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
144
144
  <% if execution.completed? %>
145
- Step <%= execution.workflow.total_steps %>
145
+ Step <%= execution.total_steps %>
146
146
  <% else %>
147
147
  Step <%= execution.current_step + 1 %>
148
148
  <% current_step_obj = execution.workflow_steps.find_by(step: execution.current_step) %>
149
- <% max_repetitions = execution.workflow.step_repetitions(execution.current_step) if current_step_obj %>
150
- <% step_data = safe_step_data(execution.workflow, execution.current_step) %>
149
+ <% max_repetitions = execution.step_repetitions(execution.current_step) if current_step_obj %>
150
+ <% step_data = safe_step_data(execution, execution.current_step) %>
151
151
 
152
152
  <% if current_step_obj&.repetition.present? && max_repetitions.present? %>
153
153
  <br><span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800">
@@ -84,7 +84,7 @@
84
84
  <div class="flex items-center">
85
85
  <h3 class="text-sm font-medium text-gray-900">
86
86
  Step <%= workflow_step.step + 1 %>
87
- <% max_repetitions = @execution.workflow.step_repetitions(workflow_step.step) %>
87
+ <% max_repetitions = @execution.step_repetitions(workflow_step.step) %>
88
88
  <% if max_repetitions.present? %>
89
89
  <span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
90
90
  <svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
@@ -105,8 +105,8 @@
105
105
  <% end %>
106
106
  </div>
107
107
 
108
- <% step_data = safe_step_data(@execution.workflow, workflow_step.step) %>
109
- <% max_repetitions = @execution.workflow.step_repetitions(workflow_step.step) %>
108
+ <% step_data = safe_step_data(@execution, workflow_step.step) %>
109
+ <% max_repetitions = @execution.step_repetitions(workflow_step.step) %>
110
110
 
111
111
  <% if step_data %>
112
112
  <div class="mt-2 text-sm text-gray-600">
@@ -0,0 +1,5 @@
1
+ class AddRecipeToMetaWorkflowsWorkflowExecutions < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :meta_workflows_workflow_executions, :recipe, :jsonb
4
+ end
5
+ end
@@ -3,7 +3,7 @@
3
3
  module MetaWorkflows
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- PATCH = 7 # this is automatically incremented by the build process
6
+ PATCH = 9 # this is automatically incremented by the build process
7
7
 
8
8
  VERSION = "#{MetaWorkflows::MAJOR}.#{MetaWorkflows::MINOR}.#{MetaWorkflows::PATCH}".freeze
9
9
  end
@@ -21,7 +21,7 @@ module Services
21
21
  validate_workflow_presence
22
22
 
23
23
  workflow, workflow_execution = find_or_create_workflow_execution
24
- execution_step, execution_output, workflow_step = prepare_workflow_execution(workflow, workflow_execution)
24
+ execution_step, execution_output, workflow_step = prepare_workflow_execution(workflow_execution)
25
25
 
26
26
  if ACTIONS_WITHOUT_CONVERSATION.include?(execution_step['action'])
27
27
  process_action(execution_step, nil, workflow_execution, workflow)
@@ -41,11 +41,11 @@ module Services
41
41
  when 'human'
42
42
  process_human_action(execution_step, workflow_execution)
43
43
  when 'record_redirect'
44
- process_record_redirect_action(workflow_execution, workflow)
44
+ process_record_redirect_action(workflow_execution)
45
45
  when 'collection_create'
46
- process_collection_create_action(execution_step, workflow_execution, workflow)
46
+ process_collection_create_action(execution_step, workflow_execution)
47
47
  when 'record_update'
48
- process_record_update_action(execution_step, workflow_execution, workflow)
48
+ process_record_update_action(execution_step, workflow_execution)
49
49
  else
50
50
  raise ArgumentError, "The action #{execution_step['action']} does not exist"
51
51
  end
@@ -57,7 +57,7 @@ module Services
57
57
  begin
58
58
  clear_previous_errors(workflow_step)
59
59
  execute_llm_call(conversation, workflow_execution)
60
- handle_workflow_continuation(workflow_execution, workflow, conversation)
60
+ handle_workflow_continuation(workflow_execution, conversation)
61
61
  rescue StandardError => e
62
62
  handle_agent_error(e, workflow_step, workflow, workflow_execution)
63
63
  raise
@@ -77,10 +77,10 @@ module Services
77
77
  workflow_execution.increment_step
78
78
  end
79
79
 
80
- def handle_workflow_continuation(workflow_execution, workflow, conversation)
80
+ def handle_workflow_continuation(workflow_execution, conversation)
81
81
  new_inputs = extract_tool_call_inputs(conversation)
82
82
 
83
- if workflow_execution.current_step < workflow.total_steps
83
+ if workflow_execution.current_step < workflow_execution.total_steps
84
84
  schedule_next_workflow_step_with_inputs(new_inputs)
85
85
  else
86
86
  workflow_execution.update(completed: true)
@@ -127,35 +127,35 @@ module Services
127
127
  # the step advancement is handled in the human input job
128
128
  end
129
129
 
130
- def process_record_redirect_action(workflow_execution, workflow)
130
+ def process_record_redirect_action(workflow_execution)
131
131
  ::MetaWorkflows::RecordRedirectJob.perform_later(workflow_execution: workflow_execution)
132
132
  workflow_execution.increment_step
133
133
 
134
- return unless workflow_execution.current_step >= workflow.total_steps
134
+ return unless workflow_execution.current_step >= workflow_execution.total_steps
135
135
 
136
136
  workflow_execution.update(completed: true)
137
137
  end
138
138
 
139
- def process_collection_create_action(execution_step, workflow_execution, workflow)
139
+ def process_collection_create_action(execution_step, workflow_execution)
140
140
  service = build_collection_service(execution_step, workflow_execution)
141
141
 
142
142
  begin
143
143
  service.call
144
144
  workflow_execution.increment_step
145
- continue_workflow(workflow_execution, workflow)
145
+ continue_workflow(workflow_execution)
146
146
  rescue StandardError => e
147
147
  Rails.logger.error("Error creating collection: #{e.message}")
148
148
  # The workflow should halt on error per requirements - do not increment step
149
149
  end
150
150
  end
151
151
 
152
- def process_record_update_action(execution_step, workflow_execution, workflow)
152
+ def process_record_update_action(execution_step, workflow_execution)
153
153
  service = build_record_update_service(execution_step, workflow_execution)
154
154
 
155
155
  begin
156
156
  service.call
157
157
  workflow_execution.increment_step
158
- continue_workflow(workflow_execution, workflow)
158
+ continue_workflow(workflow_execution)
159
159
  rescue StandardError => e
160
160
  Rails.logger.error("Error updating record: #{e.message}")
161
161
  # Let Sidekiq handle retry - reraise the error
@@ -192,8 +192,8 @@ module Services
192
192
  record_class.find(workflow_execution.record_id)
193
193
  end
194
194
 
195
- def continue_workflow(workflow_execution, workflow)
196
- if workflow_execution.current_step < workflow.total_steps
195
+ def continue_workflow(workflow_execution)
196
+ if workflow_execution.current_step < workflow_execution.total_steps
197
197
  schedule_next_workflow_step
198
198
  else
199
199
  workflow_execution.update(completed: true)
@@ -246,7 +246,8 @@ module Services
246
246
  workflow: workflow,
247
247
  current_step: 0,
248
248
  completed: false,
249
- workflow_params: workflow_params
249
+ workflow_params: workflow_params,
250
+ recipe: workflow.recipe
250
251
  )
251
252
  else
252
253
  workflow_execution = active_workflow_execution
@@ -261,9 +262,9 @@ module Services
261
262
  record.workflow_executions.order(created_at: :desc).first
262
263
  end
263
264
 
264
- def prepare_workflow_execution(workflow, workflow_execution)
265
- execution_step = workflow.step_data(workflow_execution.current_step)
266
- execution_output = workflow.step_output(workflow_execution.current_step)
265
+ def prepare_workflow_execution(workflow_execution)
266
+ execution_step = workflow_execution.step_data(workflow_execution.current_step)
267
+ execution_output = workflow_execution.step_output(workflow_execution.current_step)
267
268
  workflow_step = workflow_execution.workflow_steps.find_or_create_by(step: workflow_execution.current_step)
268
269
 
269
270
  [execution_step, execution_output, workflow_step]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meta_workflows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Medovyy
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-07-09 00:00:00.000000000 Z
12
+ date: 2025-07-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -180,6 +180,7 @@ files:
180
180
  - db/migrate/20250617192849_remove_repetition_from_meta_workflows_workflow_executions.rb
181
181
  - db/migrate/20250618175439_add_call_id_and_status_to_meta_workflows_tool_calls.rb
182
182
  - db/migrate/20250626211926_add_repetition_to_meta_workflows_workflow_steps.rb
183
+ - db/migrate/20250709153017_add_recipe_to_meta_workflows_workflow_executions.rb
183
184
  - lib/meta_workflows.rb
184
185
  - lib/meta_workflows/asset_installer.rb
185
186
  - lib/meta_workflows/configuration.rb