feat(ui/agents): add ToolCallCard

Collapsible card for assistant tool invocations from tool_call events.
Cursor Cloud Agents-style: collapsed shows tool + preview; expanded
shows full input (and result, when present).
This commit is contained in:
Ishaan Jaffer 2026-05-06 15:03:31 -07:00
parent c7d820a83e
commit 3836af5681
No known key found for this signature in database

View file

@ -0,0 +1,63 @@
"use client";
/**
* ToolCallCard — collapsible card rendering an assistant tool invocation.
*
* Used for `tool_call` events. The Cursor Cloud Agents UI shows these
* collapsed by default with the tool name + a one-line preview, expanded
* on click to show the full input.
*/
import { useState } from "react";
import { Card, Tag, Typography, Button } from "antd";
import { CaretRightOutlined, CaretDownOutlined } from "@ant-design/icons";
const { Text, Paragraph } = Typography;
interface ToolCallCardProps {
tool: string;
input: string;
result?: string;
}
export default function ToolCallCard({ tool, input, result }: ToolCallCardProps) {
const [expanded, setExpanded] = useState(false);
return (
<Card size="small" className="!mb-3" data-testid="tool-call-card" bodyStyle={{ padding: 8 }}>
<div className="flex items-center gap-2">
<Button
size="small"
type="text"
icon={expanded ? <CaretDownOutlined /> : <CaretRightOutlined />}
onClick={() => setExpanded((v) => !v)}
data-testid="tool-call-toggle"
/>
<Tag color="cyan" className="!m-0">
{tool}
</Tag>
{!expanded && (
<Text type="secondary" className="!truncate !text-xs">
{input.slice(0, 80)}
</Text>
)}
</div>
{expanded && (
<div className="mt-2 space-y-2">
<div>
<Text strong className="!text-xs">
input
</Text>
<Paragraph className="!mb-0 whitespace-pre-wrap !text-xs !font-mono">{input}</Paragraph>
</div>
{result && (
<div>
<Text strong className="!text-xs">
result
</Text>
<Paragraph className="!mb-0 whitespace-pre-wrap !text-xs !font-mono">{result}</Paragraph>
</div>
)}
</div>
)}
</Card>
);
}