Repository navigation
洞察生成失败时可以一键重新生成(服务器与本地模式同形) - #2
Merged
Merged
Conversation
- server:新增 POST /api/insights/retry,body 为 { contact_ids }。非空数组、正整数、
去重、上限 100 位,非法时返回 400;联系人不存在时与 GET /api/contacts/:id 一致返回 404。
成功 200 insight_status ok;模型失败也是 200,insight_status failed,insight_error 走
与确认卡片相同的 getPublicErrorMessage,数据库不写半截
- app:新增 retryInsights({ contactIds }),服务器模式走新接口,本地模式照 confirmCard
的洞察段落实现,经 dispatch 按当前目标分发
- app:洞察页失败提示卡里加「重新生成洞察」。运行中禁用;目标已变更或没有受影响联系人时
不显示;流程已过期时丢弃结果。成功时按 id 合并新洞察并清掉失败标记,失败时保留提示卡
并显示 insight_error
- flow-context:洞察列表与失败标记合成一个状态,确认与重试的合并都走可测的纯函数
(applyConfirmInsightsToFlow / applyInsightRetryResultToFlow),
新动作 applyInsightRetryResult
- README 中英文:后续工作删去洞察重试一条,Agent 环第 7 步补一句可在洞察页重新生成
- 测试:服务器成功写库、失败不写库、非法 body 400、联系人不存在 404;本地成功与失败;
dispatch 分发;flow-context 合并、失败保留、过期丢弃
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KTuFAfAdgU7H5k9kFMWkVP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
分步计划
origin/main(b6dbdaa,已包含任务 1 的合并)开出claude/insight-retry。POST /api/insights/retry,含输入校验和联系人存在性检查。成功与失败的语义与确认卡片时的洞察部分完全一致。app/src/types.ts加类型,app/src/api.ts加服务器请求,app/src/connection/dispatch.ts按目标分发,app/src/local/api.ts加本地实现。flow-context新增动作applyInsightRetryResult,洞察页的失败提示卡里加「重新生成洞察」按钮。新接口
服务器:
POST /api/insights/retry请求:
{ "contact_ids": [3, 5] }200 { ok: true, data: { insight_status: "ok", insights: [...] } }200 { ok: true, data: { insight_status: "failed", insight_error: "…", insights: [] } }contact_ids缺失、不是数组或为空400 INVALID_REQUEST_BODY「contact_ids must be a non-empty array」"3"、true、null、1.5、0、负数都不行)400 INVALID_ID「Invalid contact id」,与parsePositiveId同一个错误400 TOO_MANY_CONTACTS404 NOT_FOUND「Contact 999 not found」,与GET /api/contacts/:id完全一致,此时不调模型insight_error走同一个getPublicErrorMessage:已知错误显示原因,其它显示「Unexpected insight generation error」。成功时新洞察替换这些联系人原有的洞察。generateInsights先对所有联系人调完模型,最后才用一个事务写库,所以中途失败什么都不写。测试里第一位联系人成功、第二位失败,库里的洞察前后完全一样。/api/cards/:id/confirm也一样。改它会影响所有 JSON 路由,这次没动,可以另开任务改成 400。app:
retryInsights({ contactIds })InsightRetryResponse,定义为Pick<ConfirmCardResponse, "insight_status" | "insight_error" | "insights">,保证与确认卡片时的洞察部分同形。服务器侧在server/src/app.ts用同样方式定义;没有新增共享类型,所以shared/types.ts没改。confirmCard的写法,providerFactory.createTextProvider(options.keys)加generateInsights({ db: options.store, contactIds, provider, now: now() })。成功返回 ok;任何异常都返回 failed,错误信息「洞察生成失败,请检查模型配置后重试。」,与confirmCard共用同一个常量。dispatch和confirmCard一样按当前目标分发,已测本地、服务器、网页三种目标。generateInsights直接跳过,不报 404。原因有二:说明要求本地照搬confirmCard的写法;而且本地模式可以删联系人,如果照服务器那样报错,删过某位联系人之后,这一批的重试就永远失败。界面行为(
app/app/insights.tsx)affectedContactIds调retryInsights。targetMismatch)或没有受影响联系人时,不显示按钮。isFlowGenerationCurrent已不成立(例如已经开始新的一批),直接丢弃:不写进新流程,也不弹提示。applyInsightRetryResult内部会再按 generation 检查一次。applyConfirmResult同一个合并函数mergeInsightRecords。hasInsightFailure被清掉,提示卡消失。洞察列表一变,页面原有的加载逻辑会补齐缺失的联系人详情,依据就是这些联系人的 observations。showError显示insight_error。请求本身失败(网络、404)时也用showError提示。insights_start/insights_ok/insights_error,detail 带retry前缀,没有新增事件类型。flow-context的实现方式insights与hasInsightFailure原本是两个独立的 state,现在合成一个FlowInsightState。这样一次更新就能同时改列表和失败标记,而且基于最新状态。applyConfirmInsightsToFlow与applyInsightRetryResultToFlow。合并去重、清标记、失败保留、过期丢弃都能直接测。动了哪些文件
server/src/app.ts(新路由、校验、类型)、server/src/tests/app.test.ts(4 个新测试)。app/src/types.ts:InsightRetryRequest/InsightRetryResponseapp/src/api.ts:服务器请求与导出app/src/connection/dispatch.ts:接口与分发app/src/local/api.ts:本地实现,失败文案提成常量app/src/flow-context.tsx:合并状态、纯函数、新动作app/app/insights.tsx:按钮与重试流程app/src/tests/local-api.test.ts:成功与失败两条路径app/src/tests/dispatch.test.ts:分发app/src/tests/flow-context.test.ts:合并、失败保留、过期丢弃、确认行为不变app/src/tests/upload-batch.test.ts:它的RoutedApi测试替身必须补上新方法,只加了一个未使用的桩README.md、README_EN.md的「后续工作 / Future Work」删去「洞察重试端点」;「Agent 环 / Agent Loop」第 7 步补了一句(中文:「洞察生成失败时,档案照常保存,可以在洞察页一键重新生成。」)。中英文各写各的。shared/core/schema.ts、shared/core/migrations.ts、shared/types.ts、deploy/、.github/、PLAN.md、docs/PLAN-V2.md、版本号、tag、打包脚本;没加依赖。示例联系人甲、示例联系人乙之类)和假 provider。本机验收(owner)
网页版需要重新构建(
bash scripts/build-web.sh),手机端需要用这个分支的包。服务器模式
.env里的DEEPSEEK_API_KEY改成无效值,重启服务器。没配 DeepSeek 的话,洞察走 DashScope 的 Qwen 文本模型,就改DASHSCOPE_API_KEY。sqlite3 server/data/mailuo.sqlite 'SELECT contact_id, kind, content FROM insights ORDER BY id DESC LIMIT 5;'。本地模式(安卓)
两种模式都看一下
验证命令输出
两条命令都在本次会话里原样跑过。完整 TAP 输出很长,下面只保留版本、安装摘要、测试汇总和 typecheck 结果。
server:
cd server && npm ci && npm test && npm run typecheck,整条命令退出码 0。app:
cd app && npm ci && npm test && npm run typecheck。npm test有 5 个失败,退出码 1,&&链因此没走到 typecheck;typecheck 单独跑,退出码 0。这 5 个失败与本改动无关,只出现在这个云端容器里,情况和任务 1 的 PR(#1)里说明的一样:
app/src/tests/review-fields.test.ts,报错是ERR_INVALID_RETURN_PROPERTY_VALUE。原因是容器里只有 Node 22.22.2,它的同步模块 hook 不接受 CommonJS 返回空 source;CI 用的 Node 22.23.2 没有这个问题。main在这个容器里同样是这 5 个失败,而任务 1 的 PR 在 CI 上 app 全过。本 PR 的 CI 结果以 checks 为准。🤖 Generated with Claude Code
https://claude.ai/code/session_01KTuFAfAdgU7H5k9kFMWkVP
Generated by Claude Code