Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions packages/core/src/sessions/titleGeneratorService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
'<github_pr number="123" title="Fix SUMMARY: parsing" url="https://github.com/org/repo/pull/123" />',
);

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(
'<github_pr number="123" title="Fix login redirect" url="https://github.com/org/repo/pull/123" />',
);

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");
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/sessions/titleGeneratorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <github_pr> 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.
Expand All @@ -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
- "<github_pr number="123" title="Fix login redirect" url="https://github.com/org/repo/pull/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
Expand Down Expand Up @@ -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]
Expand Down
Loading