| import { useAgentStore } from '@/stores/agentStore';
|
| import { uploadTraceToModal } from '@/services/api';
|
| import { getTraceExportData } from '@/services/jsonExporter';
|
| import { AgentTrace, AgentTraceMetadata, WebSocketEvent } from '@/types/agent';
|
| import { useCallback, useEffect } from 'react';
|
| import { useWebSocket } from './useWebSocket';
|
|
|
| interface UseAgentWebSocketOptions {
|
| url: string;
|
| }
|
|
|
| export const useAgentWebSocket = ({ url }: UseAgentWebSocketOptions) => {
|
| const {
|
| setTrace,
|
| traceId,
|
| setTraceId,
|
| updateTraceWithStep,
|
| completeTrace,
|
| setIsAgentProcessing,
|
| setIsConnectingToE2B,
|
| setVncUrl,
|
| setError,
|
| setIsConnected,
|
| selectedModelId,
|
| resetAgent,
|
| } = useAgentStore();
|
|
|
|
|
| const handleWebSocketMessage = useCallback(
|
| (event: WebSocketEvent) => {
|
| console.log('WebSocket event received:', event);
|
|
|
| switch (event.type) {
|
| case 'agent_start': {
|
|
|
| resetAgent();
|
|
|
| setIsAgentProcessing(true);
|
| setIsConnectingToE2B(true);
|
| setError(undefined);
|
|
|
|
|
| const traceWithMetadata = {
|
| ...event.agentTrace,
|
| traceMetadata: event.agentTrace.traceMetadata ? {
|
| ...event.agentTrace.traceMetadata,
|
| maxSteps: event.agentTrace.traceMetadata.maxSteps > 0
|
| ? event.agentTrace.traceMetadata.maxSteps
|
| : 200,
|
| } : {
|
| traceId: event.agentTrace.id,
|
| inputTokensUsed: 0,
|
| outputTokensUsed: 0,
|
| duration: 0,
|
| numberOfSteps: 0,
|
| maxSteps: 200,
|
| completed: false,
|
| final_state: null,
|
| },
|
| };
|
|
|
| setTrace(traceWithMetadata);
|
| console.log('Agent start received:', traceWithMetadata);
|
| break;
|
| }
|
|
|
| case 'agent_progress':
|
|
|
| setIsConnectingToE2B(false);
|
| updateTraceWithStep(event.agentStep, event.traceMetadata);
|
| console.log('Agent progress received:', event.agentStep);
|
| break;
|
|
|
| case 'agent_complete':
|
| setIsAgentProcessing(false);
|
| setIsConnectingToE2B(false);
|
| completeTrace(event.traceMetadata, event.final_state);
|
| console.log('Agent complete received:', event.traceMetadata, 'Final state:', event.final_state);
|
|
|
|
|
|
|
| setTimeout(() => {
|
| const state = useAgentStore.getState();
|
| const trace = state.trace;
|
| const steps = state.trace?.steps || [];
|
| const finalStep = state.finalStep;
|
| const metadata = state.trace?.traceMetadata;
|
|
|
| if (trace && !trace.isRunning) {
|
| console.log('🚀 Auto-uploading trace after task completion...');
|
| const traceData = getTraceExportData(trace, steps, metadata, finalStep);
|
| uploadTraceToModal(traceData)
|
| .then((result) => {
|
| if (result.success) {
|
| console.log('✅ Trace auto-uploaded successfully:', result);
|
| } else {
|
| console.warn('⚠️ Trace auto-upload failed:', result.error);
|
| }
|
| })
|
| .catch((error) => {
|
| console.error('❌ Error auto-uploading trace:', error);
|
| });
|
| }
|
| }, 100);
|
| break;
|
|
|
| case 'agent_error':
|
| setIsAgentProcessing(false);
|
| setIsConnectingToE2B(false);
|
| setError(event.error);
|
| console.error('Agent error received:', event.error);
|
| break;
|
|
|
| case 'vnc_url_set':
|
| setIsConnectingToE2B(false);
|
| setVncUrl(event.vncUrl);
|
| console.log('VNC URL set received:', event.vncUrl);
|
| break;
|
|
|
| case 'vnc_url_unset':
|
| setVncUrl('');
|
| console.log('VNC URL unset received');
|
| break;
|
|
|
| case 'heartbeat':
|
| console.log('Heartbeat received:', event);
|
| setTraceId(event.uuid);
|
| console.log('TraceId set from backend:', event.uuid);
|
| break;
|
|
|
| }
|
| },
|
| [setTrace, updateTraceWithStep, completeTrace, setIsAgentProcessing, setIsConnectingToE2B, setVncUrl, setError, resetAgent, setTraceId, traceId]
|
| );
|
|
|
|
|
| const handleWebSocketError = useCallback(() => {
|
|
|
| console.error('WebSocket connection error');
|
| }, []);
|
|
|
|
|
| const { isConnected, connectionState, sendMessage, manualReconnect } = useWebSocket({
|
| url,
|
| onMessage: handleWebSocketMessage,
|
| onError: handleWebSocketError,
|
| });
|
|
|
|
|
| useEffect(() => {
|
| setIsConnected(isConnected);
|
|
|
|
|
| if (!isConnected) {
|
| setTraceId(null);
|
| console.log('WebSocket disconnected - traceId cleared');
|
| }
|
| }, [isConnected, setIsConnected, setTraceId]);
|
|
|
|
|
| useEffect(() => {
|
|
|
| (window as Window & { __sendNewTask?: (instruction: string, modelId: string) => void }).__sendNewTask = (instruction: string, modelId: string) => {
|
|
|
| resetAgent();
|
|
|
|
|
| if (!traceId) {
|
| console.error('Internal error: Cannot send task. TraceId not set. Refreshing page...');
|
| window.location.reload();
|
| return;
|
| }
|
|
|
| const trace: AgentTrace = {
|
| id: traceId,
|
| instruction,
|
| modelId: modelId,
|
| timestamp: new Date(),
|
| isRunning: true,
|
| traceMetadata: {
|
| traceId: traceId,
|
| inputTokensUsed: 0,
|
| outputTokensUsed: 0,
|
| duration: 0,
|
| numberOfSteps: 0,
|
| maxSteps: 200,
|
| completed: false,
|
| final_state: null,
|
| } as AgentTraceMetadata,
|
| };
|
|
|
| setTrace(trace);
|
| setIsAgentProcessing(true);
|
| setIsConnectingToE2B(true);
|
|
|
|
|
| sendMessage({
|
| type: 'user_task',
|
| trace: trace,
|
| });
|
|
|
| console.log('Task sent:', trace);
|
| };
|
| }, [setTrace, setIsAgentProcessing, setIsConnectingToE2B, sendMessage, resetAgent, traceId]);
|
|
|
|
|
| const stopCurrentTask = useCallback(() => {
|
| const trace = useAgentStore.getState().trace;
|
| if (trace?.id && trace.isRunning) {
|
| sendMessage({
|
| type: 'stop_task',
|
| trace_id: trace.id,
|
| });
|
| console.log('Stop task sent for trace:', trace.id);
|
|
|
|
|
| }
|
| }, [sendMessage]);
|
|
|
| return {
|
| isConnected,
|
| connectionState,
|
| manualReconnect,
|
| stopCurrentTask,
|
| };
|
| };
|
|
|