( messages: Message[], ptlResponse: AssistantMessage, )
| 241 | * that wasn't migrated in bfdb472f's unification. |
| 242 | */ |
| 243 | export function truncateHeadForPTLRetry( |
| 244 | messages: Message[], |
| 245 | ptlResponse: AssistantMessage, |
| 246 | ): Message[] | null { |
| 247 | // Strip our own synthetic marker from a previous retry before grouping. |
| 248 | // Otherwise it becomes its own group 0 and the 20% fallback stalls |
| 249 | // (drops only the marker, re-adds it, zero progress on retry 2+). |
| 250 | const input = |
| 251 | messages[0]?.type === 'user' && |
| 252 | messages[0].isMeta && |
| 253 | messages[0].message.content === PTL_RETRY_MARKER |
| 254 | ? messages.slice(1) |
| 255 | : messages |
| 256 | |
| 257 | const groups = groupMessagesByApiRound(input) |
| 258 | if (groups.length < 2) return null |
| 259 | |
| 260 | const tokenGap = getPromptTooLongTokenGap(ptlResponse) |
| 261 | let dropCount: number |
| 262 | if (tokenGap !== undefined) { |
| 263 | let acc = 0 |
| 264 | dropCount = 0 |
| 265 | for (const g of groups) { |
| 266 | acc += roughTokenCountEstimationForMessages(g) |
| 267 | dropCount++ |
| 268 | if (acc >= tokenGap) break |
| 269 | } |
| 270 | } else { |
| 271 | dropCount = Math.max(1, Math.floor(groups.length * 0.2)) |
| 272 | } |
| 273 | |
| 274 | // Keep at least one group so there's something to summarize. |
| 275 | dropCount = Math.min(dropCount, groups.length - 1) |
| 276 | if (dropCount < 1) return null |
| 277 | |
| 278 | const sliced = groups.slice(dropCount).flat() |
| 279 | // groupMessagesByApiRound puts the preamble in group 0 and starts every |
| 280 | // subsequent group with an assistant message. Dropping group 0 leaves an |
| 281 | // assistant-first sequence which the API rejects (first message must be |
| 282 | // role=user). Prepend a synthetic user marker — ensureToolResultPairing |
| 283 | // already handles any orphaned tool_results this creates. |
| 284 | if (sliced[0]?.type === 'assistant') { |
| 285 | return [ |
| 286 | createUserMessage({ content: PTL_RETRY_MARKER, isMeta: true }), |
| 287 | ...sliced, |
| 288 | ] |
| 289 | } |
| 290 | return sliced |
| 291 | } |
| 292 | |
| 293 | export const ERROR_MESSAGE_PROMPT_TOO_LONG = |
| 294 | 'Conversation too long. Press esc twice to go up a few messages and try again.' |
no test coverage detected