fix(ai): require OpenAI Responses terminal events

This commit is contained in:
Mario Zechner
2026-06-23 16:35:45 +02:00
parent 2285f87964
commit cd95c2749f
12 changed files with 378 additions and 39 deletions
@@ -1874,10 +1874,12 @@ export class AgentSession {
}
// Case 2: Threshold - context is getting large
// For error messages (no usage data), estimate from last successful response.
// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.
// For error messages or all-zero usage messages, estimate from the last valid response.
// This ensures sessions that hit persistent API errors (e.g. 529) or malformed zero-usage
// responses can still compact and do not reset context accounting.
let contextTokens: number;
if (assistantMessage.stopReason === "error") {
const directContextTokens = assistantMessage.usage ? calculateContextTokens(assistantMessage.usage) : 0;
if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
const messages = this.agent.state.messages;
const estimate = estimateContextTokens(messages);
if (estimate.lastUsageIndex === null) return false; // No usage data at all
@@ -1894,7 +1896,7 @@ export class AgentSession {
}
contextTokens = estimate.tokens;
} else {
contextTokens = calculateContextTokens(assistantMessage.usage);
contextTokens = directContextTokens;
}
if (shouldCompact(contextTokens, contextWindow, settings)) {
return await this._runAutoCompaction("threshold", false);
@@ -3011,8 +3013,8 @@ export class AgentSession {
const contextTokens = calculateContextTokens(assistant.usage);
if (contextTokens > 0) {
hasPostCompactionUsage = true;
break;
}
break;
}
}
}
@@ -139,12 +139,17 @@ export function calculateContextTokens(usage: Usage): number {
/**
* Get usage from an assistant message if available.
* Skips aborted and error messages as they don't have valid usage data.
* Skips aborted, error, and all-zero usage messages as they don't have valid usage data.
*/
function getAssistantUsage(msg: AgentMessage): Usage | undefined {
if (msg.role === "assistant" && "usage" in msg) {
const assistantMsg = msg as AssistantMessage;
if (assistantMsg.stopReason !== "aborted" && assistantMsg.stopReason !== "error" && assistantMsg.usage) {
if (
assistantMsg.stopReason !== "aborted" &&
assistantMsg.stopReason !== "error" &&
assistantMsg.usage &&
calculateContextTokens(assistantMsg.usage) > 0
) {
return assistantMsg.usage;
}
}
@@ -152,7 +157,7 @@ function getAssistantUsage(msg: AgentMessage): Usage | undefined {
}
/**
* Find the last non-aborted assistant message usage from session entries.
* Find the last valid assistant message usage from session entries.
*/
export function getLastAssistantUsage(entries: SessionEntry[]): Usage | undefined {
for (let i = entries.length - 1; i >= 0; i--) {