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,
}) {
  const toolName = 'bash';
  return ai.defineTool(
    name: toolName,
    description: 'Runs a shell command in the current workspace.',
    inputSchema: createJsonObjectSchema(
      description: 'Input for the bash tool.',
      properties: <String, $Schema>{
        'command': $Schema.string(
          description: 'The shell command to execute.',
        ),
        'workdir': $Schema.string(
          description: 'Optional working directory. Defaults to the current workspace directory.',
        ),
        'timeout_ms': $Schema.integer(
          description: 'Optional timeout in milliseconds. Defaults to 30000.',
        ),
      },
      required: <String>['command'],
    ),
    outputSchema: stringOutputSchema,
    fn: (input, _) async {
      final command = readString(input, 'command')?.trim();
      final workdirInput = readString(input, 'workdir')?.trim();
      final timeoutMs = readInt(input, 'timeout_ms') ?? 30000;

      if (command == null || command.isEmpty) {
        const error = 'Error: `command` is required.';
        runtime.endTool(toolName, error);
        return error;
      }

      final workdir = workdirInput == null || workdirInput.isEmpty
          ? runtime.currentWorkingDirectory
          : runtime.resolveDirectory(workdirInput);
      if (!runtime.isWithinWorkspace(workdir)) {
        const error = 'Error: `workdir` must stay inside the workspace.';
        runtime.endTool(toolName, error);
        return error;
      }

      final assessment = assessBashCommand(command);
      if (assessment.requiresApproval) {
        final approved = await runtime.requestApproval(
          ToolApprovalRequest(
            toolName: toolName,
            reason: assessment.reason ?? 'This command requires approval.',
            command: command,
          ),
        );
        if (!approved) {
          const rejected = 'Error: command was not approved by the user.';
          runtime.endTool(toolName, rejected);
          return rejected;
        }
      }

      runtime.startTool(toolName, '$command @ $workdir');
      final output = await _runCommand(
        command: command,
        workdir: workdir,
        timeoutMs: timeoutMs < 1 ? 1 : timeoutMs,
      );
      runtime.endTool(toolName, output);
      return output;
    },
  );
}