Skip to content

Commit

Permalink
initial version of a sdk issue triage bot (#264)
Browse files Browse the repository at this point in the history
* initial version of a sdk issue triage bot

* update help message, prompts

* adjust prompts and diagnostic stdout output

* Update pkgs/sdk_triage_bot/lib/src/common.dart

Co-authored-by: Moritz <mosum@google.com>

* update the classify method type sig

* regenerate the mono_repo settings

* adjust the format of the github comment

* Update .gitignore

* Apply suggestions from code review

Co-authored-by: Nate Bosch <nbosch@google.com>

* rename 'getIssue' to 'fetchIssue'

* remove extra interfaces

---------

Co-authored-by: Moritz <mosum@google.com>
Co-authored-by: Nate Bosch <nbosch@google.com>
  • Loading branch information
3 people committed Jun 6, 2024
1 parent bc25c0c commit 268b516
Show file tree
Hide file tree
Showing 15 changed files with 975 additions and 13 deletions.
129 changes: 116 additions & 13 deletions .github/workflows/dart.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions pkgs/sdk_triage_bot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# https://dart.dev/guides/libraries/private-files

# Created by `dart pub`
.dart_tool/
pubspec.lock

.env

tool/training.csv
tool/training.jsonl
tool/training.txt
20 changes: 20 additions & 0 deletions pkgs/sdk_triage_bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## What's this?

A LLM based triage automation system for the dart-lang/sdk repo. It processes
new issues filed against the repo and triages them in the same manner that a
human would. This includes:

- re-summarizing the issue for clarity
- assigning the issues to an `area-` label (first line triage)

## Bot trigger and entry-point

TODO: doc

## Overview

TODO: doc

## Tuning

TODO: doc
1 change: 1 addition & 0 deletions pkgs/sdk_triage_bot/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:dart_flutter_team_lints/analysis_options.yaml
83 changes: 83 additions & 0 deletions pkgs/sdk_triage_bot/bin/triage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io' as io;

import 'package:args/args.dart';
import 'package:github/github.dart';
import 'package:http/http.dart' as http;
import 'package:sdk_triage_bot/src/common.dart';
import 'package:sdk_triage_bot/src/gemini.dart';
import 'package:sdk_triage_bot/src/github.dart';
import 'package:sdk_triage_bot/triage.dart';

void main(List<String> arguments) async {
final argParser = ArgParser();
argParser.addFlag('dry-run',
negatable: false,
help: 'Perform triage but don\'t make any actual changes to the issue.');
argParser.addFlag('force',
negatable: false,
help: 'Make changes to the issue even if it already looks triaged.');
argParser.addFlag('help',
abbr: 'h', negatable: false, help: 'Print this usage information.');

final ArgResults results;
try {
results = argParser.parse(arguments);
} on ArgParserException catch (e) {
print(e.message);
print('');
print(usage);
print('');
print(argParser.usage);
io.exit(64);
}

if (results.flag('help') || results.rest.isEmpty) {
print(usage);
print('');
print(argParser.usage);
io.exit(results.flag('help') ? 0 : 64);
}

var issue = results.rest.first;
final dryRun = results.flag('dry-run');
final force = results.flag('force');

// Accept either an issue number or a url (i.e.,
// https://github.com/dart-lang/sdk/issues/55816).
const sdkToken = 'dart-lang/sdk/issues/';
if (issue.contains(sdkToken)) {
issue = issue.substring(issue.indexOf(sdkToken) + sdkToken.length);
}

final client = http.Client();

final github = GitHub(
auth: Authentication.withToken(githubToken),
client: client,
);
final githubService = GithubService(github: github);

final geminiService = GeminiService(
apiKey: geminiKey,
httpClient: client,
);

await triage(
int.parse(issue),
dryRun: dryRun,
force: force,
githubService: githubService,
geminiService: geminiService,
);

client.close();
}

const String usage = '''
A tool to triage issues from https://github.com/dart-lang/sdk.
usage: dart bin/triage.dart [options] <issue>''';
43 changes: 43 additions & 0 deletions pkgs/sdk_triage_bot/lib/src/common.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

String? _envFileTokenOrEnvironment({required String key}) {
final envFile = File('.env');
if (envFile.existsSync()) {
final env = <String, String>{};
for (var line in envFile.readAsLinesSync().map((line) => line.trim())) {
if (line.isEmpty || line.startsWith('#')) continue;
var split = line.indexOf('=');
env[line.substring(0, split).trim()] = line.substring(split + 1).trim();
}
return env[key];
} else {
return Platform.environment[key];
}
}

String get githubToken {
var token = _envFileTokenOrEnvironment(key: 'GITHUB_TOKEN');
if (token == null) {
throw StateError('This tool expects a github access token in the '
'GITHUB_TOKEN environment variable.');
}
return token;
}

String get geminiKey {
var token = _envFileTokenOrEnvironment(key: 'GOOGLE_API_KEY');
if (token == null) {
throw StateError('This tool expects a gemini api key in the '
'GOOGLE_API_KEY environment variable.');
}
return token;
}

/// Don't return more than 4k of text for an issue body.
String trimmedBody(String body) {
return body.length > 4096 ? body = body.substring(0, 4096) : body;
}
Loading

0 comments on commit 268b516

Please sign in to comment.