Files
Jyotisha/docs/tasks/TASK-consultation-daily-empty-answer-20260909.md
T
Jesse_ChenandCursor 365ad799a5
Independent Staging Quality Gate / validate (push) Successful in 14m23s
Independent Staging Quality Gate / publish (push) Successful in 2m7s
docs: record BUG-609–611 fix SHA 7d3bb0c5 and free 612/613 for the daily empty-answer brief
The later daily-deep-dive task reused 609/610 while those numbers were already assigned to the sync2 repair. Keep 609–611 on the shipped dasha/fence/version fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 17:03:52 +08:00

7.8 KiB
Raw Blame History

TASK · 「深入看今日」计算完成却没有回答(empty_answer),且思考流漏出缺词英文(2026-09-09)

  • 基线:origin/staging @ ee6173e8staging 部署以健康接口为准)
  • 分支:codex/consultation-daily-empty-answer-20260909,基于 origin/staging
  • 执行方:coding agent;验收:Claude
  • 涉及文件:frontend/src/mastra/consultation-tools.tscanonicalDomainPlan L291、AGENT_SLICE_MAX_STEPS L56、consultationSliceGenerationSettings L73)、frontend/src/app/api/consult/route.tscomposeSection L1151、retryForAnswer L1128)、frontend/src/lib/stream-agent-response.tscomposeByHeadings L420、consumeAttempt L336)、frontend/src/lib/consultation-thinking-plan.tsnatalConsultationThinkingPlan)、frontend/src/lib/consultation-entrypoint.tsdaily_starlanguage 扩展 L7280)、frontend/src/lib/public-thinking.ts
  • BUG 编号起点:BUG-612docs/BUG_HISTORY.md 最大已到 BUG-611TASK-upstream-sync2-fix-20260909 占用 609611
  • 优先级:P1(首页入口"深入看今日"整条失败;不扣点是对的,但用户拿不到回答)

1. 事故实证(2026-09-09 staging,用户转录;只写结构)

活动区依次:读取分析方法 → 计算本命盘 → 先整理本盘的统一参数 → 接下来分析你的综合 → 用审计表收口后再落到生活("已完成 5 步")。随后思考区出现一段缺词英文(The a for 2026-09-09 (, per). The is a - an, not a. … The be "" or "timing" - is a/trend. … Let me use: [""]. … "timing"? … Let me run-jyotish-.),最后正文只有 计算已完成,但这次没有生成回答,本次不会扣点。请再发送一次。empty_answer)。

2. 根因

2.1 BUG-612P1):入口定的是"时运",模型自己改成"综合";写作阶段想改回来时已经没有步数

  1. 首页"深入看今日"发的是 theme: "timing" + entrypoint: "daily_starlanguage"page.tsx L14661470),问题被扩展成"深入解读 ${日期} 的今日主题:今日趋势、适合推进、需要避开、一个行动建议"(consultation-entrypoint.ts L7280)。
  2. run-jyotish-consultationcanonicalDomainPlanconsultation-tools.ts L291):模型显式传了 domains 就以模型为准,只有省略时才用路由选的 theme。活动区"接下来分析你的综合"证明本次执行的是 general,即模型把服务端定的 timing 改成了 general
  3. 计算完成后进入按标题分段写作(composeByHeadings):标题来自 natalConsultationThinkingPlan({domains: 已执行领域}) = 统一参数与原始结构 / 综合 / 技法审计表 / 现代生活。这套标题与"今日趋势 / 适合推进 / 避开 / 行动"完全对不上。思考流里模型正是在纠结这件事("is a daily/trend … 'timing'? … Let me use: [timing] … Let me run-jyotish-consultation")。
  4. 每个分段调用 maxSteps = AGENT_SLICE_MAX_STEPS = 1工具仍然可用streamOptions 没有 toolChoice: "none",分段提示只是文字上说"不要再调用排盘工具")。模型在分段里发起了第二次工具调用(想换 timing),一步用完,没有任何正文。四个分段全空 → retryForAnswer 再跑一次完整循环 → 仍空 → empty_answer。这是 BUG-280"计算成功、模型没写"的又一条来路,BUG-280 的重试救不了它,因为重试后模型面对的还是同一套错位标题。

2.2 BUG-613P2):思考流按 chunk 过滤,英文被削成词渣

sanitizePublicThinkingTextpublic-thinking.ts)对每个 reasoning-delta chunk 判断"含 ≥4 字母英文且无中文就丢"。流式 chunk 常常是一两个词:长词所在的 chunk 被丢、短词(The / a / for / is / to / Let me)和带中文的 chunk 被放行,拼出来就是用户看到的那段。工具名只剥了后缀(run-jyotish- 残留)。

3. 决策记录

  1. 入口驱动的请求由服务端钉死领域。 entrypoint 存在(daily_starlanguage / birth_time_rectification)时,canonicalDomainPlan 忽略模型传的 domains,只执行路由 theme(本例 timing);模型传了不同值记 plan_override_ignored 到 receipt,不报错不扣步。普通问题维持现状(模型可选多领域)。
  2. "深入看今日"用自己的写作标题。 新增 dailyConsultationThinkingPlan():一节"今日趋势"、一节"适合推进 / 需要避开"、一节"一个行动 + 边界句"(边界句沿用扩展里的"探索性日提示,不是确定预测"),技法审计表折进最后一节。natalConsultationThinkingPlan 只用于非入口问题。
  3. 分段写作禁用工具。 composeSectionagent.streamtoolChoice: "none"(计算已缓存,分段本来就不该调工具);某一段返回空正文时,同一段再试一次(仍 toolChoice: "none",提示追加"上一段没有输出正文,请直接写这一节"),再空才进入既有 retryForAnswer
  4. 思考流按句过滤。 sanitizePublicThinkingText 改成有状态的缓冲:按 。!?\n 或英文句号切句后再判定;纯英文句整句丢,工具名整个删(连前缀);未闭合的尾巴等下一个 chunk。对外仍只发 thinking.delta
  5. 不动计费(空回答仍不扣点)、不动 AGENT_MAX_STEPS = 8 / AGENT_TIMEOUT_MS = 110s、不动 Skill。

4. 任务分解

  • 4.1 决策 1consultation-tools.ts + route.tsentrypointConsultationAgentContext;测试——entrypoint=daily_starlanguage, theme=timing,模型传 domains:["general"] → 执行 timingreceipt 含 plan_override_ignored;无 entrypoint 时行为不变。
  • 4.2 决策 2consultation-thinking-plan.ts 新增 daily 计划;route.tsdaily_starlanguage 分支用它;测试——标题序列为三节,正文以 ## 今日趋势 开头;applyThinkingSectionProgress 能按新标题标 done。
  • 4.3 决策 3composeSectiontoolChoice: "none",分段空正文重试一次;测试(consultation-agentic-runtime.test.ts 扩)——mock 某段模型只发 tool-call 无文本 → 该段重试后写出正文,fullOutput 非空、不触发 retryForAnswer;两次都空才 answer-retry。三栏:原值"分段可调工具"→ 新值"分段禁用"→ 决策 3。
  • 4.4 决策 4public-thinking.ts 改缓冲实现;测试——把事故那段按 3–6 字符切成 chunk 喂入,输出不含任何 4 字母以上英文词、不含 run-jyotish,中文句完整;纯中文思考原样通过。
  • 4.5 记录:docs/BUG_HISTORY.md BUG-612(复发关联 BUG-280:同一"计算成功、模型没写"现象,新来路是入口领域被改写 + 分段可调工具)、BUG-613;CHANGELOG.mdPROGRESS-…docs/testing/ 加"首页点『深入看今日』必须得到三节回答,思考区不得出现英文词渣"。触发链若执行方能从 staging [agent-observability] 日志取到该 run 的 tool.input.domainsmodelFinishReason,写进 BUG-612 的验证段;取不到写 investigating,但决策 1–4 都是确定性缺陷,照做。

5. 让步顺序

4.3 与 4.1 先做(最小改动即可止血);4.2 必做;4.4 必做;4.5 不可省。

6. 开工前置命令

git fetch origin --prune
git worktree add -b codex/consultation-daily-empty-answer-20260909 .worktrees/consultation-daily-empty-answer-20260909 origin/staging
cd .worktrees/consultation-daily-empty-answer-20260909
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
cd frontend && ./node_modules/.bin/tsc --noEmit; npm run lint 2>&1 | tail -1
ls tests/consultation-*.test.ts tests/public-thinking*.test.ts tests/agent-*.test.ts 2>/dev/null | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)"