DeepChat Tape Trace Inspector:会话级只读执行检查器的完整实现方案
【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat
DeepChat 把会话中所有可持久化的执行事实记录为 Tape Entry,把 provider 请求证据记录在deepchat_message_traces表中,但此前只有消息级的 Trace 对话框,缺少一个会话级的全局因果视图。本文基于实现计划 plan.md 与规范 spec.md,完整讲解 Tape Trace Inspector 的分阶段实现方案:从 Tape 读取模型、证据与详情读取、类型化会话路由,到 committed-head 监听器、排序与瀑布时间线、渲染层可用性打磨,以及贯穿始终的"无推断(no-inference)"契约。读完本文,你将理解一个只读检查器如何在绝不引入第二事实源、不跨越脱敏边界、不要求整会话跨 IPC 的前提下,把 Tape Entry、物理运行、provider 尝试、工具操作与请求证据关联成 DevTools 风格的可导航视图。
1. 背景、目标与所有权划分
1.1 问题背景
现有消息级 Trace 对话框只能暴露 Request、View、Entries、Budget 和嵌套 Execution 诊断,无法给出覆盖 Tape Entry、物理运行(run)、provider 尝试(attempt)、工具操作、压缩(compaction)与终态(terminal state)的会话级视图。Tape Trace Inspector 的目标就是在保持 Tape、Runtime、Transcript 与请求证据各自权威边界的前提下,实现spec.md中定义的只读会话级检查器。
按 spec.md 的权威模型(Authority Model),检查器本身永远不是权威:
| 数据源 | 权威职责 |
|---|---|
| Tape | 追加式(append-only)的持久事实时序 |
| Runtime | 当前在线执行状态 |
| Transcript | 面向渲染层的会话只读模型 |
deepchat_message_traces | 已做凭据脱敏且有界约束的 provider 请求证据 |
| Inspector | 仅做关联、分组、计时、过滤与呈现 |
检查器不得新增第二事实表、不得把 provider trace 复制进 Tape、不得重写历史行,也不得把自己的分组/状态投影当作持久状态。
1.2 所有权划分(Ownership)
plan.md将实现责任明确切分给六个层面,这是理解全部后续工作的前提:
- Tape 基础设施层:负责有界的物理行读取与快照一致性;
- Tape 应用层:负责全量(total)Entry 投影与脱敏后的详情投影;
- 一个窄化的 Tape 检查能力:把投影暴露给会话查询;
- 会话路由:拥有面向渲染层的类型化 page / evidence / detail / 订阅契约;
- 渲染层功能目录:拥有分组、计时、搜索、选择、分页与呈现;
- 按需驱动的主进程监听器(P2):拥有 committed-head 脉冲。
这种划分保证了:任何一层都不越权读写另一层的持久状态。
1.3 实现状态与交付纪律
plan.md头部记录了实现状态:P1 读取模型与 UI、P2 committed follow、P3 排序/导出/大会话工作均已落地,容器响应式布局与概览时间线也已落地;最后阶段做的是语义与活动上下文的打磨——手动检查发现"不可用值看起来像未解析"、"没有加载 Tape 父节点的 model 请求看起来无效"、"message Entry 需要不必要详细的导航"等问题后,请求结果投影现在暴露最终累积的 Transcript 块而不宣称具备不可用的 chunk 重放能力;精确证据父节点发现与有界定向历史加载,让独立的 100 行窗口不再看起来像关联失败。权威、Live、分页与安全契约均保持不变。
计划同时规定了交付纪律:工作在feat/tape-trace-inspector分支上以可审查的提交拆分;每次提交前审查完整 staged diff,检查隐藏副作用、兼容性回归、边界行为、性能、安全、命名、测试充分性与未来维护成本,发现问题先修复再提交,且不从该 worktree 推送。
2. SDD 与契约基线(第 1 阶段)
- 落地
spec.md与本计划,并完成完整文档评审; - 确认每个已解决决策都有实现归属,且不存在未解决的标记。
完成条件:已提交的 SDD 必须足以拒绝任何丢弃 Entry、泄漏 payload、虚构身份(invent identity)、或依赖无界读取的实现。这一条是整个项目"契约先行"思想的浓缩——spec 的价值不在于描述做什么,而在于给出可判定的拒绝标准。
3. P1:Tape 读取模型(第 2 阶段)
这一阶段建立了检查器的数据地基,共七项工作:
- 共享 Zod 契约与 TypeScript 类型:覆盖事实页(fact page)、证据页(evidence page)、详情结果、游标、过滤器与规范排序。类型定义实际位于 src/shared/types/tape-inspector.ts,其中
TapeInspectorFactRecord、TapeInspectorEvidenceRecord、TapeInspectorEntryCursor等类型与 spec 中给出的接口一一对应,ListTapeInspectorPageInput采用判别联合:mode: 'tail'时禁止携带 cursor,older/newer时强制要求expectedTapeIncarnationId与 cursor——类型系统本身就在执行"tail 无游标、续页必有 incarnation"的契约。 - 有界的 tail/older/newer 存储读取:与既有 Tape entry 读取器并列新增,避免检查器改动现有读路径。
- 单事务快照:incarnation、快照头、行与页面级证据计数在一个显式 SQLite 读取事务内读取。plan 特别强调"不能依赖当前单线程调用顺序"——契约是事务一致性,而非事件循环顺序。
- 全量投影:实现
traceInspectorProjection.ts的 total mapping,带tool与other兜底、可空名称、有界 code 值,以及 context/Skill 正文的完全扣留。 - 哈希语义复用:沿用存储字符串的 SHA-256 语义,完整性只通过既有验证器暴露。
- 窄化读取能力:新增窄 Tape Inspector reader 能力,并经
SessionTape与会话 data/query 边界转发。 - 层边界白名单:仅为这一窄消费者扩展 Tape 层边界 allowlist。
完成条件:会话可以请求一个有界规范页,而无需加载 effective view、也不遗漏任何物理 Tape 行。
主进程侧的实现落在 src/main/tape/application/traceInspectorService.ts。从源码可以看到几个与 plan 直接对应的工程常量:
const DEFAULT_PAGE_LIMIT = 100 const MAX_PAGE_LIMIT = 200 const MAX_FILTER_SCAN_ROWS = 2_000 const STORAGE_SCAN_CHUNK = 200 const CANONICAL_SORT = { column: 'entryId', direction: 'asc' as const }即:页面默认 100 行、服务端上限 200 行;带过滤器的扫描有 2000 行预算、按 200 行分块读取——这正是"有界扫描 + 显式行预算 + 续页游标"性能契约的落地。listPage的开头即对输入做严格校验:tail 必须无 cursor、cursor 的 sort 列与方向必须匹配请求、newer页在非entryId排序下直接抛错(Live follow 仅规范序可用)。
4. P1:证据与详情读取(第 3 阶段)
请求证据(deepchat_message_traces)与 Tape Entry 属于两个独立的顺序域,这一阶段为其建立了完整读取契约:
- 新增会话范围的 trace 元数据 keyset 分页,支持可选的 message/request/attempt 过滤,且输出绝不含 endpoint/headers/body 字段;
- 其游标独立于 Tape entry 游标——这是权威边界在数据层的直接体现;
- 将证据历史排序与"行追加式 Live 游标"分开,避免相等时间戳隐藏后来的随机 traceId(
older按(createdAt, traceId)降序,newer使用基于 trace 行 ID 的追加游标,返回追加序升序); - 保留追加高水位:在支持的 tail 删除路径下保留 append 高水位,使被耗尽的过滤扫描推进到会话头,而不是反复扫描不匹配行;
- 批量页面级证据计数:不再逐行查询 trace 存在性;
- 新增
sessions.getTapeInspectorRecordDetail,带 incarnation 校验; - 详情披露严格遵循精确 schema 白名单 → 脱敏 → 字节/集合截断的三段顺序;
- 对未知 event/anchor schema 与一切 context/Skill 正文,只返回 hash/size;
- 在渲染层客户端定义"行到详情"的能力矩阵(capability matrix)。
完成条件:bound 请求、诊断与未匹配 model 请求在没有列表 payload的情况下可被发现,且每个 Entry 选择都有安全、显式的详情结果。
5. P1:类型化会话路由(第 4 阶段)
- 注册 list、evidence、detail 三类路由契约;
- 新增
SessionQuery、session>pnpm run format pnpm run i18n pnpm run lint pnpm run typecheck外加聚焦的 Tape、会话路由/查询、渲染模型与组件套件。
plan.md记录的结果是:161 个聚焦主进程测试与 249 个聚焦渲染器测试全部通过;主进程迁移套件输出了既有的"被忽略的重复列"诊断,所选测试仍然通过。唯一未勾选的项是需要交互式桌面会话的手动演示验证(明暗主题、键盘导航、会话/消息入口、请求范围/诊断/未匹配请求、稀疏 ACP Tape、重置、暂停/恢复、大会话滚动),且该手动项不改变上述读取、身份或安全契约。14. 渲染层可用性打磨(第 13 阶段)
这是"信息呈现如何不误导开发者"的迭代,核心成果:
- 三泳道概览时间线取代逐行 waterfall 列:位于账本(ledger)上方、有界,使用 session/model/tools 三条稳定语义泳道;
- 实际时间(Time)与规范序列(Sequence)两种模式分离,保留权威计时与显式点语义;Time 模式把已加载的 Tape Entry 与普通 model 请求合并为一个稳定的
(createdAt, domain, domainKey)显示序,Sequence 模式保持规范entryId序与身份分组——时间戳只是显示坐标,从不绑定证据或推进游标; - 把获批的结构化事实提升为本地化的行/组摘要,不扩展列表 IPC、不暴露 payload;
- 账本在360 / 520 / 760 / 960 px容器宽度下响应式呈现、无横向滚动;宽模式下保留列排序与调整;
- 工具栏控件在紧凑宽度下确定性地换行,并提供侧面板最大化模式用于聚焦检查;
- 详情只在选中后出现(宽侧窗或紧凑内嵌覆盖层),关闭时恢复焦点;
- 时间线渲染与已加载记录数解耦(有界像素分桶),选择、分页锚点、折叠、过滤与 Live 跟随全部保留。
渲染层组件与时间线/布局逻辑分别对应 TapeInspectorPanel.vue、TapeInspectorTimeline.vue、timeline.ts 与 layout.ts。
完成条件:首次用户在任何支持的侧面板宽度下都能定位、扫描并检查记录,而账本不需要横向导航。
15. 语义状态与证据精化(第 14 阶段)
这一阶段解决"检查器如何诚实地表达不确定":
- 区分显式状态、不适用状态(not-applicable)与未解析组状态三种渲染语义,空状态格用安静的占位符而非重复
unknown; - 显式成功的工具结果独立映射,不把无关子状态词汇混入请求/尝试组状态;
- 时长只出现在 run 与 tool 组上,fact/attempt/request/evidence 行以点或不适用呈现;
- 诊断哨兵证据(
requestSeq = 0)从普通 model 请求中拆出,默认折叠为诊断泳道,不改变 trace 身份与详情访问; - null-attempt 证据改称请求范围(request-scoped),不宣称其"一定是遗留";没有已加载父节点的证据称未匹配(unmatched),不宣称"缺失执行上下文";
- 表格化的时间与时长数值右对齐,占位符在所有行断点下保持安静。
完成条件:账本把视觉强调留给权威状态与可操作缺口,点事实与诊断保持可发现但不主导日常扫描。
16. 时间序请求与消息上下文(第 15 阶段)
- 用中性的model-request 集合取代含糊的"未匹配证据"类别,保留独立 trace 游标与精确绑定规则;
- Tape 父节点未加载的 model 请求按实际
(createdAt, traceId)时间排序,并在实际时间概览中保持可见; - 为已缓存的 user/assistant transcript 消息添加固定高度内联预览,不扩展 Inspector 列表 IPC;assistant 预览限于可见内容块,排除 reasoning、错误与 tool payload;强制 committed 会话所有权与有界输出;
- 诊断保持独立且默认折叠,provider 请求详情保留按需访问。
完成条件:日常扫描读起来像时间导向的活动历史,而完整 provider payload 与少见诊断只能通过刻意检查获得。
17. 请求上下文可读性(第 16 阶段)
- 请求行不再显示聚合的"最终消息摘要",而是显示严格先于每个 trace 的最新可见 Transcript 活动;
- 请求详情展示最新优先的有界上下文尾,工具参数与结果仍排除在账本摘要之外;
- 为新请求证据持久化归一化的 AI SDK 输入(instructions、messages、tools、provider options),使刻意的详情检查能看到供给给 SDK 的运行时上下文;
- 脱敏收窄为可复用凭据(认证/API-key 头与显式
api_key/apiKey体字段、媒体 URL 中的 basic-auth 与apiKey查询值),保留 token 计量与普通诊断可见; - 在 Trace 设置旁警告:model 请求内容本地持久化且可能含敏感 prompt 数据。
完成条件:连续 model 请求可一眼区分,刻意的详情检查暴露有用的归一化请求上下文,可复用凭据保持受保护。
18. 最终请求结果投影(第 17 阶段)
- 在新 provider 生成的 Transcript 块上持久化可选的 logical-round、request-sequence、physical-attempt 身份——只是关联元数据,绝不把 Transcript 变成请求证据;
- 当透明 provider 重试改变物理尝试时关闭挂起叙述块,防止两个尝试的内容在一个身份下合并;
- 从 committed 会话的既有 Transcript 缓存投影最终累积内容、reasoning、tool-call 参数、错误与媒体存在性;
- 每个 model-request 账本行优先使用最新精确关联块,对旧块保留有界、显式非绑定的时间回退;
- 详情中分离"观察到的结果、后续会话活动、先前上下文、持久化的 model 请求",并声明provider chunk 不被保留——展示的是最终累积块而非逐 token 重放;
- 工具结果保持在 model 生成输出之外(它们是运行时结果,有自己的 Tape Entry)。
完成条件:开发者可以扫描每个 model 请求最终产出了什么,并检查其有界最终块,而不把时间回退误认为绑定、不把最终快照误认为逐 token 重放。
19. Tape 术语对齐与历史加载反馈(第 18 阶段)
- 用户可见名词对齐 Tape 核心原语:Tape、Entry、Anchor、View;DeepChat 的 run/request/attempt/journal/contract/message/tool/lineage 明确限定为实现语义或派生分组;
- 线协议保留
FactRecord等既有标识符以兼容,但 UI 中持久行统一称 Tape Entry; - 在泳道/详情层面解释:匹配的 Entry 可能在已加载窗口之外,或旧证据缺少稳定身份;绝不从时间戳接近度推断父节点;
- 保留 prepend 滚动锚点,并为"已加载 Entry、无匹配的有界范围、到达 Tape 起点、读取失败"提供可访问的结果反馈——视口保持绝不允许看起来像无操作。
完成条件:检查器使用 Tape 术语而不夸大 DeepChat 专属概念,每个更旧页动作都有可观察结果。
20. 精确证据父节点发现(第 19 阶段)
这是修复"独立 100 行窗口看起来像关联失败"的关键机制:
- 新增incarnation 范围、仅元数据的路由,一次解析至多 200 个精确
(messageId, requestSeq, physicalAttempt)身份到 provider-attempt Entry ID; - 单条查询经既有唯一 provenance 索引解析全部身份,只选取 provenance key 与 Entry ID;
- 保持 null 与 zero 的身份区分;缺失的 completion Entry 返回显式 null;陈旧 incarnation 被拒绝且无 payload 泄露;
- 解析结果与 Tape/证据游标独立跟踪,会话或 incarnation 重置后丢弃迟到结果;
- 区分"已加载、更早、被过滤/更新、当前未记录、请求范围、诊断"六种呈现,无时间戳推断、无重复警告文案;
- 上下文式更早历史动作:每次激活至多加载 6 个连续更旧页,保持视口锚点,可显式续载;非规范排序或 Entry 过滤可能隐藏目标时禁用定向加载。
主进程实现见
TapeTraceInspectorService.resolveEvidenceEntries(traceInspectorService.ts):先去重身份、构造buildTapeProviderAttemptProvenanceKey生成的 provenance key,再用一次getEntryRefsByProvenanceKeys查询完成全部解析——与 plan 中"一条查询、只取 provenance key 与 Entry ID、无 null→zero 转换、无 JSON 扫描、无逐行查询"的描述完全一致。完成条件:独立的有界窗口不再看起来像关联失败,精确的更旧父节点可被发现与加载而不稀疏水合,中断或请求范围证据保持真实而不被呈现为错误。
21. 时间序账本与运行时上下文(第 20 阶段)
- Time 模式渲染已加载 Tape Entry 与普通 model 请求的单一稳定实际时间合并,Sequence 模式保持规范分组
entryId序; - 时间戳保持仅显示,精确证据绑定、独立游标、incarnation 重置、选择与有界分页不变;
- 识别持久化的Memory View 与 directive View Anchormanifest,暴露有界的选择/预算摘要与历史 manifest 详情,但绝不解析可变的当前 Memory 内容;
- 对已知的物理
tool_call/tool_resultschema 暴露凭据脱敏、有界的预览与结构化详情;未知 schema 保持仅元数据; - 用分类的更早/过滤/Live/未记录/不一致解释取代笼统的"未解析 endpoint"文案,且 Status 与 Duration 不重复同一警告。
完成条件:已加载活动按开发者实际经历的顺序呈现,确切运行时上下文在其持久记录处可见,不可用历史被精确描述而不削弱权威或凭据边界。
22. 交付要点回顾(Delivery Notes)
plan.md末尾的交付说明浓缩了若干长期语义约束,值得单独记住:physicalAttempt为 null 时证据保持请求范围;null 永不当作 zero,UI 不宣称每条请求范围记录都是遗留;- 组身份包含 Tape incarnation,run/request 桥接的稳定性与分页遍历顺序无关;
- 暂停/恢复保持持久的 Tape 游标与独立证据游标;仅证据追加可跟随而不推进 Tape;
- 详情窗格暴露关联、计时、脱敏后的 Raw 数据与既有消息诊断;显式请求诊断绝不回退到其他请求;
- 消息工具栏动作当前只提供
messageId:单一请求组可无歧义选中,多请求组留给用户显式选择而非猜测。
23. 提交计划
原始提交计划按功能切片组织了 8 个提交:
1. docs(tape): specify trace inspector 2. feat(tape): add inspector read model 3. feat(session): expose inspector diagnostics 4. feat(renderer): add inspector projection store 5. feat(renderer): add inspector panel 6. feat(tape): follow committed inspector facts 7. feat(renderer): complete inspector tooling 8. test(tape): cover inspector contracts提交边界允许在"公共契约会与其唯一消费者分离落地"时合并相邻切片;提交信息描述具体能力或行为,从不描述评审过程。
24. 关键契约速查
最后以一张表总结本文反复出现的硬性契约,便于检索引用:
契约 内容 依据 全量投影 N条输入 Entry 产生N条列表记录,未知 kind 落otherspec.md、traceInspectorProjection.ts 有界分页 页默认 100 行、上限 200 行;过滤扫描预算 2000 行;存储按 200 行分块 traceInspectorService.ts 快照一致 incarnation、快照头、行与证据计数在单事务内读取 traceInspectorService.ts incarnation 隔离 不匹配返回 reset且无新 incarnation 记录spec.md 证据独立域 证据游标不含 entryId,永不推进 Tapesrc/shared/types/tape-inspector.ts 精确父节点发现 单次查询经唯一 provenance 索引解析至多 200 个身份 traceInspectorService.ts 支持导出 facts 与 evidence 各至多 200 条,详情数据 256 KiB 预算 spec.md 与 导出常量 Live 无 payload 脉冲仅含 { sessionId, tapeIncarnationId, maxEntryId }TapeInspectorHeadPulse 无推断纪律 无邻接时长推断、无 started→running 状态推断、无 request→attempt 绑定推断 spec.md Tape Trace Inspector 的价值在于它示范了一种"检查器工程"的完整方法:以规范契约为拒绝标准,以所有权划分为模块边界,以全量投影、有界读取、fail-closed 详情与无推断纪律为数据纪律,再分 P1/P2/P3 与语义打磨阶段推进,最后用 161 个主进程与 249 个渲染器聚焦测试钉住每一条跨模块契约。对任何需要"在既有权威存储之上叠加只读诊断视图"的系统,这套 plan 与 spec 的组织方式本身就是可复用的模板。
【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world
项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考