validateToolPairing function
Validates the pairing invariant on the wire-equivalent sequence of
messages. An empty result means the context is safe to send.
Implementation
List<ToolPairingViolation> validateToolPairing(List<Message> messages) {
final violations = <ToolPairingViolation>[];
final seenCalls = <String>{};
final answered = <String>{};
var pending = const <String>[];
for (final item in _wireView(messages)) {
switch (item) {
case _WireAssistant(:final callIds):
_flagUnanswered(pending, answered, violations);
pending = callIds;
for (final id in callIds) {
if (!seenCalls.add(id)) {
violations.add(
ToolPairingViolation(
ToolPairingViolationKind.duplicateCallId,
id,
'tool_use id appears in more than one assistant message',
),
);
}
}
case _WireUser(:final blocks):
var sawText = false;
for (final (:resultId) in blocks) {
if (resultId == null) {
sawText = true;
continue;
}
if (answered.contains(resultId)) {
violations.add(
ToolPairingViolation(
ToolPairingViolationKind.duplicateResult,
resultId,
'a second tool_result answers the same id',
),
);
} else if (pending.contains(resultId)) {
answered.add(resultId);
if (sawText) {
violations.add(
ToolPairingViolation(
ToolPairingViolationKind.interleavedResult,
resultId,
'tool_result appears after other content in its message',
),
);
}
} else {
violations.add(
ToolPairingViolation(
ToolPairingViolationKind.orphanedResult,
resultId,
'its tool_use is not in the immediately preceding assistant '
'message',
),
);
}
}
_flagUnanswered(pending, answered, violations);
pending = const [];
}
}
_flagUnanswered(pending, answered, violations);
return violations;
}