feat(threads): auto-generate first-turn thread titles#1375
feat(threads): auto-generate first-turn thread titles#1375juliusmarminge merged 27 commits intopingdotgg:mainfrom
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
b256e14 to
5335f66
Compare
5335f66 to
6e727cd
Compare
af6a180 to
aefb74c
Compare
aefb74c to
4ad369f
Compare
| )(function* () { | ||
| return yield* new TextGenerationError({ | ||
| operation: "generateThreadTitle", | ||
| detail: "Thread title generation is only supported through Codex.", |
| const promptSections = [ | ||
| "You write concise thread titles for coding conversations.", | ||
| "Return a JSON object with key: title.", | ||
| "Rules:", | ||
| "- Title should summarize the user's request, not restate it verbatim.", | ||
| "- Keep it short and specific (3-8 words).", | ||
| "- Avoid quotes, filler, prefixes, and trailing punctuation.", | ||
| "- If images are attached, use them as primary context for visual/UI issues.", | ||
| "", | ||
| "User message:", | ||
| limitSection(input.message, 8_000), | ||
| ]; | ||
| if (attachmentLines.length > 0) { | ||
| promptSections.push( | ||
| "", | ||
| "Attachment metadata:", | ||
| limitSection(attachmentLines.join("\n"), 4_000), | ||
| ); | ||
| } | ||
| const prompt = promptSections.join("\n"); |
ff72a3c to
451f55b
Compare
80461bc to
cb2929e
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| const { | ||
| title = "T3 Code", | ||
| description = "T3 Code — The best way to code with AI.", | ||
| description = "T3 Code — A great way to code with agents.", |
|
sorry codex went rouge |
apps/marketing/src/pages/index.astro
Outdated
|
|
||
| <Layout> | ||
| <h1 class="tagline">T3 Code is the best way to code with AI.</h1> | ||
| <h1 class="tagline">T3 Code is a great way to code with agents.</h1> |
There was a problem hiding this comment.
🥲
also very unrelated to the PR
apps/web/src/components/ChatView.tsx
Outdated
| textGenerationModel: selectedTextGenerationModel, | ||
| assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered", |
There was a problem hiding this comment.
these settings are server authorative now, you don't need to send them from client. the text generaiton service reads the server settings to find the right model
There was a problem hiding this comment.
nit: name module String.ts and export just truncate. nothing title related here...
| Layer.succeed(TextGeneration, { | ||
| generateBranchName, | ||
| generateThreadTitle, | ||
| } as unknown as TextGenerationShape), |
There was a problem hiding this comment.
nit: Layer.mock(TextGeneration, {}) if you don't wanna provide a full service implementation
| function buildReplaceableThreadTitles(input: { | ||
| readonly messageText: string; | ||
| readonly attachments?: ReadonlyArray<ChatAttachment>; | ||
| readonly titleSeed?: string; | ||
| }): ReadonlySet<string> { | ||
| const titles = new Set<string>([DEFAULT_THREAD_TITLE]); | ||
| const trimmedTitleSeed = input.titleSeed?.trim(); | ||
|
|
||
| if (trimmedTitleSeed) { | ||
| titles.add(trimmedTitleSeed); | ||
| return titles; | ||
| } | ||
|
|
||
| const trimmedMessage = input.messageText.trim(); | ||
|
|
||
| if (trimmedMessage.length > 0) { | ||
| titles.add(truncateTitle(trimmedMessage)); | ||
| return titles; | ||
| } | ||
|
|
||
| const firstImageAttachment = input.attachments?.find((attachment) => attachment.type === "image"); | ||
| if (firstImageAttachment) { | ||
| titles.add(truncateTitle(`Image: ${firstImageAttachment.name}`)); | ||
| } | ||
|
|
||
| return titles; | ||
| } | ||
|
|
||
| function isReplaceableThreadTitle( | ||
| currentTitle: string, | ||
| input: { | ||
| readonly messageText: string; | ||
| readonly attachments?: ReadonlyArray<ChatAttachment>; | ||
| readonly titleSeed?: string; | ||
| }, |
There was a problem hiding this comment.
don't quite follow what this is meant to do

Closes #990
What Changed
Why
Thread titles were still just truncated prompt text.
This makes new threads easier to scan while keeping the model selection simpler and reusing the same text generation path we already have for commit, PR, and branch text.
UI Changes
Settings now says
Text generation modelChecklist
Note
Medium Risk
Adds new server-side first-turn behavior and new
TextGeneration.generateThreadTitleflows across orchestration, contracts, and providers; risk is mainly around unintended title overwrites and provider CLI/output edge cases.Overview
Auto-generates thread titles on the first user turn.
ProviderCommandReactornow forks background work on first-turn start to (a) generate a sidebar-safe thread title viaTextGeneration.generateThreadTitleand updatethread.metaonly when the current title is a replaceable placeholder (default or matches a client-provided seed), and (b) reuse the same configured text-generation model when auto-renaming temporary worktree branches.Adds end-to-end support for thread title generation: new
buildThreadTitlePrompt,sanitizeThreadTitle(single-line, quote/whitespace cleanup, 50-char ellipsis, fallback to"New thread"), provider implementations in both Codex and Claude layers, routing support, and expanded tests.Updates the command/event contract so clients send a
titleSeedinthread.turn.start, which is propagated intothread.turn-start-requestedfor consistent placeholder detection. Also replaces the web-onlytruncateTitlewith a sharedpackages/sharedtruncateutility and updates the web client to sendtitleSeedon turn start.Written by Cursor Bugbot for commit 4e07295. This will update automatically on new commits. Configure here.
Note
Auto-generate thread titles on the first user turn
ProviderCommandReactornow forks a title generation effect alongside branch name generation, callingTextGeneration.generateThreadTitleand updatingthread.metaif the current title is the default placeholder or matches the client-providedtitleSeed.ClaudeTextGenerationandCodexTextGenerationimplementgenerateThreadTitleusing a newbuildThreadTitlePrompthelper in Prompts.ts and asanitizeThreadTitleutil that trims, strips quotes, truncates to 50 chars, and falls back to"New thread".titleSeed(derived from the draft message) inthread.turn.startcommands so the server can avoid overwriting a user-set title that matches the seed.truncateutility in packages/shared/src/String.ts replaces the former per-apptruncateTitle.ThreadTurnStartRequestedPayloadgains an optionaltitleSeedfield and losesassistantDeliveryMode; consumers decoding this event type will need to handle the schema change.Macroscope summarized 4e07295.