feat: Enhance summary hook to include last user message from transcript (#95)
* feat: Enhance summary hook to include last user message from transcript - Added functionality to extract the last user message from a JSONL transcript file in the summary hook. - Updated the summary hook to send the last user message along with the summary request. - Modified the SDKSession interface to include an optional last_user_message field. - Updated the summary prompt to incorporate the last user message in the output format. - Refactored worker service to handle the last user message in the summarize queue. - Enhanced session manager to track and broadcast processing status based on active sessions and queue depth. - Improved error handling and logging for better traceability during transcript reading and processing. * feat(worker): enhance processing status broadcasting and session management - Added immediate broadcasting of processing status when a prompt is received. - Implemented logging for generator completion in multiple locations. - Updated `broadcastProcessingStatus` to include queue depth and active session count in logs. - Modified session iterator to stop yielding messages after a summary is yielded, with appropriate logging.
This commit is contained in:
@@ -188,7 +188,8 @@ export class SDKAgent {
|
||||
id: session.sessionDbId,
|
||||
sdk_session_id: session.sdkSessionId,
|
||||
project: session.project,
|
||||
user_prompt: session.userPrompt
|
||||
user_prompt: session.userPrompt,
|
||||
last_user_message: message.last_user_message || ''
|
||||
})
|
||||
},
|
||||
session_id: session.claudeSessionId,
|
||||
@@ -351,9 +352,9 @@ export class SDKAgent {
|
||||
}
|
||||
}
|
||||
|
||||
// Check and stop spinner after processing (debounced)
|
||||
if (worker && typeof worker.checkAndStopSpinner === 'function') {
|
||||
worker.checkAndStopSpinner();
|
||||
// Broadcast activity status after processing (queue may have changed)
|
||||
if (worker && typeof worker.broadcastProcessingStatus === 'function') {
|
||||
worker.broadcastProcessingStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,19 @@ export class SessionManager {
|
||||
private dbManager: DatabaseManager;
|
||||
private sessions: Map<number, ActiveSession> = new Map();
|
||||
private sessionQueues: Map<number, EventEmitter> = new Map();
|
||||
private onSessionDeletedCallback?: () => void;
|
||||
|
||||
constructor(dbManager: DatabaseManager) {
|
||||
this.dbManager = dbManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set callback to be called when a session is deleted (for broadcasting status)
|
||||
*/
|
||||
setOnSessionDeleted(callback: () => void): void {
|
||||
this.onSessionDeletedCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new session or return existing one
|
||||
*/
|
||||
@@ -115,7 +123,7 @@ export class SessionManager {
|
||||
* Queue a summarize request (zero-latency notification)
|
||||
* Auto-initializes session if not in memory but exists in database
|
||||
*/
|
||||
queueSummarize(sessionDbId: number): void {
|
||||
queueSummarize(sessionDbId: number, lastUserMessage: string): void {
|
||||
// Auto-initialize from database if needed (handles worker restarts)
|
||||
let session = this.sessions.get(sessionDbId);
|
||||
if (!session) {
|
||||
@@ -124,7 +132,10 @@ export class SessionManager {
|
||||
|
||||
const beforeDepth = session.pendingMessages.length;
|
||||
|
||||
session.pendingMessages.push({ type: 'summarize' });
|
||||
session.pendingMessages.push({
|
||||
type: 'summarize',
|
||||
last_user_message: lastUserMessage
|
||||
});
|
||||
|
||||
const afterDepth = session.pendingMessages.length;
|
||||
|
||||
@@ -165,6 +176,11 @@ export class SessionManager {
|
||||
duration: `${(sessionDuration / 1000).toFixed(1)}s`,
|
||||
project: session.project
|
||||
});
|
||||
|
||||
// Trigger callback to broadcast status update (spinner may need to stop)
|
||||
if (this.onSessionDeletedCallback) {
|
||||
this.onSessionDeletedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +207,35 @@ export class SessionManager {
|
||||
return this.sessions.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total queue depth across all sessions (for activity indicator)
|
||||
*/
|
||||
getTotalQueueDepth(): number {
|
||||
let total = 0;
|
||||
for (const session of this.sessions.values()) {
|
||||
total += session.pendingMessages.length;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any session is actively processing (has pending messages OR active generator)
|
||||
* Used for activity indicator to prevent spinner from stopping while SDK is processing
|
||||
*/
|
||||
isAnySessionProcessing(): boolean {
|
||||
for (const session of this.sessions.values()) {
|
||||
// Has queued messages waiting to be processed
|
||||
if (session.pendingMessages.length > 0) {
|
||||
return true;
|
||||
}
|
||||
// Has active SDK generator running (processing dequeued messages)
|
||||
if (session.generatorPromise !== null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message iterator for SDKAgent to consume (event-driven, no polling)
|
||||
* Auto-initializes session if not in memory but exists in database
|
||||
@@ -226,6 +271,12 @@ export class SessionManager {
|
||||
while (session.pendingMessages.length > 0) {
|
||||
const message = session.pendingMessages.shift()!;
|
||||
yield message;
|
||||
|
||||
// If we just yielded a summary, that's the end of this batch - stop the iterator
|
||||
if (message.type === 'summarize') {
|
||||
logger.info('SESSION', `Summary yielded - ending generator`, { sessionId: sessionDbId });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user