From 0ab7a52dd2e282c12c84424c15b7dd4ccc654e9b Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 25 Jul 2024 17:51:10 +0200 Subject: [PATCH] seperated definitions into respective classes --- src/agents/agent.ts | 42 +++++ src/classifiers/anthropicClassifier.ts | 20 ++- src/classifiers/bedrockClassifier.ts | 18 ++- src/classifiers/classifier.ts | 10 +- src/orchestrator.ts | 180 ++++++++++++++++++++- src/types/index.ts | 216 ++----------------------- src/utils/logger.ts | 5 +- 7 files changed, 269 insertions(+), 222 deletions(-) diff --git a/src/agents/agent.ts b/src/agents/agent.ts index 04769546..145b0765 100644 --- a/src/agents/agent.ts +++ b/src/agents/agent.ts @@ -1,9 +1,51 @@ import { ConversationMessage } from "../types"; +import { AccumulatorTransform } from "../utils/helpers"; + +export interface AgentProcessingResult { + // The original input provided by the user + userInput: string; + + // Unique identifier for the agent that processed the request + agentId: string; + + // Human-readable name of the agent + agentName: string; + + // Unique identifier for the user who initiated the request + userId: string; + + // Unique identifier for the current session + sessionId: string; + + // Additional parameters or metadata related to the processing result + // Can store any key-value pairs of varying types + additionalParams: Record; +} + +/** + * Represents the response from an agent, including metadata and output. + * @property metadata - Contains all properties of AgentProcessingResult except 'response'. + * @property output - The actual content of the agent's response, either as a transform or a string. + * @property streaming - Indicates whether the response is being streamed or not. + */ +export type AgentResponse = { + metadata: Omit; + output: AccumulatorTransform | string; + streaming: boolean; +}; export interface AgentOptions { + // The name of the agent name: string; + + // A description of the agent's purpose or capabilities description: string; + + // Optional: The ID of the model used by this agent + // If not provided, a default model may be used modelId?: string; + + // Optional: The geographic region where the agent should be deployed or run region?: string; } diff --git a/src/classifiers/anthropicClassifier.ts b/src/classifiers/anthropicClassifier.ts index 69448720..d07bed66 100644 --- a/src/classifiers/anthropicClassifier.ts +++ b/src/classifiers/anthropicClassifier.ts @@ -1,22 +1,36 @@ import { - ANTHROPIC_MODEL_ID_CLAUDE_3_5_SONNET, - ClassifierResult, + ANTHROPIC_MODEL_ID_CLAUDE_3_5_SONNET, ConversationMessage, ParticipantRole, } from "../types"; import { isToolInput } from "../utils/helpers"; import { Logger } from "../utils/logger"; -import { Classifier } from "./classifier"; +import { Classifier, ClassifierResult } from "./classifier"; import { Anthropic } from "@anthropic-ai/sdk"; export interface AnthropicClassifierOptions { + // Optional: The ID of the Anthropic model to use for classification + // If not provided, a default model may be used modelId?: string; + + // Optional: Configuration for the inference process inferenceConfig?: { + // Maximum number of tokens to generate in the response maxTokens?: number; + + // Controls randomness in output generation + // Higher values (e.g., 0.8) make output more random, lower values (e.g., 0.2) make it more deterministic temperature?: number; + + // Controls diversity of output via nucleus sampling + // 1.0 considers all tokens, lower values (e.g., 0.9) consider only the most probable tokens topP?: number; + + // Array of sequences that will stop the model from generating further tokens when encountered stopSequences?: string[]; }; + + // The API key for authenticating with Anthropic's services apiKey: string; } diff --git a/src/classifiers/bedrockClassifier.ts b/src/classifiers/bedrockClassifier.ts index 096f8dae..1fb233b2 100644 --- a/src/classifiers/bedrockClassifier.ts +++ b/src/classifiers/bedrockClassifier.ts @@ -1,6 +1,5 @@ import { BEDROCK_MODEL_ID_CLAUDE_3_5_SONNET, - ClassifierResult, ConversationMessage, ParticipantRole, } from "../types"; @@ -10,18 +9,33 @@ import { ConverseCommand, } from "@aws-sdk/client-bedrock-runtime"; -import { Classifier } from "./classifier"; +import { Classifier, ClassifierResult } from "./classifier"; import { isToolInput } from "../utils/helpers"; import { Logger } from "../utils/logger"; export interface BedrockClassifierOptions { + // Optional: The ID of the Bedrock model to use for classification + // If not provided, a default model may be used modelId?: string; + + // Optional: The AWS region where the Bedrock model is used region?: string; + + // Optional: Configuration for the inference process inferenceConfig?: { + // Maximum number of tokens to generate in the response maxTokens?: number; + + // Controls randomness in output generation + // Higher values (e.g., 0.8) make output more random, lower values (e.g., 0.2) make it more deterministic temperature?: number; + + // Controls diversity of output via nucleus sampling + // 1.0 considers all tokens, lower values (e.g., 0.9) consider only the most probable tokens topP?: number; + + // Array of sequences that will stop the model from generating further tokens when encountered stopSequences?: string[]; }; } diff --git a/src/classifiers/classifier.ts b/src/classifiers/classifier.ts index 0d623e32..f017696a 100644 --- a/src/classifiers/classifier.ts +++ b/src/classifiers/classifier.ts @@ -1,6 +1,5 @@ import { AgentTypes, - ClassifierResult, ConversationMessage, TemplateVariables, } from "../types"; @@ -10,6 +9,15 @@ import { import { Agent } from "../agents/agent"; +export interface ClassifierResult { + // The agent selected by the classifier to handle the user's request + selectedAgent: Agent | null; + + // A numeric value representing the classifier's confidence in its selection + // Typically a value between 0 and 1, where 1 represents 100% confidence + confidence: number; +} + /** * IntentClassifier class extends BedrockAgent to provide specialized functionality * for classifying user intents, selecting appropriate agents, and generating diff --git a/src/orchestrator.ts b/src/orchestrator.ts index 24ff8542..ef5fe3b3 100644 --- a/src/orchestrator.ts +++ b/src/orchestrator.ts @@ -1,15 +1,9 @@ import { AgentOverlapAnalyzer } from "./agentOverlapAnalyzer"; import { - OrchestratorConfig, - DEFAULT_CONFIG, - ClassifierResult, - DispatchToAgentsParams, - OrchestratorOptions, - AgentResponse, AgentTypes, - RequestMetadata, } from "./types/index"; -import { Agent } from "./agents/agent"; +import { Agent, AgentResponse } from "./agents/agent"; +import { ClassifierResult } from './classifiers/classifier'; import { BedrockLLMAgent } from "./agents/bedrockLLMAgent"; import { ChatStorage } from "./storage/chatStorage"; import { InMemoryChatStorage } from "./storage/memoryChatStorage"; @@ -19,6 +13,176 @@ import { Logger } from "./utils/logger"; import { BedrockClassifier } from "./classifiers/bedrockClassifier"; import { Classifier } from "./classifiers/classifier"; +export interface OrchestratorConfig { + /** If true, logs the chat interactions with the agent */ + LOG_AGENT_CHAT?: boolean; + + /** If true, logs the chat interactions with the classifier */ + LOG_CLASSIFIER_CHAT?: boolean; + + /** If true, logs the raw, unprocessed output from the classifier */ + LOG_CLASSIFIER_RAW_OUTPUT?: boolean; + + /** If true, logs the processed output from the classifier */ + LOG_CLASSIFIER_OUTPUT?: boolean; + + /** If true, logs the execution times of various operations */ + LOG_EXECUTION_TIMES?: boolean; + + /** The maximum number of retry attempts for the classifier if it receives a bad XML response */ + MAX_RETRIES?: number; + + /** + * If true, uses the default agent when no agent is identified during intent classification. + * + * When set to true: + * - If no agent is identified, the system will fall back to using a predefined default agent. + * - This ensures that user requests are still processed, even if a specific agent cannot be determined. + * + * When set to false: + * - If no agent is identified, the system will return an error message to the user. + * - This prompts the user to rephrase their request for better agent identification. + * + * Use this option to balance between always providing a response (potentially less accurate) + * and ensuring high confidence in agent selection before proceeding. + */ + USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED?: boolean; + + /** + * The error message to display when a classification error occurs. + * + * This message is shown to the user when there's an internal error during the intent classification process, + * separate from cases where no agent is identified. + */ + CLASSIFICATION_ERROR_MESSAGE?: string; + + /** + * The message to display when no agent is selected to handle the user's request. + * + * This message is shown when the classifier couldn't determine an appropriate agent + * and USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED is set to false. + */ + NO_SELECTED_AGENT_MESSAGE?: string; + + /** + * The general error message to display when an error occurs during request routing. + * + * This message is shown when an unexpected error occurs during the processing of a user's request, + * such as errors in agent dispatch or processing. + */ + GENERAL_ROUTING_ERROR_MSG_MESSAGE?: string; + + /** + * Maximum number of message pairs (user-assistant interactions) to retain per agent. + * + * This constant defines the upper limit for the conversation history stored for each agent. + * Each pair consists of a user message and its corresponding assistant response. + * + * Usage: + * - When saving messages: pass (MAX_MESSAGE_PAIRS_PER_AGENT * 2) as maxHistorySize + * - When fetching chats: pass (MAX_MESSAGE_PAIRS_PER_AGENT * 2) as maxHistorySize + * + * Note: The actual number of messages stored will be twice this value, + * as each pair consists of two messages (user and assistant). + * + * Example: + * If MAX_MESSAGE_PAIRS_PER_AGENT is 5, up to 10 messages (5 pairs) will be stored per agent. + */ + MAX_MESSAGE_PAIRS_PER_AGENT?: number; +} + +export const DEFAULT_CONFIG: OrchestratorConfig = { + /** Default: Do not log agent chat interactions */ + LOG_AGENT_CHAT: false, + + /** Default: Do not log classifier chat interactions */ + LOG_CLASSIFIER_CHAT: false, + + /** Default: Do not log raw classifier output */ + LOG_CLASSIFIER_RAW_OUTPUT: false, + + /** Default: Do not log processed classifier output */ + LOG_CLASSIFIER_OUTPUT: false, + + /** Default: Do not log execution times */ + LOG_EXECUTION_TIMES: false, + + /** Default: Retry classifier up to 3 times on bad XML response */ + MAX_RETRIES: 3, + + /** Default: Use the default agent when no agent is identified during intent classification */ + USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED: true, + + /** Default error message for classification errors */ + CLASSIFICATION_ERROR_MESSAGE: "I'm sorry, an error occurred while processing your request. Please try again later.", + + /** Default message when no agent is selected to handle the request */ + NO_SELECTED_AGENT_MESSAGE: "I'm sorry, I couldn't determine how to handle your request. Could you please rephrase it?", + + /** Default general error message for routing errors */ + GENERAL_ROUTING_ERROR_MSG_MESSAGE: "An error occurred while processing your request. Please try again later.", + + /** Default: Maximum of 100 message pairs (200 individual messages) to retain per agent */ + MAX_MESSAGE_PAIRS_PER_AGENT: 100, +}; + +export interface DispatchToAgentsParams { + // The original input provided by the user + userInput: string; + + // Unique identifier for the user who initiated the request + userId: string; + + // Unique identifier for the current session + sessionId: string; + + // The result from a classifier, determining which agent to use + classifierResult: ClassifierResult; + + // Optional: Additional parameters or metadata to be passed to the agents + // Can store any key-value pairs of varying types + additionalParams?: Record; +} + +/** + * Configuration options for the Orchestrator. + * @property storage - Optional ChatStorage instance for persisting conversations. + * @property config - Optional partial configuration for the Orchestrator. + * @property logger - Optional logging mechanism. + */ +export interface OrchestratorOptions { + storage?: ChatStorage; + config?: Partial; + logger?: any; + classifier?: Classifier; +} + +export interface RequestMetadata { + // The original input provided by the user + userInput: string; + + // Unique identifier for the agent that processed the request + agentId: string; + + // Human-readable name of the agent + agentName: string; + + // Unique identifier for the user who initiated the request + userId: string; + + // Unique identifier for the current session + sessionId: string; + + // Additional parameters or metadata related to the request + // Stores string key-value pairs + additionalParams: Record; + + // Optional: Indicates if classification failed during processing + // Only present if an error occurred during classification + errorType?: 'classification_failed'; +} + + export class MultiAgentOrchestrator { private config: OrchestratorConfig; private storage: ChatStorage; diff --git a/src/types/index.ts b/src/types/index.ts index 2241260d..9dba7d1c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,14 +1,8 @@ -import { Agent } from "../agents/agent"; -import { Classifier } from "../classifiers/classifier"; -import { ChatStorage } from "../storage/chatStorage"; -import { AccumulatorTransform } from "../utils/helpers"; - export const BEDROCK_MODEL_ID_CLAUDE_3_HAIKU = "anthropic.claude-3-haiku-20240307-v1:0"; export const BEDROCK_MODEL_ID_CLAUDE_3_SONNET = "anthropic.claude-3-sonnet-20240229-v1:0"; export const BEDROCK_MODEL_ID_CLAUDE_3_5_SONNET = "anthropic.claude-3-5-sonnet-20240620-v1:0"; export const BEDROCK_MODEL_ID_LLAMA_3_70B = "meta.llama3-70b-instruct-v1:0"; export const OPENAI_MODEL_ID_GPT_O_MINI = "gpt-4o-mini"; - export const ANTHROPIC_MODEL_ID_CLAUDE_3_5_SONNET = "claude-3-5-sonnet-20240620"; export const AgentTypes = { @@ -18,170 +12,12 @@ export const AgentTypes = { export type AgentTypes = typeof AgentTypes[keyof typeof AgentTypes]; -export interface ClassifierResult { - selectedAgent: Agent | null; - confidence: number; -} - - export interface ToolInput { userinput: string; selected_agent: string; confidence: string; } -export interface AgentProcessingResult { - userInput: string; - agentId: string; - agentName: string; - userId: string; - sessionId: string; - additionalParams: Record; -} - -export interface DispatchInput { - classifierResult: ClassifierResult; - userId: string; - sessionId: string; -} - -export interface DispatchToAgentsParams { - userInput: string; - userId: string; - sessionId: string; - classifierResult: ClassifierResult; - additionalParams?: Record; -} - -export interface FinalResult { - language: string; - languageConfidence: number; - extractedData: string[]; - selectionTime: number; - totalDuration: number; - intents: Array<{ - intent: string; - agent: string | null; - response: string; - topicContinuity: boolean; - confidence: number; - duration: number; - }>; -} - -export interface OrchestratorConfig { - /** If true, logs the chat interactions with the agent */ - LOG_AGENT_CHAT?: boolean; - - /** If true, logs the chat interactions with the classifier */ - LOG_CLASSIFIER_CHAT?: boolean; - - /** If true, logs the raw, unprocessed output from the classifier */ - LOG_CLASSIFIER_RAW_OUTPUT?: boolean; - - /** If true, logs the processed output from the classifier */ - LOG_CLASSIFIER_OUTPUT?: boolean; - - /** If true, logs the execution times of various operations */ - LOG_EXECUTION_TIMES?: boolean; - - /** The maximum number of retry attempts for the classifier if it receives a bad XML response */ - MAX_RETRIES?: number; - - /** - * If true, uses the default agent when no agent is identified during intent classification. - * - * When set to true: - * - If no agent is identified, the system will fall back to using a predefined default agent. - * - This ensures that user requests are still processed, even if a specific agent cannot be determined. - * - * When set to false: - * - If no agent is identified, the system will return an error message to the user. - * - This prompts the user to rephrase their request for better agent identification. - * - * Use this option to balance between always providing a response (potentially less accurate) - * and ensuring high confidence in agent selection before proceeding. - */ - USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED?: boolean; - - /** - * The error message to display when a classification error occurs. - * - * This message is shown to the user when there's an internal error during the intent classification process, - * separate from cases where no agent is identified. - */ - CLASSIFICATION_ERROR_MESSAGE?: string; - - /** - * The message to display when no agent is selected to handle the user's request. - * - * This message is shown when the classifier couldn't determine an appropriate agent - * and USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED is set to false. - */ - NO_SELECTED_AGENT_MESSAGE?: string; - - /** - * The general error message to display when an error occurs during request routing. - * - * This message is shown when an unexpected error occurs during the processing of a user's request, - * such as errors in agent dispatch or processing. - */ - GENERAL_ROUTING_ERROR_MSG_MESSAGE?: string; - - /** - * Maximum number of message pairs (user-assistant interactions) to retain per agent. - * - * This constant defines the upper limit for the conversation history stored for each agent. - * Each pair consists of a user message and its corresponding assistant response. - * - * Usage: - * - When saving messages: pass (MAX_MESSAGE_PAIRS_PER_AGENT * 2) as maxHistorySize - * - When fetching chats: pass (MAX_MESSAGE_PAIRS_PER_AGENT * 2) as maxHistorySize - * - * Note: The actual number of messages stored will be twice this value, - * as each pair consists of two messages (user and assistant). - * - * Example: - * If MAX_MESSAGE_PAIRS_PER_AGENT is 5, up to 10 messages (5 pairs) will be stored per agent. - */ - MAX_MESSAGE_PAIRS_PER_AGENT?: number; -} - -export const DEFAULT_CONFIG: OrchestratorConfig = { - /** Default: Do not log agent chat interactions */ - LOG_AGENT_CHAT: false, - - /** Default: Do not log classifier chat interactions */ - LOG_CLASSIFIER_CHAT: false, - - /** Default: Do not log raw classifier output */ - LOG_CLASSIFIER_RAW_OUTPUT: false, - - /** Default: Do not log processed classifier output */ - LOG_CLASSIFIER_OUTPUT: false, - - /** Default: Do not log execution times */ - LOG_EXECUTION_TIMES: false, - - /** Default: Retry classifier up to 3 times on bad XML response */ - MAX_RETRIES: 3, - - /** Default: Use the default agent when no agent is identified during intent classification */ - USE_DEFAULT_AGENT_IF_NONE_IDENTIFIED: true, - - /** Default error message for classification errors */ - CLASSIFICATION_ERROR_MESSAGE: "I'm sorry, an error occurred while processing your request. Please try again later.", - - /** Default message when no agent is selected to handle the request */ - NO_SELECTED_AGENT_MESSAGE: "I'm sorry, I couldn't determine how to handle your request. Could you please rephrase it?", - - /** Default general error message for routing errors */ - GENERAL_ROUTING_ERROR_MSG_MESSAGE: "An error occurred while processing your request. Please try again later.", - - /** Default: Maximum of 100 message pairs (200 individual messages) to retain per agent */ - MAX_MESSAGE_PAIRS_PER_AGENT: 100, -}; - /** * Represents a streaming response that can be asynchronously iterated over. * This type is useful for handling responses that come in chunks or streams. @@ -190,40 +26,6 @@ export type StreamingResponse = { [Symbol.asyncIterator]: () => AsyncIterator; }; -/** - * Represents the response from an agent, including metadata and output. - * @property metadata - Contains all properties of AgentProcessingResult except 'response'. - * @property output - The actual content of the agent's response, either as a transform or a string. - * @property streaming - Indicates whether the response is being streamed or not. - */ -export type AgentResponse = { - metadata: Omit; - output: AccumulatorTransform | string; - streaming: boolean; -}; - -/** - * Configuration options for the Orchestrator. - * @property storage - Optional ChatStorage instance for persisting conversations. - * @property config - Optional partial configuration for the Orchestrator. - * @property logger - Optional logging mechanism. - */ -export interface OrchestratorOptions { - storage?: ChatStorage; - config?: Partial; - logger?: any; - classifier?: Classifier; -} - -/** - * Extends the Message type with a timestamp. - * This is useful for tracking when messages were created or modified. - */ -export type TimestampedMessage = ConversationMessage & { timestamp: number }; - -export interface TemplateVariables { - [key: string]: string | string[]; -} /** * Represents the possible roles in a conversation. @@ -241,12 +43,12 @@ export interface ConversationMessage { content: any[] | undefined; } -export interface RequestMetadata { - userInput: string; - agentId: string; - agentName: string; - userId: string; - sessionId: string; - additionalParams: Record; - errorType?: 'classification_failed'; -} \ No newline at end of file +/** + * Extends the Message type with a timestamp. + * This is useful for tracking when messages were created or modified. + */ +export type TimestampedMessage = ConversationMessage & { timestamp: number }; + +export interface TemplateVariables { + [key: string]: string | string[]; +} diff --git a/src/utils/logger.ts b/src/utils/logger.ts index e16f4d0f..bccf35bd 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,4 +1,7 @@ -import { ClassifierResult, ConversationMessage, OrchestratorConfig } from "../types"; +import { ConversationMessage } from "../types"; +import { OrchestratorConfig } from "../orchestrator"; +import { ClassifierResult } from "../classifiers/classifier"; + export class Logger {