Files
MemRelay/docs/implementation-plan.md
T

435 lines
58 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MemRelay 完整实施计划
## 2026-08-19 Git 来源增量收集与无变化任务短路(已实施)
背景:`_collect_git` 每次对仓库 HEAD 全量 `ls-tree` 提取全部文件,与游标增量(memory/file)不对称;Git-only 项目(无 agent 活动,`auto` 策略每次兜底收集 git)即使一个字未改,每次任务也全仓重提取、重压缩、重写全部文档(实测 274 文件 → 40 次调用、约 115 万 Token)。定时任务每日空转消耗。
契约:
1. `_collect_git` 接受 `base_commit`(上次成功整理写入 CurationSource 的 git 来源 revision):与当前 HEAD 相同 → 零收集(`git_coverage.mode=unchanged`);不同 → `git diff --name-status` 只提取变更文件并为删除文件生成 SOURCE_REMOVED 声明(`mode=diff`);基线不可用(首次、浅克隆丢失)→ 回退全量(`mode=full`)。full 模式任务不传基线,始终全量。
2. 任务级短路:可用来源只剩 `curated_baseline`/全局指导(无任何主来源)且现有文档的 prompt_version 均为当前版本时,任务记录 `no_primary_changes` 事件并零调用完成(stats 带 `skip_reason`);提示词版本升级时放行重建。
3. 未变文件的信息由 curated_baseline 文档承载,与既有"基线 + 新证据重写"语义一致;diff 空集不再误标 GIT_SOURCE_EMPTY。
4. 验收:`_collect_git` 全量/unchanged/diff(含删除声明)/无效基线回退四态回归;端到端"第二次无变化任务零调用短路"回归;完整后端套件 + 前端门禁通过后发布 ARM,生产实测同一项目从"40 次调用/115 万 Token"降为"零调用完成"。
## 2026-08-19 调用预算自适应工作量(已实施)
背景:BDYG18Pro 积压 293 个来源产生 27 个证据批次,任务约需 43 次模型调用,配置上限 `task_max_calls=30` 使每天 18:30 定时任务连续 7 天在第 31 次调用(合并 4/7)处失败,每次白烧 31 次调用;失败导致增量游标不推进、积压继续膨胀,形成每日必败循环。
契约:
1. 批次准备完成后按工作量估算所需调用上界:证据每批 1 次(单批不计)+ 合并树每层 ceil(n/4) 收敛至单份 + 文档每 4 份 1 批 × 2(含 repair 预留)。
2. 估算超过配置上限时,本任务内自动放宽调用上限至估算值,并记录 `budget_calls_auto_raised` 事件(configured/required)供审计;Token 预算保持硬顶不放宽,真实成本仍受控。
3. `CURATION_BUDGET_EXCEEDED` 错误信息附带用量与上限明细(调用 X/Y,Token A/B)。
4. 验收:估算函数数学回归(27 批 10 文档=43)、调用上限 1 + 五文档两批的端到端放宽回归(事件唯一、任务完成)、Token 硬顶既有回归不变;完整后端套件 + 前端门禁通过后发布 ARM,生产实测放宽事件触发且任务越过 30 次调用关口。
## 2026-08-13 时间字段统一 UTC-aware 序列化(已实施)
背景:SQLite 存储 datetime 丢弃时区,ORM 读回 naive UTC,isoformat 序列化不带偏移,Web 前端与 MCP 客户端把它误当本地时间,全站时间显示偏差 8 小时;散落各服务的 `_ensure_utc` 补丁未覆盖序列化路径。该偏差还让静默期去抖中的整理任务(next_retry_at 为未来时刻)看起来像"卡死数小时不执行"。
契约:
1. `models.UTCDateTime`(TypeDecorator)在读取时为 naive 值补回 UTC tzinfo;全部模型时间列使用该类型,存储格式不变、无需迁移。
2. REST(FastAPI)输出 `+00:00` 偏移、MCP(pydantic)输出 `Z` 后缀;前端 `new Date().toLocaleString()` 自动转本地时区,前端零改动。
3. 任务调度语义不变:source_change 任务的 `next_retry_at` 仍是静默期去抖到期时刻,"计划执行"列语义正确。
4. 验收:REST 往返断言时间带 UTC 偏移;修正依赖"读回 naive"旧行为的存量断言;完整后端套件通过后发布 ARM,容器内 ORM 读回 aware、公网 MCP 时间带 `Z` 实测确认。
## 2026-08-13 MCP GET /mcp 返回 405 兼容新版客户端(已实施)
背景:无状态 Streamable HTTP 下 fastmcp 只注册 POST/DELETE,GET /mcp 落入 SPA 兜底返回 404;新版 Cursor 在 initialize 后主动 GET 打开服务端通知 SSE 流,把 404 视为会话失效,连续重试后墓碑化整个连接导致 MCP 不可用。
契约:
1. `/mcp` 显式注册 GET(含自动 HEAD)返回 405 + `Allow: POST, DELETE`,符合 MCP Streamable HTTP 规范"不支持服务端主动 SSE 流必须回 405";客户端(官方 TS SDK 及 Cursor)对 405 静默容忍。
2. 该处理不做鉴权(405 优先于 401,无信息泄露);POST/DELETE 行为不变。
3. 验收:回归覆盖 GET /mcp 为 405 且带 Allow 头;完整后端套件通过后发布 ARM,内外网实测 405/200。
## 2026-08-12 操作列收纳与生命周期筛选默认全部(已实施)
背景:全局记忆操作列在 132px 内排 3 个图标按钮导致换行错乱;用户希望各生命周期筛选组默认即显示"全部"。
契约:
1. 全局记忆操作列改为"编辑直达 + 更多下拉":标记待整理/移入回收站/永久删除收入 `el-dropdown`,永久删除以危险色标识(下拉挂载于 body,样式入全局 styles.css),列宽收窄为 104px 单行。新增 `common.moreActions` 文案。
2. 生命周期筛选默认值统一为 `all`:全局记忆、项目记忆(原 `pending`)、搜索页(原 `current`);项目记忆"全部"视图混入检查点与回收站记录,与手动选择"全部"语义一致。历史契约中"默认显示待整理内容"自本节起由本契约取代。
3. 验收:Vitest 覆盖搜索默认 `lifecycle=all` 请求;ESLint、Prettier、vue-tsc 构建通过;发布 ARM 后确认站点提供新构建资源。
## 2026-08-12 整理输出语言设置(已实施)
背景:文档生成提示词未指定输出语言,整理文档语言隐式跟随来源主导语言,混合语言来源下可能漂移甚至 revision 间不一致;英文习惯的使用者需要确定性保证。
契约:
1. `CurationSettings` 新增实例级 `output_language`:`auto`(默认,跟随来源主导语言且单份文档内保持一致)、`zh-CN`、`en-US`;迁移 `20260812_0015` 为存量行回填 `auto`。不做工作区级覆盖(auto 已天然按项目来源自适应)。
2. 文档生成提示词按设置注入确定性语言指令;显式语言时无论来源语言一律按目标语言书写标题与正文。`PROMPT_VERSION` 升级触发下轮全量重生成。
3. REST/MCP 设置读写自动携带该字段;Web 整理设置页新增下拉(自动/中文/English)。
4. 验收:提示词三种模式的指令注入回归、设置读写回归;完整门禁后发布 ARM。
## 2026-08-12 提示词页多场景形态(已实施)
背景:提示词页目前只展示一段通用工作流,用户需要自行摸索"规则文件放哪、如何让 AI 遵守、已有项目如何迁移到 MemRelay 记忆"。
契约:
1. 提示词页改为三个场景:`通用工作流`(现状保留)、`新项目接入`、`已有项目迁移`;语言切换对全部场景生效。
2. 新项目接入:提供各客户端规则文件位置表(Cursor:项目根 `AGENTS.md` 或 `.cursor/rules/*.mdc`;Codex CLI:项目根 `AGENTS.md`,全局 `~/.codex/AGENTS.md`;Claude Code:项目根 `CLAUDE.md`,全局 `~/.claude/CLAUDE.md`;VS Code Copilot:`.github/copilot-instructions.md`;其他客户端:项目根 `AGENTS.md` 事实标准),每行附路径复制按钮;三步流程文案——创建规则文件并粘贴工作流提示词(复制按钮)、说明客户端会自动注入每次会话、新会话验证 AI 已解析 MemRelay 项目。
3. 已有项目迁移:后端新增 `build_migration_prompt`(中英文,随密码库/AI 整理启用状态裁剪),指导 AI 完成——解析或创建项目 → 通读 README/docs/脚本/既有 AI 规则文件 → 按 rule/fact/decision/experience 分类精炼写入(凭证只入密码库、记忆只存条目名)→ 建立迁移基线检查点 → 搜索与上下文抽查校验 → 转入标准工作流;明确只迁移确定的长期知识、原文档保留。`/api/v1/system/prompt` 增加 `variant` 参数(workflow/migration)。
4. 验收:后端覆盖 variant 参数与迁移提示词中英文关键内容、功能开关裁剪;前端覆盖场景切换、位置表渲染与迁移变体请求;完整门禁后发布 ARM。
## 2026-08-12 模型分配的双模式交互重做(已实施)
背景:模型页的"候选模型链"编辑器(自由列表 + 任务类别多选 + 顺序语义)对人不直观;用户期望配置完连接后,模型选择支持两种心智模型:全部任务统一使用一个模型(区分文本与视觉),或按任务类型分别指定。
契约:
1. 连接表单保留"文本模型 + 视觉模型"两个字段不变;其下新增"模型分配"分段开关:`统一模型` 与 `按任务分配`。
2. 统一模型:不显示任何链配置,保存时提交空候选链(后端链自动回落文本模型);提示文案说明所有任务用文本模型、涉图内容用视觉模型。
3. 按任务分配:三个带标签的单选下拉——全局整理、开发项目、高频增量,均可留空表示"跟随文本模型";一个"通用兜底"有序多选(任一模型失败冷却后按顺序尝试);一个冷却秒数输入。视觉模型保持连接级单字段,不按任务拆分。
4. 保存映射:任务专属模型各生成一条对应类别候选,文本模型生成一条通配候选,兜底列表按顺序生成通配候选;该结构与既有后端候选链语义完全兼容,无后端改动。加载时按同样结构反解;无法精确表示的历史高级链(同类别多候选、default 标签等)折叠为"任务槽 + 兜底",提示文案说明保存将按简化结构重写。
5. 候选健康(冷却中标签、最近错误)继续展示在对应的任务槽上。
6. 验收:Vitest 覆盖两种模式的保存载荷映射与历史链反解;ESLint、Prettier、TypeScript/Vite 构建通过;发布 ARM 后浏览器确认两种模式交互与现有生产配置的正确回显。
## 2026-08-09 模型连接测试的可见性与抗中断改造(已实施)
背景:保存/测试模型连接会同步执行完整能力探测(模型列表、双协议文本生成、结构化输出、流式、视觉),受超时与重试影响可达数分钟。现状按钮无加载状态、过程无反馈、结果仅一次性 toast,用户离开页面即错过结果;HTTP 请求被反向代理超时或客户端断开时探测协程可能被取消,依赖状态停留在 `checking`(生产已出现,靠探测循环 5 分钟后自愈)。
契约:
1. 探测单飞与抗中断:`CurationManager` 持有单个探测任务,保存/测试/自动探测统一入口;测试与自动探测复用运行中的任务,保存新配置则取消旧任务后重启。请求侧以 `asyncio.shield` 等待,客户端断开或代理超时不再取消探测,依赖状态必定被写入终态。
2. 启动自愈:服务启动时若依赖状态遗留 `checking`,将 `next_probe_at` 置为当前时间,由探测循环在 30 秒内重新探测,不再依赖旧的探测计划时间。
3. `model_status` 增加 `probe` 字段(running、started_at、trigger),Web 轮询可见探测进行中状态。
4. Web 模型页:保存与测试按钮增加加载状态;探测进行中显示驻留面板——本次将依次验证的项目清单(模型列表、Responses/Chat Completions 文本生成、结构化输出、流式输出、视觉模型)、已耗时秒数、"可离开页面,结果会保留"提示,期间每 2 秒轮询模型状态;完成后面板转为驻留的结果横幅(成功/失败 + 错误码文案 + 检查时间),不再依赖一次性 toast。测试按钮旁增加帮助图标说明测试内容。
5. 探测语义不变:仍使用连接配置的协议、流式与超时设置端到端验证;不改动模型网关。
6. 验收:后端覆盖探测单飞复用、保存替换旧探测、请求取消后状态仍到终态、启动 `checking` 自愈;前端覆盖加载状态、探测面板轮询与结果驻留;完整门禁后发布 ARM。
## 2026-08-08 输出截断显式检测与预算默认值提升(已实施)
背景:生产首个全局 full 整理失败于 `MODEL_OUTPUT_INVALID`。三批文档(4+4+2)的最后一批被旧公式 `max(4096, 2048*n)` 压到 4096 输出上限,推理模型的思考 Token 计入输出导致 JSON 截断,repair 调用同上限再次截断后任务失败;实例配置的 80000 输出上限对小批次不生效,属代码缺陷。已先行以 `62fa810` 将下限提高到 `max(8192, 4096*n)` 并发布。标准 OpenAI 兼容协议无法可靠读取模型最大输出值(`/v1/models` 不含该字段),因此不做"自动读取模型上限",改用协议内的确定性截断信号。
契约:
1. 网关显式检测输出截断:Chat Completions `finish_reason=length`,或 Responses `status=incomplete` 且 `incomplete_details.reason=max_output_tokens`,抛出确定性 `MODEL_OUTPUT_TRUNCATED`(非 transient),不再把截断文本交给 JSON 解析产生误导性的 `MODEL_OUTPUT_INVALID`;配置候选链时按既有语义顺延下一候选。
2. Responses 流式 `response.incomplete` 是正常终止事件:计入流完成标记并作为终态响应参与截断判定,不再被误判为 `MODEL_STREAM_INCOMPLETE` 而按临时故障重试;Chat 流式装配保留 `finish_reason`。
3. 能力探测使用 16/32 Token 微预算,推理模型可能带 length 标记仍返回可用文本;全部探测调用豁免截断检测(`fail_on_truncation=False`),不因该标记把依赖判成配置错误。
4. 文档生成输出预算下限提升为 `max(32768, 4096*文档数)`;实例默认 `context_output_tokens` 从 8000 提升为 32000(SQLAlchemy 客户端默认,仅影响新实例,存量配置值不变)。
5. 暂不实施、观察真实运行后再定:截断后自动折半文档批次重试;对"max_tokens 过大"的 400 自适应钳制并按模型记忆实际上限(可存 `curation_model_candidate_states`);机会式读取 `/models` 非标上限字段。
6. 验收:网关回归覆盖非流式/流式截断、探测豁免与 `finish_reason` 装配;预算与批次断言更新;完整后端门禁通过后发布 ARM。
## 2026-08-08 整理覆盖状态与统计修复(已实施)
生产诊断(192.168.32.100 实例,2026-08-08):26 条活动记忆中 22 条待整理(含 7 条检查点),30 份活动整理文档存在且内容正常。确认以下原因,前两条为实现缺陷:
1. `_apply_documents` 写新 revision 时,文档元数据的 `cited_source_ids` 与 `source_revisions` 只包含本次运行的引用与来源;随后 `rebuild_memory_curation_states` 按“当前活动文档元数据”全量重建生命周期,上一轮已覆盖但本轮未再次引用的记忆整体翻回待整理。生产证据:任务 `ed8aa16d`(18:42)将约 10 条记忆置为已整理,任务 `ce73902c`(23:50)写入 revision 6(每份文档仅引用 1 条新来源)后这些记忆全部回到待整理。
2. 增量任务只收集变化来源,`source_revisions` 缺少未变化旧来源的 key;即使模型再次引用旧来源,revision 匹配也会失败。
3. 检查点计入待整理统计,但整理文档几乎不会逐条引用检查点,统计长期虚高。
4. 附带缺陷:`rebuild_memory_curation_states` 赋回原 `updated_at` 时值未变化、不进入 UPDATE 集合,`onupdate=utcnow` 仍触发,生命周期翻转会污染记忆的 `updated_at`。
修复契约(已按以下最终形态实现):
1. 覆盖元数据跨 revision 累计:`_apply_documents` 写新 revision 时继承活动文档现有 `cited_source_ids`、`source_revisions` 与 `supersedes` 并与本次合并(`_merge_document_coverage`);已删除记忆对应的历史引用在合并时剔除。本次重新引用的来源把 `source_revisions` 更新到新 revision;未再次引用的旧来源保留原 revision,因此被引用记忆再次编辑(revision 变化)仍自动回到待整理,现有 revision 匹配逻辑不变。元数据新增 `job_cited_source_ids` 记录本次任务实际引用,便于追溯;累计规模受范围内记忆数量约束,不会无界增长。
2. 模型对本批次每个来源声明处置:`cited`、`redundant`、`no_action`(文档生成调用的 JSON Schema 新增顶层 `source_dispositions`,Prompt/修复 Prompt 同步说明;PROMPT_VERSION=2026-08-08.1、SCHEMA_VERSION=3)。处置为宽松解析:未知来源 ID 或非法值直接忽略,模型输出缺少该字段时保持现状语义,不阻断任务。实现偏差(等价且更可靠):`redundant`/`no_action` 不写入文档元数据,而是作为持久审阅标记落在 `MemoryReference.reviewed_revision`/`reviewed_job_id` 列——审阅可能不伴随任何文档变化,文档元数据无法承载;重建时 `reviewed_revision == revision` 且未被引用/替代的记忆计为已整理,`covered_reason` 区分 `cited` 与 `reviewed`。来源在收集后被再次编辑(revision 不匹配)时跳过标记,保持待整理。
3. 检查点与“待整理”统计分离:仪表盘 `memory_lifecycle`、AI 整理状态与 rebuild 统计不再把 `checkpoint` 计入 pending/covered/superseded,检查点单独计数(rebuild 返回 `checkpoints`);记忆生命周期筛选新增 `checkpoint` 值,Web 记忆页与项目页提供该筛选;`memory_search` 的 `current` 语义保留检查点可搜索。检查点作为整理来源的行为不变。
4. 修复 rebuild 的 `updated_at` 保留:`_preserve_updated_at` 用 `flag_modified` 强制把原值纳入 UPDATE 集合,杜绝 `onupdate` 覆盖(与 Core update 等价、改动更小)。`reset_memory_curation` 同步修复并清除审阅标记。
5. 迁移 `20260808_0014`:`memory_references` 新增可空 `covered_reason`、`reviewed_revision`、`reviewed_job_id` 列,存量 `covered` 记忆回填 `covered_reason='cited'`。历史活动文档元数据为旧格式,已丢失的跨轮覆盖关系无法凭空恢复;发布后由用户手动触发整理,以新累计语义重建覆盖。
6. 验收:回归覆盖“第二轮重写不翻回已覆盖来源 + 处置声明落库 + revision 变化后审阅失效”(`test_document_rewrite_keeps_previous_citations_and_review_marks_cover_sources`)、“检查点统计分离与筛选”(`test_checkpoints_have_their_own_lifecycle_bucket`)、“updated_at 保留”(同前者断言);生产发布后由用户手动执行整理复测收敛。
## 2026-08-08 AI 整理模型退避链与场景路由(已实施)
背景:当前 `CurationModelConfig` 为单连接单文本模型,模型不可用时任务进入 `waiting_dependency` 等待探测恢复。外部网关(如 Sub2API)能在同一模型的多个账号之间切换,但不做跨模型降级;跨模型退避由 MemRelay 自身实现。
契约(已按以下最终形态实现):
1. 保持单连接(一个 Base URL、Token、协议),`CurationModelConfig` 新增 `candidates_json`(有序候选:模型名、任务类别、启用开关)与 `candidate_cooldown_seconds`(默认 600 秒)。不引入多连接或多 Base URL;候选链为空时回落 `text_model` 单模型链,向后兼容。视觉模型维持单独字段不变。
2. 任务类别与链(实现为集合匹配,与优先级方案等价且更简单):每个任务派生类别集合 `_job_task_classes`——恒含 `default`,`scope=global` 加 `global`,`trigger=source_change` 加 `incremental`,项目 `workspace_type=development` 加 `development`。候选按声明顺序参与匹配:类别为空的候选匹配全部任务,否则要求与任务类别集合有交集;因任务恒含 `default`,标记 `default` 的候选天然充当所有链的兜底。任务内选择粘性:候选一旦成功即服务同一任务后续全部调用,保证证据/合并/文档批次的一致性。
3. 退避语义:单次请求保持现有最多 3 次有界重试(`OpenAICompatibleClient` 不变);候选调用抛出任何 `ModelGatewayError` 时把该候选置入共享冷却(`CurationModelCandidateState.cooling_until`),同一任务内顺延到链上下一候选并记录切换事件;`MODEL_AUTH_FAILED` 属连接级错误,不触发切换。整链耗尽或全部冷却时抛出 `MODEL_CANDIDATES_EXHAUSTED`(transient,`retry_after` 取最近冷却剩余时间),任务进入 `waiting_dependency`。
4. 候选健康是运行时状态,存储于独立表 `curation_model_candidate_states`(按模型名主键),不进配置 revision 快照、不被配置保存重置;配置 revision 快照包含完整候选链,失败任务重试按现有语义使用当前配置,或 `use_original_config` 复用原链。
5. 探测按需进行:不做全候选周期轮询;连接保存时仍只端到端验证 `text_model`。候选可用性由真实任务调用驱动(成功清除冷却、失败进入冷却),冷却到期后自动重新参与选择。
6. 可观测性:`ModelCall.requested_model` 记录每次实际请求的候选模型(每个候选尝试一条记录);执行输出新增 `model_candidate_switched` 事件(原候选、错误码、新候选),不含 Prompt 与秘密值;任务 usage 记录 `model_used`,文档元数据与来源指纹使用实际产出模型。
7. REST/MCP:`ModelConnectionSaveRequest` 新增 `candidates`(模型名去重校验)与 `candidate_cooldown_seconds`;`model_status` 的 connection 返回候选链及每候选健康(冷却状态、最近错误、最近成功/失败时间);MCP `curation_model_connection_save` 同步扩展参数。Web 模型页提供链编辑(增删、类别多选、启用开关)与健康标签展示。
8. 验收:单元覆盖类别路由(`test_job_task_classes_follow_scope_trigger_and_workspace`)、冷却/跨任务共享/整链耗尽(`test_candidate_chain_routes_falls_back_and_cools_failed_models`)、任务内退避与调用记录/切换事件(`test_call_model_switches_candidates_and_records_each_attempt`);真实网关跨模型退避留待生产观察(用户手动触发整理验收)。未配置 AI 的零配置模式行为不变。
交付顺序:先交付“整理覆盖状态与统计修复”(生产可见的正确性问题),再交付“模型退避链与场景路由”。两份方案已在同一提交中实现并通过完整前后端门禁;发布到 ARM 生产实例后不自动触发整理任务,由用户手动执行一次整理观察新逻辑(冗余文档处置、未整理残留收敛)作为最终验收。
## 2026-08-07 AI 整理长请求断线修复
- 生产任务在来源收集和批次准备完成后,长时间非流式 Responses 请求间歇出现 `Server disconnected without sending a response.`;短模型探测仍可成功,因此该问题属于长请求传输稳定性,而不是 SQLite、Basic Memory 或文档写回故障。
- `httpx.RemoteProtocolError` 属于 `TransportError` 而不是 `NetworkError`。模型网关必须统一捕获全部 `httpx.TransportError`,映射为可恢复的 `MODEL_UNAVAILABLE`,让任务进入 `waiting_dependency`、按有界退避等待探测恢复,而不是被最外层误标记为永久 `CURATION_FAILED`。
- 模型调用记录必须在所有异常路径结束;已知模型异常保存稳定错误码,未知异常保存 `MODEL_CALL_FAILED` 后继续向上抛出。服务启动时将上个进程遗留的 `running` 模型调用标记为 `MODEL_CALL_INTERRUPTED`,避免 Web/MCP 长期显示不存在的运行中调用。
- 回归测试覆盖模型列表与生成请求的远端协议断线、请求内重试、整理任务进入依赖等待、未知调用异常收尾和启动清理遗留调用。完整后端门禁通过后才允许发布。
- 正式实例发布前创建一致性备份,只原生重建 ARM64 `memrelay` 服务;模型连接启用已验证可用的流式 Responses,使用当前活动模型配置重试每个范围最新的一条传输失败任务,不批量重放已经被后续成功任务覆盖的旧失败记录。
- 生产重试进一步发现实例并发值为 3 时,多个任务会同时读取本地 Basic Memory 并触发 `BASIC_MEMORY_TIMEOUT`。并发降低或停用整理时现有 worker 必须在当前任务结束后自动退休,不能只增不减;Basic Memory 的超时和暂时不可用必须按任务级有界退避重新排队,不得永久失败,也不得错误污染模型依赖状态。
- 流式模型请求发生网络、协议断线或服务端临时故障时,只重试当前流式模式;只有服务明确拒绝流式参数或协议时才允许退回非流式,避免一次逻辑调用被放大为多轮长超时。配置的模型超时必须直接作为每次流式读取超时,不能隐式翻倍。
- 长模型调用每 60 秒写入一次不含 Prompt 或响应正文的安全进度事件;成功事件显示底层请求尝试次数和端到端总耗时。服务停止或 worker 取消时立即结束模型调用记录,避免依赖启动清理才能修正状态。
- 修复以提交 `c3304bf` 发布到正式 ARM64 实例。发布前一致性备份为 `memrelay-20260807T140405Z.tar.gz`,新镜像摘要为 `sha256:050b38618ae05c9ae8161b79252bd27e45cd983785d8e02a868d0970f609994a`,旧镜像保留为 `memrelay:pre-curation-recovery-20260807`。发布后两个容器健康,LAN/公网 readiness 均为 200,运行时 worker 为 `1 / 1`,队列、活动任务和运行中模型调用均为 0。
- 正式实例通过受控故障实验验证本地依赖恢复:停止 Basic Memory 后重试旧超时任务,新任务以 `BASIC_MEMORY_UNAVAILABLE`、`retries=1` 和未来 `next_retry_at` 回到 `queued`,尝试状态为 `waiting_dependency`,执行输出为 `local_dependency_waiting`;测试任务随后取消,Basic Memory 恢复健康,模型依赖未被污染。
## 2026-08-07 全链路复审结果
- 对照设计初衷重新核验记忆/项目上下文、检查点与时间线、外部密码库 CRUD/TOTP、目录化文件仓储、签名上传下载、MCP、动态提示词、可选 AI 整理和可选记忆 Git;Web、REST 与 MCP 仍共用同一服务层,AI/Git 未配置时基础模式可以独立运行。
- 修正能力发现的一致性:语义搜索状态根据 Basic Memory 实际健康状态返回,不再固定宣称已启用;`memrelay://capabilities` 与 `capabilities_get` 复用同一完整能力清单;MCP `dashboard_get` 补齐数据库、整理、记忆 Git 和 Basic Memory 运行状态。
- ARM64 线上验收发现 AI 整理状态包含时间字段时 `memrelay://capabilities` 无法直接 JSON 序列化;资源输出统一经过 FastAPI `jsonable_encoder`,并增加带真实 `datetime` 状态的 Streamable HTTP MCP 回归测试。
- 修正桌面文件仓储目录按钮的可访问名称,并让 Playwright 只定位本次创建的目录,避免多设备/历史目录存在时出现歧义。
- 本轮门禁:后端 `153 passed, 18 skipped`、Ruff 通过;前端 `34 passed`、ESLint、Prettier、TypeScript/Vite 构建通过;真实桌面 Playwright `1 passed`;隔离 Docker 实例的 Streamable HTTP MCP 实测 `95` 个工具、`3` 个资源。
- 本地审计数据、测试 Token、测试文件和临时容器只存在于隔离目录,正式数据不在本轮本地测试中修改;线上发布必须在提交后重新备份并只重建 `memrelay` 服务。
- ARM64 发布后公网 HTTPS、REST 登录、95 个 MCP 工具、3 个 MCP Resources、外部 Vaultwarden 解锁、Basic Memory 语义搜索、SQLite WAL 和记忆 Git 均通过真实验证;OpenResty 只缓存带哈希的 `/assets/`,API 与 MCP 不进入代理缓存。AI 上游短暂 503 时任务保持有限合并队列,探测恢复后会自动重新排队并继续执行。
## 持续交付审计修正
- 密码库连接兼容私有网络和反向代理环境中的 HTTP/HTTPS Vaultwarden/Bitwarden 地址,不把是否启用 TLS 作为功能前置条件。
- AI 自动保存凭证时,只在名称相同且请求中提供的用户名、URI 等身份字段与已有条目吻合时自动更新;多个候选必须返回歧义,不能因“同名或任一 URI 相同”误覆盖其他账号。
- 文件元数据更新采用真正的局部更新语义,未提交字段保持原值;MCP 同时提供明确清空可空字段和解除项目关联的能力。
- 文件说明、版本、用途、标签或项目归属变化必须生成新的整理活动版本,不能因为文件正文校验值未变化而被静默去重。
- 一次性上传任务必须持久保存发起来源和记忆档案;上传完成、元数据更新、移动与删除由 Web 或 MCP 发起时,都必须以正确的 `origin` 和 `usage_profile_id` 进入同一整理事件流。
- 整理来源达到文件数量或字符预算时,未入选但仍存在的文件只能标记为未覆盖,不能生成删除墓碑;仅 MCP 来源策略不得把活动仓储文件误判为已删除。
- 文件扫描与密码库同步周期在运行中启用、停用或修改后必须生效,不要求重启服务,也不得在周期设为 `0` 时形成高频空转。
- 启动、周期、Web 和 MCP 文件扫描发现的外部新增、修改、恢复或丢失文件必须生成准确的整理活动;目录变化只维护目录表,不作为正文来源。
- 未显式指定 `scope` 但指定 `project_id` 的 `memory_search` 必须同时搜索该项目和当前记忆空间可见的全局记忆/整理文档,与 `context_get` 的全局规则继承语义保持一致;显式 `scope=project` 或 `scope=global` 时仍严格限定范围。
- MCP 必须提供写权限保护的 `project_resolve_or_create`:优先按 Git remote、设备目录和项目名称解析,找不到时仅用已提供的标识创建项目,并返回项目与 `created` 标记;动态提示词和能力清单必须引用真实存在的工具,避免新项目首个会话依赖两次非原子调用。
- 上述行为必须同时由 REST 与 MCP 回归测试覆盖,并继续保持 Web、REST、MCP 共用同一服务层。
## 原始记忆生命周期与稳定整理文档优化
> 执行状态:已完成。原始 Markdown 和完整来源追溯保持不变,默认浏览、搜索和上下文只关注尚未整理或重新发生变化的内容;数据库层保证同一范围、记忆空间、项目和文档类型只有一个活动整理文档。
1. 为原始记忆增加可重建的整理状态:`pending`、`covered`、`superseded`。记录被哪些活动整理文档覆盖、覆盖时的原始记忆 revision、整理任务和整理时间;原始 Markdown 仍是正文来源,整理状态属于可由活动整理文档元数据和变化游标重建的 SQLite 派生索引。
2. 新建或编辑原始记忆时自动回到 `pending`,清除旧覆盖关系;成功整理后,仅把被模型明确引用的记忆标记为 `covered`,把 `supersedes` 明确指出的旧记忆标记为 `superseded`,未被引用的来源继续保持 `pending`,避免静默隐藏未处理内容。
3. 全局和项目整理文档继续按稳定文档更新 revision,不为同类型内容反复创建文件。增加基于 `scope + COALESCE(project_id) + COALESCE(usage_profile_id) + document_type` 的活动文档唯一索引;迁移时保留最新活动文档并把历史重复项标记为已替代,不删除历史 revision。
4. `context_get` 优先读取稳定整理文档,并补充所有类型的 `pending` 原始记忆、整理游标之后发生变化的内容和最近检查点;为待整理来源和最新进度保留独立上下文预算,避免超长整理文档独占返回内容。`memory_search` 默认使用 `current`,同时搜索活动整理文档和待整理来源,排除 `covered`、`superseded` 与回收站内容;Web/MCP 可以显式检索这些历史来源。
5. 全局记忆页和项目记忆页提供“待整理、已整理、已替代、回收站、全部”筛选和状态数量,默认显示待整理内容;AI 未启用时所有现有活动记忆保持 `pending`,页面和基础记忆工作流不受影响。
6. REST 与 MCP 返回整理状态、覆盖文档、覆盖 revision 和整理时间;`memory_list`、`memory_search` 支持生命周期筛选,并提供把已整理或已替代记忆重新放回待整理队列的能力。重新整理只更新派生状态并记录新的变化事件,不复制正文。
7. 仪表盘和 AI 整理状态增加待整理、已整理、已替代和活动整理文档统计;整理任务详情记录本次覆盖、替代和仍待整理的记忆数量。
8. 启动时检查并修复缺失或过期的派生状态;迁移、备份恢复和旧实例升级后无需手工整理数据库。覆盖状态重建不得调用外部 AI,也不得修改原始 Markdown。
9. 验收覆盖:同类型整理多次只增加 revision、不增加活动文件;被引用记忆退出默认列表和搜索;编辑后重新变为待整理;未引用来源不被隐藏;已替代来源可追溯;AI/Git 均未配置时基础模式保持原行为;Windows AMD64 与 ARM64 正式实例迁移、备份和公网 Web/MCP 均正常。
> 生命周期优化验收:后端 Ruff 与全量 pytest 通过,结果为 `141 passed, 18 skipped`;前端 33 项 Vitest、ESLint、Prettier、TypeScript/Vite 构建和桌面浏览器布局通过。Windows Docker Desktop AMD64 和物理 Armbian ARM64 均完成原生镜像构建;正式实例迁移到 `20260806_0012`,启动重建得到 19 条待整理、4 条已整理、1 条已替代和 13 份活动整理文档,LAN readiness、公网 HTTPS 页面和生命周期筛选均正常。
> 执行状态:已完成。AI 整理与记忆 Git 保持默认关闭、彼此独立且完全可选;两者均未配置时不探测、不排队、不初始化仓库,基础 Web、REST、MCP、记忆、项目、搜索、密码库和文件仓储完整可用。Responses 非流式、SSE、原生 JSON Schema、真实整理、历史/差异/回滚、Windows AMD64、Armbian ARM64、备份恢复、正式迁移、公网 HTTPS/MCP 和重启恢复均已通过验收。
> 零配置基础模式是正式支持的完整运行方式,不是降级或试用模式。初始化、创建项目、使用 Web/MCP、健康检查和部署均不得要求填写模型或 Git 配置;AI 整理与记忆 Git 只能由用户分别显式启用,未启用时不产生后台探测、队列、工作区 clone、`.git` 目录、错误告警或额外外部请求。
## 最终验收结果
- 后端完整环境回归、Ruff、真实 Responses、真实 Git、并发、备份冷恢复和迁移链均通过;当前无外部凭证回归为 `145 passed, 18 skipped`,跳过项已在带真实依赖的独立验收中覆盖。
- 前端 `27 passed`,ESLint、Prettier、TypeScript、Vite 和桌面浏览器验收全部通过。
- Windows Docker Desktop 在所有可选构建加速参数为空时成功构建 `linux/amd64` 镜像;物理 Armbian 原生构建并运行 `linux/arm64` 镜像。
- 正式实例部署于 `192.168.32.100:/opt/1panel/docker/compose/memrelay`,数据位于 `/data/memrelay-stack`,数据库迁移至 `20260806_0013`;容器重启后项目、记忆、密码库、MCP 以及中断的 AI 整理任务自动恢复。
- `https://mr.asio.asia` 的登录、REST、Streamable HTTP MCP 均通过;上一轮线上验收发现 93 个工具和 3 个资源,本轮源码与隔离实例已核对为 95 个工具和 3 个资源。OpenResty 只缓存 `/assets/`,动态 API/MCP 不缓存。
- 正式实例在 AI/Git 都未配置时模型配置、整理队列、Git 连接和记忆仓库均为空,现有 2 个项目、23 条记忆引用、文件与已连接密码库保持可用。
## 完整交付审计与真实模型验收
1. 保留已通过的可选模式、SQLite WAL、多 worker、备份恢复、Windows AMD64 和 Armbian ARM64 能力,并对照两个正式计划逐项重新取证,不能用单元测试数量替代功能验收。
2. 修正项目源码 Git 地址的“身份规范化值”和“真实 clone URL”混用问题;补齐工作区来源策略、分支、密码库凭证引用、整理开关、Agent 最近同步和来源覆盖状态的 REST/MCP/Web 管理。
3. 修正项目归档与永久删除顺序:普通归档不得移动仍在使用的仓库;永久删除必须先删除 Markdown、生成本地 Git 删除提交,再归档 `per_workspace` 历史并保留可恢复的远程同步任务。
4. 补齐整理文档 revision 差异、调度默认恢复、间隔锚点、记忆空间统计与已有 MCP Token 重新绑定能力,并保持 Web、REST 与 MCP 同一服务层。
5. 扩展来源秘密过滤和提示注入验收,覆盖常见密码、Bearer/API Token、TOTP 种子、私钥、连接 URI 和常见平台 Token;测试凭证不得进入 Markdown、Git、日志、错误或临时产物。
6. 增加真实 Git 断网补推、服务重启、远程分叉、项目删除历史、Agent 优先/源码 Git 兜底、所有工作区模板、调度继承/恢复和真实 Streamable HTTP MCP 测试。
7. 使用运行时注入的新网关和 `gpt-5.6-sol` 完成 Responses 非流式、SSE、JSON Schema、模型探测、真实全局/项目整理、历史、差异、回滚及故障恢复;密钥只存在于进程环境或加密测试数据库。
8. 重新执行完整 pytest、Ruff、Vitest、ESLint、Prettier、TypeScript、Vite、Playwright、Windows Docker、备份冷恢复、ARM64 原生构建、正式数据迁移和公网 HTTPS/MCP 验收,最后清理测试环境并覆盖部署。
审计修正已经锁定以下契约:项目级关闭或归档会使其待处理整理任务停止;全局首次启用 AI 只为项目级启用的工作区建立基线;增量整理把已删除的记忆和文件作为来源墓碑处理;`auto` 来源策略在 Agent 数据新鲜且完整时不拉取源码 Git,过期或不足时才使用 Git 兜底;静默调度的 `inherit`、`override`、`disabled` 与周期调度保持一致;失败任务默认使用当前模型配置重试,也可显式复用任务原配置 revision。
## 无人值守 AI 整理与可选 Git 版本管理完整交付
本轮以 `docs/ai-curation-plan.md` 为详细功能、公共接口、可靠性和验收标准的权威文档,所有能力一次完整实现,不发布缺少计划能力的中间版本。
执行顺序:
1. 增加整理任务、尝试、来源、变化日志、文档、模型连接、依赖状态、调度、记忆空间及 Git 连接/仓库/同步任务的 Alembic 迁移和服务层。
2. 实现有界任务合并、运行中单一后继、调度租约、来源游标、内部事件过滤、模型配置快照、预算分批和异常恢复。
3. 实现 OpenAI-compatible Responses 与 Chat Completions、SSE/非流式、结构化输出、能力探测、退避暂停和自动恢复;真实 Responses 验收使用运行时注入的测试凭证,不把密钥写入 Git、日志或快照。
4. 实现 MCP/文件/Git 来源收集、文本/PDF/Office/图片 OCR/压缩包提取、可信边界、秘密过滤和整理 Markdown 自动应用。
5. 实现默认关闭的记忆 Git、本地历史、可选 remote、双凭证存储、push-to-create、离线补推、分叉处理、删除归档、历史/差异/恢复及远程检查/导入/冷启动。
6. 完成 REST、MCP、中文/英文桌面 Web、动态 Agent 提示词、状态诊断和 README/许可文档;AI 与 Git 未配置时必须保持当前基础服务行为。
7. 完成后端单元/集成、真实 Responses、调度与并发、MCP、前端 Vitest/TypeScript/ESLint/构建、Playwright、Windows Docker Desktop AMD64 和 Armbian ARM64 验收。
8. 通过全部验收后备份并部署到 `192.168.32.100:/opt/1panel/docker/compose/memrelay`,沿用 `/data/memrelay-stack`、端口 `3003` 和 `mr.asio.asia`,验证 LAN、公网 HTTPS、MCP、数据迁移、重启恢复与资源状态。
交付门槛:
- 模型长期不可用并积累大量变化时队列有界且不漏事件;恢复后自动补齐。
- AI 和 Git 可分别关闭,两者都未配置时不探测、不排队、不初始化仓库,也不影响现有功能。
- 所有模型、Git、Basic Memory 和文件外部 I/O 均不占用 SQLite 长事务;多 worker 不重复调度或领取。
- 测试密钥只通过进程环境或隔离的加密测试数据库使用;正式部署不包含测试连接、密钥或模型任务。
- Windows AMD64 与真实 Armbian ARM64 上全部测试和端到端工作流通过后才允许部署完成。
## 完整 AI 开发记忆工作流与正式部署
### 目标
- 让 Codex、Cursor、Claude Code 等客户端在新项目、新设备和新会话中,仅配置 MCP 与生成的 Agent 提示词即可识别项目、恢复上下文、持续记录开发历史、复用凭证和管理文件。
- Web、REST 与 MCP 共用同一套项目、记忆、检查点、密码库、文件仓储和系统能力,避免只在页面或单一客户端中可用的功能。
- 开发历史使用检查点统一记录,每条包含完成内容、原因、关键修改、验证结果、问题与解决方案及下一步,时间精确到秒并按最新在前展示。
- 对 MemRelay、Basic Memory、本地语义模型、Vaultwarden 连接、文件仓储、Web、REST、MCP、Docker 与反向代理进行完整能力和诊断审计,确认不存在静默降级、接口缺口或阻断主要工作流的问题。
### 后端与数据
- 新实例首次启动自动创建管理员 `admin`,初始密码为 `242520`;已有实例管理员不受影响,初始化接口继续作为显式关闭自动初始化时的兼容入口。
- 增加记忆和检查点永久删除能力,同时删除 Basic Memory Markdown 与 SQLite 可重建引用;归档和永久删除保持为不同操作。
- 记忆 frontmatter 明确保存 `created_at` 与 `updated_at`,更新时保留创建时间;检查点默认生成秒级标题和结构化正文。
- 记忆搜索结果返回范围、项目 ID 和项目名称,全局记忆明确标记为全局。
- 增加项目文档 ZIP 导出,直接生成 `aidocs/project_context.md`、项目记忆、全局记忆与清单;不让 AI 逐条读取后重写。导出使用短期签名下载地址,Web 和 MCP 均可准备下载。
- 仪表盘接口提供记忆类型分布、近 14 天新增记忆趋势、项目记忆排行、最近检查点、检查点数量、文件容量、有效 Token 与密码库状态。
### MCP 与 Agent 提示词
- 补齐项目创建、更新、归档、删除和文档导出;记忆列表、永久删除;检查点删除;密码库同步;仪表盘与系统设置查询/更新等 MCP 工具。
- 能力资源和 `capabilities_get` 返回实际可用工具、权限及推荐工作流;破坏性操作保留明确标记,但不人为削减读写 Token 的管理能力。
- 动态提示词提供中英文版本并锁定工作流:会话开始发现能力和解析项目,支持 Resource 的客户端继续读取 `memrelay://guide` 与 `memrelay://capabilities` 获取当前能力状态;工作前读取上下文与最新检查点,过程中保存规则、偏好、事实、决定和经验,获得凭证后立即写入密码库,重要节点和结束前保存结构化检查点。
- 提示词要求登录或连接前先查密码库,唯一匹配直接复用;通用文件进入仓储;需要本地项目文档时直接下载并解压 ZIP 到 `aidocs/`,同时确保 `.gitignore` 包含 `aidocs/`。
### Web
- 已有记忆的 Markdown 编辑器每次打开默认预览,新建记忆默认编辑。
- 项目列表增加搜索,项目名和 Git remote 分行显示;项目详情提供“项目记忆”和“开发时间线”标签及项目文档下载。
- 不设置独立进度页面;项目开发时间线显示秒级检查点并支持创建、编辑和删除;搜索与编辑页面显示每条结果所属项目或全局范围。
- 弹窗头部和底部操作区固定,正文按内容在内部滚动;Markdown、预览、日志和列表使用独立滚动区域并按桌面浏览器高度自适应。普通表单标签在左、控件在右,大型多行编辑器标签在上;提示文案使用标题旁帮助图标并在悬停时显示。
- MCP Token 页面同时管理记忆空间;默认提供共享/全部空间范围,全部记忆空间 Token 自动覆盖后续新增空间,具体空间 Token 仍可限制写入范围。
- 仪表盘使用原生 CSS、SVG 折线图和环形占比图展示聚合统计、趋势、依赖状态与最近活动,不新增重量级图表依赖;最近开发活动固定在依赖状态之后。
- 全局 AI 整理调度不显示或提交项目字段,项目调度才允许选择具体项目。
### 正式数据、文档与部署
- 更新 MemRelay 正式全局记忆、BDYG18Pro 项目记忆及最新开发检查点,清理无效测试数据。
- 将当前仍有效且可明确定位的基础设施账号、密码、Token 和服务登录信息精确匹配写入已连接 Vaultwarden,避免重复;普通记忆仅保存条目名称和用途。
- README 补充部署、使用、MCP 工具、Agent 提示词、备份恢复、项目导出,以及 AI、MCP、MemRelay、Basic Memory、Vaultwarden 和文件仓储的 Mermaid 架构图、关系图与时序图。
- 在 Windows Docker Desktop 完成 AMD64 回归后,构建并部署到 `192.168.32.100` 的 `/opt/1panel/docker/compose/memrelay`,数据保存在 `/data/memrelay-stack`,主机端口使用 `3003`。
- 备份 OpenWrt FRPC 配置后新增 `mr.asio.asia` 到 `192.168.32.100:3003` 的 HTTP 映射,验证公网 HTTPS、MCP Streamable HTTP、登录 Cookie 和转发头;API、MCP、认证及签名下载禁用代理缓存,仅静态资源允许长期缓存。
- 正式服务、数据和公网访问验收通过后关闭本机 MemRelay Compose,保留源码与构建缓存。
### 验收顺序
1. 后端迁移、单元测试、真实 Basic Memory、语义模型与 Vaultwarden 集成测试,并检查依赖健康、索引状态、降级状态和诊断信息。
2. MCP 工具发现、权限、完整新项目/新会话工作流与项目 ZIP 导出测试。
3. 前端 Vitest、TypeScript、ESLint、Prettier、Vite 构建和桌面 Playwright 验收。
4. Windows AMD64 镜像验收、Armbian ARM64 原生构建部署、FRP 与公网 HTTPS 验收。
5. 清理临时内容,更新时间线记忆、README 与第三方说明,检查 `.gitignore` 和全部工作树改动后提交独立中文 Commit。
## 总体方案
- MemRelay 是单管理员、单共享工作区的自托管 AI 记忆、密码库接入和文件仓储服务。
- 后端:Python 3.12、FastAPI、FastMCP、Pydantic、SQLAlchemy 2、Alembic、SQLite,使用 `uv` 管理依赖。
- 前端:Vue 3、TypeScript、Vite、Pinia、Vue Router、Element Plus、Vue I18n,使用 `pnpm`。
- 记忆引擎:Basic Memory `v0.22.1`,通过 Git 子模块固定源码并构建定制镜像。
- 密码库:只连接用户已有的外部 Vaultwarden/Bitwarden,不部署密码库服务。
- 许可证:AGPL-3.0-only;同步提供第三方依赖和本地语义模型许可清单。
- 支持 Windows Docker Desktop 的 Linux 容器模式,以及 Linux 原生 Docker/Compose 部署;不支持 Windows 容器模式。
- 发布固定版本的 `linux/amd64`、`linux/arm64` Docker 镜像,不绑定特定 CPU 型号、核心数、内存容量或 Linux 发行版。
- 其他架构不作为正式发布和测试目标;不为缺少上游依赖的架构维护专用实现。
## 执行顺序
### 1. 同步计划与源码
- 任何代码实施前,先将本 Codex 计划完整同步到 `docs/implementation-plan.md`。
- 更新 `aidocs/project_context.md`,检查 `.gitignore`,提交 `docs: 同步完整实施计划`。
- 将 Basic Memory 添加为 `third_party/basic-memory` Git 子模块,固定到 `v0.22.1`,禁止跟随浮动分支。
- 提交 `.gitmodules` 和子模块引用,提交 `chore: 引入Basic Memory源码`。
- 后续所有实现必须同时遵循 Codex 计划和正式计划文档;决策变化时先同步两处。
### 2. 阶段零验证
- 从本地 Basic Memory 子模块审查 MCP 工具、Markdown 格式、自定义元信息、项目、归档、索引和错误模型。
- 验证 Streamable HTTP MCP 的写入、读取、搜索、移动、归档、索引重建和并发行为。
- 构建定制 Basic Memory 镜像,预置 `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2`。
- FastEmbed 完全在本地运行,不配置 OpenAI/LiteLLM,不消耗外部 AI Token 或产生 API 费用。
- ONNX/FastEmbed 线程数根据容器可用 CPU 自动选择并允许环境变量覆盖,模型缓存持久化到 `/data/basic-memory/cache`。
- 在 Windows Docker Desktop 的 Linux 容器环境验证 `linux/amd64`,在真实 ARM64 Linux 设备验证 `linux/arm64`;两种镜像均须能够启动并提供完整能力。记录模型加载、首次索引、增量写入、查询延迟和内存占用,用于发布说明和后续优化,不设置特定硬件性能门槛,也不使用 QEMU 模拟替代正式 ARM64 验收。
- 模型故障时保留全文、标签、元数据和关系搜索,Web 显示语义搜索降级状态。
- 验证 Bitwarden CLI `2026.7.0` 在 AMD64/ARM64 下连接外部 Vaultwarden/Bitwarden、注册邮箱加主密码登录、个人 API 密钥登录、同步、TOTP、自动解锁、离线缓存和并发读取。
- 验证不通过时停止后续开发,先修正兼容版本或接口契约,不由实现者临时替换架构。
### 3. 基础框架与数据
- 建立 `backend/`、`frontend/`、`deploy/`、`scripts/`、`third_party/` 目录。
- Web 使用 HttpOnly 服务端会话;管理员密码使用 Argon2id;MCP 使用 Bearer Token。
- 部署主密钥首次启动自动生成到持久化目录;可取回 Token 和密码库登录凭据使用 AES-GCM 加密。
- SQLite 保存管理员、会话、Token、项目、项目别名、记忆引用、幂等请求、密码库连接、凭证映射、文件目录、上传任务和系统设置。
- Alembic 管理迁移;迁移前备份数据库,失败时停止启动并保留旧数据。
- 后端统一错误码、超时、取消、健康检查和结构化日志;日志不保存密码、Token、TOTP 或文件上传地址。
### 4. 记忆与项目
- Basic Memory Markdown 是记忆正文唯一来源,按 `global/`、`projects/<id>/`、`archive/` 组织。
- frontmatter 保存稳定 ID、范围、类型、项目、状态、revision、标签和时间;MemRelay SQLite 只保存可重建引用。
- 统一 SSH/HTTPS Git remote,结合目录、仓库名、人工别名和设备路径识别项目;歧义选择一次后保存映射。
- 明确规则、偏好、稳定事实、已确定决定和有效进度由读写 MCP 客户端自动保存。
- 推测、临时信息、冲突内容、普通闲聊及秘密值不自动保存;任务无实质变化时不生成空检查点。
- 记忆更新携带 revision;冲突返回最新内容;检查点只追加;创建使用请求 ID 保证幂等。
- Obsidian 可以直接读取 Markdown;第一版不保证外部编辑后的同步,所有正式写入统一通过 Web/MCP。
- 上下文依次组装全局规则、项目规则、偏好、事实、决定、最新检查点和相关经验,并限制返回长度。
### 5. 外部密码库
- 一个 MemRelay 实例维护一个外部 Vaultwarden/Bitwarden 连接。
- Web 支持两种登录方式:注册邮箱加主密码,或个人 API 密钥的 `client_id`、`client_secret` 加主密码;账号密码方式必须填写 Vaultwarden/Bitwarden 的注册邮箱,不能使用显示名称。
- API 密钥只负责 CLI 身份认证,主密码仍用于解锁密码库;账号、主密码、`client_id` 和 `client_secret` 均使用 AES-GCM 加密保存且不进入日志。
- 第一版不支持密码库账号二步验证;启用二步验证的账号使用个人 API 密钥方式连接。
- Bitwarden CLI 配置和加密缓存持久化,服务启动后自动登录和解锁。
- 默认每 5 分钟同步并支持 Web 手动同步。
- 外部服务不可达时允许读取最后一次成功同步的加密缓存,结果标明缓存状态和最后同步时间;恢复联网后自动刷新。
- 唯一凭证自动解析;多个候选选择一次并保存非秘密映射;未找到时才创建或询问用户。
- Web 和 MCP 支持登录条目的完整列表、详情、新建、修改和删除,字段覆盖账号、密码、多个 URI、备注、TOTP 和自定义字段。
- MCP 在 AI 获得、生成或修改可复用凭证后自动保存;没有条目 ID 时先按名称匹配,并使用请求中实际提供的用户名和 URI 继续收窄,唯一匹配才更新,没有匹配则创建,多个匹配返回稳定歧义错误。
- 秘密结果不进入普通日志、记忆或文件目录表。
### 6. 文件仓储
- 文件正文保存在配置目录;SQLite 文件目录表保存路径、名称、可空说明、可空版本、用途、标签、项目、MIME、大小、校验值、状态和时间。
- 启动时扫描,默认每 15 分钟周期扫描,Web/MCP 支持手动扫描;管理员可以调整或关闭周期扫描。
- Web/MCP 操作后立即更新目录表;外部新增、修改和丢失文件由扫描补齐。
- 文件版本只是可搜索字段,不保存历史版本。
- 只读 Token 可以搜索、列出和下载;读写 Token 可以更新说明、移动、重命名、删除及准备上传。
- 覆盖和删除只在用户明确要求时执行。
- MCP 不传输文件正文;`file_upload_prepare` 创建上传任务并返回一次性短期 HTTP PUT 地址。
- PUT 流写入临时文件,校验大小和可选哈希后原子移动,随后自动写入目录表;失败临时文件定期清理。
- 下载使用短期签名 GET 地址,支持 HTTP Range;上传和下载地址默认 10 分钟有效。
### 7. Web、部署与恢复
- 页面包括初始化、仪表盘、全局记忆、项目、搜索编辑、外部密码库、文件仓储、MCP Token、客户端配置、提示词、系统与备份;检查点统一在项目开发时间线中管理。
- 中文为默认语言,可切换英文;只适配桌面浏览器。
- 为 Codex、Cursor、Claude Code、VS Code 和通用 Streamable HTTP MCP 客户端生成配置和动态提示词。
- Compose 只包含 `memrelay` 和定制 `basic-memory`,统一挂载 `/data`。
- 同一套 Compose 配置用于 Windows Docker Desktop 和 Linux Docker;宿主机差异只通过环境变量、卷路径和部署脚本处理。
- 支持 UID/GID、时区、公共 URL、扫描周期、文件容量、上传限制和外部密码库配置。
- HTTP 不附加加密;HTTPS 由反向代理提供 TLS;生成地址沿用公共 URL 协议。
- 提供 Linux Shell 和 Windows PowerShell 手动备份脚本:停止 Compose、归档 `/data`、生成版本清单与校验值、恢复服务。
- 不实现定时备份和 Web 备份调度;外部 Vaultwarden/Bitwarden 数据由其自身备份。
## 公共接口
- REST 统一使用 `/api/v1`,覆盖认证、状态、项目、记忆、检查点、密码库、文件、上传任务、Token、客户端配置和系统设置。
- MCP 项目与记忆工具:`capabilities_get`、`project_create/update/archive/delete/resolve/resolve_or_create/list/export_prepare`、`context_get`、`memory_list/search/get/save/mark_pending/archive/delete`、`checkpoint_get/save/delete`。
- MCP 密码库工具:`secret_capabilities`、`secret_list`、`secret_item_get`、`secret_search`、`secret_resolve`、`secret_get`、`secret_totp`、`secret_save`、`secret_delete`。
- MCP 文件工具:`file_search/list/get`、`file_directory_create`、`file_upload_prepare/status`、`file_metadata_update`、`file_move`、`file_delete`、`file_scan`。
- MCP 整理工具:`curation_run/status/history/source_submit/cancel/retry`、`curated_document_list/get/update/history/diff/revert`、`curation_settings_get/update`、`curation_schedule_list/save/delete/reset_defaults/preview`、`curation_model_connection_status/save/test`、`curation_model_list`、`usage_profile_list/save/token_bind/delete`。
- MCP 记忆 Git 工具:`git_connection_get/save/test/delete`、`git_mode_migration_preview/execute`、`memory_repository_list/create/status/sync/history/diff`、`memory_version_get/restore`、`memory_snapshot_restore`、`memory_repository_remote_inspect`、`memory_remote_import/bootstrap`、`memory_repository_unbind/archive_purge`。历史查询支持时间、提交者、操作类型、工作区和资源 ID 筛选。
- MCP 系统工具:`dashboard_get`、`system_settings_get/update`、`token_list/create/reveal/revoke/delete`。
- MCP Resources:`memrelay://guide`、`memrelay://capabilities`、`memrelay://projects`。
- 读取和状态查询允许一次受控重试;写入不自动重试;超时、取消、冲突、候选歧义和依赖不可用返回稳定错误码。
## 测试与验收
- pytest 覆盖权限、加密、项目归一、revision、幂等、自动记忆、密码库映射与条目 CRUD、签名 URL、扫描和错误映射。
- 使用真实 Basic Memory 和测试 Vaultwarden 进行集成测试,覆盖在线、断网、重启、离线缓存与索引重建。
- 使用固定中英文检索样本验证多语言语义搜索,并断言运行期间没有外部嵌入 API 请求。
- Vitest 覆盖状态、表单、国际化和组件;Playwright 覆盖桌面端完整工作流。
- 验证 MCP 完整文件管理、一次性 PUT、Range 下载、15 分钟扫描、目录表实时更新和说明/版本搜索。
- 验证 HTTP、反向代理 HTTPS、Windows Docker Desktop、Linux Docker、`linux/amd64`、`linux/arm64`、目录权限、迁移失败和完整备份恢复。
- 每个阶段完成后清理临时内容、更新 `aidocs/project_context.md`、检查 `.gitignore` 并提交独立中文 Git commit。
## 已锁定默认值
- 单实例、单管理员、单共享工作区、单外部密码库连接。
- Element Plus、Vue I18n、AGPL-3.0-only。
- Basic Memory 以 Git 子模块固定在 `third_party/basic-memory`。
- Obsidian 只读兼容,不承诺外部 Markdown 编辑同步。
- 本地多语言 MiniLM 默认启用并预置镜像,不使用付费嵌入服务。
- 明确记忆自动保存;已有唯一凭证无感使用。
- 新获得或生成的可复用凭证由读写 MCP 客户端自动保存到外部密码库;唯一匹配条目直接更新,避免重复创建。
- 文件扫描默认 15 分钟;文件版本仅为元数据。
- MCP 完整管理文件,但上传只生成 HTTP PUT 地址。
- 密码库离线时允许使用最后同步缓存。
- 完整备份由手动短暂停机脚本触发。
- Windows 通过 Docker Desktop Linux 容器部署;Linux 通过原生 Docker/Compose 部署。
- 正式构建和测试 `linux/amd64`、`linux/arm64` 镜像,不针对 ARMv7 等缺少上游依赖的架构开发替代实现。