@assistant-ui/react-langchain 0.0.18 → 0.0.20

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.
@@ -1,7 +1,6 @@
1
1
  import { LangChainBaseMessage, UIMessage } from "./types.js";
2
2
  import { AppendMessage, MessageTiming } from "@assistant-ui/core";
3
3
  import { useExternalMessageConverter } from "@assistant-ui/core/react";
4
-
5
4
  //#region src/convertMessages.d.ts
6
5
  type LangChainMessageConverterMetadata = useExternalMessageConverter.Metadata & {
7
6
  uiMessagesByParent?: Map<string, UIMessage[]>;
@@ -13,20 +12,33 @@ declare const getMessageContent: (msg: AppendMessage) => string | ({
13
12
  type: "text";
14
13
  text: string;
15
14
  image_url?: never;
16
- data?: never;
15
+ url?: never;
17
16
  mime_type?: never;
18
17
  metadata?: never;
19
18
  source_type?: never;
19
+ data?: never;
20
20
  } | {
21
21
  type: "image_url";
22
22
  image_url: {
23
23
  url: string;
24
24
  };
25
25
  text?: never;
26
- data?: never;
26
+ url?: never;
27
27
  mime_type?: never;
28
28
  metadata?: never;
29
29
  source_type?: never;
30
+ data?: never;
31
+ } | {
32
+ type: "file";
33
+ url: string;
34
+ mime_type: string;
35
+ metadata: {
36
+ filename: string;
37
+ };
38
+ source_type: "url";
39
+ text?: never;
40
+ image_url?: never;
41
+ data?: never;
30
42
  } | {
31
43
  type: "file";
32
44
  data: string;
@@ -37,6 +49,7 @@ declare const getMessageContent: (msg: AppendMessage) => string | ({
37
49
  source_type: "base64";
38
50
  text?: never;
39
51
  image_url?: never;
52
+ url?: never;
40
53
  })[];
41
54
  //#endregion
42
55
  export { convertLangChainBaseMessage, getMessageContent, getMessageType };
@@ -1 +1 @@
1
- {"version":3,"file":"convertMessages.d.ts","names":[],"sources":["../src/convertMessages.ts"],"mappings":";;;;;KAeK,iCAAA,GACH,2BAAA,CAA4B,QAAA;EAC1B,kBAAA,GAAqB,GAAA,SAAY,SAAA;EACjC,aAAA,GAAgB,MAAA,SAAe,aAAA;AAAA;AAAA,cAStB,cAAA,GAAkB,OAA6B,EAApB,oBAAoB;AAAA,cAoE/C,2BAAA,GACX,OAAA,EAAS,oBAAA,EACT,QAAA,GAAU,iCAAA,KACT,2BAAA,CAA4B,OAAA;AAAA,cAyFlB,iBAAA,GAAqB,GAAA,EAAK,aAAa"}
1
+ {"version":3,"file":"convertMessages.d.ts","names":[],"sources":["../src/convertMessages.ts"],"mappings":";;;;KAgBK,oCACH,4BAA4B;EAC1B,qBAAqB,YAAY;EACjC,gBAAgB,eAAe;;cAStB,iBAAkB,SAAS;cAyE3B,8BACX,SAAS,sBACT,WAAU,sCACT,4BAA4B;cAyFlB,oBAAqB,KAAK"}
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { httpUrlPattern, parseDataUrl } from "@assistant-ui/core/internal";
2
3
  //#region src/convertMessages.ts
3
4
  const uiMessageToDataPart = (ui) => ({
4
5
  type: "data",
@@ -33,8 +34,8 @@ const contentToParts = (content) => {
33
34
  case "file": return {
34
35
  type: "file",
35
36
  filename: part.metadata?.filename ?? "file",
36
- data: part.data,
37
- mimeType: part.mime_type
37
+ data: part.source_type === "url" ? part.url : part.source_type === "id" ? part.id : part.data,
38
+ mimeType: part.mime_type ?? "application/octet-stream"
38
39
  };
39
40
  case "thinking": return {
40
41
  type: "reasoning",
@@ -135,13 +136,24 @@ const getMessageContent = (msg) => {
135
136
  type: "image_url",
136
137
  image_url: { url: part.image }
137
138
  };
138
- case "file": return {
139
- type: "file",
140
- data: part.data,
141
- mime_type: part.mimeType,
142
- metadata: { filename: part.filename ?? "file" },
143
- source_type: "base64"
144
- };
139
+ case "file": {
140
+ const metadata = { filename: part.filename ?? "file" };
141
+ if (httpUrlPattern.test(part.data)) return {
142
+ type: "file",
143
+ url: part.data,
144
+ mime_type: part.mimeType,
145
+ metadata,
146
+ source_type: "url"
147
+ };
148
+ const parsed = parseDataUrl(part.data);
149
+ return {
150
+ type: "file",
151
+ data: parsed?.data ?? part.data,
152
+ mime_type: parsed?.mimeType ?? part.mimeType,
153
+ metadata,
154
+ source_type: "base64"
155
+ };
156
+ }
145
157
  case "tool-call": throw new Error("Tool call appends are not supported.");
146
158
  default: throw new Error(`Unsupported append message part type: ${type}`);
147
159
  }
@@ -1 +1 @@
1
- {"version":3,"file":"convertMessages.js","names":["parts","_exhaustiveCheck"],"sources":["../src/convertMessages.ts"],"sourcesContent":["\"use client\";\n\nimport type { useExternalMessageConverter } from \"@assistant-ui/core/react\";\nimport type {\n AppendMessage,\n DataMessagePart,\n MessageTiming,\n} from \"@assistant-ui/core\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type {\n LangChainBaseMessage,\n LangChainContentBlock,\n UIMessage,\n} from \"./types\";\n\ntype LangChainMessageConverterMetadata =\n useExternalMessageConverter.Metadata & {\n uiMessagesByParent?: Map<string, UIMessage[]>;\n messageTiming?: Record<string, MessageTiming>;\n };\n\nconst uiMessageToDataPart = (ui: UIMessage): DataMessagePart => ({\n type: \"data\",\n name: ui.name,\n data: ui.props,\n});\n\nexport const getMessageType = (message: LangChainBaseMessage): string => {\n if (typeof message._getType === \"function\") return message._getType();\n if (\"type\" in message)\n return (message as Record<string, unknown>).type as string;\n throw new Error(\"Cannot determine message type\");\n};\n\nconst contentToParts = (content: unknown) => {\n if (typeof content === \"string\")\n return [{ type: \"text\" as const, text: content }];\n\n const parts = content as readonly LangChainContentBlock[];\n return parts\n .map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n case \"text_delta\":\n return { type: \"text\" as const, text: part.text };\n case \"image_url\": {\n const image =\n typeof part.image_url === \"string\"\n ? part.image_url\n : part.image_url?.url;\n if (!image) return null;\n return { type: \"image\" as const, image };\n }\n case \"file\":\n return {\n type: \"file\" as const,\n filename: part.metadata?.filename ?? \"file\",\n data: part.data,\n mimeType: part.mime_type,\n };\n case \"thinking\":\n return { type: \"reasoning\" as const, text: part.thinking };\n case \"reasoning\":\n return {\n type: \"reasoning\" as const,\n text:\n part.summary?.map((s) => s?.text ?? \"\").join(\"\\n\\n\\n\") ??\n part.reasoning ??\n \"\",\n };\n case \"tool_use\":\n case \"input_json_delta\":\n return null;\n default:\n return null;\n }\n })\n .filter((p) => p !== null);\n};\n\nconst getCustomMetadata = (\n additionalKwargs: Record<string, unknown> | undefined,\n): Record<string, unknown> =>\n (additionalKwargs?.metadata as Record<string, unknown>) ?? {};\n\nconst getStringContent = (content: unknown): string => {\n if (typeof content === \"string\") return content;\n const parts = content as readonly LangChainContentBlock[];\n return parts\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n};\n\nexport const convertLangChainBaseMessage = (\n message: LangChainBaseMessage,\n metadata: LangChainMessageConverterMetadata = {},\n): useExternalMessageConverter.Message => {\n const type = getMessageType(message);\n\n switch (type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: getStringContent(message.content) }],\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n },\n };\n\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: contentToParts(message.content),\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n },\n };\n\n case \"ai\": {\n const toolCallParts =\n message.tool_calls?.map((tc) => ({\n type: \"tool-call\" as const,\n toolCallId: tc.id,\n toolName: tc.name,\n args: tc.args as ReadonlyJSONObject,\n argsText: JSON.stringify(tc.args),\n })) ?? [];\n\n const assistantStatus =\n typeof message.status === \"object\" ? message.status : undefined;\n\n const uiDataParts =\n (message.id\n ? metadata.uiMessagesByParent\n ?.get(message.id)\n ?.map(uiMessageToDataPart)\n : undefined) ?? [];\n\n const timing = metadata.messageTiming?.[message.id ?? \"\"];\n\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n ...contentToParts(message.content),\n ...toolCallParts,\n ...uiDataParts,\n ],\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n ...(timing && { timing }),\n },\n ...(assistantStatus && { status: assistantStatus }),\n };\n }\n\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name ?? \"\",\n toolCallId: message.tool_call_id ?? \"\",\n result: message.content,\n artifact: message.artifact,\n isError: message.status === \"error\",\n };\n\n default:\n return {\n role: \"system\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text:\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content),\n },\n ],\n };\n }\n};\n\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n\n const hasNonText = allContent.some(\n (part) => part.type === \"file\" || part.type === \"image\",\n );\n const hasText = allContent.some((part) => part.type === \"text\");\n if (hasNonText && !hasText) {\n allContent.unshift({ type: \"text\", text: \" \" });\n }\n\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n case \"file\":\n return {\n type: \"file\" as const,\n data: part.data,\n mime_type: part.mimeType,\n metadata: { filename: part.filename ?? \"file\" },\n source_type: \"base64\" as const,\n };\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n default: {\n const _exhaustiveCheck:\n | \"reasoning\"\n | \"source\"\n | \"audio\"\n | \"data\"\n | \"generative-ui\" = type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n return content;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"convertMessages.js","names":["parts","_exhaustiveCheck"],"sources":["../src/convertMessages.ts"],"sourcesContent":["\"use client\";\n\nimport type { useExternalMessageConverter } from \"@assistant-ui/core/react\";\nimport type {\n AppendMessage,\n DataMessagePart,\n MessageTiming,\n} from \"@assistant-ui/core\";\nimport { httpUrlPattern, parseDataUrl } from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type {\n LangChainBaseMessage,\n LangChainContentBlock,\n UIMessage,\n} from \"./types\";\n\ntype LangChainMessageConverterMetadata =\n useExternalMessageConverter.Metadata & {\n uiMessagesByParent?: Map<string, UIMessage[]>;\n messageTiming?: Record<string, MessageTiming>;\n };\n\nconst uiMessageToDataPart = (ui: UIMessage): DataMessagePart => ({\n type: \"data\",\n name: ui.name,\n data: ui.props,\n});\n\nexport const getMessageType = (message: LangChainBaseMessage): string => {\n if (typeof message._getType === \"function\") return message._getType();\n if (\"type\" in message)\n return (message as Record<string, unknown>).type as string;\n throw new Error(\"Cannot determine message type\");\n};\n\nconst contentToParts = (content: unknown) => {\n if (typeof content === \"string\")\n return [{ type: \"text\" as const, text: content }];\n\n const parts = content as readonly LangChainContentBlock[];\n return parts\n .map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n case \"text_delta\":\n return { type: \"text\" as const, text: part.text };\n case \"image_url\": {\n const image =\n typeof part.image_url === \"string\"\n ? part.image_url\n : part.image_url?.url;\n if (!image) return null;\n return { type: \"image\" as const, image };\n }\n case \"file\":\n return {\n type: \"file\" as const,\n filename: part.metadata?.filename ?? \"file\",\n data:\n part.source_type === \"url\"\n ? part.url\n : part.source_type === \"id\"\n ? part.id\n : part.data,\n mimeType: part.mime_type ?? \"application/octet-stream\",\n };\n case \"thinking\":\n return { type: \"reasoning\" as const, text: part.thinking };\n case \"reasoning\":\n return {\n type: \"reasoning\" as const,\n text:\n part.summary?.map((s) => s?.text ?? \"\").join(\"\\n\\n\\n\") ??\n part.reasoning ??\n \"\",\n };\n case \"tool_use\":\n case \"input_json_delta\":\n return null;\n default:\n return null;\n }\n })\n .filter((p) => p !== null);\n};\n\nconst getCustomMetadata = (\n additionalKwargs: Record<string, unknown> | undefined,\n): Record<string, unknown> =>\n (additionalKwargs?.metadata as Record<string, unknown>) ?? {};\n\nconst getStringContent = (content: unknown): string => {\n if (typeof content === \"string\") return content;\n const parts = content as readonly LangChainContentBlock[];\n return parts\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n};\n\nexport const convertLangChainBaseMessage = (\n message: LangChainBaseMessage,\n metadata: LangChainMessageConverterMetadata = {},\n): useExternalMessageConverter.Message => {\n const type = getMessageType(message);\n\n switch (type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: getStringContent(message.content) }],\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n },\n };\n\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: contentToParts(message.content),\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n },\n };\n\n case \"ai\": {\n const toolCallParts =\n message.tool_calls?.map((tc) => ({\n type: \"tool-call\" as const,\n toolCallId: tc.id,\n toolName: tc.name,\n args: tc.args as ReadonlyJSONObject,\n argsText: JSON.stringify(tc.args),\n })) ?? [];\n\n const assistantStatus =\n typeof message.status === \"object\" ? message.status : undefined;\n\n const uiDataParts =\n (message.id\n ? metadata.uiMessagesByParent\n ?.get(message.id)\n ?.map(uiMessageToDataPart)\n : undefined) ?? [];\n\n const timing = metadata.messageTiming?.[message.id ?? \"\"];\n\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n ...contentToParts(message.content),\n ...toolCallParts,\n ...uiDataParts,\n ],\n metadata: {\n custom: getCustomMetadata(message.additional_kwargs),\n ...(timing && { timing }),\n },\n ...(assistantStatus && { status: assistantStatus }),\n };\n }\n\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name ?? \"\",\n toolCallId: message.tool_call_id ?? \"\",\n result: message.content,\n artifact: message.artifact,\n isError: message.status === \"error\",\n };\n\n default:\n return {\n role: \"system\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text:\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content),\n },\n ],\n };\n }\n};\n\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n\n const hasNonText = allContent.some(\n (part) => part.type === \"file\" || part.type === \"image\",\n );\n const hasText = allContent.some((part) => part.type === \"text\");\n if (hasNonText && !hasText) {\n allContent.unshift({ type: \"text\", text: \" \" });\n }\n\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n case \"file\": {\n const metadata = { filename: part.filename ?? \"file\" };\n if (httpUrlPattern.test(part.data)) {\n return {\n type: \"file\" as const,\n url: part.data,\n mime_type: part.mimeType,\n metadata,\n source_type: \"url\" as const,\n };\n }\n const parsed = parseDataUrl(part.data);\n return {\n type: \"file\" as const,\n data: parsed?.data ?? part.data,\n mime_type: parsed?.mimeType ?? part.mimeType,\n metadata,\n source_type: \"base64\" as const,\n };\n }\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n default: {\n const _exhaustiveCheck:\n | \"reasoning\"\n | \"source\"\n | \"audio\"\n | \"data\"\n | \"generative-ui\" = type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n return content;\n};\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { LangChainBaseMessage } from "./types.js";
2
-
3
2
  //#region src/findForkCheckpointInHistory.d.ts
4
3
  type ForkCheckpointHistoryState = {
5
4
  values?: Record<string, unknown> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"findForkCheckpointInHistory.d.ts","names":[],"sources":["../src/findForkCheckpointInHistory.ts"],"mappings":";;;KAEK,0BAAA;EACH,MAAA,GAAS,MAAM;EACf,UAAA;IAAe,aAAA;EAAA;AAAA;AAAA,KAGZ,iBAAA;EAAsB,YAAA;IAAgB,aAAa;EAAA;AAAA;AAAA,KAE5C,oBAAA;EACV,OAAA;IACE,UAAA,GACE,QAAA,UACA,OAAA;MAAY,KAAA;MAAgB,MAAA,GAAS,iBAAA;IAAA,MAClC,OAAA,UAAiB,0BAAA;EAAA;AAAA;AAAA,cAIb,2BAAA,GACX,MAAA,EAAQ,oBAAA,EACR,QAAA,UACA,kBAAA,WAA6B,oBAAA,IAC7B,WAAA,UACA,QAAA,cACC,OAAA"}
1
+ {"version":3,"file":"findForkCheckpointInHistory.d.ts","names":[],"sources":["../src/findForkCheckpointInHistory.ts"],"mappings":";;KAEK;EACH,SAAS;EACT;IAAe;;;KAGZ;EAAsB;IAAgB;;;KAE/B;EACV;IACE,aACE,kBACA;MAAY;MAAgB,SAAS;UAClC,iBAAiB;;;cAIb,8BACX,QAAQ,sBACR,kBACA,6BAA6B,wBAC7B,qBACA,sBACC"}
package/dist/hooks.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { LangChainBaseMessage } from "./types.js";
2
2
  import { AssembledToolCall, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot } from "@langchain/react";
3
-
4
3
  //#region src/hooks.d.ts
5
4
  /**
6
5
  * Read the current LangGraph interrupt state from the runtime extras.
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;AAwBA;cAAa,0BAAA;EACuC,KAAA;AAAA;;AAOpD;;;;cAAa,sBAAA;EAIV,EAAA;EAAA,KAAA;AAAA;;cAGU,iBAAA;AASb;;;;AAAkC;AAIlC;AAJA,cAAa,qBAAA,iBAAqB,iBAAA;;cAIrB,qBAAA,QAAqB,WAAA,SAAA,yBAAA;AAAA;AAAA,cAIrB,qBAAA,QAAqB,WAAA,SAAA,yBAAA;;;;AAAA;AASlC;;cAAa,kBAAA,mCAAkB,SAAA;;AAAA;AAQ/B;;;cAAa,kBAAA,SAGT,MAAA,EAAQ,MAAA,sCACR,OAAA,GAAU,MAAA,sBAAuB,OAAA;;;;;;cASxB,mBAAA,SAEH,QAAA,WAAmB,OAAA,GAAU,MAAA,sBAAuB,OAAA;;;;;AAXzB;AASrC;cAYa,sBAAA,SAGT,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,MAAA,sBAAuB,OAAA;;;;;;cASxB,gBAAA,SAGT,QAAA,WAAmB,oBAAA,IACnB,OAAA,GAAU,MAAA,sBAAuB,OAAA;;AA3ByB;AAU9D;;;;;cA+Ba,uBAAA,SAEH,OAAA,EAAS,MAAA,sBAAuB,OAAA;;;;;;;;;AA7BL;AASrC;;iBAkCgB,iBAAA,IAAqB,GAAA,WAAc,CAAC;AAAA,iBACpC,iBAAA,IAAqB,GAAA,UAAa,YAAA,EAAc,CAAA,GAAI,CAAC"}
1
+ {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;cAwBa;EAAA;;;;;;;cAQA;EAAA;EAAA;;;cAOA;;;;;;;cASA,sCAAqB;;cAIrB,6BAAqB,oBAAA;;cAIrB,6BAAqB,oBAAA;;;;;;;cASrB,qDAAkB;;;;;;cAQlB,2BAGT,QAAQ,4CACR,UAAU,4BAAuB;;;;;;cASxB,4BAEH,mBAAmB,UAAU,4BAAuB;;;;;;;cAUjD,+BAGT,eAAe,yBACf,UAAU,4BAAuB;;;;;;cASxB,yBAGT,mBAAmB,wBACnB,UAAU,4BAAuB;;;;;;;;cAcxB,gCAEH,SAAS,4BAAuB;;;;;;;;;;;;iBAc1B,kBAAkB,GAAG,cAAc;iBACnC,kBAAkB,GAAG,aAAa,cAAc,IAAI"}
@@ -1,6 +1,5 @@
1
1
  import { LangChainBaseMessage } from "./types.js";
2
2
  import { ForkCheckpointClient } from "./findForkCheckpointInHistory.js";
3
-
4
3
  //#region src/resolveForkCheckpoint.d.ts
5
4
  type MessageMetadataSnapshot = ReadonlyMap<string, {
6
5
  readonly parentCheckpointId: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"resolveForkCheckpoint.d.ts","names":[],"sources":["../src/resolveForkCheckpoint.ts"],"mappings":";;;;KAMK,uBAAA,GACD,WAAW;EAAA,SAAoB,kBAAkB;AAAA;;;;AAAA;AASrD;;cAAa,qBAAA,GACX,MAAA,EAAQ,oBAAA,EACR,QAAA,UACA,QAAA,WAAmB,oBAAA,IACnB,QAAA,iBACA,QAAA,6BACA,QAAA,EAAU,uBAAA,EACV,WAAA,aACC,OAAA"}
1
+ {"version":3,"file":"resolveForkCheckpoint.d.ts","names":[],"sources":["../src/resolveForkCheckpoint.ts"],"mappings":";;;KAMK,0BACD;WAA+B;;;;;;;;cAStB,wBACX,QAAQ,sBACR,kBACA,mBAAmB,wBACnB,yBACA,qCACA,UAAU,yBACV,wBACC"}
@@ -1,5 +1,4 @@
1
1
  import { LangChainRuntimeExtras } from "./types.js";
2
-
3
2
  //#region src/runtimeExtras.d.ts
4
3
  declare const langChainExtras: import("@assistant-ui/core/internal").RuntimeExtras<LangChainRuntimeExtras>;
5
4
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeExtras.d.ts","names":[],"sources":["../src/runtimeExtras.ts"],"mappings":";;;cAGa,eAAA,wCAAe,aAAA,CAAA,sBAAA"}
1
+ {"version":3,"file":"runtimeExtras.d.ts","names":[],"sources":["../src/runtimeExtras.ts"],"mappings":";;cAGa,uDAAe,cAAA"}
@@ -1,7 +1,6 @@
1
1
  import { LangChainBaseMessage } from "./types.js";
2
2
  import { MessageTiming } from "@assistant-ui/core";
3
3
  import { StreamingTimingAccessors } from "@assistant-ui/core/react";
4
-
5
4
  //#region src/streamingTiming.d.ts
6
5
  declare const langChainStreamingTimingAccessors: StreamingTimingAccessors<LangChainBaseMessage>;
7
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"streamingTiming.d.ts","names":[],"sources":["../src/streamingTiming.ts"],"mappings":";;;;;cAmEa,iCAAA,EAAmC,wBAAwB,CAAC,oBAAA;;AAAzE;;;;AAA6F;cAahF,2BAAA,GACX,QAAA,WAAmB,oBAAA,IACnB,SAAA,cACC,MAAA,SAAe,aAAA"}
1
+ {"version":3,"file":"streamingTiming.d.ts","names":[],"sources":["../src/streamingTiming.ts"],"mappings":";;;;cAmEa,mCAAmC,yBAAyB;;;;;;;cAa5D,8BACX,mBAAmB,wBACnB,uBACC,eAAe"}
package/dist/types.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { AttachmentAdapter, DictationAdapter, ExternalStoreSharedOptions, FeedbackAdapter, MessageStatus, RealtimeVoiceAdapter, RemoteThreadListAdapter, SpeechSynthesisAdapter } from "@assistant-ui/core";
2
2
  import { AnyStream, AssembledToolCall, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, UseStreamOptions } from "@langchain/react";
3
3
  import { AssistantCloud } from "assistant-cloud";
4
-
5
4
  //#region src/types.d.ts
6
5
  /** Known content block types from @langchain/core messages. */
7
6
  type LangChainContentBlock = {
@@ -33,6 +32,22 @@ type LangChainContentBlock = {
33
32
  metadata?: {
34
33
  filename?: string;
35
34
  };
35
+ } | {
36
+ type: "file";
37
+ url: string;
38
+ mime_type?: string;
39
+ source_type: "url";
40
+ metadata?: {
41
+ filename?: string;
42
+ };
43
+ } | {
44
+ type: "file";
45
+ id: string;
46
+ mime_type?: string;
47
+ source_type: "id";
48
+ metadata?: {
49
+ filename?: string;
50
+ };
36
51
  } | {
37
52
  type: "tool_use" | "input_json_delta";
38
53
  };
@@ -83,10 +98,14 @@ type LangChainBaseMessage = {
83
98
  content: unknown;
84
99
  id?: string | undefined;
85
100
  name?: string | undefined;
86
- additional_kwargs?: Record<string, unknown> | undefined; /** Present on AIMessage */
87
- tool_calls?: readonly LangChainToolCall[] | undefined; /** Present on ToolMessage */
88
- tool_call_id?: string | undefined; /** Completion status (AIMessage) or outcome status (ToolMessage) */
89
- status?: MessageStatus | "success" | "error" | undefined; /** Present on ToolMessage */
101
+ additional_kwargs?: Record<string, unknown> | undefined;
102
+ /** Present on AIMessage */
103
+ tool_calls?: readonly LangChainToolCall[] | undefined;
104
+ /** Present on ToolMessage */
105
+ tool_call_id?: string | undefined;
106
+ /** Completion status (AIMessage) or outcome status (ToolMessage) */
107
+ status?: MessageStatus | "success" | "error" | undefined;
108
+ /** Present on ToolMessage */
90
109
  artifact?: unknown;
91
110
  };
92
111
  type LangChainRuntimeExtras = {
@@ -142,10 +161,12 @@ type LangChainRuntimeExtraOptions = ExternalStoreSharedOptions & {
142
161
  * Custom `RemoteThreadListAdapter`. When provided, replaces the
143
162
  * cloud-backed thread list adapter.
144
163
  */
145
- unstable_threadListAdapter?: RemoteThreadListAdapter | undefined; /** Custom thread-creation hook, forwarded to the cloud adapter. */
164
+ unstable_threadListAdapter?: RemoteThreadListAdapter | undefined;
165
+ /** Custom thread-creation hook, forwarded to the cloud adapter. */
146
166
  create?: (() => Promise<{
147
167
  externalId: string | undefined;
148
- }>) | undefined; /** Custom thread-deletion hook, forwarded to the cloud adapter. */
168
+ }>) | undefined;
169
+ /** Custom thread-deletion hook, forwarded to the cloud adapter. */
149
170
  delete?: ((threadId: string) => Promise<void>) | undefined;
150
171
  /**
151
172
  * State key the graph accumulates generative `UIMessage`s under. Each UI
@@ -155,7 +176,7 @@ type LangChainRuntimeExtraOptions = ExternalStoreSharedOptions & {
155
176
  */
156
177
  uiStateKey?: string | undefined;
157
178
  };
158
- type UseStreamRuntimeOptions = UseStreamOptions extends infer O ? O extends UseStreamOptions ? O & LangChainRuntimeExtraOptions : never : never;
179
+ type UseStreamRuntimeOptions = UseStreamOptions extends (infer O) ? O extends UseStreamOptions ? O & LangChainRuntimeExtraOptions : never : never;
159
180
  //#endregion
160
181
  export { LangChainBaseMessage, LangChainContentBlock, LangChainRuntimeExtraOptions, LangChainRuntimeExtras, LangChainToolCall, RemoveUIMessage, UIMessage, UseStreamRuntimeOptions };
161
182
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;KAoBY,qBAAA;EACN,IAAA;EAAc,IAAA;AAAA;EACd,IAAA;EAAoB,IAAA;AAAA;EACpB,IAAA;EAAmB,SAAA;IAAsB,GAAA;EAAA;AAAA;EACzC,IAAA;EAAkB,QAAA;AAAA;EAElB,IAAA;EACA,OAAA,GAAU,KAAK;IAAG,IAAA;IAAsB,IAAA;EAAA;EACxC,SAAA;AAAA;EAGA,IAAA;EACA,IAAA;EACA,SAAA;EACA,WAAA;EACA,QAAA;IAAa,QAAA;EAAA;AAAA;EAEb,IAAA;AAAA;AAAA,KAEM,iBAAA;EACV,EAAA;EACA,IAAA;EACA,IAAA,EAAM,MAAM;AAAA;;AAAA;AAUd;;;;;KAAY,SAAA,+CAEK,MAAA,oBAA0B,MAAA;EAEzC,IAAA;EACA,EAAA;EACA,IAAA,EAAM,KAAA;EACN,KAAA,EAAO,MAAA;EACP,QAAA;IACE,KAAA;IACA,MAAA;IACA,IAAA;IACA,IAAA;IACA,UAAA;IACA,EAAA;IAAA,CACC,GAAA;EAAA;AAAA;;;;;KAQO,eAAA;EACV,IAAA;EACA,EAAE;AAAA;AAVY;AAQhB;;;;AAEI;AAUJ;AApBgB,KAoBJ,oBAAA;EACV,QAAA;EACA,OAAA;EACA,EAAA;EACA,IAAA;EACA,iBAAA,GAAoB,MAAA,+BAME;EAJtB,UAAA,YAAsB,iBAAA,gBALtB;EAOA,YAAA,uBALA;EAOA,MAAA,GAAS,aAAA,oCANW;EAQpB,QAAA;AAAA;AAAA,KAGU,sBAAA;EACV,SAAA;IAAa,KAAA;EAAA;EACb,UAAA;IAAuB,EAAA;IAAa,KAAA;EAAA;EACpC,SAAA,WAAoB,iBAAA;EACpB,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAC/B,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAC/B,MAAA,EAAQ,SAAA;EACR,KAAA;EACA,MAAA,GACE,MAAA,EAAQ,MAAA,sCACR,OAAA,GAAU,MAAA,sBACP,OAAA;EACL,OAAA,GACE,QAAA,WACA,OAAA,GAAU,MAAA,sBACP,OAAA;EACL,UAAA,GACE,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,MAAA,sBACP,OAAA;EACL,MAAA,EAAQ,MAAA;EACR,WAAA;AAAA;AAAA,KAGU,4BAAA,GAA+B,0BAAA;EAPxB;;;;;;;;EAgBjB,gBAAA,KAAqB,QAAA;EACrB,KAAA,GAAQ,cAAA;EACR,QAAA;IAEM,WAAA,GAAc,iBAAA;IACd,MAAA,GAAS,sBAAA;IACT,SAAA,GAAY,gBAAA;IACZ,KAAA,GAAQ,oBAAA;IACR,QAAA,GAAW,eAAA;EAAA;EApCN;;;;;;EA6CX,0BAAA;EAzCE;;;;EA8CF,0BAAA;EA1CE;;;;EA+CF,0BAAA,GAA6B,uBAAA,cA3CZ;EA6CjB,MAAA,UAAgB,OAAA;IAAU,UAAA;EAAA,iBA3CrB;EA6CL,MAAA,KAAW,QAAA,aAAqB,OAAA;EA5CxB;;;AACG;AAGb;;EA+CE,UAAA;AAAA;AAAA,KAOU,uBAAA,GAA0B,gBAAA,mBAClC,CAAA,SAAU,gBAAA,GACR,CAAA,GAAI,4BAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;KAoBY;EACN;EAAc;;EACd;EAAoB;;EACpB;EAAmB;IAAsB;;;EACzC;EAAkB;;EAElB;EACA,UAAU;IAAQ;IAAsB;;EACxC;;EAGA;EACA;EACA;EACA;EACA;IAAa;;;EAGb;EACA;EACA;EACA;EACA;IAAa;;;EAGb;EACA;EACA;EACA;EACA;IAAa;;;EAEb;;KAEM;EACV;EACA;EACA,MAAM;;;;;;;;;KAUI,UACV,+BACA,eAAe,0BAA0B;EAEzC;EACA;EACA,MAAM;EACN,OAAO;EACP;IACE;IACA;IACA;IACA;IACA;IACA;KACC;;;;;;;KAQO;EACV;EACA;;;;;;;;;KAUU;EACV;EACA;EACA;EACA;EACA,oBAAoB;;EAEpB,sBAAsB;;EAEtB;;EAEA,SAAS;;EAET;;KAGU;EACV;IAAa;;EACb;IAAuB;IAAa;;EACpC,oBAAoB;EACpB,WAAW,oBAAoB;EAC/B,WAAW,oBAAoB;EAC/B,QAAQ;EACR;EACA,SACE,QAAQ,4CACR,UAAU,4BACP;EACL,UACE,mBACA,UAAU,4BACP;EACL,aACE,eAAe,yBACf,UAAU,4BACP;EACL,QAAQ;EACR;;KAGU,+BAA+B;;;;;;;;;EASzC,qBAAqB;EACrB,QAAQ;EACR;IAEM,cAAc;IACd,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,WAAW;;;;;;;;EASjB;;;;;EAKA;;;;;EAKA,6BAA6B;;EAE7B,gBAAgB;IAAU;;;EAE1B,WAAW,qBAAqB;;;;;;;EAOhC;;KAOU,0BAA0B,gCAA+B,KACjE,UAAU,mBACR,IAAI"}
@@ -1,5 +1,4 @@
1
1
  import { RemoveUIMessage, UIMessage } from "./types.js";
2
-
3
2
  //#region src/uiMessages.d.ts
4
3
  type UIUpdate = UIMessage | RemoveUIMessage;
5
4
  declare const isUIUpdate: (value: unknown) => value is UIUpdate | readonly UIUpdate[];
@@ -1 +1 @@
1
- {"version":3,"file":"uiMessages.d.ts","names":[],"sources":["../src/uiMessages.ts"],"mappings":";;;KAEY,QAAA,GAAW,SAAA,GAAY,eAAe;AAAA,cAErC,UAAA,GACX,KAAA,cACC,KAAA,IAAS,QAAA,YAAoB,QAAQ;AAAA,cAmB3B,aAAA,GACX,IAAA,WAAe,SAAA,IACf,MAAA,EAAQ,QAAA,YAAoB,QAAA,OAC3B,SAAA;;;;AA1B+C;AAElD;cAkDa,eAAA,GACX,KAAA,cACC,QAAA,YAAoB,QAAQ;AAAA,cAQlB,aAAA,GAAiB,MAAA,yBAA6B,SAAS;;;;;;;AA1D5B;cA0E3B,eAAA,GACX,IAAA,WAAe,SAAA,IACf,QAAA,cACC,SAAS"}
1
+ {"version":3,"file":"uiMessages.d.ts","names":[],"sources":["../src/uiMessages.ts"],"mappings":";;KAEY,WAAW,YAAY;cAEtB,aACX,mBACC,SAAS,oBAAoB;cAmBnB,gBACX,eAAe,aACf,QAAQ,oBAAoB,eAC3B;;;;;;cA0BU,kBACX,mBACC,oBAAoB;cAQV,gBAAiB,+BAA6B;;;;;;;;cAgB9C,kBACX,eAAe,aACf,sBACC"}
@@ -1,7 +1,6 @@
1
1
  /// <reference types="@assistant-ui/core/store" />
2
2
  import { UIMessage, UseStreamRuntimeOptions } from "./types.js";
3
3
  import { AppendMessage } from "@assistant-ui/core";
4
-
5
4
  //#region src/useStreamRuntime.d.ts
6
5
  declare const runConfigToSubmitOptions: (runConfig: AppendMessage["runConfig"]) => {
7
6
  config: {
@@ -1 +1 @@
1
- {"version":3,"file":"useStreamRuntime.d.ts","names":[],"sources":["../src/useStreamRuntime.ts"],"mappings":";;;;cAsCa,wBAAA,GACX,SAAA,EAAW,aAAA;;kBAAA,MAAA;EAAA;AAAA;;;;;;;cAYA,uBAAA,GACX,KAAA,cACC,GAAG,SAAS,SAAA;;AAFf;;;;;;;;AAEwB;AAyZxB;;;;;;;;AA4BC;;;;;;cA5BY,gBAAA,GAAoB,UAAA,EAAY,uBAAuB,kCAAA,gBAAA"}
1
+ {"version":3,"file":"useStreamRuntime.d.ts","names":[],"sources":["../src/useStreamRuntime.ts"],"mappings":";;;cAsCa,2BACX,WAAW;;kBAAA;;;;;;;;;cAYA,0BACX,mBACC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;cAyZF,mBAAoB,YAAY,yDAAuB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-langchain",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "LangChain useStream adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "langchain",
@@ -29,10 +29,10 @@
29
29
  ],
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
- "@assistant-ui/core": "^0.2.19",
33
- "@assistant-ui/store": "^0.2.19",
32
+ "@assistant-ui/core": "^0.2.22",
33
+ "@assistant-ui/store": "^0.2.21",
34
34
  "assistant-cloud": "*",
35
- "assistant-stream": "^0.3.24"
35
+ "assistant-stream": "^0.3.27"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@langchain/react": "^1.0.2",
@@ -45,15 +45,15 @@
45
45
  }
46
46
  },
47
47
  "devDependencies": {
48
- "@langchain/core": "^1.2.1",
49
- "@langchain/langgraph-sdk": "^1.9.24",
50
- "@langchain/react": "^1.0.25",
48
+ "@langchain/core": "^1.2.3",
49
+ "@langchain/langgraph-sdk": "^1.9.28",
50
+ "@langchain/react": "^1.0.29",
51
51
  "@testing-library/react": "^16.3.2",
52
52
  "@types/react": "^19.2.17",
53
53
  "jsdom": "^29.1.1",
54
- "react": "^19.2.7",
55
- "vitest": "^4.1.9",
56
- "@assistant-ui/x-buildutils": "0.0.17"
54
+ "react": "^19.2.8",
55
+ "vitest": "^4.1.10",
56
+ "@assistant-ui/x-buildutils": "0.0.19"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public",
@@ -1,5 +1,9 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { convertLangChainBaseMessage } from "./convertMessages";
2
+ import type { AppendMessage } from "@assistant-ui/core";
3
+ import {
4
+ convertLangChainBaseMessage,
5
+ getMessageContent,
6
+ } from "./convertMessages";
3
7
  import type { LangChainBaseMessage, UIMessage } from "./types";
4
8
 
5
9
  const humanMessage = (content: unknown): LangChainBaseMessage => ({
@@ -62,6 +66,140 @@ describe("convertLangChainBaseMessage file content parts", () => {
62
66
  },
63
67
  ]);
64
68
  });
69
+
70
+ it("converts a url source file block", () => {
71
+ const result = convertLangChainBaseMessage(
72
+ humanMessage([
73
+ {
74
+ type: "file",
75
+ url: "https://r2.example/u/abc/file.pdf",
76
+ mime_type: "application/pdf",
77
+ source_type: "url",
78
+ metadata: { filename: "file.pdf" },
79
+ },
80
+ ]),
81
+ {},
82
+ );
83
+
84
+ expect(contentOf(result)).toEqual([
85
+ {
86
+ type: "file",
87
+ filename: "file.pdf",
88
+ data: "https://r2.example/u/abc/file.pdf",
89
+ mimeType: "application/pdf",
90
+ },
91
+ ]);
92
+ });
93
+
94
+ it("converts an id source file block", () => {
95
+ const result = convertLangChainBaseMessage(
96
+ humanMessage([{ type: "file", id: "file-abc123", source_type: "id" }]),
97
+ {},
98
+ );
99
+
100
+ expect(contentOf(result)).toEqual([
101
+ {
102
+ type: "file",
103
+ filename: "file",
104
+ data: "file-abc123",
105
+ mimeType: "application/octet-stream",
106
+ },
107
+ ]);
108
+ });
109
+ });
110
+
111
+ describe("getMessageContent file blocks", () => {
112
+ const appendMessage = (part: Record<string, unknown>) =>
113
+ ({ content: [part] }) as unknown as AppendMessage;
114
+
115
+ it("emits a base64 source block for raw base64 data", () => {
116
+ const content = getMessageContent(
117
+ appendMessage({
118
+ type: "file",
119
+ data: "ZmFrZQ==",
120
+ mimeType: "application/pdf",
121
+ filename: "a.pdf",
122
+ }),
123
+ );
124
+
125
+ expect(content).toEqual([
126
+ { type: "text", text: " " },
127
+ {
128
+ type: "file",
129
+ data: "ZmFrZQ==",
130
+ mime_type: "application/pdf",
131
+ metadata: { filename: "a.pdf" },
132
+ source_type: "base64",
133
+ },
134
+ ]);
135
+ });
136
+
137
+ it("emits a url source block with the value in the url key for http(s) data", () => {
138
+ const content = getMessageContent(
139
+ appendMessage({
140
+ type: "file",
141
+ data: "https://r2.example/u/abc/file.pdf",
142
+ mimeType: "application/pdf",
143
+ filename: "file.pdf",
144
+ }),
145
+ );
146
+
147
+ expect(content).toEqual([
148
+ { type: "text", text: " " },
149
+ {
150
+ type: "file",
151
+ url: "https://r2.example/u/abc/file.pdf",
152
+ mime_type: "application/pdf",
153
+ metadata: { filename: "file.pdf" },
154
+ source_type: "url",
155
+ },
156
+ ]);
157
+ expect(content[1]).not.toHaveProperty("data");
158
+ });
159
+
160
+ it("normalizes a base64 data URL to a raw base64 block", () => {
161
+ const content = getMessageContent(
162
+ appendMessage({
163
+ type: "file",
164
+ data: "data:application/pdf;base64,ZmFrZQ==",
165
+ mimeType: "application/octet-stream",
166
+ filename: "a.pdf",
167
+ }),
168
+ );
169
+
170
+ expect(content).toEqual([
171
+ { type: "text", text: " " },
172
+ {
173
+ type: "file",
174
+ data: "ZmFrZQ==",
175
+ mime_type: "application/pdf",
176
+ metadata: { filename: "a.pdf" },
177
+ source_type: "base64",
178
+ },
179
+ ]);
180
+ });
181
+
182
+ it("keeps non-http schemes on the base64 path", () => {
183
+ const content = getMessageContent(
184
+ appendMessage({
185
+ type: "file",
186
+ data: "blob:https://app.example/123",
187
+ mimeType: "application/pdf",
188
+ filename: "a.pdf",
189
+ }),
190
+ );
191
+
192
+ expect(content).toEqual([
193
+ { type: "text", text: " " },
194
+ {
195
+ type: "file",
196
+ data: "blob:https://app.example/123",
197
+ mime_type: "application/pdf",
198
+ metadata: { filename: "a.pdf" },
199
+ source_type: "base64",
200
+ },
201
+ ]);
202
+ });
65
203
  });
66
204
 
67
205
  describe("convertLangChainBaseMessage reasoning content parts", () => {
@@ -6,6 +6,7 @@ import type {
6
6
  DataMessagePart,
7
7
  MessageTiming,
8
8
  } from "@assistant-ui/core";
9
+ import { httpUrlPattern, parseDataUrl } from "@assistant-ui/core/internal";
9
10
  import type { ReadonlyJSONObject } from "assistant-stream/utils";
10
11
  import type {
11
12
  LangChainBaseMessage,
@@ -56,8 +57,13 @@ const contentToParts = (content: unknown) => {
56
57
  return {
57
58
  type: "file" as const,
58
59
  filename: part.metadata?.filename ?? "file",
59
- data: part.data,
60
- mimeType: part.mime_type,
60
+ data:
61
+ part.source_type === "url"
62
+ ? part.url
63
+ : part.source_type === "id"
64
+ ? part.id
65
+ : part.data,
66
+ mimeType: part.mime_type ?? "application/octet-stream",
61
67
  };
62
68
  case "thinking":
63
69
  return { type: "reasoning" as const, text: part.thinking };
@@ -206,14 +212,26 @@ export const getMessageContent = (msg: AppendMessage) => {
206
212
  return { type: "text" as const, text: part.text };
207
213
  case "image":
208
214
  return { type: "image_url" as const, image_url: { url: part.image } };
209
- case "file":
215
+ case "file": {
216
+ const metadata = { filename: part.filename ?? "file" };
217
+ if (httpUrlPattern.test(part.data)) {
218
+ return {
219
+ type: "file" as const,
220
+ url: part.data,
221
+ mime_type: part.mimeType,
222
+ metadata,
223
+ source_type: "url" as const,
224
+ };
225
+ }
226
+ const parsed = parseDataUrl(part.data);
210
227
  return {
211
228
  type: "file" as const,
212
- data: part.data,
213
- mime_type: part.mimeType,
214
- metadata: { filename: part.filename ?? "file" },
229
+ data: parsed?.data ?? part.data,
230
+ mime_type: parsed?.mimeType ?? part.mimeType,
231
+ metadata,
215
232
  source_type: "base64" as const,
216
233
  };
234
+ }
217
235
  case "tool-call":
218
236
  throw new Error("Tool call appends are not supported.");
219
237
  default: {
package/src/types.ts CHANGED
@@ -35,6 +35,20 @@ export type LangChainContentBlock =
35
35
  source_type?: "base64";
36
36
  metadata?: { filename?: string };
37
37
  }
38
+ | {
39
+ type: "file";
40
+ url: string;
41
+ mime_type?: string;
42
+ source_type: "url";
43
+ metadata?: { filename?: string };
44
+ }
45
+ | {
46
+ type: "file";
47
+ id: string;
48
+ mime_type?: string;
49
+ source_type: "id";
50
+ metadata?: { filename?: string };
51
+ }
38
52
  | { type: "tool_use" | "input_json_delta" };
39
53
 
40
54
  export type LangChainToolCall = {