File size: 4,718 Bytes
e0d4a07
af1ae43
e0d4a07
304e233
 
af1ae43
 
304e233
af1ae43
 
e0d4a07
af1ae43
304e233
 
 
af1ae43
 
 
 
 
 
 
 
 
304e233
 
af1ae43
 
 
304e233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
af1ae43
 
 
 
304e233
 
e0d4a07
 
 
 
 
 
304e233
 
af1ae43
 
 
 
 
304e233
af1ae43
 
 
304e233
af1ae43
304e233
af1ae43
 
 
 
 
304e233
af1ae43
 
 
 
 
 
 
 
 
304e233
af1ae43
 
 
 
 
 
 
 
 
304e233
 
 
 
 
 
 
 
 
 
 
af1ae43
304e233
af1ae43
 
304e233
af1ae43
 
 
 
304e233
af1ae43
 
 
304e233
af1ae43
 
304e233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
af1ae43
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { Header, Metadata, StackSteps, VNCStream } from '@/components/mock';
import { useWebSocket } from '@/hooks/useWebSocket';
import { AgentStep, AgentTrace, WebSocketEvent } from '@/types/agent';
import { useState } from 'react';
import { ulid } from 'ulid';

const Index = () => {
  const [trace, setTrace] = useState<AgentTrace>();
  const [isAgentProcessing, setIsAgentProcessing] = useState(false);
  const [vncUrl, setVncUrl] = useState<string>('');
  const [selectedModelId, setSelectedModelId] = useState<string>("Qwen/Qwen3-VL-30B-A3B-Instruct");

  // #################### WebSocket Connection ########################

  // WebSocket connection - Use environment variable
  // const WS_URL = process.env.NEXT_PUBLIC_WS_URL || 'ws://localhost:8000/ws';
  const WS_URL = 'ws://localhost:8000/ws';

  const handleWebSocketMessage = (event: WebSocketEvent) => {
    console.log('WebSocket event received:', event);

    switch (event.type) {
      case 'agent_start':
        setIsAgentProcessing(true);
        setTrace(event.agentTrace);
        console.log('Agent start received:', event.agentTrace);
        break;

      case 'agent_progress':
        // Add new step from a agent trace run with image, generated text, actions, tokens and timestamp
        setTrace(prev => {
          const existingSteps = prev?.steps || [] as AgentStep[];
          const stepExists = existingSteps.some(step => step.stepId === event.agentStep.stepId);

          if (!stepExists) {
            return {
              ...prev,
              steps: [...existingSteps, event.agentStep],
              traceMetadata: event.traceMetadata,
              isRunning: true
            };
          }
          return prev;
        });
        console.log('Agent progress received:', event.agentStep);
        break;

      case 'agent_complete':
        setIsAgentProcessing(false);
        setTrace(trace => {
          return trace.id === event.traceMetadata.traceId
            ? {
              ...trace,
              isRunning: false,
              metadata: event.traceMetadata,
            }
            : trace;
        });
        console.log('Agent complete received:', event.traceMetadata);
        break;

      case 'agent_error':
        setIsAgentProcessing(false);
        // TODO: Handle agent error
        console.log('Agent error received:', event.error);
        break;

      case 'vnc_url_set':
        setVncUrl(event.vncUrl);
        // TODO: Handle VNC URL set
        console.log('VNC URL set received:', event.vncUrl);
        break;

      case 'vnc_url_unset':
        setVncUrl('');
        // TODO: Handle VNC URL unset
        console.log('VNC URL unset received:');
        break;

      case 'heartbeat':
        console.log('Heartbeat received:', event);
        break;
    }
  };

  const handleWebSocketError = () => {
    // WebSocket Frontend Error handling

  };

  const { isConnected, connectionState, sendMessage, manualReconnect } = useWebSocket({
    url: WS_URL,
    onMessage: handleWebSocketMessage,
    onError: handleWebSocketError,
  });

  // #################### Frontend Functionality ########################

  const handleModelId = (modelId: string) => {
    setSelectedModelId(modelId);
  };

  const handleSendNewTask = (content: string, modelId: string) => {
    const trace: AgentTrace = {
      id: ulid(),
      instruction: content,
      modelId: selectedModelId,
      timestamp: new Date(),
      isRunning: true,
    };

    setTrace(trace);

    // Send message to Python backend via WebSocket
    sendMessage({
      type: 'user_task',
      trace: trace,
    });
  };

  // #################### Mock Frontend Rendering ########################

  return (
    <div style={{ height: '100%', width: '100%', display: 'flex', flexDirection: 'column', backgroundColor: '#f3f4f6' }}>
      <Header
        isConnected={isConnected}
        isAgentProcessing={isAgentProcessing}
        onSendTask={handleSendNewTask}
      />

      <div style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', overflow: 'hidden', minHeight: 0, padding: '32px' }}>
        <div style={{ width: '100%', height: '100%', maxWidth: '1400px', maxHeight: '900px', display: 'flex', flexDirection: 'row', overflow: 'hidden' }}>
          {/* Left Side: VNC Stream + Metadata */}
          <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '20px 12px', gap: '20px', minWidth: 0 }}>
            <VNCStream vncUrl={vncUrl} />
            <Metadata trace={trace} />
          </div>

          {/* Right Side: Stack Steps */}
          <StackSteps trace={trace} />
        </div>
      </div>
    </div>
  );
};

export default Index;