adjustIndexToPreserveAPIInvariants function

int adjustIndexToPreserveAPIInvariants(
  1. List<CompactMessage> messages,
  2. int startIndex
)

Adjust the start index to ensure we don't split tool_use/tool_result pairs or thinking blocks that share the same message.id with kept assistant messages.

Implementation

int adjustIndexToPreserveAPIInvariants(
  List<CompactMessage> messages,
  int startIndex,
) {
  if (startIndex <= 0 || startIndex >= messages.length) return startIndex;

  int adjustedIndex = startIndex;

  // Step 1: Handle tool_use/tool_result pairs
  final allToolResultIds = <String>[];
  for (int i = startIndex; i < messages.length; i++) {
    allToolResultIds.addAll(_getToolResultIds(messages[i]));
  }

  if (allToolResultIds.isNotEmpty) {
    final toolUseIdsInKeptRange = <String>{};
    for (int i = adjustedIndex; i < messages.length; i++) {
      final msg = messages[i];
      if (msg.type == MessageRole.assistant) {
        for (final block in msg.contentBlocks) {
          if (block.type == ContentBlockType.toolUse && block.id != null) {
            toolUseIdsInKeptRange.add(block.id!);
          }
        }
      }
    }

    final neededToolUseIds = <String>{
      ...allToolResultIds.where((id) => !toolUseIdsInKeptRange.contains(id)),
    };

    for (
      int i = adjustedIndex - 1;
      i >= 0 && neededToolUseIds.isNotEmpty;
      i--
    ) {
      final message = messages[i];
      if (_hasToolUseWithIds(message, neededToolUseIds)) {
        adjustedIndex = i;
        if (message.type == MessageRole.assistant) {
          for (final block in message.contentBlocks) {
            if (block.type == ContentBlockType.toolUse &&
                block.id != null &&
                neededToolUseIds.contains(block.id)) {
              neededToolUseIds.remove(block.id);
            }
          }
        }
      }
    }
  }

  // Step 2: Handle thinking blocks that share message.id
  final messageIdsInKeptRange = <String>{};
  for (int i = adjustedIndex; i < messages.length; i++) {
    final msg = messages[i];
    if (msg.type == MessageRole.assistant && msg.messageId != null) {
      messageIdsInKeptRange.add(msg.messageId!);
    }
  }

  for (int i = adjustedIndex - 1; i >= 0; i--) {
    final message = messages[i];
    if (message.type == MessageRole.assistant &&
        message.messageId != null &&
        messageIdsInKeptRange.contains(message.messageId)) {
      adjustedIndex = i;
    }
  }

  return adjustedIndex;
}