diff --git a/packages/core/src/sessions/titleGeneratorService.test.ts b/packages/core/src/sessions/titleGeneratorService.test.ts index 956fd897ac..dfa5829191 100644 --- a/packages/core/src/sessions/titleGeneratorService.test.ts +++ b/packages/core/src/sessions/titleGeneratorService.test.ts @@ -220,6 +220,42 @@ describe("generateTitleAndSummary", () => { expect(result?.title).toBe("Fix login bug"); }); + it("does not parse SUMMARY in a PR title as the summary", async () => { + prompt.mockResolvedValue({ + content: + "TITLE: Review PR #123: Fix SUMMARY: parsing\nSUMMARY: Fixing title and summary parsing.", + }); + + const result = await makeService().generateTitleAndSummary( + '', + ); + + expect(result).toEqual({ + title: "Review PR #123: Fix SUMMARY: parsing", + summary: "Fixing title and summary parsing.", + }); + }); + + it("instructs the model to include existing GitHub PR titles", async () => { + prompt.mockResolvedValue({ + content: + "TITLE: Review PR #123: Fix login redirect\nSUMMARY: Reviewing the existing pull request.", + }); + + await makeService().generateTitleAndSummary( + '', + ); + + expect(prompt).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + system: expect.stringContaining( + "the generated TITLE MUST include both the PR number and the PR title verbatim", + ), + }), + ); + }); + it("returns null on error", async () => { prompt.mockRejectedValue(new Error("network error")); const result = await makeService().generateTitleAndSummary("some content"); diff --git a/packages/core/src/sessions/titleGeneratorService.ts b/packages/core/src/sessions/titleGeneratorService.ts index 537317fb02..7913c2f64b 100644 --- a/packages/core/src/sessions/titleGeneratorService.ts +++ b/packages/core/src/sessions/titleGeneratorService.ts @@ -40,6 +40,7 @@ Title rules: - Remove: the, this, my, a, an - If possible, start with action verbs (Fix, Implement, Analyze, Debug, Update, Research, Review) - Keep exact: technical terms, numbers, filenames, HTTP codes, PR numbers +- GitHub PR rule: If the content contains a with a non-empty title, the generated TITLE MUST include both the PR number and the PR title verbatim. This rule overrides the 6-word title limit. Never replace the PR title with a generic phrase. Before responding, verify that both values appear in TITLE. - Never assume tech stack - Only output "Untitled" if the input is completely null/missing, not just unclear - If the input is a URL (e.g. a GitHub issue link, PR link, or any web URL), generate a title based on what you can infer from the URL structure (repo name, issue/PR number, etc.). Never say you cannot access URLs or ask the user for more information. @@ -58,6 +59,7 @@ Title examples: - "Update user documentation for new API endpoints" → Update API documentation - "Research competitor pricing strategies for our product" → Research competitor pricing - "Review pull request #123" → Review pull request #123 +- "" → Review PR #123: Fix login redirect - "debug 500 errors in production" → Debug production 500 errors - "why is the payment flow failing" → Analyze payment flow failure - "So how about that weather huh" → Weather chat @@ -173,7 +175,7 @@ export class TitleGeneratorService { const text = result.content.trim(); const titleMatch = text.match(/^TITLE:\s*(.+?)(?:\n|$)/m); - const summaryMatch = text.match(/SUMMARY:\s*([\s\S]+)$/m); + const summaryMatch = text.match(/^SUMMARY:\s*([\s\S]+)$/m); const title = titleMatch?.[1]