Merge pull request #1788 from escapade-mckv/triggers-display

Triggers display
This commit is contained in:
Bobbie 2025-10-08 15:04:29 +05:30 committed by GitHub
commit 2b22aed8b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 956 additions and 28 deletions

View File

@ -50,6 +50,7 @@ import { useAgentVersionData } from '@/hooks/use-agent-version-data';
import { useUpdateAgent, useAgents } from '@/hooks/react-query/agents/use-agents';
import { useUpdateAgentMCPs } from '@/hooks/react-query/agents/use-update-agent-mcps';
import { useExportAgent } from '@/hooks/react-query/agents/use-agent-export-import';
import { agentKeys } from '@/hooks/react-query/agents/keys';
import { ExpandableMarkdownEditor } from '@/components/ui/expandable-markdown-editor';
import { AgentModelSelector } from './config/model-selector';
import { AgentToolsConfiguration } from './agent-tools-configuration';
@ -82,7 +83,11 @@ export function AgentConfigurationDialog({
const queryClient = useQueryClient();
const { agent, versionData, isViewingOldVersion, isLoading, error } = useAgentVersionData({ agentId });
const { data: agentsResponse } = useAgents({}, { enabled: !!onAgentChange });
const { data: agentsResponse, refetch: refetchAgents } = useAgents({}, {
enabled: !!onAgentChange,
refetchOnWindowFocus: true,
refetchOnMount: 'always'
});
const agents = agentsResponse?.agents || [];
const updateAgentMutation = useUpdateAgent();
@ -106,6 +111,29 @@ export function AgentConfigurationDialog({
}
}, [open, initialTab]);
// Listen for query invalidations and refetch when agent data changes
useEffect(() => {
const unsubscribe = queryClient.getQueryCache().subscribe((event) => {
// Check if the invalidation is for this agent's data
if (event?.type === 'updated' && event?.query?.queryKey) {
const queryKey = event.query.queryKey;
// Check if it's an agent-related query for our agentId
if (
(Array.isArray(queryKey) && queryKey.includes(agentId)) ||
(Array.isArray(queryKey) && queryKey.includes('agents') && queryKey.includes('detail')) ||
(Array.isArray(queryKey) && queryKey.includes('versions'))
) {
// Force a re-render by invalidating our specific queries
queryClient.invalidateQueries({ queryKey: agentKeys.detail(agentId) });
queryClient.invalidateQueries({ queryKey: ['versions', 'list', agentId] });
}
}
});
return () => unsubscribe();
}, [agentId, queryClient]);
const [formData, setFormData] = useState({
name: '',
system_prompt: '',

View File

@ -167,11 +167,9 @@ export function CustomAgentsSection({ onAgentSelect }: CustomAgentsSectionProps)
<TitleSection />
<div className="grid gap-4 pb-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
<div key={i} className="bg-muted/30 rounded-3xl p-4 h-[180px] w-full">
<Skeleton className="h-12 w-12 rounded-2xl mb-3" />
<Skeleton className="h-5 w-3/4 mb-2" />
<Skeleton className="h-10 w-full mb-3" />
<Skeleton className="h-8 w-full mt-auto" />
<div key={i} className="bg-muted/30 rounded-3xl p-4 h-auto w-full flex items-center">
<Skeleton className="w-12 h-12 rounded-xl" />
<Skeleton className="h-6 w-1/2 ml-4" />
</div>
))}
</div>

View File

@ -0,0 +1,146 @@
import { parseToolResult } from '../tool-result-parser';
export interface McpTool {
name: string;
description: string;
inputSchema?: any;
}
export interface ProfileInfo {
profile_name: string;
toolkit_name: string;
toolkit_slug: string;
is_connected: boolean;
}
export interface DiscoverUserMcpServersData {
profile_id: string | null;
message: string | null;
profile_info: ProfileInfo | null;
tools: McpTool[];
total_tools: number;
success?: boolean;
timestamp?: string;
}
const parseContent = (content: any): any => {
if (typeof content === 'string') {
try {
return JSON.parse(content);
} catch (e) {
return content;
}
}
return content;
};
export function extractDiscoverUserMcpServersData(
assistantContent?: string,
toolContent?: any,
isSuccess?: boolean,
toolTimestamp?: string,
assistantTimestamp?: string
): DiscoverUserMcpServersData & {
actualIsSuccess: boolean;
actualToolTimestamp: string | undefined;
actualAssistantTimestamp: string | undefined;
} {
const defaultResult: DiscoverUserMcpServersData & {
actualIsSuccess: boolean;
actualToolTimestamp: string | undefined;
actualAssistantTimestamp: string | undefined;
} = {
profile_id: null,
message: null,
profile_info: null,
tools: [],
total_tools: 0,
actualIsSuccess: isSuccess || false,
actualToolTimestamp: toolTimestamp,
actualAssistantTimestamp: assistantTimestamp
};
try {
if (toolContent) {
let content = toolContent;
if (typeof toolContent === 'string') {
try {
content = JSON.parse(toolContent);
} catch (e) {
content = toolContent;
}
}
if (content && typeof content === 'object' && content.content) {
try {
const nestedContent = typeof content.content === 'string' ? JSON.parse(content.content) : content.content;
content = nestedContent;
} catch (e) {
}
}
if (content && typeof content === 'object' && content.tool_execution) {
const toolExecution = content.tool_execution;
if (toolExecution.result && toolExecution.result.success) {
const args = toolExecution.arguments;
const output = toolExecution.result.output;
if (args && output) {
return {
...defaultResult,
profile_id: args.profile_id || null,
message: output.message || null,
profile_info: output.profile_info || null,
tools: output.tools || [],
total_tools: output.total_tools || 0,
actualIsSuccess: true
};
}
}
}
if (content && typeof content === 'object' && content.tool === 'discover-user-mcp-servers') {
const parameters = content.parameters;
const output = content.output;
if (parameters && output) {
return {
...defaultResult,
profile_id: parameters.profile_id || null,
message: output.message || null,
profile_info: output.profile_info || null,
tools: output.tools || [],
total_tools: output.total_tools || 0,
actualIsSuccess: output.success !== false
};
}
}
}
if (assistantContent) {
const parsed = parseToolResult(assistantContent);
if (parsed && parsed.isSuccess) {
const toolOutput = parseContent(parsed.toolOutput);
const args = parsed.arguments;
if (args && toolOutput) {
return {
...defaultResult,
profile_id: args.profile_id || null,
message: toolOutput.message || null,
profile_info: toolOutput.profile_info || null,
tools: toolOutput.tools || [],
total_tools: toolOutput.total_tools || 0,
actualIsSuccess: true
};
}
}
}
return defaultResult;
} catch (error) {
console.error('Error extracting discover user mcp servers data:', error);
return defaultResult;
}
}

View File

@ -0,0 +1,264 @@
import React from 'react';
import {
Search,
CheckCircle,
AlertTriangle,
Plug,
Zap,
Package,
Link2,
Wrench,
ChevronRight,
Database
} from 'lucide-react';
import { ToolViewProps } from '../types';
import { formatTimestamp, getToolTitle } from '../utils';
import { cn } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from "@/components/ui/scroll-area";
import { LoadingState } from '../shared/LoadingState';
import { Separator } from "@/components/ui/separator";
import { extractDiscoverUserMcpServersData, McpTool } from './_utils';
export function DiscoverUserMcpServersToolView({
name = 'discover-user-mcp-servers',
assistantContent,
toolContent,
assistantTimestamp,
toolTimestamp,
isSuccess = true,
isStreaming = false,
}: ToolViewProps) {
const {
profile_id,
message,
profile_info,
tools,
total_tools,
actualIsSuccess,
actualToolTimestamp,
actualAssistantTimestamp
} = extractDiscoverUserMcpServersData(
assistantContent,
toolContent,
isSuccess,
toolTimestamp,
assistantTimestamp
);
const toolTitle = getToolTitle(name);
const formatToolName = (toolName: string): string => {
return toolName
.replace(/^LINEAR_/, '')
.replace(/_/g, ' ')
.split(' ')
.map(word => word.charAt(0) + word.slice(1).toLowerCase())
.join(' ');
};
const getToolCategory = (toolName: string): string => {
if (toolName.includes('CREATE')) return 'Create';
if (toolName.includes('UPDATE')) return 'Update';
if (toolName.includes('DELETE') || toolName.includes('REMOVE')) return 'Delete';
if (toolName.includes('GET') || toolName.includes('LIST')) return 'Read';
if (toolName.includes('RUN')) return 'Advanced';
return 'Other';
};
const getCategoryIcon = (category: string) => {
switch (category) {
case 'Create':
return <span className="text-green-500">+</span>;
case 'Update':
return <span className="text-blue-500"></span>;
case 'Delete':
return <span className="text-red-500">×</span>;
case 'Read':
return <span className="text-purple-500"></span>;
case 'Advanced':
return <span className="text-orange-500"></span>;
default:
return <span className="text-gray-500"></span>;
}
};
const groupToolsByCategory = (tools: McpTool[]) => {
const grouped: Record<string, McpTool[]> = {};
tools.forEach(tool => {
const category = getToolCategory(tool.name);
if (!grouped[category]) {
grouped[category] = [];
}
grouped[category].push(tool);
});
return grouped;
};
const groupedTools = groupToolsByCategory(tools);
const categoryOrder = ['Read', 'Create', 'Update', 'Delete', 'Advanced', 'Other'];
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-purple-500/20 to-purple-600/10 border border-purple-500/20">
<Search className="w-5 h-5 text-purple-500 dark:text-purple-400" />
</div>
<div>
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
{toolTitle}
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3" />
) : (
<AlertTriangle className="h-3 w-3" />
)}
{actualIsSuccess ? 'Tools discovered' : 'Discovery failed'}
</Badge>
)}
</div>
</CardHeader>
<CardContent className="p-0 h-full flex-1 overflow-hidden relative">
{isStreaming ? (
<LoadingState
icon={Search}
iconColor="text-purple-500 dark:text-purple-400"
bgColor="bg-gradient-to-b from-purple-100 to-purple-50 shadow-inner dark:from-purple-800/40 dark:to-purple-900/60 dark:shadow-purple-950/20"
title="Discovering MCP tools"
showProgress={true}
/>
) : actualIsSuccess && profile_info ? (
<ScrollArea className="h-full w-full">
<div className="p-4 space-y-4">
<div className="border rounded-xl p-4 space-y-4">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-purple-100 to-purple-50 dark:from-purple-900/40 dark:to-purple-800/20 border border-purple-200 dark:border-purple-800 flex items-center justify-center">
<Plug className="w-6 h-6 text-purple-600 dark:text-purple-400" />
</div>
<div>
<h3 className="font-semibold text-lg text-zinc-900 dark:text-zinc-100">
{profile_info.profile_name}
</h3>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
{profile_info.toolkit_name} Integration
</p>
</div>
</div>
<div className="flex items-center gap-2">
<Badge
variant={profile_info.is_connected ? "default" : "secondary"}
className={cn(
"text-xs",
profile_info.is_connected
? "bg-green-100 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800"
: "bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-900/20 dark:text-gray-300 dark:border-gray-800"
)}
>
{profile_info.is_connected ? (
<>
<Link2 className="h-3 w-3 mr-1" />
Connected
</>
) : 'Disconnected'}
</Badge>
</div>
</div>
</div>
{tools.length > 0 && (
<div className="border rounded-xl p-4 space-y-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Wrench className="w-4 h-4 text-zinc-600 dark:text-zinc-400" />
<h4 className="font-medium text-zinc-900 dark:text-zinc-100">
Discovered Tools
</h4>
</div>
<Badge variant="outline" className="text-xs">
{total_tools} available
</Badge>
</div>
<Separator />
<div className="space-y-4">
{categoryOrder.map(category => {
if (!groupedTools[category] || groupedTools[category].length === 0) return null;
return (
<div key={category} className="space-y-2">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300">
<span className="w-5 h-5 flex items-center justify-center">
{getCategoryIcon(category)}
</span>
<span>{category} Operations</span>
<Badge variant="secondary" className="text-xs ml-auto">
{groupedTools[category].length}
</Badge>
</div>
<div className="space-y-2 pl-7">
{groupedTools[category].map((tool, index) => (
<div key={index} className="border rounded-lg p-3 space-y-2 bg-zinc-50/50 dark:bg-zinc-800/30">
<div className="flex items-start justify-between gap-2">
<div className="flex-1 space-y-1">
<div className="flex items-center gap-2">
<Zap className="w-3 h-3 text-purple-500 dark:text-purple-400" />
<p className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
{formatToolName(tool.name)}
</p>
</div>
<p className="text-xs text-zinc-600 dark:text-zinc-400 pl-5">
{tool.description}
</p>
</div>
</div>
</div>
))}
</div>
</div>
);
})}
</div>
</div>
)}
{tools.length === 0 && (
<div className="border rounded-xl p-6 text-center">
<Package className="w-12 h-12 mx-auto text-zinc-400 dark:text-zinc-600 mb-3" />
<p className="text-sm text-zinc-600 dark:text-zinc-400">
No tools discovered for this profile
</p>
</div>
)}
</div>
</ScrollArea>
) : (
<div className="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg m-4">
<p className="text-sm text-red-800 dark:text-red-200 flex items-center gap-2">
<AlertTriangle className="h-4 w-4" />
Failed to discover MCP tools. Please check the profile configuration.
</p>
</div>
)}
</CardContent>
</Card>
);
}

View File

@ -0,0 +1,189 @@
import { parseToolResult } from '../tool-result-parser';
export interface UpdateAgentData {
name: string | null;
description?: string | null;
system_prompt: string | null;
agentpress_tools: Record<string, boolean> | null;
configured_mcps?: any[] | null;
is_default?: boolean;
icon_name?: string | null;
icon_color?: string | null;
icon_background?: string | null;
agent?: {
agent_id: string;
account_id: string;
name: string;
description?: string | null;
is_default: boolean;
created_at: string;
updated_at: string;
is_public: boolean;
tags: string[];
current_version_id: string;
version_count: number;
metadata: Record<string, any>;
icon_name: string;
icon_color: string;
icon_background: string;
} | null;
updated_fields?: string[];
version_created?: boolean;
message?: string;
success?: boolean;
timestamp?: string;
}
const parseContent = (content: any): any => {
if (typeof content === 'string') {
try {
return JSON.parse(content);
} catch (e) {
return content;
}
}
return content;
};
export function extractUpdateAgentData(
assistantContent?: string,
toolContent?: any,
isSuccess?: boolean,
toolTimestamp?: string,
assistantTimestamp?: string
): UpdateAgentData & {
actualIsSuccess: boolean;
actualToolTimestamp: string | undefined;
actualAssistantTimestamp: string | undefined;
} {
const defaultResult: UpdateAgentData & {
actualIsSuccess: boolean;
actualToolTimestamp: string | undefined;
actualAssistantTimestamp: string | undefined;
} = {
name: null,
description: null,
system_prompt: null,
agentpress_tools: null,
configured_mcps: null,
is_default: false,
icon_name: null,
icon_color: null,
icon_background: null,
agent: null,
updated_fields: [],
version_created: false,
message: null,
actualIsSuccess: isSuccess || false,
actualToolTimestamp: toolTimestamp,
actualAssistantTimestamp: assistantTimestamp
};
try {
if (toolContent) {
let content = toolContent;
if (typeof toolContent === 'string') {
try {
content = JSON.parse(toolContent);
} catch (e) {
content = toolContent;
}
}
if (content && typeof content === 'object' && content.content) {
try {
const nestedContent = typeof content.content === 'string' ? JSON.parse(content.content) : content.content;
content = nestedContent;
} catch (e) {
}
}
if (content && typeof content === 'object' && content.tool_execution) {
const toolExecution = content.tool_execution;
if (toolExecution.result && toolExecution.result.success) {
const args = toolExecution.arguments;
const output = toolExecution.result.output;
if (args && output) {
return {
...defaultResult,
name: args.name || null,
description: args.description || null,
system_prompt: args.system_prompt || null,
agentpress_tools: args.agentpress_tools || null,
configured_mcps: args.configured_mcps || null,
is_default: args.is_default || false,
icon_name: args.icon_name || null,
icon_color: args.icon_color || null,
icon_background: args.icon_background || null,
agent: output.agent || null,
updated_fields: output.updated_fields || [],
version_created: output.version_created || false,
message: output.message || null,
actualIsSuccess: true
};
}
}
}
if (content && typeof content === 'object' && content.tool === 'update-agent') {
const parameters = content.parameters;
const output = content.output;
if (parameters && output) {
return {
...defaultResult,
name: parameters.name || null,
description: parameters.description || null,
system_prompt: parameters.system_prompt || null,
agentpress_tools: parameters.agentpress_tools || null,
configured_mcps: parameters.configured_mcps || null,
is_default: parameters.is_default || false,
icon_name: parameters.icon_name || null,
icon_color: parameters.icon_color || null,
icon_background: parameters.icon_background || null,
agent: output.agent || null,
updated_fields: output.updated_fields || [],
version_created: output.version_created || false,
message: output.message || null,
actualIsSuccess: output.success !== false
};
}
}
}
if (assistantContent) {
const parsed = parseToolResult(assistantContent);
if (parsed && parsed.isSuccess) {
const toolOutput = parseContent(parsed.toolOutput);
const args = parsed.arguments;
if (args && toolOutput) {
return {
...defaultResult,
name: args.name || null,
description: args.description || null,
system_prompt: args.system_prompt || null,
agentpress_tools: args.agentpress_tools || null,
configured_mcps: args.configured_mcps || null,
is_default: args.is_default || false,
icon_name: args.icon_name || null,
icon_color: args.icon_color || null,
icon_background: args.icon_background || null,
agent: toolOutput.agent || null,
updated_fields: toolOutput.updated_fields || [],
version_created: toolOutput.version_created || false,
message: toolOutput.message || null,
actualIsSuccess: true
};
}
}
}
return defaultResult;
} catch (error) {
console.error('Error extracting update agent data:', error);
return defaultResult;
}
}

View File

@ -0,0 +1,274 @@
import React from 'react';
import {
Bot,
CheckCircle,
AlertTriangle,
Calendar,
Sparkles,
User,
RefreshCw,
History,
Edit3
} from 'lucide-react';
import { ToolViewProps } from '../types';
import { formatTimestamp, getToolTitle } from '../utils';
import { cn } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from "@/components/ui/scroll-area";
import { LoadingState } from '../shared/LoadingState';
import { Separator } from "@/components/ui/separator";
import { extractUpdateAgentData } from './_utils';
import { AgentAvatar } from '../../content/agent-avatar';
export function UpdateAgentToolView({
name = 'update-agent',
assistantContent,
toolContent,
assistantTimestamp,
toolTimestamp,
isSuccess = true,
isStreaming = false,
}: ToolViewProps) {
const {
name: agentName,
description,
system_prompt,
icon_name,
icon_color,
icon_background,
agentpress_tools,
configured_mcps,
is_default,
agent,
updated_fields,
version_created,
message,
actualIsSuccess,
actualToolTimestamp,
actualAssistantTimestamp
} = extractUpdateAgentData(
assistantContent,
toolContent,
isSuccess,
toolTimestamp,
assistantTimestamp
);
const toolTitle = getToolTitle(name);
const getEnabledToolsCount = () => {
if (!agentpress_tools) return 0;
return Object.values(agentpress_tools).filter(Boolean).length;
};
const formatFieldName = (field: string): string => {
return field
.split('_')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
};
const displayName = agent?.name || agentName;
const displayIconName = agent?.icon_name || icon_name;
const displayIconColor = agent?.icon_color || icon_color;
const displayIconBackground = agent?.icon_background || icon_background;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<RefreshCw className="w-5 h-5 text-blue-500 dark:text-blue-400" />
</div>
<div>
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
{toolTitle}
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3" />
) : (
<AlertTriangle className="h-3 w-3" />
)}
{actualIsSuccess ? 'Agent updated' : 'Update failed'}
</Badge>
)}
</div>
</CardHeader>
<CardContent className="p-0 h-full flex-1 overflow-hidden relative">
{isStreaming ? (
<LoadingState
icon={RefreshCw}
iconColor="text-blue-500 dark:text-blue-400"
bgColor="bg-gradient-to-b from-blue-100 to-blue-50 shadow-inner dark:from-blue-800/40 dark:to-blue-900/60 dark:shadow-blue-950/20"
title="Updating agent"
filePath={displayName ? `"${displayName}"` : undefined}
showProgress={true}
/>
) : actualIsSuccess && agent ? (
<ScrollArea className="h-full w-full">
<div className="p-4 space-y-4">
<div className="border rounded-xl p-4 space-y-4">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<AgentAvatar
iconName={displayIconName}
iconColor={displayIconColor}
backgroundColor={displayIconBackground}
agentName={displayName}
size={48}
/>
<div>
<h3 className="font-semibold text-zinc-900 dark:text-zinc-100">
{displayName}
</h3>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
Custom AI Agent
</p>
</div>
</div>
<div className="flex items-center gap-2">
{version_created && (
<Badge variant="outline" className="text-xs">
<History className="w-3 h-3 mr-1" />
v{agent.version_count}
</Badge>
)}
{is_default && (
<Badge variant="outline" className="text-xs">
<Sparkles className="w-3 h-3 mr-1" />
Default
</Badge>
)}
<Badge variant="secondary" className="text-xs bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800">
Active
</Badge>
</div>
</div>
{description && (
<div>
<h4 className="text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">Description</h4>
<p className="text-sm text-zinc-600 dark:text-zinc-400 leading-relaxed">
{description}
</p>
</div>
)}
{updated_fields && updated_fields.length > 0 && (
<>
<Separator />
<div className="space-y-2">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-900 dark:text-zinc-100">
<Edit3 className="w-4 h-4" />
Updated Fields
</div>
<div className="flex flex-wrap gap-2">
{updated_fields.map((field, index) => (
<Badge key={index} variant="outline" className="text-xs">
{formatFieldName(field)}
</Badge>
))}
</div>
{version_created && (
<div className="text-xs text-zinc-600 dark:text-zinc-400 mt-2">
<div className="flex items-center gap-1">
<History className="w-3 h-3" />
New version created (Version {agent.version_count})
</div>
</div>
)}
</div>
</>
)}
<Separator />
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="space-y-1">
<div className="flex items-center gap-2 text-zinc-500 dark:text-zinc-400">
<Calendar className="w-3 h-3" />
<span>Created</span>
</div>
<p className="text-zinc-700 dark:text-zinc-300 pl-5">
{new Date(agent.created_at).toLocaleDateString()}
</p>
</div>
<div className="space-y-1">
<div className="flex items-center gap-2 text-zinc-500 dark:text-zinc-400">
<RefreshCw className="w-3 h-3" />
<span>Updated</span>
</div>
<p className="text-zinc-700 dark:text-zinc-300 pl-5">
{new Date(agent.updated_at).toLocaleDateString()} at{' '}
{new Date(agent.updated_at).toLocaleTimeString()}
</p>
</div>
</div>
</div>
{system_prompt && (
<div className="border rounded-xl p-4 space-y-3">
<h4 className="text-sm font-medium text-zinc-900 dark:text-zinc-100 flex items-center gap-2">
<User className="w-4 h-4" />
System Prompt Preview
</h4>
<div className="bg-muted/50 rounded-lg p-3 text-xs text-zinc-600 dark:text-zinc-400 font-mono max-h-32 overflow-y-auto">
{system_prompt.substring(0, 200)}
{system_prompt.length > 200 && '...'}
</div>
</div>
)}
{agentpress_tools && (
<div className="border rounded-xl p-4 space-y-3">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Tool Configuration
</h4>
<Badge variant="outline" className="text-xs">
{getEnabledToolsCount()} enabled
</Badge>
</div>
<div className="text-xs text-zinc-600 dark:text-zinc-400">
Agent has access to {getEnabledToolsCount()} tools out of {Object.keys(agentpress_tools).length} available tools
</div>
</div>
)}
{message && (
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
<p className="text-sm text-blue-800 dark:text-blue-200 flex items-center gap-2">
<CheckCircle className="h-4 w-4" />
{message}
</p>
</div>
)}
</div>
</ScrollArea>
) : (
<div className="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg m-4">
<p className="text-sm text-red-800 dark:text-red-200 flex items-center gap-2">
<AlertTriangle className="h-4 w-4" />
Failed to update agent. Please try again.
</p>
</div>
)}
</CardContent>
</Card>
);
}

View File

@ -78,10 +78,12 @@ export function getToolTitle(toolName: string): string {
// Agent Creation Tools
'create-new-agent': 'Create New Agent',
'update-agent': 'Update Agent',
'search-mcp-servers-for-agent': 'Search MCP Servers for Agent',
'get-mcp-server-details': 'Get MCP Server Details',
'create-credential-profile-for-agent': 'Create Credential Profile for Agent',
'discover-mcp-tools-for-agent': 'Discover MCP Tools for Agent',
'discover-user-mcp-servers': 'Discovering tools',
'configure-agent-integration': 'Configure Agent Integration',
'list-available-integrations': 'List Available Integrations',
'create-agent-scheduled-trigger': 'Create Scheduled Trigger',
@ -1306,6 +1308,10 @@ export function getToolComponent(toolName: string): string {
return 'GetCredentialProfilesToolView';
case 'get-current-agent-config':
return 'GetCurrentAgentConfigToolView';
case 'update-agent':
return 'UpdateAgentToolView';
case 'discover-user-mcp-servers':
return 'DiscoverUserMcpServersToolView';
//Deploy
case 'deploy':

View File

@ -47,9 +47,11 @@ import { DesignerToolView } from '../designer-tool/DesignerToolView';
import { UploadFileToolView } from '../UploadFileToolView';
import { DocsToolView, ListDocumentsToolView, DeleteDocumentToolView } from '../docs-tool';
import { CreateNewAgentToolView } from '../create-new-agent/create-new-agent';
import { UpdateAgentToolView } from '../update-agent/update-agent';
import { SearchMcpServersForAgentToolView } from '../search-mcp-servers-for-agent/search-mcp-servers-for-agent';
import { CreateCredentialProfileForAgentToolView } from '../create-credential-profile-for-agent/create-credential-profile-for-agent';
import { DiscoverMcpToolsForAgentToolView } from '../discover-mcp-tools-for-agent/discover-mcp-tools-for-agent';
import { DiscoverUserMcpServersToolView } from '../discover-user-mcp-servers/discover-user-mcp-servers';
import { ConfigureAgentIntegrationToolView } from '../configure-agent-integration/configure-agent-integration';
import CreateAgentScheduledTriggerToolView from '../create-agent-scheduled-trigger/create-agent-scheduled-trigger';
import { createPresentationViewerToolContent, parsePresentationSlidePath } from '../utils/presentation-utils';
@ -189,9 +191,11 @@ const defaultRegistry: ToolViewRegistryType = {
'default': GenericToolView,
'create-new-agent': CreateNewAgentToolView,
'update-agent': UpdateAgentToolView,
'search-mcp-servers-for-agent': SearchMcpServersForAgentToolView,
'create-credential-profile-for-agent': CreateCredentialProfileForAgentToolView,
'discover-mcp-tools-for-agent': DiscoverMcpToolsForAgentToolView,
'discover-user-mcp-servers': DiscoverUserMcpServersToolView,
'configure-agent-integration': ConfigureAgentIntegrationToolView,
'create-agent-scheduled-trigger': CreateAgentScheduledTriggerToolView,
};

View File

@ -399,10 +399,12 @@ const TOOL_DISPLAY_NAMES = new Map([
['update_agent', 'Updating Agent'],
['get_current_agent_config', 'Getting Agent Config'],
['search_mcp_servers', 'Searching MCP Servers'],
['get_mcp_server_tools', 'Getting MCP Server Tools'],
['configure_mcp_server', 'Configuring MCP Server'],
['get_popular_mcp_servers', 'Getting Popular MCP Servers'],
['test_mcp_server_connection', 'Testing MCP Server Connection'],
['discover-user-mcp-servers', 'Discovering tools'],
['create-credential-profile', 'Creating profile'],
['get-credential-profiles', 'Getting profiles'],
['configure-profile-for-agent', 'Adding tools to agent'],
['create-new-agent', 'Creating New Agent'],

View File

@ -32,6 +32,8 @@ export const useAgent = (agentId: string) => {
enabled: !!agentId,
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
refetchOnMount: 'always',
refetchOnWindowFocus: true,
}
)();
};

View File

@ -263,31 +263,35 @@ export function useAgentStream(
});
if (agentId) {
// Core agent data
queryClient.invalidateQueries({ queryKey: agentKeys.all });
queryClient.invalidateQueries({ queryKey: agentKeys.detail(agentId) });
queryClient.invalidateQueries({ queryKey: agentKeys.lists() });
queryClient.invalidateQueries({ queryKey: agentKeys.details() });
// Agent tools and integrations
queryClient.invalidateQueries({ queryKey: ['agent-tools', agentId] });
queryClient.invalidateQueries({
queryKey: ['custom-mcp-tools', agentId],
});
queryClient.invalidateQueries({ queryKey: ['agent-tools'] });
// MCP configurations
queryClient.invalidateQueries({ queryKey: ['custom-mcp-tools', agentId] });
queryClient.invalidateQueries({ queryKey: ['custom-mcp-tools'] });
queryClient.invalidateQueries({ queryKey: composioKeys.mcpServers() });
queryClient.invalidateQueries({
queryKey: composioKeys.profiles.all(),
});
queryClient.invalidateQueries({
queryKey: composioKeys.profiles.credentials(),
});
queryClient.invalidateQueries({ queryKey: composioKeys.profiles.all() });
queryClient.invalidateQueries({ queryKey: composioKeys.profiles.credentials() });
// Triggers
queryClient.invalidateQueries({ queryKey: ['triggers', agentId] });
queryClient.invalidateQueries({
queryKey: knowledgeBaseKeys.agent(agentId),
});
// Invalidate versioning queries for agent config page
queryClient.invalidateQueries({ queryKey: ['triggers'] });
// Knowledge base
queryClient.invalidateQueries({ queryKey: knowledgeBaseKeys.agent(agentId) });
queryClient.invalidateQueries({ queryKey: knowledgeBaseKeys.all });
queryClient.invalidateQueries({ queryKey: ['versions'] });
queryClient.invalidateQueries({ queryKey: ['versions', 'list'] });
queryClient.invalidateQueries({ queryKey: ['versions', 'list', agentId] });
// Invalidate current version details if available
queryClient.invalidateQueries({ queryKey: ['versions', 'detail'] });
queryClient.invalidateQueries({
queryKey: ['versions', 'detail'],
predicate: (query) => {
@ -295,7 +299,14 @@ export function useAgentStream(
}
});
console.log(`[useAgentStream] Invalidated agent queries for refetch instead of page reload - Agent ID: ${agentId}`);
// Invalidate any version store cache
queryClient.invalidateQueries({ queryKey: ['version-store'] });
// Force refetch of agent configuration data
queryClient.refetchQueries({ queryKey: agentKeys.detail(agentId) });
queryClient.refetchQueries({ queryKey: ['versions', 'list', agentId] });
console.log(`[useAgentStream] Comprehensively invalidated and refetched all agent queries for Agent ID: ${agentId}`);
}
if (

View File

@ -36,6 +36,8 @@ export const useAgentVersions = (agentId: string) => {
},
enabled: !!agentId,
staleTime: 30000,
refetchOnMount: 'always',
refetchOnWindowFocus: true,
});
};
@ -50,6 +52,8 @@ export const useAgentVersion = (agentId: string, versionId: string | null | unde
},
enabled: !!agentId && !!versionId,
staleTime: 30000,
refetchOnMount: 'always',
refetchOnWindowFocus: true,
});
};