execute method
Processes a conversation, executing tool calls recursively until done.
conversation The active conversation with messages.
tools Available tools the AI can call.
contextMessages Pre-trimmed messages to send to the provider.
Returns the final AIResponse (one without tool calls).
Implementation
Future<AIResponse> execute({
required Conversation conversation,
required List<AIMessage> contextMessages,
List<AITool>? tools,
int depth = 0,
}) async {
if (depth >= maxIterations) {
throw StateError(
'Tool execution loop exceeded maximum depth of $maxIterations iterations. '
'The model may be stuck in an infinite tool calling cycle.',
);
}
final response = await provider.complete(contextMessages, tools: tools);
if (response.toolCalls != null && response.toolCalls!.isNotEmpty) {
// Record the assistant's tool request
conversation.addMessage(AIMessage.assistant(
response.content,
toolCalls: response.toolCalls,
));
// Execute each requested tool
for (final tc in response.toolCalls!) {
final tool = _findToolByName(tools, tc.name);
String result;
if (tool != null && tool.execute != null) {
try {
result = await tool.execute!(tc.arguments);
} catch (e) {
result = 'Error executing tool: $e';
}
} else {
result =
'Error: Tool ${tc.name} not found or has no execute function.';
}
conversation.addMessage(AIMessage.toolResult(tc.id, result));
}
// Recurse with updated context (caller should re-trim if needed)
final updatedContext = conversation.activeMessages;
return execute(
conversation: conversation,
contextMessages: updatedContext,
tools: tools,
depth: depth + 1,
);
}
// No tool calls — final response
conversation.addMessage(AIMessage.assistant(response.content));
return response;
}