( messages: Message[], querySource: QuerySource | undefined, )
| 430 | * the same predicate without coupling to the tool-result clearing action. |
| 431 | */ |
| 432 | export function evaluateTimeBasedTrigger( |
| 433 | messages: Message[], |
| 434 | querySource: QuerySource | undefined, |
| 435 | ): { gapMinutes: number; config: TimeBasedMCConfig } | null { |
| 436 | const config = getTimeBasedMCConfig() |
| 437 | // Require an explicit main-thread querySource. isMainThreadSource treats |
| 438 | // undefined as main-thread (for cached-MC backward-compat), but several |
| 439 | // callers (/context, /compact, analyzeContext) invoke microcompactMessages |
| 440 | // without a source for analysis-only purposes — they should not trigger. |
| 441 | if (!config.enabled || !querySource || !isMainThreadSource(querySource)) { |
| 442 | return null |
| 443 | } |
| 444 | const lastAssistant = messages.findLast(m => m.type === 'assistant') |
| 445 | if (!lastAssistant) { |
| 446 | return null |
| 447 | } |
| 448 | const gapMinutes = |
| 449 | (Date.now() - new Date(lastAssistant.timestamp).getTime()) / 60_000 |
| 450 | if (!Number.isFinite(gapMinutes) || gapMinutes < config.gapThresholdMinutes) { |
| 451 | return null |
| 452 | } |
| 453 | return { gapMinutes, config } |
| 454 | } |
| 455 | |
| 456 | function maybeTimeBasedMicrocompact( |
| 457 | messages: Message[], |
no test coverage detected