# CALL-MEMORY-1.1 实施记录 日期:2026-09-12。依据:`AI电话_完整通话与记忆管理_完整流程与详细设计(2).docx`,v3.1,CALL-MEMORY-1.1。原文件 SHA-256:`72cd61b7f8ee0a65ffe7a932d6856a56726d906ad469ad482338aedc153fe9f7`。代码起点:`98fb2965d0898cbe08bda36df3bb99e00ed32626`。 **本次实现了服务端通话控制、记忆变更与管理页面,并修复现有固件的本地音频和快速摘挂机问题。完整的新 RTC 固件客户端尚未接入,不能将本次改动称为文档全部功能已端到端交付。** 当前改动在本地工作区,未部署生产、未刷机。 ## 已落地的功能 | 文档要求 | 当前实现及入口 | 验证边界 | |---|---|---| | 七个设备通话接口 | `internal/callmemory/{service,lifecycle,events}.go`;warmup、prepare、events、heartbeat、end、status、command-acks | 已运行数据库集成测试;固件目前尚未调用这些新接口 | | ONBOARDING 签名复用 | `internal/onboarding/call_auth.go`;复用 DEVREQ1 原始正文签名、当前绑定代数、nonce 与 HTTPS 校验 | 不另造用户身份;新接口要求 physical_confirm 设备身份 | | 预热和签发 | 已发布 SDK/音频 profile 匹配;返回服务端配置版本;绑定、配置 ACK、SDK 注册和 engine_ready 校验;FIRST_TEST 绑定现有授权尝试 | 不凭客户端 known_config_version 提升版本;真实服务商 profile 必须单独核验 | | 清单与启动 | CALLCFG1 HMAC、原始 base64url、30 秒启动期限、45 秒绝对租约、首次 heartbeat 后才能 START_INTENT | 重复 prepare 不重复分配;提前取消不会复活;status/events 不续租 | | 通话撤销 | 隐私版本变化撤销旧清单、停止命令、阻断旧配置缓存 | 本地静音、SDK 停止、供应商停止为独立事实;远端 UNKNOWN 不完成清理 | | 控制面限额 | 与旧通话共用租户并发锁和额度检查,新会话冻结预算快照、按较短上限限制通话 | 新通话的供应商费用回执尚未接入旧 conversation_usage_event 报表 | | 最终文字 | 分片最多 4096 UTF-8 字节、16 片、整段摘要校验;每批最多 16 个事件且设备正文上限 8 KiB;持久化 ACK、事件序号/ID 去重、修订只向前 | 接收端可靠;设备 64 KiB/15 分钟补传队列仍待移植 | | 收尾与抽取 | DRAINING 安静 15 秒或最长 60 秒;COMPLETE/PARTIAL/EMPTY;迟到修订重新处理;只从可靠 USER final 抽取,来源偏移与原话核对 | 配置真实结构化内容模型后执行;本地测试没有调用模型生产账号 | | 七类记忆 | RELATIONSHIP、PROFILE、EVENT、PREFERENCE、OPEN_ITEM、STORY、INTERACTION | 页面可维护;旧记录迁移为 STORY,不重新解释历史原话 | | 使用与敏感策略 | ALLOWED/RESPOND_ONLY/NEVER 与敏感级别分离;普通主动可用条目才进入热上下文/Viking 投影 | RESPOND_ONLY 已阻止主动使用,但新通话绑定可靠用户提问的按需检索入口仍待接入 | | 事项状态 | 稳定 entity_key、OPEN/COMPLETED/CANCELLED/UNKNOWN、计划时间、完成时间及明确依据;不会因日期到达自动完成 | 关闭事项不进入主动开场;重开会清除旧完成依据;切换非事项类型清除事项字段 | | 热上下文 | 最新事实优先、同实体去重、只保留完整条目,保留否定与不确定性,最多约 1000 字 | 已有完整事实/关闭事项测试 | | 四类记忆变更 | ADD/CORRECT/SET_USAGE/DELETE;稳定 mutation_id、目标 record_version;语音来源按会话/话轮修订/动作序号去重 | 只有高置信度普通 ADD 可自动进入主库,其他语音方案在页面确认 | | 页面确认 | 待确认方案、具体目标和版本、10 分钟单次 token、proposal_digest;提交后取消重放不能回滚已提交变更 | 前端保留编辑时核对的版本;后台轮询不会悄悄更换提交版本 | | 六阶段任务 | main_store、serving_projection、derived_context、active_context、source_cleanup、backup_cleanup;不涉及阶段为 NOT_REQUIRED | 必要阶段全部 DONE 才 COMPLETED;备份和供应商停止不会只按时间推定完成 | | 独立记忆权限 | 家庭所有者管理授权;普通成员独立获得查看、修改、敏感记忆权限;旧记忆接口也检查授权 | 已验证设备管理权限不能绕过记忆授权;撤权后旧确认 token 失效 | | 删除与防恢复 | 隐私版本、来源抑制、删除台账、历史正文/变更内容/事项备注清理;按范围清理原始话轮和故事来源;旧摘要和 manifest 缓存失效 | 来源只保留 ID、修订和偏移;恢复数据库前必须重放删除台账 | | Viking 主从关系 | `internal/vikingmemory/projection.go` 只投影已审定条目;新链路不走 AddSession;按用户串行对账 | 没有真实 H08/schema 证据时不发布条目 | | Viking 不确定写入 | 先持久化 WRITING;写入回包丢失只按 operation key 对账;不会盲目重复新增;ACK 与可查询可见分离 | 已测试未知新增后空查询不能直接证明删除完成,水位不能越过未完成版本 | | 现有固件安全修复 | `volc_conv.c`、`volc_conv_service.c`、`volc_hal_player.c`、`platform_client.c`;本地音频授权检查、有限等待、旧任务清理前禁止新启动、SDK 参数保持到 stop 返回 | ESP-IDF 构建通过;这些改动不等于已移植 CALL-MEMORY RTC 客户端 | | SDK 日志隐私 | 清除注册/GetRTCConfig 正文、HTTP/WS 原始消息、RTC Token 和供应商错误正文日志;增加源码回归检查 | 源码检查通过;运行时日志抓取仍需真实设备 | | API 契约 | `openapi/call-memory.yaml`、主 OpenAPI 0.79.0、生成的 TypeScript 类型 | 生成器覆盖 7 个通话接口、6 个记忆接口及额外的 2 个授权接口 | ## 管理页面 入口为当前长者的故事/记忆区域中的“通话记忆管理”。支持新增、修正、使用范围、事项状态、删除范围、语音候选确认、六阶段进度以及记忆访问授权。旧的空记忆列表不再重复显示。 “已保存”只表示主库提交。“正在生效”“等待备份核验”“同步需处理”会继续显示,避免把等待外部处理伪装成全部完成。采用文档允许的 PAGE_ONLY:确认及结果在页面完成,本次没有宣称已实现设备本地语音提示。 ## 尚未完成的文档要求 1. **完整设备协议切换**:当前 ECHOEAR 固件仍使用旧 `/device/v3` 身份/会话接口和 `VOLC_MODE_WS`。需要完成 ONBOARDING 原始 32 字节密钥接入、新 7 接口调用、CALLCFG1 验签、可信时钟误差上界、原始 `vendor_params_json` 的 RTC 透传和 FIRST_TEST 实机闭环。 2. **设备可靠运行时**:仍需完成每次 media_attempt 的回调隔离、持久化终稿 64 KiB/15 分钟队列、7 天结束记录、启动 10 秒/首音频 8 秒超时及 LISTENING 120+60 秒空闲处理。当前修复了快速重拨竞态和本地音频关断,未把这些项目标成完成。 3. **真实服务商核验**:共享 S2S Bot、RTC 格式、OFF 真正不查旧记忆、Viking 条目 schema、关闭自动抽取、停止/清上下文、字段漂移及 H01–H12 实测证据。示例/单元测试中的 synthetic 标识绝不能作为发布证据。 4. **新通话按需检索**:RESPOND_ONLY 现被排除出主动上下文和旧模型工具;仍需把可靠当前 USER 提问绑定到新通话检索入口,才能在“被问及”时使用。 5. **供应商停止自动对账**:现有服务没有可验证的目标供应商查询回调。保留 UNKNOWN,并提供带证据的运维登记命令;不会用 SDK_STOPPED 自动冒充远端停止。 6. **既有报表与新通话桥接**:新 `call_session` 的全文/历史展示、供应商使用量和既有费用/通话报表尚未整合。预算准入和时长限制已经接入,但费用闭环不能据此宣称完成。 7. **全部 T01–T48 的故障注入验收**:本次执行的本地检查见下表;真实联网、断电、回调乱序、回声和隐私日志抓取仍须在目标设备上完成。 兼容影响:发生关键记忆变更、授权撤回等隐私版本变化后,旧 v3 客户端的新建会话会返回 `426 CALL_MEMORY_PROTOCOL_REQUIRED`。新 prepare 也会等待旧 SDK/远端清理证据,不能通过换会话 ID 绕过。**因此这批改动应先进入联调环境;在新固件接入前,不能直接当作老设备无感升级的生产版本发布。** ## 数据迁移与操作 迁移:`migrations/000059_call_memory_contract.up.sql`。新增表与触发器会把历史主体设为 `legacy_projection_pending=true`,并创建现有记忆的投影任务;不会把历史通话原文交给另一套抽取器。没有经过核验的已发布 profile 时,新 warmup/prepare 会拒绝启动。 迁移需要配套运行本版本 API、worker 和 Web。`down.sql` 故意拒绝自动删除隐私台账;如果需要恢复备份,应保持服务关闭、先恢复数据库,再重放删除台账与来源抑制并完成外部清理核验,最后决定是否恢复服务。不可只回退数据库而继续运行旧固件访问已撤回的记忆。 运维命令使用已有 `DATABASE_URL` 环境变量,不把密钥写进命令或文档: ```powershell # 导入未发布的草稿;真实字段和证据由经过核对的 profile JSON 提供。 go run ./cmd/call-memory-admin -operation import-profile -file ./verified-profile.json # 完成真实核验后,使用新的不可变 profile ID 发布。 go run ./cmd/call-memory-admin -operation import-profile -file ./verified-profile-v2.json -publish # 服务商停止证据登记;设备必须已提供本地音频关闭和 SDK 停止证据。 go run ./cmd/call-memory-admin -operation attest-call-stopped -session-id -evidence # 已完成旧命名空间和旧运行时清理后登记。 go run ./cmd/call-memory-admin -operation attest-legacy-cleanup -subject-id -evidence # 完成真实备份清理核验后登记。 go run ./cmd/call-memory-admin -operation attest-backup-cleanup -subject-id -evidence # 修复配置后恢复对账;不会直接再次新增结果未知的条目。 go run ./cmd/call-memory-admin -operation retry-projection -subject-id -evidence # 外部备份恢复前后使用删除台账;导出不包含记忆正文。 go run ./cmd/call-memory-admin -operation export-deletion-ledger > deletion-ledger.json go run ./cmd/call-memory-admin -operation replay-deletion-ledger -file ./deletion-ledger.json ``` 证据登记只是一条受控运维入口,不会自行执行备份擦除或凭空验证云端停止。禁止填写虚构证据以消除页面上的等待状态。 ## 本地验证与复现 | 检查 | 本次结果 | |---|---| | `go test ./...`、`go vet ./...` | 通过;未设置测试数据库的单独运行会跳过数据库测试,以下隔离数据库命令另外执行 | | `scripts/test-onboarding-integration.ps1 -Packages billing,callmemory,onboarding,saas,extraction,retrieval,memorytool,privacy,orchestration,vikingmemory` | 10 个包通过;脚本创建和删除独立测试数据库,没有迁移生产库 | | 新通话/记忆数据库用例 | 幂等和提前取消、首次心跳、租约不可复活、文字修订/收尾、确认重放、敏感权限、投影 ACK/可见水位、写入途中撤权、全量删除覆盖新通话、迟到文字修订不能恢复已删来源 | | Viking HTTP + 数据库用例 | 结果未知不重复新增,空查询不伪造删除完成,后续可见对账保持身份范围 | | `npm run generate:api`、`npm run build` | 通过;仍有既有大型前端 chunk 的体积提示 | | `test/e2e/memory-workspace.mjs` | 真实 React 组件 + 合成 API;编辑期间轮询保留核对版本、删除范围确认、不可修改所有者授权、375px 无页面横向溢出、撤权清除旧正文;无 pageerror | | 固件 `idf.py build` | 通过;`VolcRTCDemo.bin` 大小 `0x2ce070`,应用分区剩余 44%;保持原锁文件依赖版本,未刷机 | | 固件 Node 检查 `setup-portal.test.cjs`、`private-sdk-logs.test.cjs` | 6 项配网检查 + 1 项 SDK 日志隐私检查通过 | 浏览器脚本需要本机 Playwright 与 Chromium;可使用 `PLAYWRIGHT_REQUIRE_FROM` 指定现有 Playwright 包路径、`CHROME_PATH` 指定浏览器。脚本从仓库根目录运行,自行启动并关闭本地 Vite,只拦截合成 API。结果和截图位于 `.design-evidence/call-memory/`(已忽略,不入库)。这些证据不替代完整登录部署或真实话机测试。