{"version":3,"file":"history.cjs","names":["RunnableBinding","RunnableLambda","RunnablePassthrough","isBaseMessage","HumanMessage","AIMessage"],"sources":["../../src/runnables/history.ts"],"sourcesContent":["import {\n  BaseChatMessageHistory,\n  BaseListChatMessageHistory,\n} from \"../chat_history.js\";\nimport {\n  AIMessage,\n  BaseMessage,\n  HumanMessage,\n  isBaseMessage,\n} from \"../messages/index.js\";\nimport { Run } from \"../tracers/base.js\";\nimport {\n  Runnable,\n  RunnableBinding,\n  type RunnableBindingArgs,\n  RunnableLambda,\n} from \"./base.js\";\nimport { RunnableConfig } from \"./config.js\";\nimport { RunnablePassthrough } from \"./passthrough.js\";\n\ntype GetSessionHistoryCallable = (\n  // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n  ...args: Array<any>\n) =>\n  | Promise<BaseChatMessageHistory | BaseListChatMessageHistory>\n  | BaseChatMessageHistory\n  | BaseListChatMessageHistory;\n\nexport interface RunnableWithMessageHistoryInputs<\n  RunInput,\n  RunOutput,\n> extends Omit<RunnableBindingArgs<RunInput, RunOutput>, \"bound\" | \"config\"> {\n  runnable: Runnable<RunInput, RunOutput>;\n  getMessageHistory: GetSessionHistoryCallable;\n  inputMessagesKey?: string;\n  outputMessagesKey?: string;\n  historyMessagesKey?: string;\n  config?: RunnableConfig;\n}\n\n/**\n * Wraps a LCEL chain and manages history. It appends input messages\n * and chain outputs as history, and adds the current history messages to\n * the chain input.\n * @example\n * ```typescript\n * // pnpm install @langchain/anthropic @langchain/classic\n *\n * import {\n *   ChatPromptTemplate,\n *   MessagesPlaceholder,\n * } from \"@langchain/core/prompts\";\n * import { ChatAnthropic } from \"@langchain/anthropic\";\n * import { ChatMessageHistory } from \"@langchain/classic/stores/message/in_memory\";\n *\n * const prompt = ChatPromptTemplate.fromMessages([\n *   [\"system\", \"You're an assistant who's good at {ability}\"],\n *   new MessagesPlaceholder(\"history\"),\n *   [\"human\", \"{question}\"],\n * ]);\n *\n * const chain = prompt.pipe(new ChatAnthropic({}));\n *\n * const chainWithHistory = new RunnableWithMessageHistory({\n *   runnable: chain,\n *   getMessageHistory: (sessionId) =>\n *     new UpstashRedisChatMessageHistory({\n *       sessionId,\n *       config: {\n *         url: process.env.UPSTASH_REDIS_REST_URL!,\n *         token: process.env.UPSTASH_REDIS_REST_TOKEN!,\n *       },\n *     }),\n *   inputMessagesKey: \"question\",\n *   historyMessagesKey: \"history\",\n * });\n *\n * const result = await chainWithHistory.invoke(\n *   {\n *     ability: \"math\",\n *     question: \"What does cosine mean?\",\n *   },\n *   {\n *     configurable: {\n *       sessionId: \"some_string_identifying_a_user\",\n *     },\n *   }\n * );\n *\n * const result2 = await chainWithHistory.invoke(\n *   {\n *     ability: \"math\",\n *     question: \"What's its inverse?\",\n *   },\n *   {\n *     configurable: {\n *       sessionId: \"some_string_identifying_a_user\",\n *     },\n *   }\n * );\n * ```\n */\nexport class RunnableWithMessageHistory<\n  RunInput,\n  RunOutput,\n> extends RunnableBinding<RunInput, RunOutput> {\n  runnable: Runnable<RunInput, RunOutput>;\n\n  inputMessagesKey?: string;\n\n  outputMessagesKey?: string;\n\n  historyMessagesKey?: string;\n\n  getMessageHistory: GetSessionHistoryCallable;\n\n  constructor(fields: RunnableWithMessageHistoryInputs<RunInput, RunOutput>) {\n    let historyChain: Runnable = RunnableLambda.from((input, options) =>\n      this._enterHistory(input, options ?? {})\n    ).withConfig({ runName: \"loadHistory\" });\n\n    const messagesKey = fields.historyMessagesKey ?? fields.inputMessagesKey;\n    if (messagesKey) {\n      historyChain = RunnablePassthrough.assign({\n        [messagesKey]: historyChain,\n      }).withConfig({ runName: \"insertHistory\" });\n    }\n\n    const bound = historyChain\n      .pipe(\n        fields.runnable.withListeners({\n          onEnd: (run, config) => this._exitHistory(run, config ?? {}),\n        })\n      )\n      .withConfig({ runName: \"RunnableWithMessageHistory\" });\n\n    const config = fields.config ?? {};\n\n    super({\n      ...fields,\n      config,\n      bound,\n    });\n    this.runnable = fields.runnable;\n    this.getMessageHistory = fields.getMessageHistory;\n    this.inputMessagesKey = fields.inputMessagesKey;\n    this.outputMessagesKey = fields.outputMessagesKey;\n    this.historyMessagesKey = fields.historyMessagesKey;\n  }\n\n  _getInputMessages(\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    inputValue: string | BaseMessage | Array<BaseMessage> | Record<string, any>\n  ): Array<BaseMessage> {\n    let parsedInputValue;\n    if (\n      typeof inputValue === \"object\" &&\n      !Array.isArray(inputValue) &&\n      !isBaseMessage(inputValue)\n    ) {\n      let key;\n      if (this.inputMessagesKey) {\n        key = this.inputMessagesKey;\n      } else if (Object.keys(inputValue).length === 1) {\n        key = Object.keys(inputValue)[0];\n      } else {\n        key = \"input\";\n      }\n      if (Array.isArray(inputValue[key]) && Array.isArray(inputValue[key][0])) {\n        parsedInputValue = inputValue[key][0];\n      } else {\n        parsedInputValue = inputValue[key];\n      }\n    } else {\n      parsedInputValue = inputValue;\n    }\n    if (typeof parsedInputValue === \"string\") {\n      return [new HumanMessage(parsedInputValue)];\n    } else if (Array.isArray(parsedInputValue)) {\n      return parsedInputValue;\n    } else if (isBaseMessage(parsedInputValue)) {\n      return [parsedInputValue];\n    } else {\n      throw new Error(\n        `Expected a string, BaseMessage, or array of BaseMessages.\\nGot ${JSON.stringify(\n          parsedInputValue,\n          null,\n          2\n        )}`\n      );\n    }\n  }\n\n  _getOutputMessages(\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    outputValue: string | BaseMessage | Array<BaseMessage> | Record<string, any>\n  ): Array<BaseMessage> {\n    let parsedOutputValue;\n    if (\n      !Array.isArray(outputValue) &&\n      !isBaseMessage(outputValue) &&\n      typeof outputValue !== \"string\"\n    ) {\n      let key;\n      if (this.outputMessagesKey !== undefined) {\n        key = this.outputMessagesKey;\n      } else if (Object.keys(outputValue).length === 1) {\n        key = Object.keys(outputValue)[0];\n      } else {\n        key = \"output\";\n      }\n      // If you are wrapping a chat model directly\n      // The output is actually this weird generations object\n      if (outputValue.generations !== undefined) {\n        parsedOutputValue = outputValue.generations[0][0].message;\n      } else {\n        parsedOutputValue = outputValue[key];\n      }\n    } else {\n      parsedOutputValue = outputValue;\n    }\n\n    if (typeof parsedOutputValue === \"string\") {\n      return [new AIMessage(parsedOutputValue)];\n    } else if (Array.isArray(parsedOutputValue)) {\n      return parsedOutputValue;\n    } else if (isBaseMessage(parsedOutputValue)) {\n      return [parsedOutputValue];\n    } else {\n      throw new Error(\n        `Expected a string, BaseMessage, or array of BaseMessages. Received: ${JSON.stringify(\n          parsedOutputValue,\n          null,\n          2\n        )}`\n      );\n    }\n  }\n\n  async _enterHistory(\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    input: any,\n    kwargs?: RunnableConfig\n  ): Promise<BaseMessage[]> {\n    const history = kwargs?.configurable?.messageHistory;\n    const messages = await history.getMessages();\n    if (this.historyMessagesKey === undefined) {\n      return messages.concat(this._getInputMessages(input));\n    }\n    return messages;\n  }\n\n  async _exitHistory(run: Run, config: RunnableConfig): Promise<void> {\n    const history = config.configurable?.messageHistory;\n\n    // Get input messages\n    let inputs;\n    // Chat model inputs are nested arrays\n    if (Array.isArray(run.inputs) && Array.isArray(run.inputs[0])) {\n      inputs = run.inputs[0];\n    } else {\n      inputs = run.inputs;\n    }\n    let inputMessages = this._getInputMessages(inputs);\n    // If historic messages were prepended to the input messages, remove them to\n    // avoid adding duplicate messages to history.\n    if (this.historyMessagesKey === undefined) {\n      const existingMessages = await history.getMessages();\n      inputMessages = inputMessages.slice(existingMessages.length);\n    }\n    // Get output messages\n    const outputValue = run.outputs;\n    if (!outputValue) {\n      throw new Error(\n        `Output values from 'Run' undefined. Run: ${JSON.stringify(\n          run,\n          null,\n          2\n        )}`\n      );\n    }\n    const outputMessages = this._getOutputMessages(outputValue);\n    await history.addMessages([...inputMessages, ...outputMessages]);\n  }\n\n  async _mergeConfig(...configs: Array<RunnableConfig | undefined>) {\n    const config = await super._mergeConfig(...configs);\n    // Extract sessionId\n    if (!config.configurable || !config.configurable.sessionId) {\n      const exampleInput = {\n        [this.inputMessagesKey ?? \"input\"]: \"foo\",\n      };\n      const exampleConfig = { configurable: { sessionId: \"123\" } };\n      throw new Error(\n        `sessionId is required. Pass it in as part of the config argument to .invoke() or .stream()\\n` +\n          `eg. chain.invoke(${JSON.stringify(exampleInput)}, ${JSON.stringify(\n            exampleConfig\n          )})`\n      );\n    }\n    // attach messageHistory\n    const { sessionId } = config.configurable;\n    config.configurable.messageHistory =\n      await this.getMessageHistory(sessionId);\n    return config;\n  }\n}\n"],"mappings":"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"}