feat(desktop): wire template welcome_message + quick_commands to chat UI
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Add welcomeMessage/quickCommands fields to Clone interface - Persist template welcome/quick data via updateClone after creation - FirstConversationPrompt: prefer template-provided welcome message over dynamically generated one - FirstConversationPrompt: render template quick_commands as chips instead of hardcoded QUICK_ACTIONS when available - Tighten assign/unassign template endpoint permissions from model:read to relay:use (self-service operation for all authenticated users)
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
Microscope,
|
||||
Layers,
|
||||
GraduationCap,
|
||||
MessageSquare,
|
||||
} from 'lucide-react';
|
||||
import { cn } from '../lib/utils';
|
||||
import {
|
||||
@@ -63,13 +64,15 @@ export function FirstConversationPrompt({
|
||||
ultra: '多代理协作,全能力调度',
|
||||
};
|
||||
|
||||
const welcomeMessage = generateWelcomeMessage({
|
||||
userName: clone.userName,
|
||||
agentName: clone.nickname || clone.name,
|
||||
emoji: clone.emoji,
|
||||
personality: clone.personality,
|
||||
scenarios: clone.scenarios,
|
||||
});
|
||||
// Use template-provided welcome message if available, otherwise generate dynamically
|
||||
const welcomeMessage = clone.welcomeMessage
|
||||
|| generateWelcomeMessage({
|
||||
userName: clone.userName,
|
||||
agentName: clone.nickname || clone.name,
|
||||
emoji: clone.emoji,
|
||||
personality: clone.personality,
|
||||
scenarios: clone.scenarios,
|
||||
});
|
||||
|
||||
const handleQuickAction = (key: string) => {
|
||||
if (key === 'learn') {
|
||||
@@ -149,32 +152,54 @@ export function FirstConversationPrompt({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Quick action chips — DeerFlow-style horizontal colored pills */}
|
||||
{/* Quick action chips — template-provided or DeerFlow-style defaults */}
|
||||
<div className="flex items-center justify-center gap-2 flex-wrap">
|
||||
{QUICK_ACTIONS.map((action, index) => {
|
||||
const ActionIcon = action.icon;
|
||||
return (
|
||||
<motion.button
|
||||
key={action.key}
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.05, duration: 0.2 }}
|
||||
onClick={() => handleQuickAction(action.key)}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-4 py-2',
|
||||
'bg-white dark:bg-gray-800',
|
||||
'border border-gray-200 dark:border-gray-700',
|
||||
'rounded-full text-sm text-gray-600 dark:text-gray-300',
|
||||
'hover:border-gray-300 dark:hover:border-gray-600',
|
||||
'hover:bg-gray-50 dark:hover:bg-gray-750',
|
||||
'transition-all duration-150'
|
||||
)}
|
||||
>
|
||||
<ActionIcon className={`w-4 h-4 ${action.color}`} />
|
||||
<span>{action.label}</span>
|
||||
</motion.button>
|
||||
);
|
||||
})}
|
||||
{clone.quickCommands && clone.quickCommands.length > 0
|
||||
? clone.quickCommands.map((cmd, index) => (
|
||||
<motion.button
|
||||
key={cmd.label}
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.05, duration: 0.2 }}
|
||||
onClick={() => onSelectSuggestion?.(cmd.command)}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-4 py-2',
|
||||
'bg-white dark:bg-gray-800',
|
||||
'border border-gray-200 dark:border-gray-700',
|
||||
'rounded-full text-sm text-gray-600 dark:text-gray-300',
|
||||
'hover:border-gray-300 dark:hover:border-gray-600',
|
||||
'hover:bg-gray-50 dark:hover:bg-gray-750',
|
||||
'transition-all duration-150'
|
||||
)}
|
||||
>
|
||||
<MessageSquare className="w-4 h-4 text-primary" />
|
||||
<span>{cmd.label}</span>
|
||||
</motion.button>
|
||||
))
|
||||
: QUICK_ACTIONS.map((action, index) => {
|
||||
const ActionIcon = action.icon;
|
||||
return (
|
||||
<motion.button
|
||||
key={action.key}
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.05, duration: 0.2 }}
|
||||
onClick={() => handleQuickAction(action.key)}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-4 py-2',
|
||||
'bg-white dark:bg-gray-800',
|
||||
'border border-gray-200 dark:border-gray-700',
|
||||
'rounded-full text-sm text-gray-600 dark:text-gray-300',
|
||||
'hover:border-gray-300 dark:hover:border-gray-600',
|
||||
'hover:bg-gray-50 dark:hover:bg-gray-750',
|
||||
'transition-all duration-150'
|
||||
)}
|
||||
>
|
||||
<ActionIcon className={`w-4 h-4 ${action.color}`} />
|
||||
<span>{action.label}</span>
|
||||
</motion.button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Scenario tags */}
|
||||
|
||||
Reference in New Issue
Block a user