{"version":3,"file":"message-coercion.cjs","names":["HumanMessage","AIMessage","SystemMessage","ToolMessage","RemoveMessage"],"sources":["../../src/stream/message-coercion.ts"],"sourcesContent":["import type { BaseMessage, BaseMessageChunk } from \"@langchain/core/messages\";\nimport {\n  AIMessage,\n  HumanMessage,\n  RemoveMessage,\n  SystemMessage,\n  ToolMessage,\n  coerceMessageLikeToMessage,\n} from \"@langchain/core/messages\";\nimport type { Message } from \"../types.messages.js\";\n\ntype MessageLike = Omit<Message, \"type\"> & { type: string };\n\ntype ToolCallLike = {\n  id?: string;\n  name?: string;\n  args?: unknown;\n  input?: unknown;\n};\n\ntype SerializedMessageWithContentBlocks = MessageLike & {\n  content?: unknown;\n  contentBlocks?: unknown;\n  content_blocks?: unknown;\n};\n\n/**\n * Stream-local message coercion for serialized messages returned by\n * `getState()`, `getHistory()`, and `values` events.\n *\n * LangGraph API payloads may carry v1 content blocks as snake_case\n * `content_blocks`, while `@langchain/core` message constructors only\n * understand camelCase `contentBlocks` (or `content`). Normalize that\n * boundary here so stream consumers always see `BaseMessage.text`.\n */\nexport function tryCoerceMessageLikeToMessage(\n  message: MessageLike\n): BaseMessage | BaseMessageChunk {\n  const normalized = normalizeAIMessageToolCalls(message);\n\n  if (normalized.type === \"human\" || normalized.type === \"user\") {\n    return new HumanMessage(normalized);\n  }\n\n  if (normalized.type === \"ai\" || normalized.type === \"assistant\") {\n    return new AIMessage(normalized);\n  }\n\n  if (normalized.type === \"system\") {\n    return new SystemMessage(normalized);\n  }\n\n  if (normalized.type === \"tool\" && \"tool_call_id\" in normalized) {\n    return new ToolMessage({\n      ...normalized,\n      tool_call_id: normalized.tool_call_id as string,\n    });\n  }\n\n  if (normalized.type === \"remove\" && normalized.id != null) {\n    return new RemoveMessage({ ...normalized, id: normalized.id });\n  }\n\n  return coerceMessageLikeToMessage(normalized);\n}\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\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\nfunction normalizeSerializedContentBlocks<T extends MessageLike>(\n  message: T\n): T {\n  const record = message as SerializedMessageWithContentBlocks;\n  const contentBlocks = record.contentBlocks ?? record.content_blocks;\n  if (!Array.isArray(contentBlocks) || contentBlocks.length === 0) {\n    return message;\n  }\n\n  const shouldPreferContentBlocks =\n    isEmptyContent(record.content) ||\n    (!hasTextContent(record.content) && hasTextContent(contentBlocks));\n  if (!shouldPreferContentBlocks && record.contentBlocks === contentBlocks) {\n    return message;\n  }\n\n  return {\n    ...message,\n    content: shouldPreferContentBlocks ? contentBlocks : record.content,\n    contentBlocks,\n  } as T;\n}\n\nexport function normalizeAIMessageToolCalls<T extends MessageLike>(\n  message: T\n): T {\n  const normalized = normalizeSerializedContentBlocks(message);\n  const record = normalized as T & {\n    content?: unknown;\n    tool_calls?: unknown;\n  };\n  if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) {\n    return normalized;\n  }\n\n  const toolCalls = extractToolCallsFromContent(record.content);\n  if (toolCalls.length === 0) return normalized;\n  return {\n    ...normalized,\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\nfunction isEmptyContent(content: unknown): boolean {\n  return (\n    content == null ||\n    content === \"\" ||\n    (Array.isArray(content) && content.length === 0)\n  );\n}\n\nfunction hasTextContent(content: unknown): boolean {\n  if (typeof content === \"string\") return content.length > 0;\n  if (!Array.isArray(content)) return false;\n  return content.some((block) => {\n    if (typeof block === \"string\") return block.length > 0;\n    if (block == null || typeof block !== \"object\") return false;\n    const record = block as { type?: unknown; text?: unknown };\n    return (\n      record.type === \"text\" &&\n      typeof record.text === \"string\" &&\n      record.text.length > 0\n    );\n  });\n}\n"],"mappings":";;;;;;;;;;;;AAmCA,SAAgB,8BACd,SACgC;CAChC,MAAM,aAAa,4BAA4B,QAAQ;AAEvD,KAAI,WAAW,SAAS,WAAW,WAAW,SAAS,OACrD,QAAO,IAAIA,yBAAAA,aAAa,WAAW;AAGrC,KAAI,WAAW,SAAS,QAAQ,WAAW,SAAS,YAClD,QAAO,IAAIC,yBAAAA,UAAU,WAAW;AAGlC,KAAI,WAAW,SAAS,SACtB,QAAO,IAAIC,yBAAAA,cAAc,WAAW;AAGtC,KAAI,WAAW,SAAS,UAAU,kBAAkB,WAClD,QAAO,IAAIC,yBAAAA,YAAY;EACrB,GAAG;EACH,cAAc,WAAW;EAC1B,CAAC;AAGJ,KAAI,WAAW,SAAS,YAAY,WAAW,MAAM,KACnD,QAAO,IAAIC,yBAAAA,cAAc;EAAE,GAAG;EAAY,IAAI,WAAW;EAAI,CAAC;AAGhE,SAAA,GAAA,yBAAA,4BAAkC,WAAW;;;;;;AAO/C,SAAgB,uBACd,UACoC;AACpC,QAAO,SAAS,KAAK,QAAQ;AAC3B,MAAI,OAAQ,IAAoB,YAAY,WAC1C,QAAO;AAET,SAAO,8BACL,IACD;GACD;;AAGJ,SAAS,iCACP,SACG;CACH,MAAM,SAAS;CACf,MAAM,gBAAgB,OAAO,iBAAiB,OAAO;AACrD,KAAI,CAAC,MAAM,QAAQ,cAAc,IAAI,cAAc,WAAW,EAC5D,QAAO;CAGT,MAAM,4BACJ,eAAe,OAAO,QAAQ,IAC7B,CAAC,eAAe,OAAO,QAAQ,IAAI,eAAe,cAAc;AACnE,KAAI,CAAC,6BAA6B,OAAO,kBAAkB,cACzD,QAAO;AAGT,QAAO;EACL,GAAG;EACH,SAAS,4BAA4B,gBAAgB,OAAO;EAC5D;EACD;;AAGH,SAAgB,4BACd,SACG;CACH,MAAM,aAAa,iCAAiC,QAAQ;CAC5D,MAAM,SAAS;AAIf,KAAI,MAAM,QAAQ,OAAO,WAAW,IAAI,OAAO,WAAW,SAAS,EACjE,QAAO;CAGT,MAAM,YAAY,4BAA4B,OAAO,QAAQ;AAC7D,KAAI,UAAU,WAAW,EAAG,QAAO;AACnC,QAAO;EACL,GAAG;EACH,YAAY;EACb;;AAGH,SAAS,4BAA4B,SAAkB;AACrD,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO,EAAE;AACtC,QAAO,QAAQ,SAEX,UAMI;AACJ,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO,EAAE;EACzD,MAAM,SAAS;AACf,MAAI,OAAO,SAAS,eAAe,OAAO,SAAS,WAAY,QAAO,EAAE;AACxE,SAAO,CACL;GACE,IAAI,OAAO,MAAM;GACjB,MAAM,OAAO,QAAQ;GACrB,MAAM,sBAAsB,OAAO,QAAQ,OAAO,MAAM;GACxD,MAAM;GACP,CACF;GAEJ;;AAGH,SAAS,sBAAsB,OAAyC;AACtE,KAAI,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,CACrE,QAAO;AAET,KAAI,OAAO,UAAU,YAAY,MAAM,SAAS,EAC9C,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MACE,UAAU,QACV,OAAO,WAAW,YAClB,CAAC,MAAM,QAAQ,OAAO,CAEtB,QAAO;SAEH;AAIV,QAAO,EAAE;;AAGX,SAAS,eAAe,SAA2B;AACjD,QACE,WAAW,QACX,YAAY,MACX,MAAM,QAAQ,QAAQ,IAAI,QAAQ,WAAW;;AAIlD,SAAS,eAAe,SAA2B;AACjD,KAAI,OAAO,YAAY,SAAU,QAAO,QAAQ,SAAS;AACzD,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;AACpC,QAAO,QAAQ,MAAM,UAAU;AAC7B,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,SAAS;AACrD,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;EACvD,MAAM,SAAS;AACf,SACE,OAAO,SAAS,UAChB,OAAO,OAAO,SAAS,YACvB,OAAO,KAAK,SAAS;GAEvB"}