@assistant-ui/react-langchain 0.0.17 → 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.
- package/dist/convertMessages.d.ts +16 -3
- package/dist/convertMessages.d.ts.map +1 -1
- package/dist/convertMessages.js +29 -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 +9 -9
- package/src/convertMessages.test.ts +139 -1
- package/src/convertMessages.ts +33 -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":";;;;KAeK,oCACH,4BAA4B;EAC1B,qBAAqB,YAAY;EACjC,gBAAgB,eAAe;;cAStB,iBAAkB,SAAS;cAyE3B,8BACX,SAAS,sBACT,WAAU,sCACT,4BAA4B;cAmGlB,oBAAqB,KAAK"}
|
package/dist/convertMessages.js
CHANGED
|
@@ -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":
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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 +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.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.
|
|
33
|
-
"@assistant-ui/store": "^0.2.
|
|
32
|
+
"@assistant-ui/core": "^0.2.21",
|
|
33
|
+
"@assistant-ui/store": "^0.2.20",
|
|
34
34
|
"assistant-cloud": "*",
|
|
35
|
-
"assistant-stream": "^0.3.
|
|
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.
|
|
49
|
-
"@langchain/langgraph-sdk": "^1.9.
|
|
50
|
-
"@langchain/react": "^1.0.
|
|
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.
|
|
56
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
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 {
|
|
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
|
@@ -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:
|
|
60
|
-
|
|
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
|
|
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 = {
|