Files
makelore/.project-docs/10-decisions/proposals/20260928-agent-single-chat-27da516b__single-conversation.md
T

148 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用户与下发智能体的单一持续会话
- 日期:2026-09-28
- 状态:待采纳设计;尚未修改产品代码或已接受 ADR。
- 任务:20260928-agent-single-chat-27da516b
- 代码基线:b26e25c9ed26bf30f4d0bc03869c223f0fe34386
- 用户要求:像微信联系人聊天,一个用户与一个智能体只有一个可见会话。
- 范围解释:按用户+智能体理解为跨项目连续聊天;先保持现有本机历史持久化范围,不承诺跨设备同步。
## 1. 用户体验
顶栏继续显示所有已下发智能体。点头像直接恢复这个用户与该智能体的唯一聊天、草稿、未读和阅读位置。移除学生面板的“新话题”加号和“以往讨论/选择话题”下拉框。向上滚动加载更早消息。
切换项目或 Pi 会话不另建可见会话。输入区显示本轮上下文,例如“当前项目:天气 App · 操作对话:我要做个天气 App”;上下文变化时在下一轮提问旁显示来源。已开始的问题仍绑定原项目,切页不会改走它的文件读取路径。
不同智能体各有自己的聊天;昵称、头像、默认项、发布版本变化不会变成另一个联系人。保留已有 Markdown、工具活动和结构化讨论渲染,不顺带增加附件、搜索或聊天删除系统。
## 2. 已确认现状与改造位置
| 源码 | 已确认事实 | 影响 |
| --- | --- | --- |
| electron/coding-teacher/service.ts | scopedStore 在项目 .makelore/teacher-conversations/账号/范围下存历史;create 每次生成 UUID;topic 固定项目和版本 | 会话身份与本轮上下文分离 |
| shared/coding-teacher.ts | TeacherTopic 持有 projectId、version、definition;TeacherRequest 只有可选 sourceConversationId | 项目与发布版本下沉到请求 |
| electron/coding-teacher/cloud-runner.ts | thread_id = topic.id;teacher_version = topic.version;local_context.scope 使用 topic.projectId | 可见聊天 ID 和云执行线程 ID 解耦 |
| electron/coding-teacher/store.ts | topic 文件包含全部 requests;list 读取各 topic 文件 | 改为分页读取,避免永久聊天全量加载 |
| electron/api/routes/coding-teacher.ts | 项目级 agent-topics 路由;SSE 发送完整 topic | 按联系人读写,事件只更新目标轮次 |
| src/pages/Chat/TeacherChatPanel.tsx、use-teacher-companion.ts | 话题选择和显式新建;状态、草稿以 account/project/agent 组织 | 归属改为 account/agent,项目只作上下文 |
这些结论来自本地源码和老师 ADR,不代表部署验收。本轮未检查 Yuxi 服务端线程绑定与压缩实现;实施前必须核实。
## 3. 数据结构
### AgentConversation:唯一可见聊天
- 唯一键:accountId + agentId。agentId 使用目录稳定 teacher_id,对应 definition.config_id,不使用名称、版本或默认标记。
- 保存 conversationId、创建/更新时间、最后消息、未读游标、阅读位置及当前执行段。
- 首次真正保存消息时由 Main 串行获取或创建;多窗口并发不能生成两个聊天。打开空面板不触发模型。
- 运营同步同一个配置沿用身份;删除后重新创建得到新配置 ID,视作另一智能体,不按同名合并。
- 当前展示资料使用已下发配置;历史保留执行版本及必要显示快照。
### ConversationTurn:每轮请求
在现有 TeacherRequest 上明确保存:
- requestId、conversationId、问题/引用/回答、状态、工具活动、用量。
- projectId、项目名称快照、sourceConversationId、来源游标和采集时间。
- teacherVersion、runtimeThreadId、云 request/run ID。
- 用户提问或主动建议来源、结构化讨论引用。
Main 接受时冻结项目、来源和版本,使用现有项目服务校验 Pi 会话归属并解析路径。Renderer 不传任意本地路径。流式回调按 requestId 更新目标轮,不能继续假设数组最后一项就是当前请求,因为主动建议可能同时到达。
### RuntimeSegment:内部执行段
建议同项目、同发布版本连续提问复用当前 Yuxi 线程。下一次发送发现项目或版本改变时,创建内部线程,带入有预算的近期交流及相关状态;旧消息仍显示在同一时间线。A → B → A 可以产生新执行段,不需要后台线程池。只切换页面或头像不建线程、不收费。
历史过长优先使用已验证的 Yuxi 压缩能力;若该能力不满足合同,可使用相同执行段机制轮转,并带入有界上下文。实施前验证服务端能力,不假定已有压缩,也不把全部历史不断追加到 query。摘要若调用模型,必须沿用学生计费链并明确触发,不新增定时总结调用。
这可利用现有 thread_id 参数;初步判断客户端为主要改动。Yuxi 是否需要补充压缩或恢复接口,在实施时依据其源码与测试确定。Works 继续负责目录、版本和学生身份,无需为此新增运营会话管理。
## 4. 发送与恢复
建议 Host API(名称在实施时按项目风格收敛):
- GET /api/coding/agents/:agentId/conversation:读取唯一聊天或空态。
- GET /api/coding/agent-conversations/:id/messages?before=...&limit=50:历史页。
- POST /api/coding/agents/:agentId/messages:幂等创建聊天、冻结上下文并接受问题。
- GET /api/coding/agent-conversations/:id/events:活动轮、未读和状态事件。
- POST /api/coding/agent-conversations/:id/requests/:requestId/cancel:取消精确请求。
断网、切页、重开只查询/订阅原状态,不重放计费问题。重复提交沿用 requestId。同一用户与智能体一次接受一轮主动问答;运行时可编辑草稿、等待或停止,先不引入消息队列。不同智能体沿用现有总运行约束。
历史页与事件按消息序号/revision 合并,避免分页覆盖流式结果;先显示最近 50 轮,向上加载,保持阅读锚点,阅读较早消息时不强制滚到底部。
每轮只读工具仍使用冻结 projectPath、Pi 消息快照、账号与取消状态;现有分页、预算和最终回答规则保持。其他项目的历史聊天文本不授予读取那些项目文件的权限。
草稿文字归用户+智能体,代码/消息引用携带项目与 Pi 来源。切项目后若草稿有旧引用,发送前明确保留旧上下文或移除引用,不能静默解释成新项目资料。“带回操作对话”定位消息原目标,不写入碰巧打开的另一会话。无有效项目时保留历史与草稿;普通无项目聊天需核对云合同,第一版可继续要求选择项目,不伪造上下文。
## 5. 配置与结构化讨论
版本改为“每轮接受时固定”:下一轮使用当前已下发版本;已运行轮次保持原版本;必要时切内部执行段,聊天不重建。停用禁止新调用,历史可读;同 ID 重启下发继续原聊天。运行中停用、取消和结算遵守原服务端规则。
现有 topic.discussion 不能直接合并成一个跨项目对象。卡片保留独立 ID、projectId、revision 与历史快照,当前只激活对应项目的讨论对象。操作旧项目卡片应明确恢复其来源上下文,不能套用当前项目卡片。
## 6. 持久化与旧历史
建议使用现有 app userData 根下新增账号隔离的 agent-conversations 目录,不改变全局路径配置。项目源文件和 Pi 会话继续在项目目录。移除项目不会连带删除用户与智能体的全部聊天。
使用轻量聊天索引加每轮独立文件,复用现有原子写文件能力,不新增数据库依赖。仅写当前轮和必要元数据;验证轮文件/索引在退出中断时可恢复,不能重发模型问题。
旧记录接入:
1. 只扫描应用已登记项目的既有老师历史目录、当前账号;不扫描整块磁盘。
2. 相同 definition.config_id 的旧话题归入同一聊天,按发生时间展示,保存 originProjectId/originTopicId/originRequestId;同时间用来源 ID 稳定排序。
3. 使用来源 ID 判定是否已接入,不按正文去重;重复问同一句话仍是两条消息。
4. 原文件保留,新结构写入成功才记录进度,重启可继续,不原地覆盖。
5. 无法证明身份的旧合成朋友/旧老师记录继续只读,通过单独旧记录入口查看,不按名字猜归属。
6. 失联项目稍后重新打开时再接入;不宣称已收集所有磁盘历史。
7. 不合并云端 checkpoint;旧运行结束或取消后启用新发送。只带入必要公开交流,不重新执行旧问题或上传完整工程。
8. 多份草稿只选择身份明确的一份恢复,其余保留供恢复,不用最后写入覆盖所有内容。
本方案先保持本机持久化。若需要同账号跨设备共享记录,必须增加服务端唯一会话与同步游标,文件读取仍绑定发起设备;各机器独立 UUID 无法保证跨设备唯一。
## 7. 并行主动观察任务
20260928-agent-observer-design-9c41a872 的记录显示正在实施项目选择观察者及轮数/空闲/冷却触发。其代码尚不属于本方案基线。建议由 Main 提供幂等的“向 accountId + agentId 聊天追加观察结果”操作,带 originatingProjectId 和 observationId。
观察调度仍按项目,无建议不制造空消息,有建议进入同一个聊天并产生对应头像未读。观察运行不能复用或挤占正在运行的主动问答线程。先前提到的按 requestId 更新可防止结果写错轮次。
实施前刷新该任务与 20260928-consultation-scope-83fa19c2 的记录;后者目前为模板、范围未知。明确 shared DTO、service、hook 和面板的文件所有权后再写产品代码。本轮仅写独立方案,不干扰并行实现。
## 8. 实施顺序与验收
1. 确认数据合同、云端线程/版本约束与并行接口,完成 Main 唯一存储和幂等发送。
2. 接入旧历史,冻结每轮项目/版本,验证执行段与云端恢复。
3. 替换话题 UI,接分页、上下文提示、草稿/阅读位置/未读。
4. 主动建议通过统一消息入口接入,完成联调。
实施必须验证:
- 双窗口、重试和重启只产生一个聊天和一次模型调用。
- 同智能体跨项目保留历史;A 请求运行中切 B,工具仍只读 A。
- 不同账号、智能体的消息/草稿/未读隔离。
- 下一轮采用新发布版本,运行中轮次不被切换。
- 重复正文、同时间旧消息、中断接入及失联项目不丢记录、不复制调用。
- 数千轮历史分页,流式结果不被翻页覆盖,阅读位置不跳动。
- 断网/关闭/取消/退出恢复不重发,不留假运行状态。
- 原项目或 Pi 来源删除后历史仍可读,旧引用/卡片不能误操作新项目。
- 主动建议和问答同时返回,分别更新正确记录,未读只追加一次。
- 顶栏打开即持续聊天,无学生新话题加号及话题下拉框。
设计阶段未运行产品测试、构建、真实收费模型或云端验收。实施时应做聚焦 Store/Service/API/Renderer 回归、Electron 切项目与分页流程、类型检查和生产构建。
## 9. 采纳与规范
待实施批准并验证后,在集成阶段更新老师 ADR、system-overview、data-flow、business-rules、README:
- 账号+项目+话题改为账号+智能体;
- 项目/Pi 来源改为每轮冻结上下文;
- 话题固定版本改为每轮接受时固定版本;
- 建议/讨论/问答共用联系人时间线,各自保留项目来源。
当前已接受决策保持不变。本提案不会把尚未实现的行为写成现状。
## 10. 实施结果(2026-09-28)
用户已批准实施和既有主动观察任务协调。单会话客户端已实现;具体数据、路由、验证和集成边界以[任务记录](../../30-worklog/tasks/20260928-agent-single-chat-27da516b.md)为准。
实际采用 `/api/coding/agent-conversations/:agentId` 系列接口;Main 原子保存轻量索引和独立轮文件,每页50轮,流事件仅传当前轮。云端源码协调结果显示线程同时绑定项目和Pi来源,故项目、Pi来源或版本改变都会切换内部线程;同段沿用现有Yuxi压缩,新段只携带有预算的公开历史。本机长历史可由只读工具按消息ID取回。
正文草稿、已读位置和旧记录已处理;滚动位置和已加载页的缓存只维持当前窗口生命周期。未进行跨设备同步或生产付费模型验收。旧原始记录全部保留,可从只读入口查看。
主动观察实现仍在另一任务独立审查中,尚未进入本分支。其“继续讨论”仍创建项目话题,必须在两项集成时改为同一聊天的幂等建议投递/定位;不能把接口协调记为组合功能已实现。单会话方向已经用户批准,共享规范的正式更新留给集成任务。