UNPKG

limitless-ai-mcp-server

Version:

MCP server for integrating Limitless AI Pendant recordings with AI assistants

231 lines (217 loc) 9.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SamplingHandlers = void 0; const logger_1 = require("../utils/logger"); const templates_1 = require("./templates"); const format_1 = require("../utils/format"); class SamplingHandlers { client; constructor(client) { this.client = client; } /** * Handle sampling create message request * Note: This is a mock implementation since we don't have actual LLM integration * In a real implementation, this would call an LLM API */ async handleCreateMessage(request) { try { const { messages, modelPreferences, systemPrompt, temperature, maxTokens, metadata } = request.params; logger_1.logger.debug('Handling sampling request', { messageCount: messages.length, modelPreferences, metadata, }); // Extract the user's request from messages const lastUserMessage = messages.filter((msg) => msg.role === 'user').pop(); if (!lastUserMessage) { throw new Error('No user message found in sampling request'); } // Extract text content from the message let textContent = ''; if (typeof lastUserMessage.content === 'object' && lastUserMessage.content !== null && 'type' in lastUserMessage.content && lastUserMessage.content.type === 'text' && 'text' in lastUserMessage.content) { textContent = String(lastUserMessage.content.text); } if (!textContent) { throw new Error('No text content found in user message'); } // Check if this matches a template const templateMatch = this.matchTemplate(textContent); if (templateMatch) { // Process with template return this.processWithTemplate(templateMatch.template, templateMatch.variables, { temperature, maxTokens, modelPreferences, }); } // Generic processing for non-template requests return this.processGenericRequest(textContent, { systemPrompt, temperature, maxTokens, modelPreferences, }); } catch (error) { logger_1.logger.error('Sampling request failed', error); throw error; } } matchTemplate(text) { // Simple pattern matching for demonstration // In a real implementation, this would be more sophisticated if (text.toLowerCase().includes('summarize')) { // Extract content to summarize const contentMatch = text.match(/summarize[:\s]+(.+)/i); if (contentMatch) { return { template: 'summarize', variables: { content: contentMatch[1] }, }; } } if (text.toLowerCase().includes('extract')) { // Extract info type and content const match = text.match(/extract\s+(\w+)\s+from[:\s]+(.+)/i); if (match) { return { template: 'extractInfo', variables: { infoType: match[1], content: match[2], }, }; } } if (text.toLowerCase().includes('analyze patterns')) { const contentMatch = text.match(/analyze patterns[:\s]+(.+)/i); if (contentMatch) { return { template: 'analyzePatterns', variables: { content: contentMatch[1] }, }; } } return null; } async processWithTemplate(templateName, variables, _options) { const template = templates_1.samplingTemplates[templateName]; if (!template) { throw new Error(`Unknown sampling template: ${templateName}`); } // Check if we need to fetch lifelog data if (variables.content && variables.content.startsWith('lifelog://')) { // Fetch the actual lifelog data const lifelogData = await this.fetchLifelogData(variables.content); variables.content = lifelogData; } const prompt = (0, templates_1.buildSamplingPrompt)(template, variables); // Mock response generation // In a real implementation, this would call an LLM API const mockResponse = this.generateMockResponse(templateName, prompt); return { role: 'assistant', content: { type: 'text', text: mockResponse, }, model: 'mock-model-v1', stopReason: 'endTurn', }; } async processGenericRequest(text, options) { // Check if the request mentions lifelog URIs const uriMatch = text.match(/lifelog:\/\/[^\s]+/); if (uriMatch) { const lifelogData = await this.fetchLifelogData(uriMatch[0]); text = text.replace(uriMatch[0], lifelogData); } // Mock generic response const response = `I understand you want me to process: "${text}". In a real implementation, this would be sent to an LLM for processing with the following options: temperature=${options.temperature || 0.7}, maxTokens=${options.maxTokens || 1000}.`; return { role: 'assistant', content: { type: 'text', text: response, }, model: 'mock-model-v1', stopReason: 'endTurn', }; } async fetchLifelogData(uri) { try { // Parse the URI to determine what to fetch if (uri === 'lifelog://recent') { const logs = await this.client.listRecentLifelogs({ limit: 5 }); return (0, format_1.formatLifelogResponse)(logs, { includeMarkdown: true, includeHeadings: true }); } const dateMatch = uri.match(/lifelog:\/\/(\d{4}-\d{2}-\d{2})/); if (dateMatch) { const logs = await this.client.listLifelogsByDate(dateMatch[1]); return (0, format_1.formatLifelogResponse)(logs, { includeMarkdown: true, includeHeadings: true }); } const idMatch = uri.match(/lifelog:\/\/[^/]+\/(.+)/); if (idMatch) { const log = await this.client.getLifelogById(idMatch[1]); return (0, format_1.formatLifelogResponse)([log], { includeMarkdown: true, includeHeadings: true }); } return `Unable to fetch data for URI: ${uri}`; } catch (error) { logger_1.logger.error('Failed to fetch lifelog data for sampling', { uri, error }); return `Error fetching lifelog data: ${error instanceof Error ? error.message : 'Unknown error'}`; } } generateMockResponse(templateName, prompt) { // Mock responses based on template type switch (templateName) { case 'summarize': return `**Summary of Lifelog Content** Based on the provided lifelog data, here are the key points: 1. **Main Topics**: The discussion covered project updates, team coordination, and upcoming deadlines. 2. **Key Decisions**: The team agreed to prioritize the API integration and postpone the UI redesign. 3. **Action Items**: - Complete API documentation by Friday - Schedule follow-up meeting for next week - Review budget allocations 4. **Duration**: Approximately 45 minutes of recorded content. This summary captures the essential information from your lifelog.`; case 'extractInfo': return `**Extracted Information** Based on the analysis of the lifelog content: - **Requested Information Type**: ${prompt.includes('dates') ? 'Important Dates' : 'Key Information'} - **Extracted Data**: 1. Meeting scheduled for January 20th at 2 PM 2. Project deadline: February 15th 3. Quarterly review: March 1st The information has been extracted and organized for easy reference.`; case 'analyzePatterns': return `**Pattern Analysis Results** After analyzing the lifelog data, I've identified the following patterns: 1. **Recurring Topics**: - Project status updates (mentioned 8 times) - Resource allocation (mentioned 5 times) - Client feedback (mentioned 4 times) 2. **Time Patterns**: - Most meetings occur between 10 AM - 12 PM - Friday afternoons have fewer recordings - Average discussion length: 30-45 minutes 3. **Key Relationships**: - Frequent collaboration with engineering team - Regular check-ins with project management - Client interactions primarily on Tuesdays 4. **Notable Changes**: - Increased focus on technical debt over the past week - Shift from planning to execution phase`; default: return `Processed your request using the ${templateName} template. In a real implementation, this would provide detailed analysis based on the actual lifelog content.`; } } } exports.SamplingHandlers = SamplingHandlers; //# sourceMappingURL=handlers.js.map