feat: enhance tool display names for better user experience in chat UI

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-29 07:40:11 -07:00
parent c110f5b955
commit 9a114a2d45
7 changed files with 267 additions and 32 deletions

View file

@ -37,6 +37,7 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { getToolDisplayName } from "@/contracts/enums/toolIcons";
import {
agentActionsApiService,
type RevertTurnActionResult,
@ -48,10 +49,6 @@ interface RevertTurnButtonProps {
chatTurnId: string | null | undefined;
}
function formatToolName(name: string): string {
return name.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}
// Empty-array sentinel so the per-turn ``selectAtom`` slice returns a
// stable reference when the turn has no recorded actions yet. Without
// this every render allocates a fresh ``[]`` and Jotai's
@ -218,7 +215,7 @@ function RevertResultRow({ result }: { result: RevertTurnActionResult }) {
/>
<div className="min-w-0 flex-1">
<p className="font-medium truncate">
{formatToolName(result.tool_name)}{" "}
{getToolDisplayName(result.tool_name)}{" "}
<span className="ml-1 text-xs text-muted-foreground">
{result.status.replace(/_/g, " ")}
</span>

View file

@ -82,6 +82,7 @@ import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
import {
CONNECTOR_ICON_TO_TYPES,
CONNECTOR_TOOL_ICON_PATHS,
getToolDisplayName,
getToolIcon,
} from "@/contracts/enums/toolIcons";
import type { Document } from "@/contracts/types/document.types";
@ -1317,12 +1318,14 @@ const ComposerAction: FC<ComposerActionProps> = ({ isBlockedByOtherUser = false
);
};
/** Convert snake_case tool names to human-readable labels */
/**
* Friendly tool name for display in the chat UI. Delegates to the
* shared map in ``contracts/enums/toolIcons`` so unix-style identifiers
* (``rm``, ``ls``, ``grep`` ) and snake_cased function names render as
* plain English (e.g. "Delete file", "List files", "Search in files").
*/
function formatToolName(name: string): string {
return name
.split("_")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
return getToolDisplayName(name);
}
interface ToolGroup {

View file

@ -25,16 +25,12 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { getToolIcon } from "@/contracts/enums/toolIcons";
import { getToolDisplayName, getToolIcon } from "@/contracts/enums/toolIcons";
import { agentActionsApiService } from "@/lib/apis/agent-actions-api.service";
import { AppError } from "@/lib/error";
import { isInterruptResult } from "@/lib/hitl";
import { cn } from "@/lib/utils";
function formatToolName(name: string): string {
return name.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}
/**
* Inline Revert button rendered on a tool card when the matching
* ``AgentActionLog`` row is reversible and hasn't been reverted yet.
@ -104,9 +100,10 @@ function ToolCardRevertButton({ toolCallId }: { toolCallId: string }) {
<AlertDialogHeader>
<AlertDialogTitle>Revert this action?</AlertDialogTitle>
<AlertDialogDescription>
This will undo <span className="font-medium">{formatToolName(action.toolName)}</span>{" "}
and append a new audit entry. Chat history is preserved only the tool's effects on
your knowledge base or connectors will be reversed where possible.
This will undo{" "}
<span className="font-medium">{getToolDisplayName(action.toolName)}</span> and add a
new entry to the history. Your chat is preserved only the changes the agent made to
your knowledge base or connected apps will be rolled back where possible.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
@ -164,7 +161,7 @@ const DefaultToolFallbackInner: ToolCallMessagePartComponent = ({
: null;
const Icon = getToolIcon(toolName);
const displayName = formatToolName(toolName);
const displayName = getToolDisplayName(toolName);
return (
<div
@ -215,7 +212,7 @@ const DefaultToolFallbackInner: ToolCallMessagePartComponent = ({
? `Failed: ${displayName}`
: displayName}
</p>
{isRunning && <p className="text-xs text-muted-foreground mt-0.5">Running...</p>}
{isRunning && <p className="text-xs text-muted-foreground mt-0.5">Working</p>}
{cancelledReason && (
<p className="text-xs text-muted-foreground mt-0.5 truncate">{cancelledReason}</p>
)}
@ -241,7 +238,7 @@ const DefaultToolFallbackInner: ToolCallMessagePartComponent = ({
<div className="px-5 py-3 space-y-3">
{argsText && (
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">Arguments</p>
<p className="text-xs font-medium text-muted-foreground mb-1">Inputs</p>
<pre className="text-xs text-foreground/80 whitespace-pre-wrap break-all">
{argsText}
</pre>