fixed stats and billing sync

This commit is contained in:
ValueOn AG 2026-02-08 01:44:48 +01:00
parent 148412c31c
commit 3d75880d13
4 changed files with 37 additions and 15 deletions

View file

@ -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<string, any>;
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 = {

View file

@ -45,11 +45,6 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({
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 (
<div className={`${styles.message} ${messageClass} ${errorClass}`}>
<div className={styles.messageBubble}>

View file

@ -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) {

View file

@ -87,6 +87,9 @@ export function useWorkflowLifecycle(instanceId: string) {
const hasRenderedLastMessageRef = useRef<boolean>(false);
const [hasRenderedLastMessage, setHasRenderedLastMessage] = useState<boolean>(false);
// Flag to prevent useEffect from stopping polling during active workflow start
const isStartingWorkflowRef = useRef<boolean>(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]);