langgraph-ui-components 0.0.25 → 0.0.27

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 (82) hide show
  1. package/README.md +412 -51
  2. package/dist/_virtual/index.cjs6.js +1 -1
  3. package/dist/_virtual/index.cjs8.js +1 -1
  4. package/dist/_virtual/index.es6.js +2 -2
  5. package/dist/_virtual/index.es8.js +2 -2
  6. package/dist/assets/langgraph-ui-components.css +1 -1
  7. package/dist/components/ChatBody.cjs.js +2 -2
  8. package/dist/components/ChatBody.cjs.js.map +1 -1
  9. package/dist/components/ChatBody.d.ts.map +1 -1
  10. package/dist/components/ChatBody.es.js +137 -98
  11. package/dist/components/ChatBody.es.js.map +1 -1
  12. package/dist/components/messages/AgentMessage.cjs.js +3 -1
  13. package/dist/components/messages/AgentMessage.cjs.js.map +1 -1
  14. package/dist/components/messages/AgentMessage.d.ts +3 -1
  15. package/dist/components/messages/AgentMessage.d.ts.map +1 -1
  16. package/dist/components/messages/AgentMessage.es.js +197 -112
  17. package/dist/components/messages/AgentMessage.es.js.map +1 -1
  18. package/dist/entries/components.cjs.js +1 -1
  19. package/dist/entries/components.d.ts.map +1 -1
  20. package/dist/entries/components.es.js +4 -5
  21. package/dist/entries/components.es.js.map +1 -1
  22. package/dist/entries/hooks.cjs.js +1 -1
  23. package/dist/entries/hooks.d.ts.map +1 -1
  24. package/dist/entries/hooks.es.js +5 -6
  25. package/dist/entries/hooks.es.js.map +1 -1
  26. package/dist/entries/providers.cjs.js +1 -1
  27. package/dist/entries/providers.d.ts +1 -1
  28. package/dist/entries/providers.d.ts.map +1 -1
  29. package/dist/entries/providers.es.js +18 -19
  30. package/dist/entries/providers.es.js.map +1 -1
  31. package/dist/index.cjs.js +1 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.es.js +28 -29
  35. package/dist/index.es.js.map +1 -1
  36. package/dist/node_modules/.pnpm/eventemitter3@4.0.7/node_modules/eventemitter3/index.cjs.js +1 -1
  37. package/dist/node_modules/.pnpm/eventemitter3@4.0.7/node_modules/eventemitter3/index.es.js +1 -1
  38. package/dist/node_modules/.pnpm/p-timeout@3.2.0/node_modules/p-timeout/index.cjs.js +1 -1
  39. package/dist/node_modules/.pnpm/p-timeout@3.2.0/node_modules/p-timeout/index.es.js +1 -1
  40. package/dist/node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@19.2.3/node_modules/react-syntax-highlighter/dist/cjs/styles/prism/index.cjs.js +1 -1
  41. package/dist/node_modules/.pnpm/react-syntax-highlighter@16.1.0_react@19.2.3/node_modules/react-syntax-highlighter/dist/cjs/styles/prism/index.es.js +1 -1
  42. package/dist/providers/ChatProvider.cjs.js +1 -1
  43. package/dist/providers/ChatProvider.cjs.js.map +1 -1
  44. package/dist/providers/ChatProvider.d.ts +17 -1
  45. package/dist/providers/ChatProvider.d.ts.map +1 -1
  46. package/dist/providers/ChatProvider.es.js +18 -17
  47. package/dist/providers/ChatProvider.es.js.map +1 -1
  48. package/dist/providers/ChatRuntime.es.js +4 -4
  49. package/dist/providers/CustomComponentProvider.cjs.js +1 -1
  50. package/dist/providers/CustomComponentProvider.cjs.js.map +1 -1
  51. package/dist/providers/CustomComponentProvider.d.ts +11 -0
  52. package/dist/providers/CustomComponentProvider.d.ts.map +1 -1
  53. package/dist/providers/CustomComponentProvider.es.js +51 -35
  54. package/dist/providers/CustomComponentProvider.es.js.map +1 -1
  55. package/dist/providers/Stream.cjs.js +1 -1
  56. package/dist/providers/Stream.cjs.js.map +1 -1
  57. package/dist/providers/Stream.d.ts.map +1 -1
  58. package/dist/providers/Stream.es.js +113 -94
  59. package/dist/providers/Stream.es.js.map +1 -1
  60. package/dist/providers/Thread.cjs.js +1 -1
  61. package/dist/providers/Thread.cjs.js.map +1 -1
  62. package/dist/providers/Thread.d.ts +2 -1
  63. package/dist/providers/Thread.d.ts.map +1 -1
  64. package/dist/providers/Thread.es.js +19 -19
  65. package/dist/providers/Thread.es.js.map +1 -1
  66. package/dist/styles.css +1 -1
  67. package/package.json +1 -1
  68. package/src/components/ChatBody.tsx +88 -28
  69. package/src/components/messages/AgentMessage.tsx +281 -81
  70. package/src/entries/components.ts +0 -2
  71. package/src/entries/hooks.ts +0 -2
  72. package/src/entries/providers.ts +1 -3
  73. package/src/index.css +2 -2
  74. package/src/index.ts +1 -3
  75. package/src/providers/ChatProvider.tsx +18 -1
  76. package/src/providers/CustomComponentProvider.tsx +41 -0
  77. package/src/providers/Stream.tsx +34 -15
  78. package/src/providers/Thread.tsx +2 -2
  79. package/dist/components/ToolCallFunctions.cjs.js +0 -2
  80. package/dist/components/ToolCallFunctions.cjs.js.map +0 -1
  81. package/dist/components/ToolCallFunctions.es.js +0 -75
  82. package/dist/components/ToolCallFunctions.es.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBody.es.js","sources":["../../src/components/ChatBody.tsx"],"sourcesContent":["import { parsePartialJson } from \"@langchain/core/output_parsers\";\nimport { useStreamContext } from \"@/providers/Stream\";\nimport type { chatBodyProps } from \"@/types/ChatProps\";\nimport { logger } from \"@/utils/logger\";\nimport { isAiWithToolCalls, isToolMessage } from \"@/utils/utils\";\nimport type { AIMessage, Message } from \"@langchain/langgraph-sdk\";\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport AgentMessage from \"./messages/AgentMessage\";\nimport CustomComponentRender from \"./messages/CustomComponentRender\";\nimport HumanMessage from \"./messages/HumanMessage\";\nimport type { MessageFeedback } from \"./messages/MessageActions\";\nimport Thinking from \"./Thinking\";\nimport ToolCallFunctions from \"./ToolCallFunctions\";\n\nexport default function ChatBody({ setIsFirstMessage, enableToolCallIndicator, chatBodyProps }: { setIsFirstMessage?: React.Dispatch<React.SetStateAction<boolean>>, enableToolCallIndicator?: boolean, chatBodyProps?: chatBodyProps }) {\n const stream = useStreamContext();\n const messages = stream.messages;\n const isLoading = stream.isLoading;\n\n // State to track message feedback (likes/dislikes)\n const [messageFeedback, setMessageFeedback] = useState<Record<string, MessageFeedback>>({});\n\n logger.debug(\"ChatBody render - messages count:\", messages, \"isLoading:\", isLoading);\n\n // Memoize messages with stable reference\n const memoMessages = useMemo(() => messages ?? [], [messages]);\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const prevMessageCountRef = useRef(0);\n const shouldAutoScrollRef = useRef(true);\n\n // Handler for message feedback\n const handleFeedback = useCallback((messageId: string, feedback: MessageFeedback) => {\n setMessageFeedback(prev => ({\n ...prev,\n [messageId]: feedback,\n }));\n }, []);\n\n // Handler for message regeneration\n const handleRegenerate = useCallback(async (\n parentCheckpoint: any | null | undefined,\n ) => {\n if (!parentCheckpoint) {\n console.error(\"No parent checkpoint available for regeneration\");\n return;\n }\n\n await stream.submit(undefined, {\n checkpoint: parentCheckpoint,\n streamMode: [\"values\"],\n streamSubgraphs: true,\n streamResumable: true,\n });\n }, [stream]);\n\n // Handler for selecting a different branch\n const handleBranchSelect = useCallback((branch: string) => {\n stream.setBranch(branch);\n }, [stream]);\n\n const getToolCallsFromContent = useCallback((content: Message[\"content\"]): AIMessage[\"tool_calls\"] => {\n if (!Array.isArray(content)) return [];\n const toolCallContents = content.filter(\n (c) => typeof c === \"object\" && c !== null && (c as any).type === \"tool_use\" && (c as any).id,\n ) as Array<Record<string, any>>;\n\n return toolCallContents.map((tc) => {\n let args: Record<string, any> = {};\n if (tc?.input) {\n if (typeof tc.input === \"string\") {\n try {\n args = parsePartialJson(tc.input) ?? {};\n } catch {\n args = {};\n }\n } else if (typeof tc.input === \"object\") {\n args = tc.input as Record<string, any>;\n }\n }\n return {\n name: tc.name ?? \"\",\n id: tc.id ?? \"\",\n args,\n type: \"tool_call\",\n };\n });\n }, []);\n\n // Get the parent scroll container\n const getScrollContainer = useCallback(() => {\n if (containerRef.current) {\n // Find the parent with overflow-y-auto class\n let parent = containerRef.current.parentElement;\n while (parent) {\n const style = window.getComputedStyle(parent);\n if (style.overflowY === 'auto' || style.overflowY === 'scroll') {\n return parent;\n }\n parent = parent.parentElement;\n }\n }\n return null;\n }, []);\n\n useEffect(() => {\n if (memoMessages.length > 0 && setIsFirstMessage) {\n setIsFirstMessage(false);\n }\n }, [memoMessages.length, setIsFirstMessage]);\n\n // Memoize message rendering logic to prevent unnecessary re-renders\n const renderMessage = useCallback((msg: typeof messages[0], index: number, messagesArray: typeof messages) => {\n const isCurrentlyStreamingMessage = isLoading && index === messagesArray.length - 1 && msg.type === \"ai\";\n if (!msg.content.length && !isAiWithToolCalls(msg) && !isCurrentlyStreamingMessage) return null;\n\n if (msg.additional_kwargs?.hidden) {\n return null;\n }\n\n // Use message id or fallback to index for key\n const msgKey = msg.id ?? `msg-${index}`;\n\n if (msg.type === \"human\") {\n return <HumanMessage key={msgKey} message={msg} fontSize={chatBodyProps?.fontSize} />;\n }\n\n // Skip standalone tool messages\n if (isToolMessage(msg)) {\n return null;\n }\n\n // Skip if this AI message was already combined with a previous one\n if (msg.type === \"ai\" && index > 0) {\n // Check if previous non-tool message is also an AI message\n let prevIndex = index - 1;\n while (prevIndex >= 0 && isToolMessage(messagesArray[prevIndex])) {\n prevIndex--;\n }\n\n if (prevIndex >= 0 && messagesArray[prevIndex].type === \"ai\") {\n // This is a consecutive AI message, skip it (it will be combined with the previous one)\n return null;\n }\n }\n\n // Collect all consecutive AI messages and tool messages\n const groupedMessages = [msg];\n const toolMessages = [];\n let nextIndex = index + 1;\n\n while (nextIndex < messagesArray.length) {\n const nextMsg = messagesArray[nextIndex];\n\n if (isToolMessage(nextMsg)) {\n toolMessages.push(nextMsg);\n nextIndex++;\n } else if (nextMsg.type === \"ai\") {\n // Combine consecutive AI messages\n groupedMessages.push(nextMsg);\n nextIndex++;\n } else {\n // Stop at human messages or other types\n break;\n }\n }\n\n // Merge content from all AI messages, preserving r/reasoning blocks\n const hasArrayContent = groupedMessages.some(m => Array.isArray(m.content));\n const mergedContent: Message[\"content\"] = hasArrayContent\n ? groupedMessages.flatMap(m => {\n if (Array.isArray(m.content)) return m.content as any[];\n if (typeof m.content === \"string\" && m.content.length > 0)\n return [{ type: \"text\", text: m.content }];\n return [];\n })\n : groupedMessages\n .map(m => (typeof m.content === \"string\" ? m.content : \"\"))\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n // Extract plain-text portion for legacy checks (tool-call extraction, etc.)\n const combinedContent = hasArrayContent\n ? (mergedContent as any[])\n .map((c: any) => (c.type === \"text\" ? (c.text as string) : \"\"))\n .filter(Boolean)\n .join(\" \")\n : (mergedContent as string);\n\n const toolCallsFromContent = groupedMessages\n .flatMap((m) => {\n const calls = getToolCallsFromContent(m.content);\n return calls || [];\n })\n .filter((tc): tc is NonNullable<typeof tc> => tc != null && tc !== undefined);\n\n // Create a combined message object preserving full content (including thinking blocks)\n const combinedMessage = {\n ...msg,\n content: mergedContent,\n };\n\n // Get branch metadata from thread\n const meta = msg ? stream.getMessagesMetadata(msg) : undefined;\n\n // Determine if there is any displayable content (text OR thinking/reasoning blocks)\n const hasThinkingContent = hasArrayContent\n ? (mergedContent as any[]).some(\n (b: any) =>\n (b.type === \"thinking\" && (b.thinking as string)?.length > 0) ||\n (b.type === \"reasoning\" && (b.reasoning as string)?.length > 0),\n )\n : false;\n const hasKwargsReasoning =\n typeof (msg as any).additional_kwargs?.reasoning_content === \"string\" &&\n ((msg as any).additional_kwargs.reasoning_content as string).length > 0;\n const hasAnyDisplayableContent = !!combinedContent || hasThinkingContent || hasKwargsReasoning;\n\n const isLastMessageGroup = nextIndex >= messagesArray.length;\n const isStreamingThisMessage = isLoading && isLastMessageGroup;\n\n // Check if the first message in the group has tool calls\n const hasToolCalls = isAiWithToolCalls(msg) || toolCallsFromContent.length > 0;\n\n // Show Thinking animation whenever streaming with no displayable content yet (plain chat or tool-call)\n const showThinkingIndicator = isStreamingThisMessage && !hasAnyDisplayableContent;\n\n return (\n <React.Fragment key={msgKey}>\n {/* 1. Thinking indicator - show when streaming with no content yet (no icon shown) */}\n {showThinkingIndicator && (\n <Thinking />\n )}\n {enableToolCallIndicator && hasToolCalls && (\n <ToolCallFunctions\n title=\"Agent Thinking\"\n toolMessages={toolMessages}\n toolCalls={toolCallsFromContent}\n />\n )}\n {/* 2. Agent message — pass full mergedContent so thinking/reasoning blocks are preserved */}\n {hasAnyDisplayableContent && (\n <AgentMessage\n agentName={chatBodyProps?.agentName}\n fontSize={chatBodyProps?.fontSize}\n // agentAvatarUrl={chatBodyProps?.agentAvatarUrl}\n message={combinedMessage}\n isStreaming={isStreamingThisMessage}\n onRegenerate={handleRegenerate}\n feedback={msg.id ? messageFeedback[msg.id] : undefined}\n onFeedback={handleFeedback}\n branch={meta?.branch}\n branchOptions={meta?.branchOptions}\n onBranchSelect={handleBranchSelect}\n />\n )}\n {/* 3. Custom component (from all messages in the group) */}\n {groupedMessages.map((m) => (\n <CustomComponentRender key={m.id} message={m} thread={stream} />\n ))}\n </React.Fragment>\n );\n }, [isLoading, stream, enableToolCallIndicator, handleRegenerate, messageFeedback, handleFeedback, handleBranchSelect]);\n\n // Memoize the rendered messages array\n const renderedMessages = useMemo(() => {\n return memoMessages.map((msg, index) => {\n const element = renderMessage(msg, index, memoMessages);\n // Ensure every element has a key, using message id or fallback to index\n if (element && !element.key) {\n return React.cloneElement(element, { key: msg.id ?? `msg-${index}` });\n }\n return element;\n });\n }, [memoMessages, renderMessage]);\n\n // Track user scroll position to determine if we should auto-scroll\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer) return;\n\n const handleScroll = () => {\n const { scrollTop, scrollHeight, clientHeight } = scrollContainer;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n // Consider \"at bottom\" if within 100px\n shouldAutoScrollRef.current = distanceFromBottom < 100;\n };\n\n scrollContainer.addEventListener('scroll', handleScroll);\n return () => scrollContainer.removeEventListener('scroll', handleScroll);\n }, [getScrollContainer]);\n\n // Auto-scroll when new messages are added\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer) return;\n\n const currentCount = memoMessages.length;\n const hasNewMessage = currentCount > prevMessageCountRef.current;\n\n if (hasNewMessage) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n shouldAutoScrollRef.current = true;\n }\n\n prevMessageCountRef.current = currentCount;\n }, [memoMessages, getScrollContainer]);\n\n // Use MutationObserver to detect DOM changes and auto-scroll during streaming\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer || !isLoading) return;\n\n const observer = new MutationObserver(() => {\n if (shouldAutoScrollRef.current && scrollContainer) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n });\n\n // Observe the ChatBody container for changes\n if (containerRef.current) {\n observer.observe(containerRef.current, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n\n return () => observer.disconnect();\n }, [isLoading, getScrollContainer]);\n\n // Use useLayoutEffect to scroll after DOM updates\n useLayoutEffect(() => {\n const scrollContainer = getScrollContainer();\n if (isLoading && shouldAutoScrollRef.current && scrollContainer) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n });\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col gap-4 rounded-4xl p-2\"\n >\n {memoMessages.length === 0 ? (\n <div className=\"flex items-center justify-center h-full text-zinc-500\">\n {isLoading ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"animate-spin h-5 w-5 border-2 border-zinc-500 border-t-transparent rounded-full\" />\n <span>Loading conversation...</span>\n </div>\n ) : (\n \"Start a conversation...\"\n )}\n </div>\n ) : (\n <>\n {renderedMessages}\n {/* Show thinking indicator when loading and no AI response has started yet */}\n {isLoading && memoMessages.length > 0 && (() => {\n const lastMsg = memoMessages[memoMessages.length - 1];\n // Show if last message is human or if last AI has no content (only tool calls)\n return lastMsg.type === \"human\" ||\n (lastMsg.type === \"ai\" && !lastMsg.content && isAiWithToolCalls(lastMsg));\n })() && (\n <Thinking />\n )}\n </>\n )}\n\n </div>\n );\n}\n"],"names":["ChatBody","setIsFirstMessage","enableToolCallIndicator","chatBodyProps","stream","useStreamContext","messages","isLoading","messageFeedback","setMessageFeedback","useState","logger","memoMessages","useMemo","containerRef","useRef","prevMessageCountRef","shouldAutoScrollRef","handleFeedback","useCallback","messageId","feedback","prev","handleRegenerate","parentCheckpoint","handleBranchSelect","branch","getToolCallsFromContent","content","c","tc","args","parsePartialJson","getScrollContainer","parent","style","useEffect","renderMessage","msg","index","messagesArray","isCurrentlyStreamingMessage","isAiWithToolCalls","msgKey","HumanMessage","isToolMessage","prevIndex","groupedMessages","toolMessages","nextIndex","nextMsg","hasArrayContent","m","mergedContent","combinedContent","toolCallsFromContent","combinedMessage","meta","hasThinkingContent","b","hasKwargsReasoning","hasAnyDisplayableContent","isLastMessageGroup","isStreamingThisMessage","hasToolCalls","showThinkingIndicator","jsxs","React","Thinking","jsx","ToolCallFunctions","AgentMessage","CustomComponentRender","renderedMessages","element","scrollContainer","handleScroll","scrollTop","scrollHeight","clientHeight","distanceFromBottom","currentCount","observer","useLayoutEffect","Fragment","lastMsg"],"mappings":"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"}
1
+ {"version":3,"file":"ChatBody.es.js","sources":["../../src/components/ChatBody.tsx"],"sourcesContent":["import { parsePartialJson } from \"@langchain/core/output_parsers\";\nimport { useStreamContext } from \"@/providers/Stream\";\nimport { useCustomComponents } from \"@/providers/CustomComponentProvider\";\nimport type { chatBodyProps } from \"@/types/ChatProps\";\nimport { logger } from \"@/utils/logger\";\nimport { isAiWithToolCalls, isToolMessage } from \"@/utils/utils\";\nimport type { AIMessage, Message } from \"@langchain/langgraph-sdk\";\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport AgentMessage from \"./messages/AgentMessage\";\nimport CustomComponentRender from \"./messages/CustomComponentRender\";\nimport HumanMessage from \"./messages/HumanMessage\";\nimport type { MessageFeedback } from \"./messages/MessageActions\";\nimport Thinking from \"./Thinking\";\n\nexport default function ChatBody({ setIsFirstMessage, enableToolCallIndicator = true, chatBodyProps }: { setIsFirstMessage?: React.Dispatch<React.SetStateAction<boolean>>, enableToolCallIndicator?: boolean, chatBodyProps?: chatBodyProps }) {\n const stream = useStreamContext();\n const { interruptComponents } = useCustomComponents();\n const messages = stream.messages;\n const isLoading = stream.isLoading;\n\n // State to track message feedback (likes/dislikes)\n const [messageFeedback, setMessageFeedback] = useState<Record<string, MessageFeedback>>({});\n\n logger.debug(\"ChatBody render - messages count:\", messages, \"isLoading:\", isLoading);\n\n // Memoize messages with stable reference\n const memoMessages = useMemo(() => messages ?? [], [messages]);\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const prevMessageCountRef = useRef(0);\n const shouldAutoScrollRef = useRef(true);\n\n // Handler for message feedback\n const handleFeedback = useCallback((messageId: string, feedback: MessageFeedback) => {\n setMessageFeedback(prev => ({\n ...prev,\n [messageId]: feedback,\n }));\n }, []);\n\n // Handler for message regeneration\n const handleRegenerate = useCallback(async (\n parentCheckpoint: any | null | undefined,\n ) => {\n if (!parentCheckpoint) {\n console.error(\"No parent checkpoint available for regeneration\");\n return;\n }\n\n await stream.submit(undefined, {\n checkpoint: parentCheckpoint,\n streamMode: [\"values\"],\n streamSubgraphs: true,\n streamResumable: true,\n });\n }, [stream]);\n\n // Handler for selecting a different branch\n const handleBranchSelect = useCallback((branch: string) => {\n stream.setBranch(branch);\n }, [stream]);\n\n // Handler for HITL interrupt responses\n const handleInterruptRespond = useCallback((response: any) => {\n stream.submit(null, { command: { resume: response } });\n }, [stream]);\n\n // Build interrupt actions for custom renderers\n const interruptActions = useMemo(() => {\n const interrupt = stream.interrupt;\n if (!interrupt) return null;\n const payload = interrupt.value as any;\n const actionRequests = payload?.actionRequests ?? [];\n return {\n approve: () => {\n handleInterruptRespond({\n decisions: actionRequests.map(() => ({ type: \"approve\" as const })),\n });\n },\n reject: (reason?: string) => {\n handleInterruptRespond({\n decisions: actionRequests.map(() => ({\n type: \"reject\" as const,\n message: reason || undefined,\n })),\n });\n },\n edit: (editedArgs: Record<string, unknown>) => {\n const action = actionRequests[0];\n handleInterruptRespond({\n decisions: [\n {\n type: \"edit\" as const,\n editedAction: {\n name: action?.name ?? \"\",\n args: { ...action?.args, ...editedArgs },\n },\n },\n ],\n });\n },\n };\n }, [stream.interrupt, handleInterruptRespond]);\n\n const getToolCallsFromContent = useCallback((content: Message[\"content\"]): AIMessage[\"tool_calls\"] => {\n if (!Array.isArray(content)) return [];\n const toolCallContents = content.filter(\n (c) => typeof c === \"object\" && c !== null && (c as any).type === \"tool_use\" && (c as any).id,\n ) as Array<Record<string, any>>;\n\n return toolCallContents.map((tc) => {\n let args: Record<string, any> = {};\n if (tc?.input) {\n if (typeof tc.input === \"string\") {\n try {\n args = parsePartialJson(tc.input) ?? {};\n } catch {\n args = {};\n }\n } else if (typeof tc.input === \"object\") {\n args = tc.input as Record<string, any>;\n }\n }\n return {\n name: tc.name ?? \"\",\n id: tc.id ?? \"\",\n args,\n type: \"tool_call\",\n };\n });\n }, []);\n\n // Get the parent scroll container\n const getScrollContainer = useCallback(() => {\n if (containerRef.current) {\n // Find the parent with overflow-y-auto class\n let parent = containerRef.current.parentElement;\n while (parent) {\n const style = window.getComputedStyle(parent);\n if (style.overflowY === 'auto' || style.overflowY === 'scroll') {\n return parent;\n }\n parent = parent.parentElement;\n }\n }\n return null;\n }, []);\n\n useEffect(() => {\n if (memoMessages.length > 0 && setIsFirstMessage) {\n setIsFirstMessage(false);\n }\n }, [memoMessages.length, setIsFirstMessage]);\n\n // Memoize message rendering logic to prevent unnecessary re-renders\n const renderMessage = useCallback((msg: typeof messages[0], index: number, messagesArray: typeof messages) => {\n const isCurrentlyStreamingMessage = isLoading && index === messagesArray.length - 1 && msg.type === \"ai\";\n if (!msg.content.length && !isAiWithToolCalls(msg) && !isCurrentlyStreamingMessage) return null;\n\n if (msg.additional_kwargs?.hidden) {\n return null;\n }\n\n // Use message id or fallback to index for key\n const msgKey = msg.id ?? `msg-${index}`;\n\n if (msg.type === \"human\") {\n return <HumanMessage key={msgKey} message={msg} fontSize={chatBodyProps?.fontSize} />;\n }\n\n // Skip standalone tool messages\n if (isToolMessage(msg)) {\n return null;\n }\n\n // Skip if this AI message was already combined with a previous one\n if (msg.type === \"ai\" && index > 0) {\n // Check if previous non-tool message is also an AI message\n let prevIndex = index - 1;\n while (prevIndex >= 0 && isToolMessage(messagesArray[prevIndex])) {\n prevIndex--;\n }\n\n if (prevIndex >= 0 && messagesArray[prevIndex].type === \"ai\") {\n // This is a consecutive AI message, skip it (it will be combined with the previous one)\n return null;\n }\n }\n\n const groupedTimelineMessages: Message[] = [msg];\n let nextIndex = index + 1;\n\n while (nextIndex < messagesArray.length) {\n const nextMsg = messagesArray[nextIndex];\n\n if (isToolMessage(nextMsg)) {\n groupedTimelineMessages.push(nextMsg);\n nextIndex++;\n } else if (nextMsg.type === \"ai\") {\n groupedTimelineMessages.push(nextMsg);\n nextIndex++;\n } else {\n // Stop at human messages or other types\n break;\n }\n }\n\n const groupedAiMessages = groupedTimelineMessages.filter((m) => m.type === \"ai\");\n const toolMessages = groupedTimelineMessages.filter((m) => isToolMessage(m));\n\n // Merge content from all AI messages, preserving r/reasoning blocks\n const hasArrayContent = groupedAiMessages.some((m) => Array.isArray(m.content));\n const mergedContent: Message[\"content\"] = hasArrayContent\n ? groupedAiMessages.flatMap((m) => {\n if (Array.isArray(m.content)) return m.content as any[];\n if (typeof m.content === \"string\" && m.content.length > 0)\n return [{ type: \"text\", text: m.content }];\n return [];\n })\n : groupedAiMessages\n .map((m) => (typeof m.content === \"string\" ? m.content : \"\"))\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n // Extract plain-text portion for legacy checks (tool-call extraction, etc.)\n const combinedContent = hasArrayContent\n ? (mergedContent as any[])\n .map((c: any) => (c.type === \"text\" ? (c.text as string) : \"\"))\n .filter(Boolean)\n .join(\" \")\n : (mergedContent as string);\n\n const toolCallsFromContent = groupedAiMessages\n .flatMap((m) => {\n const calls = getToolCallsFromContent(m.content);\n return calls || [];\n })\n .filter((tc): tc is NonNullable<typeof tc> => tc != null && tc !== undefined);\n\n // Create a combined message object preserving full content (including thinking blocks)\n const combinedMessage = {\n ...msg,\n content: mergedContent,\n };\n\n // Get branch metadata from thread\n const meta = msg ? stream.getMessagesMetadata(msg) : undefined;\n\n // Determine if there is any displayable content (text OR thinking/reasoning blocks)\n const hasThinkingContent = hasArrayContent\n ? (mergedContent as any[]).some(\n (b: any) =>\n (b.type === \"thinking\" && (b.thinking as string)?.length > 0) ||\n (b.type === \"reasoning\" && (b.reasoning as string)?.length > 0),\n )\n : false;\n const hasKwargsReasoning =\n groupedAiMessages.some((m) => {\n const ak = (m as Record<string, unknown>).additional_kwargs as Record<string, unknown> | undefined;\n return typeof ak?.reasoning_content === \"string\" && (ak.reasoning_content as string).length > 0;\n });\n const hasKwargsToolStatus = groupedAiMessages.some((m) => {\n const ak = (m as Record<string, unknown>).additional_kwargs as Record<string, unknown> | undefined;\n return Array.isArray(ak?.tool_status) && (ak.tool_status as unknown[]).length > 0;\n });\n\n const hasToolCalls =\n groupedAiMessages.some((m) => isAiWithToolCalls(m)) ||\n toolCallsFromContent.length > 0 ||\n toolMessages.length > 0 ||\n hasKwargsToolStatus;\n\n const hasAnyDisplayableContent =\n !!combinedContent ||\n hasThinkingContent ||\n hasKwargsReasoning ||\n (enableToolCallIndicator && hasToolCalls);\n\n const isLastMessageGroup = nextIndex >= messagesArray.length;\n const isStreamingThisMessage = isLoading && isLastMessageGroup;\n\n // Show Thinking animation whenever streaming with no displayable content yet (plain chat or tool-call)\n const showThinkingIndicator = isStreamingThisMessage && !hasAnyDisplayableContent;\n\n return (\n <React.Fragment key={msgKey}>\n {/* 1. Thinking indicator - show when streaming with no content yet (no icon shown) */}\n {showThinkingIndicator && (\n <Thinking />\n )}\n {/* 2. Agent message — pass full mergedContent and grouped timeline for in-order rendering */}\n {hasAnyDisplayableContent && (\n <AgentMessage\n agentName={chatBodyProps?.agentName}\n fontSize={chatBodyProps?.fontSize}\n // agentAvatarUrl={chatBodyProps?.agentAvatarUrl}\n message={combinedMessage}\n groupedMessages={groupedTimelineMessages}\n showToolActivity={enableToolCallIndicator}\n isStreaming={isStreamingThisMessage}\n onRegenerate={handleRegenerate}\n feedback={msg.id ? messageFeedback[msg.id] : undefined}\n onFeedback={handleFeedback}\n branch={meta?.branch}\n branchOptions={meta?.branchOptions}\n onBranchSelect={handleBranchSelect}\n />\n )}\n {/* 3. Custom component (from all messages in the group) */}\n {groupedAiMessages.map((m) => (\n <CustomComponentRender key={m.id} message={m} thread={stream} />\n ))}\n </React.Fragment>\n );\n }, [isLoading, stream, enableToolCallIndicator, handleRegenerate, messageFeedback, handleFeedback, handleBranchSelect]);\n\n // Memoize the rendered messages array\n const renderedMessages = useMemo(() => {\n return memoMessages.map((msg, index) => {\n const element = renderMessage(msg, index, memoMessages);\n // Ensure every element has a key, using message id or fallback to index\n if (element && !element.key) {\n return React.cloneElement(element, { key: msg.id ?? `msg-${index}` });\n }\n return element;\n });\n }, [memoMessages, renderMessage]);\n\n // Track user scroll position to determine if we should auto-scroll\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer) return;\n\n const handleScroll = () => {\n const { scrollTop, scrollHeight, clientHeight } = scrollContainer;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n // Consider \"at bottom\" if within 100px\n shouldAutoScrollRef.current = distanceFromBottom < 100;\n };\n\n scrollContainer.addEventListener('scroll', handleScroll);\n return () => scrollContainer.removeEventListener('scroll', handleScroll);\n }, [getScrollContainer]);\n\n // Auto-scroll when new messages are added\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer) return;\n\n const currentCount = memoMessages.length;\n const hasNewMessage = currentCount > prevMessageCountRef.current;\n\n if (hasNewMessage) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n shouldAutoScrollRef.current = true;\n }\n\n prevMessageCountRef.current = currentCount;\n }, [memoMessages, getScrollContainer]);\n\n // Use MutationObserver to detect DOM changes and auto-scroll during streaming\n useEffect(() => {\n const scrollContainer = getScrollContainer();\n if (!scrollContainer || !isLoading) return;\n\n const observer = new MutationObserver(() => {\n if (shouldAutoScrollRef.current && scrollContainer) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n });\n\n // Observe the ChatBody container for changes\n if (containerRef.current) {\n observer.observe(containerRef.current, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n\n return () => observer.disconnect();\n }, [isLoading, getScrollContainer]);\n\n // Use useLayoutEffect to scroll after DOM updates\n useLayoutEffect(() => {\n const scrollContainer = getScrollContainer();\n if (isLoading && shouldAutoScrollRef.current && scrollContainer) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n });\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col gap-4 rounded-4xl p-2\"\n >\n {memoMessages.length === 0 ? (\n <div className=\"flex items-center justify-center h-full text-zinc-500\">\n {isLoading ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"animate-spin h-5 w-5 border-2 border-zinc-500 border-t-transparent rounded-full\" />\n <span>Loading conversation...</span>\n </div>\n ) : (\n \"Start a conversation...\"\n )}\n </div>\n ) : (\n <>\n {renderedMessages}\n {/* Show HITL interrupt card when agent is paused for approval */}\n {!isLoading && stream.interrupt && interruptActions && (() => {\n const payload = stream.interrupt.value as any;\n const toolName = payload?.actionRequests?.[0]?.name;\n const InterruptComponent = toolName ? interruptComponents[toolName] : undefined;\n if (!InterruptComponent) return null;\n return <InterruptComponent interrupt={payload} actions={interruptActions} />;\n })()}\n {/* Show thinking indicator when loading and no AI response has started yet */}\n {isLoading && memoMessages.length > 0 && (() => {\n const lastMsg = memoMessages[memoMessages.length - 1];\n // Show if last message is human or if last AI has no content (only tool calls)\n return lastMsg.type === \"human\" ||\n (lastMsg.type === \"ai\" && !lastMsg.content && isAiWithToolCalls(lastMsg));\n })() && (\n <Thinking />\n )}\n </>\n )}\n\n </div>\n );\n}\n"],"names":["ChatBody","setIsFirstMessage","enableToolCallIndicator","chatBodyProps","stream","useStreamContext","interruptComponents","useCustomComponents","messages","isLoading","messageFeedback","setMessageFeedback","useState","logger","memoMessages","useMemo","containerRef","useRef","prevMessageCountRef","shouldAutoScrollRef","handleFeedback","useCallback","messageId","feedback","prev","handleRegenerate","parentCheckpoint","handleBranchSelect","branch","handleInterruptRespond","response","interruptActions","interrupt","actionRequests","reason","editedArgs","action","getToolCallsFromContent","content","c","tc","args","parsePartialJson","getScrollContainer","parent","style","useEffect","renderMessage","msg","index","messagesArray","isCurrentlyStreamingMessage","isAiWithToolCalls","msgKey","HumanMessage","isToolMessage","prevIndex","groupedTimelineMessages","nextIndex","nextMsg","groupedAiMessages","m","toolMessages","hasArrayContent","mergedContent","combinedContent","toolCallsFromContent","combinedMessage","meta","hasThinkingContent","b","hasKwargsReasoning","ak","hasKwargsToolStatus","hasToolCalls","hasAnyDisplayableContent","isLastMessageGroup","isStreamingThisMessage","showThinkingIndicator","jsxs","React","Thinking","jsx","AgentMessage","CustomComponentRender","renderedMessages","element","scrollContainer","handleScroll","scrollTop","scrollHeight","clientHeight","distanceFromBottom","currentCount","observer","useLayoutEffect","Fragment","payload","toolName","InterruptComponent","lastMsg"],"mappings":"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"}
@@ -1,2 +1,4 @@
1
- "use strict";const e=require("react/jsx-runtime"),p=require("../../utils/tailwindUtil.cjs.js"),w=require("../../utils/utils.cjs.js"),d=require("lucide-react"),f=require("react"),m=require("../ui/AgentMarkdown.cjs.js"),A=require("./BranchSwitcher.cjs.js"),b=require("./MessageActions.cjs.js");function q(n){if(!n)return null;const t=n.additional_kwargs;return t&&typeof t.reasoning_content=="string"&&t.reasoning_content.length>0?t.reasoning_content:null}function j({text:n,isStreaming:t,fontSize:a}){const[s,c]=f.useState(!1);return f.useEffect(()=>{c(!!t)},[t]),e.jsxs("div",{className:"my-1",children:[e.jsxs("button",{type:"button",onClick:()=>c(g=>!g),className:"inline-flex items-center gap-1.5 text-xs text-zinc-400/80 transition-colors hover:text-zinc-300",children:[t?e.jsx(d.LoaderCircle,{className:"size-3 animate-spin"}):e.jsx(d.Sparkles,{className:"size-3"}),e.jsx("span",{children:t?"Thinking":"Thought"}),e.jsx(d.ChevronRight,{className:p.cn("size-3 transition-transform duration-200",s&&"rotate-90")})]}),s&&e.jsx("div",{className:"mt-1.5 border-l-2 border-white/10 pl-4 text-sm text-zinc-300",children:e.jsx(m.AgentMarkdown,{fontSize:a,children:n})})]})}function M(n,t,a){if(!n)return null;const s=n.content,c=[],g=q(n);if(g){const r=typeof s=="string"?s.length>0:Array.isArray(s)&&s.some(i=>i.type==="text"&&typeof i.text=="string"&&i.text.length>0);c.push(e.jsx(j,{text:g,isStreaming:t&&!r,fontSize:a},"kwargs-reasoning"))}if(typeof s=="string")return s.length>0&&c.push(e.jsx("div",{className:"py-1",children:e.jsx(m.AgentMarkdown,{fontSize:a,children:s})},"text-content")),c.length>0?e.jsx(e.Fragment,{children:c}):null;if(!Array.isArray(s))return null;const x=s;let o="",l=0;const h=()=>{o.length>0&&(c.push(e.jsx("div",{className:"py-1",children:e.jsx(m.AgentMarkdown,{fontSize:a,children:o})},`text-${l}`)),o="",l++)};for(let r=0;r<x.length;r++){const i=x[r];if(i.type==="text"&&typeof i.text=="string")o+=i.text;else if(i.type==="reasoning"&&typeof i.reasoning=="string"||i.type==="thinking"&&typeof i.thinking=="string"){h();const k=i.reasoning??i.thinking,y=x.slice(r+1).some(u=>u.type==="text"&&typeof u.text=="string"&&u.text.length>0),N=t&&!y;c.push(e.jsx(j,{text:k,isStreaming:N,fontSize:a},`thinking-${l}`)),l++}}return h(),c.length>0?e.jsx(e.Fragment,{children:c}):null}function R({agentName:n,fontSize:t,message:a,isStreaming:s=!1,onRegenerate:c,feedback:g,onFeedback:x,branch:o,branchOptions:l,onBranchSelect:h}){const r=w.getContentString(a?.content),i=M(a,s,t);return e.jsxs("div",{className:"agent-message flex flex-col gap-1 w-full group",children:[e.jsxs("div",{className:"flex items-center gap-3 w-full",children:[e.jsx("div",{className:"rounded-full size-8 shrink-0 bg-zinc-800 flex items-center justify-center p-2","data-alt":"AI Avatar",children:e.jsx(d.BotMessageSquare,{className:"text-xs",color:"white"})}),e.jsx("span",{className:"text-zinc-500 text-sm",children:n||"Agent"})]}),e.jsxs("div",{className:"flex flex-1 flex-col gap-1 items-start min-w-0",children:[e.jsx("div",{className:"text-content text-foreground",style:t?{fontSize:t}:void 0,children:i||e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex items-center gap-2 text-zinc-500",children:e.jsx("span",{children:"Thinking..."})}),s&&r&&e.jsx("span",{className:"inline-block w-2 h-4 ml-1 bg-zinc-400 animate-pulse"})]})}),!s&&o&&l&&h&&l.length>1&&e.jsx(A.BranchSwitcher,{branch:o,branchOptions:l,onSelect:h,isLoading:s}),!s&&r&&e.jsx(b.MessageActions,{message:a,onRegenerate:c,feedback:g,onFeedback:x,className:""})]})]})}const T=f.memo(R,(n,t)=>t.isStreaming?!1:n.message.id===t.message.id&&n.isStreaming===t.isStreaming&&n.feedback===t.feedback&&n.onRegenerate===t.onRegenerate&&n.onFeedback===t.onFeedback&&n.branch===t.branch&&n.branchOptions?.length===t.branchOptions?.length&&n.onBranchSelect===t.onBranchSelect);module.exports=T;
1
+ "use strict";const n=require("react/jsx-runtime"),L=require("../../utils/tailwindUtil.cjs.js"),E=require("../../utils/utils.cjs.js"),j=require("lucide-react"),C=require("react"),R=require("../ui/AgentMarkdown.cjs.js"),O=require("./BranchSwitcher.cjs.js"),J=require("./MessageActions.cjs.js");function U(t){if(!t)return null;const e=t.additional_kwargs;return e&&typeof e.reasoning_content=="string"&&e.reasoning_content.length>0?e.reasoning_content:null}function W({reasoningText:t,toolStatuses:e,isStreaming:s,fontSize:m}){const[g,a]=C.useState(!1);C.useEffect(()=>{a(!!s)},[s]);const x=e&&e.length>0,y=!!t&&t.length>0;return!x&&!y&&!s?null:n.jsxs("div",{className:"my-1",children:[n.jsxs("button",{type:"button",onClick:()=>a(d=>!d),className:"inline-flex items-center gap-1.5 text-xs text-zinc-400/80 transition-colors hover:text-zinc-300",children:[s?n.jsx(j.LoaderCircle,{className:"size-3 animate-spin"}):n.jsx(j.Sparkles,{className:"size-3"}),n.jsx("span",{children:s?"Thinking":"Thought"}),n.jsx(j.ChevronRight,{className:L.cn("size-3 transition-transform duration-200",g&&"rotate-90")})]}),g&&n.jsxs("div",{className:"mt-1.5 border-l-2 border-white/10 pl-4 space-y-1",children:[x&&e.map(d=>n.jsxs("div",{className:"flex items-center gap-2 text-sm text-zinc-300 py-0.5",children:[!d.isCompleted&&n.jsx(j.LoaderCircle,{className:"size-3.5 animate-spin text-zinc-400"}),n.jsx(j.Wrench,{className:"size-3.5 text-zinc-500"}),n.jsx("span",{children:d.label})]},d.key)),y&&n.jsx("div",{className:"text-sm text-zinc-300",children:n.jsx(R.AgentMarkdown,{fontSize:m,children:t})})]})]})}function D(t){if(!t||typeof t!="object")return null;const e=t,s=typeof e.visible=="boolean"?e.visible:typeof e.show=="boolean"?e.show:typeof e.display=="boolean"?e.display:typeof e.hidden=="boolean"?!e.hidden:!0;return{id:typeof e.id=="string"?e.id:void 0,name:typeof e.name=="string"?e.name:void 0,label:typeof e.label=="string"?e.label:void 0,event:typeof e.event=="string"?e.event:void 0,visible:s}}function G(t){if(!t)return[];const e=t.additional_kwargs;return!e||!Array.isArray(e.tool_status)?[]:e.tool_status.map(D).filter(s=>s!==null)}function H(t){if(!t)return!1;const e=t.additional_kwargs;return e?Object.prototype.hasOwnProperty.call(e,"tool_status"):!1}function T(t){return t?t.toLowerCase().replace(/\s+/g," ").replace(/\s*event:\s*metadata\s*$/i,"").trim():""}function Q(t){return!(t.visible===!1||T(t.label).length===0||t.event?.toLowerCase()==="metadata"||/\bevent:\s*metadata\b/i.test(t.label??""))}function V(t,e){if(!e)return t;if(typeof e=="string"){const s=e.trim();return s.length===0?t:`${t} ${s.slice(0,80)}${s.length>80?"...":""}`}if(typeof e=="object")try{const s=JSON.stringify(e);return`${t} ${s.length>80?`${s.slice(0,80)}...`:s}`}catch{return t}return t}function X(t,e,s,m){if(!t||t.length===0)return null;const g=t,a=g.filter(i=>i.type==="tool"),x=g.some(i=>H(i)),y=new Set(a.map(i=>i.tool_call_id).filter(i=>typeof i=="string"&&i.length>0)),d=new Set(a.map(i=>i.name).filter(i=>typeof i=="string"&&i.length>0)),f=[],u=[],h=[],p=new Set;let c=0;const q=i=>{if(e)for(const o of G(i)){if(!Q(o))continue;const r=T(o.label)||T(o.name)||"tool";if(p.has(r))continue;p.add(r);const w=o.label??o.name??"Running tool",b=(o.id?y.has(o.id):!1)||(o.name?d.has(o.name):!1)||!s;f.push({key:r,label:w,isCompleted:b})}};for(const i of g){if(i.type!=="ai")continue;const o=i.content,r=U(i);if(q(i),typeof o=="string"){r?u.push(r):o.length>0&&(h.push(n.jsx("div",{className:"py-1",children:n.jsx(R.AgentMarkdown,{fontSize:m,children:o})},`text-content-${i.id??c}`)),c++);continue}if(!Array.isArray(o)){r&&u.push(r);continue}const w=o;let b="",M=!1;const z=()=>{b.length>0&&(h.push(n.jsx("div",{className:"py-1",children:n.jsx(R.AgentMarkdown,{fontSize:m,children:b})},`text-${i.id??c}-${c}`)),b="",c++)};for(let N=0;N<w.length;N++){const l=w[N];if(l.type==="text"&&typeof l.text=="string"){b+=l.text;continue}if(l.type==="reasoning"&&typeof l.reasoning=="string"||l.type==="thinking"&&typeof l.thinking=="string"){z(),M=!0;const v=l.reasoning??l.thinking;u.push(v);continue}if(e&&!x&&l.type==="tool_use"){z();const v=typeof l.id=="string"?l.id:void 0,K=typeof l.name=="string"?l.name:"tool",A=T(K)||`tool-${N}`;if(!p.has(A)){p.add(A);const I=V(K,l.input),B=v?y.has(v):!s;f.push({key:A,label:I,isCompleted:B})}}}!M&&r?(b="",u.push(r)):z()}if(e&&!s&&!x&&f.length===0&&h.length===0&&a.length>0)for(const i of a)f.push({key:`tool-msg-${i.id??c}`,label:"Tool call completed",isCompleted:!0}),c++;const k=[],S=h.length>0,$=u.join(`
2
+
3
+ `),F=e&&f.length>0||$.length>0,_=!!s&&!S;return(F||_)&&k.push(n.jsx(W,{reasoningText:$||void 0,toolStatuses:e?f:void 0,isStreaming:_,fontSize:m},"agent-activity")),k.push(...h),k.length>0?n.jsx(n.Fragment,{children:k}):null}function Y({agentName:t,fontSize:e,message:s,groupedMessages:m,showToolActivity:g=!0,isStreaming:a=!1,onRegenerate:x,feedback:y,onFeedback:d,branch:f,branchOptions:u,onBranchSelect:h}){const p=E.getContentString(s?.content),c=X(m??[s],g,a,e);return n.jsxs("div",{className:"agent-message flex flex-col gap-1 w-full group",children:[n.jsxs("div",{className:"flex items-center gap-3 w-full",children:[n.jsx("div",{className:"rounded-full size-8 shrink-0 bg-zinc-800 flex items-center justify-center p-2","data-alt":"AI Avatar",children:n.jsx(j.BotMessageSquare,{className:"text-xs",color:"white"})}),n.jsx("span",{className:"text-zinc-500 text-sm",children:t||"Agent"})]}),n.jsxs("div",{className:"flex flex-1 flex-col gap-1 items-start min-w-0",children:[n.jsx("div",{className:"text-content text-foreground",style:e?{fontSize:e}:void 0,children:c||n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"flex items-center gap-2 text-zinc-500",children:n.jsx("span",{children:"Thinking..."})}),a&&p&&n.jsx("span",{className:"inline-block w-2 h-4 ml-1 bg-zinc-400 animate-pulse"})]})}),!a&&f&&u&&h&&u.length>1&&n.jsx(O.BranchSwitcher,{branch:f,branchOptions:u,onSelect:h,isLoading:a}),!a&&p&&n.jsx(J.MessageActions,{message:s,onRegenerate:x,feedback:y,onFeedback:d,className:""})]})]})}const Z=C.memo(Y,(t,e)=>e.isStreaming?!1:t.message.id===e.message.id&&t.groupedMessages?.length===e.groupedMessages?.length&&t.showToolActivity===e.showToolActivity&&t.isStreaming===e.isStreaming&&t.feedback===e.feedback&&t.onRegenerate===e.onRegenerate&&t.onFeedback===e.onFeedback&&t.branch===e.branch&&t.branchOptions?.length===e.branchOptions?.length&&t.onBranchSelect===e.onBranchSelect);module.exports=Z;
2
4
  //# sourceMappingURL=AgentMessage.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentMessage.cjs.js","sources":["../../../src/components/messages/AgentMessage.tsx"],"sourcesContent":["import { cn } from \"@/utils/tailwindUtil\";\nimport { getContentString } from \"@/utils/utils\";\nimport type { Message } from \"@langchain/langgraph-sdk\";\nimport { BotMessageSquare, ChevronRight, LoaderCircle, Sparkles } from \"lucide-react\";\nimport React, { useEffect, useState } from \"react\";\nimport { AgentMarkdown } from \"../ui/AgentMarkdown\";\nimport { BranchSwitcher } from \"./BranchSwitcher\";\nimport { MessageActions, type MessageFeedback } from \"./MessageActions\";\n\nfunction getReasoningFromKwargs(message: Message | undefined): string | null {\n if (!message) return null;\n const ak = (message as Record<string, unknown>).additional_kwargs as\n | Record<string, unknown>\n | undefined;\n if (\n ak &&\n typeof ak.reasoning_content === \"string\" &&\n ak.reasoning_content.length > 0\n ) {\n return ak.reasoning_content;\n }\n return null;\n}\n\nfunction InlineThinking({\n text,\n isStreaming,\n fontSize,\n}: {\n text: string;\n isStreaming?: boolean;\n fontSize?: string;\n}) {\n const [expanded, setExpanded] = useState(false);\n\n useEffect(() => {\n setExpanded(!!isStreaming);\n }, [isStreaming]);\n\n return (\n <div className=\"my-1\">\n <button\n type=\"button\"\n onClick={() => setExpanded((p) => !p)}\n className=\"inline-flex items-center gap-1.5 text-xs text-zinc-400/80 transition-colors hover:text-zinc-300\"\n >\n {isStreaming ? (\n <LoaderCircle className=\"size-3 animate-spin\" />\n ) : (\n <Sparkles className=\"size-3\" />\n )}\n <span>{isStreaming ? \"Thinking\" : \"Thought\"}</span>\n <ChevronRight\n className={cn(\n \"size-3 transition-transform duration-200\",\n expanded && \"rotate-90\",\n )}\n />\n </button>\n {expanded && (\n <div className=\"mt-1.5 border-l-2 border-white/10 pl-4 text-sm text-zinc-300\">\n <AgentMarkdown fontSize={fontSize}>{text}</AgentMarkdown>\n </div>\n )}\n </div>\n );\n}\n\nfunction renderContentInline(\n message: Message | undefined,\n isActivelyStreaming?: boolean,\n fontSize?: string,\n) {\n if (!message) return null;\n const content = message.content;\n const parts: React.ReactNode[] = [];\n\n const kwargsReasoning = getReasoningFromKwargs(message);\n if (kwargsReasoning) {\n const hasTextContent =\n typeof content === \"string\"\n ? content.length > 0\n : Array.isArray(content) &&\n (content as Record<string, unknown>[]).some(\n (block) =>\n block.type === \"text\" &&\n typeof block.text === \"string\" &&\n (block.text as string).length > 0,\n );\n\n parts.push(\n <InlineThinking\n key=\"kwargs-reasoning\"\n text={kwargsReasoning}\n isStreaming={isActivelyStreaming && !hasTextContent}\n fontSize={fontSize}\n />,\n );\n }\n\n if (typeof content === \"string\") {\n if (content.length > 0) {\n parts.push(\n <div key=\"text-content\" className=\"py-1\">\n <AgentMarkdown fontSize={fontSize}>{content}</AgentMarkdown>\n </div>,\n );\n }\n return parts.length > 0 ? <>{parts}</> : null;\n }\n\n if (!Array.isArray(content)) return null;\n\n const blocks = content as Record<string, unknown>[];\n let textAccum = \"\";\n let idx = 0;\n\n const flushText = () => {\n if (textAccum.length > 0) {\n parts.push(\n <div key={`text-${idx}`} className=\"py-1\">\n <AgentMarkdown fontSize={fontSize}>{textAccum}</AgentMarkdown>\n </div>,\n );\n textAccum = \"\";\n idx++;\n }\n };\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n if (block.type === \"text\" && typeof block.text === \"string\") {\n textAccum += block.text;\n } else if (\n (block.type === \"reasoning\" && typeof block.reasoning === \"string\") ||\n (block.type === \"thinking\" && typeof block.thinking === \"string\")\n ) {\n flushText();\n const text = (block.reasoning ?? block.thinking) as string;\n const hasTextAfter = blocks.slice(i + 1).some(\n (b) =>\n b.type === \"text\" &&\n typeof b.text === \"string\" &&\n (b.text as string).length > 0,\n );\n const isThisBlockStreaming = isActivelyStreaming && !hasTextAfter;\n parts.push(\n <InlineThinking\n key={`thinking-${idx}`}\n text={text}\n isStreaming={isThisBlockStreaming}\n fontSize={fontSize}\n />,\n );\n idx++;\n }\n }\n\n flushText();\n return parts.length > 0 ? <>{parts}</> : null;\n}\n\nfunction AgentMessage({\n agentName,\n fontSize,\n message,\n isStreaming = false,\n onRegenerate,\n feedback,\n onFeedback,\n branch,\n branchOptions,\n onBranchSelect,\n}: {\n agentName?: string;\n fontSize?: string;\n message: Message;\n isStreaming?: boolean;\n onRegenerate?: (parentCheckpoint: any | null | undefined, messageId: string, currentMessage: any) => void;\n feedback?: MessageFeedback;\n onFeedback?: (messageId: string, feedback: MessageFeedback) => void;\n branch?: string;\n branchOptions?: string[];\n onBranchSelect?: (branch: string) => void;\n}) {\n const content = getContentString(message?.content);\n const inlineContent = renderContentInline(message, isStreaming, fontSize);\n\n return (\n <div className=\"agent-message flex flex-col gap-1 w-full group\">\n <div className=\"flex items-center gap-3 w-full\">\n <div\n className=\"rounded-full size-8 shrink-0 bg-zinc-800 flex items-center justify-center p-2\"\n data-alt=\"AI Avatar\"\n >\n <BotMessageSquare className=\"text-xs\" color=\"white\" />\n </div>\n <span className=\"text-zinc-500 text-sm\">{agentName || \"Agent\"}</span>\n </div>\n <div className=\"flex flex-1 flex-col gap-1 items-start min-w-0\">\n <div className=\"text-content text-foreground\" style={fontSize ? { fontSize } : undefined}>\n {inlineContent ? (\n inlineContent\n ) : (\n <>\n <div className=\"flex items-center gap-2 text-zinc-500\">\n {/* <Loader2 className=\"animate-spin\" size={16} /> */}\n <span>Thinking...</span>\n </div>\n {isStreaming && content && (\n <span className=\"inline-block w-2 h-4 ml-1 bg-zinc-400 animate-pulse\" />\n )}\n </>\n )}\n </div>\n\n {/* Branch switcher - show when multiple branches exist */}\n {!isStreaming && branch && branchOptions && onBranchSelect && branchOptions.length > 1 && (\n <BranchSwitcher\n branch={branch}\n branchOptions={branchOptions}\n onSelect={onBranchSelect}\n isLoading={isStreaming}\n />\n )}\n\n {/* Show actions only when not streaming and content exists */}\n {!isStreaming && content && (\n <MessageActions\n message={message}\n onRegenerate={onRegenerate}\n feedback={feedback}\n onFeedback={onFeedback}\n className=\"\"\n />\n )}\n </div>\n </div>\n );\n}\n\n// Memoize - only re-render if message ID changes or streaming state changes\nexport default React.memo(AgentMessage, (prevProps, nextProps) => {\n // If it's streaming, we need to re-render to show updates\n if (nextProps.isStreaming) {\n return false; // Always re-render when streaming\n }\n\n // Otherwise, only re-render if the message ID, feedback, branch, or callbacks changed\n return (\n prevProps.message.id === nextProps.message.id &&\n prevProps.isStreaming === nextProps.isStreaming &&\n prevProps.feedback === nextProps.feedback &&\n prevProps.onRegenerate === nextProps.onRegenerate &&\n prevProps.onFeedback === nextProps.onFeedback &&\n prevProps.branch === nextProps.branch &&\n prevProps.branchOptions?.length === nextProps.branchOptions?.length &&\n prevProps.onBranchSelect === nextProps.onBranchSelect\n );\n});\n"],"names":["getReasoningFromKwargs","message","ak","InlineThinking","text","isStreaming","fontSize","expanded","setExpanded","useState","useEffect","jsxs","p","jsx","LoaderCircle","Sparkles","ChevronRight","cn","AgentMarkdown","renderContentInline","isActivelyStreaming","content","parts","kwargsReasoning","hasTextContent","block","Fragment","blocks","textAccum","idx","flushText","i","hasTextAfter","b","isThisBlockStreaming","AgentMessage","agentName","onRegenerate","feedback","onFeedback","branch","branchOptions","onBranchSelect","getContentString","inlineContent","BotMessageSquare","BranchSwitcher","MessageActions","React","prevProps","nextProps"],"mappings":"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"}
1
+ {"version":3,"file":"AgentMessage.cjs.js","sources":["../../../src/components/messages/AgentMessage.tsx"],"sourcesContent":["import { cn } from \"@/utils/tailwindUtil\";\nimport { getContentString } from \"@/utils/utils\";\nimport type { Message } from \"@langchain/langgraph-sdk\";\nimport { BotMessageSquare, ChevronRight, LoaderCircle, Sparkles, Wrench } from \"lucide-react\";\nimport React, { useEffect, useState } from \"react\";\nimport { AgentMarkdown } from \"../ui/AgentMarkdown\";\nimport { BranchSwitcher } from \"./BranchSwitcher\";\nimport { MessageActions, type MessageFeedback } from \"./MessageActions\";\n\ntype ToolStatusEntry = {\n id?: string;\n name?: string;\n label?: string;\n event?: string;\n visible?: boolean;\n};\n\nfunction getReasoningFromKwargs(message: Message | undefined): string | null {\n if (!message) return null;\n const ak = (message as Record<string, unknown>).additional_kwargs as\n | Record<string, unknown>\n | undefined;\n if (\n ak &&\n typeof ak.reasoning_content === \"string\" &&\n ak.reasoning_content.length > 0\n ) {\n return ak.reasoning_content;\n }\n return null;\n}\n\nfunction AgentActivity({\n reasoningText,\n toolStatuses,\n isStreaming,\n fontSize,\n}: {\n reasoningText?: string;\n toolStatuses?: Array<{ key: string; label: string; isCompleted: boolean }>;\n isStreaming?: boolean;\n fontSize?: string;\n}) {\n const [expanded, setExpanded] = useState(false);\n\n useEffect(() => {\n setExpanded(!!isStreaming);\n }, [isStreaming]);\n\n const hasTools = toolStatuses && toolStatuses.length > 0;\n const hasReasoning = !!reasoningText && reasoningText.length > 0;\n\n if (!hasTools && !hasReasoning && !isStreaming) return null;\n\n return (\n <div className=\"my-1\">\n <button\n type=\"button\"\n onClick={() => setExpanded((p) => !p)}\n className=\"inline-flex items-center gap-1.5 text-xs text-zinc-400/80 transition-colors hover:text-zinc-300\"\n >\n {isStreaming ? (\n <LoaderCircle className=\"size-3 animate-spin\" />\n ) : (\n <Sparkles className=\"size-3\" />\n )}\n <span>{isStreaming ? \"Thinking\" : \"Thought\"}</span>\n <ChevronRight\n className={cn(\n \"size-3 transition-transform duration-200\",\n expanded && \"rotate-90\",\n )}\n />\n </button>\n {expanded && (\n <div className=\"mt-1.5 border-l-2 border-white/10 pl-4 space-y-1\">\n {hasTools && toolStatuses!.map((ts) => (\n <div key={ts.key} className=\"flex items-center gap-2 text-sm text-zinc-300 py-0.5\">\n {!ts.isCompleted && (\n <LoaderCircle className=\"size-3.5 animate-spin text-zinc-400\" />\n )}\n <Wrench className=\"size-3.5 text-zinc-500\" />\n <span>{ts.label}</span>\n </div>\n ))}\n {hasReasoning && (\n <div className=\"text-sm text-zinc-300\">\n <AgentMarkdown fontSize={fontSize}>{reasoningText!}</AgentMarkdown>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction toToolStatusEntry(value: unknown): ToolStatusEntry | null {\n if (!value || typeof value !== \"object\") return null;\n const v = value as Record<string, unknown>;\n\n const visible =\n typeof v.visible === \"boolean\"\n ? v.visible\n : typeof v.show === \"boolean\"\n ? v.show\n : typeof v.display === \"boolean\"\n ? v.display\n : typeof v.hidden === \"boolean\"\n ? !v.hidden\n : true;\n\n return {\n id: typeof v.id === \"string\" ? v.id : undefined,\n name: typeof v.name === \"string\" ? v.name : undefined,\n label: typeof v.label === \"string\" ? v.label : undefined,\n event: typeof v.event === \"string\" ? v.event : undefined,\n visible,\n };\n}\n\nfunction getToolStatusFromKwargs(message: Message | undefined): ToolStatusEntry[] {\n if (!message) return [];\n const ak = (message as Record<string, unknown>).additional_kwargs as\n | Record<string, unknown>\n | undefined;\n\n if (!ak || !Array.isArray(ak.tool_status)) return [];\n\n return (ak.tool_status as unknown[])\n .map(toToolStatusEntry)\n .filter((s): s is ToolStatusEntry => s !== null);\n}\n\nfunction hasToolStatusFieldInKwargs(message: Message | undefined): boolean {\n if (!message) return false;\n const ak = (message as Record<string, unknown>).additional_kwargs as\n | Record<string, unknown>\n | undefined;\n if (!ak) return false;\n return Object.prototype.hasOwnProperty.call(ak, \"tool_status\");\n}\n\nfunction normalizeSemanticKey(value: string | undefined): string {\n if (!value) return \"\";\n return value\n .toLowerCase()\n .replace(/\\s+/g, \" \")\n .replace(/\\s*event:\\s*metadata\\s*$/i, \"\")\n .trim();\n}\n\nfunction shouldRenderToolStatus(status: ToolStatusEntry): boolean {\n if (status.visible === false) return false;\n\n const labelKey = normalizeSemanticKey(status.label);\n if (labelKey.length === 0) return false;\n\n // Filter transport/debug noise like \"event: metadata\".\n if (status.event?.toLowerCase() === \"metadata\") return false;\n if (/\\bevent:\\s*metadata\\b/i.test(status.label ?? \"\")) return false;\n\n return true;\n}\n\nfunction normalizeToolLabel(name: string, input: unknown): string {\n if (!input) return name;\n if (typeof input === \"string\") {\n const trimmed = input.trim();\n if (trimmed.length === 0) return name;\n return `${name} ${trimmed.slice(0, 80)}${trimmed.length > 80 ? \"...\" : \"\"}`;\n }\n if (typeof input === \"object\") {\n try {\n const json = JSON.stringify(input);\n return `${name} ${json.length > 80 ? `${json.slice(0, 80)}...` : json}`;\n } catch {\n return name;\n }\n }\n return name;\n}\n\nfunction renderContentInline(\n groupedMessages: Message[] | undefined,\n showToolActivity: boolean,\n isActivelyStreaming?: boolean,\n fontSize?: string,\n) {\n if (!groupedMessages || groupedMessages.length === 0) return null;\n\n const timeline = groupedMessages;\n const toolMessages = timeline.filter((m) => m.type === \"tool\");\n const hasBackendToolStatus = timeline.some((m) => hasToolStatusFieldInKwargs(m));\n\n const completedToolIds = new Set(\n toolMessages\n .map((m) => (m as Record<string, unknown>).tool_call_id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0),\n );\n const completedToolNames = new Set(\n toolMessages\n .map((m) => (m as Record<string, unknown>).name)\n .filter((name): name is string => typeof name === \"string\" && name.length > 0),\n );\n\n // ── Collect activity (reasoning + tool statuses) and text content separately ──\n const collectedToolStatuses: Array<{ key: string; label: string; isCompleted: boolean }> = [];\n const reasoningTexts: string[] = [];\n const textParts: React.ReactNode[] = [];\n const renderedToolKeys = new Set<string>();\n let textIdx = 0;\n\n const collectToolStatusFromKwargs = (message: Message) => {\n if (!showToolActivity) return;\n for (const status of getToolStatusFromKwargs(message)) {\n if (!shouldRenderToolStatus(status)) continue;\n const semanticKey =\n normalizeSemanticKey(status.label) || normalizeSemanticKey(status.name) || \"tool\";\n if (renderedToolKeys.has(semanticKey)) continue;\n renderedToolKeys.add(semanticKey);\n const label = status.label ?? status.name ?? \"Running tool\";\n const isCompleted =\n (status.id ? completedToolIds.has(status.id) : false) ||\n (status.name ? completedToolNames.has(status.name) : false) ||\n !isActivelyStreaming;\n collectedToolStatuses.push({ key: semanticKey, label, isCompleted });\n }\n };\n\n for (const message of timeline) {\n if (message.type !== \"ai\") continue;\n\n const content = message.content;\n const kwargsReasoning = getReasoningFromKwargs(message);\n\n // Collect tool statuses from kwargs\n collectToolStatusFromKwargs(message);\n\n if (typeof content === \"string\") {\n if (kwargsReasoning) {\n // When reasoning_content exists in kwargs, the string content is the\n // same thinking text (set by messages-tuple before wrapModelCall clears\n // it). Capture it only as reasoning to avoid duplication.\n reasoningTexts.push(kwargsReasoning);\n } else if (content.length > 0) {\n textParts.push(\n <div key={`text-content-${message.id ?? textIdx}`} className=\"py-1\">\n <AgentMarkdown fontSize={fontSize}>{content}</AgentMarkdown>\n </div>,\n );\n textIdx++;\n }\n continue;\n }\n\n if (!Array.isArray(content)) {\n if (kwargsReasoning) reasoningTexts.push(kwargsReasoning);\n continue;\n }\n\n const blocks = content as Record<string, unknown>[];\n let textAccum = \"\";\n let hasReasoningBlock = false;\n\n const flushText = () => {\n if (textAccum.length > 0) {\n textParts.push(\n <div key={`text-${message.id ?? textIdx}-${textIdx}`} className=\"py-1\">\n <AgentMarkdown fontSize={fontSize}>{textAccum}</AgentMarkdown>\n </div>,\n );\n textAccum = \"\";\n textIdx++;\n }\n };\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n if (block.type === \"text\" && typeof block.text === \"string\") {\n textAccum += block.text;\n continue;\n }\n\n if (\n (block.type === \"reasoning\" && typeof block.reasoning === \"string\") ||\n (block.type === \"thinking\" && typeof block.thinking === \"string\")\n ) {\n flushText();\n hasReasoningBlock = true;\n const text = (block.reasoning ?? block.thinking) as string;\n reasoningTexts.push(text);\n continue;\n }\n\n if (showToolActivity && !hasBackendToolStatus && block.type === \"tool_use\") {\n flushText();\n const toolId = typeof block.id === \"string\" ? block.id : undefined;\n const toolName = typeof block.name === \"string\" ? block.name : \"tool\";\n const semanticKey = normalizeSemanticKey(toolName) || `tool-${i}`;\n if (!renderedToolKeys.has(semanticKey)) {\n renderedToolKeys.add(semanticKey);\n const label = normalizeToolLabel(toolName, (block as Record<string, unknown>).input);\n const isCompleted = toolId ? completedToolIds.has(toolId) : !isActivelyStreaming;\n collectedToolStatuses.push({ key: semanticKey, label, isCompleted });\n }\n }\n }\n\n if (!hasReasoningBlock && kwargsReasoning) {\n // Same as the string-content case: kwargs reasoning duplicates the\n // text blocks, so discard accumulated text and capture as reasoning only.\n textAccum = \"\";\n reasoningTexts.push(kwargsReasoning);\n } else {\n flushText();\n }\n }\n\n // Fallback for legacy payloads without backend tool_status (only after streaming completes)\n if (showToolActivity && !isActivelyStreaming && !hasBackendToolStatus && collectedToolStatuses.length === 0 && textParts.length === 0 && toolMessages.length > 0) {\n for (const toolMessage of toolMessages) {\n collectedToolStatuses.push({\n key: `tool-msg-${toolMessage.id ?? textIdx}`,\n label: \"Tool call completed\",\n isCompleted: true,\n });\n textIdx++;\n }\n }\n\n // ── Assemble output: AgentActivity block first, then text content ──\n const parts: React.ReactNode[] = [];\n const hasTextContent = textParts.length > 0;\n const combinedReasoning = reasoningTexts.join(\"\\n\\n\");\n const hasActivity =\n (showToolActivity && collectedToolStatuses.length > 0) ||\n combinedReasoning.length > 0;\n const activityIsStreaming = !!isActivelyStreaming && !hasTextContent;\n\n if (hasActivity || activityIsStreaming) {\n parts.push(\n <AgentActivity\n key=\"agent-activity\"\n reasoningText={combinedReasoning || undefined}\n toolStatuses={showToolActivity ? collectedToolStatuses : undefined}\n isStreaming={activityIsStreaming}\n fontSize={fontSize}\n />,\n );\n }\n\n parts.push(...textParts);\n\n return parts.length > 0 ? <>{parts}</> : null;\n}\n\nfunction AgentMessage({\n agentName,\n fontSize,\n message,\n groupedMessages,\n showToolActivity = true,\n isStreaming = false,\n onRegenerate,\n feedback,\n onFeedback,\n branch,\n branchOptions,\n onBranchSelect,\n}: {\n agentName?: string;\n fontSize?: string;\n message: Message;\n groupedMessages?: Message[];\n showToolActivity?: boolean;\n isStreaming?: boolean;\n onRegenerate?: (parentCheckpoint: any | null | undefined, messageId: string, currentMessage: any) => void;\n feedback?: MessageFeedback;\n onFeedback?: (messageId: string, feedback: MessageFeedback) => void;\n branch?: string;\n branchOptions?: string[];\n onBranchSelect?: (branch: string) => void;\n}) {\n const content = getContentString(message?.content);\n const inlineContent = renderContentInline(groupedMessages ?? [message], showToolActivity, isStreaming, fontSize);\n\n return (\n <div className=\"agent-message flex flex-col gap-1 w-full group\">\n <div className=\"flex items-center gap-3 w-full\">\n <div\n className=\"rounded-full size-8 shrink-0 bg-zinc-800 flex items-center justify-center p-2\"\n data-alt=\"AI Avatar\"\n >\n <BotMessageSquare className=\"text-xs\" color=\"white\" />\n </div>\n <span className=\"text-zinc-500 text-sm\">{agentName || \"Agent\"}</span>\n </div>\n <div className=\"flex flex-1 flex-col gap-1 items-start min-w-0\">\n <div className=\"text-content text-foreground\" style={fontSize ? { fontSize } : undefined}>\n {inlineContent ? (\n inlineContent\n ) : (\n <>\n <div className=\"flex items-center gap-2 text-zinc-500\">\n {/* <Loader2 className=\"animate-spin\" size={16} /> */}\n <span>Thinking...</span>\n </div>\n {isStreaming && content && (\n <span className=\"inline-block w-2 h-4 ml-1 bg-zinc-400 animate-pulse\" />\n )}\n </>\n )}\n </div>\n\n {/* Branch switcher - show when multiple branches exist */}\n {!isStreaming && branch && branchOptions && onBranchSelect && branchOptions.length > 1 && (\n <BranchSwitcher\n branch={branch}\n branchOptions={branchOptions}\n onSelect={onBranchSelect}\n isLoading={isStreaming}\n />\n )}\n\n {/* Show actions only when not streaming and content exists */}\n {!isStreaming && content && (\n <MessageActions\n message={message}\n onRegenerate={onRegenerate}\n feedback={feedback}\n onFeedback={onFeedback}\n className=\"\"\n />\n )}\n </div>\n </div>\n );\n}\n\n// Memoize - only re-render if message ID changes or streaming state changes\nexport default React.memo(AgentMessage, (prevProps, nextProps) => {\n // If it's streaming, we need to re-render to show updates\n if (nextProps.isStreaming) {\n return false; // Always re-render when streaming\n }\n\n // Otherwise, only re-render if the message ID, feedback, branch, or callbacks changed\n return (\n prevProps.message.id === nextProps.message.id &&\n prevProps.groupedMessages?.length === nextProps.groupedMessages?.length &&\n prevProps.showToolActivity === nextProps.showToolActivity &&\n prevProps.isStreaming === nextProps.isStreaming &&\n prevProps.feedback === nextProps.feedback &&\n prevProps.onRegenerate === nextProps.onRegenerate &&\n prevProps.onFeedback === nextProps.onFeedback &&\n prevProps.branch === nextProps.branch &&\n prevProps.branchOptions?.length === nextProps.branchOptions?.length &&\n prevProps.onBranchSelect === nextProps.onBranchSelect\n );\n});\n"],"names":["getReasoningFromKwargs","message","ak","AgentActivity","reasoningText","toolStatuses","isStreaming","fontSize","expanded","setExpanded","useState","useEffect","hasTools","hasReasoning","jsxs","p","jsx","LoaderCircle","Sparkles","ChevronRight","cn","ts","Wrench","AgentMarkdown","toToolStatusEntry","value","v","visible","getToolStatusFromKwargs","hasToolStatusFieldInKwargs","normalizeSemanticKey","shouldRenderToolStatus","status","normalizeToolLabel","name","input","trimmed","json","renderContentInline","groupedMessages","showToolActivity","isActivelyStreaming","timeline","toolMessages","m","hasBackendToolStatus","completedToolIds","id","completedToolNames","collectedToolStatuses","reasoningTexts","textParts","renderedToolKeys","textIdx","collectToolStatusFromKwargs","semanticKey","label","isCompleted","content","kwargsReasoning","blocks","textAccum","hasReasoningBlock","flushText","i","block","text","toolId","toolName","toolMessage","parts","hasTextContent","combinedReasoning","hasActivity","activityIsStreaming","Fragment","AgentMessage","agentName","onRegenerate","feedback","onFeedback","branch","branchOptions","onBranchSelect","getContentString","inlineContent","BotMessageSquare","BranchSwitcher","MessageActions","React","prevProps","nextProps"],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import { Message } from '@langchain/langgraph-sdk';
2
2
  import { default as React } from 'react';
3
3
  import { MessageFeedback } from './MessageActions';
4
- declare function AgentMessage({ agentName, fontSize, message, isStreaming, onRegenerate, feedback, onFeedback, branch, branchOptions, onBranchSelect, }: {
4
+ declare function AgentMessage({ agentName, fontSize, message, groupedMessages, showToolActivity, isStreaming, onRegenerate, feedback, onFeedback, branch, branchOptions, onBranchSelect, }: {
5
5
  agentName?: string;
6
6
  fontSize?: string;
7
7
  message: Message;
8
+ groupedMessages?: Message[];
9
+ showToolActivity?: boolean;
8
10
  isStreaming?: boolean;
9
11
  onRegenerate?: (parentCheckpoint: any | null | undefined, messageId: string, currentMessage: any) => void;
10
12
  feedback?: MessageFeedback;
@@ -1 +1 @@
1
- {"version":3,"file":"AgentMessage.d.ts","sourceRoot":"","sources":["../../../src/components/messages/AgentMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA2JxE,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,WAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,MAAM,EACN,aAAa,EACb,cAAc,GACf,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,gBAAgB,EAAE,GAAG,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,KAAK,IAAI,CAAC;IAC1G,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C,2CAuDA;;AAGD,wBAiBG"}
1
+ {"version":3,"file":"AgentMessage.d.ts","sourceRoot":"","sources":["../../../src/components/messages/AgentMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA6VxE,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,eAAe,EACf,gBAAuB,EACvB,WAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,MAAM,EACN,aAAa,EACb,cAAc,GACf,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,gBAAgB,EAAE,GAAG,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,KAAK,IAAI,CAAC;IAC1G,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C,2CAuDA;;AAGD,wBAmBG"}