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
1 change: 1 addition & 0 deletions desktop/renderer/src/browser-openclaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function createBrowserOpenClawMock(): OpenClawAPI {
{ id: "painter", name: "Van Gogh" },
{ id: "dr-pulse", name: "Dr. Pulse" },
{ id: "intel-analyst", name: "Intel Analyst" },
{ id: "market-sentinel", name: "Market Sentinel" },
];
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 @@ -825,18 +825,21 @@ export default {
"agent.intelAnalyst.task.3.desc":
"Monitor pricing, product updates, and market activity to surface changes and recommended responses.",

"agent.leopard.name": "Money Leopard",
"agent.leopard.desc": "Stock market analysis & portfolio tracking",
"agent.leopard.tag.1": "Stock Analysis",
"agent.leopard.tag.2": "Market Review",
"agent.leopard.tag.3": "Portfolio Mgmt",
"agent.leopard.task.1.title": "Today's market analysis",
"agent.leopard.task.1.desc": "Quick overview of market trends and sector movements.",
"agent.leopard.task.2.title": "30-day K-line review",
"agent.leopard.task.2.desc": "Review recent technical indicators and key support levels.",
"agent.leopard.task.3.title": "Position adjustment advice",
"agent.leopard.task.3.desc":
"Provide risk diversification optimization based on current holdings.",
"agent.marketSentinel.name": "Market Sentinel",
"agent.marketSentinel.desc":
"Sourced A-share briefs, filing tracking & watchlist monitoring without investment advice",
"agent.marketSentinel.tag.1": "Market Briefs",
"agent.marketSentinel.tag.2": "Filing Tracker",
"agent.marketSentinel.tag.3": "Watchlist Signals",
"agent.marketSentinel.task.1.title": "Prepare today's A-share market brief",
"agent.marketSentinel.task.1.desc":
"Summarize sourced index, breadth, turnover, sector, and scheduled-event data with timestamps.",
"agent.marketSentinel.task.2.title": "Track earnings and company announcements",
"agent.marketSentinel.task.2.desc":
"Review official filings, preserve reporting periods and units, and highlight factual changes.",
"agent.marketSentinel.task.3.title": "Monitor my watchlist and indicator changes",
"agent.marketSentinel.task.3.desc":
"Describe price, volume, and formula-based indicator changes without trade or position advice.",

"agent.creativeMuse.name": "Creative Muse",
"agent.creativeMuse.desc":
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 @@ -66,6 +66,14 @@ describe("i18n", () => {
setLocale("en-US"); // restore
});

it("Market Sentinel catalog keys exist in both locales", () => {
setLocale("en-US");
expect(t("agent.marketSentinel.name")).toBe("Market Sentinel");
setLocale("zh-CN");
expect(t("agent.marketSentinel.name")).toBe("财经哨兵");
setLocale("en-US"); // restore
});

it("Creative Muse catalog keys exist in both locales", () => {
setLocale("en-US");
expect(t("agent.creativeMuse.name")).toBe("Creative Muse");
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 @@ -779,17 +779,17 @@ export default {
"agent.intelAnalyst.task.3.title": "追踪竞品关键动态",
"agent.intelAnalyst.task.3.desc": "监控竞品定价、功能更新和市场动作,提炼变化与应对建议。",

"agent.leopard.name": "金钱豹",
"agent.leopard.desc": "股票行情分析与持仓追踪",
"agent.leopard.tag.1": "股票分析",
"agent.leopard.tag.2": "行情复盘",
"agent.leopard.tag.3": "持仓管理",
"agent.leopard.task.1.title": "今日沪深 300 涨跌分析",
"agent.leopard.task.1.desc": "快速了解大盘走势和板块异动。",
"agent.leopard.task.2.title": "茅台近 30 日 K 线复盘",
"agent.leopard.task.2.desc": "回顾个股近期技术面和关键支撑位。",
"agent.leopard.task.3.title": "仓位调整建议",
"agent.leopard.task.3.desc": "根据当前持仓给出风险分散优化方案。",
"agent.marketSentinel.name": "财经哨兵",
"agent.marketSentinel.desc": "有来源的 A 股简报、财报公告追踪与自选股监控,不提供投资建议",
"agent.marketSentinel.tag.1": "市场简报",
"agent.marketSentinel.tag.2": "财报公告",
"agent.marketSentinel.tag.3": "自选股监控",
"agent.marketSentinel.task.1.title": "生成今日 A 股盘前或盘后简报",
"agent.marketSentinel.task.1.desc": "按时间戳整理指数、涨跌家数、成交额、板块和重要事件数据。",
"agent.marketSentinel.task.2.title": "追踪这些公司的财报与公告",
"agent.marketSentinel.task.2.desc": "优先核对官方披露,保留报告期、单位并提炼客观变化。",
"agent.marketSentinel.task.3.title": "监控我的自选股与指标变化",
"agent.marketSentinel.task.3.desc": "描述价格、成交量和公式化指标变化,不给出买卖或仓位建议。",

"agent.creativeMuse.name": "灵感创客",
"agent.creativeMuse.desc": "从选题、素材集合到图文发布包的小红书内容工作室",
Expand Down
27 changes: 26 additions & 1 deletion desktop/renderer/src/stores/agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,21 @@ describe("agent store", () => {
{ id: "main", name: "Assistant" },
{ id: "dr-pulse", name: "Dr. Pulse" },
{ id: "master", name: "Dr. Pulse" },
{ id: "market-sentinel", name: "Market Sentinel" },
{ id: "leopard", name: "Market Sentinel" },
{ id: "creative-muse", name: "Creative Muse" },
{ id: "singer", name: "Creative Muse" },
],
});

await store.fetchAgents();

expect(store.agents.map((agent) => agent.id)).toEqual(["main", "dr-pulse", "creative-muse"]);
expect(store.agents.map((agent) => agent.id)).toEqual([
"main",
"dr-pulse",
"market-sentinel",
"creative-muse",
]);
});

it("adds Master Archive to OpenClaw before showing it in the sidebar", async () => {
Expand Down Expand Up @@ -119,6 +126,24 @@ describe("agent store", () => {
expect(store.marketAgents.some((entry) => entry.id === "master")).toBe(false);
});

it("presents the Market Sentinel non-advisory financial scenarios", () => {
const store = useAgentStore();

expect(store.marketAgents.find((entry) => entry.id === "market-sentinel")).toMatchObject({
name: "Market Sentinel",
description:
"Sourced A-share briefs, filing tracking & watchlist monitoring without investment advice",
tags: ["Market Briefs", "Filing Tracker", "Watchlist Signals"],
isAdded: false,
});
expect(store.marketAgents.find((entry) => entry.id === "market-sentinel")?.quickTasks).toEqual([
expect.objectContaining({ title: "Prepare today's A-share market brief" }),
expect.objectContaining({ title: "Track earnings and company announcements" }),
expect.objectContaining({ title: "Monitor my watchlist and indicator changes" }),
]);
expect(store.marketAgents.some((entry) => entry.id === "leopard")).toBe(false);
});

it("presents the Creative Muse platform content scenarios", () => {
const store = useAgentStore();

Expand Down
7 changes: 7 additions & 0 deletions desktop/renderer/src/stores/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,13 @@ describe("useChatStore — draft sessions", () => {
expect(store.sessionKey).toMatch(/^agent:master:session-/);
expect(store.currentSessionAgentId).toBe("dr-pulse");
});

it("attributes historical Leopard session keys to Market Sentinel", () => {
const store = useChatStore();
store.newSession("leopard");
expect(store.sessionKey).toMatch(/^agent:leopard:session-/);
expect(store.currentSessionAgentId).toBe("market-sentinel");
});
});

describe("useChatStore — attachments", () => {
Expand Down
22 changes: 22 additions & 0 deletions desktop/renderer/src/stores/sessions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,28 @@ describe("useSessionStore", () => {
});
});

it("keeps historical Leopard sessions visible under Market Sentinel", () => {
storage["openclaw-sessions"] = JSON.stringify([
{
key: "agent:leopard:legacy",
title: "Legacy market review",
createdAt: 1,
updatedAt: 1,
preview: "market",
agentId: "leopard",
},
]);
setActivePinia(createPinia());

const store = useSessionStore();

expect(store.sessions[0]).toMatchObject({
key: "agent:leopard:legacy",
agentId: "market-sentinel",
title: "Legacy market review",
});
});

it("removes a persisted reserved warm-up session on load", () => {
storage["openclaw-sessions"] = JSON.stringify([
{
Expand Down
12 changes: 12 additions & 0 deletions desktop/src/agent-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ describe("agent catalog skills binding", () => {
expect(canonicalAgentId("master")).toBe("dr-pulse");
});

it("replaces Leopard with the dedicated Market Sentinel persona", () => {
expect(AGENT_CATALOG.some((agent) => agent.id === "leopard")).toBe(false);
expect(AGENT_CATALOG.find((agent) => agent.id === "market-sentinel")).toMatchObject({
name: "Market Sentinel",
avatar: "market-sentinel-avatar.png",
image: "stock.png",
workspaceDirName: "workspace-market-sentinel",
personaProfile: "market-sentinel",
});
expect(canonicalAgentId("leopard")).toBe("market-sentinel");
});

it("replaces Singer with the dedicated Creative Muse persona", () => {
expect(AGENT_CATALOG.some((agent) => agent.id === "singer")).toBe(false);
expect(AGENT_CATALOG.find((agent) => agent.id === "creative-muse")).toMatchObject({
Expand Down
42 changes: 32 additions & 10 deletions desktop/src/agent-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ export interface AgentCatalogEntry {
skills: readonly string[];
ownedSkills?: readonly string[];
workspaceDirName?: string;
personaProfile?: "master-archive" | "code-geek" | "dr-pulse" | "intel-analyst" | "creative-muse";
personaProfile?:
| "master-archive"
| "code-geek"
| "dr-pulse"
| "intel-analyst"
| "market-sentinel"
| "creative-muse";
}

export const AGENT_CATALOG: readonly AgentCatalogEntry[] = [
Expand Down Expand Up @@ -187,20 +193,35 @@ export const AGENT_CATALOG: readonly AgentCatalogEntry[] = [
personaProfile: "intel-analyst",
},
{
id: "leopard",
name: "Leopard",
nameKey: "agent.leopard.name",
descKey: "agent.leopard.desc",
avatar: "leopard-avatar.png",
id: "market-sentinel",
name: "Market Sentinel",
nameKey: "agent.marketSentinel.name",
descKey: "agent.marketSentinel.desc",
avatar: "market-sentinel-avatar.png",
image: "stock.png",
tagKeys: ["agent.leopard.tag.1", "agent.leopard.tag.2", "agent.leopard.tag.3"],
tagKeys: [
"agent.marketSentinel.tag.1",
"agent.marketSentinel.tag.2",
"agent.marketSentinel.tag.3",
],
taskKeys: [
{ titleKey: "agent.leopard.task.1.title", descKey: "agent.leopard.task.1.desc" },
{ titleKey: "agent.leopard.task.2.title", descKey: "agent.leopard.task.2.desc" },
{ titleKey: "agent.leopard.task.3.title", descKey: "agent.leopard.task.3.desc" },
{
titleKey: "agent.marketSentinel.task.1.title",
descKey: "agent.marketSentinel.task.1.desc",
},
{
titleKey: "agent.marketSentinel.task.2.title",
descKey: "agent.marketSentinel.task.2.desc",
},
{
titleKey: "agent.marketSentinel.task.3.title",
descKey: "agent.marketSentinel.task.3.desc",
},
],
installedByDefault: false,
skills: catalogSkills(),
workspaceDirName: "workspace-market-sentinel",
personaProfile: "market-sentinel",
},
{
id: "creative-muse",
Expand Down Expand Up @@ -292,6 +313,7 @@ export function getAgentOwnedSkillIds(agentId: string): readonly string[] {
}

export const LEGACY_AGENT_ID_ALIASES: Readonly<Record<string, string>> = {
leopard: "market-sentinel",
master: "dr-pulse",
singer: "creative-muse",
};
Expand Down
Loading
Loading