fix(agent-service): store proper title in session metadata, exclude systemPrompt from list API
Two issues fixed:
1. agent.controller.ts — on the FIRST task of each session, write title+voiceMode
into session.metadata so the client can display a meaningful conversation title:
- Text sessions: metadata.title = first 40 chars of user prompt
- Voice sessions: metadata.title = '' + metadata.voiceMode = true
(Flutter renders these as '语音对话 M/D HH:mm')
titleSet flag prevents overwriting the title on subsequent turns of the same session.
2. session.controller.ts — listSessions() now returns a DTO instead of the raw entity.
systemPrompt is an internal engine instruction and is explicitly excluded from the
response. The client receives { id, status, engineType, metadata, createdAt, updatedAt }.
This commit is contained in:
parent
9546dab93d
commit
6ca8aab243
|
|
@ -53,17 +53,33 @@ export class AgentController {
|
|||
: this.engineRegistry.getActiveEngine();
|
||||
|
||||
// Reuse existing session or create new one
|
||||
const isVoice = body.voiceMode ?? false;
|
||||
let session: AgentSession;
|
||||
if (body.sessionId) {
|
||||
const existing = await this.sessionRepository.findById(body.sessionId);
|
||||
if (existing && existing.status === 'active' && existing.tenantId === tenantId) {
|
||||
session = existing;
|
||||
} else {
|
||||
session = this.createNewSession(tenantId, engine.engineType, body.systemPrompt);
|
||||
session = this.createNewSession(tenantId, engine.engineType, body.systemPrompt, isVoice);
|
||||
}
|
||||
} else {
|
||||
session = this.createNewSession(tenantId, engine.engineType, body.systemPrompt);
|
||||
session = this.createNewSession(tenantId, engine.engineType, body.systemPrompt, isVoice);
|
||||
}
|
||||
|
||||
// Set a human-readable title on the FIRST task of this session.
|
||||
// This title is stored in metadata so the session list can display it
|
||||
// without ever exposing the internal systemPrompt string to the client.
|
||||
// - Text sessions: truncate the first user prompt to 40 chars
|
||||
// - Voice sessions: leave title empty; Flutter renders "语音对话 M/D HH:mm"
|
||||
if (!(session.metadata as Record<string, unknown>).title && !(session.metadata as Record<string, unknown>).titleSet) {
|
||||
session.metadata = {
|
||||
...session.metadata as Record<string, unknown>,
|
||||
voiceMode: isVoice,
|
||||
title: isVoice ? '' : body.prompt.substring(0, 40).trim(),
|
||||
titleSet: true, // prevent overwrite on subsequent turns
|
||||
};
|
||||
}
|
||||
|
||||
// Keep session active for multi-turn
|
||||
session.status = 'active';
|
||||
session.updatedAt = new Date();
|
||||
|
|
@ -619,14 +635,20 @@ export class AgentController {
|
|||
});
|
||||
}
|
||||
|
||||
private createNewSession(tenantId: string, engineType: string, systemPrompt?: string): AgentSession {
|
||||
private createNewSession(
|
||||
tenantId: string,
|
||||
engineType: string,
|
||||
systemPrompt?: string,
|
||||
voiceMode?: boolean,
|
||||
): AgentSession {
|
||||
const session = new AgentSession();
|
||||
session.id = crypto.randomUUID();
|
||||
session.tenantId = tenantId;
|
||||
session.engineType = engineType;
|
||||
session.status = 'active';
|
||||
session.systemPrompt = systemPrompt;
|
||||
session.metadata = {};
|
||||
// Pre-populate voiceMode so it's available even before the first task saves it
|
||||
session.metadata = { voiceMode: voiceMode ?? false };
|
||||
session.createdAt = new Date();
|
||||
session.updatedAt = new Date();
|
||||
return session;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,18 @@ export class SessionController {
|
|||
|
||||
@Get()
|
||||
async listSessions(@TenantId() tenantId: string) {
|
||||
return this.sessionRepository.findByTenant(tenantId);
|
||||
const sessions = await this.sessionRepository.findByTenant(tenantId);
|
||||
// Return a safe DTO: systemPrompt is an internal engine instruction and must
|
||||
// NOT be sent to the client (it would be displayed as the conversation title).
|
||||
// The client derives the display title from metadata.title / metadata.voiceMode.
|
||||
return sessions.map((s) => ({
|
||||
id: s.id,
|
||||
status: s.status,
|
||||
engineType: s.engineType,
|
||||
metadata: s.metadata, // contains { title, voiceMode, titleSet, sdkSessionId? }
|
||||
createdAt: s.createdAt,
|
||||
updatedAt: s.updatedAt,
|
||||
}));
|
||||
}
|
||||
|
||||
@Get(':sessionId')
|
||||
|
|
|
|||
Loading…
Reference in New Issue