diff --git a/src/services/llm/pipeline/stages/tool_calling_stage.ts b/src/services/llm/pipeline/stages/tool_calling_stage.ts index e66bf0009..8ffe75c94 100644 --- a/src/services/llm/pipeline/stages/tool_calling_stage.ts +++ b/src/services/llm/pipeline/stages/tool_calling_stage.ts @@ -26,6 +26,8 @@ export class ToolCallingStage extends BasePipelineStage 200 ? '...' : ''}"`); @@ -45,6 +45,12 @@ export class ToolCallingStage extends BasePipelineStage 0) { + const availableToolNames = availableTools.map(t => t.definition.function.name).join(', '); + log.info(`Available tools: ${availableToolNames}`); + } + if (availableTools.length === 0) { log.error(`No tools available in registry, cannot execute tool calls`); // Try to initialize tools as a recovery step @@ -70,8 +76,12 @@ export class ToolCallingStage extends BasePipelineStage { try { + log.info(`========== TOOL CALL ${index + 1} OF ${response.tool_calls.length} ==========`); log.info(`Tool call ${index + 1} received - Name: ${toolCall.function.name}, ID: ${toolCall.id || 'unknown'}`); // Log parameters @@ -176,6 +186,10 @@ export class ToolCallingStage extends BasePipelineStage { // Format the result content based on type diff --git a/src/services/llm/rest_chat_service.ts b/src/services/llm/rest_chat_service.ts index af2ea88a8..89dfb6a82 100644 --- a/src/services/llm/rest_chat_service.ts +++ b/src/services/llm/rest_chat_service.ts @@ -530,28 +530,78 @@ class RestChatService { log.info(`Tool calls details: ${JSON.stringify(response.tool_calls)}`); try { - // Execute the tools - const toolResults = await this.executeToolCalls(response); - log.info(`Successfully executed ${toolResults.length} tool calls in advanced context flow`); + let currentMessages = [...aiMessages]; + let hasMoreToolCalls = true; + let iterationCount = 0; + const MAX_ITERATIONS = 3; // Prevent infinite loops - // Build updated messages with tool results - const toolMessages = [...aiMessages, { + // Add initial assistant response with tool calls + currentMessages.push({ role: 'assistant', content: response.text || '', tool_calls: response.tool_calls - }, ...toolResults]; - - // Make a follow-up request with the tool results - log.info(`Making follow-up request with ${toolResults.length} tool results`); - const followUpOptions = {...chatOptions, enableTools: false}; // Disable tools for follow-up - const followUpResponse = await service.generateChatCompletion(toolMessages, followUpOptions); - - // Update the session with the final response - session.messages.push({ - role: 'assistant', - content: followUpResponse.text || '', - timestamp: new Date() }); + + while (hasMoreToolCalls && iterationCount < MAX_ITERATIONS) { + iterationCount++; + log.info(`Tool iteration ${iterationCount}/${MAX_ITERATIONS}`); + + // Execute the tools + const toolResults = await this.executeToolCalls(response); + log.info(`Successfully executed ${toolResults.length} tool calls in iteration ${iterationCount}`); + + // Add tool results to messages + currentMessages = [...currentMessages, ...toolResults]; + + // Make a follow-up request with the tool results + log.info(`Making follow-up request with ${toolResults.length} tool results`); + const followUpOptions = {...chatOptions, enableTools: iterationCount < MAX_ITERATIONS}; // Enable tools for follow-up but limit iterations + const followUpResponse = await service.generateChatCompletion(currentMessages, followUpOptions); + + // Check if the follow-up response has more tool calls + if (followUpResponse.tool_calls && followUpResponse.tool_calls.length > 0) { + log.info(`Follow-up response has ${followUpResponse.tool_calls.length} more tool calls`); + + // Add this response to messages for next iteration + currentMessages.push({ + role: 'assistant', + content: followUpResponse.text || '', + tool_calls: followUpResponse.tool_calls + }); + + // Update response for next iteration + response.tool_calls = followUpResponse.tool_calls; + } else { + // No more tool calls, add final response and break loop + log.info(`No more tool calls in follow-up response`); + hasMoreToolCalls = false; + + // Update the session with the final response + session.messages.push({ + role: 'assistant', + content: followUpResponse.text || '', + timestamp: new Date() + }); + } + } + + // If we reached the max iterations, add the last response + if (iterationCount >= MAX_ITERATIONS && hasMoreToolCalls) { + log.info(`Reached maximum tool iteration limit of ${MAX_ITERATIONS}`); + + // Get the last response we received + const lastResponse = currentMessages + .filter(msg => msg.role === 'assistant') + .pop(); + + if (lastResponse) { + session.messages.push({ + role: 'assistant', + content: lastResponse.content || '', + timestamp: new Date() + }); + } + } } catch (toolError: any) { log.error(`Error executing tools in advanced context: ${toolError.message}`); diff --git a/src/services/llm/tools/tool_initializer.ts b/src/services/llm/tools/tool_initializer.ts index 0641f7788..9f6ef9750 100644 --- a/src/services/llm/tools/tool_initializer.ts +++ b/src/services/llm/tools/tool_initializer.ts @@ -1,12 +1,16 @@ /** * Tool Initializer - * + * * This module initializes all available tools for the LLM to use. */ import toolRegistry from './tool_registry.js'; import { SearchNotesTool } from './search_notes_tool.js'; import { ReadNoteTool } from './read_note_tool.js'; +import { NoteCreationTool } from './note_creation_tool.js'; +import { NoteUpdateTool } from './note_update_tool.js'; +import { ContentExtractionTool } from './content_extraction_tool.js'; +import { RelationshipTool } from './relationship_tool.js'; import log from '../../log.js'; /** @@ -15,16 +19,23 @@ import log from '../../log.js'; export async function initializeTools(): Promise { try { log.info('Initializing LLM tools...'); - - // Register basic notes tools + + // Register basic note search and read tools toolRegistry.registerTool(new SearchNotesTool()); toolRegistry.registerTool(new ReadNoteTool()); - - // More tools can be registered here - + + // Register note creation and manipulation tools + toolRegistry.registerTool(new NoteCreationTool()); + toolRegistry.registerTool(new NoteUpdateTool()); + + // Register content analysis tools + toolRegistry.registerTool(new ContentExtractionTool()); + toolRegistry.registerTool(new RelationshipTool()); + // Log registered tools const toolCount = toolRegistry.getAllTools().length; - log.info(`Successfully registered ${toolCount} LLM tools`); + const toolNames = toolRegistry.getAllTools().map(tool => tool.definition.function.name).join(', '); + log.info(`Successfully registered ${toolCount} LLM tools: ${toolNames}`); } catch (error: any) { log.error(`Error initializing LLM tools: ${error.message || String(error)}`); // Don't throw, just log the error to prevent breaking the pipeline