/** * SAAP API Client - HuggingFace Deployment Compatible * Automatically detects environment and uses correct base URL */ import axios from 'axios'; // 🌐 Environment-aware base URL detection const getApiBaseUrl = () => { // Production HuggingFace Spaces deployment if (window.location.hostname.includes('hf.space')) { return '/api/v1'; // Relative path - nginx routes to backend } // Local development if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') { return 'http://localhost:8000/api/v1'; } // Network development (IP-based) if (window.location.hostname.match(/^\d+\.\d+\.\d+\.\d+$/)) { return `http://${window.location.hostname}:8000/api/v1`; } // Fallback: relative path return '/api/v1'; }; const API_BASE_URL = getApiBaseUrl(); console.log('πŸ”§ SAAP API Configuration:'); console.log(` Environment: ${window.location.hostname}`); console.log(` API Base URL: ${API_BASE_URL}`); // Create axios instance with base configuration const apiClient = axios.create({ baseURL: API_BASE_URL, timeout: 120000, // πŸš€ ErhΓΆht auf 2 Minuten fΓΌr Multi-Agent Chat (Jane β†’ Spezialist Delegation) headers: { 'Content-Type': 'application/json', }, withCredentials: false, // Changed from true for HuggingFace }); // Request interceptor for logging apiClient.interceptors.request.use( (config) => { console.log(`πŸ”„ API Request: ${config.method?.toUpperCase()} ${config.url}`); console.log(`πŸ”„ Full URL: ${config.baseURL}${config.url}`); return config; }, (error) => { console.error('❌ Request Error:', error); return Promise.reject(error); } ); // Response interceptor for error handling apiClient.interceptors.response.use( (response) => { console.log(`βœ… API Response: ${response.status} ${response.config.url}`); return response; }, (error) => { if (error.response) { console.error('❌ API Error:', { status: error.response.status, data: error.response.data, message: error.message }); } else if (error.request) { console.error('❌ Network Error: No response received', error.message); } else { console.error('❌ Request Setup Error:', error.message); } return Promise.reject(error); } ); // API Methods const saapApi = { // Agent Management async getAgents() { const response = await apiClient.get('/agents'); return response.data; }, async getAgent(agentId) { const response = await apiClient.get(`/agents/${agentId}`); return response.data; }, async createAgent(agentData) { const response = await apiClient.post('/agents', agentData); return response.data; }, async updateAgent(agentId, agentData) { const response = await apiClient.put(`/agents/${agentId}`, agentData); return response.data; }, async deleteAgent(agentId) { const response = await apiClient.delete(`/agents/${agentId}`); return response.data; }, // Agent Lifecycle async startAgent(agentId) { const response = await apiClient.post(`/agents/${agentId}/start`); return response.data; }, async stopAgent(agentId) { const response = await apiClient.post(`/agents/${agentId}/stop`); return response.data; }, // Agent Communication async sendMessage(agentId, message) { const response = await apiClient.post(`/agents/${agentId}/chat`, { message: message, timestamp: Date.now() }); return response.data; }, // Multi-Agent System async multiAgentChat(message, options = {}) { const response = await apiClient.post('/multi-agent/chat', { user_message: message, ...options }); return response.data; }, async getMultiAgentStatus() { const response = await apiClient.get('/multi-agent/status'); return response.data; }, // Templates async getAgentTemplates() { const response = await apiClient.get('/templates/agents'); return response.data; }, async createAgentFromTemplate(templateName) { const response = await apiClient.post(`/templates/agents/${templateName}`); return response.data; }, // Health Check async healthCheck() { const response = await apiClient.get('/health'); return response.data; }, }; // WebSocket connection for real-time updates class SaapWebSocket { constructor() { this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectDelay = 1000; this.listeners = new Map(); } connect() { const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsHost = window.location.hostname.includes('hf.space') ? window.location.host : 'localhost:8000'; const wsUrl = `${wsProtocol}//${wsHost}/ws`; console.log(`πŸ”Œ Connecting to WebSocket: ${wsUrl}`); this.ws = new WebSocket(wsUrl); this.ws.onopen = () => { console.log('βœ… WebSocket connected'); this.reconnectAttempts = 0; this.emit('connected', {}); }; this.ws.onmessage = (event) => { try { const data = JSON.parse(event.data); console.log('πŸ“¨ WebSocket message:', data); this.emit('message', data); } catch (error) { console.error('❌ WebSocket message parse error:', error); } }; this.ws.onerror = (error) => { console.error('❌ WebSocket error:', error); this.emit('error', error); }; this.ws.onclose = () => { console.log('❌ WebSocket disconnected'); this.emit('disconnected', {}); this.attemptReconnect(); }; } attemptReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; const delay = this.reconnectDelay * this.reconnectAttempts; console.log(`πŸ”„ Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => this.connect(), delay); } else { console.error('❌ Max reconnection attempts reached'); } } on(event, callback) { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event).push(callback); } emit(event, data) { if (this.listeners.has(event)) { this.listeners.get(event).forEach(callback => callback(data)); } } send(data) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(data)); } else { console.error('❌ WebSocket not connected'); } } disconnect() { if (this.ws) { this.ws.close(); this.ws = null; } } } const saapWebSocket = new SaapWebSocket(); // Export both default and named for compatibility export default saapApi; export { saapApi, saapWebSocket };