( allMessages: Message[], pivotIndex: number, context: ToolUseContext, cacheSafeParams: CacheSafeParams, userFeedback?: string, direction: PartialCompactDirection = 'from', )
| 799 | * Prompt cache is invalidated since the summary precedes the kept messages. |
| 800 | */ |
| 801 | export async function partialCompactConversation( |
| 802 | allMessages: Message[], |
| 803 | pivotIndex: number, |
| 804 | context: ToolUseContext, |
| 805 | cacheSafeParams: CacheSafeParams, |
| 806 | userFeedback?: string, |
| 807 | direction: PartialCompactDirection = 'from', |
| 808 | ): Promise<CompactionResult> { |
| 809 | try { |
| 810 | const messagesToSummarize = |
| 811 | direction === 'up_to' |
| 812 | ? allMessages.slice(0, pivotIndex) |
| 813 | : allMessages.slice(pivotIndex) |
| 814 | // 'up_to' must strip old compact boundaries/summaries: for 'up_to', |
| 815 | // summary_B sits BEFORE kept, so a stale boundary_A in kept wins |
| 816 | // findLastCompactBoundaryIndex's backward scan and drops summary_B. |
| 817 | // 'from' keeps them: summary_B sits AFTER kept (backward scan still |
| 818 | // works), and removing an old summary would lose its covered history. |
| 819 | const messagesToKeep = |
| 820 | direction === 'up_to' |
| 821 | ? allMessages |
| 822 | .slice(pivotIndex) |
| 823 | .filter( |
| 824 | m => |
| 825 | m.type !== 'progress' && |
| 826 | !isCompactBoundaryMessage(m) && |
| 827 | !(m.type === 'user' && m.isCompactSummary), |
| 828 | ) |
| 829 | : allMessages.slice(0, pivotIndex).filter(m => m.type !== 'progress') |
| 830 | |
| 831 | if (messagesToSummarize.length === 0) { |
| 832 | throw new Error( |
| 833 | direction === 'up_to' |
| 834 | ? 'Nothing to summarize before the selected message.' |
| 835 | : 'Nothing to summarize after the selected message.', |
| 836 | ) |
| 837 | } |
| 838 | |
| 839 | const preCompactTokenCount = tokenCountWithEstimation(allMessages) |
| 840 | |
| 841 | context.onCompactProgress?.({ |
| 842 | type: 'hooks_start', |
| 843 | hookType: 'pre_compact', |
| 844 | }) |
| 845 | |
| 846 | context.setSDKStatus?.('compacting') |
| 847 | const hookResult = await executePreCompactHooks( |
| 848 | { |
| 849 | trigger: 'manual', |
| 850 | customInstructions: null, |
| 851 | }, |
| 852 | context.abortController.signal, |
| 853 | ) |
| 854 | |
| 855 | // Merge hook instructions with user feedback |
| 856 | let customInstructions: string | undefined |
| 857 | if (hookResult.newCustomInstructions && userFeedback) { |
| 858 | customInstructions = `${hookResult.newCustomInstructions}\n\nUser context: ${userFeedback}` |
no test coverage detected