|
47 | 47 | * <p><b>Behavior:</b> |
48 | 48 | * <ul> |
49 | 49 | * <li>Only activates when the agent is a {@link ReActAgent}</li> |
50 | | - * <li>Only patches when pending tool calls exist AND user input does not contain |
51 | | - * {@link ToolResultBlock}s (i.e., user is not providing results themselves)</li> |
| 50 | + * <li>Only patches when pending tool calls exist AND user input does not contain any |
| 51 | + * {@link ToolResultBlock} whose ID matches a current pending tool call ID</li> |
| 52 | + * <li>If the input contains {@link ToolResultBlock}s but none of their IDs match the current |
| 53 | + * pending IDs (i.e., stale or unrelated results), a warning is logged and the input is |
| 54 | + * passed through unmodified — {@link ReActAgent}'s {@code doCall} will then reject the |
| 55 | + * invalid IDs with an {@link IllegalStateException}</li> |
52 | 56 | * <li>Generated error results are added to memory as TOOL-role messages</li> |
53 | 57 | * </ul> |
54 | 58 | * |
@@ -107,10 +111,31 @@ private Mono<PreCallEvent> handlePreCall(PreCallEvent event) { |
107 | 111 | return Mono.just(event); |
108 | 112 | } |
109 | 113 |
|
110 | | - boolean userProvidedResults = |
111 | | - inputMessages.stream().anyMatch(m -> m.hasContentBlocks(ToolResultBlock.class)); |
112 | | - if (userProvidedResults) { |
113 | | - return Mono.just(event); |
| 114 | + // Collect all ToolResultBlock IDs present in the input messages |
| 115 | + Set<String> providedResultIds = |
| 116 | + inputMessages.stream() |
| 117 | + .flatMap(m -> m.getContentBlocks(ToolResultBlock.class).stream()) |
| 118 | + .map(ToolResultBlock::getId) |
| 119 | + .collect(Collectors.toSet()); |
| 120 | + |
| 121 | + if (!providedResultIds.isEmpty()) { |
| 122 | + // Check whether any provided ID actually matches a current pending tool call. |
| 123 | + // Only treat input as user-provided results when the IDs are relevant; |
| 124 | + // stale or unrelated IDs should not suppress auto-recovery. |
| 125 | + if (providedResultIds.stream().anyMatch(pendingIds::contains)) { |
| 126 | + // User provided at least one relevant result — skip auto-patch and let |
| 127 | + // doCall's validateAndAddToolResults handle strict ID validation |
| 128 | + return Mono.just(event); |
| 129 | + } |
| 130 | + // Input contains ToolResultBlocks, but none of their IDs match the current |
| 131 | + // pending tool call IDs (stale / unrelated results). Log a warning and |
| 132 | + // proceed with auto-patch; doCall will reject the invalid IDs with |
| 133 | + // an IllegalStateException, which is the correct strict-mode behavior. |
| 134 | + log.warn( |
| 135 | + "Input contains ToolResultBlock(s) with IDs {} that do not match" |
| 136 | + + " pending tool call IDs {}. Proceeding with auto-patch.", |
| 137 | + providedResultIds, |
| 138 | + pendingIds); |
114 | 139 | } |
115 | 140 |
|
116 | 141 | // Auto-patch: generate error tool results for orphaned pending tool calls |
|
0 commit comments