From 589020ab373422385104dcab897c970d820f5adb Mon Sep 17 00:00:00 2001 From: centdix Date: Tue, 7 Oct 2025 14:06:12 +0000 Subject: [PATCH 01/26] save each assitant and tool message --- ...update_conversation_message_types.down.sql | 11 + ...6_update_conversation_message_types.up.sql | 9 + .../windmill-api/src/flow_conversations.rs | 15 +- backend/windmill-api/src/jobs.rs | 12 +- backend/windmill-worker/src/ai_executor.rs | 192 +++++++++++++++++- .../conversations/FlowChatMessage.svelte | 72 ++++--- 6 files changed, 267 insertions(+), 44 deletions(-) create mode 100644 backend/migrations/20251007123506_update_conversation_message_types.down.sql create mode 100644 backend/migrations/20251007123506_update_conversation_message_types.up.sql diff --git a/backend/migrations/20251007123506_update_conversation_message_types.down.sql b/backend/migrations/20251007123506_update_conversation_message_types.down.sql new file mode 100644 index 0000000000000..7786d7da9aeb5 --- /dev/null +++ b/backend/migrations/20251007123506_update_conversation_message_types.down.sql @@ -0,0 +1,11 @@ +-- Remove step_name column +ALTER TABLE flow_conversation_message +DROP COLUMN IF EXISTS step_name; + +-- Note: PostgreSQL doesn't support removing values from ENUMs directly +-- You would need to recreate the enum to remove values, which is complex +-- and may cause issues with existing data. For safety, we leave the enum values. +-- If you need to fully revert, you'll need to: +-- 1. Create a new enum without the new values +-- 2. Update all uses to the new enum +-- 3. Drop the old enum diff --git a/backend/migrations/20251007123506_update_conversation_message_types.up.sql b/backend/migrations/20251007123506_update_conversation_message_types.up.sql new file mode 100644 index 0000000000000..465d03e43804a --- /dev/null +++ b/backend/migrations/20251007123506_update_conversation_message_types.up.sql @@ -0,0 +1,9 @@ +-- Add up migration script here + +-- Extend MESSAGE_TYPE enum to include 'system' and 'tool' +ALTER TYPE MESSAGE_TYPE ADD VALUE 'system'; +ALTER TYPE MESSAGE_TYPE ADD VALUE 'tool'; + +-- Add step_name column to flow_conversation_message table +ALTER TABLE flow_conversation_message +ADD COLUMN step_name VARCHAR(255); \ No newline at end of file diff --git a/backend/windmill-api/src/flow_conversations.rs b/backend/windmill-api/src/flow_conversations.rs index efe11c2045eca..497f759ac75c9 100644 --- a/backend/windmill-api/src/flow_conversations.rs +++ b/backend/windmill-api/src/flow_conversations.rs @@ -22,6 +22,8 @@ use windmill_common::{ pub enum MessageType { User, Assistant, + System, + Tool, } pub fn workspaced_service() -> Router { @@ -50,6 +52,7 @@ pub struct FlowConversationMessage { pub content: String, pub job_id: Option, pub created_at: DateTime, + pub step_name: Option, } #[derive(Deserialize)] @@ -226,9 +229,9 @@ async fn list_messages( // Fetch messages for this conversation, oldest first, but reverse the order of the messages for easy rendering on the frontend let messages = sqlx::query_as!( FlowConversationMessage, - r#"SELECT id, conversation_id, message_type as "message_type: MessageType", content, job_id, created_at + r#"SELECT id, conversation_id, message_type as "message_type: MessageType", content, job_id, created_at, step_name FROM ( - SELECT id, conversation_id, message_type, content, job_id, created_at + SELECT id, conversation_id, message_type, content, job_id, created_at, step_name FROM flow_conversation_message WHERE conversation_id = $1 ORDER BY created_at DESC, CASE WHEN message_type = 'user' THEN 0 ELSE 1 END @@ -255,6 +258,7 @@ pub async fn create_message( content: &str, job_id: Option, workspace_id: &str, + step_name: Option<&str>, ) -> windmill_common::error::Result<()> { // Verify the conversation exists and belongs to the user let conversation_exists = sqlx::query_scalar!( @@ -275,12 +279,13 @@ pub async fn create_message( // Insert the message sqlx::query!( - "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id) - VALUES ($1, $2, $3, $4)", + "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name) + VALUES ($1, $2, $3, $4, $5)", conversation_id, message_type as MessageType, content, - job_id + job_id, + step_name ) .execute(&mut **tx) .await?; diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 813e912d6e0ca..a3d1764a2deb2 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -3982,17 +3982,7 @@ async fn handle_chat_conversation_messages( &user_message, None, // No job_id for user message w_id, - ) - .await?; - - // Create placeholder assistant message in the same transaction as the job - flow_conversations::create_message( - tx, - memory_id, - MessageType::Assistant, - "", // Empty content, will be updated when job completes - Some(uuid), // Associate with the job - w_id, + None, // No step_name for user message ) .await?; diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index 06d265e435ec3..671e03181b121 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -2,6 +2,7 @@ use crate::memory_oss::{read_from_memory, write_to_memory}; use anyhow::Context; use async_recursion::async_recursion; use regex::Regex; +use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; use std::{collections::HashMap, sync::Arc}; use ulid; @@ -13,7 +14,7 @@ use windmill_common::{ db::DB, error::{self, to_anyhow, Error}, flow_status::AgentAction, - flows::{FlowModuleValue, Step}, + flows::{FlowModuleValue, FlowValue, Step}, get_latest_hash_for_path, jobs::JobKind, scripts::{get_full_hub_script_by_path, ScriptHash, ScriptLang}, @@ -85,6 +86,16 @@ pub struct FlowJobRunnableIdAndRawFlow { pub kind: JobKind, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, sqlx::Type)] +#[sqlx(type_name = "MESSAGE_TYPE", rename_all = "lowercase")] +#[serde(rename_all = "lowercase")] +pub enum MessageType { + User, + Assistant, + System, + Tool, +} + pub async fn get_flow_job_runnable_and_raw_flow( db: &DB, job_id: &uuid::Uuid, @@ -296,6 +307,7 @@ pub async fn handle_ai_agent_job( parent_job, &args, &tools, + value, client, &mut inner_occupancy_metrics, job_completed_tx, @@ -409,6 +421,65 @@ async fn update_flow_status_module_with_actions_success( Ok(()) } +/// Add a message to the conversation database +async fn add_message_to_conversation( + db: &DB, + workspace_id: &str, + conversation_id: Uuid, + job_id: Uuid, + content: &str, + message_type: MessageType, + step_name: Option<&str>, +) -> Result<(), Error> { + let mut tx = db.begin().await?; + + // Verify the conversation exists + let conversation_exists = sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1 AND workspace_id = $2)", + conversation_id, + workspace_id + ) + .fetch_one(&mut *tx) + .await? + .unwrap_or(false); + + if !conversation_exists { + // Conversation doesn't exist yet, silently skip + return Ok(()); + } + + // Insert the message + sqlx::query!( + "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name) + VALUES ($1, $2, $3, $4, $5)", + conversation_id, + message_type as MessageType, + content, + job_id, + step_name + ) + .execute(&mut *tx) + .await?; + + // Update conversation updated_at timestamp + sqlx::query!( + "UPDATE flow_conversation SET updated_at = NOW() WHERE id = $1", + conversation_id + ) + .execute(&mut *tx) + .await?; + + tx.commit().await?; + Ok(()) +} + +/// Get step name from the flow module (summary if exists, else id) +fn get_step_name_from_flow(flow_value: &FlowValue, flow_step_id: Option<&str>) -> Option { + let flow_step_id = flow_step_id?; + let module = flow_value.modules.iter().find(|m| m.id == flow_step_id)?; + Some(module.summary.clone().unwrap_or_else(|| module.id.clone())) +} + /// Check if the provider is Anthropic (either direct or through OpenRouter) fn is_anthropic_provider(provider: &ProviderWithResource) -> bool { let provider_is_anthropic = provider.kind.is_anthropic(); @@ -428,6 +499,7 @@ pub async fn run_agent( parent_job: &Uuid, args: &AIAgentArgs, tools: &[Tool], + flow_value: &FlowValue, // job execution context client: &AuthedClient, @@ -659,6 +731,43 @@ pub async fn run_agent( .await?; content = Some(OpenAIContent::Text(response_content.clone())); + + // Add assistant message to conversation if chat_input_enabled + if flow_value.chat_input_enabled.unwrap_or(false) { + if let Ok(Some(memory_id)) = + get_memory_id_from_flow_status(db, parent_job).await + { + let workspace_id = job.workspace_id.clone(); + let agent_job_id = job.id; + let db_clone = db.clone(); + let message_content = response_content.clone(); + let step_name = get_step_name_from_flow( + flow_value, + job.flow_step_id.as_deref(), + ); + + // Spawn task to avoid blocking on DB write + tokio::spawn(async move { + if let Err(e) = add_message_to_conversation( + &db_clone, + &workspace_id, + memory_id, + agent_job_id, + &message_content, + MessageType::Assistant, + step_name.as_deref(), + ) + .await + { + tracing::warn!( + "Failed to add assistant message to conversation {}: {}", + memory_id, + e + ); + } + }); + } + } } if tool_calls.is_empty() { @@ -977,7 +1086,7 @@ pub async fn run_agent( let tool_result_event = StreamingEvent::ToolResult { call_id: tool_call.id.clone(), function_name: tool_call.function.name.clone(), - result: error_message, + result: error_message.clone(), success: false, }; stream_event_processor @@ -989,6 +1098,47 @@ pub async fn run_agent( db, parent_job, false, ) .await?; + + // Add tool message to conversation if chat_input_enabled (error case) + if flow_value.chat_input_enabled.unwrap_or(false) { + if let Ok(Some(memory_id)) = + get_memory_id_from_flow_status(db, parent_job).await + { + let error_text = error_message; + let workspace_id = job.workspace_id.clone(); + let tool_job_id = job_id; + let db_clone = db.clone(); + let tool_name = tool_call.function.name.clone(); + let step_name = get_step_name_from_flow( + flow_value, + job.flow_step_id.as_deref(), + ); + + // Spawn task to avoid blocking on DB write + tokio::spawn(async move { + if let Err(e) = add_message_to_conversation( + &db_clone, + &workspace_id, + memory_id, + tool_job_id, + &format!( + "Error executing {}: {}", + tool_name, error_text + ), + MessageType::Tool, + step_name.as_deref(), + ) + .await + { + tracing::warn!( + "Failed to add tool error message to conversation {}: {}", + memory_id, + e + ); + } + }); + } + } } Ok(success) => { let send_result = @@ -1055,6 +1205,44 @@ pub async fn run_agent( db, parent_job, success, ) .await?; + + // Add tool message to conversation if chat_input_enabled + if flow_value.chat_input_enabled.unwrap_or(false) { + if let Ok(Some(memory_id)) = + get_memory_id_from_flow_status(db, parent_job).await + { + let workspace_id = job.workspace_id.clone(); + let tool_job_id = job_id; + let db_clone = db.clone(); + let tool_name = tool_call.function.name.clone(); + let step_name = tool + .module + .summary + .clone() + .unwrap_or_else(|| tool.module.id.clone()); + + // Spawn task to avoid blocking on DB write + tokio::spawn(async move { + if let Err(e) = add_message_to_conversation( + &db_clone, + &workspace_id, + memory_id, + tool_job_id, + &format!("Used {} tool", tool_name), + MessageType::Tool, + Some(&step_name), + ) + .await + { + tracing::warn!( + "Failed to add tool message to conversation {}: {}", + memory_id, + e + ); + } + }); + } + } } } } else { diff --git a/frontend/src/lib/components/flows/conversations/FlowChatMessage.svelte b/frontend/src/lib/components/flows/conversations/FlowChatMessage.svelte index 9bb8172e2cf54..01fac7ee18ec5 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatMessage.svelte +++ b/frontend/src/lib/components/flows/conversations/FlowChatMessage.svelte @@ -1,7 +1,7 @@
{#if message.step_name} -
{message.step_name}
{/if} @@ -43,9 +45,11 @@ : ''}" > {#if message.message_type === 'tool'} - - {:else if message.error} - + {#if message.error} + + {:else} + + {/if} {/if}
Date: Wed, 8 Oct 2025 14:03:11 +0000 Subject: [PATCH 10/26] flag flow errors --- backend/windmill-queue/src/jobs.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index f10ab2901ee53..889153d843fa9 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -851,8 +851,8 @@ pub async fn add_completed_job( .map(|v| matches!(v, FlowModuleValue::AIAgent { .. })) .unwrap_or(false); - // Only create assistant message if last module is NOT an AI agent - if !last_module_is_ai_agent { + // Only create assistant message if last module is NOT an AI agent, or there was an error + if !last_module_is_ai_agent || success == false { let value = serde_json::to_value(result.0).map_err(|e| { Error::internal_err(format!("Failed to serialize result: {e}")) })?; @@ -883,11 +883,12 @@ pub async fn add_completed_job( // Insert new assistant message let _ = sqlx::query!( - "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id) - VALUES ($1, 'assistant', $2, $3)", + "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, error) + VALUES ($1, 'assistant', $2, $3, $4)", conversation_id, content, queued_job.id, + success == false, ) .execute(db) .await; From b3dfd29079f541f95d46e7bb570fe544145b42a3 Mon Sep 17 00:00:00 2001 From: centdix Date: Wed, 8 Oct 2025 14:35:08 +0000 Subject: [PATCH 11/26] cleaning --- .../windmill-api/src/flow_conversations.rs | 24 ------------------- backend/windmill-api/src/jobs.rs | 12 +++++----- .../windmill-common/src/flow_conversations.rs | 16 ------------- backend/windmill-queue/src/jobs.rs | 17 +++++++------ backend/windmill-worker/src/ai_executor.rs | 6 ----- .../components/FlowStatusViewerInner.svelte | 2 +- .../conversations/FlowChatInterface.svelte | 14 +---------- 7 files changed, 18 insertions(+), 73 deletions(-) diff --git a/backend/windmill-api/src/flow_conversations.rs b/backend/windmill-api/src/flow_conversations.rs index 8f29c16aeab98..7f988d0939a67 100644 --- a/backend/windmill-api/src/flow_conversations.rs +++ b/backend/windmill-api/src/flow_conversations.rs @@ -251,27 +251,3 @@ async fn list_messages( tx.commit().await?; Ok(Json(messages)) } - -// Helper function to create a message using an existing transaction -pub async fn create_message( - tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, - conversation_id: Uuid, - message_type: MessageType, - content: &str, - job_id: Option, - workspace_id: &str, - step_name: Option<&str>, - error: bool, -) -> windmill_common::error::Result<()> { - windmill_common::flow_conversations::add_message_to_conversation_tx( - tx, - workspace_id, - conversation_id, - job_id, - content, - message_type, - step_name, - error, - ) - .await -} diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 7999c362d01aa..0e3992ff4a208 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -30,6 +30,7 @@ use windmill_common::auth::is_super_admin_email; use windmill_common::auth::TOKEN_PREFIX_LEN; use windmill_common::db::UserDbWithAuthed; use windmill_common::error::JsonResult; +use windmill_common::flow_conversations::add_message_to_conversation_tx; use windmill_common::flow_status::{JobResult, RestartedFrom}; use windmill_common::jobs::{ check_tag_available_for_workspace_internal, format_completed_job_result, format_result, @@ -3978,15 +3979,14 @@ async fn handle_chat_conversation_messages( .await?; // Create user message - flow_conversations::create_message( + add_message_to_conversation_tx( tx, memory_id, - MessageType::User, + None, &user_message, - None, // No job_id for user message - w_id, - None, // No step_name for user message - false, // User messages are not errors + MessageType::User, + None, + false, ) .await?; diff --git a/backend/windmill-common/src/flow_conversations.rs b/backend/windmill-common/src/flow_conversations.rs index d5b99883d9076..2ff03d5c893ba 100644 --- a/backend/windmill-common/src/flow_conversations.rs +++ b/backend/windmill-common/src/flow_conversations.rs @@ -17,7 +17,6 @@ pub enum MessageType { /// Add a message to a conversation using an existing transaction pub async fn add_message_to_conversation_tx( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, - workspace_id: &str, conversation_id: Uuid, job_id: Option, content: &str, @@ -25,21 +24,6 @@ pub async fn add_message_to_conversation_tx( step_name: Option<&str>, error: bool, ) -> Result<()> { - // Verify the conversation exists - let conversation_exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1 AND workspace_id = $2)", - conversation_id, - workspace_id - ) - .fetch_one(&mut **tx) - .await? - .unwrap_or(false); - - if !conversation_exists { - // Conversation doesn't exist yet, silently skip - return Ok(()); - } - // Insert the message sqlx::query!( "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name, error) diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 889153d843fa9..c2a2f3f4952e6 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -33,6 +33,7 @@ use windmill_common::add_time; use windmill_common::auth::JobPerms; #[cfg(feature = "benchmark")] use windmill_common::bench::BenchmarkIter; +use windmill_common::flow_conversations::{add_message_to_conversation_tx, MessageType}; use windmill_common::jobs::{JobTriggerKind, EMAIL_ERROR_HANDLER_USER_EMAIL}; use windmill_common::utils::now_from_db; use windmill_common::worker::{Connection, SCRIPT_TOKEN_EXPIRY}; @@ -882,16 +883,18 @@ pub async fn add_completed_job( }; // Insert new assistant message - let _ = sqlx::query!( - "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, error) - VALUES ($1, 'assistant', $2, $3, $4)", + let mut tx = db.begin().await?; + add_message_to_conversation_tx( + &mut tx, conversation_id, - content, - queued_job.id, + Some(queued_job.id), + &content, + MessageType::Assistant, + None, success == false, ) - .execute(db) - .await; + .await?; + tx.commit().await?; } } } diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index 5801f03149b11..e48d01f3253b8 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -682,7 +682,6 @@ pub async fn run_agent( if let Ok(Some(memory_id)) = get_memory_id_from_flow_status(db, parent_job).await { - let workspace_id = job.workspace_id.clone(); let agent_job_id = job.id; let db_clone = db.clone(); let message_content = response_content.clone(); @@ -697,7 +696,6 @@ pub async fn run_agent( Ok(mut tx) => { if let Err(e) = add_message_to_conversation_tx( &mut tx, - &workspace_id, memory_id, Some(agent_job_id), &message_content, @@ -1068,7 +1066,6 @@ pub async fn run_agent( get_memory_id_from_flow_status(db, parent_job).await { let error_text = error_message; - let workspace_id = job.workspace_id.clone(); let tool_job_id = job_id; let db_clone = db.clone(); let tool_name = tool_call.function.name.clone(); @@ -1084,7 +1081,6 @@ pub async fn run_agent( if let Err(e) = add_message_to_conversation_tx( &mut tx, - &workspace_id, memory_id, Some(tool_job_id), &format!( @@ -1193,7 +1189,6 @@ pub async fn run_agent( if let Ok(Some(memory_id)) = get_memory_id_from_flow_status(db, parent_job).await { - let workspace_id = job.workspace_id.clone(); let tool_job_id = job_id; let db_clone = db.clone(); let tool_name = tool_call.function.name.clone(); @@ -1214,7 +1209,6 @@ pub async fn run_agent( if let Err(e) = add_message_to_conversation_tx( &mut tx, - &workspace_id, memory_id, Some(tool_job_id), &content, diff --git a/frontend/src/lib/components/FlowStatusViewerInner.svelte b/frontend/src/lib/components/FlowStatusViewerInner.svelte index 7aa69a293404a..51c2cb554aaed 100644 --- a/frontend/src/lib/components/FlowStatusViewerInner.svelte +++ b/frontend/src/lib/components/FlowStatusViewerInner.svelte @@ -1183,7 +1183,7 @@ selectedForLoopSetManually: false }) } - if (selectedNode?.startsWith(AI_TOOL_CAL / modL_PREFIX)) { + if (selectedNode?.startsWith(AI_TOOL_CALL_PREFIX)) { const [, agentModuleId, toolCallIndex, _] = selectedNode.split('-') const parentLoopsPrefix = getParentLoopsPrefix(agentModuleId) toolCallStore?.addToolCallToLoad(parentLoopsPrefix + agentModuleId + '-' + toolCallIndex) diff --git a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte index 4b313750a0bbb..bc155c3ab26c2 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte +++ b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte @@ -241,15 +241,7 @@ // Add any new intermediate messages not already present for (const msg of filteredResponse) { if (!messages.find((m) => m.id === msg.id)) { - // Insert in chronological order - const insertIndex = messages.findIndex( - (m) => new Date(m.created_at) > new Date(msg.created_at) - ) - if (insertIndex === -1) { - messages = [...messages, msg] - } else { - messages = [...messages.slice(0, insertIndex), msg, ...messages.slice(insertIndex)] - } + messages = [...messages, msg] } } } catch (error) { @@ -455,10 +447,6 @@ eventSource.close() currentEventSource = undefined isLoading = false - - // Do one final poll to ensure we have all messages - // await pollConversationMessages(currentConversationId) - // stopPolling() } } } catch (error) { From 36ad2f7cf6f0556b3ea14181ad93209baf5ca2b5 Mon Sep 17 00:00:00 2001 From: centdix Date: Wed, 8 Oct 2025 15:17:18 +0000 Subject: [PATCH 12/26] use separate manager --- .../conversations/FlowChatInterface.svelte | 539 ++---------------- .../conversations/FlowChatManager.svelte.ts | 482 ++++++++++++++++ .../conversations/FlowChatMessage.svelte | 1 - .../(logged)/flows/get/[...path]/+page.svelte | 1 + 4 files changed, 523 insertions(+), 500 deletions(-) create mode 100644 frontend/src/lib/components/flows/conversations/FlowChatManager.svelte.ts diff --git a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte index bc155c3ab26c2..7b81e74604f08 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte +++ b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte @@ -1,13 +1,10 @@ @@ -535,18 +76,18 @@
{#if deploymentInProgress} {/if} - {#if isLoadingMessages} + {#if manager.isLoadingMessages}
- {:else if messages.length === 0} + {:else if manager.messages.length === 0}

Start a conversation

@@ -554,10 +95,10 @@
{:else}
- {#each messages as message (message.id)} + {#each manager.messages as message (message.id)} {/each} - {#if isWaitingForResponse} + {#if manager.isWaitingForResponse}
Processing... @@ -574,10 +115,10 @@ class:opacity-50={deploymentInProgress} >