| import { useCallback, useRef, useState } from 'react';
|
| import { uploadTraceToModal } from '@/services/api';
|
| import { getTraceExportData } from '@/services/jsonExporter';
|
| import { AgentTrace, AgentStep, AgentTraceMetadata, FinalStep } from '@/types/agent';
|
|
|
| |
| |
| |
|
|
| type GetTraceDataFn = () => {
|
| trace?: AgentTrace;
|
| steps: AgentStep[];
|
| metadata?: AgentTraceMetadata;
|
| finalStep?: FinalStep;
|
| };
|
|
|
| interface UseTraceUploaderOptions {
|
| getTraceData: GetTraceDataFn;
|
| }
|
|
|
| interface UseTraceUploaderReturn {
|
| uploadTrace: (forceUpload?: boolean) => Promise<boolean>;
|
| isUploading: boolean;
|
| uploadError: string | null;
|
| uploadSuccess: boolean;
|
| hasUploaded: boolean;
|
| resetUploadState: () => void;
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export const useTraceUploader = ({
|
| getTraceData,
|
| }: UseTraceUploaderOptions): UseTraceUploaderReturn => {
|
| const [isUploading, setIsUploading] = useState(false);
|
| const [uploadError, setUploadError] = useState<string | null>(null);
|
| const [uploadSuccess, setUploadSuccess] = useState(false);
|
| const hasUploadedRef = useRef(false);
|
| const uploadCountRef = useRef(0);
|
|
|
| const uploadTrace = useCallback(async (forceUpload: boolean = false): Promise<boolean> => {
|
|
|
| const { trace, steps, metadata, finalStep } = getTraceData();
|
|
|
|
|
| if (!trace) {
|
| console.log('Skipping trace upload: no trace');
|
| return false;
|
| }
|
|
|
|
|
| if (trace.isRunning) {
|
| console.log('Skipping trace upload: trace is still running');
|
| return false;
|
| }
|
|
|
|
|
| const traceData = getTraceExportData(trace, steps, metadata, finalStep);
|
|
|
|
|
| const currentEvaluation = (traceData as { user_evaluation?: string }).user_evaluation;
|
| const hasEvaluation = currentEvaluation && currentEvaluation !== 'not_evaluated';
|
|
|
|
|
|
|
|
|
|
|
| if (!forceUpload && hasUploadedRef.current && !hasEvaluation) {
|
| console.log('Skipping trace upload: already uploaded and no new evaluation');
|
| return false;
|
| }
|
|
|
| setIsUploading(true);
|
| setUploadError(null);
|
| uploadCountRef.current += 1;
|
| const uploadNum = uploadCountRef.current;
|
|
|
| try {
|
| console.log(`Uploading trace to Modal (upload #${uploadNum})...`, {
|
| traceId: trace.id,
|
| user_evaluation: currentEvaluation,
|
| forceUpload,
|
| hasEvaluation
|
| });
|
|
|
| const result = await uploadTraceToModal(traceData);
|
|
|
| if (result.success) {
|
| console.log(`✅ Trace uploaded successfully (upload #${uploadNum}):`, result);
|
| hasUploadedRef.current = true;
|
| setUploadSuccess(true);
|
| return true;
|
| } else {
|
| console.warn(`⚠️ Trace upload failed (upload #${uploadNum}):`, result.error);
|
| setUploadError(result.error || 'Unknown error');
|
| return false;
|
| }
|
| } catch (error) {
|
| const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
| console.error(`❌ Error uploading trace (upload #${uploadNum}):`, error);
|
| setUploadError(errorMessage);
|
| return false;
|
| } finally {
|
| setIsUploading(false);
|
| }
|
| }, [getTraceData]);
|
|
|
| const resetUploadState = useCallback(() => {
|
| hasUploadedRef.current = false;
|
| uploadCountRef.current = 0;
|
| setUploadSuccess(false);
|
| setUploadError(null);
|
| }, []);
|
|
|
| return {
|
| uploadTrace,
|
| isUploading,
|
| uploadError,
|
| uploadSuccess,
|
| hasUploaded: hasUploadedRef.current,
|
| resetUploadState,
|
| };
|
| };
|
|
|