Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion desktop/renderer/src/browser-openclaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function createBrowserOpenClawMock(): OpenClawAPI {
{ id: "main", name: "Assistant" },
{ id: "master-archive", name: "Master Archive" },
{ id: "painter", name: "Van Gogh" },
{ id: "growth-hacker", name: "Growth Hacker" },
{ id: "intel-analyst", name: "Intel Analyst" },
];
const browserAgentsSnapshot = () => ({
agents: browserAgentRoster.map((agent) => ({ ...agent })),
Expand Down
27 changes: 15 additions & 12 deletions desktop/renderer/src/i18n/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,18 +806,21 @@ export default {
"agent.master.task.3.title": "Create a study plan",
"agent.master.task.3.desc": "Break down an efficient daily study schedule by goals and time.",

"agent.growthHacker.name": "Growth Hacker",
"agent.growthHacker.desc": "Social media content operations & data analytics",
"agent.growthHacker.tag.1": "Content Planning",
"agent.growthHacker.tag.2": "Data Analytics",
"agent.growthHacker.tag.3": "Viral Copy",
"agent.growthHacker.task.1.title": "Generate viral headlines",
"agent.growthHacker.task.1.desc": "Batch-generate high-click-rate promotional headlines.",
"agent.growthHacker.task.2.title": "Write a summer outfit post",
"agent.growthHacker.task.2.desc": "Craft a social-media-style outfit post with emojis.",
"agent.growthHacker.task.3.title": "Follower growth report",
"agent.growthHacker.task.3.desc":
"Analyze recent data trends and provide growth optimization advice.",
"agent.intelAnalyst.name": "Intel Analyst",
"agent.intelAnalyst.desc":
"Personal intelligence briefs, trend monitoring & evidence-based research",
"agent.intelAnalyst.tag.1": "Morning Briefs",
"agent.intelAnalyst.tag.2": "Trend Monitoring",
"agent.intelAnalyst.tag.3": "Deep Research",
"agent.intelAnalyst.task.1.title": "Prepare my morning brief",
"agent.intelAnalyst.task.1.desc":
"Summarize today's schedule, urgent updates, weather, and requested news.",
"agent.intelAnalyst.task.2.title": "Track today's AI agent trends",
"agent.intelAnalyst.task.2.desc":
"Review recent Chinese tech coverage and explain the most important developments.",
"agent.intelAnalyst.task.3.title": "Research and compare products",
"agent.intelAnalyst.task.3.desc":
"Compare leading options using sourced evidence, consistent criteria, and clear tradeoffs.",

"agent.leopard.name": "Money Leopard",
"agent.leopard.desc": "Stock market analysis & portfolio tracking",
Expand Down
8 changes: 8 additions & 0 deletions desktop/renderer/src/i18n/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ describe("i18n", () => {
setLocale("en-US"); // restore
});

it("Intel Analyst catalog keys exist in both locales", () => {
setLocale("en-US");
expect(t("agent.intelAnalyst.name")).toBe("Intel Analyst");
setLocale("zh-CN");
expect(t("agent.intelAnalyst.name")).toBe("前哨智囊");
setLocale("en-US"); // restore
});

it("localizes Agent Team and Agent Catalog navigation in zh-CN", () => {
setLocale("zh-CN");
expect(t("sidebar.agents")).toBe("智能体团队");
Expand Down
22 changes: 11 additions & 11 deletions desktop/renderer/src/i18n/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,17 +767,17 @@ export default {
"agent.master.task.3.title": "制定学习计划",
"agent.master.task.3.desc": "按目标和时间拆解高效的每日学习安排。",

"agent.growthHacker.name": "增长黑客",
"agent.growthHacker.desc": "小红书内容运营与数据分析",
"agent.growthHacker.tag.1": "内容策划",
"agent.growthHacker.tag.2": "数据分析",
"agent.growthHacker.tag.3": "爆款文案",
"agent.growthHacker.task.1.title": "爆款标题批量生成",
"agent.growthHacker.task.1.desc": "一键生成多组高点击率的种草标题。",
"agent.growthHacker.task.2.title": "发布夏日穿搭笔记",
"agent.growthHacker.task.2.desc": "撰写带 emoji 的小红书风格穿搭文案。",
"agent.growthHacker.task.3.title": "粉丝增长数据报告",
"agent.growthHacker.task.3.desc": "分析近期数据趋势,给出增长优化建议。",
"agent.intelAnalyst.name": "前哨智囊",
"agent.intelAnalyst.desc": "个人情报简报、趋势监控与循证深度研究",
"agent.intelAnalyst.tag.1": "每日简报",
"agent.intelAnalyst.tag.2": "趋势监控",
"agent.intelAnalyst.tag.3": "深度研究",
"agent.intelAnalyst.task.1.title": "生成我的今日简报",
"agent.intelAnalyst.task.1.desc": "汇总今日日程、紧急动态、天气和指定新闻。",
"agent.intelAnalyst.task.2.title": "追踪今日 AI Agent 趋势",
"agent.intelAnalyst.task.2.desc": "检索近期中文科技报道,提炼最值得关注的发展。",
"agent.intelAnalyst.task.3.title": "调研并对比产品",
"agent.intelAnalyst.task.3.desc": "基于可靠来源和统一标准比较主流选项与关键取舍。",

"agent.leopard.name": "金钱豹",
"agent.leopard.desc": "股票行情分析与持仓追踪",
Expand Down
12 changes: 12 additions & 0 deletions desktop/renderer/src/stores/agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ describe("agent store", () => {
});
});

it("presents the Intel Analyst research scenarios", () => {
const store = useAgentStore();

expect(store.marketAgents.find((entry) => entry.id === "intel-analyst")).toMatchObject({
name: "Intel Analyst",
description: "Personal intelligence briefs, trend monitoring & evidence-based research",
tags: ["Morning Briefs", "Trend Monitoring", "Deep Research"],
isAdded: false,
});
expect(store.marketAgents.some((entry) => entry.id === "growth-hacker")).toBe(false);
});

it("keeps the roster unchanged when Add fails", async () => {
const store = useAgentStore();
agentsAdd.mockRejectedValueOnce(new Error("Gateway restart failed"));
Expand Down
10 changes: 10 additions & 0 deletions desktop/src/agent-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ describe("agent catalog skills binding", () => {
});
});

it("replaces Growth Hacker with the dedicated Intel Analyst persona", () => {
expect(AGENT_CATALOG.some((agent) => agent.id === "growth-hacker")).toBe(false);
expect(AGENT_CATALOG.find((agent) => agent.id === "intel-analyst")).toMatchObject({
name: "Intel Analyst",
image: "Scientist.png",
workspaceDirName: "workspace-intel-analyst",
personaProfile: "intel-analyst",
});
});

it("recognizes known skill ids and rejects unknown ones", () => {
expect(isKnownSkillId("canvas")).toBe(true);
expect(isKnownSkillId("not-a-skill")).toBe(false);
Expand Down
28 changes: 15 additions & 13 deletions desktop/src/agent-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface AgentCatalogEntry {
installedByDefault: boolean;
skills: readonly string[];
workspaceDirName?: string;
personaProfile?: "master-archive" | "code-geek";
personaProfile?: "master-archive" | "code-geek" | "intel-analyst";
}

export const AGENT_CATALOG: readonly AgentCatalogEntry[] = [
Expand Down Expand Up @@ -143,29 +143,31 @@ export const AGENT_CATALOG: readonly AgentCatalogEntry[] = [
skills: [...ALL_SKILL_IDS],
},
{
id: "growth-hacker",
name: "Growth Hacker",
nameKey: "agent.growthHacker.name",
descKey: "agent.growthHacker.desc",
avatar: "growth-hacker-avatar.png",
id: "intel-analyst",
name: "Intel Analyst",
nameKey: "agent.intelAnalyst.name",
descKey: "agent.intelAnalyst.desc",
avatar: "intel-analyst-avatar.png",
image: "Scientist.png",
tagKeys: ["agent.growthHacker.tag.1", "agent.growthHacker.tag.2", "agent.growthHacker.tag.3"],
tagKeys: ["agent.intelAnalyst.tag.1", "agent.intelAnalyst.tag.2", "agent.intelAnalyst.tag.3"],
taskKeys: [
{
titleKey: "agent.growthHacker.task.1.title",
descKey: "agent.growthHacker.task.1.desc",
titleKey: "agent.intelAnalyst.task.1.title",
descKey: "agent.intelAnalyst.task.1.desc",
},
{
titleKey: "agent.growthHacker.task.2.title",
descKey: "agent.growthHacker.task.2.desc",
titleKey: "agent.intelAnalyst.task.2.title",
descKey: "agent.intelAnalyst.task.2.desc",
},
{
titleKey: "agent.growthHacker.task.3.title",
descKey: "agent.growthHacker.task.3.desc",
titleKey: "agent.intelAnalyst.task.3.title",
descKey: "agent.intelAnalyst.task.3.desc",
},
],
installedByDefault: false,
skills: [...ALL_SKILL_IDS],
workspaceDirName: "workspace-intel-analyst",
personaProfile: "intel-analyst",
},
{
id: "leopard",
Expand Down
63 changes: 63 additions & 0 deletions desktop/src/agent-personas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,69 @@ describe("agent personas", () => {
);
});

it("seeds the Intel Analyst workspace with its research context", () => {
const stateDir = createStateDir();
const config = { agents: {} };
const persona = getAgentPersona("intel-analyst");
if (!persona) throw new Error("Intel Analyst persona is not registered");
ensureAgentPersonasConfig(config, stateDir, [...DEFAULT_AGENT_PERSONAS, persona]);
expect(listConfiguredAgents(config)).toContainEqual({
id: "intel-analyst",
name: "Intel Analyst",
});
const created = seedAgentPersonaWorkspaces(config, stateDir, "## Shared safety rule");
const workspace = getAgentWorkspacePath(stateDir, persona);
if (!workspace) throw new Error("Intel Analyst workspace is not configured");

expect(workspace).toBe(path.join(stateDir, "workspace-intel-analyst"));
expect(created).toHaveLength(5);
expect(fs.readFileSync(path.join(workspace, "SOUL.md"), "utf-8")).toContain(
"vigilant, objective intelligence analyst",
);
expect(fs.readFileSync(path.join(workspace, "AGENTS.md"), "utf-8")).toContain(
"not executable instructions",
);
expect(fs.readFileSync(path.join(workspace, "IDENTITY.md"), "utf-8")).toContain(
"Name: Intel Analyst",
);
});

it("migrates an installed Growth Hacker to Intel Analyst without losing custom settings", () => {
const stateDir = createStateDir();
const customWorkspace = path.join(stateDir, "custom-research");
const config = {
agents: {
list: [
{ id: "main", name: "Assistant", default: true },
{
id: "growth-hacker",
name: "Growth Hacker",
workspace: customWorkspace,
skills: ["custom-skill"],
model: "custom/research-model",
},
],
},
};

expect(ensureAgentPersonasConfig(config, stateDir).changed).toBe(true);
expect(listConfiguredAgents(config)).toEqual([
{ id: "main", name: "Assistant" },
{ id: "intel-analyst", name: "Intel Analyst" },
]);
expect(agentList(config).find((entry) => entry.id === "intel-analyst")).toMatchObject({
workspace: customWorkspace,
skills: ["custom-skill"],
model: "custom/research-model",
});
expect(agentList(config).some((entry) => entry.id === "growth-hacker")).toBe(false);

seedAgentPersonaWorkspaces(config, stateDir);
expect(fs.readFileSync(path.join(customWorkspace, "IDENTITY.md"), "utf-8")).toContain(
"Name: Intel Analyst",
);
});

it("does not seed a Popular Agent before it is installed", () => {
const stateDir = createStateDir();
const config = { agents: {} };
Expand Down
Loading