@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.
- package/dist/convertMessages.d.ts +16 -3
- package/dist/convertMessages.d.ts.map +1 -1
- package/dist/convertMessages.js +21 -9
- package/dist/convertMessages.js.map +1 -1
- package/dist/findForkCheckpointInHistory.d.ts +0 -1
- package/dist/findForkCheckpointInHistory.d.ts.map +1 -1
- package/dist/hooks.d.ts +0 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/resolveForkCheckpoint.d.ts +0 -1
- package/dist/resolveForkCheckpoint.d.ts.map +1 -1
- package/dist/runtimeExtras.d.ts +0 -1
- package/dist/runtimeExtras.d.ts.map +1 -1
- package/dist/streamingTiming.d.ts +0 -1
- package/dist/streamingTiming.d.ts.map +1 -1
- package/dist/types.d.ts +29 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/uiMessages.d.ts +0 -1
- package/dist/uiMessages.d.ts.map +1 -1
- package/dist/useStreamRuntime.d.ts +0 -1
- package/dist/useStreamRuntime.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/convertMessages.test.ts +139 -1
- package/src/convertMessages.ts +24 -6
- package/src/types.ts +14 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
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":"
|
|
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"}
|
package/dist/convertMessages.js
CHANGED
|
@@ -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":
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findForkCheckpointInHistory.d.ts","names":[],"sources":["../src/findForkCheckpointInHistory.ts"],"mappings":"
|
|
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
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;
|
|
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":"
|
|
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"}
|
package/dist/runtimeExtras.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeExtras.d.ts","names":[],"sources":["../src/runtimeExtras.ts"],"mappings":"
|
|
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":"
|
|
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;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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;
|
|
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;
|
|
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
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"
|
|
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"}
|
package/dist/uiMessages.d.ts
CHANGED
package/dist/uiMessages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uiMessages.d.ts","names":[],"sources":["../src/uiMessages.ts"],"mappings":"
|
|
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":"
|
|
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.
|
|
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.
|
|
33
|
-
"@assistant-ui/store": "^0.2.
|
|
32
|
+
"@assistant-ui/core": "^0.2.22",
|
|
33
|
+
"@assistant-ui/store": "^0.2.21",
|
|
34
34
|
"assistant-cloud": "*",
|
|
35
|
-
"assistant-stream": "^0.3.
|
|
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.
|
|
49
|
-
"@langchain/langgraph-sdk": "^1.9.
|
|
50
|
-
"@langchain/react": "^1.0.
|
|
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.
|
|
55
|
-
"vitest": "^4.1.
|
|
56
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
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 {
|
|
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", () => {
|
package/src/convertMessages.ts
CHANGED
|
@@ -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:
|
|
60
|
-
|
|
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
|
|
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 = {
|