createBashTool function
Builds the tool that runs shell commands in the workspace.
Implementation
Tool<JsonMap, String> createBashTool(
Genkit ai, {
required ToolRuntime runtime,
}) {
return defineTextTool(
ai,
runtime: runtime,
name: 'bash',
description: _description,
properties: <String, Object?>{
'command': stringProperty('The command to execute.'),
'description': stringProperty(
'A short (5-10 word) description of what the command does, shown to the user. '
'For example: "Run unit tests", "Show working tree status".',
),
'workdir': stringProperty('Directory to run in. Defaults to the workspace root.'),
'timeout_ms': integerProperty('Timeout in milliseconds (max $_maxTimeoutMs). Defaults to $_defaultTimeoutMs.'),
},
required: <String>['command'],
run: (input) async {
final command = requireString(input, 'command').trim();
final description = readString(input, 'description')?.trim();
final workdirInput = readString(input, 'workdir');
final timeoutMs = (readInt(input, 'timeout_ms') ?? _defaultTimeoutMs).clamp(1, _maxTimeoutMs);
final workdir = workdirInput == null ? runtime.currentWorkingDirectory : runtime.resolvePath(workdirInput);
if (!runtime.isWithinWorkspace(workdir)) {
throw ToolFailure('`workdir` must be inside the workspace ${runtime.workspaceRoot}.');
}
if (!await Directory(workdir).exists()) {
throw ToolFailure('`workdir` does not exist: $workdir');
}
final assessment = assessBashCommand(command);
if (assessment.requiresApproval) {
final approved = await runtime.requestApproval(
ToolApprovalRequest(
toolName: 'bash',
reason: assessment.reason ?? 'This command requires approval.',
command: command,
),
);
if (!approved) {
throw const ToolFailure(
'The user declined to run this command. Do not retry it; adjust your approach or ask the user.',
);
}
}
final label = description == null || description.isEmpty ? command : '$description: $command';
runtime.startTool('bash', label);
return _runCommand(command: command, workdir: workdir, timeoutMs: timeoutMs);
},
);
}