diff --git a/src/components/thread/messages/ai.tsx b/src/components/thread/messages/ai.tsx
index e269a63..91fa365 100644
--- a/src/components/thread/messages/ai.tsx
+++ b/src/components/thread/messages/ai.tsx
@@ -6,7 +6,7 @@ import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { MarkdownText } from "../markdown-text";
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui/client";
import { cn } from "@/lib/utils";
-import { ToolCalls } from "./tool-calls";
+import { ToolCalls, ToolResult } from "./tool-calls";
function CustomComponent({
message,
@@ -61,40 +61,45 @@ export function AssistantMessage({
"tool_calls" in message &&
message.tool_calls &&
message.tool_calls.length > 0;
+ const isToolResult = message.type === "tool";
return (
A
-
- {hasToolCalls &&
}
-
- {contentString.length > 0 && (
-
- {contentString}
-
- )}
-
+ ) : (
+
+ {hasToolCalls &&
}
+
+ {contentString.length > 0 && (
+
+ {contentString}
+
)}
- >
-
thread.setBranch(branch)}
- isLoading={isLoading}
- />
- handleRegenerate(parentCheckpoint)}
- />
+
+ thread.setBranch(branch)}
+ isLoading={isLoading}
+ />
+ handleRegenerate(parentCheckpoint)}
+ />
+
-
+ )}
);
}
diff --git a/src/components/thread/messages/tool-calls.tsx b/src/components/thread/messages/tool-calls.tsx
index 741b297..bd768c3 100644
--- a/src/components/thread/messages/tool-calls.tsx
+++ b/src/components/thread/messages/tool-calls.tsx
@@ -1,4 +1,7 @@
-import { AIMessage } from "@langchain/langgraph-sdk";
+import { AIMessage, ToolMessage } from "@langchain/langgraph-sdk";
+import { useState } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import { ChevronDown, ChevronUp } from "lucide-react";
function isComplexValue(value: any): boolean {
return Array.isArray(value) || (typeof value === "object" && value !== null);
@@ -23,7 +26,14 @@ export function ToolCalls({
className="border border-gray-200 rounded-lg overflow-hidden"
>
-
{tc.name}
+
+ {tc.name}
+ {tc.id && (
+
+ {tc.id}
+
+ )}
+
@@ -51,3 +61,123 @@ export function ToolCalls({
);
}
+
+export function ToolResult({ message }: { message: ToolMessage }) {
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ let parsedContent: any;
+ let isJsonContent = false;
+
+ try {
+ if (typeof message.content === "string") {
+ parsedContent = JSON.parse(message.content);
+ isJsonContent = true;
+ }
+ } catch {
+ // Content is not JSON, use as is
+ parsedContent = message.content;
+ }
+
+ const contentStr = isJsonContent
+ ? JSON.stringify(parsedContent, null, 2)
+ : String(message.content);
+ const contentLines = contentStr.split("\n");
+ const shouldTruncate = contentLines.length > 4 || contentStr.length > 500;
+ const displayedContent =
+ shouldTruncate && !isExpanded
+ ? contentStr.length > 500
+ ? contentStr.slice(0, 500) + "..."
+ : contentLines.slice(0, 4).join("\n") + "\n..."
+ : contentStr;
+
+ return (
+
+
+
+ {message.name ? (
+
+ Tool Result:{" "}
+
+ {message.name}
+
+
+ ) : (
+ Tool Result
+ )}
+ {message.tool_call_id && (
+
+ {message.tool_call_id}
+
+ )}
+
+
+
+
+
+
+ {isJsonContent ? (
+
+
+ {(Array.isArray(parsedContent)
+ ? isExpanded
+ ? parsedContent
+ : parsedContent.slice(0, 5)
+ : Object.entries(parsedContent)
+ ).map((item, argIdx) => {
+ const [key, value] = Array.isArray(parsedContent)
+ ? [argIdx, item]
+ : [item[0], item[1]];
+ return (
+
+ |
+ {key}
+ |
+
+ {isComplexValue(value) ? (
+
+ {JSON.stringify(value, null, 2)}
+
+ ) : (
+ String(value)
+ )}
+ |
+
+ );
+ })}
+
+
+ ) : (
+ {displayedContent}
+ )}
+
+
+
+ {((shouldTruncate && !isJsonContent) ||
+ (isJsonContent &&
+ Array.isArray(parsedContent) &&
+ parsedContent.length > 5)) && (
+ setIsExpanded(!isExpanded)}
+ className="w-full py-2 flex items-center justify-center border-t-[1px] border-gray-200 text-gray-500 hover:text-gray-600 hover:bg-gray-50 transition-all ease-in-out duration-200 cursor-pointer"
+ initial={{ scale: 1 }}
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+ {isExpanded ? : }
+
+ )}
+
+
+ );
+}