TL;DR(中文)
- 本地使用一段时间后,注册并登录账号,桌面端「任务」页清空,但 Web viewer(
http://127.0.0.1:18960/viewer)能看到全部任务;「记忆」页正常。
- 根因:memory-service 的
panelTasks 会按 namespace.userId 过滤 episodes。agent hook / 插件以 userId = local-user 写入 episodes,而桌面端登录账号后用「账号 userId」查询 → 被过滤成 0 条。
- Web viewer 的
GET /api/v1/episodes 调用 panelTasks 时不带 userId → 不筛选 → 能显示全部。
- 退出账号(切回本地模式)后,桌面端「任务」立刻恢复显示。
Environment
- Memmy desktop
1.1.4,memory-service 2.1.2(Windows)
- 接入来源:Cursor hook、opencode 插件
- 相关配置:agent 侧
memmy-memory-config.json 中 "userId": "local-user"
Steps to reproduce
- 在未登录状态下安装 agent hooks/plugins → 生成的
memmy-memory-config.json 里 "userId": "local-user"。
- 在桌面端登录 Memmy 账号(account 模式)。
- 通过 Cursor / opencode 对话 → episodes 以
user_id = local-user 写入。
- 打开桌面端「任务」→ 空。打开
http://127.0.0.1:18960/viewer → 全部任务可见。
- 桌面端退出账号 → 「任务」页又显示全部任务。
Root cause
-
memory-service dist/src/service/read-model/panel-read.js:
panelTasks(input) {
const pageSize = 20;
const query = input.q?.trim() || undefined;
const userId = input.namespace?.userId; // ← episodes 按 userId 过滤
const total = this.deps.repos.runtime.countEpisodes(userId, query, input.sourceAgent);
const episodes = this.deps.repos.runtime.listEpisodes(userId, pageSize, (page - 1) * pageSize, query, input.sourceAgent);
...
}
-
桌面端本地 API(@memmy/backend)把登录账号的 userId 注入每次 memory client 调用:
// dist/src/services/index.js
const resolveMemoryUserId = () => {
const session = accountSessionRepository.get();
return session.authenticated ? session.profile.userId : "local-user";
};
// dist/src/services/panel-service.js
const context = (ctx) => ({ ...ctx, userId: deps.getUserId() });
该 userId 由 memory client 以 x-memmy-user-id 头发给 memory-service。
-
agent hook/插件写入的 memmy-memory-config.json 使用 "userId": "local-user",因此 sessions / episodes / raw_turns 的 user_id 全是 local-user。
-
Web viewer 路径(dist/src/server/viewer-api.js):
if (method === "GET" && path === "/api/v1/episodes") {
return { body: context.service.panelTasks({
...envelope, // ← 不含 namespace.userId
q: query(url, "q"),
sourceAgent: query(url, "sourceAgent"),
page: numberQuery(url, "page")
}) };
}
→ 不按 userId 过滤,所以 viewer 能看到全部。
Evidence
直接请求 memory-service(不带 viewer 头):
x-memmy-user-id |
/api/v1/panel/tasks total |
| (不传) |
10 |
local-user |
10 |
| 账号 userId(此处已脱敏) |
0 |
对照:/api/v1/panel/items(记忆页)对上述任意 userId 都返回相同结果(不做用户过滤),因此「记忆」页不受影响,只有「任务」页为空。
Expected
桌面端「任务」应与 Web viewer 显示一致,且不应受登录状态影响;agent 写入任务所用的身份,应与桌面端读取所用的身份一致。
Suggested fix(任选/组合)
- 桌面端在已登录状态下安装/更新 agent hooks 时,把账号 userId 写入
memmy-memory-config.json(而不是 local-user)。
- 登录后提供迁移:将既有
local-user 数据(sessions / episodes / raw_turns 等)重新关联到账号 userId。
panelTasks 在身份不匹配导致结果为空时不要静默返回空列表(至少给出可诊断信号),或让桌面端按 agent 实际写入的身份查询。
- 顺带修一个相关小问题:opencode 插件的
memmy-memory-config.json 中 memmy_config_path 指向了不存在的 C:\Users\<user>\.memmy\config.yaml,导致读取不到服务端配置、回落到 local-user。
Notes
- 复现中涉及的账号 id、会话/记忆 id 等均已脱敏。
- 该问题可解释 “配置好 hook 后曾经能显示、后来不显示” 的现象:登出(本地模式)时桌面查询身份为
local-user,与写入身份一致;登录后查询身份变为账号 id,与写入身份不一致。
TL;DR(中文)
http://127.0.0.1:18960/viewer)能看到全部任务;「记忆」页正常。panelTasks会按namespace.userId过滤 episodes。agent hook / 插件以userId = local-user写入 episodes,而桌面端登录账号后用「账号 userId」查询 → 被过滤成 0 条。GET /api/v1/episodes调用panelTasks时不带 userId → 不筛选 → 能显示全部。Environment
1.1.4,memory-service2.1.2(Windows)memmy-memory-config.json中"userId": "local-user"Steps to reproduce
memmy-memory-config.json里"userId": "local-user"。user_id = local-user写入。http://127.0.0.1:18960/viewer→ 全部任务可见。Root cause
memory-service
dist/src/service/read-model/panel-read.js:桌面端本地 API(
@memmy/backend)把登录账号的 userId 注入每次 memory client 调用:该 userId 由 memory client 以
x-memmy-user-id头发给 memory-service。agent hook/插件写入的
memmy-memory-config.json使用"userId": "local-user",因此sessions/episodes/raw_turns的user_id全是local-user。Web viewer 路径(
dist/src/server/viewer-api.js):→ 不按 userId 过滤,所以 viewer 能看到全部。
Evidence
直接请求 memory-service(不带 viewer 头):
x-memmy-user-id/api/v1/panel/taskstotallocal-user对照:
/api/v1/panel/items(记忆页)对上述任意 userId 都返回相同结果(不做用户过滤),因此「记忆」页不受影响,只有「任务」页为空。Expected
桌面端「任务」应与 Web viewer 显示一致,且不应受登录状态影响;agent 写入任务所用的身份,应与桌面端读取所用的身份一致。
Suggested fix(任选/组合)
memmy-memory-config.json(而不是local-user)。local-user数据(sessions/episodes/raw_turns等)重新关联到账号 userId。panelTasks在身份不匹配导致结果为空时不要静默返回空列表(至少给出可诊断信号),或让桌面端按 agent 实际写入的身份查询。memmy-memory-config.json中memmy_config_path指向了不存在的C:\Users\<user>\.memmy\config.yaml,导致读取不到服务端配置、回落到local-user。Notes
local-user,与写入身份一致;登录后查询身份变为账号 id,与写入身份不一致。