createBashTool function

Tool<JsonMap, String> createBashTool(
  1. Genkit ai, {
  2. required ToolRuntime runtime,
})

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);
    },
  );
}