{"version":3,"file":"history.cjs","names":["RunnableBinding","fields: RunnableWithMessageHistoryInputs<RunInput, RunOutput>","historyChain: Runnable","RunnableLambda","RunnablePassthrough","config","inputValue: string | BaseMessage | Array<BaseMessage> | Record<string, any>","isBaseMessage","HumanMessage","outputValue: string | BaseMessage | Array<BaseMessage> | Record<string, any>","AIMessage","input: any","kwargs?: RunnableConfig","run: Run","config: RunnableConfig"],"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  // eslint-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<RunInput, 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/community @upstash/redis\n *\n * import {\n *   ChatPromptTemplate,\n *   MessagesPlaceholder,\n * } from \"@langchain/core/prompts\";\n * import { ChatAnthropic } from \"@langchain/anthropic\";\n * import { UpstashRedisChatMessageHistory } from \"@langchain/community/stores/message/upstash_redis\";\n * // For demos, you can also use an in-memory store:\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    // eslint-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    // eslint-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    // eslint-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 = await this.getMessageHistory(\n      sessionId\n    );\n    return config;\n  }\n}\n"],"mappings":"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"}