truncateHeadForPTLRetry function

List<CompactMessage>? truncateHeadForPTLRetry(
  1. List<CompactMessage> messages,
  2. int? tokenGap
)

Drops the oldest API-round groups from messages until tokenGap is covered. Returns null when nothing can be dropped without leaving an empty summarize set.

Implementation

List<CompactMessage>? truncateHeadForPTLRetry(
  List<CompactMessage> messages,
  int? tokenGap,
) {
  // Strip our own synthetic marker from a previous retry before grouping.
  final input =
      (messages.isNotEmpty &&
          messages.first.type == MessageRole.user &&
          messages.first.isMeta &&
          messages.first.contentBlocks.length == 1 &&
          messages.first.contentBlocks.first.text == _ptlRetryMarker)
      ? messages.sublist(1)
      : messages;

  final groups = groupMessagesByApiRound(input);
  if (groups.length < 2) return null;

  int dropCount;
  if (tokenGap != null) {
    int acc = 0;
    dropCount = 0;
    for (final g in groups) {
      acc += roughTokenCountEstimationForMessages(g);
      dropCount++;
      if (acc >= tokenGap) break;
    }
  } else {
    dropCount = max(1, (groups.length * 0.2).floor());
  }

  // Keep at least one group so there's something to summarize.
  dropCount = min(dropCount, groups.length - 1);
  if (dropCount < 1) return null;

  final sliced = groups.sublist(dropCount).expand((g) => g).toList();

  // Prepend synthetic user marker if first message is assistant.
  if (sliced.isNotEmpty && sliced.first.type == MessageRole.assistant) {
    return [
      CompactMessage(
        uuid: _generateUuid(),
        type: MessageRole.user,
        timestamp: DateTime.now(),
        isMeta: true,
        contentBlocks: [
          const ContentBlock(
            type: ContentBlockType.text,
            text: _ptlRetryMarker,
          ),
        ],
      ),
      ...sliced,
    ];
  }
  return sliced;
}