Files
cc-web/.planning/user-input-history-mcp/findings.md

8.5 KiB
Raw Blame History

Findings & Decisions: 用户输入历史 MCP

Requirements

  • 新增一个专用 ccweb MCP,只读返回用户输入内容列表。
  • 可指定目标对话;未指定时默认当前来源对话。
  • 默认返回最近 15 次用户输入。
  • 所有返回输入正文合计最多 1000 个 Unicode 字符,并明确标记截断或仍有更早内容。
  • 引导表单提交后插入为普通用户消息的内容必须包含在内。
  • 结果供 LLM 回看用户要求、作为实现验收参考。

Research Findings

  • 当前暴露的 ccweb_list_conversations 只返回会话元数据,明确不返回对话正文。
  • 当前 ccweb MCP 工具清单没有读取会话用户输入历史的工具。
  • 仓库已有其他活跃计划,当前任务使用 .planning/user-input-history-mcp/ 隔离,避免覆盖根目录或其他任务计划。
  • Trellis 开发者身份已初始化为 shiyue;共享 .trellis/.current-task 指向其他任务,因此本任务不覆盖该共享指针。
  • codebase-memory 项目 home-cc-web 索引状态为 ready(6308 nodes / 14349 edges),可直接用于函数级定位。
  • 第二次独立计划审查已通过,契约足以进入代码研究与实施。
  • MCP 公共工具定义集中在 lib/ccweb-mcp-server.js 的 TOOLS;现有 ccweb_list_conversations、ccweb_prompt_user 均在此声明 schema。
  • 内部 MCP 分派入口是 server.js 的 callInternalMcpTool(tool, args, sourceSessionId, sourceHopCount),现有列表工具转到 listConversationSummaries。
  • listConversationSummaries 已提供来源会话清洗、limit clamp、会话文件枚举和运行状态等可复用模式;正文读取应另建只读函数,避免扩大摘要接口职责。
  • 引导表单链路关键函数为 createCcwebPromptUser、handleCcwebPromptUserResponse、buildCcwebPromptUserResponseText;需读取精确源码确认提交内容最终是否由普通 handleMessage 持久化为 role=user。
  • 已确认引导表单提交链路:handleCcwebPromptUserResponse 用 buildCcwebPromptUserResponseText 生成问题/选择/答案正文,再调用普通 handleMessage(..., { emitUserMessage: true });因此提交结果会成为普通 role=user 消息,新工具只按角色筛选即可自然纳入。
  • 待填写的引导卡本身是 role=assistant 且携带 ccwebPrompt,必须排除;只有用户提交后的普通消息才应返回。
  • loadSession(id) 已是统一、安全的会话 JSON 读取入口,包含 ID 清洗、大小限制、会话规范化和运行时线程索引更新;新查询不应自行读文件。
  • 公共 MCP tools/list 读取 lib/ccweb-mcp-server.js 的 TOOLS,共享 HTTP/JSON-RPC 调用经 handleMcpJsonRpcMessage 与 isCallableToolName 进入 callInternalMcpTool。
  • isCallableToolName 会自动接受所有 TOOLS 中的公开工具;新增工具无需维护额外 allowlist。CODEX_APP_COMMUNICATION_TOOL_NAMES 只控制旧 dynamic-tool 兼容集,是否纳入需结合兼容路径调用点判断。
  • 现有回归函数 assertCcwebListConversationsScopeContract 同时断言正式 MCP schema、兼容工具定义和内部分派源码;新工具应补同等级 schema/route 契约,并通过内部 MCP HTTP 做数据行为验证。
  • server.js 的 composer 候选和共享 MCP tools/list 都直接展开 CCWEB_MCP_TOOLS,因此加入 TOOLS 后会自动出现在 / MCP mention 与正式 MCP 列表中。
  • 旧 Codex App dynamic-tool 兼容路径由 CODEX_APP_COMMUNICATION_TOOL_NAMES 精确筛选,并最终仍调用同一个 callInternalMcpTool。新工具与 ccweb_list_conversations 同属只读会话通信能力,应纳入该兼容集合;正式 MCP 仍是主路径。
  • 测试编写阶段检查工作区时,仅本任务计划/Trellis 文件与测试代理临时清单为新增文件,尚无生产代码改动或与用户既有改动冲突。
  • 新增聚焦测试 scripts/ccweb-list-user-inputs-unit.js,覆盖正式 schema、JSON-RPC/旧内部路由、默认/指定会话、15 条、角色筛选、引导提交、Unicode 总预算、错误码与只读性。
  • 首次执行按预期失败:公开 TOOLS 尚无新工具,调用返回 unknown_tool;只读 fixture hash/mtime 断言已独立通过,说明红灯指向缺失实现而非测试环境破坏。
  • 主审阅发现初版测试有两处需修正:禁止覆盖 HOME;提交表单正文会合法包含表单标题,排除未提交卡应按角色/消息 ID 断言。
  • codebase-memory 一次搜索误报项目未索引,但随后的 list_projects/index_status 显示 home-cc-web 仍为 ready(6387 nodes / 14484 edges),属于瞬时查询异常,无需重建索引。
  • codebase-memory 收敛重试又返回 Transport closed,已按降级规则停用本轮该查询并改用本地 rg/sed;定位范围仅限 sanitizeId、truncateTextValue、normalizeSession。
  • 测试代理已移除 HOME 覆盖、改用消息 ID 排除未提交引导卡,并增加临时目录清理;复跑仍只因 unknown_tool/缺失 schema 失败。
  • 生产实现新增 listUserInputHistory,使用 loadSession 只读筛选 role=user,从最新向前分配 Unicode code point 总预算,再按旧到新返回。
  • 正式 TOOLS、Codex App 旧兼容集合和 callInternalMcpTool 已统一注册 ccweb_list_user_inputs,没有第二套实现。
  • 主线程与实现代理在交接边界发生一次 apply_patch 上下文冲突;补丁工具安全拒绝覆盖,最终 diff 仅包含代理的目标改动,无丢失或重复代码。
  • 语法检查和聚焦测试全部通过,包含 fixture 文件 hash/mtime 不变断言。
  • 既有 ccweb-message-reply-unit 通过,说明新增 fallback 工具未破坏统一发送/旧别名契约。
  • 完整 npm run regression 在约 37 秒内通过;git diff --check 无空白或补丁格式问题。
  • 独立 Trellis 质量审查已通过,无阻断问题;补强了空会话、预算恰好用满(有/无更早输入)和运行时 clamp 测试,复跑通过。
  • 运行态检查发现除当前对话外,63b18af6-1b9a-4ad0-8627-f2b5ba22fc39 仍为 running;按仓库运维规则不得重启 cc-web,因此当前进程尚未加载新 MCP,需待其他对话空闲后重启。

Finalized Query Semantics

  • conversationId:显式传入则读取该会话;缺省才回退到来源会话。显式无效 ID 不得静默回退。
  • limit:默认 15,允许 1–50;先从全部非空 role=user 文本中取最近 N 条。
  • maxChars:默认 1000,允许 1–1000;以 JavaScript Unicode code point(Array.from)计数,约束所有返回 content 合计。
  • 预算分配:从最新候选向更早候选分配;遇到剩余预算不足时保留该消息开头并标记 truncated=true,更早候选不再返回;最后按旧到新排序。
  • hasMore=true:存在 limit 之外的更早用户输入,或字数预算截断/省略了候选。
  • 空白/空正文 user 消息不作为“内容”返回;引导表单提交正文是非空普通 user 消息,因此自然包含。
  • 缺少来源会话返回 missing_source_conversation;显式无效 ID 返回 invalid_conversation_id;会话不存在返回 conversation_not_found。
  • 返回项包含 messageId|null、createdAt|null、content、contentChars、originalChars、truncated;顶层包含会话 ID、limit/maxChars、总字符数、返回数与 hasMore。
  • Trellis backend 规范目前大多是占位内容;本改动不涉及“部分 JSON 预览”专项规则。实现应沿用现有 loadSession、mcpToolError 和 scripts/regression.js 的实际项目惯例。
  • 已创建隔离 Trellis 任务 .trellis/tasks/08-17-user-input-history-mcp/ 并写入完整 PRD;因共享 current task 属于其他工作,本任务不改写 .trellis/.current-task。

Technical Decisions

Decision Rationale
工具采用只读查询 不应改变会话、消息或运行状态
当前会话默认值由 MCP 服务的来源会话上下文解析 与已有跨会话工具的线程级来源语义保持一致
返回最近 N 条后再按旧到新输出 查询高效,同时方便 LLM 顺序理解需求演进
1000 字作为整体硬预算,从最新输入向前填充 限制最坏上下文体积并优先保留最新验收要求

Issues Encountered

Issue Resolution
“最多 1000 字”存在逐条或整体预算歧义 独立计划审查后选择更保守的整体硬预算,并增加截断/更多标记

Resources

  • .trellis/workflow.md
  • AGENTS.md 中 ccweb MCP 与线程级来源上下文约定