( messages: Message[], context: ToolUseContext, customInstructions: string, reactive: NonNullable<typeof reactiveCompact>, )
| 137 | } |
| 138 | |
| 139 | async function compactViaReactive( |
| 140 | messages: Message[], |
| 141 | context: ToolUseContext, |
| 142 | customInstructions: string, |
| 143 | reactive: NonNullable<typeof reactiveCompact>, |
| 144 | ): Promise<{ |
| 145 | type: 'compact' |
| 146 | compactionResult: CompactionResult |
| 147 | displayText: string |
| 148 | }> { |
| 149 | context.onCompactProgress?.({ |
| 150 | type: 'hooks_start', |
| 151 | hookType: 'pre_compact', |
| 152 | }) |
| 153 | context.setSDKStatus?.('compacting') |
| 154 | |
| 155 | try { |
| 156 | // Hooks and cache-param build are independent — run concurrently. |
| 157 | // getCacheSharingParams walks all tools to build the system prompt; |
| 158 | // pre-compact hooks spawn subprocesses. Neither depends on the other. |
| 159 | const [hookResult, cacheSafeParams] = await Promise.all([ |
| 160 | executePreCompactHooks( |
| 161 | { trigger: 'manual', customInstructions: customInstructions || null }, |
| 162 | context.abortController.signal, |
| 163 | ), |
| 164 | getCacheSharingParams(context, messages), |
| 165 | ]) |
| 166 | const mergedInstructions = mergeHookInstructions( |
| 167 | customInstructions, |
| 168 | hookResult.newCustomInstructions, |
| 169 | ) |
| 170 | |
| 171 | context.setStreamMode?.('requesting') |
| 172 | context.setResponseLength?.(() => 0) |
| 173 | context.onCompactProgress?.({ type: 'compact_start' }) |
| 174 | |
| 175 | const outcome = await reactive.reactiveCompactOnPromptTooLong( |
| 176 | messages, |
| 177 | cacheSafeParams, |
| 178 | { customInstructions: mergedInstructions, trigger: 'manual' }, |
| 179 | ) |
| 180 | |
| 181 | if (!outcome.ok) { |
| 182 | // The outer catch in `call` translates these: aborted → "Compaction |
| 183 | // canceled." (via abortController.signal.aborted check), NOT_ENOUGH → |
| 184 | // re-thrown as-is, everything else → "Error during compaction: …". |
| 185 | switch (outcome.reason) { |
| 186 | case 'too_few_groups': |
| 187 | throw new Error(ERROR_MESSAGE_NOT_ENOUGH_MESSAGES) |
| 188 | case 'aborted': |
| 189 | throw new Error(ERROR_MESSAGE_USER_ABORT) |
| 190 | case 'exhausted': |
| 191 | case 'error': |
| 192 | case 'media_unstrippable': |
| 193 | throw new Error(ERROR_MESSAGE_INCOMPLETE_RESPONSE) |
| 194 | } |
| 195 | } |
| 196 |
no test coverage detected