feat(web): add durable session metrics (round 1)
This commit is contained in:
@@ -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/architecture/2026-07-28-host-owned-web-session-metrics.md
|
||||
2026-07-28-host-owned-web-session-metrics.md: 04381c7443491fd9de101a87713fa5c183800d0e
|
||||
2026-07-28-host-owned-web-session-metrics.zh.md: 6ad06ea61508d3f0703c19bc7c9f14969f119334
|
||||
@@ -0,0 +1,35 @@
|
||||
# Agent Note: Host-owned Web session metrics
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-07-28-host-owned-web-session-metrics.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
A Web stats line derived from the currently loaded conversation nodes is window-dependent under pagination. Compaction can replace visible content without preserving historical usage, and route changes leave the browser without an authoritative context capacity. Cache-write tokens also risk being folded into a cache-hit formula whose denominator has different semantics.
|
||||
|
||||
## Decision
|
||||
|
||||
The Host owns one session-level metrics projection. It incrementally folds the complete durable event log, keys settled usage by `(turn, step)`, and replaces an earlier usage record for the same key instead of double-counting chunk and message forms. Uncached input, output, cache reads, and cache writes remain four disjoint cumulative buckets. Compaction can change the current prompt surface without erasing historical usage.
|
||||
|
||||
Current context pressure is a separate point-in-time value from `tokenMeter.measure(session).totalTokens`. Capacity comes only from `llm.resolveModelInfo(provider, model).context.contextWindow` for the agent's selected route. A route change immediately publishes metrics with capacity absent, then publishes the resolved capacity behind a route generation fence; stale metadata cannot label the new route.
|
||||
|
||||
The tail `session.history` response carries the projection, while older pages omit it. Live changes use `session/metrics` mux frames. Both forms carry a durable-log revision and a projection revision; the client accepts only nondecreasing revisions, preserves metrics across older-page prepend, and clears them at a new subscription baseline. Missing measurement or metadata stays absent.
|
||||
|
||||
The Web stats line treats the projection as its sole token source. It renders uncached input, output, and cache reads separately, computes cache hit as `cacheRead / (uncachedInput + cacheRead)`, and shows current context as a percentage of the exact route capacity. Cache writes never enter that percentage. Visible nodes continue to supply only turn and step counts.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Fold the loaded node window in React.** This cannot survive pagination or compaction and duplicates durable-log semantics in a presentation package.
|
||||
|
||||
**Send usage only with raw assistant events.** Reconnect and older-page stitching would still need the client to reconstruct a full-log aggregate, and duplicate usage forms would need protocol-specific repair there.
|
||||
|
||||
**Reuse one total-token field for cache hit.** Cache reads, cache writes, and uncached input represent distinct provider accounting buckets; combining them would make the displayed rate misleading.
|
||||
|
||||
**Keep the previous capacity until the new route resolves.** The old number would temporarily claim the wrong selected model. An explicit unknown state is honest and generation-safe.
|
||||
|
||||
## Consequences
|
||||
|
||||
Token totals remain stable across pagination, replay, compaction, and browser reconnect. The client stores a small detached projection instead of scanning the conversation window, and the status row remains readable for large histories through compact number formatting.
|
||||
|
||||
The Host performs one incremental log fold per session and schedules live projection updates only for usage, request-header, or surface-changing events; text and reasoning deltas do not publish metrics. Exact capacity resolution is asynchronous and may briefly render as unknown. Deployments without a token meter or model context metadata retain the row and label the unavailable value instead of fabricating one.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Agent Note: Host 拥有的 Web 会话指标
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-07-28-host-owned-web-session-metrics.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
Web 统计行若根据当前加载的会话节点推导指标,其结果会随分页窗口变化。压缩(compaction)可以替换可见内容,却无法保留历史用量;路由变更会让浏览器缺少权威的上下文容量。缓存写入 token 还可能被计入缓存命中率公式,而该公式的分母具有不同语义。
|
||||
|
||||
## 决策
|
||||
|
||||
Host 拥有一项会话级指标投影。它以增量方式归并完整的持久事件日志,按 `(turn, step)` 标识已结算用量;同一标识再次出现时,会替换较早的用量记录,而不会重复统计分片和消息两种形态。未缓存输入、输出、缓存读取与缓存写入保持为四个彼此独立的累计计数项。压缩可以改变当前提示词表层,但不会抹除历史用量。
|
||||
|
||||
当前上下文压力是一个独立的即时值,取自 `tokenMeter.measure(session).totalTokens`。容量仅来自 `llm.resolveModelInfo(provider, model).context.contextWindow`,并对应 agent(智能体)所选的路由。路由变更时,Host 会立即发布不带容量的指标,再通过路由代际围栏发布解析出的容量;陈旧元数据无法标记新的路由。
|
||||
|
||||
`session.history` 尾页响应携带该投影,较早页面则省略它。实时变更使用 `session/metrics` mux 帧。两种形式都携带持久日志修订号和投影修订号;客户端只接受不减小的修订号,在向前加载较早页面时保留指标,并在建立新的订阅基线时将其清除。测量值或元数据缺失时,对应字段保持缺失。
|
||||
|
||||
Web 统计行把该投影视为唯一的 token 数据来源。它分别呈现未缓存输入、输出与缓存读取,通过 `cacheRead / (uncachedInput + cacheRead)` 计算缓存命中率,并把当前上下文显示为精确路由容量的百分比。缓存写入绝不计入缓存命中率。可见节点仍然只提供轮次和步骤计数。
|
||||
|
||||
## 备选方案
|
||||
|
||||
**在 React 中归并已加载的节点窗口。** 此方案无法跨越分页或压缩保留数据,还会在展示包中重复实现持久日志语义。
|
||||
|
||||
**只随原始 assistant 事件发送用量。** 重连和较早页面拼接仍会要求客户端重建完整日志聚合,而且重复的用量形态需要在客户端按协议专门修复。
|
||||
|
||||
**为缓存命中率复用单一的 token 总数字段。** 缓存读取、缓存写入与未缓存输入是提供方记账中的不同计数项;将它们合并会使显示的比率产生误导。
|
||||
|
||||
**在新路由解析完成前保留旧容量。** 旧数值会在短时间内错误标示所选模型。显式的「未知」状态能如实反映情况,并避免跨代串扰。
|
||||
|
||||
## 后果
|
||||
|
||||
token 总量在分页、回放、压缩和浏览器重连期间保持稳定。客户端存储一项小型脱耦投影,无需扫描会话窗口;状态行采用紧凑数字格式,因此在较长的历史记录中仍然清晰易读。
|
||||
|
||||
Host 为每个会话执行一次增量日志归并,仅为用量事件、请求头事件或表层变更事件调度实时投影更新;文本与推理(reasoning)增量不会发布指标。精确容量解析为异步操作,因此可能短暂显示「未知」。未部署 token 计量器或缺少模型上下文元数据时,系统仍保留该行,并标示不可用的值,而不会虚构数据。
|
||||
Reference in New Issue
Block a user