@assistant-ui/react-langchain 0.0.18 → 0.0.19

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":";;;;KAeK,oCACH,4BAA4B;EAC1B,qBAAqB,YAAY;EACjC,gBAAgB,eAAe;;cAStB,iBAAkB,SAAS;cAyE3B,8BACX,SAAS,sBACT,WAAU,sCACT,4BAA4B;cAmGlB,oBAAqB,KAAK"}
@@ -33,8 +33,8 @@ const contentToParts = (content) => {
33
33
  case "file": return {
34
34
  type: "file",
35
35
  filename: part.metadata?.filename ?? "file",
36
- data: part.data,
37
- mimeType: part.mime_type
36
+ data: part.source_type === "url" ? part.url : part.source_type === "id" ? part.id : part.data,
37
+ mimeType: part.mime_type ?? "application/octet-stream"
38
38
  };
39
39
  case "thinking": return {
40
40
  type: "reasoning",
@@ -116,6 +116,15 @@ const convertLangChainBaseMessage = (message, metadata = {}) => {
116
116
  };
117
117
  }
118
118
  };
119
+ const parseDataUrl = (value) => {
120
+ const match = value.match(/^data:([^;,]+)(?:;[^;,]+)*;base64,(.+)$/);
121
+ if (!match) return null;
122
+ return {
123
+ mimeType: match[1],
124
+ data: match[2]
125
+ };
126
+ };
127
+ const httpUrlPattern = /^https?:\/\//i;
119
128
  const getMessageContent = (msg) => {
120
129
  const allContent = [...msg.content, ...msg.attachments?.flatMap((a) => a.content) ?? []];
121
130
  const hasNonText = allContent.some((part) => part.type === "file" || part.type === "image");
@@ -135,13 +144,24 @@ const getMessageContent = (msg) => {
135
144
  type: "image_url",
136
145
  image_url: { url: part.image }
137
146
  };
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
- };
147
+ case "file": {
148
+ const metadata = { filename: part.filename ?? "file" };
149
+ if (httpUrlPattern.test(part.data)) return {
150
+ type: "file",
151
+ url: part.data,
152
+ mime_type: part.mimeType,
153
+ metadata,
154
+ source_type: "url"
155
+ };
156
+ const parsed = parseDataUrl(part.data);
157
+ return {
158
+ type: "file",
159
+ data: parsed?.data ?? part.data,
160
+ mime_type: parsed?.mimeType ?? part.mimeType,
161
+ metadata,
162
+ source_type: "base64"
163
+ };
164
+ }
145
165
  case "tool-call": throw new Error("Tool call appends are not supported.");
146
166
  default: throw new Error(`Unsupported append message part type: ${type}`);
147
167
  }
@@ -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 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\nconst parseDataUrl = (\n value: string,\n): { mimeType: string; data: string } | null => {\n const match = value.match(/^data:([^;,]+)(?:;[^;,]+)*;base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1]!, data: match[2]! };\n};\n\nconst httpUrlPattern = /^https?:\\/\\//i;\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.19",
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.21",
33
+ "@assistant-ui/store": "^0.2.20",
34
34
  "assistant-cloud": "*",
35
- "assistant-stream": "^0.3.24"
35
+ "assistant-stream": "^0.3.26"
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.25",
50
+ "@langchain/react": "^1.0.26",
51
51
  "@testing-library/react": "^16.3.2",
52
52
  "@types/react": "^19.2.17",
53
53
  "jsdom": "^29.1.1",
54
54
  "react": "^19.2.7",
55
- "vitest": "^4.1.9",
56
- "@assistant-ui/x-buildutils": "0.0.17"
55
+ "vitest": "^4.1.10",
56
+ "@assistant-ui/x-buildutils": "0.0.18"
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", () => {
@@ -56,8 +56,13 @@ const contentToParts = (content: unknown) => {
56
56
  return {
57
57
  type: "file" as const,
58
58
  filename: part.metadata?.filename ?? "file",
59
- data: part.data,
60
- mimeType: part.mime_type,
59
+ data:
60
+ part.source_type === "url"
61
+ ? part.url
62
+ : part.source_type === "id"
63
+ ? part.id
64
+ : part.data,
65
+ mimeType: part.mime_type ?? "application/octet-stream",
61
66
  };
62
67
  case "thinking":
63
68
  return { type: "reasoning" as const, text: part.thinking };
@@ -185,6 +190,16 @@ export const convertLangChainBaseMessage = (
185
190
  }
186
191
  };
187
192
 
193
+ const parseDataUrl = (
194
+ value: string,
195
+ ): { mimeType: string; data: string } | null => {
196
+ const match = value.match(/^data:([^;,]+)(?:;[^;,]+)*;base64,(.+)$/);
197
+ if (!match) return null;
198
+ return { mimeType: match[1]!, data: match[2]! };
199
+ };
200
+
201
+ const httpUrlPattern = /^https?:\/\//i;
202
+
188
203
  export const getMessageContent = (msg: AppendMessage) => {
189
204
  const allContent = [
190
205
  ...msg.content,
@@ -206,14 +221,26 @@ export const getMessageContent = (msg: AppendMessage) => {
206
221
  return { type: "text" as const, text: part.text };
207
222
  case "image":
208
223
  return { type: "image_url" as const, image_url: { url: part.image } };
209
- case "file":
224
+ case "file": {
225
+ const metadata = { filename: part.filename ?? "file" };
226
+ if (httpUrlPattern.test(part.data)) {
227
+ return {
228
+ type: "file" as const,
229
+ url: part.data,
230
+ mime_type: part.mimeType,
231
+ metadata,
232
+ source_type: "url" as const,
233
+ };
234
+ }
235
+ const parsed = parseDataUrl(part.data);
210
236
  return {
211
237
  type: "file" as const,
212
- data: part.data,
213
- mime_type: part.mimeType,
214
- metadata: { filename: part.filename ?? "file" },
238
+ data: parsed?.data ?? part.data,
239
+ mime_type: parsed?.mimeType ?? part.mimeType,
240
+ metadata,
215
241
  source_type: "base64" as const,
216
242
  };
243
+ }
217
244
  case "tool-call":
218
245
  throw new Error("Tool call appends are not supported.");
219
246
  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 = {