mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(usage): thread real context occupancy + last-call usage into usageState
context.used_tokens / pct_used were derived from the snapshot's aggregate prompt total (cacheRead+cacheWrite+input). Over a multi-call tool-loop turn that is the run AGGREGATE, overstating window occupancy (often past 100%) so a footer's context gauge pins full while /status shows the true ~7%. Add two optional fields to PluginHookReplyUsageState and populate them in the reply path: - contextUsedTokens: the final call's prompt size (agentMeta.promptTokens) = real end-of-turn occupancy, a point-in-time state, not the aggregate. - lastUsage: the final model call's usage only (vs `usage`, the turn aggregate), so a footer can render the last exchange's i/o + cache. Both optional and additive; consumers fall back to the aggregate when absent (correct for single-call turns). Renderer consumption lands separately (#89835). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Ayaan Zaidi
parent
99db98a7ce
commit
56f2102c28
@@ -1748,6 +1748,7 @@ export async function runReplyAgent(params: {
|
||||
const winnerModel = runResult.meta?.executionTrace?.winnerModel ?? modelUsed;
|
||||
const ctxTokens = runResult.meta?.agentMeta?.contextTokens;
|
||||
const compactions = runResult.meta?.agentMeta?.compactionCount;
|
||||
const lastCallUsage = runResult.meta?.agentMeta?.lastCallUsage;
|
||||
recordReplyUsageState(
|
||||
{ runId, sessionKey },
|
||||
{
|
||||
@@ -1790,6 +1791,14 @@ export async function runReplyAgent(params: {
|
||||
compactionCount: typeof compactions === "number" ? compactions : undefined,
|
||||
contextTokenBudget:
|
||||
typeof ctxTokens === "number" && Number.isFinite(ctxTokens) ? ctxTokens : undefined,
|
||||
// Real end-of-turn context occupancy (final call's prompt tokens), so
|
||||
// the footer's context gauge is a point-in-time state and not the
|
||||
// multi-call aggregate. `promptTokens` is the agentMeta value already
|
||||
// resolved above.
|
||||
contextUsedTokens:
|
||||
typeof promptTokens === "number" && Number.isFinite(promptTokens)
|
||||
? promptTokens
|
||||
: undefined,
|
||||
usage: usage
|
||||
? {
|
||||
input: usage.input,
|
||||
@@ -1799,6 +1808,16 @@ export async function runReplyAgent(params: {
|
||||
total: usage.total,
|
||||
}
|
||||
: undefined,
|
||||
// Final model call only (vs the turn aggregate in `usage`).
|
||||
lastUsage: lastCallUsage
|
||||
? {
|
||||
input: lastCallUsage.input,
|
||||
output: lastCallUsage.output,
|
||||
cacheRead: lastCallUsage.cacheRead,
|
||||
cacheWrite: lastCallUsage.cacheWrite,
|
||||
total: lastCallUsage.total,
|
||||
}
|
||||
: undefined,
|
||||
// Provider subscription/limit windows for the 📊 readout. Non-blocking
|
||||
// (stale-while-revalidate): returns cached windows or undefined on a
|
||||
// cold cache and refreshes in the background, so it never delays the
|
||||
|
||||
@@ -539,6 +539,15 @@ export type PluginHookReplyUsageState = {
|
||||
compactionCount?: number;
|
||||
/** Effective context-token budget after model/config/agent caps. */
|
||||
contextTokenBudget?: number;
|
||||
/**
|
||||
* Actual context-window occupancy at the END of the turn — the final model
|
||||
* call's prompt tokens, NOT the per-turn aggregate. This is the value
|
||||
* `context.used_tokens` / `context.pct_used` must use: the aggregate prompt
|
||||
* total over a multi-call tool loop overstates occupancy (often beyond the
|
||||
* window). Absent on harnesses that don't report it (the contract then falls
|
||||
* back to the aggregate prompt total, which is correct for single-call turns).
|
||||
*/
|
||||
contextUsedTokens?: number;
|
||||
usage?: {
|
||||
input?: number;
|
||||
output?: number;
|
||||
@@ -546,6 +555,19 @@ export type PluginHookReplyUsageState = {
|
||||
cacheWrite?: number;
|
||||
total?: number;
|
||||
};
|
||||
/**
|
||||
* Usage from the FINAL model call of the turn only — vs `usage`, which is the
|
||||
* turn aggregate summed across every tool-loop call. Lets a footer render the
|
||||
* last exchange's i/o + cache instead of the whole turn. Absent on harnesses
|
||||
* that don't report per-call usage.
|
||||
*/
|
||||
lastUsage?: {
|
||||
input?: number;
|
||||
output?: number;
|
||||
cacheRead?: number;
|
||||
cacheWrite?: number;
|
||||
total?: number;
|
||||
};
|
||||
/**
|
||||
* Provider subscription/usage-limit windows for the active provider, attached
|
||||
* by core when it records the snapshot. Absent for api-key / unmapped
|
||||
|
||||
Reference in New Issue
Block a user