generateWithTools static method
Generate text with tool calling support.
This is the main entry point for tool-enabled generation. Handles the full tool calling loop:
- Format tools into system prompt
- Generate LLM response
- Parse tool calls from output
- Execute tools (if autoExecute is true)
- Continue generation with tool results
- Repeat until no more tool calls or max iterations reached
prompt User's question or request
options Tool calling options (optional)
Example:
final result = await RunAnywhereTools.generateWithTools(
'What is the weather in San Francisco?',
);
print(result.text); // "The weather in San Francisco is 72°F and Sunny."
print(result.toolCalls); // [ToolCall(name: 'get_weather', ...)]
Implementation
static Future<ToolCallingResult> generateWithTools(
String prompt, {
ToolCallingOptions? options,
}) async {
final opts = options ?? const ToolCallingOptions();
final tools = opts.tools ?? getRegisteredTools();
final formatName = opts.formatName;
if (tools.isEmpty) {
// No tools - just do regular generation
final result = await RunAnywhere.generate(prompt);
return ToolCallingResult(
text: result.text,
toolCalls: [],
toolResults: [],
isComplete: true,
);
}
// Build tools JSON
final toolsJson = toolsToJson(tools);
_logger.debug('Tools JSON: $toolsJson');
_logger.debug('Using tool call format: $formatName');
// Build initial prompt with tools using the specified format
final toolsPrompt = DartBridgeToolCalling.shared.formatToolsPromptWithFormat(
toolsJson,
formatName,
);
// Build the full prompt with system instructions and user query
final formattedPrompt = '$toolsPrompt\n\nUser: $prompt';
_logger.debug('Formatted prompt: ${formattedPrompt.substring(0, formattedPrompt.length.clamp(0, 200))}...');
// Track all tool calls and results
final allToolCalls = <ToolCall>[];
final allToolResults = <ToolResult>[];
var currentPrompt = formattedPrompt;
var iterations = 0;
final maxIterations = opts.maxToolCalls;
while (iterations < maxIterations) {
iterations++;
// Lower temperature for more consistent tool calling behavior
final genOptions = LLMGenerationOptions(
maxTokens: opts.maxTokens ?? 1024,
temperature: opts.temperature ?? 0.3,
);
// Use streaming like Swift does, then collect all tokens
final streamResult = await RunAnywhere.generateStream(currentPrompt, options: genOptions);
final buffer = StringBuffer();
await for (final token in streamResult.stream) {
buffer.write(token);
}
final responseText = buffer.toString();
_logger.debug('LLM output (iter $iterations): ${responseText.substring(0, responseText.length.clamp(0, 200))}...');
// Parse for tool calls using C++ bridge (auto-detection like Swift)
final parseResult = DartBridgeToolCalling.shared.parseToolCall(responseText);
if (!parseResult.hasToolCall || parseResult.toolName == null) {
// No tool call - return final result
return ToolCallingResult(
text: parseResult.cleanText,
toolCalls: allToolCalls,
toolResults: allToolResults,
isComplete: true,
);
}
// Create tool call
final toolCall = ToolCall(
toolName: parseResult.toolName!,
arguments: parseResult.arguments != null
? dynamicMapToToolValueMap(parseResult.arguments!)
: {},
callId: parseResult.callId.toString(),
);
allToolCalls.add(toolCall);
_logger.info('Tool call detected: ${toolCall.toolName}');
if (!opts.autoExecute) {
// Return for manual execution
return ToolCallingResult(
text: parseResult.cleanText,
toolCalls: allToolCalls,
toolResults: allToolResults,
isComplete: false,
);
}
// Execute the tool
final toolResult = await executeTool(toolCall);
allToolResults.add(toolResult);
// Build follow-up prompt with tool result
final resultJson = toolResult.result != null
? toolResultToJsonString(toolResult.result!)
: '{"error": "${toolResult.error ?? 'Unknown error'}"}';
currentPrompt = DartBridgeToolCalling.shared.buildFollowupPrompt(
originalPrompt: prompt,
toolsPrompt: opts.keepToolsAvailable
? DartBridgeToolCalling.shared.formatToolsPrompt(toolsJson)
: null,
toolName: toolCall.toolName,
toolResultJson: resultJson,
keepToolsAvailable: opts.keepToolsAvailable,
);
_logger.debug('Follow-up prompt: ${currentPrompt.substring(0, currentPrompt.length.clamp(0, 200))}...');
}
// Max iterations reached - return what we have
_logger.warning('Max tool call iterations ($maxIterations) reached');
return ToolCallingResult(
text: '',
toolCalls: allToolCalls,
toolResults: allToolResults,
isComplete: true,
);
}