runToolUse function
Stream<MessageUpdate>
runToolUse(
- ToolUseBlock toolUse,
- AssistantMessage assistantMessage,
- CanUseToolFn canUseTool,
- ToolUseContext toolUseContext,
Run a single tool use block — checks permissions and executes the tool.
Implementation
Stream<MessageUpdate> runToolUse(
ToolUseBlock toolUse,
AssistantMessage assistantMessage,
CanUseToolFn canUseTool,
ToolUseContext toolUseContext,
) async* {
final toolName = toolUse.name;
// First try available tools
var tool = findToolByName(toolUseContext.tools, toolName);
// Fallback for deprecated aliases
if (tool == null) {
// Would search all base tools — simplified for port
}
if (tool == null) {
yield MessageUpdate(
message: ToolMessage(
type: 'user',
toolResults: [
ToolResultBlock(
toolUseId: toolUse.id,
content:
'<tool_use_error>Error: No such tool available: $toolName</tool_use_error>',
isError: true,
),
],
toolUseResult: 'Error: No such tool available: $toolName',
sourceToolAssistantUUID: assistantMessage.uuid,
),
);
return;
}
if (toolUseContext.abortController.isAborted) {
yield MessageUpdate(
message: ToolMessage(
type: 'user',
toolResults: [
ToolResultBlock(toolUseId: toolUse.id, content: cancelMessage),
],
toolUseResult: cancelMessage,
sourceToolAssistantUUID: assistantMessage.uuid,
),
);
return;
}
try {
// Check permissions
final permissionResult = await canUseTool(
tool,
toolUse.input,
toolUseContext,
assistantMessage,
toolUse.id,
);
if (permissionResult.behavior == PermissionBehavior.deny) {
yield MessageUpdate(
message: ToolMessage(
type: 'user',
toolResults: [
ToolResultBlock(
toolUseId: toolUse.id,
content: permissionResult.message ?? rejectMessage,
isError: true,
),
],
toolUseResult: permissionResult.message ?? rejectMessage,
sourceToolAssistantUUID: assistantMessage.uuid,
),
);
return;
}
// Execute the tool
final effectiveInput = permissionResult.updatedInput ?? toolUse.input;
final result = await tool.execute(effectiveInput, toolUseContext);
yield MessageUpdate(message: result);
} catch (error) {
final errorMsg = error is Exception ? error.toString() : '$error';
final detailedError = 'Error calling tool (${tool.name}): $errorMsg';
yield MessageUpdate(
message: ToolMessage(
type: 'user',
toolResults: [
ToolResultBlock(
toolUseId: toolUse.id,
content: '<tool_use_error>$detailedError</tool_use_error>',
isError: true,
),
],
toolUseResult: detailedError,
sourceToolAssistantUUID: assistantMessage.uuid,
),
);
}
}