Retry auto title generation for prompt-derived session titles

This commit is contained in:
7Sageer 2026-07-30 16:47:57 +08:00
parent 68ed623561
commit cca5387e7c
3 changed files with 37 additions and 15 deletions

View file

@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---
Automatically generate concise session titles after the first turn without overwriting custom titles.

View file

@ -393,22 +393,28 @@ export class SessionEventHandler {
}
/**
* Best-effort auto title: while the session has no title yet, ask the
* engine to generate one from the first prompts after each completed turn.
* The engine keeps custom titles untouched and dedupes in-flight requests;
* a resolved `undefined` (no managed login / no prompt yet) just retries on
* the next turn, while a rejection (v1 engine, dead RPC) disables further
* attempts for this session. The generated title lands through the regular
* `session.meta.updated` event.
* Best-effort auto title: after each completed turn, ask the engine to
* generate a title from the first prompts until one lands. The engine
* overwrites the prompt-derived easy title but never a custom title
* (enforced server-side), and dedupes in-flight requests. A resolved string
* means a title was applied stop asking so later turns don't regenerate
* over it; a resolved `undefined` (no managed login / no prompt yet / a
* custom title) just retries on the next turn; a rejection (v1 engine,
* dead RPC) disables further attempts for this session. The generated
* title lands through the regular `session.meta.updated` event.
*/
private requestSessionTitleGeneration(): void {
if (this.titleGenerationDisabled) return;
const { sessionId, sessionTitle } = this.host.state.appState;
const { sessionId } = this.host.state.appState;
if (sessionId.length === 0) return;
if (typeof sessionTitle === 'string' && sessionTitle.trim().length > 0) return;
void this.host.harness.generateSessionTitle({ id: sessionId }).catch(() => {
this.titleGenerationDisabled = true;
});
void this.host.harness.generateSessionTitle({ id: sessionId }).then(
(title) => {
if (title !== undefined) this.titleGenerationDisabled = true;
},
() => {
this.titleGenerationDisabled = true;
},
);
}
private handleStepBegin(event: TurnStepStartedEvent): void {

View file

@ -84,13 +84,24 @@ describe('session auto title generation', () => {
expect(harness.generateSessionTitle).toHaveBeenCalledWith({ id: 's1' });
});
it('does not request a title when the session already has one', () => {
const { host, harness } = makeHost({ sessionTitle: 'custom title' });
it('requests a title after a turn ends even when an easy title exists', () => {
const { host, harness } = makeHost({ sessionTitle: '首条 prompt 的截断标题' });
const handler = new SessionEventHandler(host);
handler.handleEvent(turnEndedEvent(), vi.fn());
expect(harness.generateSessionTitle).not.toHaveBeenCalled();
expect(harness.generateSessionTitle).toHaveBeenCalledWith({ id: 's1' });
});
it('stops requesting after a title was generated', async () => {
const { host, harness } = makeHost({ generateTitle: async () => '生成的标题' });
const handler = new SessionEventHandler(host);
handler.handleEvent(turnEndedEvent(), vi.fn());
await flushMicrotasks();
handler.handleEvent(turnEndedEvent(), vi.fn());
expect(harness.generateSessionTitle).toHaveBeenCalledTimes(1);
});
it('keeps requesting after an unavailable (undefined) result', async () => {