From 3d75880d13b7292b81ac6c4b5c1e2533a76fafff Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Sun, 8 Feb 2026 01:44:48 +0100 Subject: [PATCH] fixed stats and billing sync --- src/api/workflowApi.ts | 4 +- .../Messages/ChatMessages/ChatMessage.tsx | 5 --- src/hooks/playground/useDashboardInputForm.ts | 5 ++- src/hooks/playground/useWorkflowLifecycle.ts | 38 +++++++++++++++---- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/api/workflowApi.ts b/src/api/workflowApi.ts index 2d5110f..a6191b4 100644 --- a/src/api/workflowApi.ts +++ b/src/api/workflowApi.ts @@ -47,6 +47,7 @@ export interface StartWorkflowRequest { listFileId?: string[]; // Array of file ID strings (files must be uploaded first via /api/files/upload) userLanguage?: string; // Optional, defaults to "en" metadata?: Record; + allowedProviders?: string[]; // Optional: Restrict AI calls to these providers (empty = all RBAC-permitted) } export interface StartWorkflowResponse extends Workflow { @@ -343,7 +344,8 @@ export async function startWorkflowApi( prompt: workflowData.prompt, ...(workflowData.listFileId && workflowData.listFileId.length > 0 && { listFileId: workflowData.listFileId }), ...(workflowData.userLanguage && { userLanguage: workflowData.userLanguage }), - ...(workflowData.metadata && { metadata: workflowData.metadata }) + ...(workflowData.metadata && { metadata: workflowData.metadata }), + ...(workflowData.allowedProviders && workflowData.allowedProviders.length > 0 && { allowedProviders: workflowData.allowedProviders }) }; const requestConfig = { diff --git a/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx b/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx index aff1272..f62aef4 100644 --- a/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx +++ b/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx @@ -45,11 +45,6 @@ export const ChatMessage: React.FC = ({ const messageClass = isUser ? styles.messageUser : styles.messageAssistant; const errorClass = isError ? styles.messageError : ''; - // Debug: Log documents if in dev mode - if (import.meta.env.DEV && message.documents) { - console.log('ChatMessage documents:', message.id, message.documents); - } - return (
diff --git a/src/hooks/playground/useDashboardInputForm.ts b/src/hooks/playground/useDashboardInputForm.ts index b41c1ea..ec0267d 100644 --- a/src/hooks/playground/useDashboardInputForm.ts +++ b/src/hooks/playground/useDashboardInputForm.ts @@ -596,9 +596,12 @@ export function useDashboardInputForm(instanceId: string) { prompt: trimmedInput, listFileId: fileIdsToSend.length > 0 ? fileIdsToSend : undefined, userLanguage: 'en', - preferredProviders: selectedProviders.length > 0 ? selectedProviders : undefined // AI provider selection (multiselect) + allowedProviders: selectedProviders.length > 0 ? selectedProviders : undefined // AI provider filter (multiselect) }; + // Debug: Log provider selection + console.log('🤖 Provider selection:', { selectedProviders, sentProviders: requestBody.allowedProviders }); + const result = await startWorkflow(requestBody, workflowOptions); if (result.success) { diff --git a/src/hooks/playground/useWorkflowLifecycle.ts b/src/hooks/playground/useWorkflowLifecycle.ts index e553a68..3fb301e 100644 --- a/src/hooks/playground/useWorkflowLifecycle.ts +++ b/src/hooks/playground/useWorkflowLifecycle.ts @@ -87,6 +87,9 @@ export function useWorkflowLifecycle(instanceId: string) { const hasRenderedLastMessageRef = useRef(false); const [hasRenderedLastMessage, setHasRenderedLastMessage] = useState(false); + // Flag to prevent useEffect from stopping polling during active workflow start + const isStartingWorkflowRef = useRef(false); + // === HOOKS === const { startWorkflow, stopWorkflow, startingWorkflow, stoppingWorkflows } = useWorkflowOperations(); const { request } = useApiRequest(); @@ -372,19 +375,28 @@ export function useWorkflowLifecycle(instanceId: string) { return; } + // Skip if we're actively starting a workflow - handleStartWorkflow manages polling + if (isStartingWorkflowRef.current) { + console.log('📍 Polling decision: Skipping - workflow start in progress'); + return; + } + // === STATE MACHINE: Determine if polling should be active === + // Use ref for immediate value (state may be stale) + const hasLastMessage = hasRenderedLastMessageRef.current; + const shouldPoll = workflowStatus === 'running' || - (workflowStatus === 'completed' && !hasRenderedLastMessage); + (workflowStatus === 'completed' && !hasLastMessage); const shouldStopImmediately = workflowStatus === 'stopped' || workflowStatus === 'failed' || - hasRenderedLastMessage; + hasLastMessage; console.log('📍 Polling decision:', { workflowStatus, - hasRenderedLastMessage, + hasRenderedLastMessage: hasLastMessage, shouldPoll, shouldStopImmediately }); @@ -406,6 +418,9 @@ export function useWorkflowLifecycle(instanceId: string) { options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' } ) => { try { + // Set flag to prevent useEffect from interfering during start + isStartingWorkflowRef.current = true; + const result = await startWorkflow(instanceId, workflowData, options); if (result.success && result.data) { @@ -414,25 +429,32 @@ export function useWorkflowLifecycle(instanceId: string) { // === STATE MACHINE: New round starts === console.log('🚀 Starting workflow:', workflow.id); - // Reset state for new round - setWorkflowId(workflow.id); + // Reset state for new round - MUST update refs BEFORE state hasRenderedLastMessageRef.current = false; - setHasRenderedLastMessage(false); // Set afterTimestamp to NOW - only poll for new data lastRenderedTimestampRef.current = Date.now(); - // Start polling immediately + // Start polling immediately (before state updates trigger useEffect) pollingControllerRef.current.startPolling(workflow.id, pollWorkflowData); - // Update status + // Now update state (will trigger re-renders) + setWorkflowId(workflow.id); + setHasRenderedLastMessage(false); updateWorkflowStatus(workflow.status || 'running'); + // Clear the starting flag after a short delay to allow React to settle + setTimeout(() => { + isStartingWorkflowRef.current = false; + }, 100); + return { success: true, data: result.data }; } else { + isStartingWorkflowRef.current = false; return { success: false, error: result.error || 'Failed to start workflow' }; } } catch (error: any) { + isStartingWorkflowRef.current = false; return { success: false, error: error.message || 'Failed to start workflow' }; } }, [instanceId, startWorkflow, updateWorkflowStatus, pollWorkflowData]);