meta_workflows 0.9.11 → 0.9.12

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: da33fe899987ea382b188f0c9056155a1d40089422a73f676e68f4cd138a61ce
4
- data.tar.gz: 5260bf938ba32055af4487a2ddf696419e066f6038ca8bf26da661a1f3382457
3
+ metadata.gz: 73fcb0be3ef0902a994689da96b1d7dbd8164fe4997f3d1ffb47bbde0608c163
4
+ data.tar.gz: 15adbe1b54336b7cbc301a16e38924279d5ff44748d4310bc3bf6f6f28dac583
5
5
  SHA512:
6
- metadata.gz: 80a92e4f1083182254aa04fff0d25cb027fecdac86c7d4be3cad0c2eb549dd4e1eee618c62ff44fe27d7829f905b1f9409a23fd7e8cd4430280213702f8b66b5
7
- data.tar.gz: 2aa86b2638f5a50e4f6d50b66376f7788d1e9948c496d9ad688f3ede119ac5dba2411809d0fcc199f716579ef68a5369e4b198d885b23f5c010746788bf4df8e
6
+ metadata.gz: db5004eb9417c670f71fe1be96e4e25727dbaae9f592090469de5e4887f65017131aa46a8d127bcbd6077e62c144ba93dc04522988bcc77768095b88ca3eda05
7
+ data.tar.gz: 02f2c0a1ae62055685a369ff9ca08dd5b4793d4d902894a60eb3148a2857d8c3c2416316d60eadad31825015c5be801ba8f0fe108ae2b8acd0b9633fb3c6406b
@@ -160,6 +160,96 @@
160
160
  }
161
161
  }
162
162
 
163
+ /* Loader Message Styles */
164
+ .lexi-loader-bubble {
165
+ padding: 0.25rem 0.5rem;
166
+ margin-bottom: 0.25rem;
167
+ border: none;
168
+ }
169
+
170
+ @keyframes gradient-shift {
171
+ 0% {
172
+ background-position: 0% 50%;
173
+ }
174
+ 50% {
175
+ background-position: 100% 50%;
176
+ }
177
+ 100% {
178
+ background-position: 0% 50%;
179
+ }
180
+ }
181
+
182
+ @keyframes dot-bounce {
183
+ 0%, 80%, 100% {
184
+ transform: translateY(0);
185
+ opacity: 0.7;
186
+ }
187
+ 40% {
188
+ transform: translateY(-3px);
189
+ opacity: 1;
190
+ }
191
+ }
192
+
193
+ .lexi-loader-text {
194
+ font-size: 1.25rem;
195
+ background: linear-gradient(135deg, #7B5BA3 0%, #3A9999 50%, #7B5BA3 100%);
196
+ background-size: 200% 200%;
197
+ background-clip: text;
198
+ -webkit-background-clip: text;
199
+ -webkit-text-fill-color: transparent;
200
+ color: transparent;
201
+ font-style: italic;
202
+ animation: gradient-shift 2s ease-in-out infinite;
203
+ -webkit-text-stroke: 0.75px rgba(0, 0, 0, 0.15);
204
+ text-stroke: 0.75px rgba(0, 0, 0, 0.15);
205
+ }
206
+
207
+ .lexi-loader-ellipses {
208
+ display: inline-block;
209
+ }
210
+
211
+ .lexi-dot {
212
+ display: inline-block;
213
+ font-size: 1.25rem;
214
+ background: linear-gradient(135deg, #7B5BA3 0%, #3A9999 50%, #7B5BA3 100%);
215
+ background-size: 200% 200%;
216
+ background-clip: text;
217
+ -webkit-background-clip: text;
218
+ -webkit-text-fill-color: transparent;
219
+ color: transparent;
220
+ animation: gradient-shift 2s ease-in-out infinite, dot-bounce 1.4s ease-in-out infinite;
221
+ -webkit-text-stroke: 0.75px rgba(0, 0, 0, 0.15);
222
+ text-stroke: 0.75px rgba(0, 0, 0, 0.15);
223
+ margin-left: -0.125rem;
224
+ }
225
+
226
+ .lexi-dot-1 {
227
+ animation-delay: 0s, 0s;
228
+ }
229
+
230
+ .lexi-dot-2 {
231
+ animation-delay: 0s, 0.2s;
232
+ }
233
+
234
+ .lexi-dot-3 {
235
+ animation-delay: 0s, 0.4s;
236
+ }
237
+
238
+ .lexi-dot.lexi-dot-error {
239
+ background: linear-gradient(135deg, #dc2626 0%, #b91c1c 50%, #dc2626 100%);
240
+ background-size: 200% 200%;
241
+ background-clip: text;
242
+ -webkit-background-clip: text;
243
+ -webkit-text-fill-color: transparent;
244
+ color: transparent;
245
+ -webkit-text-stroke: 0.75px rgba(220, 38, 38, 0.15);
246
+ text-stroke: 0.75px rgba(220, 38, 38, 0.15);
247
+ }
248
+
249
+ .lexi-loader-container {
250
+ margin-top: -0.5rem;
251
+ }
252
+
163
253
  /* Lexi Chat Tray Styles */
164
254
  .lexi-chat-tray {
165
255
  display: flex;
@@ -380,13 +470,13 @@
380
470
  }
381
471
 
382
472
  .lexi-message-content-user {
383
- font-size: 1rem;
473
+ font-size: 1.25rem;
384
474
  color: var(--gray-800);
385
475
  }
386
476
 
387
477
  .lexi-message-content-assistant {
388
478
  color: black;
389
- font-size: 1rem;
479
+ font-size: 1.25rem;
390
480
  line-height: 1.25;
391
481
  max-width: none;
392
482
  }
@@ -723,3 +813,14 @@
723
813
  .lexi-chat-alpha-input-container {
724
814
  width: 100%;
725
815
  }
816
+
817
+ .lexi-error-content {
818
+ display: flex;
819
+ align-items: baseline;
820
+ gap: 0.5rem;
821
+ color: var(--red-700);
822
+ }
823
+
824
+ .lexi-error-content .lexi-loader-ellipses {
825
+ margin-left: 0.375rem;
826
+ }
@@ -45,8 +45,8 @@ module MetaWorkflows
45
45
  format.turbo_stream do
46
46
  render turbo_stream: [
47
47
  turbo_stream.replace(
48
- target_frame_id(@record),
49
- partial: meta_loader,
48
+ target_frame_id(@record, loader: true),
49
+ partial: meta_loader_message,
50
50
  locals: {
51
51
  record: @record,
52
52
  step_progress: fetch_step_progress
@@ -15,8 +15,7 @@ module MetaWorkflows
15
15
  protected
16
16
 
17
17
  def fetch_step_progress
18
- @workflow_execution.step_progress(@workflow_execution.current_step) || ['Processing your request...',
19
- 'Talking to the LLM...']
18
+ @workflow_execution.step_progress(@workflow_execution.current_step) || default_step_progress
20
19
  end
21
20
 
22
21
  def current_step_repetitions
@@ -2,17 +2,25 @@
2
2
 
3
3
  module MetaWorkflows
4
4
  module MetaWorkflowsHelper
5
- def target_frame_id(record, form: nil)
5
+ def target_frame_id(record, form: nil, loader: nil)
6
6
  base_id = "#{record.class.name.downcase}_#{record.id}"
7
- form ? "#{base_id}_form" : base_id
7
+
8
+ return "#{base_id}_loader" if loader
9
+ return "#{base_id}_form" if form
10
+
11
+ base_id
8
12
  end
9
13
 
10
14
  def turbo_stream_name(record)
11
15
  [record.class.name.downcase, record.id]
12
16
  end
13
17
 
14
- def meta_loader
15
- 'meta_workflows/loader'
18
+ def meta_loader_message
19
+ 'meta_workflows/loader_message'
20
+ end
21
+
22
+ def meta_error_message
23
+ 'meta_workflows/error_message'
16
24
  end
17
25
 
18
26
  def meta_response_form
@@ -67,5 +75,9 @@ module MetaWorkflows
67
75
  def current_step_has_repetitions?(workflow_execution)
68
76
  workflow_execution.step_repetitions(workflow_execution.current_step).present?
69
77
  end
78
+
79
+ def default_step_progress
80
+ ['Thinking']
81
+ end
70
82
  end
71
83
  end
@@ -20,6 +20,13 @@ module MetaWorkflows
20
20
  last_message = messages.last
21
21
  is_streaming = full_response.present?
22
22
 
23
+ # Remove loader message
24
+ Turbo::StreamsChannel.broadcast_remove_to(
25
+ turbo_stream_name(record),
26
+ target: target_frame_id(record, loader: true)
27
+ )
28
+
29
+ # Update main chat content
23
30
  Turbo::StreamsChannel.broadcast_replace_to(turbo_stream_name(record),
24
31
  target: target_frame_id(record),
25
32
  locals: {
@@ -73,7 +73,7 @@ module MetaWorkflows
73
73
  def handle_llm_error(error, workflow_step, conversation)
74
74
  log_error(error)
75
75
  store_error_in_workflow_step(error, workflow_step, conversation)
76
- broadcast_error_response(error)
76
+ broadcast_error_response
77
77
  end
78
78
 
79
79
  def log_error(error)
@@ -97,9 +97,16 @@ module MetaWorkflows
97
97
  workflow_execution.workflow_steps.find_by(step: workflow_execution.current_step)
98
98
  end
99
99
 
100
- def broadcast_error_response(error)
101
- error_message = "Error occured during LLM processing: #{error.message}"
102
- broadcast_response(chat, error_message)
100
+ def broadcast_error_response
101
+ # Replace loader with error message
102
+ Turbo::StreamsChannel.broadcast_replace_to(
103
+ turbo_stream_name(record),
104
+ target: target_frame_id(record, loader: true),
105
+ partial: 'meta_workflows/error_message',
106
+ locals: {
107
+ record: record
108
+ }
109
+ )
103
110
  end
104
111
 
105
112
  def broadcast_form(chat)
@@ -0,0 +1,14 @@
1
+ <div class="lexi-message-assistant">
2
+ <div class="lexi-message-bubble-assistant">
3
+ <div class="lexi-message-content-assistant">
4
+ <div class="lexi-error-content">
5
+ <i class="fa-solid fa-exclamation-triangle"></i>
6
+ <span>Uh oh! Lexi needs a quick break. One moment<span class="lexi-loader-ellipses">
7
+ <span class="lexi-dot lexi-dot-error lexi-dot-1">.</span>
8
+ <span class="lexi-dot lexi-dot-error lexi-dot-2">.</span>
9
+ <span class="lexi-dot lexi-dot-error lexi-dot-3">.</span>
10
+ </span></span>
11
+ </div>
12
+ </div>
13
+ </div>
14
+ </div>
@@ -1,4 +1,7 @@
1
1
  <%# Lexi Chat Alpha Tray (Center Display) %>
2
+ <% active_execution = local_assigns[:record]&.workflow_executions&.order(created_at: :desc)&.first %>
3
+ <% active_chat = active_execution&.workflow_steps&.last&.chat %>
4
+
2
5
  <div class="lexi-chat-alpha-tray lexi-chat-container">
3
6
  <%# Header with Lexi logo left and close button right %>
4
7
  <div class="lexi-chat-alpha-header">
@@ -19,17 +22,25 @@
19
22
  <%= image_tag("lexi-expanded2.png", alt: "Lexi Avatar", class: "lexi-avatar-large") %>
20
23
  </div>
21
24
 
25
+ <!-- Main content area (chat + input) -->
22
26
  <%# Right column - Chat and Input %>
23
27
  <div class="lexi-chat-alpha-right-column">
24
28
  <%# Scrollable chat messages area %>
25
29
  <div id="main-scroll-container" class="lexi-chat-alpha-messages">
26
- <%= render partial: meta_loader, locals: {record: local_assigns[:record], step_progress: ["Generating draft course objectives...", "Talking to the LLM..."] } %>
30
+ <%= render partial: meta_response, locals: {
31
+ record: local_assigns[:record],
32
+ chat: active_chat,
33
+ messages: active_chat&.messages&.order(:created_at) || [],
34
+ user_messages: active_chat&.messages&.where(role: 'user')&.order(:created_at) || [],
35
+ last_message: active_chat&.messages&.last,
36
+ full_response: nil,
37
+ is_streaming: false
38
+ } %>
27
39
  </div>
28
40
 
29
41
  <%# Input area (fixed at bottom) %>
30
42
  <div class="lexi-chat-alpha-input-area">
31
43
  <div class="lexi-chat-alpha-input-container">
32
- <% active_execution = local_assigns[:record]&.workflow_executions&.order(created_at: :desc)&.first %>
33
44
  <%= 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 } %>
34
45
  </div>
35
46
  </div>
@@ -1,4 +1,7 @@
1
1
  <%# Lexi Chat Tray %>
2
+ <% active_execution = local_assigns[:record]&.workflow_executions&.order(created_at: :desc)&.first %>
3
+ <% active_chat = active_execution&.workflow_steps&.last&.chat %>
4
+
2
5
  <div class="lexi-chat-tray lexi-chat-container-full">
3
6
  <!-- Header with Lexi logo and action icons -->
4
7
  <div class="lexi-chat-header">
@@ -17,14 +20,21 @@
17
20
 
18
21
  <!-- Chat messages area -->
19
22
  <div id="main-scroll-container" class="lexi-chat-messages">
20
- <%= render partial: meta_loader, locals: {record: local_assigns[:record], step_progress: ["Generating draft course objectives...", "Talking to the LLM..."] } %>
23
+ <%= render partial: meta_response, locals: {
24
+ record: local_assigns[:record],
25
+ chat: active_chat,
26
+ messages: active_chat&.messages&.order(:created_at) || [],
27
+ user_messages: active_chat&.messages&.where(role: 'user')&.order(:created_at) || [],
28
+ last_message: active_chat&.messages&.last,
29
+ full_response: nil,
30
+ is_streaming: false
31
+ } %>
21
32
  </div>
22
33
 
23
34
  <!-- Avatar and input area pinned to bottom -->
24
35
  <div class="lexi-chat-bottom">
25
36
  <%= image_tag("lexi-expanded.png", alt: "Lexi Avatar", class: "lexi-avatar") %>
26
37
  <div class="lexi-input-wrapper">
27
- <% active_execution = local_assigns[:record]&.workflow_executions&.order(created_at: :desc)&.first %>
28
38
  <%= 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 } %>
29
39
  </div>
30
40
  </div>
@@ -0,0 +1,16 @@
1
+ <div class="lexi-message-assistant">
2
+ <div class="lexi-loader-bubble">
3
+ <div class="lexi-message-content-assistant"
4
+ data-controller="loading-phrases"
5
+ data-loading-phrases-phrases-value="<%= (local_assigns[:step_progress] || default_step_progress).to_json %>">
6
+ <span data-loading-phrases-target="message" class="lexi-loader-text">
7
+ <%= default_step_progress.first %>
8
+ </span>
9
+ <span class="lexi-loader-ellipses">
10
+ <span class="lexi-dot lexi-dot-1">.</span>
11
+ <span class="lexi-dot lexi-dot-2">.</span>
12
+ <span class="lexi-dot lexi-dot-3">.</span>
13
+ </span>
14
+ </div>
15
+ </div>
16
+ </div>
@@ -44,4 +44,15 @@
44
44
  <% end %>
45
45
  <% end %>
46
46
  </div>
47
- <% end %>
47
+ <% end %>
48
+
49
+ <div class="lexi-loader-container">
50
+ <%= turbo_frame_tag target_frame_id(record, loader: true) do %>
51
+ <% if chat.blank? || chat.messages.empty? %>
52
+ <%= render partial: meta_loader_message, locals: {
53
+ record: local_assigns[:record],
54
+ step_progress: default_step_progress
55
+ } %>
56
+ <% end %>
57
+ <% end %>
58
+ </div>
@@ -3,7 +3,7 @@
3
3
  module MetaWorkflows
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- PATCH = 11 # this is automatically incremented by the build process
6
+ PATCH = 12 # 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.11
4
+ version: 0.9.12
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-10 00:00:00.000000000 Z
12
+ date: 2025-07-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -160,9 +160,10 @@ files:
160
160
  - app/services/meta_workflows/workflow_import_service.rb
161
161
  - app/sidekiq/meta_workflows/tools/meta_workflow_tool.rb
162
162
  - app/views/layouts/meta_workflows/application.html.erb
163
+ - app/views/meta_workflows/_error_message.html.erb
163
164
  - app/views/meta_workflows/_lexi_chat_alpha_tray.html.erb
164
165
  - app/views/meta_workflows/_lexi_chat_right_tray.html.erb
165
- - app/views/meta_workflows/_loader.html.erb
166
+ - app/views/meta_workflows/_loader_message.html.erb
166
167
  - app/views/meta_workflows/_redirect.html.erb
167
168
  - app/views/meta_workflows/_response_form_lexi.html.erb
168
169
  - app/views/meta_workflows/_response_lexi.html.erb
@@ -1,17 +0,0 @@
1
- <%= turbo_frame_tag target_frame_id(record) do %>
2
- <div class="flex flex-col items-center justify-center gap-2"
3
- data-controller="loading-phrases"
4
- data-loading-phrases-phrases-value="<%= (local_assigns[:step_progress] || ["Processing your request...", "Talking to the LLM..."]).to_json %>">
5
- <h2
6
- class="text-center font-semibold"
7
- data-loading-phrases-target="message"
8
- >
9
- Processing your request...
10
- </h2>
11
- <div class="sm-sprite loader">
12
- <span class="image-container">
13
- <img class="" src="https://cdn.strongmind.com/backpack-ui/latest/assets/images/png/loaders/CB_loader.png" alt="loaders/CB_loader.png">
14
- </span>
15
- </div>
16
- </div>
17
- <% end %>