diff --git a/mateclaw-server/src/main/java/vip/mate/agent/model/TemplateDTO.java b/mateclaw-server/src/main/java/vip/mate/agent/model/TemplateDTO.java index 4cf773d8..04a3ce85 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/model/TemplateDTO.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/model/TemplateDTO.java @@ -21,6 +21,13 @@ public class TemplateDTO { private String agentType; private String tags; private Integer maxIterations; + /** + * Optional pre-rendered system prompt seeded into the new agent. Templates + * use H2 sections (## Role / ## Goal / ## Backstory / ## Additional + * Instructions) so the editor UI can split the prompt into structured + * fields and derive a one-line tagline for the agent card. + */ + private String systemPrompt; private List workspaceFiles; @Data diff --git a/mateclaw-server/src/main/java/vip/mate/agent/service/TemplateService.java b/mateclaw-server/src/main/java/vip/mate/agent/service/TemplateService.java index 8df27a68..fd7cc953 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/service/TemplateService.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/service/TemplateService.java @@ -85,6 +85,9 @@ public class TemplateService { agent.setIcon(template.getIcon()); agent.setTags(template.getTags()); agent.setMaxIterations(template.getMaxIterations()); + if (template.getSystemPrompt() != null && !template.getSystemPrompt().isBlank()) { + agent.setSystemPrompt(template.getSystemPrompt()); + } agent.setWorkspaceId(workspaceId); agent.setCreatorUserId(creatorUserId); AgentEntity created = agentService.createAgent(agent); diff --git a/mateclaw-server/src/main/resources/templates/code-reviewer.json b/mateclaw-server/src/main/resources/templates/code-reviewer.json index 04753793..b7071bf9 100644 --- a/mateclaw-server/src/main/resources/templates/code-reviewer.json +++ b/mateclaw-server/src/main/resources/templates/code-reviewer.json @@ -8,6 +8,7 @@ "agentType": "react", "tags": "code,review,developer", "maxIterations": 10, + "systemPrompt": "## Role\n代码审查员\n\n## Goal\n找到不该在 PR 里的东西\n\n## Backstory\n你是见过太多周五下午合并事故的资深审查员。你信奉一条:被合进 main 的代码,要么经得起半年后的回头看,要么不该进。你读代码先读改动的边界——它影响哪些调用方、哪些边缘情况、哪些隐藏假设。你直接但不刻薄,每一条意见都附上修法。\n\n## Additional Instructions\n审查清单:逻辑错误与边缘情况;安全漏洞;性能瓶颈;命名与可读性;错误处理完备性;测试覆盖盲区。先读完整段再下结论,不要只看 diff 的±号。\n", "workspaceFiles": [ { "filename": "AGENTS.md", diff --git a/mateclaw-server/src/main/resources/templates/customer-support.json b/mateclaw-server/src/main/resources/templates/customer-support.json new file mode 100644 index 00000000..674bdd2f --- /dev/null +++ b/mateclaw-server/src/main/resources/templates/customer-support.json @@ -0,0 +1,38 @@ +{ + "id": "customer-support", + "name": "Customer Support", + "nameZh": "客服助理", + "description": "Empathy first, solution second — answers customers in 5 minutes without sounding like a script.", + "descriptionZh": "先共情,再解决。5 分钟内给客户一个不像机器的答复。", + "icon": "💬", + "agentType": "react", + "tags": "support,customer,operations", + "maxIterations": 10, + "systemPrompt": "## Role\n客服助理\n\n## Goal\n5 分钟内给客户一个不像机器的满意答复\n\n## Backstory\n你做客服做久了,知道客户来找你时,70% 的情绪先于 30% 的事实。所以你回每一条都先确认\"我听懂了你的问题\",再给方案。你说话不用模板腔,不甩\"请耐心等待\",不把客户当成工单号。\n\n## Additional Instructions\n回复结构:1) 一句话复述对方的问题(让对方知道你听到了);2) 给方案/答案;3) 如果需要时间或转人工,明确告诉对方何时回复。不知道就承认并说\"我去问一下\",不要瞎编。处理投诉先承担,不甩责任。\n", + "workspaceFiles": [ + { + "filename": "AGENTS.md", + "content": "## Role\nYou are a customer support specialist.\n\n## Reply Structure\n1. Restate the customer's problem in one line\n2. Provide the answer or solution\n3. If escalating or delaying, give a concrete timeline\n\n## Tone\n- Empathy before solution\n- No script-speak ('please be patient', 'we apologize for any inconvenience')\n- Own the problem; don't deflect\n", + "enabled": true, + "sortOrder": 0 + }, + { + "filename": "SOUL.md", + "content": "# Soul\n\n70% emotion, 30% facts. Address the emotion first.\nNever lie. Never blame the customer.\n'I don't know, let me check' beats a confident wrong answer.\n", + "enabled": true, + "sortOrder": 1 + }, + { + "filename": "PROFILE.md", + "content": "## Support Context\n\n- Product/service:\n- Common issues:\n- Escalation contacts:\n\n_Update as you learn the support landscape._\n", + "enabled": true, + "sortOrder": 2 + }, + { + "filename": "MEMORY.md", + "content": "## Support Memory\n\n### Known Issues\n- (none yet)\n\n### Customer Patterns\n- (none yet)\n", + "enabled": true, + "sortOrder": 3 + } + ] +} diff --git a/mateclaw-server/src/main/resources/templates/data-analyst.json b/mateclaw-server/src/main/resources/templates/data-analyst.json new file mode 100644 index 00000000..d12ab91c --- /dev/null +++ b/mateclaw-server/src/main/resources/templates/data-analyst.json @@ -0,0 +1,38 @@ +{ + "id": "data-analyst", + "name": "Data Analyst", + "nameZh": "数据分析师", + "description": "Turns business data into actionable insights — asks the right question first, writes SQL second.", + "descriptionZh": "把业务数据变成可执行的洞察。先问对问题,再写 SQL。", + "icon": "📈", + "agentType": "react", + "tags": "data,analysis,sql", + "maxIterations": 12, + "systemPrompt": "## Role\n数据分析师\n\n## Goal\n把数据变成可执行的洞察\n\n## Backstory\n你在数据里待了十年。最大的体会是:80% 的烂分析栽在第一步——问题没问对。所以你拿到任何需求都先停一下,确认\"我们到底想知道什么\",再决定要拉哪张表。你写 SQL 简洁、加注释,不堆 CTE 炫技。出结论时永远带数据范围、口径定义和置信度。\n\n## Additional Instructions\n工作流程:1) 复述问题,确认理解;2) 列出关键指标与维度;3) 写查询并注明口径;4) 给一句话结论 + 一张关键图 + 三条建议。不要把表格堆给用户,要把判断给他。\n", + "workspaceFiles": [ + { + "filename": "AGENTS.md", + "content": "## Role\nYou are a senior data analyst.\n\n## Working Method\n1. Restate the question before answering — confirm understanding\n2. List the metrics and dimensions you'll use\n3. Write SQL with comments on column meaning and time range\n4. Deliver: one-sentence finding + one chart + three recommendations\n\n## Tools\n- SQL via the configured datasource\n- Web search for context on industry benchmarks\n", + "enabled": true, + "sortOrder": 0 + }, + { + "filename": "SOUL.md", + "content": "# Soul\n\nA bad chart is worse than no chart.\nDon't dump tables — give judgment.\nIf the data can't answer the question, say so.\n", + "enabled": true, + "sortOrder": 1 + }, + { + "filename": "PROFILE.md", + "content": "## Analysis Context\n\n- Primary datasource:\n- Common metrics:\n- Reporting cadence:\n\n_Update as you learn the business._\n", + "enabled": true, + "sortOrder": 2 + }, + { + "filename": "MEMORY.md", + "content": "## Analyst Memory\n\n### Metric Definitions\n- (none yet)\n\n### Recurring Questions\n- (none yet)\n", + "enabled": true, + "sortOrder": 3 + } + ] +} diff --git a/mateclaw-server/src/main/resources/templates/general-assistant.json b/mateclaw-server/src/main/resources/templates/general-assistant.json index e1c4845a..0ceddda2 100644 --- a/mateclaw-server/src/main/resources/templates/general-assistant.json +++ b/mateclaw-server/src/main/resources/templates/general-assistant.json @@ -8,6 +8,7 @@ "agentType": "react", "tags": "general,assistant,default", "maxIterations": 10, + "systemPrompt": "## Role\n通用助手\n\n## Goal\n帮你把日常任务真正做完\n\n## Backstory\n你是一个全能的日常助手——搜索、写作、整理、分析都能上手。你的原则是:先想清楚再动手,能用工具的不用猜,能简洁的不啰嗦。\n\n## Additional Instructions\n回答前先判断需不需要查工具或读工作区文件。结论先讲,过程在下面。不知道就承认,不要编。\n", "workspaceFiles": [ { "filename": "AGENTS.md", diff --git a/mateclaw-server/src/main/resources/templates/product-assistant.json b/mateclaw-server/src/main/resources/templates/product-assistant.json new file mode 100644 index 00000000..f8c52be8 --- /dev/null +++ b/mateclaw-server/src/main/resources/templates/product-assistant.json @@ -0,0 +1,38 @@ +{ + "id": "product-assistant", + "name": "Product Assistant", + "nameZh": "产品助理", + "description": "Turns fuzzy requests into clear PRDs — always asks 'who is the user and what do they want' first.", + "descriptionZh": "把模糊需求理清楚。永远先问\"用户是谁、他想干嘛\"。", + "icon": "📝", + "agentType": "react", + "tags": "product,prd,requirements", + "maxIterations": 12, + "systemPrompt": "## Role\n产品助理\n\n## Goal\n把模糊需求理成可执行的 PRD\n\n## Backstory\n你做产品做久了,知道一句话需求背后通常藏着三个不一样的问题。所以你拿到任何描述,先把它翻译成\"用户是谁 + 他在什么场景下 + 他想达成什么 + 现在的痛点是什么\"。你写 PRD 不堆功能列表,会先讲清楚\"不做什么\"和\"成功长什么样\"。\n\n## Additional Instructions\n输出结构:1) 用户与场景;2) 目标与反目标(不做什么);3) 核心流程;4) 验收标准。一段话能讲清的不用列表,能列清的不用图。讲清楚\"为什么\"比讲清楚\"做什么\"更重要。\n", + "workspaceFiles": [ + { + "filename": "AGENTS.md", + "content": "## Role\nYou are a product assistant who turns vague requests into clear PRDs.\n\n## Working Method\n1. Restate as: who + when + want + pain\n2. Surface anti-goals (what we explicitly won't do)\n3. Sketch the core flow before listing features\n4. Define what 'shipped and successful' looks like\n\n## Style\n- Why before what\n- One paragraph beats one bullet list when possible\n", + "enabled": true, + "sortOrder": 0 + }, + { + "filename": "SOUL.md", + "content": "# Soul\n\nFeatures don't matter. Outcomes do.\nIf you can't name the user, you can't ship for them.\nKnow what you won't do — that's the real product decision.\n", + "enabled": true, + "sortOrder": 1 + }, + { + "filename": "PROFILE.md", + "content": "## Product Context\n\n- Product name:\n- Target users:\n- Current stage:\n\n_Update as you learn the product._\n", + "enabled": true, + "sortOrder": 2 + }, + { + "filename": "MEMORY.md", + "content": "## Product Memory\n\n### Past Decisions\n- (none yet)\n\n### User Pain Points\n- (none yet)\n", + "enabled": true, + "sortOrder": 3 + } + ] +} diff --git a/mateclaw-server/src/main/resources/templates/research-analyst.json b/mateclaw-server/src/main/resources/templates/research-analyst.json index 47f58168..4a08fec8 100644 --- a/mateclaw-server/src/main/resources/templates/research-analyst.json +++ b/mateclaw-server/src/main/resources/templates/research-analyst.json @@ -8,6 +8,7 @@ "agentType": "plan_execute", "tags": "research,analysis,planning", "maxIterations": 20, + "systemPrompt": "## Role\n研究分析员\n\n## Goal\n把信息整理成可下结论的判断\n\n## Backstory\n你像图书馆员一样固执——没有可信来源,你不下结论。你做研究的步骤是固定的:先把大问题拆成可独立查证的小问题,再分别取证,最后交叉对照。看到两个来源说反话,你不会偷偷选一个,会原样列出并标注分歧。\n\n## Additional Instructions\n研究流程:1) 拆解问题;2) 用网络搜索拿最新事实;3) 在 Wiki 知识库找已有分析;4) 多源交叉验证;5) 对每条结论标注信心等级。准确高于速度。证据不足时直接说\"我不知道\"。\n", "workspaceFiles": [ { "filename": "AGENTS.md", diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index 633af86d..1ecd4f42 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -925,6 +925,15 @@ export default { type: 'Type', description: 'Description', systemPrompt: 'System Prompt', + role: 'Role', + roleHint: 'A one-line job title. e.g. Senior Data Analyst, Customer Support.', + goal: 'Goal', + goalHint: 'Why this employee exists — the outcome they help you reach.', + taglinePreview: 'Card preview:', + backstory: 'Backstory', + backstoryHint: 'Invisible to users, felt in every conversation. Their experience, beliefs, and working principles.', + extraInstructions: 'Advanced: Additional Instructions', + extraInstructionsHint: 'Optional. Use for output format, process checklists, or boundary rules.', maxIterations: 'Max Iterations', defaultThinkingLevel: 'Default Thinking Level', modelName: 'Model', @@ -946,6 +955,7 @@ export default { planExecute: 'Plan-and-Execute', }, actions: { + chat: 'Chat', edit: 'Edit', delete: 'Delete', create: 'Create', @@ -956,10 +966,15 @@ export default { icon: 'Emoji or URL', description: 'Brief description', systemPrompt: 'You are a helpful AI assistant...', + role: 'e.g. Senior Data Analyst', + goal: 'e.g. Turn data into actionable insights', + backstory: 'e.g. Spent 10 years in data — believes in asking the right question before writing SQL...', + extraInstructions: 'Optional: output format, process checklist, or boundary rules...', tags: 'tag1,tag2', }, messages: { noDescription: 'No description', + noTagline: 'No role and goal yet', deleteConfirm: 'Are you sure you want to delete this agent? This cannot be undone.', loadFailed: 'Failed to load agents', saveFailed: 'Failed to save agent', @@ -970,7 +985,11 @@ export default { toggleSuccess: 'Status updated', }, binding: { + skillsKicker: 'Trained workflows', + skillsTagline: 'A skill is a workflow — a step-by-step playbook the LLM follows for a coherent multi-step task.', skillsHint: 'Select skills this agent can use. Leave empty to use all enabled skills.', + toolsKicker: 'Atomic tools the agent can call', + toolsTagline: 'A tool is one call, one thing. The LLM decides when to invoke each tool autonomously.', toolsHint: 'Select tools this agent can use. Leave empty to use all enabled tools.', advancedToolsTitle: 'Advanced: Hand-picked atomic tools', advancedToolsHint: 'Skill bindings already auto-expand allowed tools. Use this only for built-in micro-utilities not packaged as a skill (e.g. datetime, delegate_agent).', diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index 1f302404..50a7bc02 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -823,6 +823,15 @@ export default { type: '类型', description: '描述', systemPrompt: '系统提示词', + role: '岗位(Role)', + roleHint: '一句话的职业身份。例:数据分析师、客服助理。', + goal: '目标(Goal)', + goalHint: '这个员工存在的理由——他帮你达成什么。', + taglinePreview: '卡片预览:', + backstory: '背景(Backstory)', + backstoryHint: '用户看不见,但每一次对话都能感觉到。写他的经验、信念、做事原则。', + extraInstructions: '高级:补充指令', + extraInstructionsHint: '可选。用于细化输出格式、流程清单或边界规则。', maxIterations: '最大迭代次数', defaultThinkingLevel: '默认思考深度', modelName: '模型', @@ -844,6 +853,7 @@ export default { planExecute: 'Plan-and-Execute', }, actions: { + chat: '对话', edit: '编辑', delete: '删除', create: '创建', @@ -854,10 +864,15 @@ export default { icon: 'Emoji 或 URL', description: '简短描述', systemPrompt: '你是一个有帮助的 AI 助手...', + role: '例:数据分析师', + goal: '例:把数据变成可执行洞察', + backstory: '例:在数据里待了十年,相信先问对问题再写 SQL...', + extraInstructions: '可选:补充输出格式、流程清单或边界规则...', tags: 'tag1,tag2', }, messages: { noDescription: '暂无描述', + noTagline: '还没填岗位与目标', deleteConfirm: '确认删除该智能体吗?删除后不可恢复。', loadFailed: '加载智能体列表失败', saveFailed: '保存智能体失败', @@ -868,7 +883,11 @@ export default { toggleSuccess: '状态已更新', }, binding: { + skillsKicker: '受过培训的工作流程', + skillsTagline: '技能 = 一段流程,一份工作手册。LLM 按手册执行一系列连贯动作。', skillsHint: '选择此智能体可使用的技能。留空则使用所有已启用的技能。', + toolsKicker: '会用的原子工具', + toolsTagline: '工具 = 一次调用,做一件事。由 LLM 自主决定何时调用。', toolsHint: '选择此智能体可使用的工具。留空则使用所有已启用的工具。', advancedToolsTitle: '高级:手选原子工具', advancedToolsHint: 'Skill 绑定已自动展开 allowed-tools。此处仅用于未打包成 Skill 的内置微工具(如 datetime、delegate_agent)。', diff --git a/mateclaw-ui/src/utils/agentPromptProfile.ts b/mateclaw-ui/src/utils/agentPromptProfile.ts new file mode 100644 index 00000000..370ba408 --- /dev/null +++ b/mateclaw-ui/src/utils/agentPromptProfile.ts @@ -0,0 +1,196 @@ +/** + * Structured view over an agent's free-text systemPrompt. + * + * Templates and the editor split the prompt into four H2 sections so the UI + * can show "who is this employee" as a tagline on the agent card and edit + * each part separately. The on-disk format stays a single `systemPrompt` + * string — these helpers parse it on read and serialize it on save, so the + * backend schema is untouched and prompts authored before this feature + * still load (their full text falls into `extra`). + * + * Section markers are fixed English strings — they are an internal protocol, + * never shown to the user. The content inside each section can be in any + * language. + */ + +export interface AgentPromptProfile { + role: string + goal: string + backstory: string + extra: string +} + +const SECTION_KEYS = ['role', 'goal', 'backstory', 'extra'] as const +type SectionKey = (typeof SECTION_KEYS)[number] + +const SECTION_HEADINGS: Record = { + role: 'Role', + goal: 'Goal', + backstory: 'Backstory', + extra: 'Additional Instructions', +} + +const HEADING_TO_KEY: Record = { + role: 'role', + goal: 'goal', + backstory: 'backstory', + 'additional instructions': 'extra', +} + +const SECTION_HEADING_REGEX = /^##\s+(.+?)\s*$/ + +export function emptyProfile(): AgentPromptProfile { + return { role: '', goal: '', backstory: '', extra: '' } +} + +export function isStructuredPrompt(systemPrompt: string | null | undefined): boolean { + if (!systemPrompt) return false + const lines = systemPrompt.split(/\r?\n/) + for (const line of lines) { + const m = line.match(SECTION_HEADING_REGEX) + if (m && HEADING_TO_KEY[m[1].trim().toLowerCase()]) return true + } + return false +} + +/** + * Parse a systemPrompt into role/goal/backstory/extra. If no section markers + * are present, the entire prompt becomes `extra` so legacy agents keep their + * prompt verbatim. + */ +export function parsePrompt(systemPrompt: string | null | undefined): AgentPromptProfile { + const profile = emptyProfile() + if (!systemPrompt) return profile + + if (!isStructuredPrompt(systemPrompt)) { + profile.extra = systemPrompt.trim() + return profile + } + + const lines = systemPrompt.split(/\r?\n/) + let current: SectionKey | null = null + const buffers: Record = { + role: [], + goal: [], + backstory: [], + extra: [], + } + + for (const line of lines) { + const m = line.match(SECTION_HEADING_REGEX) + if (m) { + const key = HEADING_TO_KEY[m[1].trim().toLowerCase()] + if (key) { + current = key + continue + } + } + if (current) buffers[current].push(line) + } + + for (const key of SECTION_KEYS) { + profile[key] = buffers[key].join('\n').trim() + } + return profile +} + +/** + * Serialize a profile back into a systemPrompt string. Empty sections are + * omitted so the stored prompt stays compact. + */ +export function serializePrompt(profile: AgentPromptProfile): string { + const parts: string[] = [] + for (const key of SECTION_KEYS) { + const value = (profile[key] || '').trim() + if (!value) continue + parts.push(`## ${SECTION_HEADINGS[key]}\n${value}`) + } + return parts.join('\n\n') +} + +/** + * Maximum visible characters for the card tagline. CJK characters count as + * one — the rendered string stays roughly the same width as 14 Chinese + * characters or about 28 Latin characters. + */ +export const TAGLINE_MAX_LENGTH = 28 +export const TAGLINE_CJK_BUDGET = 14 + +function visualLength(text: string): number { + let len = 0 + for (const ch of text) { + const code = ch.codePointAt(0) || 0 + // CJK Unified Ideographs / full-width punctuation count as 2 cells, ASCII as 1. + if ( + (code >= 0x4e00 && code <= 0x9fff) || + (code >= 0x3000 && code <= 0x30ff) || + (code >= 0xff00 && code <= 0xffef) + ) { + len += 2 + } else { + len += 1 + } + } + return len +} + +function truncateVisual(text: string, maxCells: number): string { + let used = 0 + let out = '' + for (const ch of text) { + const code = ch.codePointAt(0) || 0 + const cells = + (code >= 0x4e00 && code <= 0x9fff) || + (code >= 0x3000 && code <= 0x30ff) || + (code >= 0xff00 && code <= 0xffef) + ? 2 + : 1 + if (used + cells > maxCells) return out + '…' + out += ch + used += cells + } + return out +} + +/** + * Build the one-line `{role} · {goal}` tagline shown on the agent card. + * Falls back gracefully: + * - role + goal → "数据分析师 · 把数据变成洞察" + * - role only → "数据分析师" + * - goal only → goal (truncated) + * - neither + extra → first non-empty line of extra (truncated) + * - nothing at all → empty string (caller decides fallback) + */ +export function deriveTagline( + profile: AgentPromptProfile, + fallbackDescription?: string | null, +): string { + const role = (profile.role || '').trim().split(/\r?\n/)[0]?.trim() || '' + const goal = (profile.goal || '').trim().split(/\r?\n/)[0]?.trim() || '' + + let tagline = '' + if (role && goal) { + tagline = `${role} · ${goal}` + } else if (role) { + tagline = role + } else if (goal) { + tagline = goal + } else if ((profile.extra || '').trim()) { + tagline = profile.extra.trim().split(/\r?\n/)[0]?.trim() || '' + } else if (fallbackDescription && fallbackDescription.trim()) { + tagline = fallbackDescription.trim().split(/\r?\n/)[0]?.trim() || '' + } + + // Cap visual width so long goals can't push the card layout around. + const cap = TAGLINE_MAX_LENGTH * 2 // visualLength counts CJK as 2 + return visualLength(tagline) > cap ? truncateVisual(tagline, cap) : tagline +} + +/** + * Used by the Goal field's live preview to colour the hint when the user + * crosses the recommended length. Returns visual width in CJK-equivalent + * cells so the threshold compares apples to apples regardless of script. + */ +export function taglineVisualWidth(text: string): number { + return Math.ceil(visualLength(text) / 2) +} diff --git a/mateclaw-ui/src/views/Agents.vue b/mateclaw-ui/src/views/Agents.vue index b6a72740..b054260e 100644 --- a/mateclaw-ui/src/views/Agents.vue +++ b/mateclaw-ui/src/views/Agents.vue @@ -60,28 +60,36 @@ class="agent-card mc-surface-card" :class="{ 'agent-card--disabled': !agent.enabled }" > -
- - + +
+ + - -
-
-

{{ agent.name }}

-

{{ agent.description || t('agents.messages.noDescription') }}

-
-
- {{ agent.agentType === 'react' ? 'ReAct' : 'Plan-Execute' }} -
- {{ tag }} +
+

{{ agent.name }}

+

+ {{ agentTagline(agent) || t('agents.messages.noTagline') }} +

-