Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
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
12 changes: 9 additions & 3 deletions coderd/x/chatd/quickgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,6 @@ func validateGeneratedTitle(title string) error {
if title == "" {
return xerrors.New("generated title was empty")
}
if len(strings.Fields(title)) > 8 {
return xerrors.New("generated title exceeded 8 words")
}
return nil
}

Expand Down Expand Up @@ -652,11 +649,20 @@ func titlePasteText(
return pasteText, nil
}

// titleMaxWords caps generated titles at the prompt's stated 2-8 word
// budget. Quickgen pins temperature, so a model that overshoots the
// budget for a given conversation keeps overshooting on retry; keeping
// the first words of an otherwise good title beats failing generation.
const titleMaxWords = 8

func normalizeTitleOutput(title string) string {
title = normalizeShortTextOutput(title)
if title == "" {
return ""
}
if words := strings.Fields(title); len(words) > titleMaxWords {
title = strings.Join(words[:titleMaxWords], " ")
}
return truncateRunes(title, 80)
}

Expand Down
51 changes: 51 additions & 0 deletions coderd/x/chatd/quickgen_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,32 @@ func TestNormalizeTurnStatusLabel(t *testing.T) {
}
}

func Test_normalizeTitleOutput(t *testing.T) {
t.Parallel()

cases := []struct {
name string
input string
want string
}{
{name: "empty after normalization", input: " \"\" ", want: ""},
{name: "collapses whitespace and strips quotes", input: "\"Fix pq duplicate\tkey\"", want: "Fix pq duplicate key"},
{name: "keeps titles within the word budget", input: "Review risky changes in acme/webapp PR #123", want: "Review risky changes in acme/webapp PR #123"},
{
name: "truncates overlong titles to the word budget",
input: "Re-capture Tasks-enabled evidence for the Coder pull request feature flag",
want: "Re-capture Tasks-enabled evidence for the Coder pull request",
},
{name: "truncates to 80 runes", input: strings.Repeat("a", 100), want: strings.Repeat("a", 80)},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, tc.want, normalizeTitleOutput(tc.input))
})
}
}

func TestFallbackTurnStatusLabel(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -946,6 +972,31 @@ func TestGenerateStructuredTitleWithUsage_DropsRejectedTemperature(t *testing.T)
"generation should retry without temperature after the model rejects it")
}

func TestGenerateStructuredTitleWithUsage_TruncatesOverlongTitle(t *testing.T) {
t.Parallel()

model := &chattest.FakeModel{
GenerateObjectFn: func(_ context.Context, _ fantasy.ObjectCall) (*fantasy.ObjectResponse, error) {
return &fantasy.ObjectResponse{
Object: map[string]any{
"title": "Re-capture Tasks-enabled evidence for the Coder pull request feature flag",
},
}, nil
},
}

title, _, err := generateStructuredTitleWithUsage(
t.Context(),
model,
titleObjectCall(resolvedModelCall{}),
titleGenerationPrompt,
"re-capture UI evidence for a Coder pull request",
)
require.NoError(t, err)
require.Equal(t, "Re-capture Tasks-enabled evidence for the Coder pull request", title,
"an overlong generated title should be truncated to the word budget, not rejected")
}

func newOpenAICompatStructuredOutputServer(
t *testing.T,
toolName string,
Expand Down
Loading