{"version":3,"file":"messages.cjs","names":["BaseMessageChunk","HumanMessage","AIMessage","SystemMessage","ToolMessage","RemoveMessage","HumanMessageChunk","AIMessageChunk","SystemMessageChunk","ToolMessageChunk"],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n  type BaseMessage,\n  BaseMessageChunk,\n  RemoveMessage,\n  convertToChunk,\n  coerceMessageLikeToMessage,\n  HumanMessageChunk,\n  HumanMessage,\n  SystemMessageChunk,\n  SystemMessage,\n  AIMessageChunk,\n  AIMessage,\n  ToolMessageChunk,\n  ToolMessage,\n} from \"@langchain/core/messages\";\n\nimport type { Message } from \"../types.messages.js\";\nimport type { ThreadState } from \"../schema.js\";\n\n/**\n * Replaces the `messages` property in a state type with `BaseMessage[]`.\n * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`\n * converts plain message objects to class instances at runtime.\n */\nexport type StateWithBaseMessages<S> = S extends { messages: unknown }\n  ? Omit<S, \"messages\"> & { messages: BaseMessage[] }\n  : S;\n\n/**\n * Maps a `ThreadState<StateType>[]` so that the `messages` field inside\n * `values` is typed as `BaseMessage[]` instead of `Message[]`.\n */\nexport type HistoryWithBaseMessages<T> = T extends ThreadState<infer S>[]\n  ? ThreadState<StateWithBaseMessages<S>>[]\n  : T;\n\nexport function tryConvertToChunk(\n  message: BaseMessage | BaseMessageChunk\n): BaseMessageChunk | null {\n  try {\n    if (BaseMessageChunk.isInstance(message)) return message;\n    return convertToChunk(message);\n  } catch {\n    return null;\n  }\n}\n\nexport function tryCoerceMessageLikeToMessage(\n  message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n  if (message.type === \"human\" || message.type === \"user\") {\n    return new HumanMessage(message);\n  }\n\n  if (message.type === \"ai\" || message.type === \"assistant\") {\n    return new AIMessage(normalizeAIMessageToolCalls(message));\n  }\n\n  if (message.type === \"system\") {\n    return new SystemMessage(message);\n  }\n\n  if (message.type === \"tool\" && \"tool_call_id\" in message) {\n    return new ToolMessage({\n      ...message,\n      tool_call_id: message.tool_call_id as string,\n    });\n  }\n\n  if (message.type === \"remove\" && message.id != null) {\n    return new RemoveMessage({ ...message, id: message.id });\n  }\n\n  return coerceMessageLikeToMessage(message);\n}\n\nfunction tryCoerceMessageLikeToChunk(\n  message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n  if (message.type === \"human\" || message.type === \"user\") {\n    return new HumanMessageChunk(message);\n  }\n\n  if (message.type === \"ai\" || message.type === \"assistant\") {\n    return new AIMessageChunk(normalizeAIMessageToolCalls(message));\n  }\n\n  if (message.type === \"system\") {\n    return new SystemMessageChunk(message);\n  }\n\n  if (message.type === \"tool\" && \"tool_call_id\" in message) {\n    return new ToolMessageChunk({\n      ...message,\n      tool_call_id: message.tool_call_id as string,\n    });\n  }\n\n  return tryCoerceMessageLikeToMessage(message);\n}\n\ntype ToolCallLike = {\n  id?: string;\n  name?: string;\n  args?: unknown;\n  input?: unknown;\n};\n\nfunction normalizeAIMessageToolCalls<\n  T extends Omit<Message, \"type\"> & { type: string },\n>(message: T): T {\n  const record = message as T & {\n    content?: unknown;\n    tool_calls?: unknown;\n  };\n  if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) {\n    return message;\n  }\n\n  const toolCalls = extractToolCallsFromContent(record.content);\n  if (toolCalls.length === 0) return message;\n  return {\n    ...message,\n    tool_calls: toolCalls,\n  };\n}\n\nfunction extractToolCallsFromContent(content: unknown) {\n  if (!Array.isArray(content)) return [];\n  return content.flatMap(\n    (\n      block\n    ): Array<{\n      id: string;\n      name: string;\n      args: Record<string, unknown>;\n      type: \"tool_call\";\n    }> => {\n      if (block == null || typeof block !== \"object\") return [];\n      const record = block as ToolCallLike & { type?: unknown };\n      if (record.type !== \"tool_call\" && record.type !== \"tool_use\") return [];\n      return [\n        {\n          id: record.id ?? \"\",\n          name: record.name ?? \"\",\n          args: normalizeToolCallArgs(record.args ?? record.input),\n          type: \"tool_call\",\n        },\n      ];\n    }\n  );\n}\n\nfunction normalizeToolCallArgs(value: unknown): Record<string, unknown> {\n  if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n    return value as Record<string, unknown>;\n  }\n  if (typeof value === \"string\" && value.length > 0) {\n    try {\n      const parsed = JSON.parse(value);\n      if (\n        parsed != null &&\n        typeof parsed === \"object\" &&\n        !Array.isArray(parsed)\n      ) {\n        return parsed as Record<string, unknown>;\n      }\n    } catch {\n      // Streaming input fragments are expected to be invalid until finalized.\n    }\n  }\n  return {};\n}\n\nexport class MessageTupleManager {\n  chunks: Record<\n    string,\n    {\n      chunk?: BaseMessageChunk | BaseMessage;\n      metadata?: Record<string, unknown>;\n      index?: number;\n    }\n  > = {};\n\n  constructor() {\n    this.chunks = {};\n  }\n\n  add(\n    serialized: Message,\n    metadata: Record<string, unknown> | undefined\n  ): string | null {\n    // TODO: this is sometimes sent from the API\n    // figure out how to prevent this or move this to LC.js\n    if (serialized.type.endsWith(\"MessageChunk\")) {\n      // eslint-disable-next-line no-param-reassign\n      serialized.type = serialized.type\n        .slice(0, -\"MessageChunk\".length)\n        .toLowerCase() as Message[\"type\"];\n    }\n\n    const message = tryCoerceMessageLikeToChunk(serialized);\n    const chunk = tryConvertToChunk(message);\n\n    const { id } = chunk ?? message;\n    if (!id) {\n      console.warn(\n        \"No message ID found for chunk, ignoring in state\",\n        serialized\n      );\n      return null;\n    }\n\n    this.chunks[id] ??= {};\n    this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;\n    if (chunk) {\n      const prev = this.chunks[id].chunk;\n      this.chunks[id].chunk =\n        (BaseMessageChunk.isInstance(prev) ? prev : null)?.concat(chunk) ??\n        chunk;\n    } else {\n      this.chunks[id].chunk = message;\n    }\n\n    return id;\n  }\n\n  clear() {\n    this.chunks = {};\n  }\n\n  get(id: string | null | undefined, defaultIndex?: number) {\n    if (id == null) return null;\n    if (this.chunks[id] == null) return null;\n    if (defaultIndex != null) this.chunks[id].index ??= defaultIndex;\n    return this.chunks[id];\n  }\n}\n\nexport const toMessageDict = (chunk: BaseMessage): Message => {\n  const { type, data } = chunk.toDict();\n  return { ...data, type } as Message;\n};\n\n/**\n * Identity converter that keeps @langchain/core class instances.\n * Used by framework SDKs to expose BaseMessage instances instead of plain dicts.\n */\nexport const toMessageClass = (chunk: BaseMessage): BaseMessage => chunk;\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\n * Plain message objects (e.g. from API values/history) are converted\n * via {@link tryCoerceMessageLikeToMessage}.\n */\nexport function ensureMessageInstances(\n  messages: (Message | BaseMessage)[]\n): (BaseMessage | BaseMessageChunk)[] {\n  return messages.map((msg) => {\n    if (typeof (msg as BaseMessage).getType === \"function\") {\n      return msg as BaseMessage;\n    }\n    return tryCoerceMessageLikeToMessage(\n      msg as Omit<Message, \"type\"> & { type: string }\n    );\n  });\n}\n\n/**\n * Converts plain message objects within each history state's values\n * to proper BaseMessage class instances. Returns a new array with\n * shallow-copied states whose messages have been coerced.\n */\nexport function ensureHistoryMessageInstances<\n  StateType extends Record<string, unknown>,\n>(\n  history: ThreadState<StateType>[],\n  messagesKey: string = \"messages\"\n): ThreadState<StateType>[] {\n  return history.map((state) => {\n    if (state.values == null) return state;\n    const messages = state.values[messagesKey];\n    if (!Array.isArray(messages)) return state;\n    return {\n      ...state,\n      values: {\n        ...state.values,\n        [messagesKey]: ensureMessageInstances(messages),\n      },\n    };\n  });\n}\n"],"mappings":"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"}