jorel
Version:
The easiest way to use LLMs, including streams, images, documents, tools and various agent scenarios.
245 lines (244 loc) • 9.61 kB
JavaScript
"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;