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
深端到端验证发现 12 个问题,6 Phase 全栈修复: Phase 5 — 快速 UX 修复: - #9: SimpleSidebar 添加新对话按钮 (SquarePen + useChatStore) - #5: 模型列表 JOIN provider_keys 过滤无 API Key 的模型 - #11: AgentOnboardingWizard 焦点领域增加 4 行业选项 (医疗健康/教育培训/金融财务/法律合规) Phase 1 — ButlerPanel 记忆修复: - #2a: MemorySection URI 从 viking://agent/.../memories/ 修正为 agent://.../ - #2b: "立即分析对话"按钮现在触发 extractAndStoreMemories Phase 2 — FTS5 中文分词: - #4: FTS5 tokenizer 从 unicode61 切换到 trigram,原生支持 CJK - 自动迁移:检测旧 unicode61 表并重建索引 - sanitize_fts_query 支持中文引号短语查询 Phase 3 — 跨会话身份持久化: - #6-8: 重新启用 USER.md 注入系统提示词 (截断前 10 行) Phase 4 — Agent 面板同步: - #1,#10: listClones 从 4 字段扩展到完整映射 (soul/userProfile 解析 nickname/emoji/userName/userRole) - updateClone 通过 identity 系统同步 nickname→SOUL.md 和 userName/userRole→USER.md Phase 6 — Agent 创建容错: - #12: createFromTemplate 增加 SaaS 不可用 fallback 验证: tsc --noEmit ✅ cargo check ✅
385 lines
10 KiB
TypeScript
385 lines
10 KiB
TypeScript
/**
|
||
* Personality Presets Configuration
|
||
*
|
||
* Defines personality styles, scenario tags, and emoji presets for Agent onboarding.
|
||
* Used by AgentOnboardingWizard to provide guided personality setup.
|
||
*/
|
||
|
||
// === Personality Options ===
|
||
|
||
export interface PersonalityOption {
|
||
id: string;
|
||
label: string;
|
||
description: string;
|
||
icon: string; // Icon name for Lucide
|
||
traits: string[];
|
||
communicationStyle: string;
|
||
}
|
||
|
||
export const PERSONALITY_OPTIONS: PersonalityOption[] = [
|
||
{
|
||
id: 'professional',
|
||
label: '专业严谨',
|
||
description: '精确、可靠、技术导向',
|
||
icon: 'Briefcase',
|
||
traits: ['精确', '可靠', '技术导向', '系统化'],
|
||
communicationStyle: '专业、准确、注重细节,提供技术深度和可操作的建议',
|
||
},
|
||
{
|
||
id: 'friendly',
|
||
label: '友好亲切',
|
||
description: '温暖、耐心、易于沟通',
|
||
icon: 'Heart',
|
||
traits: ['温暖', '耐心', '易于沟通', '善解人意'],
|
||
communicationStyle: '亲切、耐心、善解人意,用易懂的语言解释复杂概念',
|
||
},
|
||
{
|
||
id: 'creative',
|
||
label: '创意灵活',
|
||
description: '想象力丰富、善于探索',
|
||
icon: 'Sparkles',
|
||
traits: ['想象力丰富', '善于探索', '思维开放', '创新'],
|
||
communicationStyle: '富有创意、思维开放,鼓励探索新想法和解决方案',
|
||
},
|
||
{
|
||
id: 'concise',
|
||
label: '简洁高效',
|
||
description: '快速、直接、结果导向',
|
||
icon: 'Zap',
|
||
traits: ['快速', '直接', '结果导向', '高效'],
|
||
communicationStyle: '简洁明了、直奔主题,专注于快速解决问题',
|
||
},
|
||
];
|
||
|
||
// === Scenario Tags ===
|
||
|
||
export interface ScenarioTag {
|
||
id: string;
|
||
label: string;
|
||
description: string;
|
||
icon: string; // Icon name for Lucide
|
||
keywords: string[];
|
||
}
|
||
|
||
export const SCENARIO_TAGS: ScenarioTag[] = [
|
||
{
|
||
id: 'coding',
|
||
label: '编程开发',
|
||
description: '代码编写、调试、代码审查',
|
||
icon: 'Code',
|
||
keywords: ['编程', '代码', '开发', '调试', 'Bug', '重构'],
|
||
},
|
||
{
|
||
id: 'writing',
|
||
label: '内容写作',
|
||
description: '文章撰写、文案创作、编辑润色',
|
||
icon: 'PenLine',
|
||
keywords: ['写作', '文案', '文章', '内容', '编辑', '润色'],
|
||
},
|
||
{
|
||
id: 'product',
|
||
label: '产品策划',
|
||
description: '产品规划、需求分析、用户研究',
|
||
icon: 'Package',
|
||
keywords: ['产品', '需求', '用户', '规划', '功能', 'PRD'],
|
||
},
|
||
{
|
||
id: 'data',
|
||
label: '数据分析',
|
||
description: '数据处理、统计分析、可视化',
|
||
icon: 'BarChart',
|
||
keywords: ['数据', '分析', '统计', '图表', '可视化', '报表'],
|
||
},
|
||
{
|
||
id: 'design',
|
||
label: '设计创意',
|
||
description: 'UI/UX设计、视觉设计、原型制作',
|
||
icon: 'Palette',
|
||
keywords: ['设计', 'UI', 'UX', '视觉', '原型', '界面'],
|
||
},
|
||
{
|
||
id: 'healthcare',
|
||
label: '医疗健康',
|
||
description: '医院管理、患者服务、医疗数据分析',
|
||
icon: 'HeartPulse',
|
||
keywords: ['医疗', '医院', '健康', '患者', '临床', '护理', '行政'],
|
||
},
|
||
{
|
||
id: 'education',
|
||
label: '教育培训',
|
||
description: '课程设计、教学辅助、学习规划',
|
||
icon: 'GraduationCap',
|
||
keywords: ['教育', '教学', '课程', '培训', '学习', '考试'],
|
||
},
|
||
{
|
||
id: 'finance',
|
||
label: '金融财务',
|
||
description: '财务分析、风险管理、投资研究',
|
||
icon: 'Landmark',
|
||
keywords: ['金融', '财务', '投资', '风控', '审计', '报表'],
|
||
},
|
||
{
|
||
id: 'devops',
|
||
label: '运维部署',
|
||
description: '系统运维、CI/CD、容器化部署',
|
||
icon: 'Server',
|
||
keywords: ['运维', '部署', 'CI/CD', 'Docker', 'K8s', '服务器'],
|
||
},
|
||
{
|
||
id: 'research',
|
||
label: '研究调研',
|
||
description: '技术调研、文献研究、竞品分析',
|
||
icon: 'Search',
|
||
keywords: ['研究', '调研', '分析', '文献', '竞品', '技术'],
|
||
},
|
||
{
|
||
id: 'marketing',
|
||
label: '营销推广',
|
||
description: '营销策略、内容营销、社媒运营',
|
||
icon: 'Megaphone',
|
||
keywords: ['营销', '推广', '运营', '社媒', '增长', '转化'],
|
||
},
|
||
{
|
||
id: 'legal',
|
||
label: '法律合规',
|
||
description: '合同审查、法规研究、合规管理',
|
||
icon: 'Scale',
|
||
keywords: ['法律', '合同', '合规', '法规', '审查', '风险'],
|
||
},
|
||
{
|
||
id: 'other',
|
||
label: '其他',
|
||
description: '其他用途或综合场景',
|
||
icon: 'MoreHorizontal',
|
||
keywords: [],
|
||
},
|
||
];
|
||
|
||
// === Emoji Presets ===
|
||
|
||
export const EMOJI_PRESETS = {
|
||
animals: ['🦞', '🐱', '🐶', '🦊', '🐼', '🦁', '🐬', '🦄'],
|
||
objects: ['💻', '🚀', '⚡', '🔧', '📚', '🎨', '⭐', '💎'],
|
||
expressions: ['😊', '🤓', '😎', '🤖'],
|
||
};
|
||
|
||
export const ALL_EMOJIS = [
|
||
...EMOJI_PRESETS.animals,
|
||
...EMOJI_PRESETS.objects,
|
||
...EMOJI_PRESETS.expressions,
|
||
];
|
||
|
||
// === Quick Start Suggestions ===
|
||
|
||
export interface QuickStartSuggestion {
|
||
icon: string;
|
||
text: string;
|
||
scenarios: string[]; // Which scenarios this suggestion applies to
|
||
}
|
||
|
||
export const QUICK_START_SUGGESTIONS: QuickStartSuggestion[] = [
|
||
{
|
||
icon: '💡',
|
||
text: '帮我写一个 Python 脚本处理 Excel 文件',
|
||
scenarios: ['coding', 'data'],
|
||
},
|
||
{
|
||
icon: '📊',
|
||
text: '分析这个数据集的趋势和关键指标',
|
||
scenarios: ['data', 'research'],
|
||
},
|
||
{
|
||
icon: '✍️',
|
||
text: '帮我起草一份产品需求文档',
|
||
scenarios: ['product', 'writing'],
|
||
},
|
||
{
|
||
icon: '🔍',
|
||
text: '帮我研究一下这个技术方案的可行性',
|
||
scenarios: ['research', 'coding'],
|
||
},
|
||
{
|
||
icon: '🎨',
|
||
text: '给我一些 UI 设计的创意建议',
|
||
scenarios: ['design'],
|
||
},
|
||
{
|
||
icon: '📝',
|
||
text: '帮我写一篇技术博客文章',
|
||
scenarios: ['writing'],
|
||
},
|
||
{
|
||
icon: '🚀',
|
||
text: '帮我规划一个完整的营销方案',
|
||
scenarios: ['marketing', 'product'],
|
||
},
|
||
{
|
||
icon: '⚙️',
|
||
text: '帮我配置一个自动化部署流程',
|
||
scenarios: ['devops', 'coding'],
|
||
},
|
||
];
|
||
|
||
// === Helper Functions ===
|
||
|
||
/**
|
||
* Get personality option by ID
|
||
*/
|
||
export function getPersonalityById(id: string): PersonalityOption | undefined {
|
||
return PERSONALITY_OPTIONS.find((p) => p.id === id);
|
||
}
|
||
|
||
/**
|
||
* Get scenario tag by ID
|
||
*/
|
||
export function getScenarioById(id: string): ScenarioTag | undefined {
|
||
return SCENARIO_TAGS.find((s) => s.id === id);
|
||
}
|
||
|
||
/**
|
||
* Get quick start suggestions for given scenarios
|
||
*/
|
||
export function getQuickStartSuggestions(scenarios: string[]): QuickStartSuggestion[] {
|
||
if (!scenarios || scenarios.length === 0) {
|
||
// Return first 3 general suggestions if no scenarios selected
|
||
return QUICK_START_SUGGESTIONS.slice(0, 3);
|
||
}
|
||
|
||
// Filter suggestions that match any of the selected scenarios
|
||
const matching = QUICK_START_SUGGESTIONS.filter((s) =>
|
||
s.scenarios.some((scenario) => scenarios.includes(scenario))
|
||
);
|
||
|
||
// Return up to 3 matching suggestions, fallback to first 3 if none match
|
||
return matching.length > 0 ? matching.slice(0, 3) : QUICK_START_SUGGESTIONS.slice(0, 3);
|
||
}
|
||
|
||
/**
|
||
* Generate welcome message based on personality and scenarios
|
||
*/
|
||
export function generateWelcomeMessage(config: {
|
||
userName?: string;
|
||
agentName: string;
|
||
emoji?: string;
|
||
personality?: string;
|
||
scenarios?: string[];
|
||
}): string {
|
||
const { userName, agentName, emoji, personality, scenarios } = config;
|
||
|
||
// Build greeting
|
||
const greeting = userName ? `你好,${userName}!` : '你好!';
|
||
|
||
// Build introduction
|
||
let intro = `我是${emoji ? ' ' + emoji : ''} ${agentName}`;
|
||
|
||
// Add scenario context
|
||
if (scenarios && scenarios.length > 0) {
|
||
const scenarioLabels = scenarios
|
||
.map((id) => getScenarioById(id)?.label)
|
||
.filter(Boolean)
|
||
.slice(0, 3);
|
||
if (scenarioLabels.length > 0) {
|
||
intro += `,你的${scenarioLabels.join('、')}助手`;
|
||
}
|
||
}
|
||
|
||
// Add personality touch
|
||
if (personality) {
|
||
const personalityOption = getPersonalityById(personality);
|
||
if (personalityOption) {
|
||
intro += `。我会以${personalityOption.traits[0]}的方式为你提供帮助`;
|
||
}
|
||
}
|
||
|
||
// Add closing
|
||
intro += '。有什么我可以帮你的吗?';
|
||
|
||
return `${greeting}\n\n${intro}`;
|
||
}
|
||
|
||
/**
|
||
* Generate SOUL.md content based on personality config
|
||
*/
|
||
export function generateSoulContent(config: {
|
||
agentName: string;
|
||
emoji?: string;
|
||
personality?: string;
|
||
scenarios?: string[];
|
||
communicationStyle?: string;
|
||
}): string {
|
||
const { agentName, emoji, personality, scenarios, communicationStyle } = config;
|
||
|
||
const personalityOption = personality ? getPersonalityById(personality) : undefined;
|
||
const scenarioLabels =
|
||
scenarios
|
||
?.map((id) => getScenarioById(id)?.label)
|
||
.filter(Boolean)
|
||
.join('、') || '通用';
|
||
|
||
return `# ${agentName} 人格
|
||
|
||
> ${emoji || '🤖'} ${agentName} - ${scenarioLabels}助手
|
||
|
||
## 核心特质
|
||
|
||
${
|
||
personalityOption
|
||
? personalityOption.traits.map((t) => `- ${t}`).join('\n')
|
||
: '- 高效执行\n- 专业可靠\n- 主动服务'
|
||
}
|
||
|
||
## 沟通风格
|
||
|
||
${communicationStyle || personalityOption?.communicationStyle || '简洁、专业、友好'}
|
||
|
||
## 专业领域
|
||
|
||
${scenarioLabels}
|
||
|
||
## 边界
|
||
|
||
- 安全约束:不执行可能损害用户或系统的操作
|
||
- 隐私保护:不主动收集或分享敏感信息
|
||
- 能力边界:超出能力范围时坦诚告知
|
||
|
||
## 语气
|
||
|
||
- 使用中文进行交流
|
||
- 保持专业但友好的态度
|
||
- 适时提供额外上下文和建议
|
||
`;
|
||
}
|
||
|
||
/**
|
||
* Generate USER.md content based on user profile
|
||
*/
|
||
export function generateUserContent(config: {
|
||
userName?: string;
|
||
userRole?: string;
|
||
scenarios?: string[];
|
||
}): string {
|
||
const { userName, userRole, scenarios } = config;
|
||
|
||
const scenarioLabels =
|
||
scenarios
|
||
?.map((id) => getScenarioById(id)?.label)
|
||
.filter(Boolean)
|
||
.join('、') || '通用';
|
||
|
||
const sections: string[] = ['# 用户档案\n'];
|
||
|
||
if (userName) {
|
||
sections.push(`## 基本信息\n\n- 姓名:${userName}`);
|
||
if (userRole) {
|
||
sections.push(`- 角色:${userRole}`);
|
||
}
|
||
sections.push('');
|
||
}
|
||
|
||
sections.push(`## 关注领域\n\n${scenarioLabels}\n`);
|
||
|
||
sections.push(`## 偏好设置\n\n- 语言:中文\n- 沟通风格:直接、高效\n`);
|
||
|
||
return sections.join('\n');
|
||
}
|