UNPKG

@agentforce/adk

Version:

AgentForce Agent Development Kit - A powerful framework for building AI agents and servers

323 lines (275 loc) 12 kB
import type { AgentForceAgent } from "../../../agent"; import { GoogleProvider } from "../../../provider/google"; import { OllamaProvider } from "../../../provider/ollama"; import { OpenRouterProvider } from "../../../provider/openrouter"; import { loadSkills } from "../../functions/skills"; import { loadTools } from "../../functions/tools"; import { loadMCPs, getMCPTools, disconnectMCPs } from "../../functions/mcp"; import { truncate } from "../../../utils/truncate"; /** * Executes the agent's provider call to generate response * @param this - The AgentForceAgent instance (bound context) * @returns {Promise<string>} Returns the generated response from the provider */ export async function execute(this: AgentForceAgent): Promise<string> { const logger = this.getLogger(); // Get agent configuration const provider = this.getProvider(); const model = this.getModel(); const systemPrompt = this.getSystemPrompt(); const template = this.getTemplate(); const userPrompt = this.getUserPrompt(); const modelConfig = (this as any).getModelConfig?.() || undefined; // access if available const taskList = this.getTaskList(); // Load skills content const skills = this.getSkills(); const skillsContent = (skills && skills.length > 0) ? (loadSkills(this) || "") : ""; // Load tools if configured const tools = this.getTools(); const loadedTools = (tools && tools.length > 0) ? (loadTools(this) || []) : []; // Load and connect MCP servers if configured const mcps = this.getMCPs(); if (mcps && mcps.length > 0) { await loadMCPs(this); } // Get MCP tools to add to the tool list const mcpTools = await getMCPTools(this); // Combine regular tools with MCP tools const allTools = [...loadedTools, ...mcpTools]; // Construct the full system prompt in order: systemPrompt + skills + template let fullSystemPrompt = systemPrompt; // Add skills content if available if (skillsContent) { fullSystemPrompt = `${fullSystemPrompt}${skillsContent}`; } // Add template if available if (template && template.trim()) { fullSystemPrompt = `${fullSystemPrompt}\n\n${template}`; } // Log the execution details logger.debug( "Run execute", { agent: this.getName() }, { provider: provider }, { model: model }, { systemPrompt: truncate(systemPrompt, 100) }, { skillsContent: skillsContent ? truncate(skillsContent, 100) : "none" }, { template: template ? truncate(template, 100) : "none" }, { userPrompt: userPrompt }, ); // Check if we have tasks to process if (taskList && taskList.length > 0) { logger.debug({ taskCount: taskList.length }, "Processing task list"); // Add the initial user prompt to chat history if it exists if (userPrompt && userPrompt.trim()) { this.pushToChatHistory("user", userPrompt); } const results: string[] = []; // Process each task sequentially for (let i = 0; i < taskList.length; i++) { const task = taskList[i]; if (!task) { logger.debug({ taskIndex: i }, "Skipping undefined task"); continue; } logger.debug({ taskIndex: i, task: task.description }, "Processing task"); // Add the current task as a user message to chat history this.pushToChatHistory("user", task.description); // Execute the task with full chat history context const taskResult = await executeProviderCallWithChatHistory( this, provider, model, modelConfig, fullSystemPrompt, task.description, allTools, logger, ); // Add the task result to chat history this.pushToChatHistory("assistant", taskResult); // Store the result task.result = taskResult; results.push(taskResult); logger.debug({ taskIndex: i, resultLength: taskResult.length }, "Task completed"); } // Clear the task list after processing this.clearTaskList(); // Cleanup MCP connections after task processing if (mcps && mcps.length > 0) { try { await disconnectMCPs(this); } catch (cleanupError) { logger.error("MCP cleanup error:", cleanupError); } } // Return the final result (last task's output) or empty string if no results return results.length > 0 ? results[results.length - 1]! : ""; } // Store the user prompt in chat history if not already stored const chatHistory = this.getChatHistory(); const lastUserMessage = chatHistory.findLast(msg => msg.role === "user"); if (!lastUserMessage || lastUserMessage.content !== userPrompt) { this.pushToChatHistory("user", userPrompt); } try { let response: string; response = await executeProviderCall( this, provider, model, modelConfig, fullSystemPrompt, userPrompt, allTools, logger, ); // Store the assistant response in chat history this.pushToChatHistory("assistant", response); return response; } catch (error) { // Store error in chat history as well const errorMessage = `Error: ${error}`; this.pushToChatHistory("assistant", errorMessage); logger.error("Execution error:", errorMessage); throw error; // Re-throw to let caller handle the error } finally { // Always cleanup MCP connections to prevent hanging if (mcps && mcps.length > 0) { try { await disconnectMCPs(this); } catch (cleanupError) { logger.error("MCP cleanup error:", cleanupError); } } } } /** * Helper function to execute provider calls with full chat history context * @internal */ async function executeProviderCallWithChatHistory( agent: AgentForceAgent, provider: string, model: string, modelConfig: any, systemPrompt: string, currentUserPrompt: string, loadedTools: any[], logger: any, ): Promise<string> { const chatHistory = (agent as any).getChatHistory(); // Prepare messages for chat format - include system prompt as first message const messages: Array<{ role: string; content: string }> = []; // Add system message if we have one if (systemPrompt && systemPrompt.trim()) { messages.push({ role: "system", content: systemPrompt }); } // Add chat history messages.push(...chatHistory); // Add current user prompt messages.push({ role: "user", content: currentUserPrompt }); // Execute based on provider switch (provider.toLowerCase()) { case "ollama": // Initialize Ollama provider with model config const ollamaProvider = new OllamaProvider(model, modelConfig); // Generate response using Ollama with tools if available if (loadedTools && loadedTools.length > 0) { logger.debug("Using Ollama with tools and chat history", { toolCount: loadedTools.length, chatHistoryLength: chatHistory.length, totalMessages: messages.length, }); return await ollamaProvider.chatWithTools(messages, loadedTools, logger, agent); } else { logger.debug("Using Ollama with chat history", { chatHistoryLength: chatHistory.length, totalMessages: messages.length, }); return await ollamaProvider.chat(messages); } case "openrouter": // Initialize OpenRouter provider const openRouterProvider = new OpenRouterProvider(model, modelConfig); // Generate response using OpenRouter with tools if available if (loadedTools && loadedTools.length > 0) { logger.debug("Using OpenRouter with tools and chat history", { toolCount: loadedTools.length, chatHistoryLength: chatHistory.length, totalMessages: messages.length, }); return await openRouterProvider.chatWithTools(messages, loadedTools, logger, agent); } else { logger.debug("Using OpenRouter with chat history", { chatHistoryLength: chatHistory.length, totalMessages: messages.length, }); return await openRouterProvider.chat(messages); } case "google": // Initialize Google provider const googleProvider = new GoogleProvider(model, modelConfig); // Generate response using Google with chat history logger.debug("Using Google with chat history", { chatHistoryLength: chatHistory.length, totalMessages: messages.length, }); return await googleProvider.chat(messages); case "openai": return "OpenAI integration not implemented yet."; case "anthropic": return "Anthropic integration not implemented yet."; default: return `Unknown provider integration not available: ${provider}`; } } /** * Helper function to execute provider calls (legacy - for non-task execution) * @internal */ async function executeProviderCall( _agent: AgentForceAgent, provider: string, model: string, modelConfig: any, systemPrompt: string, userPrompt: string, loadedTools: any[], logger: any, ): Promise<string> { // Execute based on provider switch (provider.toLowerCase()) { case "ollama": // Initialize Ollama provider with model config const ollamaProvider = new OllamaProvider(model, modelConfig); // Generate response using Ollama with tools if available if (loadedTools && loadedTools.length > 0) { logger.debug("Using Ollama with tools", { toolCount: loadedTools.length }); return await ollamaProvider.generateWithTools(userPrompt, loadedTools, systemPrompt, logger, _agent); } else { return await ollamaProvider.generate(userPrompt, systemPrompt); } case "openrouter": // Initialize OpenRouter provider const openRouterProvider = new OpenRouterProvider(model, modelConfig); // Generate response using OpenRouter with tools if available if (loadedTools && loadedTools.length > 0) { logger.debug("Using OpenRouter with tools", { toolCount: loadedTools.length }); return await openRouterProvider.generateWithTools(userPrompt, loadedTools, systemPrompt, logger, _agent); } else { return await openRouterProvider.generate(userPrompt, systemPrompt); } case "google": // Initialize Google provider const googleProvider = new GoogleProvider(model, modelConfig); // Generate response using Google return await googleProvider.generate(userPrompt, systemPrompt); case "openai": return "OpenAI integration not implemented yet."; case "anthropic": return "Anthropic integration not implemented yet."; default: return `Unknown provider integration not available: ${provider}`; } }