sendMessage method
Sends message to the model as a continuation of the chat history.
Prepends the history to the request and uses the provided model to generate new content.
When there are no candidates in the response, the message and response
are ignored and will not be recorded in the history.
Waits for any ongoing or pending requests to sendMessage or sendMessageStream to complete before generating new content. Successful messages and responses for ongoing or pending requests will be reflected in the history sent for this message.
Implementation
Future<GenerateContentResponse> sendMessage(Content message) async {
final lock = await _mutex.acquire();
try {
final requestHistory = <Content>[message];
var turn = 0;
while (turn < _maxTurns) {
final response = await _generateContent(
_history.followedBy(requestHistory),
safetySettings: _safetySettings,
generationConfig: _generationConfig);
final functionCalls = response.functionCalls;
// Only trigger auto-execution if:
// 1. We have auto-functions configured.
// 2. The response actually contains function calls.
// 3. ALL called functions exist in our declarations (prevents crashes).
final shouldAutoExecute = _autoFunctionDeclarations != null &&
_autoFunctionDeclarations.isNotEmpty &&
functionCalls.isNotEmpty &&
functionCalls
.every((c) => _autoFunctionDeclarations.containsKey(c.name));
if (!shouldAutoExecute) {
// Standard handling: Update history and return the response to the user.
if (response.candidates case [final candidate, ...]) {
_history.addAll(requestHistory);
final normalizedContent = candidate.content.role == null
? Content('model', candidate.content.parts)
: candidate.content;
_history.add(normalizedContent);
}
return response;
}
// Auto function execution
requestHistory.add(response.candidates.first.content);
final functionResponses = <Part>[];
for (final functionCall in functionCalls) {
final function = _autoFunctionDeclarations[functionCall.name];
Object? result;
try {
result = await function!.callable(functionCall.args);
} catch (e) {
result = e.toString();
}
functionResponses
.add(FunctionResponse(functionCall.name, {'result': result}));
}
requestHistory.add(Content('function', functionResponses));
turn++;
}
throw Exception('Max turns of $_maxTurns reached.');
} finally {
lock.release();
}
}