const http = require('http'); const https = require('https'); const querystring = require('querystring'); // Configuration const GATHER_SPACE_ID = 'dashore-enterprises-db198865-9dd4-4406-8d0c-0bb71896f09e'; const GATHER_API_KEY = 'gtr_L8dR5b9x8im9itQGYTc194Lia9KSTwTSCHAhN84av1s'; const CLAUDE_API_KEY = process.env.CLAUDE_API_KEY || 'your-anthropic-key-here'; const BOT_USER_ID = 'claude-bot-agent'; // This will be the bot's user ID const BOT_NAME = 'Claude Agent'; // Store bot position and state let botState = { position: { x: 10, y: 10 }, // Starting position in the space isActive: true, lastActivity: Date.now() }; // Function to call Claude API for AI responses async function askClaude(question) { return new Promise((resolve, reject) => { const data = JSON.stringify({ model: 'claude-3-5-sonnet-20241022', max_tokens: 300, messages: [ { role: 'user', content: question } ] }); const options = { hostname: 'api.anthropic.com', port: 443, path: '/v1/messages', method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': CLAUDE_API_KEY, 'anthropic-version': '2023-06-01' } }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const parsed = JSON.parse(body); if (parsed.content && parsed.content[0]) { resolve(parsed.content[0].text); } else { reject(new Error('Invalid response from Claude API')); } } catch (e) { reject(e); } }); }); req.on('error', reject); req.write(data); req.end(); }); } // Function to send message to chat in Gather async function sendMessage(text) { return new Promise((resolve, reject) => { const data = JSON.stringify({ message: text, userId: BOT_USER_ID }); const options = { hostname: 'gather.town', port: 443, path: `/api/v1/spaces/${GATHER_SPACE_ID}/chat`, method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GATHER_API_KEY}` } }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const parsed = JSON.parse(body); resolve(parsed); } catch (e) { reject(e); } }); }); req.on('error', reject); req.write(data); req.end(); }); } // Function to move bot to a location async function moveBotTo(x, y) { botState.position = { x, y }; return new Promise((resolve, reject) => { const data = JSON.stringify({ x: x, y: y, userId: BOT_USER_ID }); const options = { hostname: 'gather.town', port: 443, path: `/api/v1/spaces/${GATHER_SPACE_ID}/users/${BOT_USER_ID}/position`, method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GATHER_API_KEY}` } }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const parsed = JSON.parse(body); resolve(parsed); } catch (e) { reject(e); } }); }); req.on('error', reject); req.write(data); req.end(); }); } // Listen for chat messages async function listenForMessages() { // This would use Gather's webhook system in a real implementation // For now, we'll use polling to check for new messages const checkMessages = async () => { try { // Simulated message polling - in production use webhooks console.log('Bot is listening for messages...'); // Keep the bot active botState.lastActivity = Date.now(); } catch (err) { console.error('Error listening for messages:', err); } setTimeout(checkMessages, 5000); }; checkMessages(); } // Process incoming command async function processCommand(command) { console.log(`Processing command: ${command}`); let response; if (command.toLowerCase().includes('@claude')) { // Extract the actual question const question = command.replace(/@claude\s*/i, '').trim(); if (question) { try { console.log(`Asking Claude: ${question}`); response = await askClaude(question); await sendMessage(`Claude: ${response}`); } catch (err) { console.error('Error calling Claude:', err); await sendMessage(`Sorry, I encountered an error: ${err.message}`); } } } else if (command.toLowerCase() === 'come here') { await moveBotTo(15, 15); await sendMessage('I moved to a new location!'); } else if (command.toLowerCase() === 'hello') { await sendMessage(`Hello! I'm ${BOT_NAME}, your AI assistant. Ask me anything by typing @claude followed by your question.`); } } // Initialize the bot async function initializeBot() { console.log(`\nšŸ¤– Starting ${BOT_NAME}...`); console.log(`Space ID: ${GATHER_SPACE_ID}`); console.log(`Initial Position: (${botState.position.x}, ${botState.position.y})`); // Move bot to starting position try { await moveBotTo(botState.position.x, botState.position.y); console.log('āœ… Bot positioned successfully'); } catch (err) { console.error('āŒ Error positioning bot:', err); } // Start listening for messages await listenForMessages(); console.log('āœ… Bot initialized and listening for commands'); console.log('Commands:'); console.log(' - @claude [question] - Ask Claude anything'); console.log(' - come here - Move bot to your location'); console.log(' - hello - Say hello to the bot'); } // Handle graceful shutdown process.on('SIGINT', () => { console.log('\nšŸ‘‹ Shutting down bot...'); process.exit(0); }); // Start the bot initializeBot().catch(err => { console.error('Fatal error:', err); process.exit(1); });