agent.js•10.3 kB
"use strict";
/**
* Main Agent class integrating MCP capabilities with LLM interactions
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Agent = void 0;
const uuid_1 = require("uuid");
const contextDependent_1 = require("../core/contextDependent");
const exceptions_1 = require("../core/exceptions");
const aggregator_1 = require("../mcp/aggregator");
/**
* Agent class that manages MCP server connections and LLM interactions
*/
class Agent extends contextDependent_1.ContextDependentBase {
id;
name;
instruction;
serverNames;
connectionPersistence;
aggregator;
llm;
initialized = false;
// Conversation history
messages = [];
constructor(context, config) {
super(context);
this.id = (0, uuid_1.v4)();
this.name = config.name;
this.instruction = config.instruction;
this.serverNames = config.server_names || [];
this.connectionPersistence = config.connection_persistence ?? true;
// Log agent creation
this.logger.info(`Created agent '${this.name}' with ID: ${this.id}`);
}
/**
* Initialize the agent and its MCP connections
*/
async initialize() {
if (this.initialized) {
return;
}
this.logger.info(`Initializing agent '${this.name}'...`);
try {
// Create and initialize MCP aggregator if servers are configured
if (this.serverNames.length > 0) {
this.aggregator = new aggregator_1.MCPAggregator(this.context, this.serverNames, {
connectionPersistence: this.connectionPersistence,
name: this.name
});
await this.aggregator.initialize();
}
// Add system instruction if provided
if (this.instruction) {
this.messages.push({
role: 'system',
content: this.instruction
});
}
this.initialized = true;
this.logger.info(`Agent '${this.name}' initialized successfully`);
}
catch (error) {
this.logger.error(`Failed to initialize agent '${this.name}'`, error);
throw error;
}
}
/**
* Clean up agent resources
*/
async cleanup() {
this.logger.info(`Cleaning up agent '${this.name}'...`);
try {
if (this.aggregator) {
await this.aggregator.close();
}
this.initialized = false;
this.logger.info(`Agent '${this.name}' cleaned up successfully`);
}
catch (error) {
this.logger.error(`Error cleaning up agent '${this.name}'`, error);
throw error;
}
}
/**
* Context manager support
*/
async __aenter__() {
await this.initialize();
return this;
}
async __aexit__(excType, excVal, excTb) {
await this.cleanup();
}
/**
* Set the LLM for this agent
*/
setLLM(llm) {
this.llm = llm;
this.logger.debug(`Set LLM for agent '${this.name}': ${llm.model}`);
}
/**
* Get available tools from connected MCP servers
*/
async getTools() {
if (!this.aggregator) {
return [];
}
const result = await this.aggregator.listTools();
return result.tools;
}
/**
* Get available prompts from connected MCP servers
*/
async getPrompts() {
if (!this.aggregator) {
return [];
}
const result = await this.aggregator.listPrompts();
return result.prompts;
}
/**
* Get available resources from connected MCP servers
*/
async getResources() {
if (!this.aggregator) {
return [];
}
const result = await this.aggregator.listResources();
return result.resources;
}
/**
* Call a tool through the MCP aggregator
*/
async callTool(name, args) {
if (!this.aggregator) {
throw new exceptions_1.ValidationError('No MCP servers configured');
}
this.logger.debug(`Agent '${this.name}' calling tool: ${name}`);
return await this.aggregator.callTool(name, args);
}
/**
* Send a message to the agent and get a response
*/
async sendMessage(content, options) {
await this.ensureInitialized();
if (!this.llm) {
throw new exceptions_1.ValidationError('No LLM configured for this agent');
}
// Add user message to history
this.messages.push({
role: 'user',
content
});
// Get available tools if requested
let tools;
if (options?.tools && this.aggregator) {
tools = await this.getTools();
}
// Generate response
const response = await this.llm.generate(this.messages, tools, {
temperature: options?.temperature,
max_tokens: options?.max_tokens
});
// Handle tool calls if present
if (response.tool_calls && response.tool_calls.length > 0) {
// Add assistant message with tool calls
this.messages.push({
role: 'assistant',
content: response.content,
tool_calls: response.tool_calls
});
// Execute tool calls
for (const toolCall of response.tool_calls) {
await this.executeToolCall(toolCall);
}
// Get final response after tool execution
return await this.llm.generate(this.messages, tools, options);
}
// Add assistant response to history
this.messages.push({
role: 'assistant',
content: response.content
});
return response;
}
/**
* Execute a tool call
*/
async executeToolCall(toolCall) {
try {
const args = JSON.parse(toolCall.function.arguments);
const result = await this.callTool(toolCall.function.name, args);
// Add tool result to messages
this.messages.push({
role: 'tool',
content: this.formatToolResult(result),
tool_call_id: toolCall.id,
name: toolCall.function.name
});
}
catch (error) {
// Add error to messages
this.messages.push({
role: 'tool',
content: `Error calling tool: ${error}`,
tool_call_id: toolCall.id,
name: toolCall.function.name
});
}
}
/**
* Format tool result for message history
*/
formatToolResult(result) {
if (!result.content || result.content.length === 0) {
return 'Tool executed successfully with no output';
}
// Convert content array to string
return result.content
.map(item => {
if (item.type === 'text') {
return item.text;
}
else if (item.type === 'image') {
const img = item;
return `[Image: ${img.mimeType}]`;
}
else if (item.type === 'resource') {
const res = item;
return `[Resource: ${res.resource.uri}]`;
}
return '[Unknown content type]';
})
.join('\n');
}
/**
* Get conversation history
*/
getMessages() {
return [...this.messages];
}
/**
* Clear conversation history (keeping system instruction)
*/
clearHistory() {
this.messages = this.messages.filter(msg => msg.role === 'system');
}
/**
* Request human input
*/
async requestHumanInput(request) {
if (!this.context.human_input_callback) {
throw new exceptions_1.ValidationError('No human input callback configured');
}
this.logger.debug(`Agent '${this.name}' requesting human input`);
return await this.context.human_input_callback(request);
}
/**
* Get a prompt by name
*/
async getPrompt(name, args) {
if (!this.aggregator) {
throw new exceptions_1.ValidationError('No MCP servers configured');
}
const result = await this.aggregator.getPrompt(name, args);
// Extract text content from messages
const messages = result.messages || [];
return messages
.map(msg => {
if (msg.content && typeof msg.content === 'string') {
return msg.content;
}
else if (msg.content && Array.isArray(msg.content)) {
return msg.content
.filter(item => item.type === 'text')
.map(item => item.text)
.join('\n');
}
return '';
})
.join('\n\n');
}
/**
* Read a resource by URI
*/
async readResource(uri) {
if (!this.aggregator) {
throw new exceptions_1.ValidationError('No MCP servers configured');
}
const result = await this.aggregator.readResource(uri);
// Extract text content
return result.contents
.filter(item => 'type' in item && item.type === 'text')
.map(item => 'text' in item ? item.text : '')
.join('\n');
}
/**
* Ensure agent is initialized
*/
async ensureInitialized() {
if (!this.initialized) {
await this.initialize();
}
}
/**
* Get agent configuration
*/
getConfig() {
return {
name: this.name,
instruction: this.instruction,
server_names: this.serverNames,
connection_persistence: this.connectionPersistence
};
}
/**
* Get agent statistics
*/
getStats() {
return {
id: this.id,
name: this.name,
messageCount: this.messages.length,
serverCount: this.serverNames.length,
initialized: this.initialized
};
}
}
exports.Agent = Agent;