feat(chat): add auto-title generation after first exchange (M8.5)
After the first AI response, sends a background request to generate a 3-5 word title using Claude Haiku. Silently replaces the default title derived from the first user message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
5d3114b142
commit
68e296278c
@@ -281,6 +281,51 @@ function formatWebSearchContext(results: { title: string; url: string; content?:
|
||||
|
||||
let currentAbort: AbortController | null = null
|
||||
|
||||
/** Background title generation after first exchange */
|
||||
async function generateAutoTitle(conversationId: string) {
|
||||
const chatStore = useChatStore()
|
||||
const conv = chatStore.conversations.get(conversationId)
|
||||
if (!conv) return
|
||||
|
||||
// Only auto-title after first exchange (1 user + 1 assistant message)
|
||||
if (conv.messages.length !== 2) return
|
||||
const userMsg = conv.messages[0]
|
||||
if (userMsg.role !== 'user') return
|
||||
|
||||
// Skip if title was manually set (not auto-generated from first message)
|
||||
const autoTitle = userMsg.content.slice(0, 60) + (userMsg.content.length > 60 ? '...' : '')
|
||||
if (conv.title !== autoTitle) return
|
||||
|
||||
try {
|
||||
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
|
||||
const vaultKey = await getApiKey('claude')
|
||||
if (vaultKey) headers['x-api-key'] = vaultKey
|
||||
|
||||
const res = await fetch(CLAUDE_PATH, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
model: 'claude-haiku-4.5',
|
||||
system: 'You generate very short conversation titles. Respond with ONLY a 3-5 word title, no quotes, no punctuation at the end.',
|
||||
messages: [{ role: 'user', content: `Title this conversation: "${userMsg.content.slice(0, 200)}"` }],
|
||||
max_tokens: 20,
|
||||
stream: false,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!res.ok) return
|
||||
|
||||
const data = await res.json()
|
||||
const title = data?.content?.[0]?.text?.trim()
|
||||
if (title && title.length > 0 && title.length < 60) {
|
||||
conv.title = title
|
||||
conv.updatedAt = Date.now()
|
||||
}
|
||||
} catch {
|
||||
// Silent fail — title stays as default
|
||||
}
|
||||
}
|
||||
|
||||
export function useAI() {
|
||||
const chatStore = useChatStore()
|
||||
|
||||
@@ -353,6 +398,9 @@ export function useAI() {
|
||||
currentAbort = null
|
||||
chatStore.isStreaming = false
|
||||
}
|
||||
|
||||
// Auto-title: generate a short title after first exchange
|
||||
generateAutoTitle(cid)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user