From 52b464cba6300465afb768a88a0edf82441368c8 Mon Sep 17 00:00:00 2001 From: prozolic <42107886+prozolic@users.noreply.github.com> Date: Thu, 12 Mar 2026 00:19:21 +0900 Subject: [PATCH 1/2] Update PromptGenerator.SystemPrompt and GeneratePrompt --- src/PRDigest.NET/PromptGenerator.cs | 205 ++++++++++++++++++---------- 1 file changed, 131 insertions(+), 74 deletions(-) diff --git a/src/PRDigest.NET/PromptGenerator.cs b/src/PRDigest.NET/PromptGenerator.cs index af5ff81..c6d5710 100644 --- a/src/PRDigest.NET/PromptGenerator.cs +++ b/src/PRDigest.NET/PromptGenerator.cs @@ -1,122 +1,179 @@ -using System.Runtime.CompilerServices; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; namespace PRDigest.NET; -internal static class PromptGenerator +internal static partial class PromptGenerator { private const int MaxFileCount = 30; public const string SystemPrompt = """ あなたは.NET開発者向けのPull Request要約アシスタントです。 - 以下の形式で要約を出力してください: + 提供された情報のみに基づいて要約してください。 + 提供されていない情報の推測・補完は行わないでください。 - ================================= - 出力形式: - + ## 出力形式 + .NET開発者にとって有益な情報を含める形で、最大1000文字までで要約してください。 + 以下の出力フォーマット(概要、変更内容、パフォーマンスへの影響、関連Issue、その他)に遵守して、markdown形式で出力してください。 + タイトルは不要です。 + + ## 要約ガイドライン + 要約を作成する際は、以下の点に特に注意を払ってください: + - 変更の主な意図と技術的ポイントを記述してください(ファイル一覧の再掲は不要) + - 変更がランタイム/コンパイラ/ライブラリのどの部分に影響するか、公開APIか内部実装かを区別してください + - 互換性への影響(破壊的変更、非推奨化など)があれば明記してください + - セキュリティ脆弱性修正の場合はその重要度とCVE番号(あれば)を明記する + - バグ修正の場合は修正前の問題と修正後の動作を対比する + - パフォーマンス改善の場合は改善率や具体的な数値を記載する + - 全体を簡潔にまとめ、必要最低限の情報に絞ること + + ## 出力フォーマット #### 概要 - 1行から5行ぐらいで簡潔に記述してください。 - またサンプルコードなどもあれば記載してください。 - + 変更の目的と内容を1〜5行で簡潔に記述してください。 + またサンプルコードが存在する場合のみ記載してください。 + #### 変更内容 変更されたファイルと主な変更内容をリストアップしてください。 - + #### パフォーマンスへの影響 - パフォーマンスに関連する変更があれば具体的に記載してください。(なければ"影響なし") + パフォーマンス(メモリ・実行速度・スループット)に関連する変更があれば具体的に記載してください。(なければ"影響なし") + ベンチマーク結果があれば含めてください。 改善点や懸念点を明記してください。 - + #### 関連Issue - 関連するIssueあれば記載してください。(なければ"なし") - + 関連するIssueがなければ「なし」と記載してください。 + 関連するIssueがある場合は記載以下のルールに従って記載してください。 + dotnet/runtimeのIssueの場合、[#12345](https://github.com/dotnet/runtime/issues/12345)の形で記載してください。 + それ以外のリポジトリのIssueの場合は、リポジトリ名とIssue番号を記載してください。 + #### その他 - それ以外に記載した方が良い特記事項があれば記載してください。(なければ"なし") + 上記以外の特記事項があれば記載してください。 + C#のコードサンプルを示す場合は ```csharp ブロックを必ず使用してください。 + なければ「なし」。 + """; - #### サンプルコードを記載時の注意点 - C#のコードブロックを使用してください: - ```csharp - // ソースコードを記載 - ``` - ================================= + private static ReadOnlySpan EmptyReviewComment => new string[] + { + "generated no new comments", + "generated no comments", + "no new comments", + "Copilot encountered an error and was unable to review this pull request" + }; - .NET開発者にとって有益な情報を含める形で、最大1000文字までで要約してください。 - タイトルは不要です。markdown形式で出力してください。 + private static readonly SearchValues searchValues = SearchValues.Create(EmptyReviewComment, StringComparison.Ordinal); - 【追加の詳細ガイドライン】 - 要約を作成する際は、以下の点に特に注意を払ってください: + [GeneratedRegex(@"^\s*(##\s*Pull request overview\s*)?Copilot reviewed \d+ out of \d+ changed files in this pull request and generated \d+ comments\.\s*$")] + private static partial Regex ReviewedOutOfRegex(); + + public static string GeneratePrompt(PullRequestInfo info) + { + var prompt = $""" +以下のdotnet/runtimeのPull Requestを要約してください。 +またできる限り、以下の情報以外の内容を推測して含めないようにしてください。 - 1. **コード変更の技術的影響** - - 変更がランタイム、コンパイラ、ライブラリのどの部分に影響するか明記 - - API の変更がある場合は、公開APIか内部実装かを区別 - - 互換性への影響(破壊的変更、非推奨化など)を明確に記載 +Pull Request: +- {info.PullRequest.Title} #{info.PullRequest.Number} +- 作成者: {info.PullRequest.User.Login} +- レビュワー: {GenerateReviewersText(info)} - 2. **パフォーマンスに関する分析** - - メモリ使用量、実行速度、スループットへの影響を具体的に記載 - - ベンチマーク結果や計測値がある場合は必ず含める - - パフォーマンス改善の場合は、改善率や具体的な数値を記載 +作成者による概要: +{GenerateBody(info)} - 3. **セキュリティとバグ修正** - - セキュリティ上の脆弱性修正の場合は、その重要度を明記 - - バグ修正の場合、修正前の問題の再現条件と修正後の動作を対比 - - CVE番号などのセキュリティ識別子がある場合は記載 - """; +Copilotによる概要: +{GenerateCopilotReviewText(info)} - public static string GeneratePrompt(PullRequestInfo info) +変更ファイル: +{GenerateFilesChangedText(info)} +"""; + return prompt; + } + + private static string GenerateBody(PullRequestInfo info) { - // pull reqeust info var body = info.PullRequest.Body; if (string.IsNullOrWhiteSpace(body)) { body = "なし"; } + return body; + } - // file changes info - var files = info.Files; - var filesChanged = string.Join(Environment.NewLine, files - .Take(MaxFileCount) - .Select(f => $"- {f.FileName} (+{f.Additions}/-{f.Deletions}, total: {f.Changes})") - .Append(files.Count > MaxFileCount ? $"- その他 {files.Count - MaxFileCount} files" : "")); - - // reviewer info + private static string GenerateReviewersText(PullRequestInfo info) + { var reviews = info.Reviews; - var reviewersBuilder = new DefaultInterpolatedStringHandler(0, 0); + var builder = new DefaultInterpolatedStringHandler(0, 0); for (int i = 0; i < reviews.Count; i++) { var pullRequestReview = reviews[i]; - reviewersBuilder.AppendLiteral(pullRequestReview.User.Login); + builder.AppendLiteral(pullRequestReview.User.Login); if (i < reviews.Count - 1) { - reviewersBuilder.AppendLiteral(", "); + builder.AppendLiteral(", "); } } - // latest copilot overview - var copilotOverview = info.Reviews.Where(r => r.User.Login == "copilot-pull-request-reviewer[bot]") - .OrderByDescending(r => r.SubmittedAt) - .FirstOrDefault(); - var overviewText = copilotOverview != null ? copilotOverview.Body.Trim() : ""; - if (string.IsNullOrWhiteSpace(overviewText)) + return builder.ToStringAndClear(); + } + + private static string GenerateCopilotReviewText(PullRequestInfo pullRequestInfo) + { + var copilotReviews = pullRequestInfo + .Reviews + .Where(r => + r.User.Login == "copilot-pull-request-reviewer[bot]" && + r.Body.Length > 0 && + !r.Body.AsSpan().ContainsAny(searchValues) && + !ReviewedOutOfRegex().IsMatch(r.Body) + ) + .OrderBy(r => r.SubmittedAt) + .ToArray(); + + if (copilotReviews.Length == 0) return "なし"; + if (copilotReviews.Length == 1) return copilotReviews[0].Body.Trim(); + if (copilotReviews.Length == 2) return $"{copilotReviews[0].Body.Trim()}{Environment.NewLine}{Environment.NewLine}{copilotReviews[1].Body.Trim()}"; + + var copilotReviewsSpan = copilotReviews.AsSpan(); + + // Set first review body. + var builder = new DefaultInterpolatedStringHandler(0, 0); + builder.AppendLiteral(copilotReviewsSpan[0].Body.Trim()); + + // Append remaining reviews with two new lines as separator, but limit total length to 10000 characters to avoid exceeding token limit. + foreach (var review in copilotReviewsSpan[1..^1]) { - overviewText = "なし"; + if (builder.Text.Length > 10000) + { + break; + } + builder.AppendLiteral(Environment.NewLine); + builder.AppendLiteral(Environment.NewLine); + builder.AppendLiteral(review.Body.Trim()); } - var prompt = $""" -以下のdotnet/runtimeのPull Requestを要約してください。 -またできる限り、以下の情報以外の内容を推測して含めないようにしてください。 + // Append latest review. + builder.AppendLiteral(Environment.NewLine); + builder.AppendLiteral(Environment.NewLine); + builder.AppendLiteral(copilotReviewsSpan[^1].Body.Trim()); -Pull Request: -- {info.PullRequest.Title} #{info.PullRequest.Number} -- 作成者: {info.PullRequest.User.Login} -- レビュワー: {reviewersBuilder.ToStringAndClear()} - -作成者による概要: -{body} + return builder.ToStringAndClear(); + } -Copilotによる概要: -{overviewText} + private static string GenerateFilesChangedText(PullRequestInfo info) + { + var builder = new DefaultInterpolatedStringHandler(0, 0); + foreach (var f in info.Files.Take(MaxFileCount)) + { + builder.AppendLiteral($"- {f.FileName} (+{f.Additions}/-{f.Deletions}, total: {f.Changes})"); + builder.AppendLiteral(Environment.NewLine); + } -変更ファイル: -{filesChanged} + var count = info.Files.Count - MaxFileCount; + if (count > 0) + { + builder.AppendLiteral($"- その他 {count} files"); + } -"""; - return prompt; + return builder.ToStringAndClear(); } } \ No newline at end of file From cb811301574558cf4b9bcfa4555ee718dadee125 Mon Sep 17 00:00:00 2001 From: prozolic <42107886+prozolic@users.noreply.github.com> Date: Thu, 12 Mar 2026 00:55:20 +0900 Subject: [PATCH 2/2] Fix field name --- src/PRDigest.NET/PromptGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PRDigest.NET/PromptGenerator.cs b/src/PRDigest.NET/PromptGenerator.cs index c6d5710..2fd4239 100644 --- a/src/PRDigest.NET/PromptGenerator.cs +++ b/src/PRDigest.NET/PromptGenerator.cs @@ -61,7 +61,7 @@ あなたは.NET開発者向けのPull Request要約アシスタントです。 "Copilot encountered an error and was unable to review this pull request" }; - private static readonly SearchValues searchValues = SearchValues.Create(EmptyReviewComment, StringComparison.Ordinal); + private static readonly SearchValues EmptyReviewCommentSearchValues = SearchValues.Create(EmptyReviewComment, StringComparison.Ordinal); [GeneratedRegex(@"^\s*(##\s*Pull request overview\s*)?Copilot reviewed \d+ out of \d+ changed files in this pull request and generated \d+ comments\.\s*$")] private static partial Regex ReviewedOutOfRegex(); @@ -123,7 +123,7 @@ private static string GenerateCopilotReviewText(PullRequestInfo pullRequestInfo) .Where(r => r.User.Login == "copilot-pull-request-reviewer[bot]" && r.Body.Length > 0 && - !r.Body.AsSpan().ContainsAny(searchValues) && + !r.Body.AsSpan().ContainsAny(EmptyReviewCommentSearchValues) && !ReviewedOutOfRegex().IsMatch(r.Body) ) .OrderBy(r => r.SubmittedAt)