44 KiB
监督者技术设计
文档信息
| 项目 | 内容 |
|---|---|
| 状态 | 生产分页、持久化批次、暂停/继续及设置已接线;27 条消息完整会话通过真实模型验证,较大样本仍未完成;完整历史回放未实现 |
| 日期 | 2026-09-23 |
| 产品设计 | 监督者应用产品设计 |
| 行为规则 | 监督者逻辑设计 |
| 界面设计 | 监督者 UI 设计 |
| 实施进度 | SQLite schema 62;页面读取与索引见页面读取与发布,当前算法、设置和验收边界见生产接线 |
本文回答如何在现有 GoodBuddy 桌面端中实现监督者。它不改变产品范围,也不把模拟 Demo 当作生产数据模型。
FR-S11 的读取架构见时态 Story Graph 内置 MCP 设计。三个只读工具通过 readStoryGraph 投影现有 SQLite,Main 在发现、调用和返回前检查监督者启用、会话开关及 Runtime 分配。绑定携带会话 ID,按主键读取当前设置;原生客户端的复用键包含会话 ID 和开关值。本地 MCP、Model、Harness Main 代理和远程受管工具通道共用此入口;会话开关复用 context_state_json,无 schema 迁移。当前监督阶段使用共享时间线 checkpoint;候选按下文的批次项目与跨项目设置筛选。memory 继续作为背景读取,结果快照不支持 as_of 历史重建。
生产入口由 supervision-production.ts 组装服务、SQLite、共享池和无工具 Runtime。supervision-review-store.ts 保存冻结来源清单,按有界页和片段供 SupervisorService 派发;叶子及连续位置先提交,导航和完整结果之后发布。消息已有知识引用保留本地或外部 locator,已确认记忆通过独立背景输入提供。不会检索外部全库。详细存储、调度及当前限制统一见分块调度第 0 节。
模型实体 id 只在单次输出内有效。生产服务将批次的 projectId 和 crossProject 经 supervisionCandidates 传到只读 Worker,再由 listSupervisionCandidates 查询共享时间线。跨项目关闭时,只提供该项目当前事件关联的未撤销实体;开启时允许其他项目的实体。候选仍最多 100 个,按更新时间和 ID 排序。查询先取得项目事件关联的实体集合,再筛选候选,避免对每个实体重复扫描事件。省略批次参数的旧读取入口保留精确 scope 查询。
生产提示只暴露 candidateRef(如 known_1)、名称和说明。模型显式选择候选后,Main 转换为严格 UUID 类型的内部 persistedId。服务校验候选集成员和重复映射,保存事务再次按实体主键校验存在性及撤销状态。没有有效候选引用时分配新 UUID,不按名称或裸模型 ID 合并。来源仍按每次结果分配 UUID,保留原始 source_id 和 locator。
新实体省略 candidateRef,不要求模型生成数据库 ID。未知非空 candidateRef、冲突身份和候选集之外的 UUID 均拒绝。旧输出中的 persistedId 仅在 UUID 合法且属于候选集时复用;空值、占位符和格式错误值不能证明已有身份,保留为独立新实体。局部 ID 或同名不会触发合并。
真实旧库存在 goodbuddy 等文本实体主键。候选读取为这些键生成稳定 UUID 别名,并在 Main 内保留 storageId 到原键的映射;模型看不到这两个字段。别名使用 scope 和原键的 SHA-256 摘要构造 UUID v8,保存时按精确映射查询原实体,保留历史图谱引用和人工确认字段,不迁移或重写原主键。新实体仍由 Main 分配随机 UUID。此兼容仅处理已经存在的旧库键,模型返回同样的文本不能直接复用实体。实测见真实失败运行修复。
schema 42 为实体、实体变化和关系增加 source_reference_ids_json,保存映射后的来源 ID。升级只补列,旧记录、ID、确认状态及 locator 保留;此前未保存的引用使用空数组,已被覆盖或忽略的历史内容无法据此恢复。
schema 43 在结果上增加 graph_snapshot_json,保存当次实体名称、说明、确认状态、关系理由及本次来源引用。后续 run 只更新 automatic 的当前实体与关系,已确认、修订或移除状态受保护。历史结果读取自身内容;人工操作带 resultId 时先校验成员归属,在事务内更新当前对象及所选结果,其他结果不变。移除关系记录 revoked,防止后续相同端点和类型的自动关系恢复它。
结果级图谱另由 supervisionAttention 按所属 run 保存的范围和时间区间查询当前消息,返回小时桶 attention;该字段不写入历史快照。既有 supervisionGraph IPC 和 Preload 原样传递,Renderer 按选定区间生成螺旋。归一化、小时内估算和历史数据限制见 3D 密度规则,故事与结果事件的对应规则见故事线模型设计。
升级从现有事件实体关联、实体变化和来源引用恢复结果成员,不猜测名称匹配;旧数据缺失的归属或已经覆盖的内容无法还原,原对象仍保留。新结果即使实体没有事件或来源,也会保存完整成员。结果内容与运行、事件、来源在同一事务提交。
overview({ target? }) 返回稳定的 id、storyLineId 及来源 ID。指定 Conversation/Task 时,只读 Worker 读取目标实际项目,查询同时要求目标来源匹配、结果 scope 为 global 或包含该项目;LIMIT 在过滤之后。卡片展示结果真实范围,global 结果不会伪装成单会话摘要。graph({ resultId, storyLineId? }) 校验二者归属,只返回该结果的事件、对象和来源标题;显式 ID 无效时不回退到最新结果。继续讨论按结果主键读取,并验证来源属于该结果。
工作回顾保存所选结果,切换或刷新使用请求序号忽略迟到图谱。侧栏按目标重建卡片,清空来源和预览,并忽略旧请求;工作栏 tasks 实例的 targetRef 可保存 conversation/task 固定目标,取消固定后恢复跟随当前选择。该绑定只控制监督卡片,不改变任务列表的项目范围。继续讨论预览显示实际目标名称和 ID,发送回调显式携带该会话 ID,由 Main 使用该会话的 Runtime 与项目。
侧栏通过 onOpenSupervisionGraph(resultId) 交给 App 导航;App 遵守现有离页检查,向 HeartbeatCenter / SupervisorWorkspace 传递类型化 graphNavigation,复用 heartbeat 路由及 keepalive 页面。每次点击创建新的导航请求,打开 graph 页签并更新历史选择共用的 resultId。overview 未包含该 ID 时仍直接请求其 graph;旧 overview、graph、来源和操作响应通过同一请求序号失效,不覆盖新结果。没有新增 window 事件、页面或持久化字段。
继续讨论预览将 supervision:continue-context 返回的 prompt 直接作为可编辑草稿。侧栏与图谱入口发送当前草稿,不重新拼接原始上下文。supervision:continue 沿用现有正文校验(去除首尾空白,最多 12,000 字符),使用空 attachments 入队,无附件请求省略 serializedContexts;请求未指定 Runtime 时使用会话保存的选择。会话已有的记忆和知识库配置仍按普通会话发送规则处理。知识库预览与提交均检查目标库存在且为本地可写库,更新实体还检查其实际所属库。侧栏确认框展示 Main 返回的实体字段、目标库和来源正文,取消或写入失败后可以重新预览。
监督来源清单将 UI 时间区间归一化为 UTC,在 Worker 读快照内按范围筛选,元数据按小批次写入;后续片段按稳定键分页。项目必须存在且 active;消息按闭区间筛选,任务按区间内创建或完成时间筛选。手动和自动监督共用该路径,增量清单另读取 supervisor checkpoint;手动心跳报告保留原有 collector。Worker 连接、未完成初始化重建、取消确认和打包规则见调度与存储。
已确认记忆作为当前背景,不参与新增正文覆盖。最多四条、每条 500 字符,时间来自真实更新时间;模型不能把背景引用为本批新增证据。旧结果继续保留原来源类型和 locator。监督正文上限现用于分批,余段继续处理;心跳报告的有界输入语义没有改变。
页面读取与发布(2026-10-05)
对应 K01 的来源投影及 K02、K05、K06。supervision:overview、supervision:graph、supervision:stories 的生产 IPC 校验后分别调用 listSupervisionResultsAsync、getSupervisionGraphAsync、getSupervisionStoriesAsync。它们复用 readonly-query-worker 的 AssistantDatabase 独立只读连接,每次领域读取包在一个 readSnapshot 内;故事响应中的故事、经验、未归属计数及撤销状态来自同一 SQLite 快照。调用前已提交的写入对下次读取可见。
文件数据库缺少 Worker 配置、启动失败、崩溃或处于原有退避期时,请求直接失败,页面沿用既有错误与重试显示;这三个入口不使用 readWithFallback,不在 Main 重跑重查询。内存 SQLite 测试保留同步分支。原工具 readStoryGraphAsync、来源详情及其他存储入口保持各自原有实现,没有增加存储进程或通用协议。
结果图谱和 scope 图谱的 sources 都只查询共享合同已有的 id、title、occurred_at,并按原表 rowid 顺序返回。正文、来源类型、locator 等仍完整保存在 supervision_sources,通过 supervision:source/source-context 按 ID 读取;历史结果、所有事件、对象和关联均保留。概览是否请求图谱由 Renderer 的页面加载规则决定,后端不截断图谱内容。
schema 62 在既有迁移事务中新增 supervision_sources(result_id, occurred_at, source_type, id) 和 supervision_results(created_at) 索引。前者供每份概览的首来源定位,后者支持结果时间及 rowid 倒序读取。升级沿用启动存储 Worker,保留表内容和 rowid,不重写正文,不触发历史转换或 VACUUM。新版本仍遵守既有的禁止旧客户端打开更高 schema 规则。
故事查询先按 scope 选择故事,再一次读取这些故事的事件成员;经验查询在 SQL 中筛选仍有形成事件、且与所选项目有关的经验,再一次读取其全部有效事件关联。经验的跨项目关联不会随项目筛选被裁掉。两类列表各至多两条 SQL,原列表和成员排序、人工调整状态及完整内容访问保留。
发布继续使用 Main 原有 BEGIN IMMEDIATE 事务。每个叶子写入后收集当时的实体、关系及来源引用,末尾只写一次 graph_snapshot_json;重复持久身份仍采用原 SQL 分组规则,保留首叶子快照值和全部叶子详情。结果、运行状态、来源、时间线与 checkpoint 仍一起提交或回滚。没有将写入迁到 Worker,也没有把一个完整结果分多次提交。大批量发布仍超过 Main 16 ms 预算,实测与剩余限制见实施进度。独立存储服务的职责迁移继续留在目标方向。
监督者模型连接
ApplicationSettings.supervisorModelProfileId 只保存已有连接 UUID,null 或旧设置缺少字段时跟随 RuntimeSettings.defaultModelProfileId。Main 的 resolveSupervisorRuntime 从 getResolvedSettings() 读取连接和已有凭据,校验文本协议及认证后,用 createModelProfileRuntime 创建无工具直连 Runtime。Renderer 仅接收公开连接信息,不新增凭据存储或 IPC 方法。
SupervisorService.admit 在执行位置内调用生产工厂的 withExecution,为提取、导航、故事及经验共享一个 Runtime;执行结束后释放。每次请求仍释放自身临时会话。建议措辞在自身调用开始时解析同一设置,结束后释放 Runtime。生命周期规则见监督者模型选择。这条路径在桌面 Main 内运行,即使证据来自远程项目,也不经过 GoodBuddy Agent 或远程模型桥。
模型阶段超时与调度
监督整理超时由 run 创建时冻结;共享模型池仍采用实时设置上限。supervision:pause 取消该 run 的排队和在途工作,supervision:resume 继续已保存批次;监督整理输出在流中按 supervisionReview.responseKiB 检查响应容量,默认 1024 KiB,可在设置页调整为 100 至 16384 KiB。该容量每次请求读取当前设置,继续旧运行也采用新值;超限保留成功批次并提示调高后继续。生成摘要及事实内容不设独立短字符限制,监督旧摘要读取保留全文,具体边界见生产接线。以下报告领取和租约规则继续适用。
手动和自动监督均在桌面 Main 调用生产工厂,由 resolveSupervisorRuntime 解析上文的直连模型,不进入 SSH 项目或 selectedRuntimes.getRuntime 分支;内部分析使用无工具构造,回顾 scope 只筛选证据。摘要校验、合并和持久化在 Main 完成,single-flight、取消及 UI 控制不改变 gbagent、远端 Runtime 启动或桌面到 Agent 协议。
ApplicationSettingsStore 持久化报告和整理模型超时,均为 30..600 整数秒,默认 240。报告排队前冻结,监督创建 run 时冻结;计时从获槽及 Runtime 解析后开始,覆盖单次 Runtime 执行及其内部重试。监督包装层的第二次尝试重新按同一秒数计时,500ms 等待和临时会话清理不计入该时限。流结束校验 signal 和完成事件,finally 释放临时会话,心跳报告保持原有 100KB 上限,监督整理使用上文的可调响应容量。采集、排队、保存和清理不计入模型超时。
runSupervisionModel 为提取、导航、故事、经验和建议共用一次临时错误重试,错误范围见逻辑规则。每次尝试使用新的 request/conversation ID 和隐藏任务,正文缓冲单独创建;用量按各次任务保存。失败后先清理计时器并释放临时会话,再等待;等待继续持有监督池槽位,受父 signal 和池取消控制,结束或失败后释放槽位。error 事件的 status: cancelled 优先于错误文字;抛出的结构化错误检查 status、statusCode 和 cause,字符串只识别明确的 HTTP 状态或已知网络/流中断格式。
直连文本请求保留 HTTP 错误的 status,并在响应流失败前交出已收到的用量;没有提供方用量时不估算补记。监督响应超容量后立即 abort 并清空正文,最多继续消费 1 秒,仅保存用量事件,不累积后续文本;随后请求关闭迭代器、释放临时会话和池槽位,迟到事件不再写入。容量错误保持原文,不被随后到达的超时或流错误替换,也不重试;已缓冲完成响应和中止响应均沿用原 call ID 记账。重试决策只在监督包装层,直连传输原有重试、OpenCode 和 Continue 策略不变。429 使用同一 500ms 等待,不新增 Retry-After、UI 或配置项。
supervisorModelConcurrency 为 1 至 4 的整数,默认 1。报告和监督整理共用 Main 内 SupervisionModelPool FIFO 池,普通聊天不入池;降低上限不终止在途请求。报告槽位从领取前持有至报告完成或无变化提交后,在下游监督开始前释放,避免并发 1 时相互等待。监督服务外层运行仍串行;该池不是完整分块调度器,也不提供跨聊天与监督的提供商全局并发、RPM、TPM 或 Retry-After 控制。
报告租约为 max(300, reportTimeoutSeconds + 60) 秒,300 是下限;每次到期领取最多一条。Runtime 解析后、模型请求开始前按冻结超时刷新租约,数据库要求运行 ID、owner、attempt、claimed 状态和未过期条件均匹配,否则拒绝启动模型。直连模型独立的 600 秒传输超时、网络重试、心跳重领及轮询不属于用户阶段时限。设置 UI 提供两个超时、共享并发及分页/分批/单次响应容量字段;整次回顾持续处理至完成,旧 executionSeconds 不再参与执行判断。
schema 47 的四张批次相关表使用外键随监督运行清理,未完成运行不新增自动过期删除规则。启动时原有 running 记录会标 failed,但已保存批次和配置保留,活动页仍可继续。发布逐页读取叶子并复用现有结果/来源/图谱写入,在同一事务更新完成状态和自动 checkpoint。
会话删除复用 SupervisionReviewStore.omitDeletedConversations,只处理 running/paused/failed 的暂存记录。删除入口在事务内补齐旧任务清单的会话归属;新清单由 Worker 在初始化时记录任务所属的现存会话。初始化完成、恢复、分块读取、模型调用前及返回落库、导航合并和发布前均检查删除。初始化中的清单仍可丢弃重建,省略计数在完整清单提交后计算。
失效计算只取批次的来源键,不把保存正文作为删除会话的替代输入;依赖导航沿 children_json 递归删除。省略数写入既有 state_json.omittedSources,透出到活动进度及结果 coverage_json,不增加 schema。发布事务先核对省略数与待发布结果一致,再保存事实和 checkpoint;若删除使摘要过时,服务返回现有提取/合并循环。已发布历史不参与失效,行为定义见逻辑规则。
当前设置及冻结范围见当前设置合同。未实现的高级参数继续保留在目标清单,不显示为可保存控件;没有兼容原型数据库的读取器。
单次执行与取消
对应 FR-S4、FR-S6、FR-S10;状态规则见活动记录。同一个 SupervisorService 在异步配置读取前占用唯一执行位置,run 和 resume 共用准入。已有执行或停止清理时,手动新建及继续立即返回 SUPERVISION_REVIEW_BUSY;trigger: heartbeat 等待当前 Promise 结束,醒来后重新检查占用。等待中的自动请求尚未创建监督 run,不占模型池;心跳报告在进入下游监督前已释放自己的槽位。
supervision:execution 返回进程内 { active, runId?, stopping? },配置读取期间可有 active: true 而尚无 runId。supervision:cancel({ runId }) 先在既有 supervision_runs 写入 cancelled、清除错误并保存取消时间,再向父 controller 传播 abort;重复取消保留原时间。该接口等待执行 Promise 结束,包含并行批次的 allSettled 和 Runtime releaseConversation,之后才释放准入。暂停只请求 abort,执行停止后保存 paused;取消优先于暂停。迟到模型输出不得保存叶子、导航或完整结果,成功批次保留,自动 checkpoint 不推进。发布是同步 SQLite 事务,已完成或无变化的运行拒绝取消,不撤销已发布结果;本次无 schema 迁移。
发布前重读已保存批次所需候选后,再检查父 signal。此时收到暂停或取消,走原有停止分支;完整叶子和导航保留,结果及 checkpoint 尚未提交。该检查与同步保存之间没有新的异步等待。
故事归属和子线索拆分在既有写事务内,按主键检查模型选中的目标、父故事和跨项目功能仍为 current。模型等待期间若用户移除或合并目标,整批写入回滚,包含新建故事和已处理标记;重新整理使用当前候选。拆分同样检查原功能及目标子线索。已发布回顾、用户调整和此前成功批次保留,不增加版本表或恢复日志。
Preload 暴露类型化 execution、cancel,取消输入使用 UUID schema 并校验可信 sender。活动 UI 用实时执行状态覆盖持久记录的停止显示;工作回顾只在发起前查询执行状态,Main 仍作最终准入判断。resume IPC 直到运行结束才返回,Renderer 发出请求后释放提交锁并独立处理结果,确保继续中的回顾仍可暂停或取消。
App 将既有通知回调经 HeartbeatCenter 传给 SupervisorWorkspace。回顾操作用 supervisor-review 去重键发送本地化 Toast,结果读取失败仍写入 loadError 并就地重试;实体、关系操作和来源读取失败也使用通知。工作回顾不再为状态条轮询执行状态,历史读取不发送操作通知。请求锁覆盖发起前检查和整次运行;页面刷新只使旧结果选择失效,不丢弃运行结束反馈。卸载后忽略迟到响应,检查阶段尚未提交的回顾不再发起,已提交的后台运行不取消。活动查询、原始错误持久化和 Main 生命周期保持原路径。
心跳触发与建议(2026-09-30)
对应 FR-S12,规则见心跳职责与介入。HeartbeatService 只依赖 HeartbeatActions { review, suggest? }:领取后 completeHeartbeatTrigger 立即提交心跳自身运行(租约 5 分钟,仅覆盖交接),再调用 review,由 ipc.ts 转为 supervisorService.run({ trigger: 'heartbeat' }, heartbeatRunId)。审查失败写 projection_status/error,结果为 no_change 时标记心跳无变化。心跳不再占用模型池,也不读取 heartbeatReportTimeoutSeconds;该设置字段保留兼容,界面不显示。下文关于心跳报告阶段、报告租约与报告增量的描述均为历史行为。
isIncrementalReview(request) 统一判断:trigger: heartbeat 或未设 reanalyze 的手动请求读取并在发布事务中推进 review_checkpoints;reanalyze: true 从零读取且不写进度。SupervisionReviewStore.unfinished 只续跑 failed/running 的心跳运行,用户暂停的保持暂停。
计划 intervention 为 suggest 时,deriveSuggestions 调用 SupervisionSuggestionStore.candidates(supervisionRunId):读取该运行叶子批次的 openItems(按原始来源映射到本结果 supervision_sources)、revised 实体变化、快照内 contrasts 关系,以及事件关联中不同原始来源数不少于 3 的 automatic 实体。指纹按类型与实体、关系或规范化文本生成;依据键使用原始来源类型、ID 与内容哈希,不用每次结果新生成的来源行 ID。每次最多 20 条。有候选时 createProductionSuggestionPhraser 发起一次无工具请求,共享监督模型池与整理超时;模型只返回 ref/title/detail,未知 ref 丢弃,缺失措辞回退规则文本。建议失败写 suggestion_status = 'failed' 与错误,supervision:retry-suggestions 只重跑建议。
IPC supervision:suggestions、supervision:suggestion-action、supervision:retry-suggestions 校验可信 sender 与 Zod 输入;监督者关闭时列表返回空、操作拒绝。接受未决事项创建暂停任务,接受候选约定确认迁入记忆或新建已确认记忆并确认实体。Schema 50 内容见实施进度。
自动增量收集
本节的 100 来源/2,000 码点批次查询现用于原心跳报告及旧服务测试;生产监督使用 schema 47 清单及批次位置,自动 checkpoint 只在完整发布时提交。已有 schema 46 指纹算法和 checkpoint 仍复用,不重置用户已处理位置。
对应 FR-S4、FR-S10 和 US-S27,行为定义见自动增量与手动重看。schema 46 在现有数据库增加 review_checkpoints,主键为阶段、规范化 scope 和来源标识,保存版本指纹、已处理位置和来源长度。来源标识区分消息 ID、任务 ID 和消息内知识引用位置,不使用消息时间戳作为身份。
消息正文写入时由 SQLite trigger 更新轻量 review_revision;范围、标题、角色和时间共同参与版本指纹。任务标题、状态、创建和完成时间,以及知识引用内容或定位变化分别使对应来源待处理。工具执行元数据更新不会把未修改的消息正文再次标为新增。删除来源时清理其进度。原始消息不复制到进度表;自动查询先排除已处理版本,再读取待处理片段,不重新载入每个会话的历史正文。
原心跳增量查询按来源时间和 ID 排序,每轮最多 100 个来源、每个最多 2,000 码点,正文预算 12,000 UTF-16 单元。该报告路径的余段留待后续检查,窗口外来源不自动补读。生产监督另用冻结清单和持久化批次,未读尾部不会因继续时的滚动窗口变化而消失;旧监督分支的 44,000/48,000 字符上限已退出生产接线。
只有实际送入模型、通过结果校验且成功落库的完整片段推进位置。心跳报告及其进度、监督结果及其进度分别在各自 SQLite 事务提交。监督服务串行执行,后续自动请求在前次保存后重新收集。报告成功而监督失败时,下一次自动检查跳过已成功的报告输入,但重试监督输入;无变化不创建报告、来源或图谱事件。
已有故事线的 scope 表示和实体 ID 保留;比较项目集合时忽略排序。生产候选按上文的项目归属与跨项目设置读取,显式选择候选才复用;已有重复实体不自动修复。监督 checkpoint 的共享时间线规则见故事线模型。知识引用继续以独立来源保存 locator;当前记忆和旧摘要不作为新事件。
迁移在事务中扩展心跳计划及运行表的状态 CHECK,保留列、索引、ID、计划、报告与引用;消息版本列使用默认值,无需遍历或重写旧正文。进度初始为空,首次自动运行从配置窗口开始。报告保留期限覆盖 no_change 运行,但不删除来源进度;删除报告不触发重新消费。
活动读取与执行持久化
对应 FR-S10、US-S26。schema 45 在既有 supervision_runs 增加可空 heartbeat_run_id 和唯一索引,在 heartbeat_runs 增加执行范围、下游投影状态、错误及结束时间字段。迁移保留原记录,不补造旧关联。监督服务通过 store 的 start/fail 接线记录执行,保存结果事务更新同一 run;不增加调度器。心跳在执行前记录冻结范围和投影进度,报告事务仍保持原有含义,下游失败单独保存。手动心跳在生产路径使用实际结束时间,活动等待下游结束后才显示整次执行的结束时间。
supervision:activity 沿用可信 sender 与 Zod 输入校验,接受 limit(1 至 100,默认 50)、offset(0 至 100000)及可选 configId。应用未启用时返回空列表且不访问活动表。未筛选时 SQL 合并心跳及未关联的监督记录;筛选时在 LIMIT/OFFSET 前按 heartbeat_runs.config_id 精确匹配,排除独立手动回顾,不依赖计划名称或范围。关联查询使用运行 ID;返回状态、阶段、范围、时间、错误、摘要和 resultId,不调用模型。保留规则和历史缺失见活动记录。
Preload 暴露类型化 supervision.activity()。overview({ resultId }) 支持按 ID 读取历史回顾,供活动跳转使用。Renderer 只在活动页签和 heartbeat 路由同时激活时串行定时读取,每次有界分页;effect 清理撤销定时器并使旧响应失效。App 关闭应用时卸载页面;读取没有执行副作用。该改动位于桌面 Main/Renderer,未修改 Agent 或远程 Runtime 协议。
活动进度现在包含既有运行 JSON 中的持久 phase 及导航表计数 navigationNodes。SupervisionReviewStages 将实际阶段与监督运行状态组合呈现;SupervisionBatchDetails 按既有 10 批分页结果组织项目、会话和批次,新增批数变化时刷新已打开页。导航和叶子使用不同的严格输出 schema,继续仍复用成功叶子与导航节点。字段语义、旧记录缺失和同步阶段限制由生产调度合同统一定义;未增加任务调度器、数据库表或远程协议。
1. 总体方案
监督者作为 Main 进程中的一个领域服务,复用现有智能心跳的计划、运行领取、租约、重试和有界模型调用。图谱是监督者整理结果的查询视图,知识库继续拥有资料正文、索引和检索。
flowchart LR
UI["Renderer\n监督者页面 / 图谱 / 侧栏"]
IPC["Preload + IPC\n类型化输入输出"]
SVC["SupervisorService\n范围、运行、结果、用户确认"]
HB["HeartbeatService\n计划、领取、租约、重试"]
EVIDENCE["EvidenceCollector\n按范围读取有界证据"]
MODEL["BoundedSummarizer\n只读 JSON 输出"]
STORE["AssistantDatabase\nSQLite 事务与查询"]
KB["KnowledgeService\n本地资料、引用、检索"]
CONV["会话 / 笔记 / 任务"]
UI --> IPC --> SVC
HB --> SVC
SVC --> EVIDENCE
EVIDENCE --> CONV
EVIDENCE --> KB
SVC --> MODEL
SVC --> STORE
SVC --> UI
SVC -->|确认后补充本地条目| KB
职责边界如下:
| 模块 | 负责 | 不负责 |
|---|---|---|
HeartbeatService |
计划、到期运行、租约、重试、已有报告兼容 | 图谱实体合并、用户确认、知识库写入编排 |
SupervisorService |
触发统一、证据收集、整理结果、图谱查询和修订 | 自己实现调度器、复制来源正文 |
EvidenceCollector |
按冻结范围读取会话、笔记、任务、知识库引用 | 越过范围读取全部数据、调用工具 |
SupervisorSummarizer |
以有界输入调用文本模型并解析结构化输出 | 执行工具、直接修改知识库 |
AssistantDatabase |
事务、外键、分页、状态和来源定位持久化 | 生成模型内容 |
KnowledgeService |
资料和本地知识条目的维护、检索及引用 | 管理监督者事件和关系 |
| Renderer | 展示和发起用户操作 | 访问 SQLite、决定权限或拼接 SQL |
2. 运行路径
应用启停遵守逻辑规则。ApplicationSettingsStore 对新设置及缺失的 heartbeatEnabled 使用 false,保留显式布尔值。Main 在心跳 tick 调用 processDue() 前、heartbeatsRunNow 与 supervisionRun IPC 入口、心跳完成后的监督回顾回调中读取已保存设置,只有值为 true 才继续。此检查不取消已领取运行,也不改变普通任务调度链路。Renderer 由 App 将同一启用状态传入 RightAssistantSidebar,控制监督面板挂载。
HeartbeatCenter 的五个顶层页签直接选择内容,无内部页签。overview 只由 SupervisorWorkspace 读取 supervision.overview 的统一结果,历史选择和图谱共享 resultId;新请求控件不改变所选结果的 scope/timeRange。HeartbeatSections 仅在 plans 输出内容,包含 HeartbeatSettings、范围与刷新、运行概览、指标、趋势、自动监督报告、记忆与行动建议及审计;activity 只渲染 SupervisorActivity,settings 只渲染两个算法参数表单。运行中的手动请求保留既有结果,活动入口清空计划筛选并聚焦 activity。计划列表放在当前状态下,复用唯一创建按钮及未配置说明。计划表单在原组件内通过 body Portal 显示,复用 custom-task-dialog 和 activateModalFocus / trapTabFocus,没有复制表单或嵌套 form。关闭确认、提交锁定及失败草稿由本地状态管理;保存继续调用 App 原有心跳 CRUD 回调。
计划“执行记录”将 activityPlanId 交给活动查询,并切换、聚焦 activity 页签。更换计划时清空旧列表、重置 offset 并清理旧轮询,保留筛选控件的键盘焦点;该筛选不传入自动监督概览,返回 plans 时仍显示全部计划的统计和心跳审计。报告展开和追加条数保存在同一组件内,切换顶层页签仍保留;图谱继续由 SupervisorWorkspace 持有结果选择,活动结果跳转保留精确 resultId。此次仅调整桌面 UI 和只读活动查询,不修改 schema、Agent 或远程 Runtime。
计划 CRUD 沿用 App → Preload → Main 接线。heartbeatRecurrenceSchema 与 computeNextHeartbeatRun 仅支持 daily/weekly;本轮不增加分钟间隔合同或调度分支。编辑草稿保存已有 timezone 和 enabled,新建仅在显式提交时使用本机时区创建启用计划。UI 命名统一为自动监督,内部 ID、翻译键、数据库及 IPC 名称保留。
手动回顾和心跳回顾必须经过同一个 SupervisorService.run(),只在触发来源上区分。这样可以保证两者使用相同的范围校验、输入预算、输出契约、结果状态和来源处理。
sequenceDiagram
participant T as 手动/智能心跳
participant S as SupervisorService
participant D as AssistantDatabase
participant C as EvidenceCollector
participant M as 文本模型
participant R as Renderer
T->>S: run(scope, timeRange, trigger)
S->>D: 创建 run,冻结范围与时间
S->>C: collect(frozenScope)
C-->>S: 有界证据 + source references
S->>M: 结构化整理请求,禁止工具
M-->>S: validated result
S->>D: 事务写入 result、events、entities、relations、references
D-->>S: completed
S-->>R: 状态和定位信息
运行状态与内容确认状态分开保存:
- 当前监督运行状态:
running、paused、cancelled、completed、failed、no_change。心跳及合并活动的映射见活动记录。 - 内容状态:来源事实、自动归纳、待核对、用户确认、用户修订、已移除关系。
- 运行成功只表示模型结果已按契约保存,不表示所有实体和关系已经被用户确认。
- 失败保留上次完整结果和本次已保存批次;暂停不生成完整结果,继续入口恢复同一 run。
3. 数据模型
首版使用现有 AssistantDatabase 和同一 SQLite 数据库。新增表保持领域对象独立,但不复制会话、笔记或知识库正文。
erDiagram
supervision_runs ||--o{ supervision_results : produces
supervision_results ||--o{ story_events : contains
story_lines ||--o{ story_events : organizes
story_lines }o--o{ knowledge_entities : references
story_events }o--o{ knowledge_entities : changes
knowledge_entities ||--o{ knowledge_relations : source
knowledge_entities ||--o{ knowledge_relations : target
supervision_results ||--o{ source_references : cites
story_events ||--o{ source_references : cites
knowledge_entities ||--o{ source_references : cites
knowledge_relations ||--o{ source_references : cites
建议的最小持久化对象:
| 对象 | 关键字段 | 说明 |
|---|---|---|
supervision_runs |
id, trigger, scope_json, time_range_json, status, error, started_at, completed_at |
一次手动或心跳整理;保存冻结范围,不从当前配置回推历史 |
supervision_results |
id, run_id, summary, change_digest, coverage_json, graph_snapshot_json |
工作回顾、监督反馈和图谱共同读取的结果版本 |
story_lines |
id, scope_json, title, created_at, updated_at |
用户选择的工作故事线,不等同于 Project |
story_events |
id, story_line_id, result_id, occurred_at, title, description, event_type, confidence |
时间轴上的事件;同日聚合只在查询或 UI 层处理 |
knowledge_entities |
id, canonical_label, description, state, confirmation_state, updated_at |
可被多条故事线引用的持续认识,不与知识库文档一一对应 |
entity_changes |
event_id, entity_id, change_type, description, confirmation_state |
表达提出、补充、验证和修订,避免覆盖实体正文 |
knowledge_relations |
id, from_entity_id, to_entity_id, relation_type, reason, confirmation_state |
关系独立拥有状态和来源;移除关系不删除来源 |
source_references |
id, owner_type, owner_id, source_type, source_id, locator_json, availability |
只保存来源标识和有界定位,不复制正文 |
外键和索引要求:
- 新增监督者对象使用 UUID;已有文本实体主键按上文兼容映射保留。实体、来源和关系通过稳定 ID 关联,不能只按名称合并。
supervision_runs按created_at、scope查询;事件按story_line_id, occurred_at查询。- 关系对
(from_entity_id, to_entity_id, relation_type)建唯一约束,允许同一实体对存在不同关系类型。 - 删除故事线只删除其组织关系,不删除共享实体、来源或知识库资料;删除知识库资料后来源标为不可用。
- 整理结果、实体变化、关系变化和来源引用在同一 SQLite 事务中提交,提交失败全部回滚。
- 只保存整理结果自身的对象内容与有界来源,不建立原会话、记忆或知识库的完整历史快照和独立向量索引。
叶子模型输出使用严格共享契约,包含 events、entities、entityChanges、relations、summary、changeDigest、openItems,事实项保留 sourceReferenceIds。Main 校验数量、字符、枚举、ID 所属范围和引用存在性,拒绝未知字段后才保存。导航输出另用导航合同,允许省略空事实数组;该规则不适用于叶子。
4. Main、IPC 与 Renderer
新增能力沿用现有边界:Renderer 只传业务输入,Main 重新校验项目、故事线、时间范围、来源和权限。
建议的 IPC 分组:
| 通道 | 用途 |
|---|---|
supervision:overview |
工作回顾、运行状态、未解决事项和最近结果 |
supervision:run |
手动开始一次整理,完成后返回包含 runId 的结果 |
supervision:activity |
有界读取真实执行和阶段状态 |
supervision:execution |
读取唯一执行位置及停止清理状态 |
supervision:pause / supervision:cancel / supervision:resume |
暂停、终止或继续指定回顾;生命周期见上文 |
supervision:graph |
按故事线、时间区间和回放时刻分页读取图谱 |
supervision:object |
读取事件、实体、关系及来源详情 |
supervision:confirm |
确认、修订或移除自动关系和实体变化 |
supervision:continue-context |
生成继续讨论前的上下文预览 |
supervision:knowledge-preview |
预览新建或补充本地知识条目 |
supervision:knowledge-commit |
用户确认后调用知识库服务写入 |
IPC 返回图谱查询结果时使用分页和有界字段;详情中的来源正文复用现有会话、笔记和知识库读取路径。不要把完整图谱一次性发送给 Renderer,也不要把模型原始输出暴露为可执行内容。
侧栏反馈通过已有应用状态刷新机制读取结果。首版可以在手动运行完成后主动刷新,心跳完成后发布一个不含私人正文的变更通知,Renderer 再按权限读取摘要;不新增系统通知正文通道。
5. 安全与一致性
- 监督者模型调用使用无工具构造,不依赖产品模式或提示词限制;生产输入来自冻结来源的分页读取,见分块调度设计。
Global、Project、多项目和固定 Conversation/Task/Experiment 目标在 Main 冻结;模型不能生成或改变范围。- 每个来源引用必须属于本次冻结范围,跨范围引用、伪造项目 ID 和不存在的来源 ID 直接使结果失败。
- 心跳运行沿用现有
heartbeat_runs的领取、租约和重试机制;监督运行按心跳运行 ID 关联,活动据此合并阶段。监督取消不撤销已保存的心跳报告,合并活动优先显示监督已取消状态。 - 同一配置同时触发手动和定时运行时,沿用现有幂等键和运行领取规则;已完成结果不能重复写入。
- 用户确认或修订后的实体、关系不被后续整理静默覆盖;新证据以补充或冲突待核对状态写入。
- 外部知识库只读。图谱可以引用保存到本地的外部片段和定位信息,不调用远端写入、不承诺打开远端原文。
- 来源正文仍由原应用拥有。监督者删除关系、故事线或运行记录时不得删除会话、笔记、任务或知识库资料。
6. 实施顺序
阶段 A:先把现有心跳变成统一运行入口
- 抽出
HeartbeatSummarizer的有界输入和结构化输出校验,使SupervisorService可以复用。 - 增加手动运行的统一服务入口,但先只生成现有回顾结果,不改变心跳页面行为。
- 为运行状态、范围冻结、失败保留旧结果补充 Main 单元测试。
阶段 B:接入证据引用和阶段回顾
- 实现
EvidenceCollector,接入会话、任务、消息已有知识引用和记忆;魔法笔记仍未接入。 - 建立
supervision_runs、supervision_results和supervision_sources,保存来源 locator,并通过KnowledgeService解析本地文档/分块。 - 在现有智能心跳页面增加监督者工作回顾入口;不先改应用名称和导航 ID。
阶段 C:实现最小故事线图谱
- 建立事件、实体、实体变化和关系表及查询服务。
- 先完成平铺环绕时间轴、节点详情、来源展开、回放和列表模式;圆形视图继续作为后续布局。
- 同一实体通过稳定 ID 连接多个事件,禁止按每次事件复制实体。
- 用真实整理结果替换 Demo 的模拟数据,并保留 Demo 作为视觉回归 fixture。
阶段 D:接入用户确认和知识库双向定位
- 增加关系确认、修订、撤销和实体拆分的最小交互。
- 从图谱返回本地会话资料及引用位置;知识库文档定位依赖来源中存在文档/分块元数据。
- 新建或补充本地条目必须经过预览和确认;外部知识库保持只读。
阶段 E:侧栏反馈与增量整理
- 将结果摘要投影到现有右侧助手栏,并沿用当前会话生命周期。
- 心跳只负责触发,监督者根据新证据决定有无变化和是否反馈。
- 在运行去重、用户修订保护和来源失效提示稳定后,再评估更复杂的跨目标固定策略、事件唤醒和自动阶段识别。
7. 验证策略
首版每层验证一条可追踪链路:
EvidenceCollector测试范围裁剪、字符预算、来源定位和不可用来源。SupervisorService测试模型输出解析、引用完整性、重复运行、取消、失败和部分结果。AssistantDatabase测试迁移、事务回滚、外键、分页、关系移除不删来源。- IPC 测试不可信输入、越权 Project/Source ID、确认状态和知识库写入前置预览。
- Renderer 测试从反馈进入图谱、点击实体高亮多个时间点、回放不显示未来结果,以及窄屏列表访问。
- 使用一组固定脱敏 fixture 验证“监督反馈 → 实体 → 多个事件 → 来源 → 继续讨论”的完整路径。
首个生产验收不要求模型自动发现所有关系。必须先证明来源可追溯、失败可解释、用户修订不会丢失,以及图谱与工作回顾读取同一结果。
8. 暂不实现的内容
- 独立的图数据库、向量图谱或新的知识库正文存储。
- 让监督者拥有通用 Agent 工具执行能力。
- 自动把所有聊天消息变成事件或节点。
- 无依据的实体自动合并、旧观点自动失效和静默覆盖用户确认。
- 应用市场建设作为监督者开发前置依赖。
- 在没有增量和去重证据前实现事件触发、自动阶段识别和全量后台重算。
当前剩余差距
- 实体与关系 revoke 保存状态;界面没有 undo 或恢复入口。
- 跨 run identity 依赖候选 UUID 的显式引用,候选范围受批次项目及跨项目设置控制;不自动合并历史重复实体,模型漏选候选时会创建新身份。
- 结果图谱使用真实事件实体连线,侧栏已按固定目标过滤并支持结果直达图谱;逐事件状态回放和 Experiment 尚未实现。
- 用户暂停已接到排队/在途 signal,并保留已保存批次;源版本变更后的局部重算、完整模型配置冻结及其他限制见分块调度第 0 节。
- 监督知识实体与知识库正文条目仍是不同对象,知识正文只能通过现有条目定位和预览接口处理。