Merge pull request #1430 from trek-e/fix/1423-session-cost-compaction
fix: accumulate session cost independently of message array (#1423)
This commit is contained in:
commit
364bd5b65b
2 changed files with 24 additions and 9 deletions
|
|
@ -246,6 +246,12 @@ export class AgentSession {
|
|||
private _retryPromise: Promise<void> | undefined = undefined;
|
||||
private _retryResolve: (() => void) | undefined = undefined;
|
||||
|
||||
// Cumulative session stats — survives compaction (#1423)
|
||||
private _cumulativeCost = 0;
|
||||
private _cumulativeInputTokens = 0;
|
||||
private _cumulativeOutputTokens = 0;
|
||||
private _cumulativeToolCalls = 0;
|
||||
|
||||
// Bash execution state
|
||||
private _bashAbortController: AbortController | undefined = undefined;
|
||||
private _pendingBashMessages: BashExecutionMessage[] = [];
|
||||
|
|
@ -438,7 +444,13 @@ export class AgentSession {
|
|||
if (event.message.role === "assistant") {
|
||||
this._lastAssistantMessage = event.message;
|
||||
|
||||
// Accumulate session stats that survive compaction (#1423)
|
||||
const assistantMsg = event.message as AssistantMessage;
|
||||
this._cumulativeCost += assistantMsg.usage?.cost?.total ?? 0;
|
||||
this._cumulativeInputTokens += assistantMsg.usage?.input ?? 0;
|
||||
this._cumulativeOutputTokens += assistantMsg.usage?.output ?? 0;
|
||||
this._cumulativeToolCalls += assistantMsg.content.filter((c) => c.type === "toolCall").length;
|
||||
|
||||
if (assistantMsg.stopReason !== "error") {
|
||||
this._overflowRecoveryAttempted = false;
|
||||
}
|
||||
|
|
@ -3230,17 +3242,17 @@ export class AgentSession {
|
|||
sessionId: this.sessionId,
|
||||
userMessages,
|
||||
assistantMessages,
|
||||
toolCalls,
|
||||
toolCalls: Math.max(toolCalls, this._cumulativeToolCalls),
|
||||
toolResults,
|
||||
totalMessages: state.messages.length,
|
||||
tokens: {
|
||||
input: totalInput,
|
||||
output: totalOutput,
|
||||
input: Math.max(totalInput, this._cumulativeInputTokens),
|
||||
output: Math.max(totalOutput, this._cumulativeOutputTokens),
|
||||
cacheRead: totalCacheRead,
|
||||
cacheWrite: totalCacheWrite,
|
||||
total: totalInput + totalOutput + totalCacheRead + totalCacheWrite,
|
||||
total: Math.max(totalInput + totalOutput, this._cumulativeInputTokens + this._cumulativeOutputTokens) + totalCacheRead + totalCacheWrite,
|
||||
},
|
||||
cost: totalCost,
|
||||
cost: Math.max(totalCost, this._cumulativeCost),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,10 +54,11 @@ test("settings.json change emits settings-changed event", async () => {
|
|||
const bus = createMockEventBus();
|
||||
|
||||
await startFileWatcher(dir, bus);
|
||||
await delay(200);
|
||||
|
||||
writeFileSync(join(dir, "settings.json"), JSON.stringify({ updated: true }));
|
||||
// Wait for debounce (300ms) + filesystem propagation
|
||||
await delay(600);
|
||||
await delay(800);
|
||||
|
||||
const matched = bus.events.filter((e) => e.channel === "settings-changed");
|
||||
assert.ok(matched.length > 0, "should emit settings-changed event");
|
||||
|
|
@ -68,9 +69,10 @@ test("auth.json change emits auth-changed event", async () => {
|
|||
const bus = createMockEventBus();
|
||||
|
||||
await startFileWatcher(dir, bus);
|
||||
await delay(200);
|
||||
|
||||
writeFileSync(join(dir, "auth.json"), JSON.stringify({ token: "new" }));
|
||||
await delay(600);
|
||||
await delay(800);
|
||||
|
||||
const matched = bus.events.filter((e) => e.channel === "auth-changed");
|
||||
assert.ok(matched.length > 0, "should emit auth-changed event");
|
||||
|
|
@ -81,9 +83,10 @@ test("models.json change emits models-changed event", async () => {
|
|||
const bus = createMockEventBus();
|
||||
|
||||
await startFileWatcher(dir, bus);
|
||||
await delay(200);
|
||||
|
||||
writeFileSync(join(dir, "models.json"), JSON.stringify({ model: "new" }));
|
||||
await delay(600);
|
||||
await delay(800);
|
||||
|
||||
const matched = bus.events.filter((e) => e.channel === "models-changed");
|
||||
assert.ok(matched.length > 0, "should emit models-changed event");
|
||||
|
|
@ -133,7 +136,7 @@ test("debouncing coalesces rapid changes into one event", async () => {
|
|||
for (let i = 0; i < 5; i++) {
|
||||
writeFileSync(join(dir, "settings.json"), JSON.stringify({ i }));
|
||||
}
|
||||
await delay(600);
|
||||
await delay(800);
|
||||
|
||||
const matched = bus.events.filter((e) => e.channel === "settings-changed");
|
||||
assert.strictEqual(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue