UNPKG

jorel

Version:

The easiest way to use LLMs, including streams, images, documents, tools and various agent scenarios.

245 lines (244 loc) 9.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LlmAgent = exports.AgentError = void 0; const utils_1 = require("./utils"); const index_1 = require("../index"); /** * Agent-specific error */ class AgentError extends Error { constructor(message, agentName) { super(`Agent ${agentName}: ${message}`); this.agentName = agentName; } } exports.AgentError = AgentError; /** * Represents an agent that can process requests, consider documents, * delegate to other agents, and use tools. */ class LlmAgent { /** * Creates a new LLM Agent * @param agentDefinition - The configuration for this agent * @param jorEl - The agent manager instance * @throws {AgentError} If the agent configuration is invalid */ constructor(agentDefinition, jorEl) { if (!agentDefinition) throw new Error("Agent definition is required"); if (!jorEl) throw new Error("JorElAgentManager instance is required"); this.name = (0, utils_1.validateAgentName)(agentDefinition.name); this.description = agentDefinition.description; this.model = agentDefinition.model ?? null; this.systemMessageTemplate = (0, utils_1.validateAgentCoreMessageTemplate)(agentDefinition.systemMessageTemplate); this.documents = agentDefinition.documents instanceof index_1.LlmDocumentCollection ? agentDefinition.documents : new index_1.LlmDocumentCollection(agentDefinition.documents); this._allowedTools = agentDefinition.allowedTools ? new Set(agentDefinition.allowedTools) : new Set(); this._allowedDelegateAgentNames = agentDefinition.canDelegateTo ? new Set(agentDefinition.canDelegateTo) : new Set(); this._allowedTransferAgentsNames = agentDefinition.canTransferTo ? new Set(agentDefinition.canTransferTo) : new Set(); this.delegateTemplate = agentDefinition.delegateTemplate ? (0, utils_1.validateAgentDelegateTemplate)(agentDefinition.delegateTemplate) : `<Agent name="{{name}}">{{description}}</Agent>`; this.responseType = agentDefinition.responseType ?? "text"; this.temperature = agentDefinition.temperature ?? 0; this.jorEl = jorEl; } /** * Get the list of tools that this agent can use */ get allowedToolNames() { return Array.from(this._allowedTools); } /** * Get the list of agent names that this agent can delegate to */ get allowedDelegateNames() { return Array.from(this._allowedDelegateAgentNames); } /** * Get the list of agent names that this agent can transfer to */ get allowedTransferAgentNames() { return Array.from(this._allowedTransferAgentsNames); } /** * Get the list of tools that this agent can use */ get availableTools() { return this.allowedToolNames.map((toolName) => { const tool = this.jorEl.tools.getTool(toolName); if (!tool) { throw new AgentError(`Tool with name ${toolName} does not exist`, this.name); } return tool; }); } /** * Get the list of delegates that this agent can delegate to */ get availableDelegateAgents() { return this.allowedDelegateNames.map((agentName) => { const delegate = this.jorEl.getAgent(agentName); if (!delegate) { throw new AgentError(`Delegate agent with name ${agentName} does not exist`, this.name); } return delegate; }); } /** * Get the list of transfer agents that this agent can transfer to */ get availableTransferAgents() { return this.allowedTransferAgentNames.map((agentName) => { const transferAgent = this.jorEl.getAgent(agentName); if (!transferAgent) { throw new AgentError(`Transfer agent with name ${agentName} does not exist`, this.name); } return transferAgent; }); } /** * Get the agent definition */ get definition() { return { name: this.name, description: this.description, model: this.model ?? undefined, systemMessageTemplate: this.systemMessageTemplate, delegateTemplate: this.delegateTemplate, allowedTools: this._allowedTools.size > 0 ? Array.from(this._allowedTools) : undefined, canDelegateTo: this._allowedDelegateAgentNames.size > 0 ? Array.from(this._allowedDelegateAgentNames) : undefined, canTransferTo: this._allowedTransferAgentsNames.size > 0 ? Array.from(this._allowedTransferAgentsNames) : undefined, }; } /** * Get the system message for this agent with the delegates and documents filled in */ get systemMessage() { return this.systemMessageTemplate .replace("{{delegates}}", this.availableDelegateAgents.map((agent) => agent.systemMessageRepresentation).join("\n")) .replace("{{documents}}", this.documents.systemMessageRepresentation); } /** * Representation of this agent to be used in other agents' system messages */ get systemMessageRepresentation() { return this.delegateTemplate.replace("{{name}}", this.name).replace("{{description}}", this.description); } /** * Get a delegate agent by name * @param agentName * @param type */ getDelegate(agentName, type = "delegate") { this.validateDelegation(agentName, type); const agent = this.jorEl.getAgent(agentName); if (!agent) { throw new AgentError(`Unable to find ${type} agent with name ${agentName}`, this.name); } return agent; } /** * Add an agent that this agent can delegate to * @param agent * @param type */ addDelegate(agent, type = "delegate") { const agentName = typeof agent === "string" ? agent : agent.name; if (this.name === agentName) throw new Error("An agent cannot delegate to itself"); let registeredAgent = this.jorEl.getAgent(agentName); if (!registeredAgent) { if (typeof agent === "string") { throw new AgentError(`Unable to add delegate. Agent with name ${agentName} does not exist`, this.name); } registeredAgent = this.jorEl.addAgent(agent); } if (type === "delegate") { if (registeredAgent.allowedDelegateNames.includes(this.name)) { // Currently only checks for direct circular delegation throw new Error(`Circular delegation detected between ${this.name} and ${registeredAgent.name}`); } if (!this._allowedDelegateAgentNames.has(agentName)) { this._allowedDelegateAgentNames.add(agentName); } } if (type === "transfer") { if (!this._allowedTransferAgentsNames.has(agentName)) { this._allowedTransferAgentsNames.add(agentName); } } return registeredAgent; } /** * Remove an agent from the list of agents that this agent can delegate to * @param agent */ removeDelegate(agent) { const agentName = typeof agent === "string" ? agent : agent.name; if (this._allowedDelegateAgentNames.has(agentName)) { this._allowedDelegateAgentNames.delete(agentName); } } /** * Add a tool that this agent can use. If the tool does not exist, it will be registered * @param tool */ addToolAccess(tool) { const toolName = typeof tool === "string" ? tool : tool.name; if (!this.jorEl.tools.getTool(toolName)) { if (typeof tool === "string") { throw new AgentError(`Unable to add tool. Tool with name ${toolName} does not exist`, this.name); } this.jorEl.tools.registerTool(tool); } if (!this._allowedTools.has(toolName)) { this._allowedTools.add(toolName); } } /** * Remove a tool from the list of tools that this agent can use * @param tool */ removeToolAccess(tool) { const toolName = typeof tool === "string" ? tool : tool.name; if (this._allowedTools.has(toolName)) { this._allowedTools.delete(toolName); } } /** * Set this agent as the default agent for the team */ setAsDefault() { this.jorEl.defaultAgentId = this.name; } /** * Validate that the agent can delegate to the target agent * @param targetAgentName * @param type * @throws {AgentError} If the target agent name is empty, the agent is trying to delegate to itself, or the agent is not allowed to delegate to the target agent * @internal */ validateDelegation(targetAgentName, type) { if (!targetAgentName) { throw new AgentError("target agent name cannot be empty", this.name); } if (targetAgentName === this.name) { throw new AgentError(`cannot ${type} to itself`, this.name); } const allowed = type === "delegate" ? this._allowedDelegateAgentNames : this._allowedTransferAgentsNames; if (!allowed.has(targetAgentName)) { throw new AgentError(`not allowed to ${type} to ${targetAgentName}`, this.name); } } } exports.LlmAgent = LlmAgent;