Files
zclaw_openfang/desktop/src/lib/personality-presets.ts
iven 3c01754c40
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
fix(agent): 12 项 agent 对话链路全栈修复
深端到端验证发现 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 
2026-04-16 09:21:46 +08:00

385 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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');
}