meta_workflows 0.8.6 → 0.8.8
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 +4 -4
- data/app/controllers/concerns/tray_configurable.rb +9 -6
- data/app/helpers/meta_workflows/meta_workflows_helper.rb +2 -2
- data/app/jobs/meta_workflows/human_input_job.rb +17 -3
- data/app/jobs/meta_workflows/meta_job.rb +14 -19
- data/app/views/meta_workflows/_response_form_lexi.html.erb +53 -0
- data/app/views/meta_workflows/_response_lexi.html.erb +57 -0
- data/lib/meta_workflows/version.rb +1 -1
- data/lib/services/meta_workflows/meta_workflow_service.rb +7 -2
- metadata +4 -4
- data/app/views/meta_workflows/_response.html.erb +0 -5
- data/app/views/meta_workflows/_response_form.html.erb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b59bf863e285b8d7f6b88f4d7547745bf89776f6e8c6ee1b7a77feee3fbe4d8
|
4
|
+
data.tar.gz: 1e005cddde9031f92399c506f3ca84f61db4703b6784c2aa5b4e496f218a2ea9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70110e137cc53c66b295d90b8a02485498029f30c62db4d4b7c5eedfe7c7b0273141745a30172ee1d7a0e6bb86aa32abf7446a921514c0b940c6c59d47c03a85
|
7
|
+
data.tar.gz: d10e39347a37ae1b1747a19bc3baa501fe84698940726238229302f8504a53a5b01365e47c878b3aceb2add999dec9c1d723094b4c8551166526a03d2ca84f7b
|
@@ -10,16 +10,19 @@ module TrayConfigurable
|
|
10
10
|
def tray_config
|
11
11
|
@tray_config ||= {
|
12
12
|
beta: {
|
13
|
-
visible:
|
14
|
-
collapsible: true
|
13
|
+
visible: true,
|
14
|
+
collapsible: true,
|
15
|
+
lexi: false
|
15
16
|
},
|
16
17
|
gamma: {
|
17
|
-
visible:
|
18
|
-
collapsible: true
|
18
|
+
visible: true,
|
19
|
+
collapsible: true,
|
20
|
+
lexi: false
|
19
21
|
},
|
20
22
|
delta: {
|
21
|
-
visible:
|
22
|
-
collapsible: true
|
23
|
+
visible: true,
|
24
|
+
collapsible: true,
|
25
|
+
lexi: false
|
23
26
|
}
|
24
27
|
}
|
25
28
|
end
|
@@ -16,11 +16,11 @@ module MetaWorkflows
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def meta_response_form
|
19
|
-
'meta_workflows/
|
19
|
+
'meta_workflows/response_form_lexi'
|
20
20
|
end
|
21
21
|
|
22
22
|
def meta_response
|
23
|
-
'meta_workflows/
|
23
|
+
'meta_workflows/response_lexi'
|
24
24
|
end
|
25
25
|
|
26
26
|
def meta_redirect
|
@@ -13,20 +13,34 @@ module MetaWorkflows
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def broadcast_response(
|
16
|
+
def broadcast_response(chat, full_response)
|
17
|
+
user_messages = chat.messages.where(role: 'user').order(:created_at)
|
18
|
+
messages = chat.messages.order(:created_at)
|
19
|
+
last_message = messages.last
|
20
|
+
is_streaming = full_response.present?
|
21
|
+
|
17
22
|
Turbo::StreamsChannel.broadcast_replace_to(turbo_stream_name(record),
|
18
23
|
target: target_frame_id(record),
|
19
|
-
locals: {
|
24
|
+
locals: {
|
25
|
+
record: record,
|
26
|
+
chat: chat,
|
27
|
+
full_response: full_response,
|
28
|
+
user_messages: user_messages,
|
29
|
+
messages: messages,
|
30
|
+
last_message: last_message,
|
31
|
+
is_streaming: is_streaming
|
32
|
+
},
|
20
33
|
partial: meta_response)
|
21
34
|
end
|
22
35
|
|
23
36
|
def broadcast_form(chat)
|
37
|
+
workflow_execution = active_workflow_execution
|
24
38
|
Turbo::StreamsChannel.broadcast_replace_to(
|
25
39
|
turbo_stream_name(record),
|
26
40
|
target: target_frame_id(record, form: true),
|
27
41
|
partial: meta_response_form,
|
28
42
|
locals: { record: record,
|
29
|
-
workflow_execution_id:
|
43
|
+
workflow_execution_id: workflow_execution&.id,
|
30
44
|
response_enabled: true,
|
31
45
|
chat_id: chat.id }
|
32
46
|
)
|
@@ -9,6 +9,7 @@ module MetaWorkflows
|
|
9
9
|
def setup(user_id, record)
|
10
10
|
@user_id = user_id
|
11
11
|
@record = record.class.find(record.id)
|
12
|
+
@full_response = +''
|
12
13
|
end
|
13
14
|
|
14
15
|
def initialize_conversation(params)
|
@@ -22,12 +23,10 @@ module MetaWorkflows
|
|
22
23
|
def initialize_new_conversation(params)
|
23
24
|
inputs = params.symbolize_keys[:inputs]
|
24
25
|
|
25
|
-
workflow_execution =
|
26
|
-
current_step = workflow_execution.workflow_steps
|
26
|
+
workflow_execution = active_workflow_execution
|
27
|
+
current_step = workflow_execution.workflow_steps&.find_by(step: workflow_execution.current_step)
|
27
28
|
@chat = current_step&.chat
|
28
29
|
|
29
|
-
@full_response = +''
|
30
|
-
|
31
30
|
conversation = RubyConversations::Conversation.new(chat:)
|
32
31
|
conversation.with_prompt(params[:prompt_id], inputs: inputs, description: "Running #{params[:prompt_id]} process")
|
33
32
|
end
|
@@ -35,11 +34,8 @@ module MetaWorkflows
|
|
35
34
|
def continue_existing_conversation(params)
|
36
35
|
@chat = MetaWorkflows::Chat.find(params[:chat_id])
|
37
36
|
conversation = RubyConversations::Conversation.new(chat:, id: chat.conversation_id)
|
38
|
-
|
39
37
|
new_message = params[:inputs]
|
40
38
|
conversation.with_user_message(new_message, description: "Following up on #{params[:prompt_id]} process")
|
41
|
-
@full_response = chat.messages[1..].map(&:content).join + format_user_message(new_message)
|
42
|
-
|
43
39
|
conversation
|
44
40
|
end
|
45
41
|
|
@@ -62,14 +58,13 @@ module MetaWorkflows
|
|
62
58
|
|
63
59
|
def execute_llm_conversation(conversation)
|
64
60
|
conversation.call_llm do |chunk|
|
65
|
-
full_response << (chunk.content || '')
|
66
|
-
broadcast_response(full_response)
|
61
|
+
@full_response << (chunk.content || '')
|
62
|
+
broadcast_response(chat, full_response)
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
70
66
|
def finalize_conversation(conversation)
|
71
67
|
chat.update!(conversation_id: conversation.id) if chat.conversation_id.blank?
|
72
|
-
broadcast_response(full_response)
|
73
68
|
broadcast_form(chat)
|
74
69
|
end
|
75
70
|
|
@@ -94,28 +89,28 @@ module MetaWorkflows
|
|
94
89
|
end
|
95
90
|
|
96
91
|
def current_workflow_step
|
97
|
-
|
92
|
+
workflow_execution = active_workflow_execution
|
93
|
+
return nil unless workflow_execution
|
98
94
|
|
99
|
-
workflow_execution = record.workflow_execution
|
100
95
|
workflow_execution.workflow_steps.find_by(step: workflow_execution.current_step)
|
101
96
|
end
|
102
97
|
|
103
98
|
def broadcast_error_response(error)
|
104
|
-
error_message = "Error
|
105
|
-
broadcast_response(error_message)
|
99
|
+
error_message = "Error occured during LLM processing: #{error.message}"
|
100
|
+
broadcast_response(chat, error_message)
|
106
101
|
end
|
107
102
|
|
108
|
-
def
|
103
|
+
def broadcast_form(chat)
|
109
104
|
raise NotImplementedError
|
110
105
|
end
|
111
106
|
|
112
|
-
def
|
107
|
+
def broadcast_response(chat, full_response)
|
113
108
|
raise NotImplementedError
|
114
109
|
end
|
115
110
|
|
116
|
-
|
117
|
-
|
118
|
-
|
111
|
+
# Get the most recent (active) workflow execution for the record
|
112
|
+
def active_workflow_execution
|
113
|
+
record.workflow_executions.order(created_at: :desc).first
|
119
114
|
end
|
120
115
|
end
|
121
116
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<%= turbo_frame_tag target_frame_id(record, form: true) do %>
|
2
|
+
<% if local_assigns[:response_enabled] %>
|
3
|
+
<div>
|
4
|
+
<%= form_with url: (workflow_execution_id.present? ? meta_workflows.human_path(workflow_execution_id) : "#"), method: :patch do |form| %>
|
5
|
+
<%= form.hidden_field :chat_id, value: chat_id %>
|
6
|
+
<fieldset>
|
7
|
+
<div class="flex flex-col gap-1">
|
8
|
+
<!-- Input Container -->
|
9
|
+
<div class="flex flex-col max-h-[200px] border border-gray-300 rounded-lg bg-white/80 p-2">
|
10
|
+
<!-- Input area with icons -->
|
11
|
+
<div class="flex-1 relative">
|
12
|
+
<%= form.text_area :message, rows: 1, placeholder: random_chat_placeholder, disabled: local_assigns[:responding], class: "w-full min-h-[50px] border-0 resize-none focus:outline-none focus:ring-0 bg-transparent text-base overflow-y-auto" %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="flex justify-between">
|
16
|
+
<div class="flex gap-1 items-end justify-end">
|
17
|
+
<button type="button" class="p-2 rounded-xl hover:bg-gray-100" disabled>
|
18
|
+
<i class="fa-solid fa-microphone text-lg"></i>
|
19
|
+
</button>
|
20
|
+
<button type="button" class="p-2 rounded-xl hover:bg-gray-100" disabled>
|
21
|
+
<i class="fa-solid fa-headphones text-lg"></i>
|
22
|
+
</button>
|
23
|
+
<button type="button" class="p-2 rounded-xl hover:bg-gray-100" disabled>
|
24
|
+
<i class="fa-solid fa-waveform-lines text-lg"></i>
|
25
|
+
</button>
|
26
|
+
</div>
|
27
|
+
<div>
|
28
|
+
<!-- Send button -->
|
29
|
+
<% if local_assigns[:responding] %>
|
30
|
+
<button type="button" class="w-12 h-12 rounded-full flex items-center justify-center text-white transition-colors bg-purple-600 opacity-50 cursor-not-allowed" disabled>
|
31
|
+
<i class="fa-solid fa-arrow-up text-lg"></i>
|
32
|
+
</button>
|
33
|
+
<% else %>
|
34
|
+
<%= form.button type: "submit", class: "w-12 h-12 rounded-full flex items-center justify-center text-white bg-purple-600 transition-colors focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2" do %>
|
35
|
+
<i class="fa-solid fa-arrow-up text-lg"></i>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<!-- Next Button (outside input container) -->
|
43
|
+
<div class="flex justify-end">
|
44
|
+
<%= form.button type: "submit", name: "advance", value: "true", class: "text-xs mb-2 #{local_assigns[:responding] ? 'opacity-50 cursor-not-allowed' : ''}", disabled: local_assigns[:responding] do %>
|
45
|
+
<i class="fa-light fa-arrow-right"></i> Next
|
46
|
+
<% end %>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
</fieldset>
|
50
|
+
<% end %>
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
<% end %>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<%= turbo_frame_tag target_frame_id(record) do %>
|
2
|
+
<div id="response-content-container" class="space-y-4" 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 %>
|
10
|
+
|
11
|
+
<% if message.role == 'user' %>
|
12
|
+
<!-- User message bubble (right-aligned, amber background) -->
|
13
|
+
<div class="flex justify-end">
|
14
|
+
<div class="max-w-[80%] bg-amber-100 rounded-xl px-4 py-2">
|
15
|
+
<div class="text-sm">
|
16
|
+
<%= simple_format(message.content) %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<% elsif message.role == 'assistant' %>
|
22
|
+
<!-- Lexi message bubble (left-aligned with avatar) -->
|
23
|
+
<div class="flex items-start space-x-3">
|
24
|
+
<!-- Lexi Avatar -->
|
25
|
+
<div class="flex-shrink-0">
|
26
|
+
<%= image_tag 'lexi-chaticon.png', alt: 'Lexi', class: 'w-auto h-10' %>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<!-- Message Bubble -->
|
30
|
+
<div class="max-w-[80%] bg-slate-100 rounded-xl px-4 py-2">
|
31
|
+
<div class="prose prose-sm max-w-none text-sm">
|
32
|
+
<%= markdown(message.content) %>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<!-- Show streaming response -->
|
40
|
+
<% if is_streaming %>
|
41
|
+
<div class="flex items-start space-x-3">
|
42
|
+
<!-- Lexi Avatar -->
|
43
|
+
<div class="flex-shrink-0">
|
44
|
+
<%= image_tag 'lexi-chaticon.png', alt: 'Lexi', class: 'w-auto h-10' %>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<!-- Streaming Message Bubble -->
|
48
|
+
<div class="max-w-[80%] bg-slate-100 rounded-xl px-4 py-2">
|
49
|
+
<div class="prose prose-sm max-w-none text-sm">
|
50
|
+
<%= markdown(full_response) %>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
<% end %>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
57
|
+
<% end %>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module MetaWorkflows
|
4
4
|
MAJOR = 0
|
5
5
|
MINOR = 8
|
6
|
-
PATCH =
|
6
|
+
PATCH = 8 # this is automatically incremented by the build process
|
7
7
|
|
8
8
|
VERSION = "#{MetaWorkflows::MAJOR}.#{MetaWorkflows::MINOR}.#{MetaWorkflows::PATCH}".freeze
|
9
9
|
end
|
@@ -235,7 +235,7 @@ module Services
|
|
235
235
|
end
|
236
236
|
|
237
237
|
def validate_workflow_presence
|
238
|
-
return unless workflow_name.nil? &&
|
238
|
+
return unless workflow_name.nil? && active_workflow_execution.blank?
|
239
239
|
|
240
240
|
raise ArgumentError, 'No workflow specified and record has no workflow attached'
|
241
241
|
end
|
@@ -251,13 +251,18 @@ module Services
|
|
251
251
|
workflow_params: workflow_params
|
252
252
|
)
|
253
253
|
else
|
254
|
-
workflow_execution =
|
254
|
+
workflow_execution = active_workflow_execution
|
255
255
|
workflow = workflow_execution.workflow
|
256
256
|
end
|
257
257
|
|
258
258
|
[workflow, workflow_execution]
|
259
259
|
end
|
260
260
|
|
261
|
+
# Get the most recent (active) workflow execution for the record
|
262
|
+
def active_workflow_execution
|
263
|
+
record.workflow_executions.order(created_at: :desc).first
|
264
|
+
end
|
265
|
+
|
261
266
|
def prepare_workflow_execution(workflow, workflow_execution)
|
262
267
|
execution_step = workflow.step_data(workflow_execution.current_step)
|
263
268
|
execution_output = workflow.step_output(workflow_execution.current_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.8.
|
4
|
+
version: 0.8.8
|
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-06-
|
12
|
+
date: 2025-06-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -152,8 +152,8 @@ files:
|
|
152
152
|
- app/views/layouts/meta_workflows/debug.html.erb
|
153
153
|
- app/views/meta_workflows/_loader.html.erb
|
154
154
|
- app/views/meta_workflows/_redirect.html.erb
|
155
|
-
- app/views/meta_workflows/
|
156
|
-
- app/views/meta_workflows/
|
155
|
+
- app/views/meta_workflows/_response_form_lexi.html.erb
|
156
|
+
- app/views/meta_workflows/_response_lexi.html.erb
|
157
157
|
- app/views/meta_workflows/debug/executions.html.erb
|
158
158
|
- app/views/meta_workflows/debug/show_execution.html.erb
|
159
159
|
- app/views/meta_workflows/debug/show_workflow.html.erb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
<%= turbo_frame_tag target_frame_id(record, form: true) do %>
|
2
|
-
<% if local_assigns[:response_enabled] %>
|
3
|
-
<div>
|
4
|
-
<%= form_with url: meta_workflows.human_path(workflow_execution_id), method: :patch do |form| %>
|
5
|
-
<%= form.hidden_field :chat_id, value: chat_id %>
|
6
|
-
<fieldset>
|
7
|
-
<div class="flex flex-col gap-5">
|
8
|
-
<div class="flex gap-2">
|
9
|
-
<%= form.text_area :message, rows: 3, placeholder: random_chat_placeholder, disabled: local_assigns[:responding], class: "flex-1" %>
|
10
|
-
|
11
|
-
<% if local_assigns[:responding] %>
|
12
|
-
<button type="button" class="sm-btn sm-btn-primary self-start" disabled>
|
13
|
-
<i class="fa-light fa-spinner fa-spin mr-1"></i> Generating...
|
14
|
-
</button>
|
15
|
-
<% else %>
|
16
|
-
<%= form.button type: "submit", class: "sm-btn sm-btn-outline" do %>
|
17
|
-
<i class="fa-light fa-paper-plane"></i>
|
18
|
-
<% end %>
|
19
|
-
<% end %>
|
20
|
-
</div>
|
21
|
-
|
22
|
-
<hr/>
|
23
|
-
|
24
|
-
<% unless local_assigns[:responding] %>
|
25
|
-
<div class="flex justify-end">
|
26
|
-
<%= form.button type: "submit", name: "advance", value: "true", class: "sm-btn sm-btn-primary sm-btn-large" do %>
|
27
|
-
<i class="fa-light fa-arrow-right"></i> Next
|
28
|
-
<% end %>
|
29
|
-
</div>
|
30
|
-
<% end %>
|
31
|
-
</div>
|
32
|
-
</fieldset>
|
33
|
-
<% end %>
|
34
|
-
</div>
|
35
|
-
<% end %>
|
36
|
-
<% end %>
|