execute method
Execute a tool call manually. Used when autoExecute: false is
passed to generateWithTools.
Mirrors Swift RunAnywhere.executeTool(_:) semantics
(RunAnywhere+ToolCalling.swift:158-203): unknown tools, argument
parse failures, and executor errors all surface as success: false
results — a parse failure must NOT silently execute the tool with
empty arguments, which would make bad model output look like a
successful empty-argument call.
Implementation
Future<ToolResult> execute(ToolCall toolCall) async {
final executor = _toolExecutors[toolCall.name];
if (executor == null) {
return ToolResult(
toolCallId: toolCall.id,
name: toolCall.name,
success: false,
error: 'Tool not found: ${toolCall.name}',
);
}
Map<String, dynamic> args = const {};
if (toolCall.argumentsJson.isNotEmpty) {
try {
final decoded = jsonDecode(toolCall.argumentsJson);
if (decoded is Map<String, dynamic>) {
args = decoded;
} else {
return ToolResult(
toolCallId: toolCall.id,
name: toolCall.name,
success: false,
error:
'Failed to parse tool arguments: expected a JSON object, '
'got ${decoded.runtimeType}',
);
}
} catch (e) {
return ToolResult(
toolCallId: toolCall.id,
name: toolCall.name,
success: false,
error: 'Failed to parse tool arguments: $e',
);
}
}
try {
_logger.debug('Executing tool: ${toolCall.name}');
final result = await executor(args);
_logger.debug('Tool ${toolCall.name} completed successfully');
return ToolResult(
toolCallId: toolCall.id,
name: toolCall.name,
success: true,
resultJson: jsonEncode(result),
);
} catch (e) {
_logger.error('Tool ${toolCall.name} failed: $e');
return ToolResult(
toolCallId: toolCall.id,
name: toolCall.name,
success: false,
error: e.toString(),
);
}
}