import { MessageUI } from '@/lib/types/database'
import { ToolResult } from '@/lib/services/tool-executor'
export interface ContextInfo {
filesFound: number
fileNames: string[]
}
export interface StreamingActivity {
planning: string
currentExecution: {
name: string
description: string
args?: any
} | null
toolResults: Array<{
name: string
result: string
success: boolean
}>
}
/**
* Generate a summary of tool operations for display
*/
export function generateToolSummary(results: ToolResult[]): string {
let summary = "๐ ๏ธ **File Operations Completed:**\n\n"
results.forEach((result, i) => {
if (result.name === 'search_files') {
summary += `${i + 1}. ๐ **Search Files**: Found ${(result as any).result?.length || 0} file(s)\n`
} else if (result.name === 'read_file') {
summary += `${i + 1}. ๐ **Read File**: ${(result as any).result?.name || 'file'}\n`
} else if (result.name === 'update_file') {
summary += `${i + 1}. โ๏ธ **Updated File**: ${(result as any).result?.name || 'file'}\n ๐ ${(result as any).result?.change_summary || 'updated'}\n`
}
})
return summary
}
/**
* Build comprehensive message content that includes all AI activity
*/
export function buildComprehensiveMessageContent(
finalResponse: string,
streamingActivity: StreamingActivity
): string {
let comprehensiveContent = ''
// Add planning phase if it occurred
if (streamingActivity.planning) {
comprehensiveContent += `๐ **AI Planning:** ${streamingActivity.planning}\n\n`
}
// Add tool execution results if any
if (streamingActivity.toolResults.length > 0) {
comprehensiveContent += `๐ ๏ธ **Actions Performed:**\n`
streamingActivity.toolResults.forEach((result, index) => {
const status = result.success ? 'โ
' : 'โ'
comprehensiveContent += `${status} **${result.name}:** ${result.result}\n`
})
comprehensiveContent += '\n'
}
// Add the main AI response
if (finalResponse.trim()) {
comprehensiveContent += finalResponse
}
return comprehensiveContent
}
/**
* Build content for stopped/interrupted execution
*/
export function buildStoppedMessageContent(
partialContent: string,
streamingActivity: StreamingActivity
): string {
let stoppedContent = ''
// Add planning phase if it occurred
if (streamingActivity.planning) {
stoppedContent += `๐ **AI Planning:** ${streamingActivity.planning}\n\n`
}
// Add current tool execution if it was in progress
if (streamingActivity.currentExecution) {
stoppedContent += `โ๏ธ **Was Executing:** ${streamingActivity.currentExecution.description} *(interrupted)*\n\n`
}
// Add completed tool execution results if any
if (streamingActivity.toolResults.length > 0) {
stoppedContent += `๐ ๏ธ **Actions Performed Before Stop:**\n`
streamingActivity.toolResults.forEach((result, index) => {
const status = result.success ? 'โ
' : 'โ'
stoppedContent += `${status} **${result.name}:** ${result.result}\n`
})
stoppedContent += '\n'
}
// Add the partial content
if (partialContent) {
stoppedContent += partialContent + '\n\n'
}
// Add stop indicator
stoppedContent += 'โน๏ธ *Execution stopped by user*'
return stoppedContent
}
/**
* Compose all display messages including streaming content
*/
export function composeDisplayMessages(
messages: MessageUI[],
isStreaming: boolean,
streamingMessage: string,
aiPlanning: string,
currentToolExecution: {
name: string
description: string
args?: any
} | null,
toolExecutionResults: Array<{
name: string
result: string
success: boolean
}>
): (MessageUI & { _isStreaming?: boolean })[] {
// Enhanced message composition that avoids duplicates
const baseMessages = [...messages]
// Only add streaming message if we have content and are actively streaming
if (isStreaming && (streamingMessage || aiPlanning || currentToolExecution)) {
// Create a comprehensive streaming message that includes all current AI activity
let streamingContent = ''
if (aiPlanning) {
streamingContent += `๐ **Planning:** ${aiPlanning}\n\n`
}
if (currentToolExecution) {
streamingContent += `โ๏ธ **Executing:** ${currentToolExecution.description}\n\n`
}
// Add tool execution results
if (toolExecutionResults.length > 0) {
streamingContent += `๐ **Tool Results:**\n`
toolExecutionResults.forEach((result, index) => {
const status = result.success ? 'โ
' : 'โ'
streamingContent += `${status} ${result.name}: ${result.result}\n`
})
streamingContent += '\n'
}
// Add the main content with proper separation
if (streamingMessage) {
// If we have tool activity and then content, add proper separation
if ((aiPlanning || currentToolExecution || toolExecutionResults.length > 0) && !streamingMessage.startsWith('\n')) {
streamingContent += '\n'
}
streamingContent += streamingMessage
}
// Only add streaming message if we have any content
if (streamingContent.trim()) {
baseMessages.push({
id: 'streaming-temp', // Use a consistent ID to prevent React key issues
type: 'ai' as const,
content: streamingContent,
timestamp: new Date(),
// Add temporary property for streaming identification
_isStreaming: true
} as MessageUI & { _isStreaming: boolean })
}
}
return baseMessages
}
/**
* Check if tool results contain file-modifying operations
*/
export function hasFileModifyingOperations(toolResults: ToolResult[]): boolean {
return toolResults.some((result: ToolResult) =>
['update_file', 'create_file', 'delete_file', 'move_file'].includes(result.name)
)
}
/**
* Create error message for display
*/
export function createErrorMessage(): MessageUI {
return {
id: Date.now() + 1,
type: 'ai',
content: 'Sorry, I encountered an error while processing your request. Please try again.',
timestamp: new Date()
}
}
// Shared utility for deleting messages
export const deleteMessage = async (messageId: string): Promise<void> => {
// Get auth headers with session token
const { data: { session } } = await import('@/lib/supabase').then(m => m.supabase.auth.getSession())
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (session?.access_token) {
headers['Authorization'] = `Bearer ${session.access_token}`
}
const response = await fetch(`/api/chat/messages/${messageId}`, {
method: 'DELETE',
headers,
})
if (!response.ok) {
const errorData = await response.json()
throw new Error(errorData.error || 'Failed to delete message')
}
}