/** * Alexa Skill Lambda - OpenClaw/Grok Integration * Connects Alexa to your personal AI gateway */ const https = require('https'); const http = require('http'); // Gateway configuration - set via environment variables or Account Linking const DEFAULT_GATEWAY_URL = process.env.OPENCLAW_GATEWAY_URL || ''; const DEFAULT_GATEWAY_PASSWORD = process.env.OPENCLAW_GATEWAY_PASSWORD || ''; // Fallback to Grok API const XAI_API_KEY = process.env.XAI_API_KEY || ''; // Call OpenClaw gateway using OpenAI-compatible endpoint async function callGateway(message) { return new Promise((resolve, reject) => { const url = new URL(DEFAULT_GATEWAY_URL); // OpenClaw uses OpenAI-compatible chat completions endpoint const postData = JSON.stringify({ model: 'openclaw', messages: [ { role: 'system', content: 'You are Smart Claw, a helpful AI assistant connected via Alexa. Keep responses concise and suitable for voice output (under 150 words).' }, { role: 'user', content: message } ], stream: false }); const options = { hostname: url.hostname, port: 443, path: '/v1/chat/completions', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData), 'Authorization': `Bearer ${DEFAULT_GATEWAY_PASSWORD}` }, timeout: 25000 }; console.log('Calling OpenClaw gateway:', DEFAULT_GATEWAY_URL + '/v1/chat/completions'); const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { console.log('Gateway response status:', res.statusCode); console.log('Gateway response data:', data.substring(0, 500)); // If gateway returns HTML or error, fall back to Grok if (res.statusCode !== 200 || data.includes(' { console.error('Gateway request error:', e.message); reject(e); }); req.on('timeout', () => { console.error('Gateway request timeout'); req.destroy(); reject(new Error('Gateway timeout')); }); req.write(postData); req.end(); }); } // Call Grok API directly (fallback) async function callGrok(message) { return new Promise((resolve, reject) => { const postData = JSON.stringify({ model: 'grok-3-fast', messages: [ { role: 'system', content: 'You are a helpful AI assistant called Smart Claw. Keep responses concise and suitable for voice output (under 150 words).' }, { role: 'user', content: message } ], max_tokens: 400 }); const options = { hostname: 'api.x.ai', port: 443, path: '/v1/chat/completions', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData), 'Authorization': `Bearer ${XAI_API_KEY}` } }; const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const json = JSON.parse(data); if (json.choices && json.choices[0] && json.choices[0].message) { resolve(json.choices[0].message.content); } else { resolve('Sorry, I could not process that request.'); } } catch (e) { resolve('Sorry, I encountered an error.'); } }); }); req.on('error', reject); req.write(postData); req.end(); }); } // Main handler exports.handler = async (event) => { console.log('Alexa Request:', JSON.stringify(event, null, 2)); const requestType = event.request.type; // Launch request if (requestType === 'LaunchRequest') { return buildResponse( 'Welcome to Smart Claw, connected to your OpenClaw gateway. What would you like to know?', false ); } // Intent request if (requestType === 'IntentRequest') { const intentName = event.request.intent.name; if (intentName === 'AMAZON.HelpIntent') { return buildResponse( 'I am connected to your OpenClaw AI gateway. You can ask me anything. Try saying: scan my network, or tell me a joke.', false ); } if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') { return buildResponse('Goodbye!', true); } if (intentName === 'AMAZON.FallbackIntent') { return buildResponse('I did not catch that. Please try again.', false); } // Handle ChatIntent - main conversation if (intentName === 'ChatIntent') { const userMessage = event.request.intent.slots?.query?.value || 'Hello'; console.log('User message:', userMessage); try { let response; // Try gateway first try { console.log('Attempting gateway call...'); response = await callGateway(userMessage); console.log('Gateway success:', response?.substring(0, 100)); } catch (gatewayError) { console.log('Gateway failed, using Grok:', gatewayError.message); // Fallback to Grok if (XAI_API_KEY) { response = await callGrok(userMessage); } else { response = 'Sorry, I could not connect to the gateway. Please check if OpenClaw is running.'; } } // Clean and truncate response let speechResponse = String(response).trim(); if (speechResponse.length > 6000) { speechResponse = speechResponse.substring(0, 5900) + '... That is all for now.'; } return buildResponse(speechResponse, false); } catch (error) { console.error('Handler error:', error); return buildResponse('Sorry, I encountered an error. Please try again.', false); } } } // Session ended if (requestType === 'SessionEndedRequest') { return { version: '1.0', response: {} }; } return buildResponse('I did not understand that. Please try again.', false); }; function buildResponse(speechText, shouldEndSession) { return { version: '1.0', response: { outputSpeech: { type: 'PlainText', text: speechText }, shouldEndSession: shouldEndSession, reprompt: shouldEndSession ? undefined : { outputSpeech: { type: 'PlainText', text: 'What else would you like to know?' } } } }; }