Skip to content

feat(copaw-plugin): MemOS Cloud memory backend for CoPaw (demo)#1447

Open
fancyboi999 wants to merge 5 commits intoMemTensor:mainfrom
fancyboi999:feat/copaw-plugin
Open

feat(copaw-plugin): MemOS Cloud memory backend for CoPaw (demo)#1447
fancyboi999 wants to merge 5 commits intoMemTensor:mainfrom
fancyboi999:feat/copaw-plugin

Conversation

@fancyboi999
Copy link
Copy Markdown
Contributor

背景

Issue #1440 提到希望 MemOS 支持 CoPaw 平台。CoPaw 官方已有基于 ReMeLight 的本地记忆系统,架构上也预留了可插拔的 memory backend 接口(BaseMemoryManager + memory_manager_backend 配置)。

这个 PR 是一次集成尝试(demo 级别),验证了 MemOS Cloud 作为 CoPaw memory backend 的可行性。

做了什么

apps/memos-copaw-plugin/ 下新建了一个 CoPaw 插件,包含 4 个文件:

  • plugin.json — CoPaw 插件清单
  • plugin.py — 插件入口,通过 api.register_memory_manager("memos", MemOSMemoryManager) 注册 backend
  • memos_memory_manager.py — 继承 ReMeLightMemoryManager,只覆写 memory_search 走 MemOS Cloud API,其他本地能力(compaction、token 计数、context 管理)全部复用 ReMeLight
  • memos_client.py — MemOS Cloud HTTP 客户端(/search/memory + /add/message

用户安装后,在 CoPaw agent 配置里设 memory_manager_backend: "memos" + MEMOS_API_KEY 环境变量即可启用。

当前集成范围

老实说,目前只接了 MemOS 最基础的一层:

能力 状态
/search/memory 云端记忆召回 ✅ 通过覆写 memory_search 实现
偏好召回(preference_detail_list) ✅ 搜索结果已包含
云端不可达时 fallback 到本地 ReMeLight
/add/message 对话自动上传 ❌ CoPaw 没有 per-turn hook,未实现
工具记忆、技能记忆 ❌ 未接入
知识库检索、多 agent 隔离 ⚠️ 配置字段预留了,但没实际使用
Recall Filter(LLM 二次过滤) ❌ 未实现

核心缺口是 add 流程 — CoPaw 的 BaseMemoryManager 没有 per-turn 回调,对话内容不会自动上传到 MemOS Cloud。目前只能通过外部手段(MemOS 控制台、API)写入记忆。

本地验证

  • 语法检查 + 单元级导入验证通过
  • 实际启动 CoPaw,插件正常加载,memory_search 走 MemOS Cloud 成功召回记忆
  • 不相关对话不受记忆影响,上下文无污染

配套 PR

CoPaw 侧需要一个小改动来支持插件注册 memory backend:agentscope-ai/CoPaw — feat/memos-memory-backend 分支(PluginApi.register_memory_manager + _resolve_memory_class 扩展)。

想讨论的方向

  1. add 流程怎么做? CoPaw 需要 post-turn hook 还是有其他方式?
  2. MemOS 的高级功能(工具记忆、技能记忆、Recall Filter)值不值得在 CoPaw 侧接入? 如果值得,接口怎么设计比较好?
  3. 这个插件应该放在 MemOS 仓库还是独立仓库?

cc @tangg555 @CaralHsi @xyxy 想听听你们的想法。

Closes #1440

Implements CoPaw's BaseMemoryManager interface, delegating long-term
memory search/add to MemOS Cloud API while handling context compaction
locally. Follows the same pattern as existing OpenClaw plugins.

Closes MemTensor#1440
…re parity

Replace the standalone BaseMemoryManager implementation with
inheritance from ReMeLightMemoryManager. This ensures all local
operations (token-aware compaction, check_context, compact_tool_result,
get_in_memory_memory) use CoPaw's battle-tested ReMeLight code.

Only memory_search and summary_memory are overridden for MemOS Cloud.
summary_memory only fires during context compaction, not every turn.
Putting MemOS Cloud add logic there was both unreliable (too infrequent)
and architecturally wrong (mixing local summary with cloud upload).

v1 scope: MemOS Cloud provides recall (memory_search) only.
All local operations (compaction, summary, persistence) stay with
ReMeLight unchanged.  Cloud-side add requires CoPaw to expose a
post-turn hook first.
Copilot AI review requested due to automatic review settings April 9, 2026 09:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a demo CoPaw plugin that registers a MemOS Cloud–backed MemoryManager so CoPaw agents can recall long-term memory via the MemOS Cloud /search/memory API while reusing ReMeLight’s local memory features and providing a local fallback path.

Changes:

  • Introduce a CoPaw plugin manifest + entrypoint that registers the "memos" memory backend.
  • Add MemOSMemoryManager (extends ReMeLightMemoryManager) overriding memory_search to call MemOS Cloud with fallback to local search.
  • Add an aiohttp-based async MemOS Cloud client (search + add endpoints, plus a lightweight ping).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
apps/memos-copaw-plugin/plugin.json Defines CoPaw plugin metadata and dependency on aiohttp.
apps/memos-copaw-plugin/plugin.py Plugin entrypoint; registers the MemOS memory backend and a startup hook.
apps/memos-copaw-plugin/memos_memory_manager.py MemoryManager implementation integrating MemOS Cloud recall with local ReMeLight fallback.
apps/memos-copaw-plugin/memos_client.py Async HTTP client for MemOS Cloud API endpoints used by the memory manager.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2 to +12
"""MemOS Cloud memory manager for CoPaw agents.

Extends ReMeLightMemoryManager — all local operations (context compaction,
token counting, tool result truncation, in-memory memory) are delegated
to the parent class unchanged. Only two methods are overridden:

- memory_search → queries MemOS Cloud instead of local vector index
- summary_memory → uploads conversation to MemOS Cloud after local summary

This ensures full compatibility with CoPaw's MemoryCompactionHook and
force_memory_search auto-recall mechanism.
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module docstring says this class overrides summary_memory to upload conversations to MemOS Cloud, but the implementation does not override summary_memory and the later comment explicitly states cloud "add" is intentionally not implemented. Please update the docstring to match the actual behavior (cloud recall only) to avoid misleading users.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +20
from agentscope.message import Msg, TextBlock
from agentscope.tool import ToolResponse
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Msg is imported but never used. This will fail Ruff (F401) in CI; please remove the unused import or use it if intended.

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +140
"memory_limit_number": cfg.get("memory_limit_number", 9),
"include_preference": cfg.get("include_preference", True),
"preference_limit_number": cfg.get("preference_limit_number", 6),
"relativity": cfg.get("relativity", 0.45),
"timeout": cfg.get("timeout", 8.0),
"conversation_id": cfg.get("conversation_id", ""),
"knowledgebase_ids": cfg.get("knowledgebase_ids", []),
"async_mode": cfg.get("async_mode", True),
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memory_limit_number (and async_mode) are resolved from config/env but never used; memory_search always passes max_results to MemOS instead. Either wire these config values into the request defaults (e.g., use mc["memory_limit_number"] when max_results isn't explicitly provided) or remove the unused config fields to avoid a misleading configuration surface.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
import asyncio
import logging
import time
from typing import Any, Dict, List, Optional
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

time is imported but never used. This will fail Ruff (F401) in CI; please remove the unused import.

Copilot uses AI. Check for mistakes.
Comment on lines +174 to +183
async def ping(self) -> bool:
"""Lightweight connectivity check via a minimal search call."""
try:
session = await self._ensure_session()
async with session.post(
f"{self.base_url}/search/memory",
json={"user_id": "_ping", "query": "ping"},
timeout=aiohttp.ClientTimeout(total=5),
) as resp:
return resp.status < 500
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping() treats any HTTP status < 500 as "healthy". If the API key is missing/invalid, MemOS will likely return 401/403, which currently reports as healthy and leads start() to log "connected" even though requests will fail. Consider returning True only for 2xx (or at least treating 401/403 as unhealthy) so connectivity/auth problems are surfaced correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
"name": "MemOS Cloud Memory",
"version": "0.1.0",
"description": "MemOS Cloud memory backend for CoPaw — provides cloud-based long-term memory via MemOS API (search + add).",
"author": "MemTensor",
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin description claims "search + add", but this demo implementation does not implement automatic /add/message uploading (per the PR description and memos_memory_manager comment). Please adjust the description to avoid implying that add/sync is supported.

Copilot uses AI. Check for mistakes.
- SIM105: use contextlib.suppress instead of try-except-pass
- F401: remove unused imports (Msg, time)
- ping(): return True only for 2xx, not all < 500
- plugin.json: remove "add" claim from description
- docstring: remove stale summary_memory override reference
- wire memory_limit_number config into search request
- ruff format fixes
@fancyboi999
Copy link
Copy Markdown
Contributor Author

All review feedback addressed in 32a89db:

  • Stale docstring — removed summary_memory override reference, now accurately describes search-only override
  • Unused imports — removed Msg and time (F401)
  • memory_limit_number unused — now wired into search request as max(max_results, config_limit)
  • ping() too permissive — changed to return True only for 2xx responses
  • plugin.json claims "search + add" — updated to "cloud-based long-term memory recall via MemOS search API"
  • ruff format — ran ruff check --fix, 29 auto-fixes applied, 0 remaining

@fancyboi999
Copy link
Copy Markdown
Contributor Author

Hermes 的本地插件(memos-local-plugin v1.0.2)已经发了,回来看这个 CoPaw 的 demo,觉得有些地方需要重新想想。

两个框架的记忆体系差得挺远

扒了一圈两边的代码,发现一个容易踩的坑:不能把 Hermes 的模式直接搬到 CoPaw 上。

Hermes 的 MemoryProvider 给了很完整的生命周期钩子 — sync_turn 每轮写入、prefetch 预检索、on_memory_writeon_session_end。MemOS 本地插件的 ingest 管线、混合检索都能直接挂上去。

CoPaw 这边不一样。BaseMemoryManager 的重心在上下文窗口管理:compact_tool_result 截断工具输出、check_context 算 token、compact_memory 做 LLM 摘要压缩。长期记忆检索 memory_search 只是接口里的一个方法,没有 per-turn 回调。

照搬 Hermes adapter 的架构会水土不服。

MemOS 能帮 CoPaw 做什么

memory_search 是匹配度最高的点。MemOS 的混合检索(FTS5 + 向量 + RRF + MMR + 时间衰减)比 ReMeLight 默认的搜索强不少,现在 PR 里继承 ReMeLight 只换掉 memory_search 的思路是对的。

记忆写入可以做,但得找对时机。CoPaw 没有 per-turn hook,不过 compact_memory 是个切入口——上下文压缩时 ReMeLight 会产出结构化摘要(Goals / Progress / Key Decisions),质量不错,可以顺手推到 MemOS。做法是覆写 compact_memory,先 super() 拿到摘要,再异步发到 MemOS,主流程不受影响。

上下文管理(compact、check_context、token 计数)不该碰,这是 ReMeLight 自己的活。文件式持久化(MEMORY.md、每日日志)也不该替代,MemOS 的 SQLite + 向量库是补充。

另一个想法:支持本地模式

现在只走 Cloud API。但 memos-local-plugin 的 Bridge daemon 跑起来已经挺稳了,没理由不让 CoPaw 也用。可以加个 mode 配置:cloud 走现有的 MemOS Cloud,local 走 Bridge daemon,后者能拿到本地混合检索、去重、Web 面板这些。用户按场景选就行。

几个拿不准的

  1. compact_memory 作为写入时机合不合适?CoPaw 侧有没有更好的 hook 我没看到?
  2. 本地模式要依赖 Node.js 跑 Bridge daemon,CoPaw 用户群对这个接不接受?
  3. 插件继续放 apps/memos-copaw-plugin/ 还是挪到 memos-local-plugin/adapters/copaw/

cc @tangg555 @CaralHsi @xyxy

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 咱们的MemOS插件挺好用的,能不能支持一下copaw的安装

2 participants