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.ts 的 buildRequestSuffix() 调 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 应有两个互相独立的事实源:
-
MessageStore
- 只保存对话历史、assistant 内容、tool call 协议、ZimoOS action 记录和操作摘要。
- 不保存当前 ZimoOS UI 状态块。
- 不保存完整 OSFrame JSON。
-
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 就算完”的模型:
- zimoos toolcall 执行。
- tool 返回 OSFrame 或结构化结果。
- MA 更新内部
zimoos.currentFrame。
- request view 把最新 frame 只挂到最新消息。
- LLM 基于最新 frame 继续推理,并产出本次操作摘要。
- MA 将该摘要回写/压缩到对应 ZimoOS tool result 历史,形成 Action + Summary 的完整操作记录。
- 下一轮请求历史只看到 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,新增 latestMessageAttachments 或 requestOnlyContext 参数,而不是在 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
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 验证:
要求:
- mteam backend 可用时必须跑真实 ZimoOS MCP e2e。
- mteam backend 不可用时只能报告 skipped: requires mteam backend,不能用 mock 代替。
- 不能用 unit/mock/dry-run 声称真实 ZimoOS 体验完成。
Acceptance Criteria
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 证明最终行为。
Problem
MA 的 ZimoOS 上下文适配方向需要修正。当前实现已经有
zimoos.currentFramelive slot、OSFrame 降噪、工具名编码和真实 ZimoOS e2e 基础,但实时界面状态的注入位置仍然不对:它通过 dynamic suffix 进入请求尾部的systemmessage。这样虽然没有污染稳定的system[0],但仍会让 provider 前缀缓存命中变差,也不符合目标上下文模型。本 issue 关闭时必须真正完成完整功能,不能只交一个 live slot slice,也不能把核心验收拆到后续 issue。允许按执行顺序分步骤实现,但关闭 #26 必须满足本文全部 Acceptance Criteria。
目标模型:
核心原则:
zimoos.currentFrame。<zimoos>...</zimoos>。Evidence
当前实现和目标思路的差异
RuntimeContextSlotStore内部保存zimoos.currentFrameagent.ts的buildRequestSuffix()调runtimeSlots.render(),再传给 request buildersystemmessage,不利于前缀缓存。RequestContextBuilder.build(..., { suffix })把 suffix 转成尾部 system message<zimoos>或[ZimoOS Current Frame]当前状态块system[0]稳定,但尾部 dynamic system 每轮变化代码证据
src/agent.ts当前buildRequestSuffix()把runtimeSlots.render()放入 suffix:runtimeSlotText = runtimeSlots.render()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.tssrc/agent/tool-executor.tsruntimeSlotUpdate。src/agent/tool-router.tszimoos.current编码成 OpenAI-compatible function name,再路由回原始 MCP tool name。src/agent/request-context-builder.tssrc/agent/message-store.tstest/e2e/zimoos.test.tsArchitecture Direction
Source of Truth
MA 应有两个互相独立的事实源:
MessageStoreRuntimeContextSlotStorezimoos.currentFrame。<zimoos>回放。Request View
Provider request 必须从事实源生成一个临时 view:
ZimoOS 状态不能再走
suffix -> system message。它应成为 request-only latest-message attachment:实现细节必须兼顾 provider 协议和缓存:
<zimoos>附到该 user content 后面,但不能写回MessageStore。<zimoos>状态和极短说明。MessageStore.getPendingForPersist()。<zimoos>、[ZimoOS Current Frame]、rawprotocol:"zimoos/os-frame",应视为 bug。system[0]不变;历史 selected transcript 不因当前 frame 变化而改写;只有尾部 latest request-only message 随 frame 变化。ZimoOS Operation History
历史要保留 Agent 做过什么,但不能保留 UI 快照。ZimoOS tool call 的历史记录应成为:
必须修正当前“工具返回时立即生成 audit 就算完”的模型:
zimoos.currentFrame。如果模型在调用 ZimoOS tool 后没有给出摘要而继续调用下一个工具,MA 必须有确定性策略:
不能接受“没有摘要就只保留 audit count”作为完成状态。
Cache Boundary
修正后的缓存边界:
system[0]、历史 transcript、历史 Action + Summary。<zimoos>carrier。验收必须能证明 frame 从 A 变成 B 时:
system[0]hash 不变。system的 ZimoOS 当前状态块。Reuse / Mature Solution Plan
优先复用现有结构,不新造上下文系统:
RuntimeContextSlotStore作为当前 UI 状态内存事实源。renderZimoosFrameSlot()的内容选择逻辑,但输出 wrapper 改成 request-only<zimoos>,并去掉 system-block 语义。RequestContextBuilder的 transcript grouping/windowing,新增latestMessageAttachments或requestOnlyContext参数,而不是在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 能力。MessageStore、不进入 session JSONL、不进入历史 selected groups。<zimoos>;如果不是 user,则追加 request-only user carrier。改 ZimoOS renderer 语义
[ZimoOS Current Frame]改为<zimoos>...</zimoos>或等价明确 request-only wrapper。改历史操作记录
改测试口径
[ZimoOS Current Frame]”的测试。systemmessage 都不得包含<zimoos>或[ZimoOS Current Frame]。MessageStore.snapshot()和 persisted session JSONL 不包含<zimoos>、[ZimoOS Current Frame]、raw OSFrame JSON。<zimoos>,历史 user/assistant/tool message 都不包含。补真实回归
npm run e2e:zimoos在 mteam backend 可用时断言:调用zimoos.current、更新 runtime slot、最终回答包含真实 title/frameCursor/visible count。<zimoos>只在最新 request message,绝不在 system message 和历史 message。保持 重构 MA 上下文为线性追加,并适配 ZimoOS 实时虚拟界面 #26 父目标完整
ContextManager.buildLlmContext()。ma ctx/ ContextManager 仍只能作为 debug/compat,不影响 provider request。Validation
必须跑并记录结果:
必须新增或更新并通过的 focused tests:
真实 runtime 验证:
要求:
Acceptance Criteria
system[0]稳定,不包含任何 ZimoOS 当前界面状态。system的 ZimoOS 当前状态块。<zimoos>或等价 wrapper 中。<zimoos>wrapper 是 request-only:不进入MessageStore,不进入 session JSONL,不进入历史 transcript。[ZimoOS Current Frame]、<zimoos>或 raw OSFrame JSON。zimoos.current -> zimoos.act -> zimoos.search后,请求中只有最新 frame,历史中有每步 Action + Summary。ContextManager.buildLlmContext()。zimoos.current / zimoos.act / zimoos.search。Acceptance Mapping
system[0]稳定,不包含 ZimoOS 当前界面状态src/agent.ts,src/agent/request-context-builder.ts,src/agent/message-store.tsmessages[0]across frame changes; debug request log confirms no ZimoOS block insystem[0]system的 ZimoOS 当前状态块RequestContextBuildersuffix handling; ZimoOS attachment pathsystemrequest message for<zimoos>and[ZimoOS Current Frame]<zimoos><zimoos>不进入持久历史MessageStore,SessionStore, request builder cloningMessageStore.snapshot()and persisted JSONL after requestRequestContextBuilder.sanitizeToolMessage,RuntimeContextSlotStore, debug logToolExecutor,MessageStore, new operation-summary correction pathRuntimeContextSlotStore, request builder, operation journalContextManager.buildLlmContext()src/agent.ts,test/provider-request-redline.test.tsRequestContextBuildergroup/windowing,MessageStoremutationsrc/agent/tool-router.ts, mteam MCP configzimoos.current -> zimoos_x2e_current -> zimoos.current; real e2e tool call visibletest/e2e/zimoos.test.ts, local mteam backendnpm run e2e:zimoospasses or explicitly skips due missing backendRegression Boundaries
必须防止以下回归:
system[0]。systemdynamic suffix。<zimoos>写入MessageStore或 session JSONL。Non-goals
zimoos.current / zimoos.act / zimoos.search。Parent Scope Status
Status: partial until all Acceptance Criteria above are complete.
已完成基础:
zimoos.currentFrameruntime slot。仍未完成且不能延期:
<zimoos>request-only,不入历史。