Repository navigation
Conversation
|
This pull request was closed by a temporary author restriction. Pull requests may only be opened by:
Ask a maintainer to add your GitHub login to that allowlist, then reopen the pull request. 此 Pull Request 已被临时的作者限制自动关闭。 当前仅允许以下用户创建 PR:
如需在首次合入前贡献,请联系维护者把 GitHub 用户名加入允许名单,然后再重新打开这个 PR。 维护者可将仓库变量 |
|
CI 里的 本地已跑完同等的门禁,供参考:
|
|
This pull request was closed by a temporary author restriction. Pull requests may only be opened by:
Ask a maintainer to add your GitHub login to that allowlist, then reopen the pull request. 此 Pull Request 已被临时的作者限制自动关闭。 当前仅允许以下用户创建 PR:
如需在首次合入前贡献,请联系维护者把 GitHub 用户名加入允许名单,然后再重新打开这个 PR。 维护者可将仓库变量 |
|
感谢 @ArvinQi 把这块从 #356、#445 一路推到现在 🙏 让外部 agent 通过 MCP 读写专家记忆,是我们非常想要的能力:Claude Code、Codex 和 Octop 专家共享同一份记忆,正是 octop-memory 接下来的方向。 我们整体读了一遍代码,方向认可,但目前的状态还不能合并。下面按优先级列出问题,并给出改法建议。 ✅ 我们想保留的设计
🔴 合并前必须修1.
2. 鉴权需要落到「用户」 现在整个实例共用一个 token,
建议(改动不大):
3. 写入要走 octop-memory 的应用层,不要直接调 core
建议:capture 改走 4. 工具是同步函数,会阻塞 Octop 的事件循环 9 个 5. 它在启动时全局替换了 octop-memory 的三个私有函数( 🟡 建议一起修
📦 拆分建议11k 行放在一个 PR 里很难评审,建议拆成:
长期来看,MCP 工具层也会下沉到 octop-memory( 🧪 测试补充
流程
拆分方式如果有不同想法,欢迎一起讨论。改完 a 之后我们会优先评审。再次感谢! |
7884039 to
5a473b3
Compare
按 review 把"实例共享 token"换成"用户级 token"的存储与发放层: - 迁移 026 建 memory_mcp_tokens 表:token 绑定 user,带客户端名、可限定专家 范围、可单独吊销;服务端只存 sha256(明文只在创建时返回一次) - MemoryMcpTokenRepo(create / list_for_user / get_by_token_hash / get_for_user / revoke / touch / any_active)+ RepoBundle / SharedServices 接线 - token 管理 API:POST/GET/DELETE /api/memory-mcp/tokens,创建时逐个校验专家 存在且当前用户可访问,撤销只能撤自己的 - 迁移版本升到 26:同步 8 处 schema 断言
鉴权 - MCP 中间件从 Bearer token 推出用户(sha256 + hmac.compare_digest,忽略 X-Octop-User-Id);每次请求按 owner / 共享专家规则重新校验专家访问权, 并支持 token 的专家范围限制 - 挂载条件:OCTOP_MEMORY_MCP_ENABLED=1 或已存在有效 token;lifespan 串接原 FastAPI lifespan,不再覆盖 工具面 - capture 改走 MemoryRuntime.capture:脱敏、回声保护、角色/长度策略生效; 调用者写进事件 metadata(caller / source_host),不再拼 `<user>说:` - save 改走 MemoryService.save:人工审核调度器能收到通知 - 9 个工具全部 async,阻塞调用一律 asyncio.to_thread - 审核/运维工具(raws/candidates/extract/promote/reject)仅专家所有者 - 外部写入默认不进晋升(跟随专家提炼配置);后台提炼串行、保存任务引用, 不自动启动停用的专家 测试:越权、伪造 header、密钥脱敏、工具不阻塞事件循环、lifespan 串接。
- docs/memory-mcp.md 重写为 PR a 的实际形态:用户级 token 的创建/吊销、挂载 开关、9 个工具(4 个日常 + 5 个仅专家所有者)、客户端配置与拆分计划 - CHANGELOG 改为描述用户级 token 与审核队列
5a473b3 to
ecfc292
Compare
DSH 的记忆接入从 hook 桥接换成进程内原生插件(v0.1.2):每轮开始前召回并注入 共享记忆,轮末上报本轮增量,不再依赖外部子进程 / hook 方言 / `--use-system-ca`。 插件源码随本仓发版(vendored,`link:` 安装,离线可装)。 开源版相比闭源版本副本的差异只有身份与文案:去掉 userId / X-Octop-User-Id、把闭源专有鉴权头换成通用 Bearer 逻辑、README 的内网域名/员工号替换为公开占位符。
- `/mcp/memory/setup`、`/uninstall`:检测 Claude Code / Kiro / DSH / Codex /
Cursor,写入 hooks(提问前召回、会话结束上报)与 MCP 条目;token 由用户在
运行时粘贴(用户级 omcp_ token),安装器不内置任何凭据
- 项目级安装(`?project=` / `OCTOP_PROJECT_DIR`):项目里只写注册,hook 脚本与
含 token 的 config.json 留在用户目录;Kiro 项目级 MCP 因含凭据而跳过
- Windows 原生 PowerShell 版(`?os=windows`):Read-Host/Read-Secret + .cmd
包装,不需要 Git Bash
- DSH 走原生插件(见上一 commit),安装器负责写 bundle/profile 配置并清理旧的
hook 桥接与 preset
- `memory_capture` 恢复终端 transcript 形态:本地文件或 gzip+base64 上传,按
终端格式解析成 L0(user/assistant/tool 事件),导入前做密钥脱敏;整份原文
归档到 `{workspace}/.octop/memory-sessions/`
- 移除已无引用的 dsh-memory-share preset
- 新增一键安装器章节(macOS/Linux + Windows PowerShell、项目级安装、5 个终端 的 hooks/注册位置) - 拆分计划更新:d 已并入本 PR,c 仍计划下沉到 octop-memory - CHANGELOG 补上终端接入(DSH 原生插件 / 项目级 / Windows)
825c264 to
e55d3b7
Compare
移除断言里对闭源产品名与私有域名的硬编码,避免测试文件本身携带这些词; 安装器的脱敏由 `grep` 自检与其余用例覆盖。
个人记忆页(/personalization/memory)新增 tab:列出用户级 MCP token(名称、 掩码、专家范围、创建/最近使用/状态),创建时名称必填、可限定专家,明文只显示 一次并提供复制,支持撤销。只对个人记忆页展示(Experts 抽屉不出现)。 - 新增 api/modules/memoryMcp.ts(list/create/revoke,snake_case 对齐 TokenOut) - 新增 pages/Agent/Memory/McpAccess.tsx + 4 条组件测试 - MemoryPanel 增加受 showMcpTab 控制的 mcp tab - en/zh 文案(memory.tabs.mcp / memory.mcp)
|
感谢 @ArvinQi 这么快就完成了第二轮 🙏 我们对照代码逐条核对过,第一轮提的核心问题基本都解决了:
鉴权这部分做得很扎实。下面是我们这一轮的一个主要建议,以及几处小问题。 1. 这个 PR 只保留服务端,客户端部分拆出去第一轮我们建议客户端 hook 和安装器「先放 Octop」。看到完整实现之后,我们重新评估了 Octop 的维护边界,觉得放在客户端那一侧更合适。这是我们调整了建议,不是实现有问题,抱歉让你多改一轮。 我们按文件统计了一下:现在的 1.24 万行里,约 68%(≈8.5k 行)是客户端那一侧的代码,包括 5 种客户端的安装器( 我们希望 Octop 只负责服务端,原因有三个:
具体建议:
被拆出去的部分欢迎直接给 octop-memory 提 PR,我们在那边评审。 2. 留在本 PR 的几处小问题
3. 合并后再单独开 issue 的(不阻塞本 PR)
更正第一轮里我们说「DSH 预设不要放进开源仓库」,这是我们判断错了:DSH 是 DeepSeek Harness,是公开的工具,没有保密问题。DSH 插件和其他客户端一样,按第 1 点拆到客户端那一侧就好。 流程
拆分方式如果有不同想法,欢迎直接讨论。服务端这部分改完,我们会尽快评审合并。再次感谢! |
- 路由:token 恰好绑定 1 个专家时,客户端只带 Authorization 即可;不限/多专家
且未带 X-Octop-Agent-Id 时返回 400(附允许列表),带头保持原行为
- 每次请求重读 token 行:Dashboard 切换专家 / 撤销 token 对下一次请求立即生效
- 新增 PATCH /api/memory-mcp/tokens/{token_id}:改名 / 换专家 / 清空为不限;
仅本人未撤销可改,他人 404、已撤销 409,专家校验与创建一致
- repo 增加 update()(仅更新未撤销、属于该用户的行)
- 创建 token:专家单选(默认当前专家),最后一个选项「不限定专家」 - 列表:「上报专家」列(单专家显示名称、不限显示 Tag、多专家显示数量) - 行内「切换专家」→ PATCH 换绑,下一次 MCP 请求即生效;已撤销 token 禁用 - 文案 en/zh 同步(memory.mcp 47 键)
- config.json / MCP 条目 / DSH 插件配置只剩 url + token(+ tokenHeader); hooks 与原生插件不再发 X-Octop-Agent-Id,激活判据改为 endpoint && token - 安装器不再询问专家 ID,非交互只认 OCTOP_MEMORY_TOKEN;支持 `curl .../setup | OCTOP_MEMORY_TOKEN=omcp_… sh` 一条命令配置 - hooks 的「未配置」判定同步放宽,避免删掉 agentId 后静默不工作 - 文档:token 绑定专家、可切换;客户端只需 Authorization;补快速配置命令
- 新增 docs/memory-mcp-setup.md:创建 token、绑定/切换专家、macOS/Linux 与 Windows 一键安装、5 个终端落点、手动配置、验证、排障、安全说明 - 主文档 linked 到安装指引,并说明 token 绑定专家、客户端只带 Authorization - Dashboard「MCP 接入」:页面顶部常驻「一条命令接入」提示(可复制),创建成功 弹窗直接给出带该 token 的 curl 命令 - CHANGELOG 补充 token 绑定/切换专家
6b6ae6f to
da39471
Compare
Claude Code 2.1.x 校验 settings.json 时要求事件下是 matcher 组、组内再套
`hooks` 数组;安装器此前写的是「事件直接挂 handler」的简写形态,
`claude doctor` 报 `Hook matcher "hooks" must be an array of hook entries`
并把该 hook 静默忽略(表现为安装后 Claude 里召回/上报都不生效)。
改成 `[{"hooks": [{type, command}]}]`,重装即可修复;旧形态仍会被识别并替换。
- 创建成功弹窗:Token 输入框旁直接「复制 Token」,下面紧挨着带该 Token 的 安装命令 + 「复制命令」,无需手拼 - 弹窗底部的复制按钮改为「复制命令」(带 token 可直接粘贴执行)
- hooks / DSH 原生插件 / 安装器写入并发送 X-Octop-Client(claude-code、codex、 cursor、kiro、dsh);服务端按 token 记录 first_seen / last_seen / count - token 新增 disabled_clients:命中的接入端直接 403(其它接入端不受影响), 迁移 026 折叠新增 disabled_clients / client_stats 两列 - API:TokenOut 暴露两个字段,PATCH 支持 disabled_clients - Dashboard:列表新增「接入端」列,展开可看每个客户端的最近使用/次数并逐个 开关(已撤销 token 不可改) - 文档补充接入端识别与禁用后的 403 说明
- MemoryPanel 把「MCP 接入」tab 移到「设置」之前
- 标题旁增加「接入说明」链接(docs/memory-mcp-setup.md)
- 每行新增「接入命令」:本次会话创建的 token 直接复制带 token 的 curl 命令;
更早的 token 因服务端只存 hash,走「重新生成并复制」(rotate 旧值立即失效)
- 后端新增 POST /api/memory-mcp/tokens/{id}/rotate:为本人未撤销的 token 换发
新明文(hint 更新、last_used_at 清空),旧明文立即 401
- 创建成功弹窗:Token 段与「一键安装命令」段都带标题与各自的复制按钮 - 重新生成(rotate)弹窗:生成结果同样展示新 Token 与带该 Token 的命令两段, 不再只有命令
|
https://github.com/TencentCloud/octop-memory |
- source_host 改为 token 名字(服务端已知的客户端身份),不再信任客户端自报的 source;caller 仍是 token 所有者 - /mcp/memory 只在 OCTOP_MEMORY_MCP_ENABLED=1 时挂载,token 存在与否不再影响 启动期挂载(创建 token 后无需重启) - transcript 导入不再直接 add_raw_batch:解析后的候选事件交给 MemoryRuntime.capture 写入,脱敏 / 回声 / 角色与长度过滤统一生效;删除对 octop-memory 私有 `_privacy_cfg` / `_redact_text` 的依赖 - memory_capture 新增 `events` 入参:客户端可自行解析对话记录后上传事件, content/source 变为可选;dry_run 同样支持 - 文档同步(挂载条件、来源字段、events 形式)
Summary(摘要)
本次按 #2887 上的 review 重做了核心与鉴权;随后把另一分支上已验证的本地终端接入(hooks + 安装器 + DSH 原生插件)脱敏后一并并入本 PR:
用户级 token 鉴权:token 绑定用户,可命名客户端(
codex@macbook)、可限定专家范围、可单独吊销;服务端只存 sha256,hmac.compare_digest校验;调用者身份只从 token 推出,不再信任X-Octop-User-Id按请求校验专家权限:每次请求都按 owner / 共享专家规则重新检查(与 HTTP 路由同一套规则),改 header 无法越权
写入走应用层:
memory_capture→MemoryRuntime.capture(脱敏、回声保护、角色/长度策略生效),memory_save→MemoryService.save(人工审核调度器能收到通知)工具面重做:9 个工具全部
async def+asyncio.to_thread;日常 4 个(search/get/save/capture)任何 token 可用,审核/运维 5 个(raws/candidates/extract/promote/reject)仅专家所有者默认进审核队列:外部写入不再固定
promote=True,跟随专家提炼配置;后台提炼按专家串行、保存任务引用、不会为了提炼自动启动停用的专家归属写进 metadata:
caller/source_host落到原始事件 payload,不再把<user>说:拼进正文lifespan 不再被覆盖:把 MCP session manager 串进原来的 FastAPI lifespan
挂载 fail-closed:
OCTOP_MEMORY_MCP_ENABLED=1(显式开启)或已存在有效 token 才挂载Dashboard token 管理:个人记忆页新增「MCP 接入」tab,创建(名称 + 单选上报专家)、查看(掩码/最近使用/状态)、切换专家、撤销;明文只在创建时显示一次,页面同时给出可直接复制的 curl 一键安装命令
本地终端接入:
/mcp/memory/setup(含?project=项目级、?os=windowsPowerShell 版)检测并接入 Claude Code / Kiro / DSH / Codex / Cursor;安装器不内置凭据,支持curl ... | OCTOP_MEMORY_TOKEN=omcp_… sh一条命令配置token 即唯一凭据:token 绑定一个专家,客户端只带
Authorization(不再需要X-Octop-Agent-Id);可随时切换专家,下一次请求生效;不限/多专家 token 仍支持带头指定安装与配置指引:新增
docs/memory-mcp-setup.md(创建 token、一键命令、手动配置、验证、排障)DSH 改原生插件:
octop-memory-native(vendored,可离线link:安装)在 DSH 进程内完成召回/上报,不再依赖 hook 桥接;旧 preset/hook 自动清理transcript 导入:终端 hook 上传会话 JSONL(本地文件或 gzip+base64),服务端按终端格式解析成 L0;导入前做密钥脱敏,原会话归档到 workspace
仅开源以下 5 个终端;不附带任何域名、凭据或账号信息。
拆分(按 review 建议)
cordis.patch.yml)被移除的内容保留在 fork 分支
archive/pr2887-pre-split,b/c/d 提交时会复用。对 review 各条的回应
/setup不鉴权却内置实例 tokendefault_token="",安装时粘贴用户 token);实例共享 token 已删除/api/memory-mcp/tokens),身份从 token 推出;专家权限每次请求用 owner /expert_visible_to规则校验;只存 hash + 常量时间比较MemoryRuntime.capture;save →MemoryService.save(supersedes仍用deprecate_atom标记旧记忆)async def,阻塞体asyncio.to_threadmemory_recall_patch.py拿出去server.py的启动挂钩),后续作为 octop-memory PR bpromote跟随专家提炼配置,默认False(外部写入进审核队列)asyncio.Lock串行、专家停止时不自动启动caller/source_host/source;正文不再加前缀[mcp_servers.octop-memory]配置与首次信任说明Verification(本地验证)
uv run ruff check src testsuv run ruff format --check src testsuv run mypy src/octop— 657 source filesuv run pytest -n auto -m "not live"— 5619 passed / 40 skippedtsc -b、vitest run src/pages/Agent/Memory(86 条)、eslint / prettier、en/zh 文案键树一致性hits=5 http=200、上报 hookparsed=2 imported=2 http=200;多专家 token 不带头发请求返回 400新增测试覆盖 review 点名的四类:
X-Octop-User-Id:不影响写入身份(身份只从 token 推出)memory_capture写入sk-…→ 落库为[REDACTED]async defCompatibility(兼容性)
OCTOP_MEMORY_MCP_TOKEN鉴权,改用用户级 token;升级后需要创建 token 并重启(或设置OCTOP_MEMORY_MCP_ENABLED=1)026(SQLite + PostgreSQL 成对),schema 版本 25 → 26/mcp/memory不挂载,对现有部署零影响/setup、/uninstall仍位于 token 校验之前(只返回脚本、不发放凭据);部署应只对可信网络暴露/mcpmcp>=1.9,<2、octop-memory>=1.0.3)Target branch
developmainType of change
Test plan
uv run ruff check src testsuv run ruff format --check src testsuv run mypy src/octopuv run pytest -n auto -m "not live"Checklist
CHANGELOG.md(user-facing)docs/memory-mcp.md重写)Dashboard「MCP 接入」
个人记忆页(
/personalization/memory)新增 tab(Experts 抽屉不显示):token_hint)/ 上报专家 / 创建时间 / 最近使用 / 状态安装与配置指引
新增
docs/memory-mcp-setup.md,覆盖:OCTOP_MEMORY_TOKEN/OCTOP_TERMINALS/?project=)终端接入(本次新增)
.claude/settings.local.json~/.codex/config.toml的[mcp_servers]<proj>/.codex/config.toml~/.cursor/hooks.json<proj>/.cursor/hooks.json本 PR 不包含任何域名、凭据或个人信息。