runTools function
Stream<MessageUpdate>
runTools(
- List<
ToolUseBlock> toolUseMessages, - List<
AssistantMessage> assistantMessages, - CanUseToolFn canUseTool,
- ToolUseContext toolUseContext,
Run tools — handles both serial and concurrent execution.
Implementation
Stream<MessageUpdate> runTools(
List<ToolUseBlock> toolUseMessages,
List<AssistantMessage> assistantMessages,
CanUseToolFn canUseTool,
ToolUseContext toolUseContext,
) async* {
var currentContext = toolUseContext;
for (final batch in partitionToolCalls(toolUseMessages, currentContext)) {
if (batch.isConcurrencySafe) {
// Run concurrency-safe batch in parallel
final futures = <Future<List<MessageUpdate>>>[];
for (final toolUse in batch.blocks) {
currentContext.setInProgressToolUseIDs?.call(
(prev) => {...prev, toolUse.id},
);
final assistantMsg = assistantMessages.firstWhere(
(a) => a.content.any(
(c) => c is Map && c['type'] == 'tool_use' && c['id'] == toolUse.id,
),
orElse: () => assistantMessages.first,
);
futures.add(
runToolUse(
toolUse,
assistantMsg,
canUseTool,
currentContext,
).toList(),
);
}
final results = await Future.wait(futures);
for (final updates in results) {
for (final update in updates) {
yield MessageUpdate(
message: update.message,
newContext: currentContext,
);
}
}
// Mark all as complete
for (final toolUse in batch.blocks) {
_markToolUseAsComplete(currentContext, toolUse.id);
}
} else {
// Run non-concurrency-safe batch serially
for (final toolUse in batch.blocks) {
currentContext.setInProgressToolUseIDs?.call(
(prev) => {...prev, toolUse.id},
);
final assistantMsg = assistantMessages.firstWhere(
(a) => a.content.any(
(c) => c is Map && c['type'] == 'tool_use' && c['id'] == toolUse.id,
),
orElse: () => assistantMessages.first,
);
await for (final update in runToolUse(
toolUse,
assistantMsg,
canUseTool,
currentContext,
)) {
if (update.contextModifier != null) {
currentContext = update.contextModifier!.modifyContext(
currentContext,
);
}
yield MessageUpdate(
message: update.message,
newContext: currentContext,
);
}
_markToolUseAsComplete(currentContext, toolUse.id);
}
}
}
}