mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 15:17:59 -05:00
feat(platform): Chat UI refinements with simplified tool status indicators (#11337)
This commit is contained in:
@@ -39,6 +39,7 @@ class StreamToolCallStart(StreamBaseResponse):
|
||||
"""Tool call started notification."""
|
||||
|
||||
type: ResponseType = ResponseType.TOOL_CALL_START
|
||||
tool_name: str = Field(..., description="Name of the tool that was executed")
|
||||
tool_id: str = Field(..., description="Unique tool call ID")
|
||||
|
||||
|
||||
|
||||
@@ -440,9 +440,11 @@ async def _stream_chat_chunks(
|
||||
if (
|
||||
idx not in emitted_start_for_idx
|
||||
and tool_calls[idx]["id"]
|
||||
and tool_calls[idx]["function"]["name"]
|
||||
):
|
||||
yield StreamToolCallStart(
|
||||
tool_id=tool_calls[idx]["id"],
|
||||
tool_name=tool_calls[idx]["function"]["name"],
|
||||
timestamp=datetime.now(UTC).isoformat(),
|
||||
)
|
||||
emitted_start_for_idx.add(idx)
|
||||
|
||||
@@ -43,7 +43,7 @@ async def execute_tool(
|
||||
"find_agent": find_agent_tool,
|
||||
"get_agent_details": get_agent_details_tool,
|
||||
"get_required_setup_info": get_required_setup_info_tool,
|
||||
"setup_agent": setup_agent_tool,
|
||||
"schedule_agent": setup_agent_tool,
|
||||
"run_agent": run_agent_tool,
|
||||
}
|
||||
if tool_name not in tool_map:
|
||||
|
||||
@@ -120,7 +120,7 @@ class FindAgentTool(BaseTool):
|
||||
f"Found {len(agents)} agent{'s' if len(agents) != 1 else ''} for '{query}'"
|
||||
)
|
||||
return AgentCarouselResponse(
|
||||
message="Now you have found some options for the user to choose from. Please ask the user if they would like to use any of these agents. If they do, please call the get_agent_details tool for this agent.",
|
||||
message="Now you have found some options for the user to choose from. You can add a link to a recommended agent at: /marketplace/agent/agent_id Please ask the user if they would like to use any of these agents. If they do, please call the get_agent_details tool for this agent.",
|
||||
title=title,
|
||||
agents=agents,
|
||||
count=len(agents),
|
||||
|
||||
@@ -204,7 +204,7 @@ class GetAgentDetailsTool(BaseTool):
|
||||
)
|
||||
|
||||
return AgentDetailsResponse(
|
||||
message=f"Found agent '{agent_details.name}'. You do not need to run this tool again for this agent.",
|
||||
message=f"Found agent '{agent_details.name}'. When presenting the agent you do not need to mention the required credentials. You do not need to run this tool again for this agent.",
|
||||
session_id=session_id,
|
||||
agent=agent_details,
|
||||
user_authenticated=user_id is not None,
|
||||
|
||||
@@ -66,6 +66,7 @@ class AgentCarouselResponse(ToolResponseBase):
|
||||
title: str = "Available Agents"
|
||||
agents: list[AgentInfo]
|
||||
count: int
|
||||
name: str = "agent_carousel"
|
||||
|
||||
|
||||
class NoResultsResponse(ToolResponseBase):
|
||||
@@ -73,6 +74,7 @@ class NoResultsResponse(ToolResponseBase):
|
||||
|
||||
type: ResponseType = ResponseType.NO_RESULTS
|
||||
suggestions: list[str] = []
|
||||
name: str = "no_results"
|
||||
|
||||
|
||||
# Agent details models
|
||||
|
||||
@@ -248,7 +248,7 @@ class RunAgentTool(BaseTool):
|
||||
)
|
||||
|
||||
return ExecutionStartedResponse(
|
||||
message="Agent execution successfully started. Do not run this tool again unless specifically asked to run the agent again.",
|
||||
message=f"Agent execution successfully started. You can add a link to the agent at: /library/agents/{library_agent.id}. Do not run this tool again unless specifically asked to run the agent again.",
|
||||
session_id=session_id,
|
||||
execution_id=execution.id,
|
||||
graph_id=library_agent.graph_id,
|
||||
|
||||
@@ -273,7 +273,7 @@ class SetupAgentTool(BaseTool):
|
||||
)
|
||||
|
||||
return ExecutionStartedResponse(
|
||||
message="Agent execution successfully scheduled. Do not run this tool again unless specifically asked to run the agent again.",
|
||||
message=f"Agent execution successfully scheduled. You can add a link to the agent at: /library/agents/{library_agent.id}. Do not run this tool again unless specifically asked to run the agent again.",
|
||||
session_id=session_id,
|
||||
execution_id=result.id,
|
||||
graph_id=library_agent.graph_id,
|
||||
|
||||
@@ -145,6 +145,7 @@ export function parseToolResponse(
|
||||
if (isAgentArray(agentsData)) {
|
||||
return {
|
||||
type: "agent_carousel",
|
||||
toolName: "agent_carousel",
|
||||
agents: agentsData,
|
||||
totalCount: parsedResult.total_count as number | undefined,
|
||||
timestamp: timestamp || new Date(),
|
||||
@@ -156,6 +157,7 @@ export function parseToolResponse(
|
||||
if (responseType === "execution_started") {
|
||||
return {
|
||||
type: "execution_started",
|
||||
toolName: "execution_started",
|
||||
executionId: (parsedResult.execution_id as string) || "",
|
||||
agentName: parsedResult.agent_name as string | undefined,
|
||||
message: parsedResult.message as string | undefined,
|
||||
@@ -165,6 +167,7 @@ export function parseToolResponse(
|
||||
if (responseType === "need_login") {
|
||||
return {
|
||||
type: "login_needed",
|
||||
toolName: "login_needed",
|
||||
message:
|
||||
(parsedResult.message as string) ||
|
||||
"Please sign in to use chat and agent features",
|
||||
@@ -260,6 +263,7 @@ export function extractCredentialsNeeded(
|
||||
}));
|
||||
return {
|
||||
type: "credentials_needed",
|
||||
toolName: "get_required_setup_info",
|
||||
credentials,
|
||||
message: `To run ${agentName}, you need to add ${credentials.length === 1 ? "credentials" : `${credentials.length} credentials`}.`,
|
||||
agentName,
|
||||
|
||||
@@ -141,6 +141,7 @@ export function handleLoginNeeded(
|
||||
) {
|
||||
const loginNeededMessage: ChatMessageData = {
|
||||
type: "login_needed",
|
||||
toolName: "login_needed",
|
||||
message: chunk.message || "Please sign in to use chat and agent features",
|
||||
sessionId: chunk.session_id || deps.sessionId,
|
||||
agentInfo: chunk.agent_info,
|
||||
|
||||
@@ -9,12 +9,9 @@ import { ToolCallMessage } from "@/app/(platform)/chat/components/ToolCallMessag
|
||||
import { ToolResponseMessage } from "@/app/(platform)/chat/components/ToolResponseMessage/ToolResponseMessage";
|
||||
import { AuthPromptWidget } from "@/app/(platform)/chat/components/AuthPromptWidget/AuthPromptWidget";
|
||||
import { ChatCredentialsSetup } from "@/app/(platform)/chat/components/ChatCredentialsSetup/ChatCredentialsSetup";
|
||||
import { NoResultsMessage } from "@/app/(platform)/chat/components/NoResultsMessage/NoResultsMessage";
|
||||
import { AgentCarouselMessage } from "@/app/(platform)/chat/components/AgentCarouselMessage/AgentCarouselMessage";
|
||||
import { ExecutionStartedMessage } from "@/app/(platform)/chat/components/ExecutionStartedMessage/ExecutionStartedMessage";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { useChatMessage, type ChatMessageData } from "./useChatMessage";
|
||||
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
export interface ChatMessageProps {
|
||||
message: ChatMessageData;
|
||||
className?: string;
|
||||
@@ -38,9 +35,6 @@ export function ChatMessage({
|
||||
isToolResponse,
|
||||
isLoginNeeded,
|
||||
isCredentialsNeeded,
|
||||
isNoResults,
|
||||
isAgentCarousel,
|
||||
isExecutionStarted,
|
||||
} = useChatMessage(message);
|
||||
|
||||
const handleAllCredentialsComplete = useCallback(
|
||||
@@ -129,63 +123,25 @@ export function ChatMessage({
|
||||
if (isToolCall && message.type === "tool_call") {
|
||||
return (
|
||||
<div className={cn("px-4 py-2", className)}>
|
||||
<ToolCallMessage
|
||||
toolId={message.toolId}
|
||||
toolName={message.toolName}
|
||||
arguments={message.arguments}
|
||||
/>
|
||||
<ToolCallMessage toolName={message.toolName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Render tool response messages
|
||||
if (isToolResponse && message.type === "tool_response") {
|
||||
if (
|
||||
(isToolResponse && message.type === "tool_response") ||
|
||||
message.type === "no_results" ||
|
||||
message.type === "agent_carousel" ||
|
||||
message.type === "execution_started"
|
||||
) {
|
||||
return (
|
||||
<div className={cn("px-4 py-2", className)}>
|
||||
<ToolResponseMessage
|
||||
toolId={message.toolId}
|
||||
toolName={message.toolName}
|
||||
result={message.result}
|
||||
success={message.success}
|
||||
/>
|
||||
<ToolResponseMessage toolName={getToolActionPhrase(message.toolName)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Render no results messages
|
||||
if (isNoResults && message.type === "no_results") {
|
||||
return (
|
||||
<NoResultsMessage
|
||||
message={message.message}
|
||||
suggestions={message.suggestions}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Render agent carousel messages
|
||||
if (isAgentCarousel && message.type === "agent_carousel") {
|
||||
return (
|
||||
<AgentCarouselMessage
|
||||
agents={message.agents}
|
||||
totalCount={message.totalCount}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Render execution started messages
|
||||
if (isExecutionStarted && message.type === "execution_started") {
|
||||
return (
|
||||
<ExecutionStartedMessage
|
||||
executionId={message.executionId}
|
||||
agentName={message.agentName}
|
||||
message={message.message}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Render regular chat messages
|
||||
if (message.type === "message") {
|
||||
return (
|
||||
|
||||
@@ -25,6 +25,7 @@ export type ChatMessageData =
|
||||
}
|
||||
| {
|
||||
type: "login_needed";
|
||||
toolName: string;
|
||||
message: string;
|
||||
sessionId: string;
|
||||
agentInfo?: {
|
||||
@@ -36,6 +37,7 @@ export type ChatMessageData =
|
||||
}
|
||||
| {
|
||||
type: "credentials_needed";
|
||||
toolName: string;
|
||||
credentials: Array<{
|
||||
provider: string;
|
||||
providerName: string;
|
||||
@@ -49,6 +51,7 @@ export type ChatMessageData =
|
||||
}
|
||||
| {
|
||||
type: "no_results";
|
||||
toolName: string;
|
||||
message: string;
|
||||
suggestions?: string[];
|
||||
sessionId?: string;
|
||||
@@ -56,6 +59,7 @@ export type ChatMessageData =
|
||||
}
|
||||
| {
|
||||
type: "agent_carousel";
|
||||
toolName: string;
|
||||
agents: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -67,6 +71,7 @@ export type ChatMessageData =
|
||||
}
|
||||
| {
|
||||
type: "execution_started";
|
||||
toolName: string;
|
||||
executionId: string;
|
||||
agentName?: string;
|
||||
message?: string;
|
||||
|
||||
@@ -1,29 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import { Wrench, Spinner, CaretDown, CaretUp } from "@phosphor-icons/react";
|
||||
import React from "react";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getToolDisplayName } from "@/app/(platform)/chat/helpers";
|
||||
import type { ToolArguments } from "@/types/chat";
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
|
||||
export interface ToolCallMessageProps {
|
||||
toolId: string;
|
||||
toolName: string;
|
||||
arguments?: ToolArguments;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ToolCallMessage({
|
||||
toolId,
|
||||
toolName,
|
||||
arguments: args,
|
||||
className,
|
||||
}: ToolCallMessageProps) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
export function ToolCallMessage({ toolName, className }: ToolCallMessageProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-hidden rounded-lg border transition-all duration-200",
|
||||
"mx-10 max-w-[70%] overflow-hidden rounded-lg border transition-all duration-200",
|
||||
"border-neutral-200 dark:border-neutral-700",
|
||||
"bg-white dark:bg-neutral-900",
|
||||
"animate-in fade-in-50 slide-in-from-top-1",
|
||||
@@ -37,72 +26,24 @@ export function ToolCallMessage({
|
||||
"bg-gradient-to-r from-neutral-50 to-neutral-100 dark:from-neutral-800/20 dark:to-neutral-700/20",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Wrench
|
||||
<div className="flex items-center gap-2 overflow-hidden">
|
||||
<WrenchIcon
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-500 dark:text-neutral-400"
|
||||
className="flex-shrink-0 text-neutral-500 dark:text-neutral-400"
|
||||
/>
|
||||
<span className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
{getToolDisplayName(toolName)}
|
||||
<span className="relative inline-block overflow-hidden text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
{getToolActionPhrase(toolName)}...
|
||||
<span
|
||||
className={cn(
|
||||
"absolute inset-0 bg-gradient-to-r from-transparent via-white/50 to-transparent",
|
||||
"dark:via-white/20",
|
||||
"animate-shimmer",
|
||||
)}
|
||||
/>
|
||||
</span>
|
||||
<div className="ml-2 flex items-center gap-1.5">
|
||||
<Spinner
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="animate-spin text-blue-500"
|
||||
/>
|
||||
<span className="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
Executing...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="rounded p-1 hover:bg-neutral-200/50 dark:hover:bg-neutral-700/50"
|
||||
aria-label={isExpanded ? "Collapse details" : "Expand details"}
|
||||
>
|
||||
{isExpanded ? (
|
||||
<CaretUp
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
/>
|
||||
) : (
|
||||
<CaretDown
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Expandable Content */}
|
||||
{isExpanded && (
|
||||
<div className="px-4 py-3">
|
||||
{args && Object.keys(args).length > 0 && (
|
||||
<div className="mb-3">
|
||||
<div className="mb-2 text-xs font-medium text-neutral-600 dark:text-neutral-400">
|
||||
Parameters:
|
||||
</div>
|
||||
<div className="rounded-md bg-neutral-50 p-3 dark:bg-neutral-800">
|
||||
<pre className="overflow-x-auto text-xs text-neutral-700 dark:text-neutral-300">
|
||||
{JSON.stringify(args, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Text
|
||||
variant="small"
|
||||
className="text-neutral-500 dark:text-neutral-400"
|
||||
>
|
||||
Tool ID: {toolId.slice(0, 8)}...
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,90 +1,23 @@
|
||||
import React, { useState } from "react";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import {
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
CaretDown,
|
||||
CaretUp,
|
||||
Wrench,
|
||||
} from "@phosphor-icons/react";
|
||||
import React from "react";
|
||||
import { WrenchIcon } from "@phosphor-icons/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getToolDisplayName } from "@/app/(platform)/chat/helpers";
|
||||
import type { ToolResult } from "@/types/chat";
|
||||
import { getToolActionPhrase } from "@/app/(platform)/chat/helpers";
|
||||
|
||||
export interface ToolResponseMessageProps {
|
||||
toolId: string;
|
||||
toolName: string;
|
||||
result: ToolResult;
|
||||
success?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Check if result should be hidden (special response types)
|
||||
function shouldHideResult(result: ToolResult): boolean {
|
||||
try {
|
||||
const resultString =
|
||||
typeof result === "string" ? result : JSON.stringify(result);
|
||||
const parsed = JSON.parse(resultString);
|
||||
|
||||
// Hide raw JSON for these special types
|
||||
if (parsed.type === "agent_carousel") return true;
|
||||
if (parsed.type === "execution_started") return true;
|
||||
if (parsed.type === "setup_requirements") return true;
|
||||
if (parsed.type === "no_results") return true;
|
||||
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a friendly summary for special response types
|
||||
function getResultSummary(result: ToolResult): string | null {
|
||||
try {
|
||||
const resultString =
|
||||
typeof result === "string" ? result : JSON.stringify(result);
|
||||
const parsed = JSON.parse(resultString);
|
||||
|
||||
if (parsed.type === "agent_carousel") {
|
||||
return `Found ${parsed.agents?.length || parsed.count || 0} agents${parsed.query ? ` matching "${parsed.query}"` : ""}`;
|
||||
}
|
||||
if (parsed.type === "execution_started") {
|
||||
return `Started execution${parsed.execution_id ? ` (ID: ${parsed.execution_id.slice(0, 8)}...)` : ""}`;
|
||||
}
|
||||
if (parsed.type === "setup_requirements") {
|
||||
return "Retrieved setup requirements";
|
||||
}
|
||||
if (parsed.type === "no_results") {
|
||||
return parsed.message || "No results found";
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function ToolResponseMessage({
|
||||
toolId,
|
||||
toolName,
|
||||
result,
|
||||
success = true,
|
||||
className,
|
||||
}: ToolResponseMessageProps) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const hideResult = shouldHideResult(result);
|
||||
const resultSummary = getResultSummary(result);
|
||||
const resultString =
|
||||
typeof result === "object"
|
||||
? JSON.stringify(result, null, 2)
|
||||
: String(result);
|
||||
const shouldTruncate = resultString.length > 200;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-hidden rounded-lg border transition-all duration-200",
|
||||
"mx-10 max-w-[70%] overflow-hidden rounded-lg border transition-all duration-200",
|
||||
success
|
||||
? "border-neutral-200 dark:border-neutral-700"
|
||||
: "border-red-200 dark:border-red-800",
|
||||
@@ -104,97 +37,16 @@ export function ToolResponseMessage({
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Wrench
|
||||
<WrenchIcon
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-500 dark:text-neutral-400"
|
||||
/>
|
||||
<span className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
{getToolDisplayName(toolName)}
|
||||
{getToolActionPhrase(toolName)}...
|
||||
</span>
|
||||
<div className="ml-2 flex items-center gap-1.5">
|
||||
{success ? (
|
||||
<CheckCircle size={16} weight="fill" className="text-green-500" />
|
||||
) : (
|
||||
<XCircle size={16} weight="fill" className="text-red-500" />
|
||||
)}
|
||||
<span className="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
{success ? "Completed" : "Error"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!hideResult && (
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="rounded p-1 hover:bg-neutral-200/50 dark:hover:bg-neutral-700/50"
|
||||
aria-label={isExpanded ? "Collapse details" : "Expand details"}
|
||||
>
|
||||
{isExpanded ? (
|
||||
<CaretUp
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
/>
|
||||
) : (
|
||||
<CaretDown
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Expandable Content */}
|
||||
{isExpanded && !hideResult && (
|
||||
<div className="px-4 py-3">
|
||||
<div className="mb-2 text-xs font-medium text-neutral-600 dark:text-neutral-400">
|
||||
Result:
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-md p-3",
|
||||
success
|
||||
? "bg-green-50 dark:bg-green-900/20"
|
||||
: "bg-red-50 dark:bg-red-900/20",
|
||||
)}
|
||||
>
|
||||
<pre
|
||||
className={cn(
|
||||
"whitespace-pre-wrap text-xs",
|
||||
success
|
||||
? "text-green-800 dark:text-green-200"
|
||||
: "text-red-800 dark:text-red-200",
|
||||
)}
|
||||
>
|
||||
{shouldTruncate && !isExpanded
|
||||
? `${resultString.slice(0, 200)}...`
|
||||
: resultString}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<Text
|
||||
variant="small"
|
||||
className="mt-2 text-neutral-500 dark:text-neutral-400"
|
||||
>
|
||||
Tool ID: {toolId.slice(0, 8)}...
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Summary for special response types */}
|
||||
{hideResult && resultSummary && (
|
||||
<div className="px-4 py-2">
|
||||
<Text
|
||||
variant="small"
|
||||
className="text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
{resultSummary}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Maps internal tool names to user-friendly display names with emojis.
|
||||
* @deprecated Use getToolActionPhrase or getToolCompletionPhrase for status messages
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A user-friendly display name with an emoji prefix
|
||||
@@ -16,6 +17,54 @@ export function getToolDisplayName(toolName: string): string {
|
||||
return toolDisplayNames[toolName] || toolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps internal tool names to human-friendly action phrases (present continuous).
|
||||
* Used for tool call messages to indicate what action is currently happening.
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A human-friendly action phrase in present continuous tense
|
||||
*/
|
||||
export function getToolActionPhrase(toolName: string): string {
|
||||
const toolActionPhrases: Record<string, string> = {
|
||||
find_agent: "Looking for agents in the marketplace",
|
||||
agent_carousel: "Looking for agents in the marketplace",
|
||||
get_agent_details: "Learning about the agent",
|
||||
check_credentials: "Checking your credentials",
|
||||
setup_agent: "Setting up the agent",
|
||||
execution_started: "Running the agent",
|
||||
run_agent: "Running the agent",
|
||||
get_required_setup_info: "Getting setup requirements",
|
||||
schedule_agent: "Scheduling the agent to run",
|
||||
};
|
||||
|
||||
// Return mapped phrase or generate human-friendly fallback
|
||||
return toolActionPhrases[toolName] || toolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps internal tool names to human-friendly completion phrases (past tense).
|
||||
* Used for tool response messages to indicate what action was completed.
|
||||
*
|
||||
* @param toolName - The internal tool name from the backend
|
||||
* @returns A human-friendly completion phrase in past tense
|
||||
*/
|
||||
export function getToolCompletionPhrase(toolName: string): string {
|
||||
const toolCompletionPhrases: Record<string, string> = {
|
||||
find_agent: "Finished searching the marketplace",
|
||||
get_agent_details: "Got agent details",
|
||||
check_credentials: "Checked credentials",
|
||||
setup_agent: "Agent setup complete",
|
||||
run_agent: "Agent execution started",
|
||||
get_required_setup_info: "Got setup requirements",
|
||||
};
|
||||
|
||||
// Return mapped phrase or generate human-friendly fallback
|
||||
return (
|
||||
toolCompletionPhrases[toolName] ||
|
||||
`Finished ${toolName.replace(/_/g, " ").replace("...", "")}`
|
||||
);
|
||||
}
|
||||
|
||||
/** Validate UUID v4 format */
|
||||
export function isValidUUID(value: string): boolean {
|
||||
const uuidRegex =
|
||||
|
||||
@@ -13,7 +13,7 @@ export function TallyPopupSimple() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-1 right-24 z-20 hidden select-none items-center gap-4 p-3 transition-all duration-300 ease-in-out md:flex">
|
||||
<div className="fixed bottom-1 right-0 z-20 hidden select-none items-center gap-4 p-3 transition-all duration-300 ease-in-out md:flex">
|
||||
{state.showTutorial && (
|
||||
<Button
|
||||
variant="primary"
|
||||
|
||||
Reference in New Issue
Block a user