初始化模版工程

This commit is contained in:
Cloud Bot
2026-03-20 07:33:46 +00:00
commit 23717e0ecd
386 changed files with 51675 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
import React from 'react'
import {
Code,
Terminal,
Search,
FileCode,
Globe,
FileText,
FileEdit,
Image,
GalleryHorizontal,
Puzzle,
Bot,
RefreshCw,
Eye,
Layers,
Wrench,
} from 'lucide-react'
import { cn } from '@/utils/cn'
import type { ApiEvent } from '../../types'
import { SILENT_ACTION_TYPES } from './utils'
export interface ToolCallActionProps {
name?: string
arguments?: string[]
action_type?: string
event?: ApiEvent
onClick?: (event: ApiEvent) => void
}
// ─── action_type → { icon, label } ──────────────────────────────────────────
const ACTION_TYPE_META: Record<string, { icon: React.ReactNode; label: string }> = {
shell_execute: { icon: <Terminal className="w-4 h-4" />, label: '执行命令' },
terminal_operator: { icon: <Terminal className="w-4 h-4" />, label: '终端操作' },
code_execute: { icon: <Code className="w-4 h-4" />, label: '运行代码' },
file_operator: { icon: <FileCode className="w-4 h-4" />, label: '文件操作' },
file_create: { icon: <FileText className="w-4 h-4" />, label: '创建文件' },
file_read: { icon: <FileText className="w-4 h-4" />, label: '读取文件' },
file_replace_text: { icon: <FileEdit className="w-4 h-4" />, label: '编辑文件' },
file_write_text: { icon: <FileEdit className="w-4 h-4" />, label: '写入文件' },
str_replace: { icon: <FileEdit className="w-4 h-4" />, label: '替换内容' },
info_search_web: { icon: <Search className="w-4 h-4" />, label: '搜索网页' },
info_fetch_webpage: { icon: <Globe className="w-4 h-4" />, label: '获取网页' },
news_search: { icon: <Search className="w-4 h-4" />, label: '新闻搜索' },
image_search: { icon: <Image className="w-4 h-4" />, label: '图片搜索' },
info_search_custom_knowledge: { icon: <Search className="w-4 h-4" />, label: '知识检索' },
search_custom_knowledge: { icon: <Search className="w-4 h-4" />, label: '知识检索' },
browser_use: { icon: <Globe className="w-4 h-4" />, label: '浏览器操作' },
slide_init: { icon: <GalleryHorizontal className="w-4 h-4" />, label: '初始化幻灯片' },
slide_template: { icon: <GalleryHorizontal className="w-4 h-4" />, label: '选择模板' },
slide_create: { icon: <GalleryHorizontal className="w-4 h-4" />, label: '生成幻灯片' },
slide_create_batch: { icon: <Layers className="w-4 h-4" />, label: '批量生成幻灯片' },
slide_present: { icon: <GalleryHorizontal className="w-4 h-4" />, label: '展示幻灯片' },
media_generate_image: { icon: <Image className="w-4 h-4" />, label: '生成图片' },
media_vision_image: { icon: <Eye className="w-4 h-4" />, label: '识别图片' },
generate_image: { icon: <Image className="w-4 h-4" />, label: '生成图片' },
call_flow: { icon: <RefreshCw className="w-4 h-4" />, label: '调用流程' },
integrated_app: { icon: <Puzzle className="w-4 h-4" />, label: '集成应用' },
custom_api: { icon: <Wrench className="w-4 h-4" />, label: '自定义工具' },
skill_loader: { icon: <Bot className="w-4 h-4" />, label: '加载技能' },
brand_search: { icon: <Search className="w-4 h-4" />, label: '品牌检索' },
xiaohongshu_search: { icon: <Search className="w-4 h-4" />, label: '小红书搜索' },
e_commerce: { icon: <Search className="w-4 h-4" />, label: '电商搜索' },
experience_query: { icon: <Search className="w-4 h-4" />, label: '经验查询' },
writer: { icon: <FileEdit className="w-4 h-4" />, label: '文档创作' },
parallel_map: { icon: <Layers className="w-4 h-4" />, label: '并行任务' },
media_comments: { icon: <Search className="w-4 h-4" />, label: '媒体搜索' },
system_api: { icon: <Wrench className="w-4 h-4" />, label: '系统接口' },
}
/**
* 工具调用 Action 组件
* - 静默事件类型 → 不渲染
* - name / label / argsText 全空 → 不渲染
* - 点击触发外部 onClick打开右侧面板
*/
export function ToolCallAction({
name,
arguments: args,
action_type,
event,
onClick,
}: ToolCallActionProps) {
// 静默类型直接跳过
if (action_type && SILENT_ACTION_TYPES.has(action_type)) return null
const meta = action_type ? ACTION_TYPE_META[action_type] : undefined
const icon = meta?.icon ?? <Code className="w-4 h-4" />
const label = name || meta?.label || ''
const argsText = args?.filter(Boolean).join(' ') || ''
// 没有任何可展示内容时不渲染
if (!label && !argsText) return null
const handleClick = () => {
if (event && onClick) onClick(event)
}
const isClickable = !!(event && onClick)
return (
<div
className={cn(
'inline-flex items-center gap-2 px-3 py-1.5 rounded-lg max-w-full mb-2',
'border border-gray-200 bg-white/80',
'text-sm',
isClickable && 'cursor-pointer transition-all duration-150 hover:bg-gray-50 hover:border-gray-300',
)}
onClick={isClickable ? handleClick : undefined}
role={isClickable ? 'button' : undefined}
tabIndex={isClickable ? 0 : undefined}
onKeyDown={
isClickable
? e => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
handleClick()
}
}
: undefined
}
>
<span className="shrink-0 text-gray-500">{icon}</span>
{label && <span className="shrink-0 font-medium text-gray-800">{label}:</span>}
{argsText && (
<code className="min-w-0 flex-1 truncate font-mono text-xs text-gray-500">
{argsText}
</code>
)}
</div>
)
}