diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 03a935a5..7c673589 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -3065,3 +3065,31 @@ - 防复发:Case API 的公开 DTO 必须有单一解析边界并由合同测试锁定;特殊业务流不得继承通用推荐问题兜底;Agent 正文、Activity 和结构化业务卡片必须各自拥有唯一内容职责,不得重复呈现或把内部执行过程写进自然回复。 - 相关记录:BUG-173、BUG-174、BUG-175、BUG-176 - 修复版本:本次提交(staging 精确 SHA 以推送结果为准;尚未部署) + +## BUG-180 | 生时校正缺少跨轮安全上下文且单一事件契约破坏自然叙述 + +- 状态:resolved(已验证,待本次 staging 发布完成) +- 首次发现:2026-08-13 +- 最近更新:2026-08-13 +- 影响面:V9 System Prompt、首次开场、`rectification-read-case` 安全投影、多轮承接与多事件证据记录。 +- 用户现象:Agent 容易把每条输入当成新事件;同一段中的多件事件被合并或要求逐条重发;“是的、那年、后来改了”等承接回答缺少上下文;用户拒答后可能被重复追问;首次开场像客服式流程介绍。 +- 根因:Prompt 缺少以理解真实经历和信息增益为导向的正向行为目标,并把输入限制为单一事件;`buildAgentMessages` 只提供当前轮消息,`rectification-read-case` 又只返回统计,没有受限的近期对话、事件摘要、当前修订目标和近期拒答目标。 +- 修复:整体替换 System Prompt 与首次开场指令;支持同轮多事件分别 propose/confirm;`rectification-read-case` 从服务端 Dossier 派生有界的 `evidence_context` 与 `conversation_context`;允许当前 pending 用户轮立即关闭已拒绝的 active follow-up;同步 Skill 与 conversation strategy。 +- 验证:V9 Agent、status/security、evidence、contracts 聚焦行为与安全合同测试共 56 项通过;目标 ESLint 通过,`git diff --check` 通过。 +- 防复发:不得恢复单一事件问卷契约;跨轮承接必须通过服务端安全投影,不得传递 raw ledger;拒答不落成证据,也不得重新开启同一追问目标。 +- 相关记录:BUG-173、BUG-174、BUG-175、BUG-179 +- 修复版本:本次 staging 发布提交(精确 SHA 以提交与部署结果为准) + +## BUG-181 | 生时校正 Activity 写死状态且完成凭证抢在 Agent 正文之前 + +- 状态:resolved(已验证,待本次 staging 发布与真实浏览器验收) +- 首次发现:2026-08-13 +- 最近更新:2026-08-13 +- 影响面:V9 生时校正 NDJSON Activity、运行中 Orbs、完成凭证、候选采用按钮与 Agent 执行静默。 +- 用户现象:Agent 运行时显示与真实工具不一致的“正在核对星盘信息”等写死文案;只有候选比较能在开始阶段出现公开状态,其他工具实时状态缺失;完成后的大块执行记录位于 Agent 正文之前,用户先看到系统日志而不是结论,技法又以不可点击的标签堆叠产生交互误导。 +- 根因:前端把运行中 Activity 与持久化执行凭证混在同一展示状态中,通用消息行在没有真实事件时虚构具体动作;服务端 stream mapping 只为少数 phase 映射开始状态,没有为所有公开校正工具投影统一的 started/completed/failed 生命周期;Prompt/Skill 也未明确禁止正文自行生成执行记录标题与 Activity 文案。 +- 修复:新增仅包含 allowlist 工具、状态与公开 `executed_methods` 的 `tool.activity` 协议,并在 API 出口再次清理;所有十个公开工具均按真实 tool-call/tool-result/tool-error 映射 started/completed/failed。客户端拆分当前 Activity 与完成凭证,运行时只显示 Orbs 和当前真实动作,正文开始后清除状态;完成凭证移动到 Agent 正文之后,使用原生默认折叠 `details/summary`、普通文本分组和可见键盘焦点,不再使用大灰卡与胶囊标签。候选采用按钮内部改为“正在采用…”,不增加第二个 Orbs;文字流光支持 160ms 切换淡入和 reduced-motion。Prompt、Skill 与会话策略禁止正文生成“本轮做了什么”“执行步骤”“使用技法”或内部错误细节。 +- 验证:V9 Agent/status/evidence/contracts、Activity stream、入口和布局聚焦回归共 98 项全部通过;目标 ESLint 与定向 TypeScript 检查通过;Next.js webpack 生产构建完成 TypeScript、60 个静态页面及全部路由生成;`git diff --check` 通过。默认 Turbopack 仅因隔离 worktree 的外部 `node_modules` 符号链接触发环境性 panic,非本次代码错误。真实键盘、读屏器、移动端状态切换和登录业务流仍需浏览器验收。 +- 防复发:Activity 只能来自服务端清理后的真实工具生命周期,不得从 Agent 正文、未来步骤或前端猜测生成;工具参数、出生资料、评分、权限、Provider metadata 与内部错误不得进入公开事件;Agent 正文、运行状态、完成凭证和候选卡必须保持单一内容所有权。 +- 相关记录:BUG-172、BUG-173、BUG-179、BUG-180 +- 修复版本:本次 staging 发布提交(精确 SHA 以提交与部署结果为准) diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index aaac8d08..87884ccc 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -165,8 +165,32 @@ button:disabled { cursor: default; opacity: .45; } .message-markdown p { margin: 0 0 14px; } .message-markdown ul, .message-markdown ol { margin: 10px 0 16px; padding-left: 24px; } .message-markdown li { margin: 6px 0; } -.agent-activity-status { min-height: 24px; display: flex; align-items: center; gap: var(--space-2); color: var(--color-ink-secondary); font-size: var(--type-body-sm); line-height: 1.5; } +.agent-activity-status { min-height: 24px; display: flex; align-items: center; gap: var(--space-2); color: var(--color-ink-tertiary); font-size: var(--type-body-sm); line-height: 1.5; } .agent-activity-status canvas { flex: 0 0 auto; } +.agent-activity-status__text { + color: var(--color-ink-tertiary); + background: linear-gradient( + 100deg, + var(--color-ink-tertiary) 25%, + var(--color-ink) 48%, + var(--color-ink-tertiary) 72% + ); + background-size: 220% 100%; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: + agent-activity-status-in 160ms ease-out, + agent-activity-shimmer 1.6s linear infinite; +} +@keyframes agent-activity-status-in { + from { opacity: 0; } + to { opacity: 1; } +} +@keyframes agent-activity-shimmer { + from { background-position: 120% 0; } + to { background-position: -120% 0; } +} .agent-activity-status + .message-markdown { margin-top: var(--space-2); } .composer-suggestions::-webkit-scrollbar { display: none; } .composer textarea::placeholder { color: var(--color-ink-tertiary); } @@ -2061,52 +2085,87 @@ input:not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input):disabled .membership-plan-grid, .membership-credit-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } -.rectification-message-wrap { display: grid; gap: var(--space-2); } -.rectification-activity { +.rectification-message-wrap { display: grid; gap: var(--space-1); } +.rectification-activity-receipt { width: min(720px, 100%); - margin: 0; - overflow: hidden; - border: 1px solid var(--color-border); - border-radius: var(--radius-md); - background: color-mix(in srgb, var(--color-canvas-muted) 72%, var(--color-canvas)); - color: var(--color-ink-secondary); + margin: 0 0 var(--space-2) 36px; + color: var(--color-ink-tertiary); font-size: var(--type-caption); } -.rectification-activity summary { +.rectification-activity-receipt summary { display: flex; - min-height: 36px; + min-height: 32px; align-items: center; - gap: var(--space-2); - padding: 0 var(--space-3); - color: var(--color-ink-secondary); + justify-content: space-between; + gap: var(--space-3); + padding: 0; + color: var(--color-ink-tertiary); cursor: pointer; - font-weight: 600; + font-weight: 500; list-style: none; } -.rectification-activity summary::-webkit-details-marker { display: none; } -.rectification-activity summary::before { content: "+"; color: var(--color-ink-tertiary); } -.rectification-activity[open] summary::before { content: "−"; } -.rectification-activity summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; } -.rectification-activity ol { - display: grid; - gap: var(--space-1); - margin: 0; - padding: 0 var(--space-4) var(--space-3) calc(var(--space-4) + 18px); -} -.rectification-activity-methods { - display: grid; - gap: var(--space-2); - padding: var(--space-3); - border-top: 1px solid var(--color-border); -} -.rectification-activity-methods > span { color: var(--color-ink-tertiary); font-size: var(--type-overline); font-weight: 600; } -.rectification-activity-methods ul { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; } -.rectification-activity-methods li { - padding: 3px 7px; - border: 1px solid var(--color-border); +.rectification-activity-receipt summary::-webkit-details-marker { display: none; } +.rectification-activity-receipt summary:focus-visible { border-radius: var(--radius-sm); - background: var(--color-canvas); - color: var(--color-ink-secondary); + outline: 2px solid var(--color-focus); + outline-offset: 3px; +} +.rectification-activity-receipt__summary-main, +.rectification-activity-receipt__toggle { + display: inline-flex; + align-items: center; + gap: var(--space-1); +} +.rectification-activity-receipt__summary-main svg { color: var(--color-success); } +.rectification-activity-receipt__toggle { flex: 0 0 auto; color: var(--color-ink-tertiary); } +.rectification-activity-receipt__toggle svg { transition: transform 160ms ease; } +.rectification-activity-receipt[open] .rectification-activity-receipt__toggle svg { transform: rotate(180deg); } +.rectification-activity-receipt__failure-mark { + display: inline-grid; + width: 15px; + height: 15px; + place-items: center; + border: 1px solid currentColor; + border-radius: 50%; + font-size: 10px; + font-weight: 700; + line-height: 1; +} +.rectification-activity-receipt.is-failed, +.rectification-activity-failure { color: var(--color-danger); } +.rectification-activity-failure { margin: 0 0 var(--space-2) 36px; font-size: var(--type-caption); } +.rectification-activity-receipt__details { + display: grid; + gap: var(--space-3); + margin-top: var(--space-1); + padding: var(--space-3) 0 var(--space-2) 19px; + border-left: 1px solid var(--color-border); +} +.rectification-activity-receipt__details section { display: grid; gap: var(--space-1); } +.rectification-activity-receipt__details h3 { + margin: 0; + color: var(--color-ink-tertiary); + font-size: var(--type-overline); + font-weight: 650; +} +.rectification-activity-receipt__details p { margin: 0; color: var(--color-ink-secondary); line-height: 1.65; } +.rectification-activity-receipt__method-groups { display: grid; gap: 2px; } +.rectification-activity-receipt__method-groups strong { color: var(--color-ink-secondary); font-weight: 600; } + +@media (max-width: 640px) { + .rectification-activity-receipt, + .rectification-activity-failure { margin-left: 32px; } + .rectification-activity-receipt summary { align-items: flex-start; } + .rectification-activity-receipt__toggle { padding-left: var(--space-1); } +} + +@media (prefers-reduced-motion: reduce) { + .agent-activity-status__text { + animation: none; + background: none; + -webkit-text-fill-color: currentColor; + } + .rectification-activity-receipt__toggle svg { transition: none; } } /* Admin: quiet operational surface. */ diff --git a/frontend/src/components/agent-activity-status.tsx b/frontend/src/components/agent-activity-status.tsx index 11d9b03e..77320dd2 100644 --- a/frontend/src/components/agent-activity-status.tsx +++ b/frontend/src/components/agent-activity-status.tsx @@ -21,7 +21,7 @@ export function AgentActivityStatus({ return (
); } diff --git a/frontend/src/components/chat-message-row.tsx b/frontend/src/components/chat-message-row.tsx index 656ee494..c8a1273a 100644 --- a/frontend/src/components/chat-message-row.tsx +++ b/frontend/src/components/chat-message-row.tsx @@ -16,7 +16,13 @@ export function AgentAvatar() { return