langgraph-ui-components 0.0.10 → 0.0.11

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.
Files changed (118) hide show
  1. package/dist/index.es116.js +1 -1
  2. package/dist/index.es119.js +1 -1
  3. package/dist/index.es12.js +1 -1
  4. package/dist/index.es120.js +9 -9
  5. package/dist/index.es13.js +6 -6
  6. package/dist/index.es15.js +59 -31
  7. package/dist/index.es15.js.map +1 -1
  8. package/dist/index.es16.js +1 -1
  9. package/dist/index.es18.js +7 -7
  10. package/dist/index.es2.js +25 -11
  11. package/dist/index.es2.js.map +1 -1
  12. package/dist/index.es20.js +2 -2
  13. package/dist/index.es22.js +15 -119
  14. package/dist/index.es22.js.map +1 -1
  15. package/dist/index.es23.js +37 -17
  16. package/dist/index.es23.js.map +1 -1
  17. package/dist/index.es233.js +1 -1
  18. package/dist/index.es234.js +3 -3
  19. package/dist/index.es235.js +1 -1
  20. package/dist/index.es24.js +27 -34
  21. package/dist/index.es24.js.map +1 -1
  22. package/dist/index.es25.js +146 -27
  23. package/dist/index.es25.js.map +1 -1
  24. package/dist/index.es26.js +100 -144
  25. package/dist/index.es26.js.map +1 -1
  26. package/dist/index.es260.js +5 -8
  27. package/dist/index.es260.js.map +1 -1
  28. package/dist/index.es261.js +13 -5
  29. package/dist/index.es261.js.map +1 -1
  30. package/dist/index.es262.js +5 -12
  31. package/dist/index.es262.js.map +1 -1
  32. package/dist/index.es263.js +8 -6
  33. package/dist/index.es263.js.map +1 -1
  34. package/dist/index.es27.js +66 -101
  35. package/dist/index.es27.js.map +1 -1
  36. package/dist/index.es28.js +295 -58
  37. package/dist/index.es28.js.map +1 -1
  38. package/dist/index.es280.js +131 -3726
  39. package/dist/index.es280.js.map +1 -1
  40. package/dist/index.es281.js +2 -342
  41. package/dist/index.es281.js.map +1 -1
  42. package/dist/index.es282.js +3704 -76
  43. package/dist/index.es282.js.map +1 -1
  44. package/dist/index.es283.js +326 -117
  45. package/dist/index.es283.js.map +1 -1
  46. package/dist/index.es284.js +107 -13
  47. package/dist/index.es284.js.map +1 -1
  48. package/dist/index.es285.js +123 -142
  49. package/dist/index.es285.js.map +1 -1
  50. package/dist/index.es286.js +13 -13
  51. package/dist/index.es286.js.map +1 -1
  52. package/dist/index.es287.js +150 -6
  53. package/dist/index.es287.js.map +1 -1
  54. package/dist/index.es288.js +13 -19
  55. package/dist/index.es288.js.map +1 -1
  56. package/dist/index.es289.js +6 -88
  57. package/dist/index.es289.js.map +1 -1
  58. package/dist/index.es29.js +114 -298
  59. package/dist/index.es29.js.map +1 -1
  60. package/dist/index.es290.js +16 -238
  61. package/dist/index.es290.js.map +1 -1
  62. package/dist/index.es291.js +88 -22
  63. package/dist/index.es291.js.map +1 -1
  64. package/dist/index.es292.js +243 -6
  65. package/dist/index.es292.js.map +1 -1
  66. package/dist/index.es293.js +24 -4
  67. package/dist/index.es293.js.map +1 -1
  68. package/dist/index.es294.js +6 -18
  69. package/dist/index.es294.js.map +1 -1
  70. package/dist/index.es295.js +4 -8
  71. package/dist/index.es295.js.map +1 -1
  72. package/dist/index.es296.js +17 -141
  73. package/dist/index.es296.js.map +1 -1
  74. package/dist/index.es297.js +8 -2
  75. package/dist/index.es297.js.map +1 -1
  76. package/dist/index.es31.js +7 -7
  77. package/dist/index.es32.js +1 -1
  78. package/dist/index.es35.js +4 -4
  79. package/dist/index.es36.js +204 -114
  80. package/dist/index.es36.js.map +1 -1
  81. package/dist/index.es37.js +5 -71
  82. package/dist/index.es37.js.map +1 -1
  83. package/dist/index.es38.js +119 -19
  84. package/dist/index.es38.js.map +1 -1
  85. package/dist/index.es39.js +66 -256
  86. package/dist/index.es39.js.map +1 -1
  87. package/dist/index.es40.js +17 -42
  88. package/dist/index.es40.js.map +1 -1
  89. package/dist/index.es41.js +239 -193
  90. package/dist/index.es41.js.map +1 -1
  91. package/dist/index.es42.js +17 -41
  92. package/dist/index.es42.js.map +1 -1
  93. package/dist/index.es43.js +193 -120
  94. package/dist/index.es43.js.map +1 -1
  95. package/dist/index.es44.js +60 -17
  96. package/dist/index.es44.js.map +1 -1
  97. package/dist/index.es45.js +123 -211
  98. package/dist/index.es45.js.map +1 -1
  99. package/dist/index.es46.js +22 -7
  100. package/dist/index.es46.js.map +1 -1
  101. package/dist/index.es47.js +214 -1176
  102. package/dist/index.es47.js.map +1 -1
  103. package/dist/index.es48.js +10 -8
  104. package/dist/index.es48.js.map +1 -1
  105. package/dist/index.es49.js +1182 -137
  106. package/dist/index.es49.js.map +1 -1
  107. package/dist/index.es50.js +7 -208
  108. package/dist/index.es50.js.map +1 -1
  109. package/dist/index.es51.js +147 -5
  110. package/dist/index.es51.js.map +1 -1
  111. package/dist/index.es55.js +1 -1
  112. package/dist/index.es56.js +1 -1
  113. package/dist/index.es57.js +1 -1
  114. package/dist/index.es58.js +7 -7
  115. package/dist/index.es97.js +1 -1
  116. package/dist/index.es98.js +1 -1
  117. package/dist/styles.css +1 -1
  118. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { __export } from "./index.es52.js";
2
- import { getBufferString } from "./index.es45.js";
2
+ import { getBufferString } from "./index.es47.js";
3
3
  import { getEnvironmentVariable } from "./index.es231.js";
4
4
  import { isBaseCallbackHandler, BaseCallbackHandler } from "./index.es232.js";
5
5
  import { isBaseTracer } from "./index.es123.js";
@@ -1,4 +1,4 @@
1
- import { getLangSmithEnvironmentVariable } from "./index.es285.js";
1
+ import { getLangSmithEnvironmentVariable } from "./index.es287.js";
2
2
  var LIMIT_REPLACE_NODE = "[...]";
3
3
  var CIRCULAR_REPLACE_NODE = { result: "[Circular]" };
4
4
  var arr = [];
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useStreamContext } from "./index.es7.js";
3
3
  import { useGeneratedSuggestions } from "./index.es11.js";
4
- import { LiquidButton } from "./index.es29.js";
4
+ import { LiquidButton } from "./index.es28.js";
5
5
  function Suggestion() {
6
6
  const stream = useStreamContext();
7
7
  const agentSuggestions = stream.values?.suggestions;
@@ -1,12 +1,12 @@
1
- import { Client } from "./index.es280.js";
2
- import { isTracingEnabled } from "./index.es292.js";
3
- import { isConflictingEndpointsError, ConflictingEndpointsError } from "./index.es289.js";
4
- import { _LC_CONTEXT_VARIABLES_KEY, _REPLICA_TRACE_ROOTS_KEY } from "./index.es293.js";
5
- import { getContextVar, setContextVar } from "./index.es294.js";
6
- import { getEnvironmentVariable, getRuntimeEnvironment, getLangSmithEnvironmentVariable } from "./index.es285.js";
7
- import { getDefaultProjectName } from "./index.es263.js";
8
- import { warnOnce } from "./index.es287.js";
9
- import { uuid7FromTime } from "./index.es286.js";
1
+ import { Client } from "./index.es282.js";
2
+ import { isTracingEnabled } from "./index.es294.js";
3
+ import { isConflictingEndpointsError, ConflictingEndpointsError } from "./index.es291.js";
4
+ import { _LC_CONTEXT_VARIABLES_KEY, _REPLICA_TRACE_ROOTS_KEY } from "./index.es295.js";
5
+ import { getContextVar, setContextVar } from "./index.es296.js";
6
+ import { getEnvironmentVariable, getRuntimeEnvironment, getLangSmithEnvironmentVariable } from "./index.es287.js";
7
+ import { getDefaultProjectName } from "./index.es262.js";
8
+ import { warnOnce } from "./index.es289.js";
9
+ import { uuid7FromTime } from "./index.es288.js";
10
10
  import { v5 } from "uuid";
11
11
  const UUID_NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
12
12
  function getReplicaKey(replica) {
@@ -1,12 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useStreamContext } from "./index.es7.js";
3
- import { isAiWithToolCalls, isToolMessage } from "./index.es23.js";
3
+ import { isAiWithToolCalls, isToolMessage } from "./index.es22.js";
4
4
  import React__default, { useMemo, useRef, useCallback, useEffect, useLayoutEffect } from "react";
5
- import AgentMessage from "./index.es24.js";
6
- import CustomComponentRender from "./index.es25.js";
7
- import HumanMessage from "./index.es26.js";
8
- import Thinking from "./index.es27.js";
9
- import ToolCallFunctions from "./index.es28.js";
5
+ import AgentMessage from "./index.es23.js";
6
+ import CustomComponentRender from "./index.es24.js";
7
+ import HumanMessage from "./index.es25.js";
8
+ import Thinking from "./index.es26.js";
9
+ import ToolCallFunctions from "./index.es27.js";
10
10
  function ChatBody({ setIsFirstMessage, enableToolCallIndicator }) {
11
11
  const stream = useStreamContext();
12
12
  const messages = stream.messages;
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
- import { FileIcon, X, Paperclip, MoveUp } from "lucide-react";
3
- import "react";
2
+ import { Paperclip, Loader2, MoveUp } from "lucide-react";
3
+ import { useState } from "react";
4
4
  function ChatInput({
5
5
  input,
6
6
  inputFileAccept = ".png,.jpg,.jpeg,.pdf,.docx",
@@ -10,41 +10,69 @@ function ChatInput({
10
10
  setFileInput,
11
11
  handleFileSelect,
12
12
  isLoading = false,
13
- onCancel
13
+ onCancel,
14
+ filePreview
14
15
  }) {
15
16
  const canSubmit = (input.trim().length > 0 || fileInput.length > 0) && !isLoading;
17
+ const [isDragOver, setIsDragOver] = useState(false);
18
+ const handleDragOver = (e) => {
19
+ e.preventDefault();
20
+ e.stopPropagation();
21
+ setIsDragOver(true);
22
+ };
23
+ const handleDragLeave = (e) => {
24
+ e.preventDefault();
25
+ e.stopPropagation();
26
+ setIsDragOver(false);
27
+ };
28
+ const handleDrop = async (e) => {
29
+ e.preventDefault();
30
+ e.stopPropagation();
31
+ setIsDragOver(false);
32
+ const files = Array.from(e.dataTransfer.files);
33
+ if (files.length === 0) return;
34
+ const acceptedFiles = files.filter((file) => {
35
+ if (!inputFileAccept) return true;
36
+ const acceptTypes = inputFileAccept.split(",").map((type) => type.trim());
37
+ return acceptTypes.some((type) => {
38
+ if (type.startsWith(".")) {
39
+ return file.name.toLowerCase().endsWith(type.toLowerCase());
40
+ }
41
+ return file.type.match(type.replace("*", ".*"));
42
+ });
43
+ });
44
+ if (acceptedFiles.length === 0) return;
45
+ const fileDetails = await Promise.all(
46
+ acceptedFiles.map(async (file) => {
47
+ const base64Data = await new Promise((resolve, reject) => {
48
+ const reader = new FileReader();
49
+ reader.onload = () => {
50
+ const result = reader.result;
51
+ resolve(result.split(",")[1]);
52
+ };
53
+ reader.onerror = reject;
54
+ reader.readAsDataURL(file);
55
+ });
56
+ return {
57
+ fileName: file.name,
58
+ fileType: file.type,
59
+ file,
60
+ fileData: base64Data
61
+ };
62
+ })
63
+ );
64
+ setFileInput((prevFile) => [...prevFile, ...fileDetails]);
65
+ };
16
66
  return /* @__PURE__ */ jsxs(
17
67
  "form",
18
68
  {
19
69
  onSubmit: handleSubmit,
20
- className: "relative flex flex-col gap-2 border rounded-xl m-2 bg-zinc-900 border-zinc-800",
70
+ className: `relative flex flex-col gap-2 border rounded-xl m-2 bg-zinc-900 border-zinc-800 transition-colors ${isDragOver ? "border-blue-500 bg-zinc-800" : ""}`,
71
+ onDragOver: handleDragOver,
72
+ onDragLeave: handleDragLeave,
73
+ onDrop: handleDrop,
21
74
  children: [
22
- fileInput.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-1 flex-col gap-2 p-2 bg-zinc-900 border-b border-zinc-700 max-h-48 thread-scrollbar", children: fileInput.map((file, index) => /* @__PURE__ */ jsxs(
23
- "div",
24
- {
25
- className: "flex items-center justify-between gap-3 bg-zinc-800 p-2 rounded group hover:bg-zinc-700 transition-colors",
26
- children: [
27
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0 flex-1", children: [
28
- /* @__PURE__ */ jsx(FileIcon, { className: "text-blue-400 shrink-0", size: 20 }),
29
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 overflow-hidden", children: [
30
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-zinc-200 truncate", children: file.fileName }),
31
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-500 truncate", children: file.fileType || "Unknown file type" })
32
- ] })
33
- ] }),
34
- /* @__PURE__ */ jsx(
35
- "button",
36
- {
37
- type: "button",
38
- onClick: () => setFileInput((prev) => prev.filter((_, i) => i !== index)),
39
- className: "shrink-0 p-1 rounded hover:bg-zinc-600 transition-colors",
40
- "aria-label": "Remove file",
41
- children: /* @__PURE__ */ jsx(X, { size: 16, className: "text-red-400" })
42
- }
43
- )
44
- ]
45
- },
46
- `file-${index}-${file.fileName}`
47
- )) }),
75
+ filePreview && filePreview(fileInput, setFileInput),
48
76
  /* @__PURE__ */ jsx(
49
77
  "textarea",
50
78
  {
@@ -115,7 +143,7 @@ function ChatInput({
115
143
  disabled: !canSubmit,
116
144
  className: "focus:outline-none transition-all bg-zinc-300 border rounded-full p-1 cursor-pointer",
117
145
  style: { border: "none" },
118
- children: /* @__PURE__ */ jsx(MoveUp, { size: 24, className: "text-black p-1" })
146
+ children: isLoading ? /* @__PURE__ */ jsx(Loader2, { size: 24, className: "animate-spin text-black p-1" }) : /* @__PURE__ */ jsx(MoveUp, { size: 24, className: "text-black p-1" })
119
147
  }
120
148
  )
121
149
  ] })
@@ -1 +1 @@
1
- {"version":3,"file":"index.es15.js","sources":["../src/components/sidebar/ChatInput.tsx"],"sourcesContent":["import type { FileInfo } from \"@/types/fileInput\";\nimport { FileIcon, MoveUp, Paperclip, X } from \"lucide-react\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type FormEvent,\n type SetStateAction,\n} from \"react\";\n\nexport default function ChatInput({\n input,\n inputFileAccept = \".png,.jpg,.jpeg,.pdf,.docx\",\n setInput,\n handleSubmit,\n fileInput,\n setFileInput,\n handleFileSelect,\n isLoading = false,\n onCancel,\n}: {\n input: string;\n setInput: (value: string) => void;\n handleSubmit: (e: FormEvent<HTMLFormElement>) => void;\n fileInput: FileInfo[];\n setFileInput: Dispatch<SetStateAction<FileInfo[]>>;\n handleFileSelect: (event: ChangeEvent<HTMLInputElement>) => void;\n inputFileAccept?: string;\n isLoading?: boolean;\n onCancel?: () => void;\n}) {\n const canSubmit =\n (input.trim().length > 0 || fileInput.length > 0) && !isLoading;\n\n return (\n <form\n onSubmit={handleSubmit}\n className=\"relative flex flex-col gap-2 border rounded-xl m-2 bg-zinc-900 border-zinc-800\"\n >\n {/* File attachments preview */}\n {fileInput.length > 0 && (\n <div className=\"flex-1 flex-col gap-2 p-2 bg-zinc-900 border-b border-zinc-700 max-h-48 thread-scrollbar\">\n {fileInput.map((file, index) => (\n <div\n key={`file-${index}-${file.fileName}`}\n className=\"flex items-center justify-between gap-3 bg-zinc-800 p-2 rounded group hover:bg-zinc-700 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0 flex-1\">\n <FileIcon className=\"text-blue-400 shrink-0\" size={20} />\n <div className=\"flex flex-col min-w-0 overflow-hidden\">\n <span className=\"text-xs font-medium text-zinc-200 truncate\">\n {file.fileName}\n </span>\n <span className=\"text-[10px] text-zinc-500 truncate\">\n {file.fileType || \"Unknown file type\"}\n </span>\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={() =>\n setFileInput((prev) => prev.filter((_, i) => i !== index))\n }\n className=\"shrink-0 p-1 rounded hover:bg-zinc-600 transition-colors\"\n aria-label=\"Remove file\"\n >\n <X size={16} className=\"text-red-400\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Text input */}\n <textarea\n placeholder=\"Type your message...\"\n value={input}\n onChange={(e) => {\n setInput(e.target.value)\n const maxHeight = 300; // max height in pixels\n e.target.style.height = \"auto\"; // reset height\n e.target.style.height = Math.min(e.target.scrollHeight, maxHeight) + \"px\";\n }}\n onKeyDown={(e) => {\n if (\n e.key === \"Enter\" &&\n !e.shiftKey &&\n !e.metaKey &&\n !e.nativeEvent.isComposing\n ) {\n e.preventDefault();\n if (canSubmit) {\n e.currentTarget.form?.requestSubmit();\n }\n }\n }}\n disabled={isLoading}\n className=\"w-full field-sizing-content resize-none p-3.5 bg-transparent text-white placeholder-zinc-500 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed overflow-y-auto thread-scrollbar\"\n rows={1}\n />\n\n {/* Footer with controls */}\n <div className=\"flex justify-between items-center px-1 pb-2\">\n <div className=\"flex gap-1 m-2\">\n <label\n htmlFor=\"file-input\"\n className={`cursor-pointer ${isLoading ? \"opacity-50 cursor-not-allowed\" : \"\"\n }`}\n >\n <Paperclip\n size={24}\n className=\"text-zinc-400 hover:text-white hover:bg-zinc-800 rounded p-1 transition-colors\"\n />\n </label>\n <input\n id=\"file-input\"\n type=\"file\"\n multiple\n disabled={isLoading}\n accept={inputFileAccept}\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </div>\n\n <div className=\"flex gap-2 items-center\">\n {isLoading && onCancel && (\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1 text-xs text-zinc-400 hover:text-white hover:bg-zinc-800 rounded transition-colors\"\n >\n Cancel\n </button>\n )}\n\n <button\n type=\"submit\"\n disabled={!canSubmit}\n className=\"focus:outline-none transition-all bg-zinc-300 border rounded-full p-1 cursor-pointer\"\n style={{ border: \"none\" }}\n >\n <MoveUp size={24} className=\"text-black p-1\" />\n </button>\n </div>\n </div>\n </form>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.es15.js","sources":["../src/components/sidebar/ChatInput.tsx"],"sourcesContent":["import type { FileInfo } from \"@/types/fileInput\";\nimport { MoveUp, Paperclip, Loader2 } from \"lucide-react\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type FormEvent,\n type SetStateAction,\n useState,\n type DragEvent,\n} from \"react\";\n\nexport default function ChatInput({\n input,\n inputFileAccept = \".png,.jpg,.jpeg,.pdf,.docx\",\n setInput,\n handleSubmit,\n fileInput,\n setFileInput,\n handleFileSelect,\n isLoading = false,\n onCancel,\n filePreview,\n}: {\n input: string;\n setInput: (value: string) => void;\n handleSubmit: (e: FormEvent<HTMLFormElement>) => void;\n fileInput: FileInfo[];\n setFileInput: Dispatch<SetStateAction<FileInfo[]>>;\n handleFileSelect: (event: ChangeEvent<HTMLInputElement>) => void;\n inputFileAccept?: string;\n isLoading?: boolean;\n onCancel?: () => void;\n filePreview?: (files: FileInfo[], setFileInput: Dispatch<SetStateAction<FileInfo[]>>) => React.ReactNode;\n}) {\n const canSubmit =\n (input.trim().length > 0 || fileInput.length > 0) && !isLoading;\n\n const [isDragOver, setIsDragOver] = useState(false);\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(true);\n };\n\n const handleDragLeave = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n };\n\n const handleDrop = async (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n const files = Array.from(e.dataTransfer.files);\n if (files.length === 0) return;\n\n const acceptedFiles = files.filter(file => {\n if (!inputFileAccept) return true;\n const acceptTypes = inputFileAccept.split(',').map(type => type.trim());\n return acceptTypes.some(type => {\n if (type.startsWith('.')) {\n return file.name.toLowerCase().endsWith(type.toLowerCase());\n }\n return file.type.match(type.replace('*', '.*'));\n });\n });\n\n if (acceptedFiles.length === 0) return;\n\n const fileDetails: FileInfo[] = await Promise.all(\n acceptedFiles.map(async (file) => {\n const base64Data = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n resolve(result.split(\",\")[1]); \n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n\n return {\n fileName: file.name,\n fileType: file.type,\n file: file,\n fileData: base64Data,\n };\n })\n );\n\n setFileInput((prevFile) => [...prevFile, ...fileDetails]);\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className={`relative flex flex-col gap-2 border rounded-xl m-2 bg-zinc-900 border-zinc-800 transition-colors ${\n isDragOver ? 'border-blue-500 bg-zinc-800' : ''\n }`}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n {/* File attachments preview */}\n {filePreview && filePreview(fileInput, setFileInput)}\n\n {/* Text input */}\n <textarea\n placeholder=\"Type your message...\"\n value={input}\n onChange={(e) => {\n setInput(e.target.value)\n const maxHeight = 300; // max height in pixels\n e.target.style.height = \"auto\"; // reset height\n e.target.style.height = Math.min(e.target.scrollHeight, maxHeight) + \"px\";\n }}\n onKeyDown={(e) => {\n if (\n e.key === \"Enter\" &&\n !e.shiftKey &&\n !e.metaKey &&\n !e.nativeEvent.isComposing\n ) {\n e.preventDefault();\n if (canSubmit) {\n e.currentTarget.form?.requestSubmit();\n }\n }\n }}\n disabled={isLoading}\n className=\"w-full field-sizing-content resize-none p-3.5 bg-transparent text-white placeholder-zinc-500 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed overflow-y-auto thread-scrollbar\"\n rows={1}\n />\n\n {/* Footer with controls */}\n <div className=\"flex justify-between items-center px-1 pb-2\">\n <div className=\"flex gap-1 m-2\">\n <label\n htmlFor=\"file-input\"\n className={`cursor-pointer ${isLoading ? \"opacity-50 cursor-not-allowed\" : \"\"\n }`}\n >\n <Paperclip\n size={24}\n className=\"text-zinc-400 hover:text-white hover:bg-zinc-800 rounded p-1 transition-colors\"\n />\n </label>\n <input\n id=\"file-input\"\n type=\"file\"\n multiple\n disabled={isLoading}\n accept={inputFileAccept}\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </div>\n\n <div className=\"flex gap-2 items-center\">\n {isLoading && onCancel && (\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1 text-xs text-zinc-400 hover:text-white hover:bg-zinc-800 rounded transition-colors\"\n >\n Cancel\n </button>\n )}\n\n <button\n type=\"submit\"\n disabled={!canSubmit}\n className=\"focus:outline-none transition-all bg-zinc-300 border rounded-full p-1 cursor-pointer\"\n style={{ border: \"none\" }}\n >\n {isLoading ? (\n <Loader2 size={24} className=\"animate-spin text-black p-1\" />\n ) : (\n <MoveUp size={24} className=\"text-black p-1\" />\n )}\n </button>\n </div>\n </div>\n </form>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import useTools from "./index.es10.js";
3
3
  import { useThread } from "./index.es6.js";
4
- import { getContentString } from "./index.es23.js";
4
+ import { getContentString } from "./index.es22.js";
5
5
  import { PanelLeft, MoreVertical, Pencil, Share2, Archive, Trash2 } from "lucide-react";
6
6
  import { useState, useEffect, useRef } from "react";
7
7
  function ThreadHistory() {
@@ -1,16 +1,16 @@
1
1
  import { __export } from "./index.es52.js";
2
2
  import { parseMimeType, parseBase64DataUrl, isURLContentBlock, isPlainTextContentBlock, isIDContentBlock, isDataContentBlock, isBase64ContentBlock, convertToProviderContentBlock, convertToOpenAIImageBlock } from "./index.es53.js";
3
3
  import { isMessage } from "./index.es54.js";
4
- import { mergeContent, isOpenAIToolCallArray, isBaseMessageChunk, isBaseMessage, _mergeStatus, _mergeObj, _mergeLists, _mergeDicts, _isMessageFieldWithRole, BaseMessageChunk, BaseMessage } from "./index.es39.js";
4
+ import { mergeContent, isOpenAIToolCallArray, isBaseMessageChunk, isBaseMessage, _mergeStatus, _mergeObj, _mergeLists, _mergeDicts, _isMessageFieldWithRole, BaseMessageChunk, BaseMessage } from "./index.es41.js";
5
5
  import { mergeUsageMetadata, mergeResponseMetadata } from "./index.es55.js";
6
- import { isToolMessageChunk, isToolMessage, isDirectToolOutput, defaultToolCallParser, ToolMessageChunk, ToolMessage } from "./index.es43.js";
6
+ import { isToolMessageChunk, isToolMessage, isDirectToolOutput, defaultToolCallParser, ToolMessageChunk, ToolMessage } from "./index.es45.js";
7
7
  import { isChatMessageChunk, isChatMessage, ChatMessageChunk, ChatMessage } from "./index.es56.js";
8
8
  import { isFunctionMessageChunk, isFunctionMessage, FunctionMessageChunk, FunctionMessage } from "./index.es57.js";
9
- import { isHumanMessageChunk, isHumanMessage, HumanMessageChunk, HumanMessage } from "./index.es40.js";
10
- import { RemoveMessage } from "./index.es44.js";
11
- import { isSystemMessageChunk, isSystemMessage, SystemMessageChunk, SystemMessage } from "./index.es42.js";
12
- import { mapStoredMessagesToChatMessages, mapStoredMessageToChatMessage, mapChatMessagesToStoredMessages, iife, getBufferString, convertToChunk, collapseToolCallChunks, coerceMessageLikeToMessage } from "./index.es45.js";
13
- import { isAIMessageChunk, isAIMessage, AIMessageChunk, AIMessage } from "./index.es41.js";
9
+ import { isHumanMessageChunk, isHumanMessage, HumanMessageChunk, HumanMessage } from "./index.es42.js";
10
+ import { RemoveMessage } from "./index.es46.js";
11
+ import { isSystemMessageChunk, isSystemMessage, SystemMessageChunk, SystemMessage } from "./index.es44.js";
12
+ import { mapStoredMessagesToChatMessages, mapStoredMessageToChatMessage, mapChatMessagesToStoredMessages, iife, getBufferString, convertToChunk, collapseToolCallChunks, coerceMessageLikeToMessage } from "./index.es47.js";
13
+ import { isAIMessageChunk, isAIMessage, AIMessageChunk, AIMessage } from "./index.es43.js";
14
14
  import { trimMessages, mergeMessageRuns, filterMessages, defaultTextSplitter } from "./index.es58.js";
15
15
  import { KNOWN_BLOCK_TYPES as KNOWN_BLOCK_TYPES$2 } from "./index.es59.js";
16
16
  var messages_exports = {};
package/dist/index.es2.js CHANGED
@@ -11,7 +11,7 @@ import ChatBody from "./index.es13.js";
11
11
  import ChatButton from "./index.es14.js";
12
12
  import ChatInput from "./index.es15.js";
13
13
  function Sidebar(props) {
14
- const { handleFileSelect, callThisOnSubmit, enableToolCallIndicator, header, inputFileAccept } = props;
14
+ const { handleFileSelect, callThisOnSubmit, enableToolCallIndicator, header, inputFileAccept, filePreview, s3_upload, preventSubmit } = props;
15
15
  const [open, setOpen] = useState(false);
16
16
  const [input, setInput] = useState("");
17
17
  const { fileInput, setFileInput } = useFileProvider();
@@ -23,21 +23,34 @@ function Sidebar(props) {
23
23
  }, [setMode]);
24
24
  const defaultHandleSubmit = async (e) => {
25
25
  e.preventDefault();
26
- if (input.trim().length === 0 && fileInput.length === 0 || isLoading)
26
+ if (preventSubmit || input.trim().length === 0 && fileInput.length === 0 || isLoading)
27
27
  return;
28
28
  let latestFiles = fileInput;
29
29
  if (callThisOnSubmit) {
30
30
  const result = await callThisOnSubmit();
31
31
  if (result && result.length > 0) latestFiles = result;
32
32
  }
33
- const contentBlocks = [
34
- ...input.trim().length > 0 ? [{ type: "text", text: input }] : [],
35
- ...latestFiles.map((file) => ({
36
- type: "document",
37
- ...file,
38
- cache_control: { type: "ephemeral" }
39
- }))
40
- ];
33
+ let contentBlocks;
34
+ if (s3_upload) {
35
+ let messageText = input.trim();
36
+ if (latestFiles.length > 0) {
37
+ const fileNames = latestFiles.map((file) => file.fileName).join(", ");
38
+ const fileText = `file${latestFiles.length > 1 ? "s" : ""} uploaded: ${fileNames}`;
39
+ messageText = messageText ? `${fileText}
40
+
41
+ - ${messageText}` : fileText;
42
+ }
43
+ contentBlocks = [{ type: "text", text: messageText }];
44
+ } else {
45
+ contentBlocks = [
46
+ ...input.trim().length > 0 ? [{ type: "text", text: input }] : [],
47
+ ...latestFiles.map((file) => ({
48
+ type: "document",
49
+ ...file,
50
+ cache_control: { type: "ephemeral" }
51
+ }))
52
+ ];
53
+ }
41
54
  const newHumanMessage = {
42
55
  id: v4(),
43
56
  type: "human",
@@ -128,7 +141,8 @@ function Sidebar(props) {
128
141
  fileInput,
129
142
  handleFileSelect: onFileSelect,
130
143
  setFileInput,
131
- onCancel: () => stream.stop?.()
144
+ onCancel: () => stream.stop?.(),
145
+ filePreview
132
146
  }
133
147
  ) })
134
148
  ] })
@@ -1 +1 @@
1
- {"version":3,"file":"index.es2.js","sources":["../src/pages/Sidebar/sidebar.tsx"],"sourcesContent":["import Suggestion from \"@/components/Suggestion\";\nimport { useFileProvider } from \"@/providers/FileProvider\";\nimport { useStreamContext } from \"@/providers/Stream\";\nimport { useThread } from \"@/providers/Thread\";\nimport type { ChatSidebarProps } from \"@/types/ChatProps\";\nimport type { FileInfo } from \"@/types/fileInput\";\nimport type { Message } from \"@langchain/langgraph-sdk\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { X } from \"lucide-react\";\nimport { useEffect, useState, type FormEvent } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport ChatBody from \"../../components/ChatBody\";\nimport ChatButton from \"../../components/ChatButton\";\nimport ChatInput from \"../../components/sidebar/ChatInput\";\n\n/**\n * Main sidebar chat interface component.\n * Displays a chat button that opens a sliding sidebar with full chat functionality.\n * \n * @param header - Custom header text for the chat sidebar (default: \"AI Assistant\")\n * @param handleFileSelect - Optional custom file selection handler\n * @param callThisOnSubmit - Optional callback invoked before message submission, can return updated file list\n * \n * @example\n * ```tsx\n * <Sidebar \n * header=\"My Custom AI\"\n * callThisOnSubmit={async () => {\n * // Upload files to your backend\n * return updatedFiles;\n * }}\n * />\n * ```\n */\nexport default function Sidebar(props: ChatSidebarProps) {\n\n const { handleFileSelect, callThisOnSubmit, enableToolCallIndicator, header, inputFileAccept } = props;\n const [open, setOpen] = useState(false);\n const [input, setInput] = useState(\"\");\n const { fileInput, setFileInput } = useFileProvider();\n\n const stream = useStreamContext();\n const isLoading = stream.isLoading;\n const { setMode } = useThread();\n\n // Set thread mode to single when using Sidebar\n useEffect(() => {\n setMode(\"single\");\n }, [setMode]);\n\n const defaultHandleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n\n if ((input.trim().length === 0 && fileInput.length === 0) || isLoading)\n return;\n\n // Call the custom upload and get the latest files\n let latestFiles: FileInfo[] = fileInput;\n if (callThisOnSubmit) {\n const result = await callThisOnSubmit();\n if (result && result.length > 0) latestFiles = result;\n }\n\n const contentBlocks = [\n ...(input.trim().length > 0 ? [{ type: \"text\", text: input }] : []),\n ...latestFiles.map((file) => ({\n type: \"document\" as const,\n ...file,\n cache_control: { type: \"ephemeral\" as const },\n })),\n ] as unknown as Message[\"content\"];\n\n const newHumanMessage: Message = {\n id: uuidv4(),\n type: \"human\",\n content: contentBlocks,\n };\n\n // Use the unified submitMessage function\n await stream.submitMessage(newHumanMessage);\n\n setInput(\"\");\n setFileInput([]);\n };\n\n const defaultHandleFileSelect = async (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const files = event.target.files;\n if (!files) return;\n\n // Convert files to base64 for sending\n const fileDetails: FileInfo[] = await Promise.all(\n Array.from(files).map(async (file) => {\n const base64Data = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n resolve(result.split(\",\")[1]); // Remove data:...;base64, prefix\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n\n return {\n fileName: file.name,\n fileType: file.type,\n file: file,\n fileData: base64Data, // Add this to your FileInfo type\n };\n })\n );\n\n setFileInput((prevFile) => [...prevFile, ...fileDetails]);\n };\n\n const onFileSelect = handleFileSelect || defaultHandleFileSelect;\n \n return (\n <>\n <AnimatePresence>\n {open && (\n <>\n {/* Overlay */}\n <motion.div\n className=\"fixed inset-0 z-40 bg-black/30\"\n onClick={() => setOpen(false)}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n />\n\n {/* Sidebar */}\n <motion.aside\n className=\"fixed right-0 top-0 z-50 h-screen w-[520px] bg-black flex flex-col text-white\"\n initial={{ x: \"100%\" }}\n animate={{ x: 0 }}\n exit={{ x: \"100%\" }}\n transition={{ type: \"spring\", stiffness: 260, damping: 30 }}\n >\n <div className=\"flex h-full flex-col\">\n <div className=\"flex border-b border-zinc-800 py-4 px-6 justify-between items-center\">\n <div className=\"flex items-center gap-3\">\n {header?.logoUrl && (\n // Render provided logo image if present\n <img\n src={header?.logoUrl}\n alt={header?.title ? `${header.title} logo` : \"AI Assistant logo\"}\n className=\"h-8 w-8 object-contain rounded-sm\"\n />\n )}\n <div className=\"text-start text-2xl font-bold\">{header?.title || \"AI Assistant\"}</div>\n </div>\n <X\n className=\"text-zinc-400 cursor-pointer\"\n onClick={() => setOpen(false)}\n />\n </div>\n\n <div className=\"flex-1 overflow-auto scrollbar-none\">\n <div className=\"p-4\">\n <ChatBody enableToolCallIndicator={enableToolCallIndicator} />\n </div>\n </div>\n <Suggestion />\n <div className=\"sticky bottom-0 border-t border-zinc-800 m-2\">\n <ChatInput\n input={input}\n inputFileAccept={inputFileAccept}\n setInput={setInput}\n handleSubmit={defaultHandleSubmit}\n isLoading={isLoading}\n fileInput={fileInput}\n handleFileSelect={onFileSelect}\n setFileInput={setFileInput}\n onCancel={() => stream.stop?.()}\n />\n </div>\n </div>\n </motion.aside>\n </>\n )}\n </AnimatePresence>\n\n <ChatButton isVisible={!open} setOpen={setOpen} />\n </>\n );\n}\n"],"names":["uuidv4"],"mappings":";;;;;;;;;;;;AAkCA,SAAwB,QAAQ,OAAyB;AAEvD,QAAM,EAAE,kBAAkB,kBAAkB,yBAAyB,QAAQ,oBAAoB;AACjG,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,EAAE,WAAW,aAAA,IAAiB,gBAAA;AAEpC,QAAM,SAAS,iBAAA;AACf,QAAM,YAAY,OAAO;AACzB,QAAM,EAAE,QAAA,IAAY,UAAA;AAGpB,YAAU,MAAM;AACd,YAAQ,QAAQ;AAAA,EAClB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,sBAAsB,OAAO,MAAiB;AAClD,MAAE,eAAA;AAEF,QAAK,MAAM,KAAA,EAAO,WAAW,KAAK,UAAU,WAAW,KAAM;AAC3D;AAGF,QAAI,cAA0B;AAC9B,QAAI,kBAAkB;AACpB,YAAM,SAAS,MAAM,iBAAA;AACrB,UAAI,UAAU,OAAO,SAAS,EAAG,eAAc;AAAA,IACjD;AAEA,UAAM,gBAAgB;AAAA,MACpB,GAAI,MAAM,OAAO,SAAS,IAAI,CAAC,EAAE,MAAM,QAAQ,MAAM,MAAA,CAAO,IAAI,CAAA;AAAA,MAChE,GAAG,YAAY,IAAI,CAAC,UAAU;AAAA,QAC5B,MAAM;AAAA,QACN,GAAG;AAAA,QACH,eAAe,EAAE,MAAM,YAAA;AAAA,MAAqB,EAC5C;AAAA,IAAA;AAGJ,UAAM,kBAA2B;AAAA,MAC/B,IAAIA,GAAA;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,IAAA;AAIX,UAAM,OAAO,cAAc,eAAe;AAE1C,aAAS,EAAE;AACX,iBAAa,CAAA,CAAE;AAAA,EACjB;AAEA,QAAM,0BAA0B,OAC9B,UACG;AACH,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,CAAC,MAAO;AAGZ,UAAM,cAA0B,MAAM,QAAQ;AAAA,MAC5C,MAAM,KAAK,KAAK,EAAE,IAAI,OAAO,SAAS;AACpC,cAAM,aAAa,MAAM,IAAI,QAAgB,CAAC,SAAS,WAAW;AAChE,gBAAM,SAAS,IAAI,WAAA;AACnB,iBAAO,SAAS,MAAM;AACpB,kBAAM,SAAS,OAAO;AACtB,oBAAQ,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,UAC9B;AACA,iBAAO,UAAU;AACjB,iBAAO,cAAc,IAAI;AAAA,QAC3B,CAAC;AAED,eAAO;AAAA,UACL,UAAU,KAAK;AAAA,UACf,UAAU,KAAK;AAAA,UACf;AAAA,UACA,UAAU;AAAA;AAAA,QAAA;AAAA,MAEd,CAAC;AAAA,IAAA;AAGH,iBAAa,CAAC,aAAa,CAAC,GAAG,UAAU,GAAG,WAAW,CAAC;AAAA,EAC1D;AAEA,QAAM,eAAe,oBAAoB;AAEzC,SACE,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA,oBAAC,iBAAA,EACE,kBACC,qBAAA,UAAA,EAEE,UAAA;AAAA,MAAA;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,QAAQ,KAAK;AAAA,UAC5B,SAAS,EAAE,SAAS,EAAA;AAAA,UACpB,SAAS,EAAE,SAAS,EAAA;AAAA,UACpB,MAAM,EAAE,SAAS,EAAA;AAAA,QAAE;AAAA,MAAA;AAAA,MAIrB;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,WAAU;AAAA,UACV,SAAS,EAAE,GAAG,OAAA;AAAA,UACd,SAAS,EAAE,GAAG,EAAA;AAAA,UACd,MAAM,EAAE,GAAG,OAAA;AAAA,UACX,YAAY,EAAE,MAAM,UAAU,WAAW,KAAK,SAAS,GAAA;AAAA,UAEvD,UAAA,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,YAAA,qBAAC,OAAA,EAAI,WAAU,wEACb,UAAA;AAAA,cAAA,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,gBAAA,QAAQ;AAAA,gBAEP;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,KAAK,QAAQ;AAAA,oBACb,KAAK,QAAQ,QAAQ,GAAG,OAAO,KAAK,UAAU;AAAA,oBAC9C,WAAU;AAAA,kBAAA;AAAA,gBAAA;AAAA,oCAGb,OAAA,EAAI,WAAU,iCAAiC,UAAA,QAAQ,SAAS,eAAA,CAAe;AAAA,cAAA,GAClF;AAAA,cACA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAU;AAAA,kBACV,SAAS,MAAM,QAAQ,KAAK;AAAA,gBAAA;AAAA,cAAA;AAAA,YAC9B,GACF;AAAA,YAEA,oBAAC,OAAA,EAAI,WAAU,uCACb,UAAA,oBAAC,OAAA,EAAI,WAAU,OACb,UAAA,oBAAC,UAAA,EAAS,wBAAA,CAAkD,EAAA,CAC9D,GACF;AAAA,gCACC,YAAA,EAAW;AAAA,YACZ,oBAAC,OAAA,EAAI,WAAU,gDACb,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,cAAc;AAAA,gBACd;AAAA,gBACA;AAAA,gBACA,kBAAkB;AAAA,gBAClB;AAAA,gBACA,UAAU,MAAM,OAAO,OAAA;AAAA,cAAO;AAAA,YAAA,EAChC,CACF;AAAA,UAAA,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,IACF,EAAA,CACF,EAAA,CAEJ;AAAA,IAEA,oBAAC,YAAA,EAAW,WAAW,CAAC,MAAM,QAAA,CAAkB;AAAA,EAAA,GAClD;AAEJ;"}
1
+ {"version":3,"file":"index.es2.js","sources":["../src/pages/Sidebar/sidebar.tsx"],"sourcesContent":["import Suggestion from \"@/components/Suggestion\";\nimport { useFileProvider } from \"@/providers/FileProvider\";\nimport { useStreamContext } from \"@/providers/Stream\";\nimport { useThread } from \"@/providers/Thread\";\nimport type { ChatSidebarProps } from \"@/types/ChatProps\";\nimport type { FileInfo } from \"@/types/fileInput\";\nimport type { Message } from \"@langchain/langgraph-sdk\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { X } from \"lucide-react\";\nimport { useEffect, useState, type FormEvent } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport ChatBody from \"../../components/ChatBody\";\nimport ChatButton from \"../../components/ChatButton\";\nimport ChatInput from \"../../components/sidebar/ChatInput\";\n\n/**\n * Main sidebar chat interface component.\n * Displays a chat button that opens a sliding sidebar with full chat functionality.\n * \n * @param header - Custom header text for the chat sidebar (default: \"AI Assistant\")\n * @param handleFileSelect - Optional custom file selection handler\n * @param callThisOnSubmit - Optional callback invoked before message submission, can return updated file list\n * @param preventSubmit - Optional boolean to prevent all submit actions when true\n * \n * @example\n * ```tsx\n * <Sidebar \n * header=\"My Custom AI\"\n * preventSubmit={true} // Disables all submit functionality\n * callThisOnSubmit={async () => {\n * // Upload files to your backend\n * return updatedFiles;\n * }}\n * />\n * ```\n */\nexport default function Sidebar(props: ChatSidebarProps) {\n\n const { handleFileSelect, callThisOnSubmit, enableToolCallIndicator, header, inputFileAccept, filePreview, s3_upload, preventSubmit } = props;\n const [open, setOpen] = useState(false);\n const [input, setInput] = useState(\"\");\n const { fileInput, setFileInput } = useFileProvider();\n\n const stream = useStreamContext();\n const isLoading = stream.isLoading;\n const { setMode } = useThread();\n\n // Set thread mode to single when using Sidebar\n useEffect(() => {\n setMode(\"single\");\n }, [setMode]);\n\n const defaultHandleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n\n if (preventSubmit || (input.trim().length === 0 && fileInput.length === 0) || isLoading)\n return;\n\n // Call the custom upload and get the latest files\n let latestFiles: FileInfo[] = fileInput;\n if (callThisOnSubmit) {\n const result = await callThisOnSubmit();\n if (result && result.length > 0) latestFiles = result;\n }\n\n // Create content blocks based on upload type\n let contentBlocks: any;\n if (s3_upload) {\n // For S3 uploads, send text message\n let messageText = input.trim();\n if (latestFiles.length > 0) {\n const fileNames = latestFiles.map(file => file.fileName).join(\", \");\n const fileText = `file${latestFiles.length > 1 ? 's' : ''} uploaded: ${fileNames}`;\n messageText = messageText ? `${fileText}\\n\\n - ${messageText}` : fileText;\n }\n contentBlocks = [{ type: \"text\", text: messageText }];\n } else {\n contentBlocks = [\n ...(input.trim().length > 0 ? [{ type: \"text\", text: input }] : []),\n ...latestFiles.map((file) => ({\n type: \"document\" as const,\n ...file,\n cache_control: { type: \"ephemeral\" as const },\n })),\n ];\n }\n\n const newHumanMessage: Message = {\n id: uuidv4(),\n type: \"human\",\n content: contentBlocks,\n };\n\n // Use the unified submitMessage function\n await stream.submitMessage(newHumanMessage);\n\n setInput(\"\");\n setFileInput([]);\n };\n\n const defaultHandleFileSelect = async (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const files = event.target.files;\n if (!files) return;\n\n // Convert files to base64 for sending\n const fileDetails: FileInfo[] = await Promise.all(\n Array.from(files).map(async (file) => {\n const base64Data = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n resolve(result.split(\",\")[1]); // Remove data:...;base64, prefix\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n\n return {\n fileName: file.name,\n fileType: file.type,\n file: file,\n fileData: base64Data, // Add this to your FileInfo type\n };\n })\n );\n\n setFileInput((prevFile) => [...prevFile, ...fileDetails]);\n };\n\n const onFileSelect = handleFileSelect || defaultHandleFileSelect;\n \n return (\n <>\n <AnimatePresence>\n {open && (\n <>\n {/* Overlay */}\n <motion.div\n className=\"fixed inset-0 z-40 bg-black/30\"\n onClick={() => setOpen(false)}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n />\n\n {/* Sidebar */}\n <motion.aside\n className=\"fixed right-0 top-0 z-50 h-screen w-[520px] bg-black flex flex-col text-white\"\n initial={{ x: \"100%\" }}\n animate={{ x: 0 }}\n exit={{ x: \"100%\" }}\n transition={{ type: \"spring\", stiffness: 260, damping: 30 }}\n >\n <div className=\"flex h-full flex-col\">\n <div className=\"flex border-b border-zinc-800 py-4 px-6 justify-between items-center\">\n <div className=\"flex items-center gap-3\">\n {header?.logoUrl && (\n // Render provided logo image if present\n <img\n src={header?.logoUrl}\n alt={header?.title ? `${header.title} logo` : \"AI Assistant logo\"}\n className=\"h-8 w-8 object-contain rounded-sm\"\n />\n )}\n <div className=\"text-start text-2xl font-bold\">{header?.title || \"AI Assistant\"}</div>\n </div>\n <X\n className=\"text-zinc-400 cursor-pointer\"\n onClick={() => setOpen(false)}\n />\n </div>\n\n <div className=\"flex-1 overflow-auto scrollbar-none\">\n <div className=\"p-4\">\n <ChatBody enableToolCallIndicator={enableToolCallIndicator} />\n </div>\n </div>\n <Suggestion />\n <div className=\"sticky bottom-0 border-t border-zinc-800 m-2\">\n <ChatInput\n input={input}\n inputFileAccept={inputFileAccept}\n setInput={setInput}\n handleSubmit={defaultHandleSubmit}\n isLoading={isLoading}\n fileInput={fileInput}\n handleFileSelect={onFileSelect}\n setFileInput={setFileInput}\n onCancel={() => stream.stop?.()}\n filePreview={filePreview}\n />\n </div>\n </div>\n </motion.aside>\n </>\n )}\n </AnimatePresence>\n\n <ChatButton isVisible={!open} setOpen={setOpen} />\n </>\n );\n}\n"],"names":["uuidv4"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { bootstrapUiContext } from "./index.es22.js";
2
- import { LoadExternalComponent, useStreamContext } from "./index.es22.js";
1
+ import { bootstrapUiContext } from "./index.es29.js";
2
+ import { LoadExternalComponent, useStreamContext } from "./index.es29.js";
3
3
  bootstrapUiContext();
4
4
  export {
5
5
  LoadExternalComponent,
@@ -1,125 +1,21 @@
1
- import { useStream } from "./index.es19.js";
2
- import "./index.es18.js";
3
- import * as React from "react";
4
- import * as ReactDOM from "react-dom";
5
- import * as JsxRuntime from "react/jsx-runtime";
6
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
7
- const UseStreamContext = React.createContext(null);
8
- function useStreamContext() {
9
- const ctx = React.useContext(UseStreamContext);
10
- if (!ctx) throw new Error("useStreamContext must be used within a LoadExternalComponent");
11
- return new Proxy(ctx, { get(target, prop) {
12
- if (prop === "meta") return target.meta;
13
- return target.stream[prop];
14
- } });
1
+ function getContentString(content) {
2
+ if (typeof content === "string") return content;
3
+ const texts = content.filter((c) => c.type === "text").map((c) => c.text);
4
+ return texts.join(" ");
15
5
  }
16
- var ComponentStore = class {
17
- cache = {};
18
- boundCache = {};
19
- callbacks = {};
20
- respond(shadowRootId, comp, targetElement) {
21
- this.cache[shadowRootId] = {
22
- comp,
23
- target: targetElement
24
- };
25
- this.callbacks[shadowRootId]?.forEach((c) => c(comp, targetElement));
26
- }
27
- getBoundStore(shadowRootId) {
28
- this.boundCache[shadowRootId] ??= {
29
- subscribe: (onStoreChange) => {
30
- this.callbacks[shadowRootId] ??= [];
31
- this.callbacks[shadowRootId].push(onStoreChange);
32
- return () => {
33
- this.callbacks[shadowRootId] = this.callbacks[shadowRootId].filter((c) => c !== onStoreChange);
34
- };
35
- },
36
- getSnapshot: () => this.cache[shadowRootId]
37
- };
38
- return this.boundCache[shadowRootId];
39
- }
40
- };
41
- const COMPONENT_STORE = new ComponentStore();
42
- const EXT_STORE_SYMBOL = /* @__PURE__ */ Symbol.for("LGUI_EXT_STORE");
43
- const REQUIRE_SYMBOL = /* @__PURE__ */ Symbol.for("LGUI_REQUIRE");
44
- const REQUIRE_EXTRA_SYMBOL = /* @__PURE__ */ Symbol.for("LGUI_REQUIRE_EXTRA");
45
- const isIterable = (value) => value != null && typeof value === "object" && Symbol.iterator in value;
46
- const isPromise = (value) => value != null && typeof value === "object" && "then" in value && typeof value.then === "function";
47
- const isReactNode = (value) => {
48
- if (React.isValidElement(value)) return true;
49
- if (value == null) return true;
50
- if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") return true;
51
- if (isIterable(value)) return true;
52
- if (isPromise(value)) return true;
53
- return false;
54
- };
55
- function LoadExternalComponent({ stream, namespace, message, meta, fallback, components, ...props }) {
56
- const ref = React.useRef(null);
57
- const shadowRootId = `child-shadow-${React.useId()}`;
58
- const store = React.useMemo(() => COMPONENT_STORE.getBoundStore(shadowRootId), [shadowRootId]);
59
- const state = React.useSyncExternalStore(store.subscribe, store.getSnapshot);
60
- const clientComponent = components?.[message.name];
61
- const hasClientComponent = clientComponent != null;
62
- let fallbackComponent = null;
63
- if (isReactNode(fallback)) fallbackComponent = fallback;
64
- else if (typeof fallback === "object" && fallback != null) fallbackComponent = fallback?.[message.name];
65
- const uiNamespace = namespace ?? stream.assistantId;
66
- const uiClient = stream.client["~ui"];
67
- React.useEffect(() => {
68
- if (hasClientComponent) return;
69
- uiClient.getComponent(uiNamespace, message.name).then((html) => {
70
- const dom = ref.current;
71
- if (!dom) return;
72
- const root = dom.shadowRoot ?? dom.attachShadow({ mode: "open" });
73
- const fragment = document.createRange().createContextualFragment(html.replace("{{shadowRootId}}", shadowRootId));
74
- root.appendChild(fragment);
75
- });
76
- }, [
77
- uiClient,
78
- uiNamespace,
79
- message.name,
80
- shadowRootId,
81
- hasClientComponent
82
- ]);
83
- if (hasClientComponent) return /* @__PURE__ */ jsx(UseStreamContext.Provider, {
84
- value: {
85
- stream,
86
- meta
87
- },
88
- children: React.createElement(clientComponent, message.props)
89
- });
90
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
91
- id: shadowRootId,
92
- ref,
93
- ...props
94
- }), /* @__PURE__ */ jsx(UseStreamContext.Provider, {
95
- value: {
96
- stream,
97
- meta
98
- },
99
- children: state?.target != null ? ReactDOM.createPortal(React.createElement(state.comp, message.props), state.target) : fallbackComponent
100
- })] });
6
+ function isAIMessage(message) {
7
+ return message.type === "ai";
8
+ }
9
+ function isAiWithToolCalls(message) {
10
+ return isAIMessage(message) && message.tool_calls && message.tool_calls.length > 0;
101
11
  }
102
- function bootstrapUiContext() {
103
- if (typeof window === "undefined") return;
104
- window[EXT_STORE_SYMBOL] = COMPONENT_STORE;
105
- window[REQUIRE_SYMBOL] = (name) => {
106
- if (name === "react") return React;
107
- if (name === "react-dom") return ReactDOM;
108
- if (name === "react/jsx-runtime") return JsxRuntime;
109
- if (name === "@langchain/langgraph-sdk/react") return { useStream };
110
- if (name === "@langchain/langgraph-sdk/react-ui") return {
111
- useStreamContext,
112
- LoadExternalComponent: () => {
113
- throw new Error("Nesting LoadExternalComponent is not supported");
114
- }
115
- };
116
- if (window[REQUIRE_EXTRA_SYMBOL] != null && typeof window[REQUIRE_EXTRA_SYMBOL] === "object" && name in window[REQUIRE_EXTRA_SYMBOL]) return window[REQUIRE_EXTRA_SYMBOL][name];
117
- throw new Error(`Unknown module...: ${name}`);
118
- };
12
+ function isToolMessage(message) {
13
+ return message.type === "tool";
119
14
  }
120
15
  export {
121
- LoadExternalComponent,
122
- bootstrapUiContext,
123
- useStreamContext
16
+ getContentString,
17
+ isAIMessage,
18
+ isAiWithToolCalls,
19
+ isToolMessage
124
20
  };
125
21
  //# sourceMappingURL=index.es22.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.es22.js","sources":["../node_modules/.pnpm/@langchain+langgraph-sdk@1.5.3_@langchain+core@1.1.13_openai@6.16.0_zod@4.3.5___react-d_6e8116ad15c37793c6138fe0d58aa04e/node_modules/@langchain/langgraph-sdk/dist/react-ui/client.js"],"sourcesContent":["\"use client\";\n\nimport { useStream } from \"../react/stream.js\";\nimport \"../react/index.js\";\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport * as JsxRuntime from \"react/jsx-runtime\";\nimport { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\n\n//#region src/react-ui/client.tsx\nconst UseStreamContext = React.createContext(null);\nfunction useStreamContext() {\n\tconst ctx = React.useContext(UseStreamContext);\n\tif (!ctx) throw new Error(\"useStreamContext must be used within a LoadExternalComponent\");\n\treturn new Proxy(ctx, { get(target, prop) {\n\t\tif (prop === \"meta\") return target.meta;\n\t\treturn target.stream[prop];\n\t} });\n}\nvar ComponentStore = class {\n\tcache = {};\n\tboundCache = {};\n\tcallbacks = {};\n\trespond(shadowRootId, comp, targetElement) {\n\t\tthis.cache[shadowRootId] = {\n\t\t\tcomp,\n\t\t\ttarget: targetElement\n\t\t};\n\t\tthis.callbacks[shadowRootId]?.forEach((c) => c(comp, targetElement));\n\t}\n\tgetBoundStore(shadowRootId) {\n\t\tthis.boundCache[shadowRootId] ??= {\n\t\t\tsubscribe: (onStoreChange) => {\n\t\t\t\tthis.callbacks[shadowRootId] ??= [];\n\t\t\t\tthis.callbacks[shadowRootId].push(onStoreChange);\n\t\t\t\treturn () => {\n\t\t\t\t\tthis.callbacks[shadowRootId] = this.callbacks[shadowRootId].filter((c) => c !== onStoreChange);\n\t\t\t\t};\n\t\t\t},\n\t\t\tgetSnapshot: () => this.cache[shadowRootId]\n\t\t};\n\t\treturn this.boundCache[shadowRootId];\n\t}\n};\nconst COMPONENT_STORE = new ComponentStore();\nconst EXT_STORE_SYMBOL = Symbol.for(\"LGUI_EXT_STORE\");\nconst REQUIRE_SYMBOL = Symbol.for(\"LGUI_REQUIRE\");\nconst REQUIRE_EXTRA_SYMBOL = Symbol.for(\"LGUI_REQUIRE_EXTRA\");\nconst isIterable = (value) => value != null && typeof value === \"object\" && Symbol.iterator in value;\nconst isPromise = (value) => value != null && typeof value === \"object\" && \"then\" in value && typeof value.then === \"function\";\nconst isReactNode = (value) => {\n\tif (React.isValidElement(value)) return true;\n\tif (value == null) return true;\n\tif (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"bigint\" || typeof value === \"boolean\") return true;\n\tif (isIterable(value)) return true;\n\tif (isPromise(value)) return true;\n\treturn false;\n};\nfunction LoadExternalComponent({ stream, namespace, message, meta, fallback, components, ...props }) {\n\tconst ref = React.useRef(null);\n\tconst shadowRootId = `child-shadow-${React.useId()}`;\n\tconst store = React.useMemo(() => COMPONENT_STORE.getBoundStore(shadowRootId), [shadowRootId]);\n\tconst state = React.useSyncExternalStore(store.subscribe, store.getSnapshot);\n\tconst clientComponent = components?.[message.name];\n\tconst hasClientComponent = clientComponent != null;\n\tlet fallbackComponent = null;\n\tif (isReactNode(fallback)) fallbackComponent = fallback;\n\telse if (typeof fallback === \"object\" && fallback != null) fallbackComponent = fallback?.[message.name];\n\tconst uiNamespace = namespace ?? stream.assistantId;\n\tconst uiClient = stream.client[\"~ui\"];\n\tReact.useEffect(() => {\n\t\tif (hasClientComponent) return;\n\t\tuiClient.getComponent(uiNamespace, message.name).then((html) => {\n\t\t\tconst dom = ref.current;\n\t\t\tif (!dom) return;\n\t\t\tconst root = dom.shadowRoot ?? dom.attachShadow({ mode: \"open\" });\n\t\t\tconst fragment = document.createRange().createContextualFragment(html.replace(\"{{shadowRootId}}\", shadowRootId));\n\t\t\troot.appendChild(fragment);\n\t\t});\n\t}, [\n\t\tuiClient,\n\t\tuiNamespace,\n\t\tmessage.name,\n\t\tshadowRootId,\n\t\thasClientComponent\n\t]);\n\tif (hasClientComponent) return /* @__PURE__ */ jsx(UseStreamContext.Provider, {\n\t\tvalue: {\n\t\t\tstream,\n\t\t\tmeta\n\t\t},\n\t\tchildren: React.createElement(clientComponent, message.props)\n\t});\n\treturn /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(\"div\", {\n\t\tid: shadowRootId,\n\t\tref,\n\t\t...props\n\t}), /* @__PURE__ */ jsx(UseStreamContext.Provider, {\n\t\tvalue: {\n\t\t\tstream,\n\t\t\tmeta\n\t\t},\n\t\tchildren: state?.target != null ? ReactDOM.createPortal(React.createElement(state.comp, message.props), state.target) : fallbackComponent\n\t})] });\n}\nfunction experimental_loadShare(name, module) {\n\tif (typeof window === \"undefined\") return;\n\twindow[REQUIRE_EXTRA_SYMBOL] ??= {};\n\twindow[REQUIRE_EXTRA_SYMBOL][name] = module;\n}\nfunction bootstrapUiContext() {\n\tif (typeof window === \"undefined\") return;\n\twindow[EXT_STORE_SYMBOL] = COMPONENT_STORE;\n\twindow[REQUIRE_SYMBOL] = (name) => {\n\t\tif (name === \"react\") return React;\n\t\tif (name === \"react-dom\") return ReactDOM;\n\t\tif (name === \"react/jsx-runtime\") return JsxRuntime;\n\t\tif (name === \"@langchain/langgraph-sdk/react\") return { useStream };\n\t\tif (name === \"@langchain/langgraph-sdk/react-ui\") return {\n\t\t\tuseStreamContext,\n\t\t\tLoadExternalComponent: () => {\n\t\t\t\tthrow new Error(\"Nesting LoadExternalComponent is not supported\");\n\t\t\t}\n\t\t};\n\t\tif (window[REQUIRE_EXTRA_SYMBOL] != null && typeof window[REQUIRE_EXTRA_SYMBOL] === \"object\" && name in window[REQUIRE_EXTRA_SYMBOL]) return window[REQUIRE_EXTRA_SYMBOL][name];\n\t\tthrow new Error(`Unknown module...: ${name}`);\n\t};\n}\n\n//#endregion\nexport { LoadExternalComponent, bootstrapUiContext, experimental_loadShare, useStreamContext };\n//# sourceMappingURL=client.js.map"],"names":[],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"index.es22.js","sources":["../src/utils/utils.ts"],"sourcesContent":["import type { AIMessage, Message } from \"@langchain/langgraph-sdk\";\n\n/**\n * Extracts a string summary from a message's content, supporting multimodal (text, image, file, etc.).\n * - If text is present, returns the joined text.\n * - If not, returns a label for the first non-text modality (e.g., 'Image', 'Other').\n * - If unknown, returns 'Multimodal message'.\n */\nexport function getContentString(content: Message[\"content\"]): string {\n if (typeof content === \"string\") return content;\n const texts = content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text);\n return texts.join(\" \");\n}\n\nexport function isAIMessage(message: Message): message is AIMessage {\n return message.type === \"ai\";\n}\n\nexport function isAiWithToolCalls(message: Message) {\n return (\n isAIMessage(message) && message.tool_calls && message.tool_calls.length > 0\n );\n}\n\nexport function isToolMessage(message: Message) {\n return message.type === \"tool\";\n}\n"],"names":[],"mappings":"AAQO,SAAS,iBAAiB,SAAqC;AACpE,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,QAAM,QAAQ,QACX,OAAO,CAAC,MAA2C,EAAE,SAAS,MAAM,EACpE,IAAI,CAAC,MAAM,EAAE,IAAI;AACpB,SAAO,MAAM,KAAK,GAAG;AACvB;AAEO,SAAS,YAAY,SAAwC;AAClE,SAAO,QAAQ,SAAS;AAC1B;AAEO,SAAS,kBAAkB,SAAkB;AAClD,SACE,YAAY,OAAO,KAAK,QAAQ,cAAc,QAAQ,WAAW,SAAS;AAE9E;AAEO,SAAS,cAAc,SAAkB;AAC9C,SAAO,QAAQ,SAAS;AAC1B;"}