e99e638e45
Retry compaction recovery when model or tool state is still incomplete, and treat reasoning or tool-only assistant progress as valid output so no-text tail recovery does not misfire.
53 lines
1.2 KiB
TypeScript
53 lines
1.2 KiB
TypeScript
const MEANINGFUL_ASSISTANT_PART_TYPES = new Set([
|
|
"reasoning",
|
|
"tool",
|
|
"tool_use",
|
|
])
|
|
|
|
export type TailMonitorState = {
|
|
currentMessageID?: string
|
|
currentHasOutput: boolean
|
|
consecutiveNoTextMessages: number
|
|
lastCompactedAt?: number
|
|
lastRecoveryAt?: number
|
|
}
|
|
|
|
export function finalizeTrackedAssistantMessage(
|
|
state: TailMonitorState,
|
|
): number {
|
|
if (!state.currentMessageID) {
|
|
return state.consecutiveNoTextMessages
|
|
}
|
|
|
|
state.consecutiveNoTextMessages = state.currentHasOutput
|
|
? 0
|
|
: state.consecutiveNoTextMessages + 1
|
|
state.currentMessageID = undefined
|
|
state.currentHasOutput = false
|
|
|
|
return state.consecutiveNoTextMessages
|
|
}
|
|
|
|
export function shouldTreatAssistantPartAsOutput(part: {
|
|
type?: string
|
|
text?: string
|
|
}): boolean {
|
|
if (part.type === "text") {
|
|
return !!part.text?.trim()
|
|
}
|
|
|
|
return typeof part.type === "string" && MEANINGFUL_ASSISTANT_PART_TYPES.has(part.type)
|
|
}
|
|
|
|
export function trackAssistantOutput(
|
|
state: TailMonitorState,
|
|
messageID?: string,
|
|
): void {
|
|
if (messageID && !state.currentMessageID) {
|
|
state.currentMessageID = messageID
|
|
}
|
|
|
|
state.currentHasOutput = true
|
|
state.consecutiveNoTextMessages = 0
|
|
}
|