meta_workflows 0.9.18 → 0.9.19

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: f70452cae76da68d70cc4e7b0f5c311ca8d287aac2526983fcee42e5cdb6555a
4
- data.tar.gz: 47d7637b8ec224c160b62ac55f363b07515d1e6d6a43350dc4127afb0839f32e
3
+ metadata.gz: cf7568849f397d177f74890b1036e8a8f6ab845ff7f68b67f53641688637ad8b
4
+ data.tar.gz: da332e7bd731c441e4a80ffa53b5ba398edca8843d459cc11aa51af81de7caa6
5
5
  SHA512:
6
- metadata.gz: 3b4bce3cecda4fa622ecc808fd5293f47e321c29bcd6ba1afb4b06f0aad1766307459275bb5bfaa89a03f0fd47f0dcc15cd55acbef3f33cfc8d42c7aa0690694
7
- data.tar.gz: a1881bb94b04d89dba925e60d1915a16db2b32f0fd28a60bb1fa1517743e52be625bbbb7a32e69c7c264e95235b3b4848cf151dccf27aa7c0a8ac5e1f3574f76
6
+ metadata.gz: cfdca5467ebd4caa0872c2bde60cc7b7b800d7caabf78673711fb0480e7f297e583f276527f95598c017d097617aff4648db156226865f82b1791aa9f9c1d123
7
+ data.tar.gz: b68da4e79a390b42dc74952987f09822093424190d2373d87a0a49067a226ff04e55325db5d1c6f501f3fd8341c16fd7a85a9d4ef70041e8dbcb32aeb58f19bf
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MetaWorkflows
4
+ module Concerns
5
+ module ErrorHandling
6
+ extend ActiveSupport::Concern
7
+
8
+ private
9
+
10
+ def handle_llm_error(error, workflow_step, workflow_execution, conversation)
11
+ log_error(error)
12
+ store_error_in_workflow_step(error, workflow_step, conversation)
13
+ broadcast_error_response(workflow_execution)
14
+ end
15
+
16
+ def log_error(error)
17
+ Rails.logger.error("LLM Error in MetaJob: #{error.message}")
18
+ Rails.logger.error(error.backtrace.join("\n"))
19
+ end
20
+
21
+ def store_error_in_workflow_step(error, workflow_step, conversation)
22
+ workflow_step&.record_error(error, additional_details: {
23
+ job_class: self.class.name,
24
+ chat_id: chat&.id,
25
+ conversation_id: conversation&.id,
26
+ full_response_length: full_response&.length || 0
27
+ })
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module MetaWorkflows
4
4
  class MetaJob < MetaWorkflows::ApplicationJob
5
+ include MetaWorkflows::Concerns::ErrorHandling
5
6
  include MetaWorkflows::Streamable
6
7
 
7
8
  attr_accessor :chat, :inputs, :full_response, :user_id, :record, :auto_advancing, :manual_advancing
@@ -70,27 +71,15 @@ module MetaWorkflows
70
71
 
71
72
  def finalize_conversation(conversation)
72
73
  chat.update!(conversation_id: conversation.id) if chat.conversation_id.blank?
74
+ persist_messages_to_history
73
75
  broadcast_form(chat) unless auto_advancing
74
76
  end
75
77
 
76
- def handle_llm_error(error, workflow_step, workflow_execution, conversation)
77
- log_error(error)
78
- store_error_in_workflow_step(error, workflow_step, conversation)
79
- broadcast_error_response(workflow_execution)
80
- end
81
-
82
- def log_error(error)
83
- Rails.logger.error("LLM Error in MetaJob: #{error.message}")
84
- Rails.logger.error(error.backtrace.join("\n"))
85
- end
86
-
87
- def store_error_in_workflow_step(error, workflow_step, conversation)
88
- workflow_step&.record_error(error, additional_details: {
89
- job_class: self.class.name,
90
- chat_id: chat&.id,
91
- conversation_id: conversation&.id,
92
- full_response_length: full_response&.length || 0
93
- })
78
+ def persist_messages_to_history
79
+ MetaWorkflows::MessageHistoryService.new(
80
+ chat: chat,
81
+ workflow_execution: active_workflow_execution
82
+ ).persist_messages_to_history
94
83
  end
95
84
 
96
85
  def current_workflow_step(workflow_execution)
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MetaWorkflows
4
+ class ExecutionChatHistory < ApplicationRecord
5
+ belongs_to :workflow_execution, class_name: 'MetaWorkflows::WorkflowExecution'
6
+
7
+ def append_message(message_data)
8
+ update!(history: history + [message_data])
9
+ end
10
+
11
+ def clear_history
12
+ update!(history: [])
13
+ end
14
+
15
+ def message_count
16
+ history.length
17
+ end
18
+
19
+ def last_message
20
+ history.last
21
+ end
22
+ end
23
+ end
@@ -7,6 +7,7 @@ module MetaWorkflows
7
7
  belongs_to :workflow, class_name: 'MetaWorkflows::Workflow'
8
8
  belongs_to :record, polymorphic: true
9
9
  has_many :workflow_steps, dependent: :destroy, class_name: 'MetaWorkflows::WorkflowStep'
10
+ has_one :execution_chat_history, dependent: :destroy, class_name: 'MetaWorkflows::ExecutionChatHistory'
10
11
 
11
12
  # Default values for fields
12
13
  attribute :current_step, :integer, default: 0
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MetaWorkflows
4
+ class MessageHistoryService < MetaWorkflows::ApplicationService
5
+ def initialize(chat:, workflow_execution:)
6
+ super()
7
+ @chat = chat
8
+ @workflow_execution = workflow_execution
9
+ end
10
+
11
+ def persist_messages_to_history
12
+ # Ensure ExecutionChatHistory exists
13
+ chat_history = workflow_execution.execution_chat_history ||
14
+ workflow_execution.create_execution_chat_history!
15
+
16
+ # Get all messages from the current chat (minus the first message since that is the system message)
17
+ messages = chat.messages.order(:created_at)[1..]
18
+
19
+ # Convert messages to a format suitable for persistence
20
+ messages.each do |message|
21
+ message_data = {
22
+ role: message.role,
23
+ content: message.content,
24
+ model_id: message.model_id,
25
+ input_tokens: message.input_tokens,
26
+ output_tokens: message.output_tokens,
27
+ created_at: message.created_at.iso8601,
28
+ step: workflow_execution.current_step
29
+ }
30
+
31
+ # Only append if not already in history (to avoid duplicates)
32
+ unless chat_history.history.any? { |h| h['content'] == message.content && h['role'] == message.role }
33
+ chat_history.append_message(message_data)
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :chat, :workflow_execution
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ <!-- Lexi message bubble (left-aligned, white background) -->
2
+ <div class="lexi-message-assistant">
3
+ <!-- Message Bubble -->
4
+ <div class="lexi-message-bubble-assistant">
5
+ <div class="lexi-message-content-assistant">
6
+ <%= markdown(content) %>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -1,6 +1,7 @@
1
1
  <%# Lexi Chat Alpha Tray (Center Display) %>
2
2
  <% active_execution = local_assigns[:record]&.workflow_executions&.order(created_at: :desc)&.first %>
3
3
  <% active_chat = active_execution&.workflow_steps&.last&.chat %>
4
+ <% chat_history = active_execution&.execution_chat_history %>
4
5
 
5
6
  <div class="lexi-chat-alpha-tray">
6
7
  <%# Header with Lexi logo left and close button right %>
@@ -34,7 +35,8 @@
34
35
  user_messages: active_chat&.messages&.where(role: 'user')&.order(:created_at) || [],
35
36
  last_message: active_chat&.messages&.last,
36
37
  full_response: nil,
37
- is_streaming: false
38
+ is_streaming: false,
39
+ chat_history: chat_history
38
40
  } %>
39
41
  </div>
40
42
 
@@ -1,46 +1,37 @@
1
1
  <%= turbo_frame_tag target_frame_id(record) do %>
2
2
  <div id="response-content-container" class="lexi-response-container" data-controller="response-scroll">
3
- <% if chat.present? && chat.messages.any? %>
4
-
5
- <!-- Show all saved messages except the first user message -->
6
- <% messages.each_with_index do |message, index| %>
7
- <% next if message.role == 'system' %>
8
- <% next if message.role == 'user' && message == user_messages.first %>
9
- <% next if is_streaming && message.role == 'assistant' && message == last_message %>
3
+
4
+ <!-- Show historical messages from ExecutionChatHistory -->
5
+ <% if local_assigns[:chat_history]&.history&.any? %>
6
+ <% local_assigns[:chat_history].history.each do |historical_message| %>
7
+ <% next if historical_message['role'] == 'system' %>
10
8
 
11
- <% if message.role == 'user' %>
12
- <!-- User message bubble (right-aligned, purple background) -->
13
- <div class="lexi-message-user">
14
- <div class="lexi-message-bubble-user">
15
- <div class="lexi-message-content-user">
16
- <%= simple_format(message.content) %>
17
- </div>
18
- </div>
19
- </div>
20
-
21
- <% elsif message.role == 'assistant' %>
22
- <!-- Lexi message bubble (left-aligned, white background) -->
23
- <div class="lexi-message-assistant">
24
- <!-- Message Bubble -->
25
- <div class="lexi-message-bubble-assistant">
26
- <div class="lexi-message-content-assistant">
27
- <%= markdown(message.content) %>
28
- </div>
29
- </div>
30
- </div>
9
+ <% if historical_message['role'] == 'user' %>
10
+ <%= render 'meta_workflows/user_message_bubble', content: historical_message['content'] %>
11
+ <% elsif historical_message['role'] == 'assistant' %>
12
+ <%= render 'meta_workflows/assistant_message_bubble', content: historical_message['content'] %>
31
13
  <% end %>
32
14
  <% end %>
33
-
15
+ <% end %>
16
+
17
+ <% if chat.present? && chat.messages.any? %>
34
18
  <!-- Show streaming response -->
35
19
  <% if is_streaming %>
36
- <div class="lexi-message-assistant">
37
- <!-- Streaming Message Bubble -->
38
- <div class="lexi-message-bubble-assistant">
39
- <div class="lexi-message-content-assistant">
40
- <%= markdown(full_response) %>
41
- </div>
42
- </div>
43
- </div>
20
+
21
+ <!-- Show all saved messages except the first user message -->
22
+ <% messages.each_with_index do |message, index| %>
23
+ <% next if message.role == 'system' %>
24
+ <% next if message.role == 'user' && message == user_messages.first %>
25
+ <% next if is_streaming && message.role == 'assistant' && message == last_message %>
26
+
27
+ <% if message.role == 'user' %>
28
+ <%= render 'meta_workflows/user_message_bubble', content: message.content %>
29
+ <% elsif message.role == 'assistant' %>
30
+ <%= render 'meta_workflows/assistant_message_bubble', content: message.content %>
31
+ <% end %>
32
+ <% end %>
33
+
34
+ <%= render 'meta_workflows/assistant_message_bubble', content: full_response %>
44
35
  <% end %>
45
36
  <% end %>
46
37
 
@@ -0,0 +1,8 @@
1
+ <!-- User message bubble (right-aligned, purple background) -->
2
+ <div class="lexi-message-user">
3
+ <div class="lexi-message-bubble-user">
4
+ <div class="lexi-message-content-user">
5
+ <%= simple_format(content) %>
6
+ </div>
7
+ </div>
8
+ </div>
@@ -0,0 +1,12 @@
1
+ class CreateMetaWorkflowsExecutionChatHistories < ActiveRecord::Migration[7.2]
2
+ def change
3
+ create_table :meta_workflows_execution_chat_histories do |t|
4
+ t.references :workflow_execution, null: false, foreign_key: { to_table: :meta_workflows_workflow_executions }
5
+ t.jsonb :history, null: false, default: []
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :meta_workflows_execution_chat_histories, :workflow_execution_id, unique: true, name: 'index_execution_chat_histories_on_workflow_execution_id'
11
+ end
12
+ end
@@ -3,7 +3,7 @@
3
3
  module MetaWorkflows
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- PATCH = 18 # this is automatically incremented by the build process
6
+ PATCH = 19 # 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.18
4
+ version: 0.9.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Medovyy
@@ -143,6 +143,7 @@ files:
143
143
  - app/helpers/meta_workflows/meta_workflows_helper.rb
144
144
  - app/helpers/meta_workflows/status_badge_helper.rb
145
145
  - app/jobs/meta_workflows/application_job.rb
146
+ - app/jobs/meta_workflows/concerns/error_handling.rb
146
147
  - app/jobs/meta_workflows/human_input_job.rb
147
148
  - app/jobs/meta_workflows/meta_job.rb
148
149
  - app/jobs/meta_workflows/meta_workflow_job.rb
@@ -152,6 +153,7 @@ files:
152
153
  - app/models/meta_workflows.rb
153
154
  - app/models/meta_workflows/application_record.rb
154
155
  - app/models/meta_workflows/chat.rb
156
+ - app/models/meta_workflows/execution_chat_history.rb
155
157
  - app/models/meta_workflows/message.rb
156
158
  - app/models/meta_workflows/tool_call.rb
157
159
  - app/models/meta_workflows/workflow.rb
@@ -159,9 +161,11 @@ files:
159
161
  - app/models/meta_workflows/workflow_step.rb
160
162
  - app/services/meta_workflows/application_service.rb
161
163
  - app/services/meta_workflows/execution_filter_service.rb
164
+ - app/services/meta_workflows/message_history_service.rb
162
165
  - app/services/meta_workflows/workflow_import_service.rb
163
166
  - app/sidekiq/meta_workflows/tools/meta_workflow_tool.rb
164
167
  - app/views/layouts/meta_workflows/application.html.erb
168
+ - app/views/meta_workflows/_assistant_message_bubble.html.erb
165
169
  - app/views/meta_workflows/_error_message.html.erb
166
170
  - app/views/meta_workflows/_lexi_chat_alpha_tray.html.erb
167
171
  - app/views/meta_workflows/_lexi_chat_right_tray.html.erb
@@ -169,6 +173,7 @@ files:
169
173
  - app/views/meta_workflows/_redirect.html.erb
170
174
  - app/views/meta_workflows/_response_form_lexi.html.erb
171
175
  - app/views/meta_workflows/_response_lexi.html.erb
176
+ - app/views/meta_workflows/_user_message_bubble.html.erb
172
177
  - app/views/meta_workflows/debug/executions.html.erb
173
178
  - app/views/meta_workflows/debug/show_execution.html.erb
174
179
  - app/views/meta_workflows/debug/show_workflow.html.erb
@@ -186,6 +191,7 @@ files:
186
191
  - db/migrate/20250618175439_add_call_id_and_status_to_meta_workflows_tool_calls.rb
187
192
  - db/migrate/20250626211926_add_repetition_to_meta_workflows_workflow_steps.rb
188
193
  - db/migrate/20250709153017_add_recipe_to_meta_workflows_workflow_executions.rb
194
+ - db/migrate/20250714192853_create_meta_workflows_execution_chat_histories.rb
189
195
  - lib/meta_workflows.rb
190
196
  - lib/meta_workflows/asset_installer.rb
191
197
  - lib/meta_workflows/configuration.rb