Skip to content

重构 MA 上下文为线性追加,并适配 ZimoOS 实时虚拟界面 #26

Description

@zhuqingyv

Problem

MA 的 ZimoOS 上下文适配方向需要修正。当前实现已经有 zimoos.currentFrame live slot、OSFrame 降噪、工具名编码和真实 ZimoOS e2e 基础,但实时界面状态的注入位置仍然不对:它通过 dynamic suffix 进入请求尾部的 system message。这样虽然没有污染稳定的 system[0],但仍会让 provider 前缀缓存命中变差,也不符合目标上下文模型。

本 issue 关闭时必须真正完成完整功能,不能只交一个 live slot slice,也不能把核心验收拆到后续 issue。允许按执行顺序分步骤实现,但关闭 #26 必须满足本文全部 Acceptance Criteria。

目标模型:

稳定 system[0]
+ append-only 历史 transcript(只保留用户意图、assistant 推理/回答、工具调用协议、ZimoOS Action + 摘要)
+ request-only 最新消息 ZimoOS 状态块(只存在于本轮请求,不持久化)

核心原则:

  • MA 内部持有唯一实时 zimoos.currentFrame
  • 每次 provider request 只在最新消息上临时附加当前 ZimoOS 状态,例如 <zimoos>...</zimoos>
  • 历史消息中不保存任何 ZimoOS 当前界面状态块,也不保存旧 OSFrame 快照。
  • 历史 ZimoOS 操作必须保留,但只保留 Action + 这次操作后的摘要,不保留完整 UI 状态。
  • system prompt、历史 transcript、历史 tool-call 结构尽量保持稳定,服务 provider prefix cache。

Evidence

当前实现和目标思路的差异

维度 当前实现 目标架构 差异/风险
当前 ZimoOS UI 状态源 RuntimeContextSlotStore 内部保存 zimoos.currentFrame 相同 这部分方向正确,应复用。
UI 状态注入位置 agent.tsbuildRequestSuffix()runtimeSlots.render(),再传给 request builder 只注入最新 request message,不能成为 system/suffix 当前会生成动态 system message,不利于前缀缓存。
请求构造 RequestContextBuilder.build(..., { suffix }) 把 suffix 转成尾部 system message request builder 应支持 request-only latest-message attachment 需要把 ZimoOS 状态从 suffix 管道移到 latest-message request view。
历史 UI 快照 已经避免原始 OSFrame JSON 进入 history/request,改为 audit-only 历史不得有 <zimoos>[ZimoOS Current Frame] 当前状态块 raw OSFrame 降噪正确,但当前测试仍要求 system message 里出现 frame block。
历史操作记录 tool result 中是预生成 audit:status、visible count、shortcut count 历史应记录 Action + LLM 产出的本次摘要 当前摘要不是 LLM 推理后的操作摘要,缺少“这一步做了什么/结果是什么”的稳定历史。
cache 边界 system[0] 稳定,但尾部 dynamic system 每轮变化 system 和历史大段都稳定,只变最新 request-only 消息 当前做法比把状态塞 system[0] 好,但仍不是最佳缓存形态。
完成定义 issue 当前写了 Parent Scope partial,可能被 live slot slice 误关 #26 close 必须完整完成 需要把验收映射写死,禁止以局部 slice 关闭。

代码证据

  • src/agent.ts 当前 buildRequestSuffix()runtimeSlots.render() 放入 suffix:
    • runtimeSlotText = runtimeSlots.render()
    • suffix 由 runtimeSlotText / stack state / loop warning 拼接。
  • src/agent/request-context-builder.ts 当前 buildSuffixGroup() 把 suffix 包成 { role: "system" },并追加到 request messages 尾部。
  • src/agent/runtime-context-slots.ts 当前 renderZimoosFrameSlot() 输出 [ZimoOS Current Frame] 文本块。
  • src/agent/runtime-context-slots.ts 当前 createZimoosToolAuditText() 是工具返回时立即生成的 audit-only 文本,不是 LLM 后续推理返回的操作摘要。
  • src/agent.ts 工具执行后立即 store.appendToolResult(tc.id, result),此时还没有下一次 LLM 推理摘要。
  • test/messages-integrity.test.ts 当前测试会从 request 中寻找 role=system[ZimoOS Current Frame] 动态块,这个测试口径需要改。
  • test/e2e/zimoos.test.ts 当前只断言 debug log 出现 [ZimoOS Current Frame],没有断言它只存在于最新 user/request message,也没有断言历史无状态块。
  • test/provider-request-redline.test.ts 已经有“provider request 不走 ContextManager active context”的红线,应继续保留并扩展。

已有可复用基础

  • src/agent/runtime-context-slots.ts
    • 已有 OSFrame parser、slot store、bounded renderer、audit text。
  • src/agent/tool-executor.ts
    • 已经能在工具统一出口识别 OSFrame 并返回 runtimeSlotUpdate
  • src/agent/tool-router.ts
    • 已经能把 zimoos.current 编码成 OpenAI-compatible function name,再路由回原始 MCP tool name。
  • src/agent/request-context-builder.ts
    • 已有 append-only transcript grouping、tool-call/tool-result 配对保护、windowing 基础。
  • src/agent/message-store.ts
    • 已经是 append-only transcript 的集中事实源。
  • test/e2e/zimoos.test.ts
    • 已有真实 mteam backend 可用时的 ZimoOS MCP e2e 入口。

Architecture Direction

Source of Truth

MA 应有两个互相独立的事实源:

  1. MessageStore

    • 只保存对话历史、assistant 内容、tool call 协议、ZimoOS action 记录和操作摘要。
    • 不保存当前 ZimoOS UI 状态块。
    • 不保存完整 OSFrame JSON。
  2. RuntimeContextSlotStore

    • 只保存当前运行态 UI 状态,例如 zimoos.currentFrame
    • 这是可替换状态,不是 transcript。
    • reset/session 切换时按现有 agent 生命周期清空或从明确来源恢复,不能从历史 <zimoos> 回放。

Request View

Provider request 必须从事实源生成一个临时 view:

request messages =
  stable system[0]
  + selected append-only transcript history
  + latest request-only user message carrying current zimoos state
  + non-zimoos dynamic tail only when necessary

ZimoOS 状态不能再走 suffix -> system message。它应成为 request-only latest-message attachment:

<zimoos source="zimoos.currentFrame" request_only="true">
title: ...
frameCursor: ...
visibleContent:
- ...
actions:
- ...
handles:
- ...
</zimoos>

实现细节必须兼顾 provider 协议和缓存:

  • 如果 request 中最后一条消息是当前 root user message,可把 <zimoos> 附到该 user content 后面,但不能写回 MessageStore
  • 如果最后一条消息不是 user,例如已经有 assistant tool_calls + tool results,则追加一条 request-only user carrier message,只包含当前 <zimoos> 状态和极短说明。
  • 这条 carrier message 不能持久化到 session JSONL,不能进入 MessageStore.getPendingForPersist()
  • 历史 message 中如果出现旧 <zimoos>[ZimoOS Current Frame]、raw protocol:"zimoos/os-frame",应视为 bug。
  • system[0] 不变;历史 selected transcript 不因当前 frame 变化而改写;只有尾部 latest request-only message 随 frame 变化。

ZimoOS Operation History

历史要保留 Agent 做过什么,但不能保留 UI 快照。ZimoOS tool call 的历史记录应成为:

Action: zimoos.act { frameCursor, cmd }
Summary: LLM 对这次操作结果的简明总结
Frame audit: frame updated, frameCursor/title/status/visible count/action count

必须修正当前“工具返回时立即生成 audit 就算完”的模型:

  1. zimoos toolcall 执行。
  2. tool 返回 OSFrame 或结构化结果。
  3. MA 更新内部 zimoos.currentFrame
  4. request view 把最新 frame 只挂到最新消息。
  5. LLM 基于最新 frame 继续推理,并产出本次操作摘要。
  6. MA 将该摘要回写/压缩到对应 ZimoOS tool result 历史,形成 Action + Summary 的完整操作记录。
  7. 下一轮请求历史只看到 Action + Summary,不看到旧 frame 状态;当前 frame 仍从 runtime slot 临时挂载。

如果模型在调用 ZimoOS tool 后没有给出摘要而继续调用下一个工具,MA 必须有确定性策略:

  • 要么要求 assistant tool-call content 携带操作摘要;
  • 要么在下一次 assistant 可见内容出现后,把相关 pending ZimoOS operations 合并成摘要;
  • 要么插入内部 summary correction 步骤。

不能接受“没有摘要就只保留 audit count”作为完成状态。

Cache Boundary

修正后的缓存边界:

  • 稳定:system[0]、历史 transcript、历史 Action + Summary。
  • 可变:最新 request-only <zimoos> carrier。
  • 不稳定但低频:task stack / loop warning 等非 ZimoOS tail 状态。

验收必须能证明 frame 从 A 变成 B 时:

  • system[0] hash 不变。
  • 历史消息 JSON 不变。
  • 只有最新 request-only ZimoOS carrier 内容变化。
  • request 中不存在 role=system 的 ZimoOS 当前状态块。

Reuse / Mature Solution Plan

优先复用现有结构,不新造上下文系统:

  • 复用 RuntimeContextSlotStore 作为当前 UI 状态内存事实源。
  • 复用 renderZimoosFrameSlot() 的内容选择逻辑,但输出 wrapper 改成 request-only <zimoos>,并去掉 system-block 语义。
  • 复用 RequestContextBuilder 的 transcript grouping/windowing,新增 latestMessageAttachmentsrequestOnlyContext 参数,而不是在 agent.ts 手工拼 messages。
  • 复用 MessageStore 的集中 mutation,把“ZimoOS operation summary correction”做成明确方法,避免散落 splice。
  • 复用 ToolExecutor 的 OSFrame 识别入口,但把“历史摘要最终形态”放到 LLM 推理后修正,而不是工具返回时一次性定死。
  • 复用 tool-router 的 function name 编码,不改 mteam 公开工具名。
  • 复用 test/e2e/zimoos.test.ts 作为真实 ZimoOS e2e 入口,补强断言而不是另起 mock-only 证明。

Implementation Checklist

  • 改 request 架构

    • buildRequestSuffix() 不再包含 runtimeSlots.render()
    • RequestContextBuilder 新增 request-only latest-message attachment 能力。
    • ZimoOS 状态渲染只通过该 attachment 进入 request。
    • attachment 不写入 MessageStore、不进入 session JSONL、不进入历史 selected groups。
    • 如果 request 最后一条是 user,则 clone 并附加 <zimoos>;如果不是 user,则追加 request-only user carrier。
  • 改 ZimoOS renderer 语义

    • [ZimoOS Current Frame] 改为 <zimoos>...</zimoos> 或等价明确 request-only wrapper。
    • wrapper 中保留 frameCursor、title、summary、visibleContent、shortcuts/actions、handles、notifications、updatedAt。
    • wrapper 不包含 raw OSFrame JSON。
    • renderer 继续有 token 上限,不能把截图、大 DOM、大 JSON 塞入文本。
  • 改历史操作记录

    • 对每个 ZimoOS tool call 建立 pending operation 记录:tool name、args、tool_call_id、frame audit metadata。
    • 工具返回后立即更新 runtime slot,但历史 tool result 只放最小 pending/audit,不放当前 UI 状态。
    • 下一次 LLM 推理返回摘要后,将 pending operation 修正成 Action + Summary。
    • 如果连续多个 ZimoOS tool call 没有摘要,必须有 deterministic summary correction,不能让 pending 状态永久留在历史。
    • 修正后的历史仍保持 provider tool_call/tool_result 协议合法,无 orphan tool。
  • 改测试口径

    • 删除/改写“在 system message 中寻找 [ZimoOS Current Frame]”的测试。
    • 新增 redline:request 中任何 role=system message 都不得包含 <zimoos>[ZimoOS Current Frame]
    • 新增 redline:MessageStore.snapshot() 和 persisted session JSONL 不包含 <zimoos>[ZimoOS Current Frame]、raw OSFrame JSON。
    • 新增 redline:只有最新 request message 包含 <zimoos>,历史 user/assistant/tool message 都不包含。
    • 新增 cache redline:frame 变化时,除最新 request-only message 外,前缀 message 内容和顺序保持一致。
    • 新增 Action + Summary 测试:ZimoOS tool result 历史最终包含 tool action 和 LLM 产出的摘要,不包含完整 frame。
  • 补真实回归

    • 真实 npm run e2e:zimoos 在 mteam backend 可用时断言:调用 zimoos.current、更新 runtime slot、最终回答包含真实 title/frameCursor/visible count。
    • e2e debug/request log 断言:<zimoos> 只在最新 request message,绝不在 system message 和历史 message。
    • e2e debug/request log 断言:历史里只有 Action + Summary / audit,不出现 raw OSFrame。
    • 如果 mteam backend 不可用,必须明确 skip,不能用 mock OSFrame 替代真实结论。
  • 保持 重构 MA 上下文为线性追加,并适配 ZimoOS 实时虚拟界面 #26 父目标完整

    • Provider request 主路径继续保持 append-only transcript view,不回退到 ContextManager.buildLlmContext()
    • ma ctx / ContextManager 仍只能作为 debug/compat,不影响 provider request。
    • tool_call/tool_result windowing 继续合法,不因 latest-message attachment 破坏协议。

Validation

必须跑并记录结果:

npm run build
npm test
npx tsx test/benchmark/runner/index.ts --dry-run
npx tsx --test test/benchmark/runner/__tests__/*.test.ts

必须新增或更新并通过的 focused tests:

npx tsx --test test/runtime-context-slots.test.ts
npx tsx --test test/messages-integrity.test.ts
npx tsx --test test/provider-request-redline.test.ts
npx tsx --test test/e2e/zimoos.test.ts

真实 runtime 验证:

npm run e2e:zimoos

要求:

  • mteam backend 可用时必须跑真实 ZimoOS MCP e2e。
  • mteam backend 不可用时只能报告 skipped: requires mteam backend,不能用 mock 代替。
  • 不能用 unit/mock/dry-run 声称真实 ZimoOS 体验完成。

Acceptance Criteria

  • system[0] 稳定,不包含任何 ZimoOS 当前界面状态。
  • 请求中不存在 role=system 的 ZimoOS 当前状态块。
  • 当前 ZimoOS UI 状态只存在于最新 request message 的 <zimoos> 或等价 wrapper 中。
  • <zimoos> wrapper 是 request-only:不进入 MessageStore,不进入 session JSONL,不进入历史 transcript。
  • 历史消息不包含旧 ZimoOS frame 快照、[ZimoOS Current Frame]<zimoos> 或 raw OSFrame JSON。
  • 历史 ZimoOS 操作记录保留 Action + LLM 产出的摘要。
  • 连续 zimoos.current -> zimoos.act -> zimoos.search 后,请求中只有最新 frame,历史中有每步 Action + Summary。
  • frame A 更新到 frame B 时,除最新 request-only message 外,请求前缀内容不变,能服务缓存命中。
  • provider request 主路径不依赖 ContextManager.buildLlmContext()
  • tool_call/tool_result 协议始终合法,无 orphan tool、无半截 tool group。
  • OpenAI-compatible provider 工具名仍合法,mteam 公开工具面仍是 zimoos.current / zimoos.act / zimoos.search
  • 真实 ZimoOS e2e 在 mteam backend 可用时通过,并证明最新 frame 可见、历史无 frame 噪音、system 无动态 ZimoOS 状态。

Acceptance Mapping

Acceptance criterion Code or system path Validation/proof Old path status Notes
system[0] 稳定,不包含 ZimoOS 当前界面状态 src/agent.ts, src/agent/request-context-builder.ts, src/agent/message-store.ts Unit test hashes/compares messages[0] across frame changes; debug request log confirms no ZimoOS block in system[0] unchanged by design Stable system prompt is cache anchor.
请求中不存在 role=system 的 ZimoOS 当前状态块 RequestContextBuilder suffix handling; ZimoOS attachment path Redline test scans every role=system request message for <zimoos> and [ZimoOS Current Frame] removed Current suffix-system injection must be removed.
当前 UI 状态只存在于最新 request message New request-only attachment builder Test with multiple messages asserts only last request message contains <zimoos> bypassed Latest carrier may be cloned user or transient user message.
<zimoos> 不进入持久历史 MessageStore, SessionStore, request builder cloning Test inspects MessageStore.snapshot() and persisted JSONL after request removed No hidden persistence through pending messages.
历史不含旧 frame/raw OSFrame RequestContextBuilder.sanitizeToolMessage, RuntimeContextSlotStore, debug log Multi-frame unit + e2e assert old title/frameCursor/raw protocol absent from historical request text removed Existing raw JSON redline must be strengthened to wrapper absence.
历史 ZimoOS 操作记录保留 Action + LLM 摘要 ToolExecutor, MessageStore, new operation-summary correction path Test proves final tool result/history includes tool name/args and assistant-produced summary bypassed Current count-only audit is not enough.
连续 current/act/search 后只有最新 frame + 每步 Action/Summary RuntimeContextSlotStore, request builder, operation journal Unit test with 3 fake frames; e2e if backend available bypassed Must cover multi-step workflow, not one current call.
frame 变化只改变最新 request-only message request builder output comparison Test builds request for frame A and B and diffs message array; only final message differs removed Direct cache-boundary proof.
Provider request 不依赖 ContextManager.buildLlmContext() src/agent.ts, test/provider-request-redline.test.ts Existing redline plus focused test remains green bypassed ContextManager may remain debug/compat only.
tool protocol 合法 RequestContextBuilder group/windowing, MessageStore mutation Existing Qwen/OpenAI protocol tests plus new latest attachment tests unchanged by design Latest carrier cannot split assistant/tool group.
mteam tool surface 不变 src/agent/tool-router.ts, mteam MCP config Unit test for zimoos.current -> zimoos_x2e_current -> zimoos.current; real e2e tool call visible unchanged by design Do not rename mteam tools.
Real ZimoOS e2e proves runtime behavior test/e2e/zimoos.test.ts, local mteam backend npm run e2e:zimoos passes or explicitly skips due missing backend unchanged by design Mock cannot close this criterion.

Regression Boundaries

必须防止以下回归:

  • 把 ZimoOS 当前状态放回 system[0]
  • 把 ZimoOS 当前状态作为任意 role=system dynamic suffix。
  • <zimoos> 写入 MessageStore 或 session JSONL。
  • 把旧 frame 快照或 raw OSFrame JSON 留在历史请求里。
  • 只保留工具返回时的 count audit,没有 LLM 操作摘要。
  • 用 mock OSFrame 证明真实 ZimoOS e2e。
  • 为了 MA 改 mteam 公开工具名。
  • latest-message attachment 插入位置破坏 tool_call/tool_result 配对。
  • 关闭 issue 时只完成 live slot、未完成 latest-message request-only 注入和 Action + Summary 历史。

Non-goals

  • 不接 Mnemo 或跨 session 长期记忆。
  • 不把 renderer DOM、人类 TeamCanvas omniscient state、截图原文塞进 MA。
  • 不在 MA 内重造 TeamCanvas/MApp/MIT 状态机。
  • 不新增 MA-only mteam 业务工具。
  • 不改变 mteam 对外工具名 zimoos.current / zimoos.act / zimoos.search
  • 不以“先做一个 slice”关闭本 issue;本 issue 关闭必须代表本文完整功能完成。

Parent Scope Status

Status: partial until all Acceptance Criteria above are complete.

已完成基础:

  • OSFrame 解析。
  • zimoos.currentFrame runtime slot。
  • raw OSFrame 降噪为 audit-only。
  • OpenAI-compatible tool name encoding。
  • 真实 ZimoOS e2e 基础链路。

仍未完成且不能延期:

  • ZimoOS 状态从 dynamic system/suffix 移到 latest request message。
  • <zimoos> request-only,不入历史。
  • Action + LLM 摘要成为历史操作记录。
  • cache-boundary redline。
  • 强化真实 ZimoOS e2e 证明最终行为。

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