@langchain/classic 1.0.34 → 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/agents/chat/index.cjs.map +1 -1
- package/dist/agents/chat/index.js.map +1 -1
- package/dist/agents/chat/outputParser.cjs.map +1 -1
- package/dist/agents/chat/outputParser.d.cts +2 -2
- package/dist/agents/chat/outputParser.js.map +1 -1
- package/dist/agents/chat_convo/index.cjs.map +1 -1
- package/dist/agents/chat_convo/index.js.map +1 -1
- package/dist/agents/chat_convo/outputParser.cjs.map +1 -1
- package/dist/agents/chat_convo/outputParser.js.map +1 -1
- package/dist/agents/executor.cjs.map +1 -1
- package/dist/agents/executor.js.map +1 -1
- package/dist/agents/format_scratchpad/log.cjs.map +1 -1
- package/dist/agents/format_scratchpad/log.js.map +1 -1
- package/dist/agents/format_scratchpad/log_to_message.cjs.map +1 -1
- package/dist/agents/format_scratchpad/log_to_message.js.map +1 -1
- package/dist/agents/initialize.cjs.map +1 -1
- package/dist/agents/initialize.js.map +1 -1
- package/dist/agents/mrkl/index.cjs.map +1 -1
- package/dist/agents/mrkl/index.js.map +1 -1
- package/dist/agents/mrkl/outputParser.cjs.map +1 -1
- package/dist/agents/mrkl/outputParser.d.cts +1 -1
- package/dist/agents/mrkl/outputParser.js.map +1 -1
- package/dist/agents/openai_functions/index.cjs.map +1 -1
- package/dist/agents/openai_functions/index.js.map +1 -1
- package/dist/agents/openai_tools/index.cjs.map +1 -1
- package/dist/agents/openai_tools/index.js.map +1 -1
- package/dist/agents/react/index.cjs.map +1 -1
- package/dist/agents/react/index.js.map +1 -1
- package/dist/agents/react/output_parser.cjs.map +1 -1
- package/dist/agents/react/output_parser.js.map +1 -1
- package/dist/agents/structured_chat/index.cjs.map +1 -1
- package/dist/agents/structured_chat/index.js.map +1 -1
- package/dist/agents/structured_chat/outputParser.cjs.map +1 -1
- package/dist/agents/structured_chat/outputParser.js.map +1 -1
- package/dist/agents/tool_calling/index.cjs.map +1 -1
- package/dist/agents/tool_calling/index.js.map +1 -1
- package/dist/agents/toolkits/conversational_retrieval/openai_functions.cjs.map +1 -1
- package/dist/agents/toolkits/conversational_retrieval/openai_functions.js.map +1 -1
- package/dist/agents/toolkits/conversational_retrieval/tool.cjs.map +1 -1
- package/dist/agents/toolkits/conversational_retrieval/tool.js.map +1 -1
- package/dist/agents/toolkits/json/json.cjs.map +1 -1
- package/dist/agents/toolkits/json/json.js.map +1 -1
- package/dist/agents/toolkits/openapi/openapi.cjs.map +1 -1
- package/dist/agents/toolkits/openapi/openapi.js.map +1 -1
- package/dist/agents/toolkits/sql/sql.cjs.map +1 -1
- package/dist/agents/toolkits/sql/sql.js.map +1 -1
- package/dist/agents/toolkits/vectorstore/vectorstore.cjs.map +1 -1
- package/dist/agents/toolkits/vectorstore/vectorstore.js.map +1 -1
- package/dist/agents/xml/index.cjs.map +1 -1
- package/dist/agents/xml/index.js.map +1 -1
- package/dist/chains/analyze_documents_chain.cjs.map +1 -1
- package/dist/chains/analyze_documents_chain.js.map +1 -1
- package/dist/chains/api/api_chain.cjs.map +1 -1
- package/dist/chains/api/api_chain.js.map +1 -1
- package/dist/chains/api/prompts.js.map +1 -1
- package/dist/chains/base.cjs.map +1 -1
- package/dist/chains/base.js.map +1 -1
- package/dist/chains/chat_vector_db_chain.cjs.map +1 -1
- package/dist/chains/chat_vector_db_chain.js.map +1 -1
- package/dist/chains/combine_docs_chain.cjs.map +1 -1
- package/dist/chains/combine_docs_chain.js.map +1 -1
- package/dist/chains/combine_documents/base.cjs.map +1 -1
- package/dist/chains/combine_documents/base.js.map +1 -1
- package/dist/chains/combine_documents/reduce.cjs.map +1 -1
- package/dist/chains/combine_documents/reduce.js.map +1 -1
- package/dist/chains/constitutional_ai/constitutional_prompts.cjs.map +1 -1
- package/dist/chains/constitutional_ai/constitutional_prompts.js.map +1 -1
- package/dist/chains/conversational_retrieval_chain.cjs.map +1 -1
- package/dist/chains/conversational_retrieval_chain.js.map +1 -1
- package/dist/chains/graph_qa/cypher.cjs.map +1 -1
- package/dist/chains/graph_qa/cypher.js.map +1 -1
- package/dist/chains/graph_qa/prompts.cjs.map +1 -1
- package/dist/chains/graph_qa/prompts.js.map +1 -1
- package/dist/chains/history_aware_retriever.cjs.map +1 -1
- package/dist/chains/history_aware_retriever.js.map +1 -1
- package/dist/chains/llm_chain.cjs.map +1 -1
- package/dist/chains/llm_chain.js.map +1 -1
- package/dist/chains/openai_functions/base.cjs.map +1 -1
- package/dist/chains/openai_functions/base.js.map +1 -1
- package/dist/chains/openai_functions/openapi.cjs.map +1 -1
- package/dist/chains/openai_functions/openapi.js.map +1 -1
- package/dist/chains/query_constructor/index.cjs.map +1 -1
- package/dist/chains/query_constructor/index.js.map +1 -1
- package/dist/chains/query_constructor/parser.cjs.map +1 -1
- package/dist/chains/query_constructor/parser.js.map +1 -1
- package/dist/chains/query_constructor/prompt.cjs.map +1 -1
- package/dist/chains/query_constructor/prompt.js.map +1 -1
- package/dist/chains/question_answering/load.cjs.map +1 -1
- package/dist/chains/question_answering/load.js.map +1 -1
- package/dist/chains/question_answering/map_reduce_prompts.cjs.map +1 -1
- package/dist/chains/question_answering/map_reduce_prompts.js.map +1 -1
- package/dist/chains/question_answering/refine_prompts.cjs.map +1 -1
- package/dist/chains/question_answering/refine_prompts.js.map +1 -1
- package/dist/chains/question_answering/stuff_prompts.cjs.map +1 -1
- package/dist/chains/question_answering/stuff_prompts.js.map +1 -1
- package/dist/chains/retrieval.cjs.map +1 -1
- package/dist/chains/retrieval.js.map +1 -1
- package/dist/chains/router/multi_prompt.cjs.map +1 -1
- package/dist/chains/router/multi_prompt.js.map +1 -1
- package/dist/chains/router/multi_retrieval_qa.cjs.map +1 -1
- package/dist/chains/router/multi_retrieval_qa.js.map +1 -1
- package/dist/chains/sql_db/sql_db_chain.cjs.map +1 -1
- package/dist/chains/sql_db/sql_db_chain.js.map +1 -1
- package/dist/chains/summarization/load.cjs.map +1 -1
- package/dist/chains/summarization/load.js.map +1 -1
- package/dist/chains/summarization/refine_prompts.cjs.map +1 -1
- package/dist/chains/summarization/refine_prompts.js.map +1 -1
- package/dist/chains/summarization/stuff_prompts.cjs.map +1 -1
- package/dist/chains/summarization/stuff_prompts.js.map +1 -1
- package/dist/chat_models/universal.cjs.map +1 -1
- package/dist/chat_models/universal.js.map +1 -1
- package/dist/document_loaders/fs/json.cjs.map +1 -1
- package/dist/document_loaders/fs/json.js.map +1 -1
- package/dist/document_loaders/fs/multi_file.cjs.map +1 -1
- package/dist/document_loaders/fs/multi_file.js.map +1 -1
- package/dist/document_transformers/openai_functions.cjs.map +1 -1
- package/dist/document_transformers/openai_functions.js.map +1 -1
- package/dist/evaluation/agents/prompt.cjs.map +1 -1
- package/dist/evaluation/agents/prompt.js.map +1 -1
- package/dist/evaluation/comparison/pairwise.cjs.map +1 -1
- package/dist/evaluation/comparison/pairwise.js.map +1 -1
- package/dist/evaluation/comparison/prompt.cjs.map +1 -1
- package/dist/evaluation/comparison/prompt.js.map +1 -1
- package/dist/evaluation/criteria/criteria.cjs.map +1 -1
- package/dist/evaluation/criteria/criteria.js.map +1 -1
- package/dist/evaluation/criteria/prompt.cjs.map +1 -1
- package/dist/evaluation/criteria/prompt.js.map +1 -1
- package/dist/evaluation/embedding_distance/base.cjs.map +1 -1
- package/dist/evaluation/embedding_distance/base.js.map +1 -1
- package/dist/evaluation/qa/eval_chain.cjs.map +1 -1
- package/dist/evaluation/qa/eval_chain.js.map +1 -1
- package/dist/evaluation/qa/prompt.cjs.map +1 -1
- package/dist/evaluation/qa/prompt.js.map +1 -1
- package/dist/experimental/autogpt/agent.cjs.map +1 -1
- package/dist/experimental/autogpt/agent.js.map +1 -1
- package/dist/experimental/autogpt/prompt.cjs.map +1 -1
- package/dist/experimental/autogpt/prompt.js.map +1 -1
- package/dist/experimental/autogpt/prompt_generator.cjs.map +1 -1
- package/dist/experimental/autogpt/prompt_generator.js.map +1 -1
- package/dist/experimental/babyagi/agent.cjs.map +1 -1
- package/dist/experimental/babyagi/agent.js.map +1 -1
- package/dist/experimental/babyagi/task_creation.cjs.map +1 -1
- package/dist/experimental/babyagi/task_creation.js.map +1 -1
- package/dist/experimental/babyagi/task_execution.cjs.map +1 -1
- package/dist/experimental/babyagi/task_execution.js.map +1 -1
- package/dist/experimental/babyagi/task_prioritization.cjs.map +1 -1
- package/dist/experimental/babyagi/task_prioritization.js.map +1 -1
- package/dist/experimental/chains/violation_of_expectations/violation_of_expectations_chain.cjs.map +1 -1
- package/dist/experimental/chains/violation_of_expectations/violation_of_expectations_chain.js.map +1 -1
- package/dist/experimental/generative_agents/generative_agent.cjs.map +1 -1
- package/dist/experimental/generative_agents/generative_agent.js.map +1 -1
- package/dist/experimental/generative_agents/generative_agent_memory.cjs.map +1 -1
- package/dist/experimental/generative_agents/generative_agent_memory.js.map +1 -1
- package/dist/experimental/masking/regex_masking_transformer.cjs.map +1 -1
- package/dist/experimental/masking/regex_masking_transformer.js.map +1 -1
- package/dist/experimental/openai_assistant/index.cjs.map +1 -1
- package/dist/experimental/openai_assistant/index.js.map +1 -1
- package/dist/experimental/plan_and_execute/agent_executor.cjs.map +1 -1
- package/dist/experimental/plan_and_execute/agent_executor.js.map +1 -1
- package/dist/experimental/plan_and_execute/base.cjs.map +1 -1
- package/dist/experimental/plan_and_execute/base.js.map +1 -1
- package/dist/experimental/prompts/handlebars.cjs.map +1 -1
- package/dist/experimental/prompts/handlebars.js.map +1 -1
- package/dist/hub/base.cjs.map +1 -1
- package/dist/hub/base.js.map +1 -1
- package/dist/hub/index.cjs.map +1 -1
- package/dist/hub/index.js.map +1 -1
- package/dist/hub/node.cjs.map +1 -1
- package/dist/hub/node.js.map +1 -1
- package/dist/memory/buffer_memory.cjs.map +1 -1
- package/dist/memory/buffer_memory.js.map +1 -1
- package/dist/memory/buffer_token_memory.cjs.map +1 -1
- package/dist/memory/buffer_token_memory.js.map +1 -1
- package/dist/memory/buffer_window_memory.cjs.map +1 -1
- package/dist/memory/buffer_window_memory.js.map +1 -1
- package/dist/memory/entity_memory.cjs.map +1 -1
- package/dist/memory/entity_memory.js.map +1 -1
- package/dist/memory/prompt.cjs.map +1 -1
- package/dist/memory/prompt.js.map +1 -1
- package/dist/memory/summary.cjs.map +1 -1
- package/dist/memory/summary.js.map +1 -1
- package/dist/output_parsers/expression.cjs.map +1 -1
- package/dist/output_parsers/expression.js.map +1 -1
- package/dist/output_parsers/expression_type_handlers/base.cjs.map +1 -1
- package/dist/output_parsers/expression_type_handlers/base.js.map +1 -1
- package/dist/output_parsers/expression_type_handlers/factory.cjs.map +1 -1
- package/dist/output_parsers/expression_type_handlers/factory.js.map +1 -1
- package/dist/output_parsers/expression_type_handlers/identifier_handler.cjs.map +1 -1
- package/dist/output_parsers/expression_type_handlers/identifier_handler.js.map +1 -1
- package/dist/output_parsers/expression_type_handlers/property_assignment_handler.cjs.map +1 -1
- package/dist/output_parsers/expression_type_handlers/property_assignment_handler.js.map +1 -1
- package/dist/output_parsers/expression_type_handlers/string_literal_handler.cjs.map +1 -1
- package/dist/output_parsers/expression_type_handlers/string_literal_handler.js.map +1 -1
- package/dist/output_parsers/fix.cjs.map +1 -1
- package/dist/output_parsers/fix.js.map +1 -1
- package/dist/output_parsers/http_response.cjs.map +1 -1
- package/dist/output_parsers/http_response.js.map +1 -1
- package/dist/output_parsers/openai_functions.cjs.map +1 -1
- package/dist/output_parsers/openai_functions.js.map +1 -1
- package/dist/output_parsers/openai_tools.cjs.map +1 -1
- package/dist/output_parsers/openai_tools.js.map +1 -1
- package/dist/output_parsers/prompts.cjs.map +1 -1
- package/dist/output_parsers/prompts.js.map +1 -1
- package/dist/output_parsers/structured.cjs.map +1 -1
- package/dist/output_parsers/structured.js.map +1 -1
- package/dist/retrievers/contextual_compression.cjs.map +1 -1
- package/dist/retrievers/contextual_compression.js.map +1 -1
- package/dist/retrievers/document_compressors/chain_extract.cjs.map +1 -1
- package/dist/retrievers/document_compressors/chain_extract.js.map +1 -1
- package/dist/retrievers/ensemble.cjs.map +1 -1
- package/dist/retrievers/ensemble.js.map +1 -1
- package/dist/retrievers/hyde.cjs.map +1 -1
- package/dist/retrievers/hyde.js.map +1 -1
- package/dist/retrievers/multi_query.cjs.map +1 -1
- package/dist/retrievers/multi_query.js.map +1 -1
- package/dist/retrievers/multi_vector.cjs.map +1 -1
- package/dist/retrievers/multi_vector.js.map +1 -1
- package/dist/retrievers/parent_document.cjs.map +1 -1
- package/dist/retrievers/parent_document.js.map +1 -1
- package/dist/retrievers/score_threshold.cjs.map +1 -1
- package/dist/retrievers/score_threshold.js.map +1 -1
- package/dist/smith/runner_utils.cjs.map +1 -1
- package/dist/smith/runner_utils.js.map +1 -1
- package/dist/storage/encoder_backed.cjs.map +1 -1
- package/dist/storage/encoder_backed.js.map +1 -1
- package/dist/storage/file_system.cjs.map +1 -1
- package/dist/storage/file_system.js.map +1 -1
- package/dist/tools/json.cjs.map +1 -1
- package/dist/tools/json.js.map +1 -1
- package/dist/tools/requests.cjs.map +1 -1
- package/dist/tools/requests.js.map +1 -1
- package/dist/tools/retriever.cjs.map +1 -1
- package/dist/tools/retriever.js.map +1 -1
- package/dist/tools/sql.cjs.map +1 -1
- package/dist/tools/sql.js.map +1 -1
- package/dist/tools/webbrowser.cjs.map +1 -1
- package/dist/tools/webbrowser.js.map +1 -1
- package/dist/util/hub.cjs.map +1 -1
- package/dist/util/hub.js.map +1 -1
- package/dist/util/load.cjs.map +1 -1
- package/dist/util/load.js.map +1 -1
- package/dist/util/openapi.cjs.map +1 -1
- package/dist/util/openapi.js.map +1 -1
- package/dist/util/sql_utils.cjs.map +1 -1
- package/dist/util/sql_utils.js.map +1 -1
- package/dist/vectorstores/memory.cjs.map +1 -1
- package/dist/vectorstores/memory.js.map +1 -1
- package/package.json +47 -48
package/dist/experimental/chains/violation_of_expectations/violation_of_expectations_chain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"violation_of_expectations_chain.js","names":[],"sources":["../../../../src/experimental/chains/violation_of_expectations/violation_of_expectations_chain.ts"],"sourcesContent":["import type { BaseRetrieverInterface } from \"@langchain/core/retrievers\";\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport {\n BaseMessage,\n HumanMessage,\n isBaseMessage,\n} from \"@langchain/core/messages\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { StringOutputParser } from \"@langchain/core/output_parsers\";\nimport { CallbackManagerForChainRun } from \"@langchain/core/callbacks/manager\";\nimport { JsonOutputFunctionsParser } from \"../../../output_parsers/openai_functions.js\";\nimport { BaseChain, ChainInputs } from \"../../../chains/base.js\";\nimport {\n GetPredictionViolationsResponse,\n MessageChunkResult,\n PREDICTION_VIOLATIONS_FUNCTION,\n PREDICT_NEXT_USER_MESSAGE_FUNCTION,\n PredictNextUserMessageResponse,\n} from \"./types.js\";\nimport {\n GENERATE_FACTS_PROMPT,\n GENERATE_REVISED_PREDICTION_PROMPT,\n PREDICTION_VIOLATIONS_PROMPT,\n PREDICT_NEXT_USER_MESSAGE_PROMPT,\n} from \"./violation_of_expectations_prompt.js\";\n\n/**\n * Interface for the input parameters of the ViolationOfExpectationsChain class.\n */\nexport interface ViolationOfExpectationsChainInput extends ChainInputs {\n /**\n * The retriever to use for retrieving stored\n * thoughts and insights.\n */\n retriever: BaseRetrieverInterface;\n /**\n * The LLM to use\n */\n llm: ChatOpenAI;\n}\n\n/**\n * Chain that generates key insights/facts of a user based on a\n * a chat conversation with an AI.\n */\nexport class ViolationOfExpectationsChain\n extends BaseChain\n implements ViolationOfExpectationsChainInput\n{\n static lc_name() {\n return \"ViolationOfExpectationsChain\";\n }\n\n _chainType(): string {\n return \"violation_of_expectation_chain\";\n }\n\n chatHistoryKey = \"chat_history\";\n\n thoughtsKey = \"thoughts\";\n\n get inputKeys() {\n return [this.chatHistoryKey];\n }\n\n get outputKeys() {\n return [this.thoughtsKey];\n }\n\n retriever: BaseRetrieverInterface;\n\n llm: ChatOpenAI;\n\n jsonOutputParser: JsonOutputFunctionsParser;\n\n stringOutputParser: StringOutputParser;\n\n constructor(fields: ViolationOfExpectationsChainInput) {\n super(fields);\n this.retriever = fields.retriever;\n this.llm = fields.llm;\n this.jsonOutputParser = new JsonOutputFunctionsParser();\n this.stringOutputParser = new StringOutputParser();\n }\n\n getChatHistoryString(chatHistory: BaseMessage[]): string {\n return chatHistory\n .map((chatMessage) => {\n if (chatMessage._getType() === \"human\") {\n return `Human: ${chatMessage.content}`;\n } else if (chatMessage._getType() === \"ai\") {\n return `AI: ${chatMessage.content}`;\n } else {\n return `${chatMessage.content}`;\n }\n })\n .join(\"\\n\");\n }\n\n removeDuplicateStrings(strings: Array<string>): Array<string> {\n return [...new Set(strings)];\n }\n\n /**\n * This method breaks down the chat history into chunks of messages.\n * Each chunk consists of a sequence of messages ending with an AI message and the subsequent user response, if any.\n *\n * @param {BaseMessage[]} chatHistory - The chat history to be chunked.\n *\n * @returns {MessageChunkResult[]} An array of message chunks. Each chunk includes a sequence of messages and the subsequent user response.\n *\n * @description\n * The method iterates over the chat history and pushes each message into a temporary array.\n * When it encounters an AI message, it checks for a subsequent user message.\n * If a user message is found, it is considered as the user response to the AI message.\n * If no user message is found after the AI message, the user response is undefined.\n * The method then pushes the chunk (sequence of messages and user response) into the result array.\n * This process continues until all messages in the chat history have been processed.\n */\n chunkMessagesByAIResponse(chatHistory: BaseMessage[]): MessageChunkResult[] {\n const newArray: MessageChunkResult[] = [];\n const tempArray: BaseMessage[] = [];\n\n chatHistory.forEach((item, index) => {\n tempArray.push(item);\n if (item._getType() === \"ai\") {\n let userResponse: BaseMessage | undefined = chatHistory[index + 1];\n if (!userResponse || userResponse._getType() !== \"human\") {\n userResponse = undefined;\n }\n\n newArray.push({\n chunkedMessages: tempArray,\n userResponse: userResponse\n ? new HumanMessage(userResponse)\n : undefined,\n });\n }\n });\n\n return newArray;\n }\n\n /**\n * This method processes a chat history to generate insights about the user.\n *\n * @param {ChainValues} values - The input values for the chain. It should contain a key for chat history.\n * @param {CallbackManagerForChainRun} [runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<ChainValues>} A promise that resolves to a list of insights about the user.\n *\n * @throws {Error} If the chat history key is not found in the input values or if the chat history is not an array of BaseMessages.\n *\n * @description\n * The method performs the following steps:\n * 1. Checks if the chat history key is present in the input values and if the chat history is an array of BaseMessages.\n * 2. Breaks the chat history into chunks of messages.\n * 3. For each chunk, it generates an initial prediction for the user's next message.\n * 4. For each prediction, it generates insights and prediction violations, and regenerates the prediction based on the violations.\n * 5. For each set of messages, it generates a fact/insight about the user.\n * The method returns a list of these insights.\n */\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n if (!(this.chatHistoryKey in values)) {\n throw new Error(`Chat history key ${this.chatHistoryKey} not found`);\n }\n\n const chatHistory: unknown[] = values[this.chatHistoryKey];\n\n const isEveryMessageBaseMessage = chatHistory.every((message) =>\n isBaseMessage(message)\n );\n if (!isEveryMessageBaseMessage) {\n throw new Error(\"Chat history must be an array of BaseMessages\");\n }\n\n const messageChunks = this.chunkMessagesByAIResponse(\n chatHistory as BaseMessage[]\n );\n\n // Generate the initial prediction for every user message.\n const userPredictions = await Promise.all(\n messageChunks.map(async (chatHistoryChunk) => ({\n userPredictions: await this.predictNextUserMessage(\n chatHistoryChunk.chunkedMessages\n ),\n userResponse: chatHistoryChunk.userResponse,\n runManager,\n }))\n );\n\n // Generate insights, and prediction violations for every user message.\n // This call also regenerates the prediction based on the violations.\n const predictionViolations = await Promise.all(\n userPredictions.map((prediction) =>\n this.getPredictionViolations({\n userPredictions: prediction.userPredictions,\n userResponse: prediction.userResponse,\n runManager,\n })\n )\n );\n\n // Generate a fact/insight about the user for every set of messages.\n const insights = await Promise.all(\n predictionViolations.map((violation) =>\n this.generateFacts({\n userResponse: violation.userResponse,\n predictions: {\n revisedPrediction: violation.revisedPrediction,\n explainedPredictionErrors: violation.explainedPredictionErrors,\n },\n })\n )\n );\n\n return {\n insights,\n };\n }\n\n /**\n * This method predicts the next user message based on the chat history.\n *\n * @param {BaseMessage[]} chatHistory - The chat history based on which the next user message is predicted.\n * @param {CallbackManagerForChainRun} [runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<PredictNextUserMessageResponse>} A promise that resolves to the predicted next user message, the user state, and any insights.\n *\n * @throws {Error} If the response from the language model does not contain the expected keys: 'userState', 'predictedUserMessage', and 'insights'.\n */\n private async predictNextUserMessage(\n chatHistory: BaseMessage[],\n runManager?: CallbackManagerForChainRun\n ): Promise<PredictNextUserMessageResponse> {\n const messageString = this.getChatHistoryString(chatHistory);\n\n const llmWithFunctions = this.llm\n .bindTools([PREDICT_NEXT_USER_MESSAGE_FUNCTION])\n .withConfig({\n function_call: { name: PREDICT_NEXT_USER_MESSAGE_FUNCTION.name },\n });\n\n const chain = PREDICT_NEXT_USER_MESSAGE_PROMPT.pipe(llmWithFunctions).pipe(\n this.jsonOutputParser\n );\n\n const res = await chain.invoke(\n {\n chat_history: messageString,\n },\n runManager?.getChild(\"prediction\")\n );\n\n if (\n !(\n \"userState\" in res &&\n \"predictedUserMessage\" in res &&\n \"insights\" in res\n )\n ) {\n throw new Error(`Invalid response from LLM: ${JSON.stringify(res)}`);\n }\n\n const predictionResponse = res as PredictNextUserMessageResponse;\n\n // Query the retriever for relevant insights. Use the generates insights as a query.\n const retrievedDocs = await this.retrieveRelevantInsights(\n predictionResponse.insights\n );\n const relevantDocs = this.removeDuplicateStrings([\n ...predictionResponse.insights,\n ...retrievedDocs,\n ]);\n\n return {\n ...predictionResponse,\n insights: relevantDocs,\n };\n }\n\n /**\n * Retrieves relevant insights based on the provided insights.\n *\n * @param {Array<string>} insights - An array of insights to be used for retrieving relevant documents.\n *\n * @returns {Promise<Array<string>>} A promise that resolves to an array of relevant insights content.\n */\n private async retrieveRelevantInsights(\n insights: Array<string>\n ): Promise<Array<string>> {\n // Only extract the first relevant doc from the retriever. We don't need more than one.\n const relevantInsightsDocuments = await Promise.all(\n insights.map(async (insight) => {\n const relevantInsight = await this.retriever.invoke(insight);\n return relevantInsight[0];\n })\n );\n\n const relevantInsightsContent = relevantInsightsDocuments.map(\n (document) => document.pageContent\n );\n\n return relevantInsightsContent;\n }\n\n /**\n * This method generates prediction violations based on the predicted and actual user responses.\n * It also generates a revised prediction based on the identified violations.\n *\n * @param {Object} params - The parameters for the method.\n * @param {PredictNextUserMessageResponse} params.userPredictions - The predicted user message, user state, and insights.\n * @param {BaseMessage} [params.userResponse] - The actual user response.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<{ userResponse: BaseMessage | undefined; revisedPrediction: string; explainedPredictionErrors: Array<string>; }>} A promise that resolves to an object containing the actual user response, the revised prediction, and the explained prediction errors.\n *\n * @throws {Error} If the response from the language model does not contain the expected keys: 'violationExplanation', 'explainedPredictionErrors', and 'accuratePrediction'.\n */\n private async getPredictionViolations({\n userPredictions,\n userResponse,\n runManager,\n }: {\n userPredictions: PredictNextUserMessageResponse;\n userResponse?: BaseMessage;\n runManager?: CallbackManagerForChainRun;\n }): Promise<GetPredictionViolationsResponse> {\n const llmWithFunctions = this.llm\n .bindTools([PREDICTION_VIOLATIONS_FUNCTION])\n .withConfig({\n function_call: { name: PREDICTION_VIOLATIONS_FUNCTION.name },\n });\n\n const chain = PREDICTION_VIOLATIONS_PROMPT.pipe(llmWithFunctions).pipe(\n this.jsonOutputParser\n );\n\n if (typeof userResponse?.content !== \"string\") {\n throw new Error(\"This chain does not support non-string model output.\");\n }\n const res = (await chain.invoke(\n {\n predicted_output: userPredictions.predictedUserMessage,\n actual_output: userResponse?.content ?? \"\",\n user_insights: userPredictions.insights.join(\"\\n\"),\n },\n runManager?.getChild(\"prediction_violations\")\n )) as Awaited<{\n violationExplanation: string;\n explainedPredictionErrors: Array<string>;\n accuratePrediction: boolean;\n }>;\n\n // Generate a revised prediction based on violations.\n const revisedPrediction = await this.generateRevisedPrediction({\n originalPrediction: userPredictions.predictedUserMessage,\n explainedPredictionErrors: res.explainedPredictionErrors,\n userInsights: userPredictions.insights,\n runManager,\n });\n\n return {\n userResponse,\n revisedPrediction,\n explainedPredictionErrors: res.explainedPredictionErrors,\n };\n }\n\n /**\n * This method generates a revised prediction based on the original prediction, explained prediction errors, and user insights.\n *\n * @param {Object} params - The parameters for the method.\n * @param {string} params.originalPrediction - The original prediction made by the model.\n * @param {Array<string>} params.explainedPredictionErrors - An array of explained prediction errors.\n * @param {Array<string>} params.userInsights - An array of insights about the user.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<string>} A promise that resolves to a revised prediction.\n */\n private async generateRevisedPrediction({\n originalPrediction,\n explainedPredictionErrors,\n userInsights,\n runManager,\n }: {\n originalPrediction: string;\n explainedPredictionErrors: Array<string>;\n userInsights: Array<string>;\n runManager?: CallbackManagerForChainRun;\n }): Promise<string> {\n const revisedPredictionChain = GENERATE_REVISED_PREDICTION_PROMPT.pipe(\n this.llm\n ).pipe(this.stringOutputParser);\n\n const revisedPredictionRes = await revisedPredictionChain.invoke(\n {\n prediction: originalPrediction,\n explained_prediction_errors: explainedPredictionErrors.join(\"\\n\"),\n user_insights: userInsights.join(\"\\n\"),\n },\n runManager?.getChild(\"prediction_revision\")\n );\n\n return revisedPredictionRes;\n }\n\n /**\n * This method generates facts or insights about the user based on the revised prediction, explained prediction errors, and the user's response.\n *\n * @param {Object} params - The parameters for the method.\n * @param {BaseMessage} [params.userResponse] - The actual user response.\n * @param {Object} params.predictions - The revised prediction and explained prediction errors.\n * @param {string} params.predictions.revisedPrediction - The revised prediction made by the model.\n * @param {Array<string>} params.predictions.explainedPredictionErrors - An array of explained prediction errors.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<string>} A promise that resolves to a string containing the generated facts or insights about the user.\n */\n private async generateFacts({\n userResponse,\n predictions,\n runManager,\n }: {\n userResponse?: BaseMessage;\n /**\n * Optional if the prediction was accurate.\n */\n predictions: {\n revisedPrediction: string;\n explainedPredictionErrors: Array<string>;\n };\n runManager?: CallbackManagerForChainRun;\n }): Promise<string> {\n const chain = GENERATE_FACTS_PROMPT.pipe(this.llm).pipe(\n this.stringOutputParser\n );\n\n if (typeof userResponse?.content !== \"string\") {\n throw new Error(\"This chain does not support non-string model output.\");\n }\n const res = await chain.invoke(\n {\n prediction_violations: predictions.explainedPredictionErrors.join(\"\\n\"),\n prediction: predictions.revisedPrediction,\n user_message: userResponse?.content ?? \"\",\n },\n runManager?.getChild(\"generate_facts\")\n );\n\n return res;\n }\n\n /**\n * Static method that creates a ViolationOfExpectationsChain instance from a\n * ChatOpenAI and retriever. It also accepts optional options\n * to customize the chain.\n *\n * @param llm The ChatOpenAI instance.\n * @param retriever The retriever used for similarity search.\n * @param options Optional options to customize the chain.\n *\n * @returns A new instance of ViolationOfExpectationsChain.\n */\n static fromLLM(\n llm: ChatOpenAI,\n retriever: BaseRetrieverInterface,\n options?: Partial<\n Omit<ViolationOfExpectationsChainInput, \"llm\" | \"retriever\">\n >\n ): ViolationOfExpectationsChain {\n return new this({\n retriever,\n llm,\n ...options,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"violation_of_expectations_chain.js","names":[],"sources":["../../../../src/experimental/chains/violation_of_expectations/violation_of_expectations_chain.ts"],"sourcesContent":["import type { BaseRetrieverInterface } from \"@langchain/core/retrievers\";\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport {\n BaseMessage,\n HumanMessage,\n isBaseMessage,\n} from \"@langchain/core/messages\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { StringOutputParser } from \"@langchain/core/output_parsers\";\nimport { CallbackManagerForChainRun } from \"@langchain/core/callbacks/manager\";\nimport { JsonOutputFunctionsParser } from \"../../../output_parsers/openai_functions.js\";\nimport { BaseChain, ChainInputs } from \"../../../chains/base.js\";\nimport {\n GetPredictionViolationsResponse,\n MessageChunkResult,\n PREDICTION_VIOLATIONS_FUNCTION,\n PREDICT_NEXT_USER_MESSAGE_FUNCTION,\n PredictNextUserMessageResponse,\n} from \"./types.js\";\nimport {\n GENERATE_FACTS_PROMPT,\n GENERATE_REVISED_PREDICTION_PROMPT,\n PREDICTION_VIOLATIONS_PROMPT,\n PREDICT_NEXT_USER_MESSAGE_PROMPT,\n} from \"./violation_of_expectations_prompt.js\";\n\n/**\n * Interface for the input parameters of the ViolationOfExpectationsChain class.\n */\nexport interface ViolationOfExpectationsChainInput extends ChainInputs {\n /**\n * The retriever to use for retrieving stored\n * thoughts and insights.\n */\n retriever: BaseRetrieverInterface;\n /**\n * The LLM to use\n */\n llm: ChatOpenAI;\n}\n\n/**\n * Chain that generates key insights/facts of a user based on a\n * a chat conversation with an AI.\n */\nexport class ViolationOfExpectationsChain\n extends BaseChain\n implements ViolationOfExpectationsChainInput\n{\n static lc_name() {\n return \"ViolationOfExpectationsChain\";\n }\n\n _chainType(): string {\n return \"violation_of_expectation_chain\";\n }\n\n chatHistoryKey = \"chat_history\";\n\n thoughtsKey = \"thoughts\";\n\n get inputKeys() {\n return [this.chatHistoryKey];\n }\n\n get outputKeys() {\n return [this.thoughtsKey];\n }\n\n retriever: BaseRetrieverInterface;\n\n llm: ChatOpenAI;\n\n jsonOutputParser: JsonOutputFunctionsParser;\n\n stringOutputParser: StringOutputParser;\n\n constructor(fields: ViolationOfExpectationsChainInput) {\n super(fields);\n this.retriever = fields.retriever;\n this.llm = fields.llm;\n this.jsonOutputParser = new JsonOutputFunctionsParser();\n this.stringOutputParser = new StringOutputParser();\n }\n\n getChatHistoryString(chatHistory: BaseMessage[]): string {\n return chatHistory\n .map((chatMessage) => {\n if (chatMessage._getType() === \"human\") {\n return `Human: ${chatMessage.content}`;\n } else if (chatMessage._getType() === \"ai\") {\n return `AI: ${chatMessage.content}`;\n } else {\n return `${chatMessage.content}`;\n }\n })\n .join(\"\\n\");\n }\n\n removeDuplicateStrings(strings: Array<string>): Array<string> {\n return [...new Set(strings)];\n }\n\n /**\n * This method breaks down the chat history into chunks of messages.\n * Each chunk consists of a sequence of messages ending with an AI message and the subsequent user response, if any.\n *\n * @param {BaseMessage[]} chatHistory - The chat history to be chunked.\n *\n * @returns {MessageChunkResult[]} An array of message chunks. Each chunk includes a sequence of messages and the subsequent user response.\n *\n * @description\n * The method iterates over the chat history and pushes each message into a temporary array.\n * When it encounters an AI message, it checks for a subsequent user message.\n * If a user message is found, it is considered as the user response to the AI message.\n * If no user message is found after the AI message, the user response is undefined.\n * The method then pushes the chunk (sequence of messages and user response) into the result array.\n * This process continues until all messages in the chat history have been processed.\n */\n chunkMessagesByAIResponse(chatHistory: BaseMessage[]): MessageChunkResult[] {\n const newArray: MessageChunkResult[] = [];\n const tempArray: BaseMessage[] = [];\n\n chatHistory.forEach((item, index) => {\n tempArray.push(item);\n if (item._getType() === \"ai\") {\n let userResponse: BaseMessage | undefined = chatHistory[index + 1];\n if (!userResponse || userResponse._getType() !== \"human\") {\n userResponse = undefined;\n }\n\n newArray.push({\n chunkedMessages: tempArray,\n userResponse: userResponse\n ? new HumanMessage(userResponse)\n : undefined,\n });\n }\n });\n\n return newArray;\n }\n\n /**\n * This method processes a chat history to generate insights about the user.\n *\n * @param {ChainValues} values - The input values for the chain. It should contain a key for chat history.\n * @param {CallbackManagerForChainRun} [runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<ChainValues>} A promise that resolves to a list of insights about the user.\n *\n * @throws {Error} If the chat history key is not found in the input values or if the chat history is not an array of BaseMessages.\n *\n * @description\n * The method performs the following steps:\n * 1. Checks if the chat history key is present in the input values and if the chat history is an array of BaseMessages.\n * 2. Breaks the chat history into chunks of messages.\n * 3. For each chunk, it generates an initial prediction for the user's next message.\n * 4. For each prediction, it generates insights and prediction violations, and regenerates the prediction based on the violations.\n * 5. For each set of messages, it generates a fact/insight about the user.\n * The method returns a list of these insights.\n */\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n if (!(this.chatHistoryKey in values)) {\n throw new Error(`Chat history key ${this.chatHistoryKey} not found`);\n }\n\n const chatHistory: unknown[] = values[this.chatHistoryKey];\n\n const isEveryMessageBaseMessage = chatHistory.every((message) =>\n isBaseMessage(message)\n );\n if (!isEveryMessageBaseMessage) {\n throw new Error(\"Chat history must be an array of BaseMessages\");\n }\n\n const messageChunks = this.chunkMessagesByAIResponse(\n chatHistory as BaseMessage[]\n );\n\n // Generate the initial prediction for every user message.\n const userPredictions = await Promise.all(\n messageChunks.map(async (chatHistoryChunk) => ({\n userPredictions: await this.predictNextUserMessage(\n chatHistoryChunk.chunkedMessages\n ),\n userResponse: chatHistoryChunk.userResponse,\n runManager,\n }))\n );\n\n // Generate insights, and prediction violations for every user message.\n // This call also regenerates the prediction based on the violations.\n const predictionViolations = await Promise.all(\n userPredictions.map((prediction) =>\n this.getPredictionViolations({\n userPredictions: prediction.userPredictions,\n userResponse: prediction.userResponse,\n runManager,\n })\n )\n );\n\n // Generate a fact/insight about the user for every set of messages.\n const insights = await Promise.all(\n predictionViolations.map((violation) =>\n this.generateFacts({\n userResponse: violation.userResponse,\n predictions: {\n revisedPrediction: violation.revisedPrediction,\n explainedPredictionErrors: violation.explainedPredictionErrors,\n },\n })\n )\n );\n\n return {\n insights,\n };\n }\n\n /**\n * This method predicts the next user message based on the chat history.\n *\n * @param {BaseMessage[]} chatHistory - The chat history based on which the next user message is predicted.\n * @param {CallbackManagerForChainRun} [runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<PredictNextUserMessageResponse>} A promise that resolves to the predicted next user message, the user state, and any insights.\n *\n * @throws {Error} If the response from the language model does not contain the expected keys: 'userState', 'predictedUserMessage', and 'insights'.\n */\n private async predictNextUserMessage(\n chatHistory: BaseMessage[],\n runManager?: CallbackManagerForChainRun\n ): Promise<PredictNextUserMessageResponse> {\n const messageString = this.getChatHistoryString(chatHistory);\n\n const llmWithFunctions = this.llm\n .bindTools([PREDICT_NEXT_USER_MESSAGE_FUNCTION])\n .withConfig({\n function_call: { name: PREDICT_NEXT_USER_MESSAGE_FUNCTION.name },\n });\n\n const chain = PREDICT_NEXT_USER_MESSAGE_PROMPT.pipe(llmWithFunctions).pipe(\n this.jsonOutputParser\n );\n\n const res = await chain.invoke(\n {\n chat_history: messageString,\n },\n runManager?.getChild(\"prediction\")\n );\n\n if (\n !(\n \"userState\" in res &&\n \"predictedUserMessage\" in res &&\n \"insights\" in res\n )\n ) {\n throw new Error(`Invalid response from LLM: ${JSON.stringify(res)}`);\n }\n\n const predictionResponse = res as PredictNextUserMessageResponse;\n\n // Query the retriever for relevant insights. Use the generates insights as a query.\n const retrievedDocs = await this.retrieveRelevantInsights(\n predictionResponse.insights\n );\n const relevantDocs = this.removeDuplicateStrings([\n ...predictionResponse.insights,\n ...retrievedDocs,\n ]);\n\n return {\n ...predictionResponse,\n insights: relevantDocs,\n };\n }\n\n /**\n * Retrieves relevant insights based on the provided insights.\n *\n * @param {Array<string>} insights - An array of insights to be used for retrieving relevant documents.\n *\n * @returns {Promise<Array<string>>} A promise that resolves to an array of relevant insights content.\n */\n private async retrieveRelevantInsights(\n insights: Array<string>\n ): Promise<Array<string>> {\n // Only extract the first relevant doc from the retriever. We don't need more than one.\n const relevantInsightsDocuments = await Promise.all(\n insights.map(async (insight) => {\n const relevantInsight = await this.retriever.invoke(insight);\n return relevantInsight[0];\n })\n );\n\n const relevantInsightsContent = relevantInsightsDocuments.map(\n (document) => document.pageContent\n );\n\n return relevantInsightsContent;\n }\n\n /**\n * This method generates prediction violations based on the predicted and actual user responses.\n * It also generates a revised prediction based on the identified violations.\n *\n * @param {Object} params - The parameters for the method.\n * @param {PredictNextUserMessageResponse} params.userPredictions - The predicted user message, user state, and insights.\n * @param {BaseMessage} [params.userResponse] - The actual user response.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<{ userResponse: BaseMessage | undefined; revisedPrediction: string; explainedPredictionErrors: Array<string>; }>} A promise that resolves to an object containing the actual user response, the revised prediction, and the explained prediction errors.\n *\n * @throws {Error} If the response from the language model does not contain the expected keys: 'violationExplanation', 'explainedPredictionErrors', and 'accuratePrediction'.\n */\n private async getPredictionViolations({\n userPredictions,\n userResponse,\n runManager,\n }: {\n userPredictions: PredictNextUserMessageResponse;\n userResponse?: BaseMessage;\n runManager?: CallbackManagerForChainRun;\n }): Promise<GetPredictionViolationsResponse> {\n const llmWithFunctions = this.llm\n .bindTools([PREDICTION_VIOLATIONS_FUNCTION])\n .withConfig({\n function_call: { name: PREDICTION_VIOLATIONS_FUNCTION.name },\n });\n\n const chain = PREDICTION_VIOLATIONS_PROMPT.pipe(llmWithFunctions).pipe(\n this.jsonOutputParser\n );\n\n if (typeof userResponse?.content !== \"string\") {\n throw new Error(\"This chain does not support non-string model output.\");\n }\n const res = (await chain.invoke(\n {\n predicted_output: userPredictions.predictedUserMessage,\n actual_output: userResponse?.content ?? \"\",\n user_insights: userPredictions.insights.join(\"\\n\"),\n },\n runManager?.getChild(\"prediction_violations\")\n )) as Awaited<{\n violationExplanation: string;\n explainedPredictionErrors: Array<string>;\n accuratePrediction: boolean;\n }>;\n\n // Generate a revised prediction based on violations.\n const revisedPrediction = await this.generateRevisedPrediction({\n originalPrediction: userPredictions.predictedUserMessage,\n explainedPredictionErrors: res.explainedPredictionErrors,\n userInsights: userPredictions.insights,\n runManager,\n });\n\n return {\n userResponse,\n revisedPrediction,\n explainedPredictionErrors: res.explainedPredictionErrors,\n };\n }\n\n /**\n * This method generates a revised prediction based on the original prediction, explained prediction errors, and user insights.\n *\n * @param {Object} params - The parameters for the method.\n * @param {string} params.originalPrediction - The original prediction made by the model.\n * @param {Array<string>} params.explainedPredictionErrors - An array of explained prediction errors.\n * @param {Array<string>} params.userInsights - An array of insights about the user.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<string>} A promise that resolves to a revised prediction.\n */\n private async generateRevisedPrediction({\n originalPrediction,\n explainedPredictionErrors,\n userInsights,\n runManager,\n }: {\n originalPrediction: string;\n explainedPredictionErrors: Array<string>;\n userInsights: Array<string>;\n runManager?: CallbackManagerForChainRun;\n }): Promise<string> {\n const revisedPredictionChain = GENERATE_REVISED_PREDICTION_PROMPT.pipe(\n this.llm\n ).pipe(this.stringOutputParser);\n\n const revisedPredictionRes = await revisedPredictionChain.invoke(\n {\n prediction: originalPrediction,\n explained_prediction_errors: explainedPredictionErrors.join(\"\\n\"),\n user_insights: userInsights.join(\"\\n\"),\n },\n runManager?.getChild(\"prediction_revision\")\n );\n\n return revisedPredictionRes;\n }\n\n /**\n * This method generates facts or insights about the user based on the revised prediction, explained prediction errors, and the user's response.\n *\n * @param {Object} params - The parameters for the method.\n * @param {BaseMessage} [params.userResponse] - The actual user response.\n * @param {Object} params.predictions - The revised prediction and explained prediction errors.\n * @param {string} params.predictions.revisedPrediction - The revised prediction made by the model.\n * @param {Array<string>} params.predictions.explainedPredictionErrors - An array of explained prediction errors.\n * @param {CallbackManagerForChainRun} [params.runManager] - Optional callback manager for the chain run.\n *\n * @returns {Promise<string>} A promise that resolves to a string containing the generated facts or insights about the user.\n */\n private async generateFacts({\n userResponse,\n predictions,\n runManager,\n }: {\n userResponse?: BaseMessage;\n /**\n * Optional if the prediction was accurate.\n */\n predictions: {\n revisedPrediction: string;\n explainedPredictionErrors: Array<string>;\n };\n runManager?: CallbackManagerForChainRun;\n }): Promise<string> {\n const chain = GENERATE_FACTS_PROMPT.pipe(this.llm).pipe(\n this.stringOutputParser\n );\n\n if (typeof userResponse?.content !== \"string\") {\n throw new Error(\"This chain does not support non-string model output.\");\n }\n const res = await chain.invoke(\n {\n prediction_violations: predictions.explainedPredictionErrors.join(\"\\n\"),\n prediction: predictions.revisedPrediction,\n user_message: userResponse?.content ?? \"\",\n },\n runManager?.getChild(\"generate_facts\")\n );\n\n return res;\n }\n\n /**\n * Static method that creates a ViolationOfExpectationsChain instance from a\n * ChatOpenAI and retriever. It also accepts optional options\n * to customize the chain.\n *\n * @param llm The ChatOpenAI instance.\n * @param retriever The retriever used for similarity search.\n * @param options Optional options to customize the chain.\n *\n * @returns A new instance of ViolationOfExpectationsChain.\n */\n static fromLLM(\n llm: ChatOpenAI,\n retriever: BaseRetrieverInterface,\n options?: Partial<\n Omit<ViolationOfExpectationsChainInput, \"llm\" | \"retriever\">\n >\n ): ViolationOfExpectationsChain {\n return new this({\n retriever,\n llm,\n ...options,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generative_agent.cjs","names":["BaseChain","LLMChain","PromptTemplate"],"sources":["../../../src/experimental/generative_agents/generative_agent.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\nimport { GenerativeAgentMemory } from \"./generative_agent_memory.js\";\nimport { BaseChain } from \"../../chains/base.js\";\n\n/**\n * Configuration for the GenerativeAgent class. Defines the character's\n * name, optional age, permanent traits, status, verbosity, and summary\n * refresh seconds.\n */\nexport type GenerativeAgentConfig = {\n name: string;\n age?: number;\n traits: string;\n status: string;\n verbose?: boolean;\n summaryRefreshSeconds?: number;\n // dailySummaries?: string[];\n};\n\n/**\n * Implementation of a generative agent that can learn and form new memories over\n * time. It extends the BaseChain class, which is a generic\n * sequence of calls to components, including other chains.\n * @example\n * ```typescript\n * const tommie: GenerativeAgent = new GenerativeAgent(\n * new OpenAI({ temperature: 0.9, maxTokens: 1500 }),\n * new GenerativeAgentMemory(\n * new ChatOpenAI({ model: \"gpt-4o-mini\" }),\n * new TimeWeightedVectorStoreRetriever({\n * vectorStore: new MemoryVectorStore(new OpenAIEmbeddings()),\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * }),\n * { reflectionThreshold: 8 },\n * ),\n * {\n * name: \"Tommie\",\n * age: 25,\n * traits: \"anxious, likes design, talkative\",\n * status: \"looking for a job\",\n * },\n * );\n *\n * await tommie.addMemory(\n * \"Tommie remembers his dog, Bruno, from when he was a kid\",\n * new Date(),\n * );\n * const summary = await tommie.getSummary({ forceRefresh: true });\n * const response = await tommie.generateDialogueResponse(\n * \"USER says Hello Tommie, how are you today?\",\n * );\n * ```\n */\nexport class GenerativeAgent extends BaseChain {\n static lc_name() {\n return \"GenerativeAgent\";\n }\n\n // a character with memory and innate characterisitics\n name: string; // the character's name\n\n age?: number; // the optional age of the character\n\n traits: string; // permanent traits to ascribe to the character\n\n status: string; // the traits of the character you wish not to change\n\n longTermMemory: GenerativeAgentMemory;\n\n llm: BaseLanguageModelInterface; // the underlying language model\n\n verbose: boolean; // false\n\n private summary: string; // stateful self-summary generated via reflection on the character's memory.\n\n private summaryRefreshSeconds = 3600;\n\n private lastRefreshed: Date; // the last time the character's summary was regenerated\n\n // TODO: Add support for daily summaries\n // private dailySummaries: string[] = []; // summary of the events in the plan that the agent took.\n\n _chainType(): string {\n return \"generative_agent_executor\";\n }\n\n get inputKeys(): string[] {\n return [\"observation\", \"suffix\", \"now\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\", \"continue_dialogue\"];\n }\n\n constructor(\n llm: BaseLanguageModelInterface,\n longTermMemory: GenerativeAgentMemory,\n config: GenerativeAgentConfig\n ) {\n super();\n this.llm = llm;\n this.longTermMemory = longTermMemory;\n this.name = config.name;\n this.age = config.age;\n this.traits = config.traits;\n this.status = config.status;\n this.verbose = config.verbose ?? this.verbose;\n this.summary = \"\";\n this.summaryRefreshSeconds =\n config.summaryRefreshSeconds ?? this.summaryRefreshSeconds;\n this.lastRefreshed = new Date();\n // this.dailySummaries = config.dailySummaries ?? this.dailySummaries;\n }\n\n // LLM methods\n /**\n * Parses a newline-separated string into a list of strings.\n * @param text The string to parse.\n * @returns An array of strings parsed from the input text.\n */\n parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n const lines: string[] = text.trim().split(\"\\n\");\n const result: string[] = lines.map((line: string) =>\n line.replace(/^\\s*\\d+\\.\\s*/, \"\").trim()\n );\n return result;\n }\n\n /**\n * Creates a new LLMChain with the given prompt and the agent's language\n * model, verbosity, output key, and memory.\n * @param prompt The prompt to use for the LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\", // new\n memory: this.longTermMemory,\n });\n return chain;\n }\n\n /**\n * Extracts the observed entity from the given observation.\n * @param observation The observation to extract the entity from.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted entity as a string.\n */\n async getEntityFromObservations(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the observed entity in the following observation? {observation}\" +\n \"\\nEntity=\"\n );\n\n const result = await this.chain(prompt).call(\n {\n observation,\n },\n runManager?.getChild(\"entity_extractor\")\n );\n\n return result.output;\n }\n\n /**\n * Extracts the action of the given entity from the given observation.\n * @param observation The observation to extract the action from.\n * @param entityName The name of the entity to extract the action for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted action as a string.\n */\n async getEntityAction(\n observation: string,\n entityName: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the {entity} doing in the following observation? {observation}\" +\n \"\\nThe {entity} is\"\n );\n\n const result = await this.chain(prompt).call(\n {\n entity: entityName,\n observation,\n },\n runManager?.getChild(\"entity_action_extractor\")\n );\n const trimmedResult = result.output.trim();\n return trimmedResult;\n }\n\n /**\n * Summarizes memories that are most relevant to an observation.\n * @param observation The observation to summarize related memories for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The summarized memories as a string.\n */\n async summarizeRelatedMemories(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n // summarize memories that are most relevant to an observation\n const prompt = PromptTemplate.fromTemplate(\n `\n{q1}?\nContext from memory:\n{relevant_memories}\nRelevant context:`\n );\n const entityName = await this.getEntityFromObservations(\n observation,\n runManager\n );\n const entityAction = await this.getEntityAction(\n observation,\n entityName,\n runManager\n );\n const q1 = `What is the relationship between ${this.name} and ${entityName}`;\n const q2 = `${entityName} is ${entityAction}`;\n const response = await this.chain(prompt).call(\n {\n q1,\n queries: [q1, q2],\n },\n runManager?.getChild(\"entity_relationships\")\n );\n\n return response.output.trim(); // added output\n }\n\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n const { observation, suffix, now } = values;\n // react to a given observation or dialogue act\n const prompt = PromptTemplate.fromTemplate(\n `{agent_summary_description}` +\n `\\nIt is {current_time}.` +\n `\\n{agent_name}'s status: {agent_status}` +\n `\\nSummary of relevant context from {agent_name}'s memory:` +\n \"\\n{relevant_memories}\" +\n `\\nMost recent observations: {most_recent_memories}` +\n `\\nObservation: {observation}` +\n `\\n\\n${suffix}`\n );\n\n const agentSummaryDescription = await this.getSummary({}, runManager); // now = now in param\n const relevantMemoriesStr = await this.summarizeRelatedMemories(\n observation,\n runManager\n );\n const currentTime = (now || new Date()).toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n const chainInputs: ChainValues = {\n agent_summary_description: agentSummaryDescription,\n current_time: currentTime,\n agent_name: this.name,\n observation,\n agent_status: this.status,\n most_recent_memories: \"\",\n };\n\n chainInputs[this.longTermMemory.getRelevantMemoriesKey()] =\n relevantMemoriesStr;\n\n const consumedTokens = await this.llm.getNumTokens(\n await prompt.format({ ...chainInputs })\n );\n\n chainInputs[this.longTermMemory.getMostRecentMemoriesTokenKey()] =\n consumedTokens;\n const response = await this.chain(prompt).call(\n chainInputs,\n runManager?.getChild(\"reaction_from_summary\")\n );\n\n const rawOutput = response.output;\n let output = rawOutput;\n let continue_dialogue = false;\n\n if (rawOutput.includes(\"REACT:\")) {\n const reaction = this._cleanResponse(rawOutput.split(\"REACT:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and reacted by ${reaction}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${reaction}`;\n continue_dialogue = false;\n } else if (rawOutput.includes(\"SAY:\")) {\n const saidValue = this._cleanResponse(rawOutput.split(\"SAY:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and said ${saidValue}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${saidValue}`;\n continue_dialogue = true;\n } else if (rawOutput.includes(\"GOODBYE:\")) {\n const farewell = this._cleanResponse(\n rawOutput.split(\"GOODBYE:\").pop() ?? \"\"\n );\n await this.addMemory(\n `${this.name} observed ${observation} and said ${farewell}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${farewell}`;\n continue_dialogue = false;\n }\n\n return { output, continue_dialogue };\n }\n\n private _cleanResponse(text: string | undefined): string {\n if (text === undefined) {\n return \"\";\n }\n const regex = new RegExp(`^${this.name} `);\n return text.replace(regex, \"\").trim();\n }\n\n /**\n * Generates a reaction to the given observation.\n * @param observation The observation to generate a reaction for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateReaction(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate: string =\n `Should {agent_name} react to the observation, and if so,` +\n ` what would be an appropriate reaction? Respond in one line.` +\n ` If the action is to engage in dialogue, write:\\nSAY: \"what to say\"` +\n ` \\notherwise, write:\\nREACT: {agent_name}'s reaction (if anything).` +\n ` \\nEither do nothing, react, or say something but not both.\\n\\n`;\n\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n /**\n * Generates a dialogue response to the given observation.\n * @param observation The observation to generate a dialogue response for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateDialogueResponse(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate = `What would ${this.name} say? To end the conversation, write: GOODBYE: \"what to say\". Otherwise to continue the conversation, write: SAY: \"what to say next\"\\n\\n`;\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n // Agent stateful' summary methods\n // Each dialog or response prompt includes a header\n // summarizing the agent's self-description. This is\n // updated periodically through probing it's memories\n /**\n * Gets the agent's summary, which includes the agent's name, age, traits,\n * and a summary of the agent's core characteristics. The summary is\n * updated periodically through probing the agent's memories.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The agent's summary as a string.\n */\n async getSummary(\n config?: {\n now?: Date;\n forceRefresh?: boolean;\n },\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const { now = new Date(), forceRefresh = false } = config ?? {};\n\n const sinceRefresh = Math.floor(\n (now.getTime() - this.lastRefreshed.getTime()) / 1000\n );\n\n if (\n !this.summary ||\n sinceRefresh >= this.summaryRefreshSeconds ||\n forceRefresh\n ) {\n this.summary = await this.computeAgentSummary(runManager);\n this.lastRefreshed = now;\n }\n\n let age;\n if (this.age) {\n age = this.age;\n } else {\n age = \"N/A\";\n }\n\n return `Name: ${this.name} (age: ${age})\nInnate traits: ${this.traits}\n${this.summary}`;\n }\n\n /**\n * Computes the agent's summary by summarizing the agent's core\n * characteristics given the agent's relevant memories.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The computed summary as a string.\n */\n async computeAgentSummary(\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"How would you summarize {name}'s core characteristics given the following statements:\\n\" +\n \"----------\" +\n \"{relevant_memories}\" +\n \"----------\" +\n \"Do not embellish.\" +\n \"\\n\\nSummary: \"\n );\n // the agent seeks to think about their core characterisitics\n const result = await this.chain(prompt).call(\n {\n name: this.name,\n queries: [`${this.name}'s core characteristics`],\n },\n runManager?.getChild(\"compute_agent_summary\")\n );\n return result.output.trim();\n }\n\n /**\n * Returns a full header of the agent's status, summary, and current time.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @returns The full header as a string.\n */\n getFullHeader(\n config: {\n now?: Date;\n forceRefresh?: boolean;\n } = {}\n ): string {\n const { now = new Date(), forceRefresh = false } = config;\n // return a full header of the agent's status, summary, and current time.\n const summary = this.getSummary({ now, forceRefresh });\n const currentTimeString = now.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n return `${summary}\\nIt is ${currentTimeString}.\\n${this.name}'s status: ${this.status}`;\n }\n\n /**\n * Adds a memory to the agent's long-term memory.\n * @param memoryContent The content of the memory to add.\n * @param now Optional current date.\n * @param metadata Optional metadata for the memory.\n * @param callbacks Optional Callbacks instance.\n * @returns The result of adding the memory to the agent's long-term memory.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.longTermMemory.addMemory(\n memoryContent,\n now,\n metadata,\n callbacks\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generative_agent.cjs","names":["BaseChain","LLMChain","PromptTemplate"],"sources":["../../../src/experimental/generative_agents/generative_agent.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\nimport { GenerativeAgentMemory } from \"./generative_agent_memory.js\";\nimport { BaseChain } from \"../../chains/base.js\";\n\n/**\n * Configuration for the GenerativeAgent class. Defines the character's\n * name, optional age, permanent traits, status, verbosity, and summary\n * refresh seconds.\n */\nexport type GenerativeAgentConfig = {\n name: string;\n age?: number;\n traits: string;\n status: string;\n verbose?: boolean;\n summaryRefreshSeconds?: number;\n // dailySummaries?: string[];\n};\n\n/**\n * Implementation of a generative agent that can learn and form new memories over\n * time. It extends the BaseChain class, which is a generic\n * sequence of calls to components, including other chains.\n * @example\n * ```typescript\n * const tommie: GenerativeAgent = new GenerativeAgent(\n * new OpenAI({ temperature: 0.9, maxTokens: 1500 }),\n * new GenerativeAgentMemory(\n * new ChatOpenAI({ model: \"gpt-4o-mini\" }),\n * new TimeWeightedVectorStoreRetriever({\n * vectorStore: new MemoryVectorStore(new OpenAIEmbeddings()),\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * }),\n * { reflectionThreshold: 8 },\n * ),\n * {\n * name: \"Tommie\",\n * age: 25,\n * traits: \"anxious, likes design, talkative\",\n * status: \"looking for a job\",\n * },\n * );\n *\n * await tommie.addMemory(\n * \"Tommie remembers his dog, Bruno, from when he was a kid\",\n * new Date(),\n * );\n * const summary = await tommie.getSummary({ forceRefresh: true });\n * const response = await tommie.generateDialogueResponse(\n * \"USER says Hello Tommie, how are you today?\",\n * );\n * ```\n */\nexport class GenerativeAgent extends BaseChain {\n static lc_name() {\n return \"GenerativeAgent\";\n }\n\n // a character with memory and innate characterisitics\n name: string; // the character's name\n\n age?: number; // the optional age of the character\n\n traits: string; // permanent traits to ascribe to the character\n\n status: string; // the traits of the character you wish not to change\n\n longTermMemory: GenerativeAgentMemory;\n\n llm: BaseLanguageModelInterface; // the underlying language model\n\n verbose: boolean; // false\n\n private summary: string; // stateful self-summary generated via reflection on the character's memory.\n\n private summaryRefreshSeconds = 3600;\n\n private lastRefreshed: Date; // the last time the character's summary was regenerated\n\n // TODO: Add support for daily summaries\n // private dailySummaries: string[] = []; // summary of the events in the plan that the agent took.\n\n _chainType(): string {\n return \"generative_agent_executor\";\n }\n\n get inputKeys(): string[] {\n return [\"observation\", \"suffix\", \"now\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\", \"continue_dialogue\"];\n }\n\n constructor(\n llm: BaseLanguageModelInterface,\n longTermMemory: GenerativeAgentMemory,\n config: GenerativeAgentConfig\n ) {\n super();\n this.llm = llm;\n this.longTermMemory = longTermMemory;\n this.name = config.name;\n this.age = config.age;\n this.traits = config.traits;\n this.status = config.status;\n this.verbose = config.verbose ?? this.verbose;\n this.summary = \"\";\n this.summaryRefreshSeconds =\n config.summaryRefreshSeconds ?? this.summaryRefreshSeconds;\n this.lastRefreshed = new Date();\n // this.dailySummaries = config.dailySummaries ?? this.dailySummaries;\n }\n\n // LLM methods\n /**\n * Parses a newline-separated string into a list of strings.\n * @param text The string to parse.\n * @returns An array of strings parsed from the input text.\n */\n parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n const lines: string[] = text.trim().split(\"\\n\");\n const result: string[] = lines.map((line: string) =>\n line.replace(/^\\s*\\d+\\.\\s*/, \"\").trim()\n );\n return result;\n }\n\n /**\n * Creates a new LLMChain with the given prompt and the agent's language\n * model, verbosity, output key, and memory.\n * @param prompt The prompt to use for the LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\", // new\n memory: this.longTermMemory,\n });\n return chain;\n }\n\n /**\n * Extracts the observed entity from the given observation.\n * @param observation The observation to extract the entity from.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted entity as a string.\n */\n async getEntityFromObservations(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the observed entity in the following observation? {observation}\" +\n \"\\nEntity=\"\n );\n\n const result = await this.chain(prompt).call(\n {\n observation,\n },\n runManager?.getChild(\"entity_extractor\")\n );\n\n return result.output;\n }\n\n /**\n * Extracts the action of the given entity from the given observation.\n * @param observation The observation to extract the action from.\n * @param entityName The name of the entity to extract the action for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted action as a string.\n */\n async getEntityAction(\n observation: string,\n entityName: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the {entity} doing in the following observation? {observation}\" +\n \"\\nThe {entity} is\"\n );\n\n const result = await this.chain(prompt).call(\n {\n entity: entityName,\n observation,\n },\n runManager?.getChild(\"entity_action_extractor\")\n );\n const trimmedResult = result.output.trim();\n return trimmedResult;\n }\n\n /**\n * Summarizes memories that are most relevant to an observation.\n * @param observation The observation to summarize related memories for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The summarized memories as a string.\n */\n async summarizeRelatedMemories(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n // summarize memories that are most relevant to an observation\n const prompt = PromptTemplate.fromTemplate(\n `\n{q1}?\nContext from memory:\n{relevant_memories}\nRelevant context:`\n );\n const entityName = await this.getEntityFromObservations(\n observation,\n runManager\n );\n const entityAction = await this.getEntityAction(\n observation,\n entityName,\n runManager\n );\n const q1 = `What is the relationship between ${this.name} and ${entityName}`;\n const q2 = `${entityName} is ${entityAction}`;\n const response = await this.chain(prompt).call(\n {\n q1,\n queries: [q1, q2],\n },\n runManager?.getChild(\"entity_relationships\")\n );\n\n return response.output.trim(); // added output\n }\n\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n const { observation, suffix, now } = values;\n // react to a given observation or dialogue act\n const prompt = PromptTemplate.fromTemplate(\n `{agent_summary_description}` +\n `\\nIt is {current_time}.` +\n `\\n{agent_name}'s status: {agent_status}` +\n `\\nSummary of relevant context from {agent_name}'s memory:` +\n \"\\n{relevant_memories}\" +\n `\\nMost recent observations: {most_recent_memories}` +\n `\\nObservation: {observation}` +\n `\\n\\n${suffix}`\n );\n\n const agentSummaryDescription = await this.getSummary({}, runManager); // now = now in param\n const relevantMemoriesStr = await this.summarizeRelatedMemories(\n observation,\n runManager\n );\n const currentTime = (now || new Date()).toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n const chainInputs: ChainValues = {\n agent_summary_description: agentSummaryDescription,\n current_time: currentTime,\n agent_name: this.name,\n observation,\n agent_status: this.status,\n most_recent_memories: \"\",\n };\n\n chainInputs[this.longTermMemory.getRelevantMemoriesKey()] =\n relevantMemoriesStr;\n\n const consumedTokens = await this.llm.getNumTokens(\n await prompt.format({ ...chainInputs })\n );\n\n chainInputs[this.longTermMemory.getMostRecentMemoriesTokenKey()] =\n consumedTokens;\n const response = await this.chain(prompt).call(\n chainInputs,\n runManager?.getChild(\"reaction_from_summary\")\n );\n\n const rawOutput = response.output;\n let output = rawOutput;\n let continue_dialogue = false;\n\n if (rawOutput.includes(\"REACT:\")) {\n const reaction = this._cleanResponse(rawOutput.split(\"REACT:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and reacted by ${reaction}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${reaction}`;\n continue_dialogue = false;\n } else if (rawOutput.includes(\"SAY:\")) {\n const saidValue = this._cleanResponse(rawOutput.split(\"SAY:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and said ${saidValue}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${saidValue}`;\n continue_dialogue = true;\n } else if (rawOutput.includes(\"GOODBYE:\")) {\n const farewell = this._cleanResponse(\n rawOutput.split(\"GOODBYE:\").pop() ?? \"\"\n );\n await this.addMemory(\n `${this.name} observed ${observation} and said ${farewell}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${farewell}`;\n continue_dialogue = false;\n }\n\n return { output, continue_dialogue };\n }\n\n private _cleanResponse(text: string | undefined): string {\n if (text === undefined) {\n return \"\";\n }\n const regex = new RegExp(`^${this.name} `);\n return text.replace(regex, \"\").trim();\n }\n\n /**\n * Generates a reaction to the given observation.\n * @param observation The observation to generate a reaction for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateReaction(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate: string =\n `Should {agent_name} react to the observation, and if so,` +\n ` what would be an appropriate reaction? Respond in one line.` +\n ` If the action is to engage in dialogue, write:\\nSAY: \"what to say\"` +\n ` \\notherwise, write:\\nREACT: {agent_name}'s reaction (if anything).` +\n ` \\nEither do nothing, react, or say something but not both.\\n\\n`;\n\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n /**\n * Generates a dialogue response to the given observation.\n * @param observation The observation to generate a dialogue response for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateDialogueResponse(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate = `What would ${this.name} say? To end the conversation, write: GOODBYE: \"what to say\". Otherwise to continue the conversation, write: SAY: \"what to say next\"\\n\\n`;\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n // Agent stateful' summary methods\n // Each dialog or response prompt includes a header\n // summarizing the agent's self-description. This is\n // updated periodically through probing it's memories\n /**\n * Gets the agent's summary, which includes the agent's name, age, traits,\n * and a summary of the agent's core characteristics. The summary is\n * updated periodically through probing the agent's memories.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The agent's summary as a string.\n */\n async getSummary(\n config?: {\n now?: Date;\n forceRefresh?: boolean;\n },\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const { now = new Date(), forceRefresh = false } = config ?? {};\n\n const sinceRefresh = Math.floor(\n (now.getTime() - this.lastRefreshed.getTime()) / 1000\n );\n\n if (\n !this.summary ||\n sinceRefresh >= this.summaryRefreshSeconds ||\n forceRefresh\n ) {\n this.summary = await this.computeAgentSummary(runManager);\n this.lastRefreshed = now;\n }\n\n let age;\n if (this.age) {\n age = this.age;\n } else {\n age = \"N/A\";\n }\n\n return `Name: ${this.name} (age: ${age})\nInnate traits: ${this.traits}\n${this.summary}`;\n }\n\n /**\n * Computes the agent's summary by summarizing the agent's core\n * characteristics given the agent's relevant memories.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The computed summary as a string.\n */\n async computeAgentSummary(\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"How would you summarize {name}'s core characteristics given the following statements:\\n\" +\n \"----------\" +\n \"{relevant_memories}\" +\n \"----------\" +\n \"Do not embellish.\" +\n \"\\n\\nSummary: \"\n );\n // the agent seeks to think about their core characterisitics\n const result = await this.chain(prompt).call(\n {\n name: this.name,\n queries: [`${this.name}'s core characteristics`],\n },\n runManager?.getChild(\"compute_agent_summary\")\n );\n return result.output.trim();\n }\n\n /**\n * Returns a full header of the agent's status, summary, and current time.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @returns The full header as a string.\n */\n getFullHeader(\n config: {\n now?: Date;\n forceRefresh?: boolean;\n } = {}\n ): string {\n const { now = new Date(), forceRefresh = false } = config;\n // return a full header of the agent's status, summary, and current time.\n const summary = this.getSummary({ now, forceRefresh });\n const currentTimeString = now.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n return `${summary}\\nIt is ${currentTimeString}.\\n${this.name}'s status: ${this.status}`;\n }\n\n /**\n * Adds a memory to the agent's long-term memory.\n * @param memoryContent The content of the memory to add.\n * @param now Optional current date.\n * @param metadata Optional metadata for the memory.\n * @param callbacks Optional Callbacks instance.\n * @returns The result of adding the memory to the agent's long-term memory.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.longTermMemory.addMemory(\n memoryContent,\n now,\n metadata,\n callbacks\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generative_agent.js","names":[],"sources":["../../../src/experimental/generative_agents/generative_agent.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\nimport { GenerativeAgentMemory } from \"./generative_agent_memory.js\";\nimport { BaseChain } from \"../../chains/base.js\";\n\n/**\n * Configuration for the GenerativeAgent class. Defines the character's\n * name, optional age, permanent traits, status, verbosity, and summary\n * refresh seconds.\n */\nexport type GenerativeAgentConfig = {\n name: string;\n age?: number;\n traits: string;\n status: string;\n verbose?: boolean;\n summaryRefreshSeconds?: number;\n // dailySummaries?: string[];\n};\n\n/**\n * Implementation of a generative agent that can learn and form new memories over\n * time. It extends the BaseChain class, which is a generic\n * sequence of calls to components, including other chains.\n * @example\n * ```typescript\n * const tommie: GenerativeAgent = new GenerativeAgent(\n * new OpenAI({ temperature: 0.9, maxTokens: 1500 }),\n * new GenerativeAgentMemory(\n * new ChatOpenAI({ model: \"gpt-4o-mini\" }),\n * new TimeWeightedVectorStoreRetriever({\n * vectorStore: new MemoryVectorStore(new OpenAIEmbeddings()),\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * }),\n * { reflectionThreshold: 8 },\n * ),\n * {\n * name: \"Tommie\",\n * age: 25,\n * traits: \"anxious, likes design, talkative\",\n * status: \"looking for a job\",\n * },\n * );\n *\n * await tommie.addMemory(\n * \"Tommie remembers his dog, Bruno, from when he was a kid\",\n * new Date(),\n * );\n * const summary = await tommie.getSummary({ forceRefresh: true });\n * const response = await tommie.generateDialogueResponse(\n * \"USER says Hello Tommie, how are you today?\",\n * );\n * ```\n */\nexport class GenerativeAgent extends BaseChain {\n static lc_name() {\n return \"GenerativeAgent\";\n }\n\n // a character with memory and innate characterisitics\n name: string; // the character's name\n\n age?: number; // the optional age of the character\n\n traits: string; // permanent traits to ascribe to the character\n\n status: string; // the traits of the character you wish not to change\n\n longTermMemory: GenerativeAgentMemory;\n\n llm: BaseLanguageModelInterface; // the underlying language model\n\n verbose: boolean; // false\n\n private summary: string; // stateful self-summary generated via reflection on the character's memory.\n\n private summaryRefreshSeconds = 3600;\n\n private lastRefreshed: Date; // the last time the character's summary was regenerated\n\n // TODO: Add support for daily summaries\n // private dailySummaries: string[] = []; // summary of the events in the plan that the agent took.\n\n _chainType(): string {\n return \"generative_agent_executor\";\n }\n\n get inputKeys(): string[] {\n return [\"observation\", \"suffix\", \"now\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\", \"continue_dialogue\"];\n }\n\n constructor(\n llm: BaseLanguageModelInterface,\n longTermMemory: GenerativeAgentMemory,\n config: GenerativeAgentConfig\n ) {\n super();\n this.llm = llm;\n this.longTermMemory = longTermMemory;\n this.name = config.name;\n this.age = config.age;\n this.traits = config.traits;\n this.status = config.status;\n this.verbose = config.verbose ?? this.verbose;\n this.summary = \"\";\n this.summaryRefreshSeconds =\n config.summaryRefreshSeconds ?? this.summaryRefreshSeconds;\n this.lastRefreshed = new Date();\n // this.dailySummaries = config.dailySummaries ?? this.dailySummaries;\n }\n\n // LLM methods\n /**\n * Parses a newline-separated string into a list of strings.\n * @param text The string to parse.\n * @returns An array of strings parsed from the input text.\n */\n parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n const lines: string[] = text.trim().split(\"\\n\");\n const result: string[] = lines.map((line: string) =>\n line.replace(/^\\s*\\d+\\.\\s*/, \"\").trim()\n );\n return result;\n }\n\n /**\n * Creates a new LLMChain with the given prompt and the agent's language\n * model, verbosity, output key, and memory.\n * @param prompt The prompt to use for the LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\", // new\n memory: this.longTermMemory,\n });\n return chain;\n }\n\n /**\n * Extracts the observed entity from the given observation.\n * @param observation The observation to extract the entity from.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted entity as a string.\n */\n async getEntityFromObservations(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the observed entity in the following observation? {observation}\" +\n \"\\nEntity=\"\n );\n\n const result = await this.chain(prompt).call(\n {\n observation,\n },\n runManager?.getChild(\"entity_extractor\")\n );\n\n return result.output;\n }\n\n /**\n * Extracts the action of the given entity from the given observation.\n * @param observation The observation to extract the action from.\n * @param entityName The name of the entity to extract the action for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted action as a string.\n */\n async getEntityAction(\n observation: string,\n entityName: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the {entity} doing in the following observation? {observation}\" +\n \"\\nThe {entity} is\"\n );\n\n const result = await this.chain(prompt).call(\n {\n entity: entityName,\n observation,\n },\n runManager?.getChild(\"entity_action_extractor\")\n );\n const trimmedResult = result.output.trim();\n return trimmedResult;\n }\n\n /**\n * Summarizes memories that are most relevant to an observation.\n * @param observation The observation to summarize related memories for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The summarized memories as a string.\n */\n async summarizeRelatedMemories(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n // summarize memories that are most relevant to an observation\n const prompt = PromptTemplate.fromTemplate(\n `\n{q1}?\nContext from memory:\n{relevant_memories}\nRelevant context:`\n );\n const entityName = await this.getEntityFromObservations(\n observation,\n runManager\n );\n const entityAction = await this.getEntityAction(\n observation,\n entityName,\n runManager\n );\n const q1 = `What is the relationship between ${this.name} and ${entityName}`;\n const q2 = `${entityName} is ${entityAction}`;\n const response = await this.chain(prompt).call(\n {\n q1,\n queries: [q1, q2],\n },\n runManager?.getChild(\"entity_relationships\")\n );\n\n return response.output.trim(); // added output\n }\n\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n const { observation, suffix, now } = values;\n // react to a given observation or dialogue act\n const prompt = PromptTemplate.fromTemplate(\n `{agent_summary_description}` +\n `\\nIt is {current_time}.` +\n `\\n{agent_name}'s status: {agent_status}` +\n `\\nSummary of relevant context from {agent_name}'s memory:` +\n \"\\n{relevant_memories}\" +\n `\\nMost recent observations: {most_recent_memories}` +\n `\\nObservation: {observation}` +\n `\\n\\n${suffix}`\n );\n\n const agentSummaryDescription = await this.getSummary({}, runManager); // now = now in param\n const relevantMemoriesStr = await this.summarizeRelatedMemories(\n observation,\n runManager\n );\n const currentTime = (now || new Date()).toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n const chainInputs: ChainValues = {\n agent_summary_description: agentSummaryDescription,\n current_time: currentTime,\n agent_name: this.name,\n observation,\n agent_status: this.status,\n most_recent_memories: \"\",\n };\n\n chainInputs[this.longTermMemory.getRelevantMemoriesKey()] =\n relevantMemoriesStr;\n\n const consumedTokens = await this.llm.getNumTokens(\n await prompt.format({ ...chainInputs })\n );\n\n chainInputs[this.longTermMemory.getMostRecentMemoriesTokenKey()] =\n consumedTokens;\n const response = await this.chain(prompt).call(\n chainInputs,\n runManager?.getChild(\"reaction_from_summary\")\n );\n\n const rawOutput = response.output;\n let output = rawOutput;\n let continue_dialogue = false;\n\n if (rawOutput.includes(\"REACT:\")) {\n const reaction = this._cleanResponse(rawOutput.split(\"REACT:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and reacted by ${reaction}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${reaction}`;\n continue_dialogue = false;\n } else if (rawOutput.includes(\"SAY:\")) {\n const saidValue = this._cleanResponse(rawOutput.split(\"SAY:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and said ${saidValue}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${saidValue}`;\n continue_dialogue = true;\n } else if (rawOutput.includes(\"GOODBYE:\")) {\n const farewell = this._cleanResponse(\n rawOutput.split(\"GOODBYE:\").pop() ?? \"\"\n );\n await this.addMemory(\n `${this.name} observed ${observation} and said ${farewell}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${farewell}`;\n continue_dialogue = false;\n }\n\n return { output, continue_dialogue };\n }\n\n private _cleanResponse(text: string | undefined): string {\n if (text === undefined) {\n return \"\";\n }\n const regex = new RegExp(`^${this.name} `);\n return text.replace(regex, \"\").trim();\n }\n\n /**\n * Generates a reaction to the given observation.\n * @param observation The observation to generate a reaction for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateReaction(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate: string =\n `Should {agent_name} react to the observation, and if so,` +\n ` what would be an appropriate reaction? Respond in one line.` +\n ` If the action is to engage in dialogue, write:\\nSAY: \"what to say\"` +\n ` \\notherwise, write:\\nREACT: {agent_name}'s reaction (if anything).` +\n ` \\nEither do nothing, react, or say something but not both.\\n\\n`;\n\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n /**\n * Generates a dialogue response to the given observation.\n * @param observation The observation to generate a dialogue response for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateDialogueResponse(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate = `What would ${this.name} say? To end the conversation, write: GOODBYE: \"what to say\". Otherwise to continue the conversation, write: SAY: \"what to say next\"\\n\\n`;\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n // Agent stateful' summary methods\n // Each dialog or response prompt includes a header\n // summarizing the agent's self-description. This is\n // updated periodically through probing it's memories\n /**\n * Gets the agent's summary, which includes the agent's name, age, traits,\n * and a summary of the agent's core characteristics. The summary is\n * updated periodically through probing the agent's memories.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The agent's summary as a string.\n */\n async getSummary(\n config?: {\n now?: Date;\n forceRefresh?: boolean;\n },\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const { now = new Date(), forceRefresh = false } = config ?? {};\n\n const sinceRefresh = Math.floor(\n (now.getTime() - this.lastRefreshed.getTime()) / 1000\n );\n\n if (\n !this.summary ||\n sinceRefresh >= this.summaryRefreshSeconds ||\n forceRefresh\n ) {\n this.summary = await this.computeAgentSummary(runManager);\n this.lastRefreshed = now;\n }\n\n let age;\n if (this.age) {\n age = this.age;\n } else {\n age = \"N/A\";\n }\n\n return `Name: ${this.name} (age: ${age})\nInnate traits: ${this.traits}\n${this.summary}`;\n }\n\n /**\n * Computes the agent's summary by summarizing the agent's core\n * characteristics given the agent's relevant memories.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The computed summary as a string.\n */\n async computeAgentSummary(\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"How would you summarize {name}'s core characteristics given the following statements:\\n\" +\n \"----------\" +\n \"{relevant_memories}\" +\n \"----------\" +\n \"Do not embellish.\" +\n \"\\n\\nSummary: \"\n );\n // the agent seeks to think about their core characterisitics\n const result = await this.chain(prompt).call(\n {\n name: this.name,\n queries: [`${this.name}'s core characteristics`],\n },\n runManager?.getChild(\"compute_agent_summary\")\n );\n return result.output.trim();\n }\n\n /**\n * Returns a full header of the agent's status, summary, and current time.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @returns The full header as a string.\n */\n getFullHeader(\n config: {\n now?: Date;\n forceRefresh?: boolean;\n } = {}\n ): string {\n const { now = new Date(), forceRefresh = false } = config;\n // return a full header of the agent's status, summary, and current time.\n const summary = this.getSummary({ now, forceRefresh });\n const currentTimeString = now.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n return `${summary}\\nIt is ${currentTimeString}.\\n${this.name}'s status: ${this.status}`;\n }\n\n /**\n * Adds a memory to the agent's long-term memory.\n * @param memoryContent The content of the memory to add.\n * @param now Optional current date.\n * @param metadata Optional metadata for the memory.\n * @param callbacks Optional Callbacks instance.\n * @returns The result of adding the memory to the agent's long-term memory.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.longTermMemory.addMemory(\n memoryContent,\n now,\n metadata,\n callbacks\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generative_agent.js","names":[],"sources":["../../../src/experimental/generative_agents/generative_agent.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\nimport { GenerativeAgentMemory } from \"./generative_agent_memory.js\";\nimport { BaseChain } from \"../../chains/base.js\";\n\n/**\n * Configuration for the GenerativeAgent class. Defines the character's\n * name, optional age, permanent traits, status, verbosity, and summary\n * refresh seconds.\n */\nexport type GenerativeAgentConfig = {\n name: string;\n age?: number;\n traits: string;\n status: string;\n verbose?: boolean;\n summaryRefreshSeconds?: number;\n // dailySummaries?: string[];\n};\n\n/**\n * Implementation of a generative agent that can learn and form new memories over\n * time. It extends the BaseChain class, which is a generic\n * sequence of calls to components, including other chains.\n * @example\n * ```typescript\n * const tommie: GenerativeAgent = new GenerativeAgent(\n * new OpenAI({ temperature: 0.9, maxTokens: 1500 }),\n * new GenerativeAgentMemory(\n * new ChatOpenAI({ model: \"gpt-4o-mini\" }),\n * new TimeWeightedVectorStoreRetriever({\n * vectorStore: new MemoryVectorStore(new OpenAIEmbeddings()),\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * }),\n * { reflectionThreshold: 8 },\n * ),\n * {\n * name: \"Tommie\",\n * age: 25,\n * traits: \"anxious, likes design, talkative\",\n * status: \"looking for a job\",\n * },\n * );\n *\n * await tommie.addMemory(\n * \"Tommie remembers his dog, Bruno, from when he was a kid\",\n * new Date(),\n * );\n * const summary = await tommie.getSummary({ forceRefresh: true });\n * const response = await tommie.generateDialogueResponse(\n * \"USER says Hello Tommie, how are you today?\",\n * );\n * ```\n */\nexport class GenerativeAgent extends BaseChain {\n static lc_name() {\n return \"GenerativeAgent\";\n }\n\n // a character with memory and innate characterisitics\n name: string; // the character's name\n\n age?: number; // the optional age of the character\n\n traits: string; // permanent traits to ascribe to the character\n\n status: string; // the traits of the character you wish not to change\n\n longTermMemory: GenerativeAgentMemory;\n\n llm: BaseLanguageModelInterface; // the underlying language model\n\n verbose: boolean; // false\n\n private summary: string; // stateful self-summary generated via reflection on the character's memory.\n\n private summaryRefreshSeconds = 3600;\n\n private lastRefreshed: Date; // the last time the character's summary was regenerated\n\n // TODO: Add support for daily summaries\n // private dailySummaries: string[] = []; // summary of the events in the plan that the agent took.\n\n _chainType(): string {\n return \"generative_agent_executor\";\n }\n\n get inputKeys(): string[] {\n return [\"observation\", \"suffix\", \"now\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\", \"continue_dialogue\"];\n }\n\n constructor(\n llm: BaseLanguageModelInterface,\n longTermMemory: GenerativeAgentMemory,\n config: GenerativeAgentConfig\n ) {\n super();\n this.llm = llm;\n this.longTermMemory = longTermMemory;\n this.name = config.name;\n this.age = config.age;\n this.traits = config.traits;\n this.status = config.status;\n this.verbose = config.verbose ?? this.verbose;\n this.summary = \"\";\n this.summaryRefreshSeconds =\n config.summaryRefreshSeconds ?? this.summaryRefreshSeconds;\n this.lastRefreshed = new Date();\n // this.dailySummaries = config.dailySummaries ?? this.dailySummaries;\n }\n\n // LLM methods\n /**\n * Parses a newline-separated string into a list of strings.\n * @param text The string to parse.\n * @returns An array of strings parsed from the input text.\n */\n parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n const lines: string[] = text.trim().split(\"\\n\");\n const result: string[] = lines.map((line: string) =>\n line.replace(/^\\s*\\d+\\.\\s*/, \"\").trim()\n );\n return result;\n }\n\n /**\n * Creates a new LLMChain with the given prompt and the agent's language\n * model, verbosity, output key, and memory.\n * @param prompt The prompt to use for the LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\", // new\n memory: this.longTermMemory,\n });\n return chain;\n }\n\n /**\n * Extracts the observed entity from the given observation.\n * @param observation The observation to extract the entity from.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted entity as a string.\n */\n async getEntityFromObservations(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the observed entity in the following observation? {observation}\" +\n \"\\nEntity=\"\n );\n\n const result = await this.chain(prompt).call(\n {\n observation,\n },\n runManager?.getChild(\"entity_extractor\")\n );\n\n return result.output;\n }\n\n /**\n * Extracts the action of the given entity from the given observation.\n * @param observation The observation to extract the action from.\n * @param entityName The name of the entity to extract the action for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The extracted action as a string.\n */\n async getEntityAction(\n observation: string,\n entityName: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"What is the {entity} doing in the following observation? {observation}\" +\n \"\\nThe {entity} is\"\n );\n\n const result = await this.chain(prompt).call(\n {\n entity: entityName,\n observation,\n },\n runManager?.getChild(\"entity_action_extractor\")\n );\n const trimmedResult = result.output.trim();\n return trimmedResult;\n }\n\n /**\n * Summarizes memories that are most relevant to an observation.\n * @param observation The observation to summarize related memories for.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The summarized memories as a string.\n */\n async summarizeRelatedMemories(\n observation: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n // summarize memories that are most relevant to an observation\n const prompt = PromptTemplate.fromTemplate(\n `\n{q1}?\nContext from memory:\n{relevant_memories}\nRelevant context:`\n );\n const entityName = await this.getEntityFromObservations(\n observation,\n runManager\n );\n const entityAction = await this.getEntityAction(\n observation,\n entityName,\n runManager\n );\n const q1 = `What is the relationship between ${this.name} and ${entityName}`;\n const q2 = `${entityName} is ${entityAction}`;\n const response = await this.chain(prompt).call(\n {\n q1,\n queries: [q1, q2],\n },\n runManager?.getChild(\"entity_relationships\")\n );\n\n return response.output.trim(); // added output\n }\n\n async _call(\n values: ChainValues,\n runManager?: CallbackManagerForChainRun\n ): Promise<ChainValues> {\n const { observation, suffix, now } = values;\n // react to a given observation or dialogue act\n const prompt = PromptTemplate.fromTemplate(\n `{agent_summary_description}` +\n `\\nIt is {current_time}.` +\n `\\n{agent_name}'s status: {agent_status}` +\n `\\nSummary of relevant context from {agent_name}'s memory:` +\n \"\\n{relevant_memories}\" +\n `\\nMost recent observations: {most_recent_memories}` +\n `\\nObservation: {observation}` +\n `\\n\\n${suffix}`\n );\n\n const agentSummaryDescription = await this.getSummary({}, runManager); // now = now in param\n const relevantMemoriesStr = await this.summarizeRelatedMemories(\n observation,\n runManager\n );\n const currentTime = (now || new Date()).toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n const chainInputs: ChainValues = {\n agent_summary_description: agentSummaryDescription,\n current_time: currentTime,\n agent_name: this.name,\n observation,\n agent_status: this.status,\n most_recent_memories: \"\",\n };\n\n chainInputs[this.longTermMemory.getRelevantMemoriesKey()] =\n relevantMemoriesStr;\n\n const consumedTokens = await this.llm.getNumTokens(\n await prompt.format({ ...chainInputs })\n );\n\n chainInputs[this.longTermMemory.getMostRecentMemoriesTokenKey()] =\n consumedTokens;\n const response = await this.chain(prompt).call(\n chainInputs,\n runManager?.getChild(\"reaction_from_summary\")\n );\n\n const rawOutput = response.output;\n let output = rawOutput;\n let continue_dialogue = false;\n\n if (rawOutput.includes(\"REACT:\")) {\n const reaction = this._cleanResponse(rawOutput.split(\"REACT:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and reacted by ${reaction}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${reaction}`;\n continue_dialogue = false;\n } else if (rawOutput.includes(\"SAY:\")) {\n const saidValue = this._cleanResponse(rawOutput.split(\"SAY:\").pop());\n await this.addMemory(\n `${this.name} observed ${observation} and said ${saidValue}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${saidValue}`;\n continue_dialogue = true;\n } else if (rawOutput.includes(\"GOODBYE:\")) {\n const farewell = this._cleanResponse(\n rawOutput.split(\"GOODBYE:\").pop() ?? \"\"\n );\n await this.addMemory(\n `${this.name} observed ${observation} and said ${farewell}`,\n now,\n {},\n runManager?.getChild(\"memory\")\n );\n output = `${this.name} said ${farewell}`;\n continue_dialogue = false;\n }\n\n return { output, continue_dialogue };\n }\n\n private _cleanResponse(text: string | undefined): string {\n if (text === undefined) {\n return \"\";\n }\n const regex = new RegExp(`^${this.name} `);\n return text.replace(regex, \"\").trim();\n }\n\n /**\n * Generates a reaction to the given observation.\n * @param observation The observation to generate a reaction for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateReaction(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate: string =\n `Should {agent_name} react to the observation, and if so,` +\n ` what would be an appropriate reaction? Respond in one line.` +\n ` If the action is to engage in dialogue, write:\\nSAY: \"what to say\"` +\n ` \\notherwise, write:\\nREACT: {agent_name}'s reaction (if anything).` +\n ` \\nEither do nothing, react, or say something but not both.\\n\\n`;\n\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n /**\n * Generates a dialogue response to the given observation.\n * @param observation The observation to generate a dialogue response for.\n * @param now Optional current date.\n * @returns A boolean indicating whether to continue the dialogue and the output string.\n */\n async generateDialogueResponse(\n observation: string,\n now?: Date\n ): Promise<[boolean, string]> {\n const callToActionTemplate = `What would ${this.name} say? To end the conversation, write: GOODBYE: \"what to say\". Otherwise to continue the conversation, write: SAY: \"what to say next\"\\n\\n`;\n const { output, continue_dialogue } = await this.call({\n observation,\n suffix: callToActionTemplate,\n now,\n });\n return [continue_dialogue, output];\n }\n\n // Agent stateful' summary methods\n // Each dialog or response prompt includes a header\n // summarizing the agent's self-description. This is\n // updated periodically through probing it's memories\n /**\n * Gets the agent's summary, which includes the agent's name, age, traits,\n * and a summary of the agent's core characteristics. The summary is\n * updated periodically through probing the agent's memories.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The agent's summary as a string.\n */\n async getSummary(\n config?: {\n now?: Date;\n forceRefresh?: boolean;\n },\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const { now = new Date(), forceRefresh = false } = config ?? {};\n\n const sinceRefresh = Math.floor(\n (now.getTime() - this.lastRefreshed.getTime()) / 1000\n );\n\n if (\n !this.summary ||\n sinceRefresh >= this.summaryRefreshSeconds ||\n forceRefresh\n ) {\n this.summary = await this.computeAgentSummary(runManager);\n this.lastRefreshed = now;\n }\n\n let age;\n if (this.age) {\n age = this.age;\n } else {\n age = \"N/A\";\n }\n\n return `Name: ${this.name} (age: ${age})\nInnate traits: ${this.traits}\n${this.summary}`;\n }\n\n /**\n * Computes the agent's summary by summarizing the agent's core\n * characteristics given the agent's relevant memories.\n * @param runManager Optional CallbackManagerForChainRun instance.\n * @returns The computed summary as a string.\n */\n async computeAgentSummary(\n runManager?: CallbackManagerForChainRun\n ): Promise<string> {\n const prompt = PromptTemplate.fromTemplate(\n \"How would you summarize {name}'s core characteristics given the following statements:\\n\" +\n \"----------\" +\n \"{relevant_memories}\" +\n \"----------\" +\n \"Do not embellish.\" +\n \"\\n\\nSummary: \"\n );\n // the agent seeks to think about their core characterisitics\n const result = await this.chain(prompt).call(\n {\n name: this.name,\n queries: [`${this.name}'s core characteristics`],\n },\n runManager?.getChild(\"compute_agent_summary\")\n );\n return result.output.trim();\n }\n\n /**\n * Returns a full header of the agent's status, summary, and current time.\n * @param config Optional configuration object with current date and a boolean to force refresh.\n * @returns The full header as a string.\n */\n getFullHeader(\n config: {\n now?: Date;\n forceRefresh?: boolean;\n } = {}\n ): string {\n const { now = new Date(), forceRefresh = false } = config;\n // return a full header of the agent's status, summary, and current time.\n const summary = this.getSummary({ now, forceRefresh });\n const currentTimeString = now.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n return `${summary}\\nIt is ${currentTimeString}.\\n${this.name}'s status: ${this.status}`;\n }\n\n /**\n * Adds a memory to the agent's long-term memory.\n * @param memoryContent The content of the memory to add.\n * @param now Optional current date.\n * @param metadata Optional metadata for the memory.\n * @param callbacks Optional Callbacks instance.\n * @returns The result of adding the memory to the agent's long-term memory.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.longTermMemory.addMemory(\n memoryContent,\n now,\n metadata,\n callbacks\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generative_agent_memory.cjs","names":["BaseChain","LLMChain","Document","PromptTemplate","BaseMemory"],"sources":["../../../src/experimental/generative_agents/generative_agent_memory.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { Document } from \"@langchain/core/documents\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { BaseMemory, InputValues, OutputValues } from \"@langchain/core/memory\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { TimeWeightedVectorStoreRetriever } from \"../../retrievers/time_weighted.js\";\nimport { BaseChain } from \"../../chains/base.js\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\n\nexport type GenerativeAgentMemoryConfig = {\n reflectionThreshold?: number;\n importanceWeight?: number;\n verbose?: boolean;\n maxTokensLimit?: number;\n};\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseChain` class and has methods for adding observations\n * or memories to the agent's memory, scoring the importance of a memory,\n * reflecting on recent events to add synthesized memories, and generating\n * insights on a topic of reflection based on pertinent memories.\n */\nclass GenerativeAgentMemoryChain extends BaseChain {\n static lc_name() {\n return \"GenerativeAgentMemoryChain\";\n }\n\n reflecting = false;\n\n reflectionThreshold?: number;\n\n importanceWeight = 0.15;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n llm: BaseLanguageModelInterface;\n\n verbose = false;\n\n private aggregateImportance = 0.0;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config: Omit<GenerativeAgentMemoryConfig, \"maxTokensLimit\">\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.reflectionThreshold = config.reflectionThreshold;\n this.importanceWeight = config.importanceWeight ?? this.importanceWeight;\n this.verbose = config.verbose ?? this.verbose;\n }\n\n _chainType(): string {\n return \"generative_agent_memory\";\n }\n\n get inputKeys(): string[] {\n return [\"memory_content\", \"now\", \"memory_metadata\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\"];\n }\n\n /**\n * Method that creates a new LLMChain with the given prompt.\n * @param prompt The PromptTemplate to use for the new LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\",\n });\n return chain;\n }\n\n async _call(values: ChainValues, runManager?: CallbackManagerForChainRun) {\n const { memory_content: memoryContent, now } = values;\n // add an observation or memory to the agent's memory\n const importanceScore = await this.scoreMemoryImportance(\n memoryContent,\n runManager\n );\n this.aggregateImportance += importanceScore;\n const document = new Document({\n pageContent: memoryContent,\n metadata: {\n importance: importanceScore,\n ...values.memory_metadata,\n },\n });\n await this.memoryRetriever.addDocuments([document]);\n // after an agent has processed a certain amount of memories (as measured by aggregate importance),\n // it is time to pause and reflect on recent events to add more synthesized memories to the agent's\n // memory stream.\n if (\n this.reflectionThreshold !== undefined &&\n this.aggregateImportance > this.reflectionThreshold &&\n !this.reflecting\n ) {\n console.log(\"Reflecting on current memories...\");\n this.reflecting = true;\n await this.pauseToReflect(now, runManager);\n this.aggregateImportance = 0.0;\n this.reflecting = false;\n }\n return { output: importanceScore };\n }\n\n /**\n * Method that pauses the agent to reflect on recent events and generate\n * new insights.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for the reflection.\n * @returns An array of new insights as strings.\n */\n async pauseToReflect(\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n if (this.verbose) {\n console.log(\"Pausing to reflect...\");\n }\n const newInsights: string[] = [];\n const topics = await this.getTopicsOfReflection(50, runManager);\n for (const topic of topics) {\n const insights = await this.getInsightsOnTopic(topic, now, runManager);\n for (const insight of insights) {\n // add memory\n await this.call(\n {\n memory_content: insight,\n now,\n memory_metadata: {\n source: \"reflection_insight\",\n },\n },\n runManager?.getChild(\"reflection_insight_memory\")\n );\n }\n newInsights.push(...insights);\n }\n return newInsights;\n }\n\n /**\n * Method that scores the importance of a given memory.\n * @param memoryContent The content of the memory to score.\n * @param runManager The CallbackManagerForChainRun to use for scoring.\n * @returns The importance score of the memory as a number.\n */\n async scoreMemoryImportance(\n memoryContent: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<number> {\n // score the absolute importance of a given memory\n const prompt = PromptTemplate.fromTemplate(\n \"On the scale of 1 to 10, where 1 is purely mundane\" +\n \" (e.g., brushing teeth, making bed) and 10 is\" +\n \" extremely poignant (e.g., a break up, college\" +\n \" acceptance), rate the likely poignancy of the\" +\n \" following piece of memory. Respond with a single integer.\" +\n \"\\nMemory: {memory_content}\" +\n \"\\nRating: \"\n );\n const score = await this.chain(prompt).run(\n memoryContent,\n runManager?.getChild(\"determine_importance\")\n );\n\n const strippedScore = score.trim();\n\n if (this.verbose) {\n console.log(\"Importance score:\", strippedScore);\n }\n const match = strippedScore.match(/^\\D*(\\d+)/);\n if (match) {\n const capturedNumber = parseFloat(match[1]);\n const result = (capturedNumber / 10) * this.importanceWeight;\n return result;\n } else {\n return 0.0;\n }\n }\n\n /**\n * Method that retrieves the topics of reflection based on the last K\n * memories.\n * @param lastK The number of most recent memories to consider for generating topics.\n * @param runManager The CallbackManagerForChainRun to use for retrieving topics.\n * @returns An array of topics of reflection as strings.\n */\n async getTopicsOfReflection(\n lastK: number,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n const prompt = PromptTemplate.fromTemplate(\n \"{observations}\\n\\n\" +\n \"Given only the information above, what are the 3 most salient\" +\n \" high-level questions we can answer about the subjects in\" +\n \" the statements? Provide each question on a new line.\\n\\n\"\n );\n\n const observations = this.memoryRetriever.getMemoryStream().slice(-lastK);\n const observationStr = observations\n .map((o: { pageContent: string }) => o.pageContent)\n .join(\"\\n\");\n const result = await this.chain(prompt).run(\n observationStr,\n runManager?.getChild(\"reflection_topics\")\n );\n return GenerativeAgentMemoryChain.parseList(result);\n }\n\n /**\n * Method that generates insights on a given topic of reflection based on\n * pertinent memories.\n * @param topic The topic of reflection.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for generating insights.\n * @returns An array of insights as strings.\n */\n async getInsightsOnTopic(\n topic: string,\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n // generate insights on a topic of reflection, based on pertinent memories\n const prompt = PromptTemplate.fromTemplate(\n \"Statements about {topic}\\n\" +\n \"{related_statements}\\n\\n\" +\n \"What 5 high-level insights can you infer from the above statements?\" +\n \" (example format: insight (because of 1, 5, 3))\"\n );\n\n const relatedMemories = await this.fetchMemories(topic, now, runManager);\n const relatedStatements: string = relatedMemories\n .map((memory, index) => `${index + 1}. ${memory.pageContent}`)\n .join(\"\\n\");\n const result = await this.chain(prompt).call(\n {\n topic,\n related_statements: relatedStatements,\n },\n runManager?.getChild(\"reflection_insights\")\n );\n return GenerativeAgentMemoryChain.parseList(result.output); // added output\n }\n\n /**\n * Method that parses a newline-separated string into a list of strings.\n * @param text The newline-separated string to parse.\n * @returns An array of strings.\n */\n static parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n return text.split(\"\\n\").map((s) => s.trim());\n }\n\n // TODO: Mock \"now\" to simulate different times\n /**\n * Method that fetches memories related to a given observation.\n * @param observation The observation to fetch memories for.\n * @param _now The current date.\n * @param runManager The CallbackManagerForChainRun to use for fetching memories.\n * @returns An array of Document instances representing the fetched memories.\n */\n async fetchMemories(\n observation: string,\n _now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<Document[]> {\n return this.memoryRetriever.invoke(\n observation,\n runManager?.getChild(\"memory_retriever\")\n );\n }\n}\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseMemory` class and has methods for adding a memory,\n * formatting memories, getting memories until a token limit is reached,\n * loading memory variables, saving the context of a model run to memory,\n * and clearing memory contents.\n * @example\n * ```typescript\n * const createNewMemoryRetriever = async () => {\n * const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());\n * const retriever = new TimeWeightedVectorStoreRetriever({\n * vectorStore,\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * });\n * return retriever;\n * };\n * const tommiesMemory = new GenerativeAgentMemory(\n * llm,\n * await createNewMemoryRetriever(),\n * { reflectionThreshold: 8 },\n * );\n * const summary = await tommiesMemory.getSummary();\n * ```\n */\nexport class GenerativeAgentMemory extends BaseMemory {\n llm: BaseLanguageModelInterface;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n verbose: boolean;\n\n reflectionThreshold?: number;\n\n private maxTokensLimit = 1200;\n\n queriesKey = \"queries\";\n\n mostRecentMemoriesTokenKey = \"recent_memories_token\";\n\n addMemoryKey = \"addMemory\";\n\n relevantMemoriesKey = \"relevant_memories\";\n\n relevantMemoriesSimpleKey = \"relevant_memories_simple\";\n\n mostRecentMemoriesKey = \"most_recent_memories\";\n\n nowKey = \"now\";\n\n memoryChain: GenerativeAgentMemoryChain;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config?: GenerativeAgentMemoryConfig\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.verbose = config?.verbose ?? this.verbose;\n this.reflectionThreshold =\n config?.reflectionThreshold ?? this.reflectionThreshold;\n this.maxTokensLimit = config?.maxTokensLimit ?? this.maxTokensLimit;\n this.memoryChain = new GenerativeAgentMemoryChain(llm, memoryRetriever, {\n reflectionThreshold: config?.reflectionThreshold,\n importanceWeight: config?.importanceWeight,\n });\n }\n\n /**\n * Method that returns the key for relevant memories.\n * @returns The key for relevant memories as a string.\n */\n getRelevantMemoriesKey(): string {\n return this.relevantMemoriesKey;\n }\n\n /**\n * Method that returns the key for the most recent memories token.\n * @returns The key for the most recent memories token as a string.\n */\n getMostRecentMemoriesTokenKey(): string {\n return this.mostRecentMemoriesTokenKey;\n }\n\n /**\n * Method that returns the key for adding a memory.\n * @returns The key for adding a memory as a string.\n */\n getAddMemoryKey(): string {\n return this.addMemoryKey;\n }\n\n /**\n * Method that returns the key for the current time.\n * @returns The key for the current time as a string.\n */\n getCurrentTimeKey(): string {\n return this.nowKey;\n }\n\n get memoryKeys(): string[] {\n // Return an array of memory keys\n return [this.relevantMemoriesKey, this.mostRecentMemoriesKey];\n }\n\n /**\n * Method that adds a memory to the agent's memory.\n * @param memoryContent The content of the memory to add.\n * @param now The current date.\n * @param metadata The metadata for the memory.\n * @param callbacks The Callbacks to use for adding the memory.\n * @returns The result of the memory addition.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.memoryChain.call(\n { memory_content: memoryContent, now, memory_metadata: metadata },\n callbacks\n );\n }\n\n /**\n * Method that formats the given relevant memories in detail.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesDetail(relevantMemories: Document[]): string {\n if (!relevantMemories.length) {\n return \"No relevant information.\";\n }\n const contentStrings = new Set();\n const content = [];\n for (const memory of relevantMemories) {\n if (memory.pageContent in contentStrings) {\n continue;\n }\n contentStrings.add(memory.pageContent);\n const createdTime = memory.metadata.created_at.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n content.push(`${createdTime}: ${memory.pageContent.trim()}`);\n }\n const joinedContent = content.map((mem) => `${mem}`).join(\"\\n\");\n return joinedContent;\n }\n\n /**\n * Method that formats the given relevant memories in a simple manner.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesSimple(relevantMemories: Document[]): string {\n const joinedContent = relevantMemories\n .map((mem) => `${mem.pageContent}`)\n .join(\"; \");\n return joinedContent;\n }\n\n /**\n * Method that retrieves memories until a token limit is reached.\n * @param consumedTokens The number of tokens consumed so far.\n * @returns The memories as a string.\n */\n async getMemoriesUntilLimit(consumedTokens: number): Promise<string> {\n // reduce the number of tokens in the documents\n const result = [];\n for (const doc of this.memoryRetriever\n .getMemoryStream()\n .slice()\n .reverse()) {\n if (consumedTokens >= this.maxTokensLimit) {\n if (this.verbose) {\n console.log(\"Exceeding max tokens for LLM, filtering memories\");\n }\n break;\n }\n // oxlint-disable-next-line no-param-reassign\n consumedTokens += await this.llm.getNumTokens(doc.pageContent);\n if (consumedTokens < this.maxTokensLimit) {\n result.push(doc);\n }\n }\n return this.formatMemoriesSimple(result);\n }\n\n get memoryVariables(): string[] {\n // input keys this memory class will load dynamically\n return [];\n }\n\n /**\n * Method that loads memory variables based on the given inputs.\n * @param inputs The inputs to use for loading memory variables.\n * @returns An object containing the loaded memory variables.\n */\n async loadMemoryVariables(\n inputs: InputValues\n ): Promise<Record<string, string>> {\n const queries = inputs[this.queriesKey];\n const now = inputs[this.nowKey];\n if (queries !== undefined) {\n const relevantMemories = (\n await Promise.all(\n queries.map((query: string) =>\n this.memoryChain.fetchMemories(query, now)\n )\n )\n ).flat();\n return {\n [this.relevantMemoriesKey]: this.formatMemoriesDetail(relevantMemories),\n [this.relevantMemoriesSimpleKey]:\n this.formatMemoriesSimple(relevantMemories),\n };\n }\n const mostRecentMemoriesToken = inputs[this.mostRecentMemoriesTokenKey];\n if (mostRecentMemoriesToken !== undefined) {\n return {\n [this.mostRecentMemoriesKey]: await this.getMemoriesUntilLimit(\n mostRecentMemoriesToken\n ),\n };\n }\n return {};\n }\n\n /**\n * Method that saves the context of a model run to memory.\n * @param _inputs The inputs of the model run.\n * @param outputs The outputs of the model run.\n * @returns Nothing.\n */\n async saveContext(\n _inputs: InputValues,\n outputs: OutputValues\n ): Promise<void> {\n // save the context of this model run to memory\n const mem = outputs[this.addMemoryKey];\n const now = outputs[this.nowKey];\n if (mem) {\n await this.addMemory(mem, now, {});\n }\n }\n\n /**\n * Method that clears the memory contents.\n * @returns Nothing.\n */\n clear(): void {\n // TODO: clear memory contents\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generative_agent_memory.cjs","names":["BaseChain","LLMChain","Document","PromptTemplate","BaseMemory"],"sources":["../../../src/experimental/generative_agents/generative_agent_memory.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { Document } from \"@langchain/core/documents\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { BaseMemory, InputValues, OutputValues } from \"@langchain/core/memory\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { TimeWeightedVectorStoreRetriever } from \"../../retrievers/time_weighted.js\";\nimport { BaseChain } from \"../../chains/base.js\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\n\nexport type GenerativeAgentMemoryConfig = {\n reflectionThreshold?: number;\n importanceWeight?: number;\n verbose?: boolean;\n maxTokensLimit?: number;\n};\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseChain` class and has methods for adding observations\n * or memories to the agent's memory, scoring the importance of a memory,\n * reflecting on recent events to add synthesized memories, and generating\n * insights on a topic of reflection based on pertinent memories.\n */\nclass GenerativeAgentMemoryChain extends BaseChain {\n static lc_name() {\n return \"GenerativeAgentMemoryChain\";\n }\n\n reflecting = false;\n\n reflectionThreshold?: number;\n\n importanceWeight = 0.15;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n llm: BaseLanguageModelInterface;\n\n verbose = false;\n\n private aggregateImportance = 0.0;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config: Omit<GenerativeAgentMemoryConfig, \"maxTokensLimit\">\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.reflectionThreshold = config.reflectionThreshold;\n this.importanceWeight = config.importanceWeight ?? this.importanceWeight;\n this.verbose = config.verbose ?? this.verbose;\n }\n\n _chainType(): string {\n return \"generative_agent_memory\";\n }\n\n get inputKeys(): string[] {\n return [\"memory_content\", \"now\", \"memory_metadata\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\"];\n }\n\n /**\n * Method that creates a new LLMChain with the given prompt.\n * @param prompt The PromptTemplate to use for the new LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\",\n });\n return chain;\n }\n\n async _call(values: ChainValues, runManager?: CallbackManagerForChainRun) {\n const { memory_content: memoryContent, now } = values;\n // add an observation or memory to the agent's memory\n const importanceScore = await this.scoreMemoryImportance(\n memoryContent,\n runManager\n );\n this.aggregateImportance += importanceScore;\n const document = new Document({\n pageContent: memoryContent,\n metadata: {\n importance: importanceScore,\n ...values.memory_metadata,\n },\n });\n await this.memoryRetriever.addDocuments([document]);\n // after an agent has processed a certain amount of memories (as measured by aggregate importance),\n // it is time to pause and reflect on recent events to add more synthesized memories to the agent's\n // memory stream.\n if (\n this.reflectionThreshold !== undefined &&\n this.aggregateImportance > this.reflectionThreshold &&\n !this.reflecting\n ) {\n console.log(\"Reflecting on current memories...\");\n this.reflecting = true;\n await this.pauseToReflect(now, runManager);\n this.aggregateImportance = 0.0;\n this.reflecting = false;\n }\n return { output: importanceScore };\n }\n\n /**\n * Method that pauses the agent to reflect on recent events and generate\n * new insights.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for the reflection.\n * @returns An array of new insights as strings.\n */\n async pauseToReflect(\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n if (this.verbose) {\n console.log(\"Pausing to reflect...\");\n }\n const newInsights: string[] = [];\n const topics = await this.getTopicsOfReflection(50, runManager);\n for (const topic of topics) {\n const insights = await this.getInsightsOnTopic(topic, now, runManager);\n for (const insight of insights) {\n // add memory\n await this.call(\n {\n memory_content: insight,\n now,\n memory_metadata: {\n source: \"reflection_insight\",\n },\n },\n runManager?.getChild(\"reflection_insight_memory\")\n );\n }\n newInsights.push(...insights);\n }\n return newInsights;\n }\n\n /**\n * Method that scores the importance of a given memory.\n * @param memoryContent The content of the memory to score.\n * @param runManager The CallbackManagerForChainRun to use for scoring.\n * @returns The importance score of the memory as a number.\n */\n async scoreMemoryImportance(\n memoryContent: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<number> {\n // score the absolute importance of a given memory\n const prompt = PromptTemplate.fromTemplate(\n \"On the scale of 1 to 10, where 1 is purely mundane\" +\n \" (e.g., brushing teeth, making bed) and 10 is\" +\n \" extremely poignant (e.g., a break up, college\" +\n \" acceptance), rate the likely poignancy of the\" +\n \" following piece of memory. Respond with a single integer.\" +\n \"\\nMemory: {memory_content}\" +\n \"\\nRating: \"\n );\n const score = await this.chain(prompt).run(\n memoryContent,\n runManager?.getChild(\"determine_importance\")\n );\n\n const strippedScore = score.trim();\n\n if (this.verbose) {\n console.log(\"Importance score:\", strippedScore);\n }\n const match = strippedScore.match(/^\\D*(\\d+)/);\n if (match) {\n const capturedNumber = parseFloat(match[1]);\n const result = (capturedNumber / 10) * this.importanceWeight;\n return result;\n } else {\n return 0.0;\n }\n }\n\n /**\n * Method that retrieves the topics of reflection based on the last K\n * memories.\n * @param lastK The number of most recent memories to consider for generating topics.\n * @param runManager The CallbackManagerForChainRun to use for retrieving topics.\n * @returns An array of topics of reflection as strings.\n */\n async getTopicsOfReflection(\n lastK: number,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n const prompt = PromptTemplate.fromTemplate(\n \"{observations}\\n\\n\" +\n \"Given only the information above, what are the 3 most salient\" +\n \" high-level questions we can answer about the subjects in\" +\n \" the statements? Provide each question on a new line.\\n\\n\"\n );\n\n const observations = this.memoryRetriever.getMemoryStream().slice(-lastK);\n const observationStr = observations\n .map((o: { pageContent: string }) => o.pageContent)\n .join(\"\\n\");\n const result = await this.chain(prompt).run(\n observationStr,\n runManager?.getChild(\"reflection_topics\")\n );\n return GenerativeAgentMemoryChain.parseList(result);\n }\n\n /**\n * Method that generates insights on a given topic of reflection based on\n * pertinent memories.\n * @param topic The topic of reflection.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for generating insights.\n * @returns An array of insights as strings.\n */\n async getInsightsOnTopic(\n topic: string,\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n // generate insights on a topic of reflection, based on pertinent memories\n const prompt = PromptTemplate.fromTemplate(\n \"Statements about {topic}\\n\" +\n \"{related_statements}\\n\\n\" +\n \"What 5 high-level insights can you infer from the above statements?\" +\n \" (example format: insight (because of 1, 5, 3))\"\n );\n\n const relatedMemories = await this.fetchMemories(topic, now, runManager);\n const relatedStatements: string = relatedMemories\n .map((memory, index) => `${index + 1}. ${memory.pageContent}`)\n .join(\"\\n\");\n const result = await this.chain(prompt).call(\n {\n topic,\n related_statements: relatedStatements,\n },\n runManager?.getChild(\"reflection_insights\")\n );\n return GenerativeAgentMemoryChain.parseList(result.output); // added output\n }\n\n /**\n * Method that parses a newline-separated string into a list of strings.\n * @param text The newline-separated string to parse.\n * @returns An array of strings.\n */\n static parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n return text.split(\"\\n\").map((s) => s.trim());\n }\n\n // TODO: Mock \"now\" to simulate different times\n /**\n * Method that fetches memories related to a given observation.\n * @param observation The observation to fetch memories for.\n * @param _now The current date.\n * @param runManager The CallbackManagerForChainRun to use for fetching memories.\n * @returns An array of Document instances representing the fetched memories.\n */\n async fetchMemories(\n observation: string,\n _now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<Document[]> {\n return this.memoryRetriever.invoke(\n observation,\n runManager?.getChild(\"memory_retriever\")\n );\n }\n}\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseMemory` class and has methods for adding a memory,\n * formatting memories, getting memories until a token limit is reached,\n * loading memory variables, saving the context of a model run to memory,\n * and clearing memory contents.\n * @example\n * ```typescript\n * const createNewMemoryRetriever = async () => {\n * const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());\n * const retriever = new TimeWeightedVectorStoreRetriever({\n * vectorStore,\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * });\n * return retriever;\n * };\n * const tommiesMemory = new GenerativeAgentMemory(\n * llm,\n * await createNewMemoryRetriever(),\n * { reflectionThreshold: 8 },\n * );\n * const summary = await tommiesMemory.getSummary();\n * ```\n */\nexport class GenerativeAgentMemory extends BaseMemory {\n llm: BaseLanguageModelInterface;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n verbose: boolean;\n\n reflectionThreshold?: number;\n\n private maxTokensLimit = 1200;\n\n queriesKey = \"queries\";\n\n mostRecentMemoriesTokenKey = \"recent_memories_token\";\n\n addMemoryKey = \"addMemory\";\n\n relevantMemoriesKey = \"relevant_memories\";\n\n relevantMemoriesSimpleKey = \"relevant_memories_simple\";\n\n mostRecentMemoriesKey = \"most_recent_memories\";\n\n nowKey = \"now\";\n\n memoryChain: GenerativeAgentMemoryChain;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config?: GenerativeAgentMemoryConfig\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.verbose = config?.verbose ?? this.verbose;\n this.reflectionThreshold =\n config?.reflectionThreshold ?? this.reflectionThreshold;\n this.maxTokensLimit = config?.maxTokensLimit ?? this.maxTokensLimit;\n this.memoryChain = new GenerativeAgentMemoryChain(llm, memoryRetriever, {\n reflectionThreshold: config?.reflectionThreshold,\n importanceWeight: config?.importanceWeight,\n });\n }\n\n /**\n * Method that returns the key for relevant memories.\n * @returns The key for relevant memories as a string.\n */\n getRelevantMemoriesKey(): string {\n return this.relevantMemoriesKey;\n }\n\n /**\n * Method that returns the key for the most recent memories token.\n * @returns The key for the most recent memories token as a string.\n */\n getMostRecentMemoriesTokenKey(): string {\n return this.mostRecentMemoriesTokenKey;\n }\n\n /**\n * Method that returns the key for adding a memory.\n * @returns The key for adding a memory as a string.\n */\n getAddMemoryKey(): string {\n return this.addMemoryKey;\n }\n\n /**\n * Method that returns the key for the current time.\n * @returns The key for the current time as a string.\n */\n getCurrentTimeKey(): string {\n return this.nowKey;\n }\n\n get memoryKeys(): string[] {\n // Return an array of memory keys\n return [this.relevantMemoriesKey, this.mostRecentMemoriesKey];\n }\n\n /**\n * Method that adds a memory to the agent's memory.\n * @param memoryContent The content of the memory to add.\n * @param now The current date.\n * @param metadata The metadata for the memory.\n * @param callbacks The Callbacks to use for adding the memory.\n * @returns The result of the memory addition.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.memoryChain.call(\n { memory_content: memoryContent, now, memory_metadata: metadata },\n callbacks\n );\n }\n\n /**\n * Method that formats the given relevant memories in detail.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesDetail(relevantMemories: Document[]): string {\n if (!relevantMemories.length) {\n return \"No relevant information.\";\n }\n const contentStrings = new Set();\n const content = [];\n for (const memory of relevantMemories) {\n if (memory.pageContent in contentStrings) {\n continue;\n }\n contentStrings.add(memory.pageContent);\n const createdTime = memory.metadata.created_at.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n content.push(`${createdTime}: ${memory.pageContent.trim()}`);\n }\n const joinedContent = content.map((mem) => `${mem}`).join(\"\\n\");\n return joinedContent;\n }\n\n /**\n * Method that formats the given relevant memories in a simple manner.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesSimple(relevantMemories: Document[]): string {\n const joinedContent = relevantMemories\n .map((mem) => `${mem.pageContent}`)\n .join(\"; \");\n return joinedContent;\n }\n\n /**\n * Method that retrieves memories until a token limit is reached.\n * @param consumedTokens The number of tokens consumed so far.\n * @returns The memories as a string.\n */\n async getMemoriesUntilLimit(consumedTokens: number): Promise<string> {\n // reduce the number of tokens in the documents\n const result = [];\n for (const doc of this.memoryRetriever\n .getMemoryStream()\n .slice()\n .reverse()) {\n if (consumedTokens >= this.maxTokensLimit) {\n if (this.verbose) {\n console.log(\"Exceeding max tokens for LLM, filtering memories\");\n }\n break;\n }\n // oxlint-disable-next-line no-param-reassign\n consumedTokens += await this.llm.getNumTokens(doc.pageContent);\n if (consumedTokens < this.maxTokensLimit) {\n result.push(doc);\n }\n }\n return this.formatMemoriesSimple(result);\n }\n\n get memoryVariables(): string[] {\n // input keys this memory class will load dynamically\n return [];\n }\n\n /**\n * Method that loads memory variables based on the given inputs.\n * @param inputs The inputs to use for loading memory variables.\n * @returns An object containing the loaded memory variables.\n */\n async loadMemoryVariables(\n inputs: InputValues\n ): Promise<Record<string, string>> {\n const queries = inputs[this.queriesKey];\n const now = inputs[this.nowKey];\n if (queries !== undefined) {\n const relevantMemories = (\n await Promise.all(\n queries.map((query: string) =>\n this.memoryChain.fetchMemories(query, now)\n )\n )\n ).flat();\n return {\n [this.relevantMemoriesKey]: this.formatMemoriesDetail(relevantMemories),\n [this.relevantMemoriesSimpleKey]:\n this.formatMemoriesSimple(relevantMemories),\n };\n }\n const mostRecentMemoriesToken = inputs[this.mostRecentMemoriesTokenKey];\n if (mostRecentMemoriesToken !== undefined) {\n return {\n [this.mostRecentMemoriesKey]: await this.getMemoriesUntilLimit(\n mostRecentMemoriesToken\n ),\n };\n }\n return {};\n }\n\n /**\n * Method that saves the context of a model run to memory.\n * @param _inputs The inputs of the model run.\n * @param outputs The outputs of the model run.\n * @returns Nothing.\n */\n async saveContext(\n _inputs: InputValues,\n outputs: OutputValues\n ): Promise<void> {\n // save the context of this model run to memory\n const mem = outputs[this.addMemoryKey];\n const now = outputs[this.nowKey];\n if (mem) {\n await this.addMemory(mem, now, {});\n }\n }\n\n /**\n * Method that clears the memory contents.\n * @returns Nothing.\n */\n clear(): void {\n // TODO: clear memory contents\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generative_agent_memory.js","names":[],"sources":["../../../src/experimental/generative_agents/generative_agent_memory.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { Document } from \"@langchain/core/documents\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { BaseMemory, InputValues, OutputValues } from \"@langchain/core/memory\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { TimeWeightedVectorStoreRetriever } from \"../../retrievers/time_weighted.js\";\nimport { BaseChain } from \"../../chains/base.js\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\n\nexport type GenerativeAgentMemoryConfig = {\n reflectionThreshold?: number;\n importanceWeight?: number;\n verbose?: boolean;\n maxTokensLimit?: number;\n};\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseChain` class and has methods for adding observations\n * or memories to the agent's memory, scoring the importance of a memory,\n * reflecting on recent events to add synthesized memories, and generating\n * insights on a topic of reflection based on pertinent memories.\n */\nclass GenerativeAgentMemoryChain extends BaseChain {\n static lc_name() {\n return \"GenerativeAgentMemoryChain\";\n }\n\n reflecting = false;\n\n reflectionThreshold?: number;\n\n importanceWeight = 0.15;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n llm: BaseLanguageModelInterface;\n\n verbose = false;\n\n private aggregateImportance = 0.0;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config: Omit<GenerativeAgentMemoryConfig, \"maxTokensLimit\">\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.reflectionThreshold = config.reflectionThreshold;\n this.importanceWeight = config.importanceWeight ?? this.importanceWeight;\n this.verbose = config.verbose ?? this.verbose;\n }\n\n _chainType(): string {\n return \"generative_agent_memory\";\n }\n\n get inputKeys(): string[] {\n return [\"memory_content\", \"now\", \"memory_metadata\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\"];\n }\n\n /**\n * Method that creates a new LLMChain with the given prompt.\n * @param prompt The PromptTemplate to use for the new LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\",\n });\n return chain;\n }\n\n async _call(values: ChainValues, runManager?: CallbackManagerForChainRun) {\n const { memory_content: memoryContent, now } = values;\n // add an observation or memory to the agent's memory\n const importanceScore = await this.scoreMemoryImportance(\n memoryContent,\n runManager\n );\n this.aggregateImportance += importanceScore;\n const document = new Document({\n pageContent: memoryContent,\n metadata: {\n importance: importanceScore,\n ...values.memory_metadata,\n },\n });\n await this.memoryRetriever.addDocuments([document]);\n // after an agent has processed a certain amount of memories (as measured by aggregate importance),\n // it is time to pause and reflect on recent events to add more synthesized memories to the agent's\n // memory stream.\n if (\n this.reflectionThreshold !== undefined &&\n this.aggregateImportance > this.reflectionThreshold &&\n !this.reflecting\n ) {\n console.log(\"Reflecting on current memories...\");\n this.reflecting = true;\n await this.pauseToReflect(now, runManager);\n this.aggregateImportance = 0.0;\n this.reflecting = false;\n }\n return { output: importanceScore };\n }\n\n /**\n * Method that pauses the agent to reflect on recent events and generate\n * new insights.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for the reflection.\n * @returns An array of new insights as strings.\n */\n async pauseToReflect(\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n if (this.verbose) {\n console.log(\"Pausing to reflect...\");\n }\n const newInsights: string[] = [];\n const topics = await this.getTopicsOfReflection(50, runManager);\n for (const topic of topics) {\n const insights = await this.getInsightsOnTopic(topic, now, runManager);\n for (const insight of insights) {\n // add memory\n await this.call(\n {\n memory_content: insight,\n now,\n memory_metadata: {\n source: \"reflection_insight\",\n },\n },\n runManager?.getChild(\"reflection_insight_memory\")\n );\n }\n newInsights.push(...insights);\n }\n return newInsights;\n }\n\n /**\n * Method that scores the importance of a given memory.\n * @param memoryContent The content of the memory to score.\n * @param runManager The CallbackManagerForChainRun to use for scoring.\n * @returns The importance score of the memory as a number.\n */\n async scoreMemoryImportance(\n memoryContent: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<number> {\n // score the absolute importance of a given memory\n const prompt = PromptTemplate.fromTemplate(\n \"On the scale of 1 to 10, where 1 is purely mundane\" +\n \" (e.g., brushing teeth, making bed) and 10 is\" +\n \" extremely poignant (e.g., a break up, college\" +\n \" acceptance), rate the likely poignancy of the\" +\n \" following piece of memory. Respond with a single integer.\" +\n \"\\nMemory: {memory_content}\" +\n \"\\nRating: \"\n );\n const score = await this.chain(prompt).run(\n memoryContent,\n runManager?.getChild(\"determine_importance\")\n );\n\n const strippedScore = score.trim();\n\n if (this.verbose) {\n console.log(\"Importance score:\", strippedScore);\n }\n const match = strippedScore.match(/^\\D*(\\d+)/);\n if (match) {\n const capturedNumber = parseFloat(match[1]);\n const result = (capturedNumber / 10) * this.importanceWeight;\n return result;\n } else {\n return 0.0;\n }\n }\n\n /**\n * Method that retrieves the topics of reflection based on the last K\n * memories.\n * @param lastK The number of most recent memories to consider for generating topics.\n * @param runManager The CallbackManagerForChainRun to use for retrieving topics.\n * @returns An array of topics of reflection as strings.\n */\n async getTopicsOfReflection(\n lastK: number,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n const prompt = PromptTemplate.fromTemplate(\n \"{observations}\\n\\n\" +\n \"Given only the information above, what are the 3 most salient\" +\n \" high-level questions we can answer about the subjects in\" +\n \" the statements? Provide each question on a new line.\\n\\n\"\n );\n\n const observations = this.memoryRetriever.getMemoryStream().slice(-lastK);\n const observationStr = observations\n .map((o: { pageContent: string }) => o.pageContent)\n .join(\"\\n\");\n const result = await this.chain(prompt).run(\n observationStr,\n runManager?.getChild(\"reflection_topics\")\n );\n return GenerativeAgentMemoryChain.parseList(result);\n }\n\n /**\n * Method that generates insights on a given topic of reflection based on\n * pertinent memories.\n * @param topic The topic of reflection.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for generating insights.\n * @returns An array of insights as strings.\n */\n async getInsightsOnTopic(\n topic: string,\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n // generate insights on a topic of reflection, based on pertinent memories\n const prompt = PromptTemplate.fromTemplate(\n \"Statements about {topic}\\n\" +\n \"{related_statements}\\n\\n\" +\n \"What 5 high-level insights can you infer from the above statements?\" +\n \" (example format: insight (because of 1, 5, 3))\"\n );\n\n const relatedMemories = await this.fetchMemories(topic, now, runManager);\n const relatedStatements: string = relatedMemories\n .map((memory, index) => `${index + 1}. ${memory.pageContent}`)\n .join(\"\\n\");\n const result = await this.chain(prompt).call(\n {\n topic,\n related_statements: relatedStatements,\n },\n runManager?.getChild(\"reflection_insights\")\n );\n return GenerativeAgentMemoryChain.parseList(result.output); // added output\n }\n\n /**\n * Method that parses a newline-separated string into a list of strings.\n * @param text The newline-separated string to parse.\n * @returns An array of strings.\n */\n static parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n return text.split(\"\\n\").map((s) => s.trim());\n }\n\n // TODO: Mock \"now\" to simulate different times\n /**\n * Method that fetches memories related to a given observation.\n * @param observation The observation to fetch memories for.\n * @param _now The current date.\n * @param runManager The CallbackManagerForChainRun to use for fetching memories.\n * @returns An array of Document instances representing the fetched memories.\n */\n async fetchMemories(\n observation: string,\n _now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<Document[]> {\n return this.memoryRetriever.invoke(\n observation,\n runManager?.getChild(\"memory_retriever\")\n );\n }\n}\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseMemory` class and has methods for adding a memory,\n * formatting memories, getting memories until a token limit is reached,\n * loading memory variables, saving the context of a model run to memory,\n * and clearing memory contents.\n * @example\n * ```typescript\n * const createNewMemoryRetriever = async () => {\n * const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());\n * const retriever = new TimeWeightedVectorStoreRetriever({\n * vectorStore,\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * });\n * return retriever;\n * };\n * const tommiesMemory = new GenerativeAgentMemory(\n * llm,\n * await createNewMemoryRetriever(),\n * { reflectionThreshold: 8 },\n * );\n * const summary = await tommiesMemory.getSummary();\n * ```\n */\nexport class GenerativeAgentMemory extends BaseMemory {\n llm: BaseLanguageModelInterface;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n verbose: boolean;\n\n reflectionThreshold?: number;\n\n private maxTokensLimit = 1200;\n\n queriesKey = \"queries\";\n\n mostRecentMemoriesTokenKey = \"recent_memories_token\";\n\n addMemoryKey = \"addMemory\";\n\n relevantMemoriesKey = \"relevant_memories\";\n\n relevantMemoriesSimpleKey = \"relevant_memories_simple\";\n\n mostRecentMemoriesKey = \"most_recent_memories\";\n\n nowKey = \"now\";\n\n memoryChain: GenerativeAgentMemoryChain;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config?: GenerativeAgentMemoryConfig\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.verbose = config?.verbose ?? this.verbose;\n this.reflectionThreshold =\n config?.reflectionThreshold ?? this.reflectionThreshold;\n this.maxTokensLimit = config?.maxTokensLimit ?? this.maxTokensLimit;\n this.memoryChain = new GenerativeAgentMemoryChain(llm, memoryRetriever, {\n reflectionThreshold: config?.reflectionThreshold,\n importanceWeight: config?.importanceWeight,\n });\n }\n\n /**\n * Method that returns the key for relevant memories.\n * @returns The key for relevant memories as a string.\n */\n getRelevantMemoriesKey(): string {\n return this.relevantMemoriesKey;\n }\n\n /**\n * Method that returns the key for the most recent memories token.\n * @returns The key for the most recent memories token as a string.\n */\n getMostRecentMemoriesTokenKey(): string {\n return this.mostRecentMemoriesTokenKey;\n }\n\n /**\n * Method that returns the key for adding a memory.\n * @returns The key for adding a memory as a string.\n */\n getAddMemoryKey(): string {\n return this.addMemoryKey;\n }\n\n /**\n * Method that returns the key for the current time.\n * @returns The key for the current time as a string.\n */\n getCurrentTimeKey(): string {\n return this.nowKey;\n }\n\n get memoryKeys(): string[] {\n // Return an array of memory keys\n return [this.relevantMemoriesKey, this.mostRecentMemoriesKey];\n }\n\n /**\n * Method that adds a memory to the agent's memory.\n * @param memoryContent The content of the memory to add.\n * @param now The current date.\n * @param metadata The metadata for the memory.\n * @param callbacks The Callbacks to use for adding the memory.\n * @returns The result of the memory addition.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.memoryChain.call(\n { memory_content: memoryContent, now, memory_metadata: metadata },\n callbacks\n );\n }\n\n /**\n * Method that formats the given relevant memories in detail.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesDetail(relevantMemories: Document[]): string {\n if (!relevantMemories.length) {\n return \"No relevant information.\";\n }\n const contentStrings = new Set();\n const content = [];\n for (const memory of relevantMemories) {\n if (memory.pageContent in contentStrings) {\n continue;\n }\n contentStrings.add(memory.pageContent);\n const createdTime = memory.metadata.created_at.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n content.push(`${createdTime}: ${memory.pageContent.trim()}`);\n }\n const joinedContent = content.map((mem) => `${mem}`).join(\"\\n\");\n return joinedContent;\n }\n\n /**\n * Method that formats the given relevant memories in a simple manner.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesSimple(relevantMemories: Document[]): string {\n const joinedContent = relevantMemories\n .map((mem) => `${mem.pageContent}`)\n .join(\"; \");\n return joinedContent;\n }\n\n /**\n * Method that retrieves memories until a token limit is reached.\n * @param consumedTokens The number of tokens consumed so far.\n * @returns The memories as a string.\n */\n async getMemoriesUntilLimit(consumedTokens: number): Promise<string> {\n // reduce the number of tokens in the documents\n const result = [];\n for (const doc of this.memoryRetriever\n .getMemoryStream()\n .slice()\n .reverse()) {\n if (consumedTokens >= this.maxTokensLimit) {\n if (this.verbose) {\n console.log(\"Exceeding max tokens for LLM, filtering memories\");\n }\n break;\n }\n // oxlint-disable-next-line no-param-reassign\n consumedTokens += await this.llm.getNumTokens(doc.pageContent);\n if (consumedTokens < this.maxTokensLimit) {\n result.push(doc);\n }\n }\n return this.formatMemoriesSimple(result);\n }\n\n get memoryVariables(): string[] {\n // input keys this memory class will load dynamically\n return [];\n }\n\n /**\n * Method that loads memory variables based on the given inputs.\n * @param inputs The inputs to use for loading memory variables.\n * @returns An object containing the loaded memory variables.\n */\n async loadMemoryVariables(\n inputs: InputValues\n ): Promise<Record<string, string>> {\n const queries = inputs[this.queriesKey];\n const now = inputs[this.nowKey];\n if (queries !== undefined) {\n const relevantMemories = (\n await Promise.all(\n queries.map((query: string) =>\n this.memoryChain.fetchMemories(query, now)\n )\n )\n ).flat();\n return {\n [this.relevantMemoriesKey]: this.formatMemoriesDetail(relevantMemories),\n [this.relevantMemoriesSimpleKey]:\n this.formatMemoriesSimple(relevantMemories),\n };\n }\n const mostRecentMemoriesToken = inputs[this.mostRecentMemoriesTokenKey];\n if (mostRecentMemoriesToken !== undefined) {\n return {\n [this.mostRecentMemoriesKey]: await this.getMemoriesUntilLimit(\n mostRecentMemoriesToken\n ),\n };\n }\n return {};\n }\n\n /**\n * Method that saves the context of a model run to memory.\n * @param _inputs The inputs of the model run.\n * @param outputs The outputs of the model run.\n * @returns Nothing.\n */\n async saveContext(\n _inputs: InputValues,\n outputs: OutputValues\n ): Promise<void> {\n // save the context of this model run to memory\n const mem = outputs[this.addMemoryKey];\n const now = outputs[this.nowKey];\n if (mem) {\n await this.addMemory(mem, now, {});\n }\n }\n\n /**\n * Method that clears the memory contents.\n * @returns Nothing.\n */\n clear(): void {\n // TODO: clear memory contents\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generative_agent_memory.js","names":[],"sources":["../../../src/experimental/generative_agents/generative_agent_memory.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport { Document } from \"@langchain/core/documents\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { BaseMemory, InputValues, OutputValues } from \"@langchain/core/memory\";\nimport {\n CallbackManagerForChainRun,\n Callbacks,\n} from \"@langchain/core/callbacks/manager\";\nimport { TimeWeightedVectorStoreRetriever } from \"../../retrievers/time_weighted.js\";\nimport { BaseChain } from \"../../chains/base.js\";\nimport { LLMChain } from \"../../chains/llm_chain.js\";\n\nexport type GenerativeAgentMemoryConfig = {\n reflectionThreshold?: number;\n importanceWeight?: number;\n verbose?: boolean;\n maxTokensLimit?: number;\n};\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseChain` class and has methods for adding observations\n * or memories to the agent's memory, scoring the importance of a memory,\n * reflecting on recent events to add synthesized memories, and generating\n * insights on a topic of reflection based on pertinent memories.\n */\nclass GenerativeAgentMemoryChain extends BaseChain {\n static lc_name() {\n return \"GenerativeAgentMemoryChain\";\n }\n\n reflecting = false;\n\n reflectionThreshold?: number;\n\n importanceWeight = 0.15;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n llm: BaseLanguageModelInterface;\n\n verbose = false;\n\n private aggregateImportance = 0.0;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config: Omit<GenerativeAgentMemoryConfig, \"maxTokensLimit\">\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.reflectionThreshold = config.reflectionThreshold;\n this.importanceWeight = config.importanceWeight ?? this.importanceWeight;\n this.verbose = config.verbose ?? this.verbose;\n }\n\n _chainType(): string {\n return \"generative_agent_memory\";\n }\n\n get inputKeys(): string[] {\n return [\"memory_content\", \"now\", \"memory_metadata\"];\n }\n\n get outputKeys(): string[] {\n return [\"output\"];\n }\n\n /**\n * Method that creates a new LLMChain with the given prompt.\n * @param prompt The PromptTemplate to use for the new LLMChain.\n * @returns A new LLMChain instance.\n */\n chain(prompt: PromptTemplate): LLMChain {\n const chain = new LLMChain({\n llm: this.llm,\n prompt,\n verbose: this.verbose,\n outputKey: \"output\",\n });\n return chain;\n }\n\n async _call(values: ChainValues, runManager?: CallbackManagerForChainRun) {\n const { memory_content: memoryContent, now } = values;\n // add an observation or memory to the agent's memory\n const importanceScore = await this.scoreMemoryImportance(\n memoryContent,\n runManager\n );\n this.aggregateImportance += importanceScore;\n const document = new Document({\n pageContent: memoryContent,\n metadata: {\n importance: importanceScore,\n ...values.memory_metadata,\n },\n });\n await this.memoryRetriever.addDocuments([document]);\n // after an agent has processed a certain amount of memories (as measured by aggregate importance),\n // it is time to pause and reflect on recent events to add more synthesized memories to the agent's\n // memory stream.\n if (\n this.reflectionThreshold !== undefined &&\n this.aggregateImportance > this.reflectionThreshold &&\n !this.reflecting\n ) {\n console.log(\"Reflecting on current memories...\");\n this.reflecting = true;\n await this.pauseToReflect(now, runManager);\n this.aggregateImportance = 0.0;\n this.reflecting = false;\n }\n return { output: importanceScore };\n }\n\n /**\n * Method that pauses the agent to reflect on recent events and generate\n * new insights.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for the reflection.\n * @returns An array of new insights as strings.\n */\n async pauseToReflect(\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n if (this.verbose) {\n console.log(\"Pausing to reflect...\");\n }\n const newInsights: string[] = [];\n const topics = await this.getTopicsOfReflection(50, runManager);\n for (const topic of topics) {\n const insights = await this.getInsightsOnTopic(topic, now, runManager);\n for (const insight of insights) {\n // add memory\n await this.call(\n {\n memory_content: insight,\n now,\n memory_metadata: {\n source: \"reflection_insight\",\n },\n },\n runManager?.getChild(\"reflection_insight_memory\")\n );\n }\n newInsights.push(...insights);\n }\n return newInsights;\n }\n\n /**\n * Method that scores the importance of a given memory.\n * @param memoryContent The content of the memory to score.\n * @param runManager The CallbackManagerForChainRun to use for scoring.\n * @returns The importance score of the memory as a number.\n */\n async scoreMemoryImportance(\n memoryContent: string,\n runManager?: CallbackManagerForChainRun\n ): Promise<number> {\n // score the absolute importance of a given memory\n const prompt = PromptTemplate.fromTemplate(\n \"On the scale of 1 to 10, where 1 is purely mundane\" +\n \" (e.g., brushing teeth, making bed) and 10 is\" +\n \" extremely poignant (e.g., a break up, college\" +\n \" acceptance), rate the likely poignancy of the\" +\n \" following piece of memory. Respond with a single integer.\" +\n \"\\nMemory: {memory_content}\" +\n \"\\nRating: \"\n );\n const score = await this.chain(prompt).run(\n memoryContent,\n runManager?.getChild(\"determine_importance\")\n );\n\n const strippedScore = score.trim();\n\n if (this.verbose) {\n console.log(\"Importance score:\", strippedScore);\n }\n const match = strippedScore.match(/^\\D*(\\d+)/);\n if (match) {\n const capturedNumber = parseFloat(match[1]);\n const result = (capturedNumber / 10) * this.importanceWeight;\n return result;\n } else {\n return 0.0;\n }\n }\n\n /**\n * Method that retrieves the topics of reflection based on the last K\n * memories.\n * @param lastK The number of most recent memories to consider for generating topics.\n * @param runManager The CallbackManagerForChainRun to use for retrieving topics.\n * @returns An array of topics of reflection as strings.\n */\n async getTopicsOfReflection(\n lastK: number,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n const prompt = PromptTemplate.fromTemplate(\n \"{observations}\\n\\n\" +\n \"Given only the information above, what are the 3 most salient\" +\n \" high-level questions we can answer about the subjects in\" +\n \" the statements? Provide each question on a new line.\\n\\n\"\n );\n\n const observations = this.memoryRetriever.getMemoryStream().slice(-lastK);\n const observationStr = observations\n .map((o: { pageContent: string }) => o.pageContent)\n .join(\"\\n\");\n const result = await this.chain(prompt).run(\n observationStr,\n runManager?.getChild(\"reflection_topics\")\n );\n return GenerativeAgentMemoryChain.parseList(result);\n }\n\n /**\n * Method that generates insights on a given topic of reflection based on\n * pertinent memories.\n * @param topic The topic of reflection.\n * @param now The current date.\n * @param runManager The CallbackManagerForChainRun to use for generating insights.\n * @returns An array of insights as strings.\n */\n async getInsightsOnTopic(\n topic: string,\n now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<string[]> {\n // generate insights on a topic of reflection, based on pertinent memories\n const prompt = PromptTemplate.fromTemplate(\n \"Statements about {topic}\\n\" +\n \"{related_statements}\\n\\n\" +\n \"What 5 high-level insights can you infer from the above statements?\" +\n \" (example format: insight (because of 1, 5, 3))\"\n );\n\n const relatedMemories = await this.fetchMemories(topic, now, runManager);\n const relatedStatements: string = relatedMemories\n .map((memory, index) => `${index + 1}. ${memory.pageContent}`)\n .join(\"\\n\");\n const result = await this.chain(prompt).call(\n {\n topic,\n related_statements: relatedStatements,\n },\n runManager?.getChild(\"reflection_insights\")\n );\n return GenerativeAgentMemoryChain.parseList(result.output); // added output\n }\n\n /**\n * Method that parses a newline-separated string into a list of strings.\n * @param text The newline-separated string to parse.\n * @returns An array of strings.\n */\n static parseList(text: string): string[] {\n // parse a newline-separated string into a list of strings\n return text.split(\"\\n\").map((s) => s.trim());\n }\n\n // TODO: Mock \"now\" to simulate different times\n /**\n * Method that fetches memories related to a given observation.\n * @param observation The observation to fetch memories for.\n * @param _now The current date.\n * @param runManager The CallbackManagerForChainRun to use for fetching memories.\n * @returns An array of Document instances representing the fetched memories.\n */\n async fetchMemories(\n observation: string,\n _now?: Date,\n runManager?: CallbackManagerForChainRun\n ): Promise<Document[]> {\n return this.memoryRetriever.invoke(\n observation,\n runManager?.getChild(\"memory_retriever\")\n );\n }\n}\n\n/**\n * Class that manages the memory of a generative agent in LangChain. It\n * extends the `BaseMemory` class and has methods for adding a memory,\n * formatting memories, getting memories until a token limit is reached,\n * loading memory variables, saving the context of a model run to memory,\n * and clearing memory contents.\n * @example\n * ```typescript\n * const createNewMemoryRetriever = async () => {\n * const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());\n * const retriever = new TimeWeightedVectorStoreRetriever({\n * vectorStore,\n * otherScoreKeys: [\"importance\"],\n * k: 15,\n * });\n * return retriever;\n * };\n * const tommiesMemory = new GenerativeAgentMemory(\n * llm,\n * await createNewMemoryRetriever(),\n * { reflectionThreshold: 8 },\n * );\n * const summary = await tommiesMemory.getSummary();\n * ```\n */\nexport class GenerativeAgentMemory extends BaseMemory {\n llm: BaseLanguageModelInterface;\n\n memoryRetriever: TimeWeightedVectorStoreRetriever;\n\n verbose: boolean;\n\n reflectionThreshold?: number;\n\n private maxTokensLimit = 1200;\n\n queriesKey = \"queries\";\n\n mostRecentMemoriesTokenKey = \"recent_memories_token\";\n\n addMemoryKey = \"addMemory\";\n\n relevantMemoriesKey = \"relevant_memories\";\n\n relevantMemoriesSimpleKey = \"relevant_memories_simple\";\n\n mostRecentMemoriesKey = \"most_recent_memories\";\n\n nowKey = \"now\";\n\n memoryChain: GenerativeAgentMemoryChain;\n\n constructor(\n llm: BaseLanguageModelInterface,\n memoryRetriever: TimeWeightedVectorStoreRetriever,\n config?: GenerativeAgentMemoryConfig\n ) {\n super();\n this.llm = llm;\n this.memoryRetriever = memoryRetriever;\n this.verbose = config?.verbose ?? this.verbose;\n this.reflectionThreshold =\n config?.reflectionThreshold ?? this.reflectionThreshold;\n this.maxTokensLimit = config?.maxTokensLimit ?? this.maxTokensLimit;\n this.memoryChain = new GenerativeAgentMemoryChain(llm, memoryRetriever, {\n reflectionThreshold: config?.reflectionThreshold,\n importanceWeight: config?.importanceWeight,\n });\n }\n\n /**\n * Method that returns the key for relevant memories.\n * @returns The key for relevant memories as a string.\n */\n getRelevantMemoriesKey(): string {\n return this.relevantMemoriesKey;\n }\n\n /**\n * Method that returns the key for the most recent memories token.\n * @returns The key for the most recent memories token as a string.\n */\n getMostRecentMemoriesTokenKey(): string {\n return this.mostRecentMemoriesTokenKey;\n }\n\n /**\n * Method that returns the key for adding a memory.\n * @returns The key for adding a memory as a string.\n */\n getAddMemoryKey(): string {\n return this.addMemoryKey;\n }\n\n /**\n * Method that returns the key for the current time.\n * @returns The key for the current time as a string.\n */\n getCurrentTimeKey(): string {\n return this.nowKey;\n }\n\n get memoryKeys(): string[] {\n // Return an array of memory keys\n return [this.relevantMemoriesKey, this.mostRecentMemoriesKey];\n }\n\n /**\n * Method that adds a memory to the agent's memory.\n * @param memoryContent The content of the memory to add.\n * @param now The current date.\n * @param metadata The metadata for the memory.\n * @param callbacks The Callbacks to use for adding the memory.\n * @returns The result of the memory addition.\n */\n async addMemory(\n memoryContent: string,\n now?: Date,\n metadata?: Record<string, unknown>,\n callbacks?: Callbacks\n ) {\n return this.memoryChain.call(\n { memory_content: memoryContent, now, memory_metadata: metadata },\n callbacks\n );\n }\n\n /**\n * Method that formats the given relevant memories in detail.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesDetail(relevantMemories: Document[]): string {\n if (!relevantMemories.length) {\n return \"No relevant information.\";\n }\n const contentStrings = new Set();\n const content = [];\n for (const memory of relevantMemories) {\n if (memory.pageContent in contentStrings) {\n continue;\n }\n contentStrings.add(memory.pageContent);\n const createdTime = memory.metadata.created_at.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n });\n content.push(`${createdTime}: ${memory.pageContent.trim()}`);\n }\n const joinedContent = content.map((mem) => `${mem}`).join(\"\\n\");\n return joinedContent;\n }\n\n /**\n * Method that formats the given relevant memories in a simple manner.\n * @param relevantMemories The relevant memories to format.\n * @returns The formatted memories as a string.\n */\n formatMemoriesSimple(relevantMemories: Document[]): string {\n const joinedContent = relevantMemories\n .map((mem) => `${mem.pageContent}`)\n .join(\"; \");\n return joinedContent;\n }\n\n /**\n * Method that retrieves memories until a token limit is reached.\n * @param consumedTokens The number of tokens consumed so far.\n * @returns The memories as a string.\n */\n async getMemoriesUntilLimit(consumedTokens: number): Promise<string> {\n // reduce the number of tokens in the documents\n const result = [];\n for (const doc of this.memoryRetriever\n .getMemoryStream()\n .slice()\n .reverse()) {\n if (consumedTokens >= this.maxTokensLimit) {\n if (this.verbose) {\n console.log(\"Exceeding max tokens for LLM, filtering memories\");\n }\n break;\n }\n // oxlint-disable-next-line no-param-reassign\n consumedTokens += await this.llm.getNumTokens(doc.pageContent);\n if (consumedTokens < this.maxTokensLimit) {\n result.push(doc);\n }\n }\n return this.formatMemoriesSimple(result);\n }\n\n get memoryVariables(): string[] {\n // input keys this memory class will load dynamically\n return [];\n }\n\n /**\n * Method that loads memory variables based on the given inputs.\n * @param inputs The inputs to use for loading memory variables.\n * @returns An object containing the loaded memory variables.\n */\n async loadMemoryVariables(\n inputs: InputValues\n ): Promise<Record<string, string>> {\n const queries = inputs[this.queriesKey];\n const now = inputs[this.nowKey];\n if (queries !== undefined) {\n const relevantMemories = (\n await Promise.all(\n queries.map((query: string) =>\n this.memoryChain.fetchMemories(query, now)\n )\n )\n ).flat();\n return {\n [this.relevantMemoriesKey]: this.formatMemoriesDetail(relevantMemories),\n [this.relevantMemoriesSimpleKey]:\n this.formatMemoriesSimple(relevantMemories),\n };\n }\n const mostRecentMemoriesToken = inputs[this.mostRecentMemoriesTokenKey];\n if (mostRecentMemoriesToken !== undefined) {\n return {\n [this.mostRecentMemoriesKey]: await this.getMemoriesUntilLimit(\n mostRecentMemoriesToken\n ),\n };\n }\n return {};\n }\n\n /**\n * Method that saves the context of a model run to memory.\n * @param _inputs The inputs of the model run.\n * @param outputs The outputs of the model run.\n * @returns Nothing.\n */\n async saveContext(\n _inputs: InputValues,\n outputs: OutputValues\n ): Promise<void> {\n // save the context of this model run to memory\n const mem = outputs[this.addMemoryKey];\n const now = outputs[this.nowKey];\n if (mem) {\n await this.addMemory(mem, now, {});\n }\n }\n\n /**\n * Method that clears the memory contents.\n * @returns Nothing.\n */\n clear(): void {\n // TODO: clear memory contents\n }\n}\n"],"mappings":"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"}
|