adjustIndexToPreserveAPIInvariants function
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;
}