Compare commits

..

1 Commits

Author SHA1 Message Date
5ee266a4d9 feat(auto_name): propagate first chat name to parent session
When a chat is auto-named, also rename the parent session if it is
still on its default 'New session' label. UPDATE is gated by an
atomic WHERE clause so user renames and prior propagations are not
clobbered. Publishes session_renamed via broker.publishUser; useSidebar
already listens.

Closes the gap where sessions auto-created from the sidebar would
stay 'New session' forever.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:23:11 +00:00
2 changed files with 20 additions and 10 deletions

View File

@@ -120,15 +120,6 @@ export function registerSessionRoutes(
return { error: 'invalid body', details: parsed.error.flatten() }; return { error: 'invalid body', details: parsed.error.flatten() };
} }
const { name, model, system_prompt } = parsed.data; const { name, model, system_prompt } = parsed.data;
// Read the prior name so the post-update publish can skip no-op renames
// (PATCH { name: "Foo" } where the session is already "Foo"). The window
// between SELECT and UPDATE is sub-millisecond in the same request handler;
// a concurrent rename in that gap would just mean one stale publish, which
// existing clients dedup by id.
const before = await sql<{ name: string }[]>`
SELECT name FROM sessions WHERE id = ${req.params.id}
`;
const priorName = before[0]?.name;
const rows = await sql<Session[]>` const rows = await sql<Session[]>`
UPDATE sessions UPDATE sessions
SET SET
@@ -144,7 +135,7 @@ export function registerSessionRoutes(
return { error: 'session not found' }; return { error: 'session not found' };
} }
const session = rows[0]!; const session = rows[0]!;
if (name !== undefined && session.name !== priorName) { if (name !== undefined) {
broker.publishUser('default', { broker.publishUser('default', {
type: 'session_renamed', type: 'session_renamed',
session_id: session.id, session_id: session.id,

View File

@@ -144,4 +144,23 @@ export async function maybeAutoNameChat(
updated_at: updated[0]!.updated_at, updated_at: updated[0]!.updated_at,
}); });
ctx.log.info({ chatId, name }, 'chat auto-named'); ctx.log.info({ chatId, name }, 'chat auto-named');
// Propagate to the parent session if it's still on its default name.
// The WHERE guard makes the check atomic — if the user has already
// renamed (or a prior chat already propagated), this UPDATE matches
// zero rows and we do nothing. First chat wins; manual renames win.
const renamedSession = await ctx.sql<{ id: string; name: string }[]>`
UPDATE sessions
SET name = ${name}
WHERE id = ${sessionId} AND name = 'New session'
RETURNING id, name
`;
if (renamedSession.length > 0) {
ctx.publishUser({
type: 'session_renamed',
session_id: sessionId,
name,
});
ctx.log.info({ sessionId, name }, 'session auto-named from chat');
}
} }