Skip to main content
Glama
jakedx6
by jakedx6

generate_conversation_summary

Create summaries from conversations to extract key points, action items, or decisions for project management and documentation.

Instructions

Generate different types of summaries from a conversation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
conversation_idYesThe conversation ID to summarize
summary_typeNoType of summary to generatebrief

Implementation Reference

  • Main handler function that parses input args using the schema, fetches the conversation by ID, generates the appropriate type of summary using dedicated helper functions, computes metadata including duration and participants, and returns the summary along with stats like word count and estimated reading time.
    export const generateConversationSummary = requireAuth(async (args: any) => { const { conversation_id, summary_type } = GenerateConversationSummarySchema.parse(args) logger.info('Generating conversation summary', { conversation_id, summary_type }) const conversation = await getConversationFromDatabase(conversation_id) if (!conversation) { throw new Error('Conversation not found') } let summary: string switch (summary_type) { case 'brief': summary = generateBriefSummary(conversation.messages) break case 'detailed': summary = generateDetailedSummary(conversation.messages, conversation.metadata?.context) break case 'action_items': summary = generateActionItemsSummary(conversation.messages) break case 'decisions': summary = generateDecisionsSummary(conversation.messages) break default: summary = generateBriefSummary(conversation.messages) } const metadata = { conversation_id, summary_type, generated_at: new Date().toISOString(), message_count: conversation.messages.length, conversation_duration: calculateConversationDuration(conversation.messages), key_participants: extractParticipants(conversation.messages) } return { summary, metadata, word_count: summary.split(' ').length, reading_time: Math.ceil(summary.split(' ').length / 200) // 200 words per minute } })
  • Zod schema used for input validation in the handler. Defines required conversation_id as UUID and optional summary_type enum with default 'brief'.
    const GenerateConversationSummarySchema = z.object({ conversation_id: z.string().uuid(), summary_type: z.enum(['brief', 'detailed', 'action_items', 'decisions']).default('brief') })
  • MCPTool object defining the tool with name 'generate_conversation_summary', description, and JSON inputSchema matching the Zod schema for tool registration.
    export const generateConversationSummaryTool: MCPTool = { name: 'generate_conversation_summary', description: 'Generate different types of summaries from a conversation', inputSchema: { type: 'object', properties: { conversation_id: { type: 'string', format: 'uuid', description: 'The conversation ID to summarize' }, summary_type: { type: 'string', enum: ['brief', 'detailed', 'action_items', 'decisions'], default: 'brief', description: 'Type of summary to generate' } }, required: ['conversation_id'] } }
  • Exported handlers object mapping snake_case tool names to their handler functions, likely used for central registration of all conversation tools.
    export const conversationHandlers = { save_conversation: saveConversation, get_conversations: getConversations, analyze_conversation: analyzeConversation, extract_action_items: extractActionItems, generate_conversation_summary: generateConversationSummary
  • Supporting helper functions that implement different summary types (brief, detailed, action_items, decisions), duration calculation, participant extraction, and other utilities used by the main handler.
    }) // Helper functions for conversation analysis function generateConversationTitle(messages: Message[], type?: string): string { if (type) { const typeLabels: Record<string, string> = { task_discussion: 'Task Discussion', document_review: 'Document Review', project_planning: 'Project Planning', troubleshooting: 'Troubleshooting', general: 'General Discussion' } return `${typeLabels[type] || 'Discussion'} - ${new Date().toLocaleDateString()}` } // Extract potential title from first user message const firstUserMessage = messages.find(m => m.role === 'user') if (firstUserMessage) { const firstLine = firstUserMessage.content.split('\n')[0] if (firstLine.length > 10 && firstLine.length < 100) { return firstLine.length > 50 ? firstLine.substring(0, 47) + '...' : firstLine } } return `AI Conversation - ${new Date().toLocaleDateString()}` } function analyzeConversationContent(messages: Message[]): any { const totalMessages = messages.length const userMessages = messages.filter(m => m.role === 'user').length const assistantMessages = messages.filter(m => m.role === 'assistant').length const totalWords = messages.reduce((sum, msg) => sum + msg.content.split(' ').length, 0) const avgWordsPerMessage = totalWords / totalMessages // Extract common patterns const questions = messages.filter(msg => msg.content.includes('?')).length const codeBlocks = messages.filter(msg => msg.content.includes('```')).length const urls = messages.filter(msg => /https?:\/\//.test(msg.content)).length return { message_count: totalMessages, user_messages: userMessages, assistant_messages: assistantMessages, total_words: totalWords, avg_words_per_message: Math.round(avgWordsPerMessage), questions_asked: questions, code_examples: codeBlocks, external_links: urls, conversation_balance: userMessages / (assistantMessages || 1) } } function extractActionItemsFromConversation(messages: Message[], context?: any): any[] { const actionItems: any[] = [] // Simple regex patterns for action items const patterns = [ /(?:need to|should|must|will|todo|action item):?\s*(.+)/gi, /(?:let's|we'll|i'll|you'll)\s+(.+)/gi, /(?:next step|follow up|follow-up):?\s*(.+)/gi ] messages.forEach((message, index) => { patterns.forEach(pattern => { const matches = [...message.content.matchAll(pattern)] matches.forEach(match => { if (match[1] && match[1].length > 10 && match[1].length < 200) { actionItems.push({ title: match[1].trim(), description: `From conversation: "${message.content.substring(0, 100)}..."`, source_message_index: index, source_role: message.role, priority: determinePriority(match[1]), confidence: calculateConfidence(match[1], message.content), context }) } }) }) }) return actionItems } function determinePriority(text: string): 'low' | 'medium' | 'high' | 'urgent' { const urgentWords = ['urgent', 'asap', 'immediately', 'critical', 'emergency'] const highWords = ['important', 'priority', 'must', 'required', 'essential'] const lowerText = text.toLowerCase() if (urgentWords.some(word => lowerText.includes(word))) return 'urgent' if (highWords.some(word => lowerText.includes(word))) return 'high' if (lowerText.includes('should') || lowerText.includes('need')) return 'medium' return 'low' } function calculateConfidence(text: string, context: string): number { let confidence = 50 // Base confidence // Increase confidence for specific patterns if (text.includes('will') || text.includes('must')) confidence += 20 if (text.includes('should') || text.includes('need to')) confidence += 15 if (context.includes('action') || context.includes('todo')) confidence += 10 if (text.length > 50) confidence += 10 // More detailed items // Decrease confidence for vague language if (text.includes('maybe') || text.includes('might')) confidence -= 15 if (text.includes('probably') || text.includes('perhaps')) confidence -= 10 return Math.max(0, Math.min(100, confidence)) } function estimateTokenCount(messages: Message[]): number { // Rough estimate: 1 token ≈ 4 characters const totalChars = messages.reduce((sum, msg) => sum + msg.content.length, 0) return Math.ceil(totalChars / 4) } // Placeholder functions for database operations (to be implemented in supabase service) async function saveConversationToDatabase(conversationData: any): Promise<any> { // This would be implemented in the supabase service return { id: 'generated-uuid', ...conversationData, created_at: new Date().toISOString(), updated_at: new Date().toISOString() } } async function getConversationsFromDatabase(filters: any): Promise<any[]> { // This would be implemented in the supabase service return [] } async function getConversationFromDatabase(id: string): Promise<any> { // This would be implemented in the supabase service return null } // Additional analysis functions function analyzeConversationFlow(messages: Message[]): any { return { turn_taking: messages.reduce((acc, msg, idx) => { if (idx > 0 && messages[idx - 1].role !== msg.role) acc++ return acc }, 0), longest_response: Math.max(...messages.map(m => m.content.length)), conversation_rhythm: 'balanced' // Would calculate based on message timing } } function analyzeAIPerformance(messages: Message[]): any { const aiMessages = messages.filter(m => m.role === 'assistant') return { response_count: aiMessages.length, avg_response_length: aiMessages.reduce((sum, msg) => sum + msg.content.length, 0) / (aiMessages.length || 1), helpful_responses: aiMessages.filter(msg => msg.content.includes('```') || msg.content.includes('example') || msg.content.length > 100 ).length } } function extractTopicsAndThemes(messages: Message[]): string[] { // Simple keyword extraction const allText = messages.map(m => m.content).join(' ').toLowerCase() const commonWords = ['the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'can', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they'] const words = allText.split(/\s+/).filter(word => word.length > 3 && !commonWords.includes(word) && /^[a-zA-Z]+$/.test(word) ) const wordCount = words.reduce((acc, word) => { acc[word] = (acc[word] || 0) + 1 return acc }, {} as Record<string, number>) return Object.entries(wordCount) .sort(([,a], [,b]) => b - a) .slice(0, 10) .map(([word]) => word) } function extractDecisions(messages: Message[]): string[] { const decisionPatterns = [ /(?:decided|decision|concluded|agreed|determined):?\s*(.+)/gi, /(?:we will|we'll|going to)\s+(.+)/gi ] const decisions: string[] = [] messages.forEach(message => { decisionPatterns.forEach(pattern => { const matches = [...message.content.matchAll(pattern)] matches.forEach(match => { if (match[1] && match[1].length > 10) { decisions.push(match[1].trim()) } }) }) }) return decisions } function extractQuestions(messages: Message[]): string[] { return messages .filter(msg => msg.content.includes('?')) .map(msg => msg.content.split('?')[0] + '?') .filter(q => q.length > 10 && q.length < 200) } function identifyKnowledgeGaps(messages: Message[]): string[] { const gapPatterns = [ /(?:don't know|not sure|unclear|confused|need help):?\s*(.+)/gi, /(?:how to|what is|what are|where is|when is|why is)\s+(.+)/gi ] const gaps: string[] = [] messages.forEach(message => { gapPatterns.forEach(pattern => { const matches = [...message.content.matchAll(pattern)] matches.forEach(match => { if (match[1] && match[1].length > 5) { gaps.push(match[1].trim()) } }) }) }) return gaps } function generateFollowUpSuggestions(messages: Message[], context?: any): string[] { const suggestions = [ 'Review and prioritize the action items identified', 'Schedule follow-up meeting to track progress', 'Create documentation based on decisions made', 'Share summary with relevant team members' ] if (context?.task_id) { suggestions.push('Update the related task with conversation insights') } if (context?.document_id) { suggestions.push('Update the related document with new information') } return suggestions } function generateBriefSummary(messages: Message[]): string {

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jakedx6/helios9-MCP-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server