feat: add option to hide tool calls

This commit is contained in:
bracesproul
2025-03-11 10:59:49 -07:00
parent 6864025fab
commit 72b9ebcf04
5 changed files with 123 additions and 8 deletions

View File

@@ -27,6 +27,7 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/postcss": "^4.0.9",
"@tailwindcss/vite": "^4.0.9",

52
pnpm-lock.yaml generated
View File

@@ -46,6 +46,9 @@ importers:
"@radix-ui/react-slot":
specifier: ^1.1.2
version: 1.1.2(@types/react@19.0.10)(react@19.0.0)
"@radix-ui/react-switch":
specifier: ^1.1.3
version: 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
"@radix-ui/react-tooltip":
specifier: ^1.1.8
version: 1.1.8(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -1184,6 +1187,22 @@ packages:
"@types/react":
optional: true
"@radix-ui/react-switch@1.1.3":
resolution:
{
integrity: sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==,
}
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
"@types/react":
optional: true
"@types/react-dom":
optional: true
"@radix-ui/react-tooltip@1.1.8":
resolution:
{
@@ -1248,6 +1267,18 @@ packages:
"@types/react":
optional: true
"@radix-ui/react-use-previous@1.1.0":
resolution:
{
integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==,
}
peerDependencies:
"@types/react": "*"
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
"@types/react":
optional: true
"@radix-ui/react-use-rect@1.1.0":
resolution:
{
@@ -6184,6 +6215,21 @@ snapshots:
optionalDependencies:
"@types/react": 19.0.10
"@radix-ui/react-switch@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)":
dependencies:
"@radix-ui/primitive": 1.1.1
"@radix-ui/react-compose-refs": 1.1.1(@types/react@19.0.10)(react@19.0.0)
"@radix-ui/react-context": 1.1.1(@types/react@19.0.10)(react@19.0.0)
"@radix-ui/react-primitive": 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
"@radix-ui/react-use-controllable-state": 1.1.0(@types/react@19.0.10)(react@19.0.0)
"@radix-ui/react-use-previous": 1.1.0(@types/react@19.0.10)(react@19.0.0)
"@radix-ui/react-use-size": 1.1.0(@types/react@19.0.10)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
"@types/react": 19.0.10
"@types/react-dom": 19.0.4(@types/react@19.0.10)
"@radix-ui/react-tooltip@1.1.8(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)":
dependencies:
"@radix-ui/primitive": 1.1.1
@@ -6230,6 +6276,12 @@ snapshots:
optionalDependencies:
"@types/react": 19.0.10
"@radix-ui/react-use-previous@1.1.0(@types/react@19.0.10)(react@19.0.0)":
dependencies:
react: 19.0.0
optionalDependencies:
"@types/react": 19.0.10
"@radix-ui/react-use-rect@1.1.0(@types/react@19.0.10)(react@19.0.0)":
dependencies:
"@radix-ui/rect": 1.1.0

View File

@@ -25,6 +25,8 @@ import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
import ThreadHistory from "./history";
import { toast } from "sonner";
import { useMediaQuery } from "@/hooks/useMediaQuery";
import { Label } from "../ui/label";
import { Switch } from "../ui/switch";
function StickyToBottomContent(props: {
content: ReactNode;
@@ -70,6 +72,10 @@ export function Thread() {
"chatHistoryOpen",
BooleanParam,
);
const [hideToolCalls, setHideToolCalls] = useQueryParam(
"hideToolCalls",
BooleanParam,
);
const [input, setInput] = useState("");
const [firstTokenReceived, setFirstTokenReceived] = useState(false);
const isLargeScreen = useMediaQuery("(min-width: 1024px)");
@@ -335,7 +341,22 @@ export function Thread() {
className="p-3.5 pb-0 border-none bg-transparent field-sizing-content shadow-none ring-0 outline-none focus:outline-none focus:ring-0 resize-none"
/>
<div className="flex items-center justify-end p-2 pt-0">
<div className="flex items-center justify-between p-2 pt-4">
<div>
<div className="flex items-center space-x-2">
<Switch
id="render-tool-calls"
checked={hideToolCalls ?? false}
onCheckedChange={setHideToolCalls}
/>
<Label
htmlFor="render-tool-calls"
className="text-sm text-gray-600"
>
Hide Tool Calls
</Label>
</div>
</div>
{stream.isLoading ? (
<Button key="stop" onClick={() => stream.stop()}>
<LoaderCircle className="w-4 h-4 animate-spin" />

View File

@@ -11,6 +11,7 @@ import { MessageContentComplex } from "@langchain/core/messages";
import { Fragment } from "react/jsx-runtime";
import { isAgentInboxInterruptSchema } from "@/lib/agent-inbox-interrupt";
import { ThreadView } from "../agent-inbox";
import { BooleanParam, useQueryParam } from "use-query-params";
function CustomComponent({
message,
@@ -78,6 +79,7 @@ export function AssistantMessage({
handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void;
}) {
const contentString = getContentString(message.content);
const [hideToolCalls] = useQueryParam("hideToolCalls", BooleanParam);
const thread = useStreamContext();
const isLastMessage =
@@ -101,6 +103,10 @@ export function AssistantMessage({
const hasAnthropicToolCalls = !!anthropicStreamedToolCalls?.length;
const isToolResult = message.type === "tool";
if (isToolResult && hideToolCalls) {
return null;
}
return (
<div className="flex items-start mr-auto gap-2 group">
{isToolResult ? (
@@ -112,13 +118,19 @@ export function AssistantMessage({
<MarkdownText>{contentString}</MarkdownText>
</div>
)}
{(hasToolCalls && toolCallsHaveContents && (
<ToolCalls toolCalls={message.tool_calls} />
)) ||
(hasAnthropicToolCalls && (
<ToolCalls toolCalls={anthropicStreamedToolCalls} />
)) ||
(hasToolCalls && <ToolCalls toolCalls={message.tool_calls} />)}
{!hideToolCalls && (
<>
{(hasToolCalls && toolCallsHaveContents && (
<ToolCalls toolCalls={message.tool_calls} />
)) ||
(hasAnthropicToolCalls && (
<ToolCalls toolCalls={anthropicStreamedToolCalls} />
)) ||
(hasToolCalls && <ToolCalls toolCalls={message.tool_calls} />)}
</>
)}
<CustomComponent message={message} thread={thread} />
{isAgentInboxInterruptSchema(interrupt?.value) && isLastMessage && (
<ThreadView interrupt={interrupt.value[0]} />

View File

@@ -0,0 +1,29 @@
import * as React from "react";
import * as SwitchPrimitive from "@radix-ui/react-switch";
import { cn } from "@/lib/utils";
function Switch({
className,
...props
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
return (
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"bg-background pointer-events-none block size-4 rounded-full ring-0 shadow-lg transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitive.Root>
);
}
export { Switch };