Merge master into docs/post-v3-release-proofreading

This commit is contained in:
xjt
2026-08-12 20:48:08 +08:00
148 changed files with 2028 additions and 408 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-max-tokens-turn-end-notice.md
2026-08-12-max-tokens-turn-end-notice.md: bdb34d67a6d8271089af04f6bcd0f046ef7cdea6
2026-08-12-max-tokens-turn-end-notice.zh.md: 9b9c679972570e791b607330195810d68f04c803

View File

@@ -0,0 +1,27 @@
# Agent Note: The chat flow surfaces a max-tokens turn end
Status: implemented
English | [中文](2026-08-12-max-tokens-turn-end-notice.zh.md)
## Problem
The agent loop records `max-tokens` as its own `turn/end` reason, but no user surface consumed it. In the Web chat flow only `reason.kind === 'error'` built a conversation node, and the unknown-surface fallback claims append-surface events only, so a turn the provider cut at its output cap ended with no visible sign: the truncated answer read as a normal completion, and the user had no way to tell why the run stopped (issue #1522).
## Decision
A `turn-max-tokens` conversation node Definition matches `turn/end` with `reason.kind === 'max-tokens'` and materializes a persistent chat row at the turn position: a warning StateDot, a localized title, and guidance that the truncated output is preserved and sending "continue" resumes in a new turn. The node derives from the durable session event alone, so refresh, restore, and history replay rebuild it identically. It shows no token numbers: the event carries none, and the notice must not fabricate budget data the provider did not report.
The renderer registers under the keyed `conversation.chat.node` seat like every chat row, and the legacy chat-snapshot contribution includes the node. The fixture history gained a max-tokens sample turn (72; the image and todo turns shifted to 73 and 74), and an assembled keyless snapshot pins the dot state, title, and hint, so a regression that routes max-tokens through the error presentation or silences it again changes a golden.
## Alternatives considered
**Extending `turn-error` with a max-tokens arm** — rejected: the acceptance for issue #1522 requires that max-tokens not read as a provider error; a shared node kind couples the two presentations, and the two reasons carry different data (an error payload versus nothing).
**A turn-tail marker instead of a flow row** — rejected: the tail renders closing chrome for a finished turn and its actions collapse on later turns, while the truncation notice must stay at the turn that was cut and remain visible in history without interaction.
**A continue or retry action button on the notice** — deferred: resuming has open semantics (new turn versus same-turn splice, old-output retention rules) that issue #1522 explicitly leaves out of scope; guidance text carries the safe next step without committing to an action contract.
## Consequences
Max-tokens turn ends are visible, localized, and distinct from both errors and normal completion across live streaming, reload, and replay. The fixture renumbering cost two comment updates in dependent snapshots, and anything pinning fixture turn numbers must count from the new layout. Surfaces other than the Web chat flow (ACP and SDK consumers) keep mapping the reason through their own presentations and are unchanged.

View File

@@ -0,0 +1,27 @@
# Agent Note: 聊天流展示 max-tokens 结束的轮次
Status: implemented
[English](2026-08-12-max-tokens-turn-end-notice.md) | 中文
## Problem
agent loop 已把 `max-tokens` 记录为独立的 `turn/end` 原因但没有任何用户表面消费它。Web 聊天流中只有 `reason.kind === 'error'` 会生成会话节点unknown-surface 兜底又只接管 append-surface 事件于是被提供方在输出上限处截断的轮次没有任何可见迹象被截断的回答看起来和正常完成一样用户无从得知运行为何停止issue #1522)。
## Decision
新增 `turn-max-tokens` 会话节点 Definition匹配 `reason.kind === 'max-tokens'``turn/end`在该轮位置生成一条持久聊天行warning 状态的 StateDot、本地化标题以及说明已截断输出会保留、发送“继续”可在新一轮接着输出的指引。节点只从持久会话事件推导因此刷新、恢复和历史回放会重建出完全一致的结果。提示不显示任何 token 数字:事件本身不携带数量,提示也不得伪造提供方未报告的预算数据。
渲染器与其他聊天行一样注册在按 kind 分发的 `conversation.chat.node` 槽位下legacy chat-snapshot 投影也包含该节点。fixture 历史新增了一个 max-tokens 样本轮72图片轮和 todo 轮顺移为 73、74并有一条 assembled keyless snapshot 钉住圆点状态、标题和指引文案,把 max-tokens 路由回错误样式或再次静默的回归都会改动 golden。
## Alternatives considered
**在 `turn-error` 上加一个 max-tokens 分支** — 否决issue #1522 的验收要求 max-tokens 不得呈现为普通 provider error共用节点会耦合两种呈现且两种原因携带的数据不同一个有错误负载一个没有
**用 turn-tail 标记代替独立聊天行** — 否决turn-tail 渲染的是完成轮次的收尾信息,其操作会在后续轮次折叠,而截断提示必须停留在被截断的那一轮,并且在历史中无需交互即可看到。
**在提示上放继续或重试按钮** — 暂缓恢复输出的语义尚未确定新开一轮还是同轮续写、旧输出保留规则issue #1522 明确把它排除在范围外;指引文字已给出安全的下一步,不必先固定一个操作契约。
## Consequences
max-tokens 结束在实时流、刷新和回放中都可见、已本地化并与错误和正常完成明确区分。fixture 重编号需要更新两处依赖 snapshot 的注释,之后钉 fixture 轮次号的改动要按新布局计数。Web 聊天流之外的表面ACP 和 SDK 消费方)仍按各自的呈现映射该原因,本次不变。