fixed stats and billing sync
This commit is contained in:
parent
148412c31c
commit
3d75880d13
4 changed files with 37 additions and 15 deletions
|
|
@ -47,6 +47,7 @@ export interface StartWorkflowRequest {
|
||||||
listFileId?: string[]; // Array of file ID strings (files must be uploaded first via /api/files/upload)
|
listFileId?: string[]; // Array of file ID strings (files must be uploaded first via /api/files/upload)
|
||||||
userLanguage?: string; // Optional, defaults to "en"
|
userLanguage?: string; // Optional, defaults to "en"
|
||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
|
allowedProviders?: string[]; // Optional: Restrict AI calls to these providers (empty = all RBAC-permitted)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StartWorkflowResponse extends Workflow {
|
export interface StartWorkflowResponse extends Workflow {
|
||||||
|
|
@ -343,7 +344,8 @@ export async function startWorkflowApi(
|
||||||
prompt: workflowData.prompt,
|
prompt: workflowData.prompt,
|
||||||
...(workflowData.listFileId && workflowData.listFileId.length > 0 && { listFileId: workflowData.listFileId }),
|
...(workflowData.listFileId && workflowData.listFileId.length > 0 && { listFileId: workflowData.listFileId }),
|
||||||
...(workflowData.userLanguage && { userLanguage: workflowData.userLanguage }),
|
...(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 = {
|
const requestConfig = {
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,6 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({
|
||||||
const messageClass = isUser ? styles.messageUser : styles.messageAssistant;
|
const messageClass = isUser ? styles.messageUser : styles.messageAssistant;
|
||||||
const errorClass = isError ? styles.messageError : '';
|
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 (
|
return (
|
||||||
<div className={`${styles.message} ${messageClass} ${errorClass}`}>
|
<div className={`${styles.message} ${messageClass} ${errorClass}`}>
|
||||||
<div className={styles.messageBubble}>
|
<div className={styles.messageBubble}>
|
||||||
|
|
|
||||||
|
|
@ -596,9 +596,12 @@ export function useDashboardInputForm(instanceId: string) {
|
||||||
prompt: trimmedInput,
|
prompt: trimmedInput,
|
||||||
listFileId: fileIdsToSend.length > 0 ? fileIdsToSend : undefined,
|
listFileId: fileIdsToSend.length > 0 ? fileIdsToSend : undefined,
|
||||||
userLanguage: 'en',
|
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);
|
const result = await startWorkflow(requestBody, workflowOptions);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,9 @@ export function useWorkflowLifecycle(instanceId: string) {
|
||||||
const hasRenderedLastMessageRef = useRef<boolean>(false);
|
const hasRenderedLastMessageRef = useRef<boolean>(false);
|
||||||
const [hasRenderedLastMessage, setHasRenderedLastMessage] = useState<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 ===
|
// === HOOKS ===
|
||||||
const { startWorkflow, stopWorkflow, startingWorkflow, stoppingWorkflows } = useWorkflowOperations();
|
const { startWorkflow, stopWorkflow, startingWorkflow, stoppingWorkflows } = useWorkflowOperations();
|
||||||
const { request } = useApiRequest();
|
const { request } = useApiRequest();
|
||||||
|
|
@ -372,19 +375,28 @@ export function useWorkflowLifecycle(instanceId: string) {
|
||||||
return;
|
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 ===
|
// === STATE MACHINE: Determine if polling should be active ===
|
||||||
|
// Use ref for immediate value (state may be stale)
|
||||||
|
const hasLastMessage = hasRenderedLastMessageRef.current;
|
||||||
|
|
||||||
const shouldPoll =
|
const shouldPoll =
|
||||||
workflowStatus === 'running' ||
|
workflowStatus === 'running' ||
|
||||||
(workflowStatus === 'completed' && !hasRenderedLastMessage);
|
(workflowStatus === 'completed' && !hasLastMessage);
|
||||||
|
|
||||||
const shouldStopImmediately =
|
const shouldStopImmediately =
|
||||||
workflowStatus === 'stopped' ||
|
workflowStatus === 'stopped' ||
|
||||||
workflowStatus === 'failed' ||
|
workflowStatus === 'failed' ||
|
||||||
hasRenderedLastMessage;
|
hasLastMessage;
|
||||||
|
|
||||||
console.log('📍 Polling decision:', {
|
console.log('📍 Polling decision:', {
|
||||||
workflowStatus,
|
workflowStatus,
|
||||||
hasRenderedLastMessage,
|
hasRenderedLastMessage: hasLastMessage,
|
||||||
shouldPoll,
|
shouldPoll,
|
||||||
shouldStopImmediately
|
shouldStopImmediately
|
||||||
});
|
});
|
||||||
|
|
@ -406,6 +418,9 @@ export function useWorkflowLifecycle(instanceId: string) {
|
||||||
options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
|
options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
|
// Set flag to prevent useEffect from interfering during start
|
||||||
|
isStartingWorkflowRef.current = true;
|
||||||
|
|
||||||
const result = await startWorkflow(instanceId, workflowData, options);
|
const result = await startWorkflow(instanceId, workflowData, options);
|
||||||
|
|
||||||
if (result.success && result.data) {
|
if (result.success && result.data) {
|
||||||
|
|
@ -414,25 +429,32 @@ export function useWorkflowLifecycle(instanceId: string) {
|
||||||
// === STATE MACHINE: New round starts ===
|
// === STATE MACHINE: New round starts ===
|
||||||
console.log('🚀 Starting workflow:', workflow.id);
|
console.log('🚀 Starting workflow:', workflow.id);
|
||||||
|
|
||||||
// Reset state for new round
|
// Reset state for new round - MUST update refs BEFORE state
|
||||||
setWorkflowId(workflow.id);
|
|
||||||
hasRenderedLastMessageRef.current = false;
|
hasRenderedLastMessageRef.current = false;
|
||||||
setHasRenderedLastMessage(false);
|
|
||||||
|
|
||||||
// Set afterTimestamp to NOW - only poll for new data
|
// Set afterTimestamp to NOW - only poll for new data
|
||||||
lastRenderedTimestampRef.current = Date.now();
|
lastRenderedTimestampRef.current = Date.now();
|
||||||
|
|
||||||
// Start polling immediately
|
// Start polling immediately (before state updates trigger useEffect)
|
||||||
pollingControllerRef.current.startPolling(workflow.id, pollWorkflowData);
|
pollingControllerRef.current.startPolling(workflow.id, pollWorkflowData);
|
||||||
|
|
||||||
// Update status
|
// Now update state (will trigger re-renders)
|
||||||
|
setWorkflowId(workflow.id);
|
||||||
|
setHasRenderedLastMessage(false);
|
||||||
updateWorkflowStatus(workflow.status || 'running');
|
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 };
|
return { success: true, data: result.data };
|
||||||
} else {
|
} else {
|
||||||
|
isStartingWorkflowRef.current = false;
|
||||||
return { success: false, error: result.error || 'Failed to start workflow' };
|
return { success: false, error: result.error || 'Failed to start workflow' };
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
isStartingWorkflowRef.current = false;
|
||||||
return { success: false, error: error.message || 'Failed to start workflow' };
|
return { success: false, error: error.message || 'Failed to start workflow' };
|
||||||
}
|
}
|
||||||
}, [instanceId, startWorkflow, updateWorkflowStatus, pollWorkflowData]);
|
}, [instanceId, startWorkflow, updateWorkflowStatus, pollWorkflowData]);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue