Skip to content

[Bug] Desktop “任务/Tasks” page is empty while the Web viewer shows tasks — userId identity mismatch (local-user vs account userId) in panel/tasks #409

Description

@cherushui

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

  1. 在未登录状态下安装 agent hooks/plugins → 生成的 memmy-memory-config.json 里 "userId": "local-user"。
  2. 在桌面端登录 Memmy 账号(account 模式)。
  3. 通过 Cursor / opencode 对话 → episodes 以 user_id = local-user 写入。
  4. 打开桌面端「任务」→ 空。打开 http://127.0.0.1:18960/viewer → 全部任务可见。
  5. 桌面端退出账号 → 「任务」页又显示全部任务。

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(任选/组合)

  1. 桌面端在已登录状态下安装/更新 agent hooks 时,把账号 userId 写入 memmy-memory-config.json(而不是 local-user)。
  2. 登录后提供迁移:将既有 local-user 数据(sessions / episodes / raw_turns 等)重新关联到账号 userId。
  3. panelTasks 在身份不匹配导致结果为空时不要静默返回空列表(至少给出可诊断信号),或让桌面端按 agent 实际写入的身份查询。
  4. 顺带修一个相关小问题:opencode 插件的 memmy-memory-config.json 中 memmy_config_path 指向了不存在的 C:\Users\<user>\.memmy\config.yaml,导致读取不到服务端配置、回落到 local-user。

Notes

  • 复现中涉及的账号 id、会话/记忆 id 等均已脱敏。
  • 该问题可解释 “配置好 hook 后曾经能显示、后来不显示” 的现象:登出(本地模式)时桌面查询身份为 local-user,与写入身份一致;登录后查询身份变为账号 id,与写入身份不一致。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions