UNPKG

swift-agent

Version:

A building block of agentic systems: an LLM that can retrieve information, use tools, and store user inputs.

142 lines (120 loc) 3.7 kB
import { BaseChatModel } from "@langchain/core/language_models/chat_models"; import { BaseMessage, HumanMessage, SystemMessage, } from "@langchain/core/messages"; import { MultiServerMCPClient } from "@langchain/mcp-adapters"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { MCPServerConfig, MCPServerTool, SwiftAgentOptions, } from "./types.js"; export class SwiftAgent { private agent?: ReturnType<typeof createReactAgent>; private mcpClient?: MultiServerMCPClient; private messages: BaseMessage[] = []; private model: BaseChatModel; private options?: SwiftAgentOptions; private tools: MCPServerTool[] = []; private toolsInitialized = false; constructor(model: BaseChatModel, options?: SwiftAgentOptions) { this.model = model; this.options = options; if (this.options?.mcp) { this.mcpClient = new MultiServerMCPClient( this.options.mcp as MCPServerConfig, ); } if (options?.messageHistory) { this.messages = options.messageHistory; } if (options?.systemPrompt) { this.applySystemPrompt(options.systemPrompt); } } public async initialize(): Promise<void> { await this.getAgent(); } public async run(message: string): Promise<BaseMessage[]> { const agent = await this.getAgent(); this.messages.push(new HumanMessage(message)); const response = await agent.invoke({ messages: this.messages }); this.messages = response.messages; return this.messages; } public async getTools(): Promise<MCPServerTool[]> { if (!this.mcpClient || this.tools.length > 0) { return this.tools; } const mcpServers = this.mcpClient.config.mcpServers || {}; const serverNames = Object.keys(mcpServers); this.tools = (await Promise.all( serverNames.map(async (serverName) => { const tools = (await this.mcpClient?.getTools(serverName)) as | MCPServerTool[] | undefined; if (!tools) { return []; } tools.forEach((tool) => { tool.serverName = serverName; tool.isEnabled = true; }); return tools; }), )).flat(); return this.tools; } public async disconnectMCPServers(): Promise<void> { if (this.mcpClient) { await this.mcpClient.close(); } } public enableMCPServer(serverName: string): void { this.setToolsEnabled(serverName, true); } public disableMCPServer(serverName: string): void { this.setToolsEnabled(serverName, false); } public resetMessages(keepSystemMessage = true): void { if (keepSystemMessage && this.messages[0]?.getType() === "system") { this.messages.splice(1); } else { this.messages = []; } } private applySystemPrompt(systemPrompt: string): void { if (this.messages[0]?.getType() === "system") { this.messages[0].content = systemPrompt; } else { this.messages.unshift(new SystemMessage(systemPrompt)); } } private async getAgent(): Promise<ReturnType<typeof createReactAgent>> { if (this.agent) { return this.agent; } if (!this.toolsInitialized) { this.tools = await this.getTools(); this.toolsInitialized = true; } this.agent = createReactAgent({ llm: this.model, tools: this.tools.filter((tool) => tool.isEnabled), }); return this.agent; } private setToolsEnabled(serverName: string, isEnabled: boolean): void { const tools = this.tools.filter( (tool) => tool.serverName === serverName, ); if (tools.length === 0) { return; } tools.forEach((tool) => { tool.isEnabled = isEnabled; }); } }