akseljoonas HF Staff commited on
Commit
32f62c3
·
1 Parent(s): 0e6ce7b

functioning frontend and docker

Browse files
.gitignore CHANGED
@@ -5,22 +5,66 @@ build/
5
  dist/
6
  wheels/
7
  *.egg-info
 
 
 
 
 
 
8
 
9
  # Virtual environments
10
- .venv
 
 
 
 
 
11
  .env
 
 
 
 
 
 
 
12
  .DS_Store
13
- .claude/
14
- *.jsonl
15
- *.csv
16
- /logs
17
- hf-agent-leaderboard/
 
18
  .cursor/
19
- session_logs/
20
- skills/
 
21
 
22
- # Frontend
23
  frontend/node_modules/
24
  frontend/dist/
25
  frontend/.cache/
26
  frontend/*.local
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  dist/
6
  wheels/
7
  *.egg-info
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .tox/
11
+ .coverage
12
+ htmlcov/
13
+ .ipynb_checkpoints/
14
 
15
  # Virtual environments
16
+ .venv/
17
+ venv/
18
+ ENV/
19
+ env/
20
+
21
+ # Environment and Secrets
22
  .env
23
+ .env.local
24
+ .env.*
25
+ !.env.example
26
+ *.local
27
+ credentials*.json
28
+
29
+ # OS-specific
30
  .DS_Store
31
+ Thumbs.db
32
+ *.swp
33
+
34
+ # IDE-specific
35
+ .vscode/
36
+ .idea/
37
  .cursor/
38
+ .history/
39
+ *.sublime-project
40
+ *.sublime-workspace
41
 
42
+ # Frontend (Node.js)
43
  frontend/node_modules/
44
  frontend/dist/
45
  frontend/.cache/
46
  frontend/*.local
47
+ frontend/.eslintcache
48
+ frontend/npm-debug.log*
49
+ frontend/yarn-debug.log*
50
+ frontend/yarn-error.log*
51
+
52
+ # Docker
53
+ .docker/
54
+
55
+ # Project-specific
56
+ session_logs/
57
+ /logs
58
+ hf-agent-leaderboard/
59
+ skills/
60
+ .claude/
61
+ *.jsonl
62
+ *.csv
63
+
64
+ # ML / Data
65
+ data/
66
+ datasets/
67
+ models/
68
+ checkpoint-*/
69
+ runs/
70
+ wandb/
backend/routes/agent.py CHANGED
@@ -124,9 +124,11 @@ async def shutdown_session(session_id: str) -> dict:
124
  @router.websocket("/ws/{session_id}")
125
  async def websocket_endpoint(websocket: WebSocket, session_id: str) -> None:
126
  """WebSocket endpoint for real-time events."""
 
127
  # Verify session exists
128
  info = session_manager.get_session_info(session_id)
129
  if not info:
 
130
  await websocket.close(code=4004, reason="Session not found")
131
  return
132
 
 
124
  @router.websocket("/ws/{session_id}")
125
  async def websocket_endpoint(websocket: WebSocket, session_id: str) -> None:
126
  """WebSocket endpoint for real-time events."""
127
+ logger.info(f"WebSocket connection request for session {session_id}")
128
  # Verify session exists
129
  info = session_manager.get_session_info(session_id)
130
  if not info:
131
+ logger.warning(f"WebSocket connection rejected: Session {session_id} not found")
132
  await websocket.close(code=4004, reason="Session not found")
133
  return
134
 
backend/session_manager.py CHANGED
@@ -68,7 +68,7 @@ class SessionManager:
68
  event_queue: asyncio.Queue = asyncio.Queue()
69
 
70
  # Create tool router
71
- tool_router = ToolRouter(config=self.config)
72
 
73
  # Create the agent session
74
  session = Session(event_queue, config=self.config, tool_router=tool_router)
@@ -253,7 +253,7 @@ class SessionManager:
253
  "session_id": session_id,
254
  "created_at": agent_session.created_at.isoformat(),
255
  "is_active": agent_session.is_active,
256
- "message_count": len(agent_session.session.context_manager.messages),
257
  }
258
 
259
  def list_sessions(self) -> list[dict[str, Any]]:
 
68
  event_queue: asyncio.Queue = asyncio.Queue()
69
 
70
  # Create tool router
71
+ tool_router = ToolRouter(self.config.mcpServers)
72
 
73
  # Create the agent session
74
  session = Session(event_queue, config=self.config, tool_router=tool_router)
 
253
  "session_id": session_id,
254
  "created_at": agent_session.created_at.isoformat(),
255
  "is_active": agent_session.is_active,
256
+ "message_count": len(agent_session.session.context_manager.items),
257
  }
258
 
259
  def list_sessions(self) -> list[dict[str, Any]]:
backend/websocket.py CHANGED
@@ -20,10 +20,11 @@ class ConnectionManager:
20
 
21
  async def connect(self, websocket: WebSocket, session_id: str) -> None:
22
  """Accept a WebSocket connection and register it."""
 
23
  await websocket.accept()
24
  self.active_connections[session_id] = websocket
25
  self.message_queues[session_id] = asyncio.Queue()
26
- logger.info(f"WebSocket connected for session {session_id}")
27
 
28
  def disconnect(self, session_id: str) -> None:
29
  """Remove a WebSocket connection."""
 
20
 
21
  async def connect(self, websocket: WebSocket, session_id: str) -> None:
22
  """Accept a WebSocket connection and register it."""
23
+ logger.info(f"Attempting to accept WebSocket for session {session_id}")
24
  await websocket.accept()
25
  self.active_connections[session_id] = websocket
26
  self.message_queues[session_id] = asyncio.Queue()
27
+ logger.info(f"WebSocket connected and registered for session {session_id}")
28
 
29
  def disconnect(self, session_id: str) -> None:
30
  """Remove a WebSocket connection."""
eval/.amp_batch_solve.py.swp DELETED
Binary file (12.3 kB)
 
frontend/index.html CHANGED
@@ -9,7 +9,7 @@
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
  </head>
12
- <body>
13
  <div id="root"></div>
14
  <script type="module" src="/src/main.tsx"></script>
15
  </body>
 
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
  </head>
12
+ <body style="margin: 0; padding: 0; background-color: #0D1117; color: #E6EDF3;">
13
  <div id="root"></div>
14
  <script type="module" src="/src/main.tsx"></script>
15
  </body>
frontend/src/components/Layout/AppLayout.tsx CHANGED
@@ -6,9 +6,6 @@ import {
6
  Typography,
7
  IconButton,
8
  Drawer,
9
- useMediaQuery,
10
- useTheme,
11
- Button,
12
  Chip,
13
  } from '@mui/material';
14
  import MenuIcon from '@mui/icons-material/Menu';
@@ -27,8 +24,6 @@ import ApprovalModal from '@/components/ApprovalModal/ApprovalModal';
27
  const DRAWER_WIDTH = 280;
28
 
29
  export default function AppLayout() {
30
- const theme = useTheme();
31
- const isMobile = useMediaQuery(theme.breakpoints.down('md'));
32
  const [mobileOpen, setMobileOpen] = useState(false);
33
 
34
  const { activeSessionId } = useSessionStore();
 
6
  Typography,
7
  IconButton,
8
  Drawer,
 
 
 
9
  Chip,
10
  } from '@mui/material';
11
  import MenuIcon from '@mui/icons-material/Menu';
 
24
  const DRAWER_WIDTH = 280;
25
 
26
  export default function AppLayout() {
 
 
27
  const [mobileOpen, setMobileOpen] = useState(false);
28
 
29
  const { activeSessionId } = useSessionStore();
frontend/src/hooks/useAgentWebSocket.ts CHANGED
@@ -1,5 +1,6 @@
1
  import { useCallback, useEffect, useRef } from 'react';
2
  import { useAgentStore } from '@/store/agentStore';
 
3
  import type { AgentEvent } from '@/types/events';
4
  import type { Message } from '@/types/agent';
5
 
@@ -29,6 +30,8 @@ export function useAgentWebSocket({
29
  setError,
30
  } = useAgentStore();
31
 
 
 
32
  const handleEvent = useCallback(
33
  (event: AgentEvent) => {
34
  if (!sessionId) return;
@@ -37,6 +40,7 @@ export function useAgentWebSocket({
37
  case 'ready':
38
  setConnected(true);
39
  setProcessing(false);
 
40
  onReady?.();
41
  break;
42
 
@@ -136,25 +140,29 @@ export function useAgentWebSocket({
136
  console.log('Unknown event:', event);
137
  }
138
  },
139
- [
140
- sessionId,
141
- addMessage,
142
- setProcessing,
143
- setConnected,
144
- setPendingApprovals,
145
- setError,
146
- onReady,
147
- onError,
148
- ]
149
  );
150
 
151
  const connect = useCallback(() => {
152
- if (!sessionId || wsRef.current?.readyState === WebSocket.OPEN) return;
 
 
 
 
 
 
153
 
 
154
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
155
- const host = window.location.host;
 
 
 
156
  const wsUrl = `${protocol}//${host}/api/ws/${sessionId}`;
157
 
 
158
  const ws = new WebSocket(wsUrl);
159
 
160
  ws.onopen = () => {
@@ -176,25 +184,28 @@ export function useAgentWebSocket({
176
  console.error('WebSocket error:', error);
177
  };
178
 
179
- ws.onclose = () => {
180
- console.log('WebSocket closed');
181
  setConnected(false);
182
 
183
- // Attempt to reconnect with exponential backoff
184
- if (reconnectTimeoutRef.current) {
185
- clearTimeout(reconnectTimeoutRef.current);
 
 
 
 
 
 
 
 
 
 
186
  }
187
- reconnectTimeoutRef.current = window.setTimeout(() => {
188
- reconnectDelayRef.current = Math.min(
189
- reconnectDelayRef.current * 2,
190
- WS_MAX_RECONNECT_DELAY
191
- );
192
- connect();
193
- }, reconnectDelayRef.current);
194
  };
195
 
196
  wsRef.current = ws;
197
- }, [sessionId, handleEvent, setConnected]);
198
 
199
  const disconnect = useCallback(() => {
200
  if (reconnectTimeoutRef.current) {
@@ -206,7 +217,7 @@ export function useAgentWebSocket({
206
  wsRef.current = null;
207
  }
208
  setConnected(false);
209
- }, [setConnected]);
210
 
211
  const sendPing = useCallback(() => {
212
  if (wsRef.current?.readyState === WebSocket.OPEN) {
@@ -214,15 +225,24 @@ export function useAgentWebSocket({
214
  }
215
  }, []);
216
 
217
- // Connect when sessionId changes
218
  useEffect(() => {
219
- if (sessionId) {
220
- connect();
 
221
  }
 
 
 
 
 
 
222
  return () => {
 
223
  disconnect();
224
  };
225
- }, [sessionId, connect, disconnect]);
 
226
 
227
  // Heartbeat
228
  useEffect(() => {
 
1
  import { useCallback, useEffect, useRef } from 'react';
2
  import { useAgentStore } from '@/store/agentStore';
3
+ import { useSessionStore } from '@/store/sessionStore';
4
  import type { AgentEvent } from '@/types/events';
5
  import type { Message } from '@/types/agent';
6
 
 
30
  setError,
31
  } = useAgentStore();
32
 
33
+ const { setSessionActive } = useSessionStore();
34
+
35
  const handleEvent = useCallback(
36
  (event: AgentEvent) => {
37
  if (!sessionId) return;
 
40
  case 'ready':
41
  setConnected(true);
42
  setProcessing(false);
43
+ setSessionActive(sessionId, true);
44
  onReady?.();
45
  break;
46
 
 
140
  console.log('Unknown event:', event);
141
  }
142
  },
143
+ // Zustand setters are stable, so we don't need them in deps
144
+ // eslint-disable-next-line react-hooks/exhaustive-deps
145
+ [sessionId, onReady, onError]
 
 
 
 
 
 
 
146
  );
147
 
148
  const connect = useCallback(() => {
149
+ if (!sessionId) return;
150
+
151
+ // Don't connect if already connected or connecting
152
+ if (wsRef.current?.readyState === WebSocket.OPEN ||
153
+ wsRef.current?.readyState === WebSocket.CONNECTING) {
154
+ return;
155
+ }
156
 
157
+ // Connect directly to backend (Vite doesn't proxy WebSockets)
158
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
159
+ // In development, connect directly to backend port 7860
160
+ // In production, use the same host
161
+ const isDev = import.meta.env.DEV;
162
+ const host = isDev ? '127.0.0.1:7860' : window.location.host;
163
  const wsUrl = `${protocol}//${host}/api/ws/${sessionId}`;
164
 
165
+ console.log('Connecting to WebSocket:', wsUrl);
166
  const ws = new WebSocket(wsUrl);
167
 
168
  ws.onopen = () => {
 
184
  console.error('WebSocket error:', error);
185
  };
186
 
187
+ ws.onclose = (event) => {
188
+ console.log('WebSocket closed', event.code, event.reason);
189
  setConnected(false);
190
 
191
+ // Only reconnect if it wasn't a normal closure and session still exists
192
+ if (event.code !== 1000 && sessionId) {
193
+ // Attempt to reconnect with exponential backoff
194
+ if (reconnectTimeoutRef.current) {
195
+ clearTimeout(reconnectTimeoutRef.current);
196
+ }
197
+ reconnectTimeoutRef.current = window.setTimeout(() => {
198
+ reconnectDelayRef.current = Math.min(
199
+ reconnectDelayRef.current * 2,
200
+ WS_MAX_RECONNECT_DELAY
201
+ );
202
+ connect();
203
+ }, reconnectDelayRef.current);
204
  }
 
 
 
 
 
 
 
205
  };
206
 
207
  wsRef.current = ws;
208
+ }, [sessionId, handleEvent]);
209
 
210
  const disconnect = useCallback(() => {
211
  if (reconnectTimeoutRef.current) {
 
217
  wsRef.current = null;
218
  }
219
  setConnected(false);
220
+ }, []);
221
 
222
  const sendPing = useCallback(() => {
223
  if (wsRef.current?.readyState === WebSocket.OPEN) {
 
225
  }
226
  }, []);
227
 
228
+ // Connect when sessionId changes (with a small delay to ensure session is ready)
229
  useEffect(() => {
230
+ if (!sessionId) {
231
+ disconnect();
232
+ return;
233
  }
234
+
235
+ // Small delay to ensure session is fully created on backend
236
+ const timeoutId = setTimeout(() => {
237
+ connect();
238
+ }, 100);
239
+
240
  return () => {
241
+ clearTimeout(timeoutId);
242
  disconnect();
243
  };
244
+ // eslint-disable-next-line react-hooks/exhaustive-deps
245
+ }, [sessionId]);
246
 
247
  // Heartbeat
248
  useEffect(() => {
frontend/tsconfig.tsbuildinfo ADDED
@@ -0,0 +1 @@
 
 
1
+ {"root":["./src/app.tsx","./src/main.tsx","./src/theme.ts","./src/vite-env.d.ts","./src/components/approvalmodal/approvalmodal.tsx","./src/components/chat/chatinput.tsx","./src/components/chat/messagebubble.tsx","./src/components/chat/messagelist.tsx","./src/components/layout/applayout.tsx","./src/components/sessionsidebar/sessionsidebar.tsx","./src/hooks/useagentwebsocket.ts","./src/store/agentstore.ts","./src/store/sessionstore.ts","./src/types/agent.ts","./src/types/events.ts"],"errors":true,"version":"5.6.3"}
frontend/vite.config.ts CHANGED
@@ -13,11 +13,11 @@ export default defineConfig({
13
  port: 5173,
14
  proxy: {
15
  '/api': {
16
- target: 'http://localhost:8000',
17
  changeOrigin: true,
18
  },
19
  '/auth': {
20
- target: 'http://localhost:8000',
21
  changeOrigin: true,
22
  },
23
  },
 
13
  port: 5173,
14
  proxy: {
15
  '/api': {
16
+ target: 'http://localhost:7860',
17
  changeOrigin: true,
18
  },
19
  '/auth': {
20
+ target: 'http://localhost:7860',
21
  changeOrigin: true,
22
  },
23
  },