UNPKG

contaigents

Version:

Modular AI Content Ecosystem with Audio Generation

175 lines (159 loc) โ€ข 7.75 kB
import { ChatService } from '../services/chatService.js'; import fs from 'fs/promises'; import path from 'path'; // Mock LLM that generates multiple turns of XML tool calls class MockMultiTurnLLM { constructor() { this.callCount = 0; } async executePrompt(prompt, _options) { this.callCount++; console.log(`๐Ÿค– Mock LLM call #${this.callCount} - received prompt with length:`, prompt.length); // First call: User asks to test multi-turn functionality if (prompt.includes('test multiple tool calls') && this.callCount === 1) { return { content: `I'll demonstrate multiple tool calls in sequence. First, let me read the README file. <tool_call name="read_file" id="1"> <file_path>README.md</file_path> </tool_call> After reading the file, I'll create a new test file based on its content.` }; } // Second call: After first tool execution, make another tool call if (this.callCount === 2 && prompt.includes('tool_response')) { return { content: `Great! I've read the README file. Now I'll create a test file based on what I learned. <tool_call name="write_file" id="2"> <file_path>multi-turn-test.md</file_path> <content><![CDATA[# Multi-Turn Test This file was created after reading the README file in a multi-turn conversation. It demonstrates the proper tool call loop functionality. ## Features Tested: - Sequential tool calls across multiple turns - Turn counting and max turn limits - Proper LLM loop continuation until no more tool calls - Tool response integration ## Turn Flow: 1. User request โ†’ LLM response with tool_call 2. Tool execution โ†’ Tool response fed back to LLM 3. LLM response with another tool_call 4. Tool execution โ†’ Tool response fed back to LLM 5. LLM final response (no tool calls) โ†’ Return to user ]]></content> </tool_call> Perfect! I've created a comprehensive test file that documents the multi-turn process.` }; } // Third call: After second tool execution, make one more tool call if (this.callCount === 3 && prompt.includes('tool_response')) { return { content: `Excellent! Now let me create one final summary file to complete the test. <tool_call name="write_file" id="3"> <file_path>turn-summary.txt</file_path> <content>Multi-Turn Tool Call Test Summary ===================================== Total LLM Calls: 3 Total Tool Calls: 3 Tools Used: read_file, write_file (x2) This demonstrates that the chat service properly: - Continues the loop until no more tool calls - Tracks turn count correctly - Feeds tool responses back to LLM - Only returns to user when LLM response has no tool calls Test Status: SUCCESS โœ…</content> </tool_call> All files created successfully! This completes the multi-turn tool call demonstration.` }; } // Fourth call: Final response with no tool calls if (this.callCount === 4) { return { content: `๐ŸŽ‰ Multi-turn tool call test completed successfully! ## Summary: - **Turn 1**: Read README file - **Turn 2**: Created multi-turn-test.md based on README content - **Turn 3**: Created turn-summary.txt with test results - **Turn 4**: Final response (this message) The chat service correctly implemented the while loop pattern: 1. โœ… Continued processing until no more tool calls 2. โœ… Tracked turn count (4 total turns) 3. โœ… Fed tool responses back to LLM as user messages 4. โœ… Only returned to user when LLM response contained no tool calls 5. โœ… Respected max turn limits (10 max, used 4) This demonstrates the proper agentic tool call flow where the LLM can make multiple sequential tool calls and only returns control to the user when the task is complete.` }; } // Fallback response return { content: `I understand your request. How can I help you with file operations?` }; } } async function testMultiTurnToolCalls() { console.log('๐Ÿงช Testing Multi-Turn Tool Call Flow'); console.log('='.repeat(50)); // Create a test directory const testDir = path.join(process.cwd(), 'test-multi-turn'); await fs.mkdir(testDir, { recursive: true }); // Create a test README file await fs.writeFile(path.join(testDir, 'README.md'), '# Multi-Turn Test Project\n\nThis README will be read by the LLM in the first tool call.\nThe LLM will then create additional files based on this content.\n'); try { // Mock the LLM factory to return our test LLM const LLMFactory = (await import('../services/llm/LLMFactory.js')).LLMFactory; const originalGetConfiguredProvider = LLMFactory.getConfiguredProvider; const originalGetProvider = LLMFactory.getProvider; // Mock both methods to return our test LLM LLMFactory.getConfiguredProvider = async () => new MockMultiTurnLLM(); LLMFactory.getProvider = (providerName) => new MockMultiTurnLLM(); // Create chat service with test directory const chatService = new ChatService(testDir); // Create a chat session const session = chatService.createSession({ systemPrompt: 'You are a helpful assistant that can read and write files. Use XML tool calls to perform file operations.' }); console.log(`๐Ÿ“ Created chat session: ${session.id}`); // Send a message that will trigger multiple tool calls console.log('\n๐Ÿš€ Sending message: "test multiple tool calls"'); const response = await chatService.sendMessage(session.id, 'test multiple tool calls'); console.log('\n๐Ÿ“จ Final Response:'); console.log(response.content); // Verify files were created console.log('\n๐Ÿ“ Verifying created files:'); const files = ['multi-turn-test.md', 'turn-summary.txt']; for (const file of files) { const filePath = path.join(testDir, file); try { const content = await fs.readFile(filePath, 'utf-8'); console.log(`โœ… ${file} created (${content.length} characters)`); } catch (error) { console.log(`โŒ ${file} not found`); } } // Show all messages in session (including tool responses) console.log('\n๐Ÿ’ฌ Complete Message History:'); const allMessages = chatService.getAllMessages(session.id); allMessages.forEach((msg, index) => { const roleIcon = msg.role === 'user' ? '๐Ÿ‘ค' : msg.role === 'assistant' ? '๐Ÿค–' : 'โš™๏ธ'; const toolFlag = msg.isToolResponse ? ' [TOOL_RESPONSE]' : ''; console.log(`${index + 1}. ${roleIcon} ${msg.role.toUpperCase()}${toolFlag}:`); console.log(` ${msg.content.substring(0, 100)}${msg.content.length > 100 ? '...' : ''}`); }); // Restore original LLM factory methods LLMFactory.getConfiguredProvider = originalGetConfiguredProvider; LLMFactory.getProvider = originalGetProvider; console.log('\n๐ŸŽ‰ Multi-Turn Tool Call Test Complete!'); console.log('\n๐ŸŽฏ Key Findings:'); console.log('- โœ… Multi-turn tool calls work correctly'); console.log('- โœ… Turn counting implemented properly'); console.log('- โœ… Tool responses fed back to LLM'); console.log('- โœ… Loop continues until no more tool calls'); console.log('- โœ… Final response returned to user only when complete'); } finally { // Cleanup await fs.rm(testDir, { recursive: true, force: true }); } } // Run the test testMultiTurnToolCalls().catch(console.error);