Repository navigation
fix: prevent the WebChat token ring from over-reporting context usage - #9255
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
Chat.vue, the computedlatestTokenUsageTotalnow primarily reflects latest context tokens rather than cumulative usage; consider renaming this computed property and its consumers to better match the new semantics and avoid confusion for future maintainers. - Using
0to represent "unknown"current_context_tokensconflates a valid zero-length context with missing data; consider usingnull/Noneat the serialization boundary and checking explicitly for that to distinguish these cases more clearly.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `Chat.vue`, the computed `latestTokenUsageTotal` now primarily reflects latest context tokens rather than cumulative usage; consider renaming this computed property and its consumers to better match the new semantics and avoid confusion for future maintainers.
- Using `0` to represent "unknown" `current_context_tokens` conflates a valid zero-length context with missing data; consider using `null`/`None` at the serialization boundary and checking explicitly for that to distinguish these cases more clearly.
## Individual Comments
### Comment 1
<location path="tests/test_tool_loop_agent_runner.py" line_range="654-678" />
<code_context>
+ assert runner.stats.to_dict()["current_context_tokens"] == 220
+
+
+@pytest.mark.asyncio
+async def test_stats_clear_current_context_when_latest_usage_is_missing(
+ runner, provider_request, mock_tool_executor, mock_hooks
+):
+ """Do not expose stale context occupancy when the latest usage is unknown."""
+ provider = MissingFinalUsageProvider()
+ await runner.reset(
+ provider=provider,
+ request=provider_request,
+ run_context=ContextWrapper(context=None),
+ tool_executor=mock_tool_executor,
+ agent_hooks=mock_hooks,
+ streaming=False,
+ )
+
+ async for _ in runner.step_until_done(3):
+ pass
+
+ assert runner.stats.token_usage == TokenUsage(
+ input_other=100,
+ input_cached=10,
+ output=1,
+ )
+ assert runner.stats.current_context_tokens == 0
+ assert runner.stats.to_dict()["current_context_tokens"] == 0
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Extend the missing-usage test to also cover streaming mode.
This regression test currently only exercises `streaming=False`, even though the underlying stats logic is shared between streaming and non-streaming flows. To ensure we also catch any discrepancies in how final responses are emitted in streaming runs, please parameterize `test_stats_clear_current_context_when_latest_usage_is_missing` on the `streaming` flag (similar to the previous test) so both modes are covered and we verify stale context is never exposed during streaming.
```suggestion
@pytest.mark.parametrize("streaming", [False, True])
@pytest.mark.asyncio
async def test_stats_clear_current_context_when_latest_usage_is_missing(
runner, provider_request, mock_tool_executor, mock_hooks, streaming
):
"""Do not expose stale context occupancy when the latest usage is unknown."""
provider = MissingFinalUsageProvider()
await runner.reset(
provider=provider,
request=provider_request,
run_context=ContextWrapper(context=None),
tool_executor=mock_tool_executor,
agent_hooks=mock_hooks,
streaming=streaming,
)
async for _ in runner.step_until_done(3):
pass
assert runner.stats.token_usage == TokenUsage(
input_other=100,
input_cached=10,
output=1,
)
assert runner.stats.current_context_tokens == 0
assert runner.stats.to_dict()["current_context_tokens"] == 0
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request introduces tracking for the most recent LLM request's input tokens (current_context_tokens) separately from cumulative token usage, allowing the UI to display the current context-window occupancy. The changes span the agent stats model, the tool loop runner, the chat dashboard component, and corresponding unit tests. Feedback on the changes suggests removing a redundant is_chunk check in the runner since chunks are already filtered earlier, and simplifying the null/undefined check in the Vue component using a loose inequality check (!= null).
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
6fac77a to
71f1fd0
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a current_context_tokens field to track the input tokens sent in the most recent LLM request separately from cumulative token usage, allowing the dashboard to display the latest context-window occupancy. The frontend has been updated to use this new field, and corresponding unit tests have been added to verify the behavior. No review comments were provided, so there is no additional feedback.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Fixes #9248。
WebChat 输入框旁的 Token 用量圆环此前直接使用
AgentStats.token_usage计算上下文占用率。然而,token_usage会累计一次 Agent 运行中所有 LLM 请求的输入和输出 Token。在包含多轮工具调用的场景下,同一段历史上下文会被重复计入,导致圆环显示 200%、1000% 等明显高于实际上下文占用率的数值。本次修改将“累计 Token 用量”和“当前上下文占用”拆分为两个独立指标:
token_usage继续保留累计语义,供统计、计费和 Agent 运行信息展示使用;current_context_tokens,记录最近一次完整 LLM 请求的输入 Token,即input_other + input_cached;current_context_tokens计算占用率,不再把多轮请求的累计用量误认为当前上下文大小。输出 Token 没有计入
current_context_tokens,因为圆环需要反映的是最近一次请求发送给模型的输入上下文,而不是这次请求产生的输出或整个 Agent 运行的累计消耗。Modifications / 改动点
修改
astrbot/core/agent/response.py:AgentStats中新增current_context_tokens字段;AgentStats.to_dict()中序列化该字段,使其能够随agent_stats事件发送并保存到 WebChat 历史消息中。修改
astrbot/core/agent/runners/tool_loop_agent_runner.py:token_usage原有的累计逻辑,不影响 Provider 统计和计费用量;current_context_tokens更新为该次响应的输入 Token;current_context_tokens重置为0,避免继续显示上一轮请求的陈旧上下文数据;conversation.token_usage更新逻辑不变。修改
dashboard/src/components/chat/Chat.vue:agentStats.current_context_tokens;token_usage计算逻辑,保证旧数据兼容;0时,不显示圆环,避免展示不可靠的数据。修改
tests/test_tool_loop_agent_runner.py:token_usage仍等于各轮用量之和;current_context_tokens只等于最后一次请求的输入 Token,并排除输出 Token;current_context_tokens能正确序列化。This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
验证步骤
结果:检查通过。
结果:
其中 warning 为项目已有的 Python
audioop弃用提示,与本次修改无关。cd dashboard pnpm typecheck结果:
vue-tsc --noEmit执行通过。两个失败均来自 Windows 下视频附件测试对
file:///path/...路径分隔符的既有预期差异:测试期望/path/to/video.mp4,实际在 Windows 上被规范化为\path\to\video.mp4。失败用例与本次 Token 统计修改无关。回归测试覆盖的核心场景
模拟一次包含两次 LLM 请求的工具调用流程:
修复后的预期和测试结果:
这证明累计统计仍被完整保留,而 Token 圆环可以使用最后一次请求的
220个输入 Token,不再错误使用累计值333。Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Separate WebChat context-window occupancy from cumulative token usage and ensure the token ring reflects only the latest request’s input tokens.
New Features:
Bug Fixes:
Enhancements:
Tests: