meta_workflows 0.9.23 → 0.9.25

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: 726c1853fd74d44442e6948f4ecad0f15b0f4bc8c0ca178f5d74339478b4c5f1
4
- data.tar.gz: 4831f59cb31e16def136625e45fbaf5260e6dd5d1eaa26caf0514a9959d4beaf
3
+ metadata.gz: 45d13fedf05d6e20b7070f2615acbc0b90e2e34a68b573213ef71e4383c7b6cb
4
+ data.tar.gz: 86344d2db4c7ad7b33549f030e3b3c6017d668e24597655b6b369b97456cbb54
5
5
  SHA512:
6
- metadata.gz: d4f4f00a82d6f151797509c0caf49fc1c65b967c459815c77d70e06cbba1afdf2a1a118a5525743feeb3d8097d64d2d59278fae989b946b11435b6ab66e4fda1
7
- data.tar.gz: 1d04504d3da419f77e23be6bb244c8e759e98904bcbf21d680c4cfe7875321c45ca5fb381a25f967b81c1e64b904d0cd4eff295feb34305377c3c30d06e848e9
6
+ metadata.gz: 182ebf3da42adc40c4e7808da4a2a030af63500b97fc1b3dabb350c6eb165706fcdf208135773053fce14facd398e2515d4457113f54c853fd7c80e3141fe5aa
7
+ data.tar.gz: e1d867b821e2d42c6a215e0c6bd7a810604c490efa51a1791f6e2a0449192cd4bc628b2a30ff6eaf7710288f702c9cc336fb3e4b09346a5492cbe6c5af12fd0a
data/README.md CHANGED
@@ -67,6 +67,17 @@ MetaWorkflows supports several action types for different workflow needs:
67
67
  - Requires `prompt_id` for context presentation
68
68
  - Collects user feedback through forms
69
69
  - Workflow pauses until human input is provided
70
+ - Supports `advanceable: true` to show "Next" button for manual step advancement
71
+ - **Note**: When `repetitions` is configured, advance/skip buttons are hidden and repetition logic takes precedence
72
+
73
+ ### `structured_human`
74
+ - Presents structured input UI (radio buttons, checkboxes, sliders) for user interaction
75
+ - Requires `prompt_id` for context presentation
76
+ - Collects structured user input through form elements
77
+ - Automatically advances to next step upon form submission
78
+ - Supports `skippable: true` to show "Skip" button for bypassing the step
79
+ - When `skippable` is present and clicked, a default user message will be sent 'Not mentioned' to notify the llm that the user did not answer whatever was being prompted
80
+ - **Note**: When `repetitions` is configured, skip buttons are hidden and repetition logic takes precedence
70
81
 
71
82
  ### `collection_create`
72
83
  - Creates collections of related records atomically
@@ -85,6 +96,68 @@ MetaWorkflows supports several action types for different workflow needs:
85
96
  - Marks workflow as complete
86
97
  - Requires `redirect_path` or `redirect_method` configuration
87
98
 
99
+ ## Workflow Step Behavior and Restrictions
100
+
101
+ ### Step Advancement Controls
102
+
103
+ MetaWorkflows provides fine-grained control over how users can advance through workflow steps:
104
+
105
+ #### `advanceable` (Human Steps Only)
106
+ - **Purpose**: Adds a "Next" button to `human` action steps for manual advancement
107
+ - **Usage**: Add `advanceable: true` to a `human` step configuration
108
+ - **Behavior**: Users can click "Next" to advance without providing input
109
+ - **Restriction**: **Not available when `repetitions` is configured** - repetition logic takes precedence
110
+
111
+ #### `skippable` (Structured Human Steps Only)
112
+ - **Purpose**: Adds a "Skip" button to `structured_human` action steps
113
+ - **Usage**: Add `skippable: true` to a `structured_human` step configuration
114
+ - **Behavior**: Users can skip the structured input and advance to the next step
115
+ - **Restriction**: **Not available when `repetitions` is configured** - repetition logic takes precedence
116
+
117
+ #### `repetitions`
118
+ - **Purpose**: Allows a step to repeat a specified number of times before advancing
119
+ - **Usage**: Add `repetitions: <number>` to any step configuration
120
+ - **Behavior**: Step will repeat until the specified count is reached, then auto-advance
121
+ - **Priority**: **Takes precedence over `advanceable` and `skippable`** - advance/skip buttons are hidden
122
+
123
+ ### Configuration Examples
124
+
125
+ ```yaml
126
+ # Human step with advance button (when no repetitions)
127
+ - name: "review_content"
128
+ action: "human"
129
+ prompt_id: "content_review"
130
+ advanceable: true
131
+
132
+ # Structured human step with skip button (when no repetitions)
133
+ - name: "optional_survey"
134
+ action: "structured_human"
135
+ prompt_id: "user_survey"
136
+ skippable: true
137
+ structured_input:
138
+ type: single_choice
139
+ options:
140
+ - label: "Option A"
141
+ value: "a"
142
+
143
+ # Step with repetitions (advance/skip buttons hidden)
144
+ - name: "retry_process"
145
+ action: "agent"
146
+ prompt_id: "processing_task"
147
+ repetitions: 3 # Will repeat 3 times before advancing
148
+ ```
149
+
150
+ ### Behavioral Rules
151
+
152
+ 1. **Repetitions Take Precedence**: When `repetitions` is configured on a step, advance and skip buttons are automatically hidden regardless of `advanceable` or `skippable` settings
153
+ 2. **Action Type Restrictions**:
154
+ - `advanceable` only applies to `human` action steps
155
+ - `skippable` only applies to `structured_human` action steps
156
+ 3. **Automatic vs Manual Advancement**:
157
+ - Steps with `repetitions` advance automatically after reaching the repeat count
158
+ - Steps with `advanceable`/`skippable` require user interaction to advance
159
+ - All other steps advance based on their action type's default behavior
160
+
88
161
  ## Model Configuration
89
162
 
90
163
  MetaWorkflows supports configuring different AI models for different workflow steps, allowing you to optimize performance and cost by using the most appropriate model for each task.
@@ -1,7 +1,7 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
3
  export default class extends Controller {
4
- static targets = ['textarea', 'form', 'structuredInputForm'];
4
+ static targets = ['textarea', 'form', 'structuredInputForm', 'hiddenMessage'];
5
5
 
6
6
  connect() {
7
7
  this.submitted = false;
@@ -19,7 +19,7 @@ export default class extends Controller {
19
19
  }
20
20
  }
21
21
 
22
- handleSubmit() {
22
+ handleSubmit(event) {
23
23
  if (this.submitted) {
24
24
  return;
25
25
  }
@@ -29,6 +29,28 @@ export default class extends Controller {
29
29
  }
30
30
 
31
31
  this.submitted = true;
32
+
33
+ if (this.hasHiddenMessageTarget) {
34
+ this.hiddenMessageTarget.disabled = true;
35
+ }
36
+
37
+ this.hideStructuredInputForm();
38
+ this.formTarget.requestSubmit();
39
+ }
40
+
41
+ handleSkip(event) {
42
+ event.preventDefault();
43
+
44
+ if (this.submitted) {
45
+ return;
46
+ }
47
+
48
+ this.submitted = true;
49
+
50
+ if (this.hasTextareaTarget) {
51
+ this.textareaTarget.disabled = true;
52
+ }
53
+
32
54
  this.hideStructuredInputForm();
33
55
  this.formTarget.requestSubmit();
34
56
  }
@@ -36,6 +58,14 @@ export default class extends Controller {
36
58
  hideStructuredInputForm() {
37
59
  if (this.hasStructuredInputFormTarget) {
38
60
  this.structuredInputFormTarget.style.display = 'none';
61
+ return;
62
+ }
63
+
64
+ const structuredForm = document.querySelector('[data-meta-workflows--lexi-form-submit-target="structuredInputForm"]');
65
+ if (structuredForm) {
66
+ structuredForm.style.display = 'none';
67
+ return;
39
68
  }
40
69
  }
41
70
  }
71
+
@@ -57,7 +57,9 @@ module MetaWorkflows
57
57
  chat_id: chat_id,
58
58
  response_enabled: response_enabled,
59
59
  responding: responding,
60
- step_has_repetitions: current_step_has_repetitions?(workflow_execution)
60
+ step_has_repetitions: current_step_has_repetitions?(workflow_execution),
61
+ show_next_button: show_next_button?(workflow_execution),
62
+ show_skip_button: show_skip_button?(workflow_execution)
61
63
  }
62
64
  end
63
65
 
@@ -49,7 +49,7 @@ module MetaWorkflows
49
49
  build_chat_history_stream(record: @record, workflow_execution: @workflow_execution),
50
50
  build_streaming_response_stream(record: @record, show_loader: true),
51
51
  build_response_form_stream(record: @record, workflow_execution: @workflow_execution,
52
- response_enabled: false, responding: false, chat_id: params[:chat_id])
52
+ response_enabled: false, responding: true, chat_id: params[:chat_id])
53
53
  ]
54
54
  end
55
55
  end
@@ -91,6 +91,18 @@ module MetaWorkflows
91
91
  workflow_execution.step_repetitions(workflow_execution.current_step).present?
92
92
  end
93
93
 
94
+ def show_next_button?(workflow_execution)
95
+ return false if current_step_has_repetitions?(workflow_execution)
96
+
97
+ workflow_execution.step_advanceable?(workflow_execution.current_step)
98
+ end
99
+
100
+ def show_skip_button?(workflow_execution)
101
+ return false if current_step_has_repetitions?(workflow_execution)
102
+
103
+ workflow_execution.step_skippable?(workflow_execution.current_step)
104
+ end
105
+
94
106
  def default_step_progress
95
107
  ['Thinking']
96
108
  end
@@ -43,6 +43,8 @@ module MetaWorkflows
43
43
  response_enabled: true,
44
44
  chat_id: chat.id,
45
45
  step_has_repetitions: current_step_has_repetitions?(workflow_execution),
46
+ show_next_button: show_next_button?(workflow_execution),
47
+ show_skip_button: show_skip_button?(workflow_execution),
46
48
  is_structured_input: is_structured_input }
47
49
  )
48
50
  end
@@ -23,6 +23,14 @@ module RecipeAccessible
23
23
  recipe&.dig('steps', step, 'repetitions')
24
24
  end
25
25
 
26
+ def step_advanceable?(step)
27
+ recipe&.dig('steps', step, 'advanceable') || false
28
+ end
29
+
30
+ def step_skippable?(step)
31
+ recipe&.dig('steps', step, 'skippable') || false
32
+ end
33
+
26
34
  def total_steps
27
35
  recipe&.dig('steps')&.size || 0
28
36
  end
@@ -51,7 +51,9 @@
51
51
  <%= render meta_structured_input, record: local_assigns[:record], structured_input_config: false, is_structured_input: false %>
52
52
 
53
53
  <!-- Regular Form Input (always present) -->
54
- <%= render partial: meta_response_form, locals: {record: local_assigns[:record], response_enabled: true, workflow_execution_id: active_execution&.id, chat_id: active_execution&.workflow_steps&.last&.chat&.id, step_has_repetitions: true, is_structured_input: is_structured_input } %>
54
+ <%= render partial: meta_response_form, locals: {record: local_assigns[:record], response_enabled: true,
55
+ workflow_execution_id: active_execution&.id, chat_id: active_execution&.workflow_steps&.last&.chat&.id,
56
+ workflow_execution: active_execution, is_structured_input: is_structured_input, show_skip_button: false, show_next_button: false } %>
55
57
  </div>
56
58
  </div>
57
59
  </div>
@@ -42,7 +42,8 @@
42
42
  <div class="lexi-input-wrapper" data-controller="meta-workflows--lexi-form-submit">
43
43
  <%= render meta_structured_input, record: local_assigns[:record], structured_input_config: false, is_structured_input: false %>
44
44
 
45
- <%= render partial: meta_response_form, locals: {record: local_assigns[:record], response_enabled: true, workflow_execution_id: active_execution&.id, chat_id: active_execution&.workflow_steps&.last&.chat&.id, step_has_repetitions: true, is_structured_input: is_structured_input } %>
45
+ <%= render partial: meta_response_form, locals: {record: local_assigns[:record], response_enabled: true, workflow_execution_id: active_execution&.id,
46
+ chat_id: active_execution&.workflow_steps&.last&.chat&.id, workflow_execution: active_execution, is_structured_input: is_structured_input } %>
46
47
  </div>
47
48
  </div>
48
49
  </div>
@@ -3,18 +3,17 @@
3
3
  <%= form_with url: workflow_execution_id.present? ? meta_workflows.human_path(workflow_execution_id) : "#",
4
4
  method: :patch,
5
5
  id: "#{target_frame_id(record, form: true)}_lexi",
6
- data: { "meta-workflows--lexi-form-submit-target": "form" } do |form| %>
6
+ data: { controller: "meta-workflows--lexi-form-submit", "meta-workflows--lexi-form-submit-target": "form", action: "submit->meta-workflows--lexi-form-submit#handleSubmit" } do |form| %>
7
7
  <%= form.hidden_field :chat_id, value: chat_id %>
8
8
  <% if local_assigns[:is_structured_input] %>
9
9
  <%= form.hidden_field :auto_advance, value: true %>
10
10
  <% end %>
11
- <fieldset>
12
11
  <div class="lexi-form-container">
13
12
  <!-- Input Container -->
14
13
  <div class="lexi-input-container lexi-input-max-height">
15
14
  <!-- Text Input -->
16
15
  <div class="lexi-textarea-wrapper">
17
- <%= 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" } %>
16
+ <%= 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", "meta-workflows--lexi-form-submit-target": "textarea" } %>
18
17
  </div>
19
18
 
20
19
  <div class="lexi-input-controls">
@@ -36,7 +35,7 @@
36
35
  <i class="fa-solid fa-arrow-up text-lg"></i>
37
36
  </button>
38
37
  <% else %>
39
- <%= form.button type: "submit", class: "lexi-send-button sm-btn sm-btn-primary" do %>
38
+ <%= form.button type: "button", class: "lexi-send-button sm-btn sm-btn-primary", data: { "meta-workflows--lexi-form-submit-target": "submitButton", action: "click->meta-workflows--lexi-form-submit#handleSubmit" } do %>
40
39
  <i class="fa-solid fa-arrow-up text-lg"></i>
41
40
  <% end %>
42
41
  <% end %>
@@ -47,13 +46,24 @@
47
46
  <p class="lexi-recording-notice">This chat is being recorded.</p>
48
47
 
49
48
  <div>
50
- <% if local_assigns[:step_has_repetitions] %>
51
- <!-- Empty placeholder to prevent layout jank -->
52
- <div aria-hidden="true"></div>
53
- <% else %>
54
- <%= form.button type: "submit", name: "manual_advance", value: "true", class: "lexi-advance-button #{'opacity-50 cursor-not-allowed' if local_assigns[:responding]}", disabled: local_assigns[:responding] do %>
49
+ <% workflow_execution = local_assigns[:workflow_execution] %>
50
+ <% if workflow_execution && show_next_button?(workflow_execution) || local_assigns[:show_next_button] %>
51
+ <!-- Next button for advanceable steps -->
52
+ <%= form.button type: "submit", name: "manual_advance", value: "true", class: "lexi-advance-button #{'opacity-50 cursor-not-allowed' if local_assigns[:responding]}", disabled: local_assigns[:responding], data: { "meta-workflows--lexi-form-submit-target": "submitButton", action: "click->meta-workflows--lexi-form-submit#handleSubmit" } do %>
55
53
  <i class="fa-light fa-arrow-right"></i> Next
56
54
  <% end %>
55
+ <% elsif workflow_execution && show_skip_button?(workflow_execution) || local_assigns[:show_skip_button] %>
56
+ <!-- Skip button for skippable steps -->
57
+ <%= form.button type: "submit", name: "auto_advance", value: true, class: "lexi-advance-button #{'opacity-50 cursor-not-allowed' if local_assigns[:responding]}", disabled: local_assigns[:responding], data: { action: "click->meta-workflows--lexi-form-submit#handleSkip" } do %>
58
+ <i class="fa-light fa-forward-step"></i> Skip
59
+ <% end %>
60
+ <%= form.hidden_field :message, value: "Not Mentioned", data: { "meta-workflows--lexi-form-submit-target": "hiddenMessage" } %>
61
+ <% elsif local_assigns[:step_has_repetitions] %>
62
+ <!-- Empty placeholder to prevent layout jank for repetitions -->
63
+ <div aria-hidden="true"></div>
64
+ <% else %>
65
+ <!-- Empty placeholder for steps with no buttons -->
66
+ <div aria-hidden="true"></div>
57
67
  <% end %>
58
68
  </div>
59
69
  </div>
@@ -3,7 +3,7 @@
3
3
  module MetaWorkflows
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- PATCH = 23 # this is automatically incremented by the build process
6
+ PATCH = 25 # this is automatically incremented by the build process
7
7
 
8
8
  VERSION = "#{MetaWorkflows::MAJOR}.#{MetaWorkflows::MINOR}.#{MetaWorkflows::PATCH}".freeze
9
9
  end
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.23
4
+ version: 0.9.25
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-18 00:00:00.000000000 Z
12
+ date: 2025-07-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails