fix: improve error handling and logging in summary and transcript processing
- Enhanced error handling in summary generation by using fallback messages for missing assistant messages. - Updated the `buildSummaryPrompt` function to streamline the retrieval of the last assistant message. - Improved the `extractLastMessage` function to log errors when transcript files are missing or empty, and to ensure proper handling of messages without content. - Added checks to ensure that messages of the specified role are found in the transcript, with appropriate logging for missing messages. - Refactored the logging mechanism to provide clearer insights into processing failures and successes.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "claude-mem-plugin",
|
||||
"version": "7.2.1",
|
||||
"private": true,
|
||||
"description": "Runtime dependencies for claude-mem bundled hooks",
|
||||
"type": "module",
|
||||
"dependencies": {},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"bun": ">=1.0.0"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -781,7 +781,7 @@ MEMORY PROCESSING START
|
||||
Write progress notes of what was done, what was learned, and what's next. This is a checkpoint to capture progress so far. The session is ongoing - you may receive more requests and tool executions after this summary. Write "next_steps" as the current trajectory of work (what's actively being worked on or coming up next), not as post-session future work. Always write at least a minimal summary explaining current progress, even if work is still in early stages, so that users see a summary output tied to each request.
|
||||
|
||||
Claude's Full Response to User:
|
||||
${vr("Missing last_assistant_message in session for summary prompt",a,a.last_assistant_message||"")}
|
||||
${a.last_assistant_message||vr("Missing last_assistant_message in session for summary prompt",a,"")}
|
||||
|
||||
Respond in this XML format:
|
||||
<summary>
|
||||
|
||||
+2
-2
@@ -177,10 +177,10 @@ export function buildObservationPrompt(obs: Observation): string {
|
||||
* Build prompt to generate progress summary
|
||||
*/
|
||||
export function buildSummaryPrompt(session: SDKSession): string {
|
||||
const lastAssistantMessage = happy_path_error__with_fallback(
|
||||
const lastAssistantMessage = session.last_assistant_message || happy_path_error__with_fallback(
|
||||
'Missing last_assistant_message in session for summary prompt',
|
||||
session,
|
||||
session.last_assistant_message || ''
|
||||
''
|
||||
);
|
||||
|
||||
return `PROGRESS SUMMARY CHECKPOINT
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
|
||||
/**
|
||||
* Extract last message of specified role from transcript JSONL file
|
||||
@@ -13,42 +14,73 @@ export function extractLastMessage(
|
||||
stripSystemReminders: boolean = false
|
||||
): string {
|
||||
if (!transcriptPath || !existsSync(transcriptPath)) {
|
||||
happy_path_error__with_fallback(
|
||||
'Transcript path missing or file does not exist',
|
||||
{ transcriptPath, role }
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
const content = readFileSync(transcriptPath, 'utf-8').trim();
|
||||
if (!content) return '';
|
||||
if (!content) {
|
||||
happy_path_error__with_fallback(
|
||||
'Transcript file exists but is empty',
|
||||
{ transcriptPath, role }
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
const lines = content.split('\n');
|
||||
let foundMatchingRole = false;
|
||||
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
try {
|
||||
const line = JSON.parse(lines[i]);
|
||||
if (line.type === role && line.message?.content) {
|
||||
let text = '';
|
||||
const msgContent = line.message.content;
|
||||
if (line.type === role) {
|
||||
foundMatchingRole = true;
|
||||
|
||||
if (typeof msgContent === 'string') {
|
||||
text = msgContent;
|
||||
} else if (Array.isArray(msgContent)) {
|
||||
text = msgContent
|
||||
.filter((c: any) => c.type === 'text')
|
||||
.map((c: any) => c.text)
|
||||
.join('\n');
|
||||
if (line.message?.content) {
|
||||
let text = '';
|
||||
const msgContent = line.message.content;
|
||||
|
||||
if (typeof msgContent === 'string') {
|
||||
text = msgContent;
|
||||
} else if (Array.isArray(msgContent)) {
|
||||
text = msgContent
|
||||
.filter((c: any) => c.type === 'text')
|
||||
.map((c: any) => c.text)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
if (stripSystemReminders) {
|
||||
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '');
|
||||
text = text.replace(/\n{3,}/g, '\n\n').trim();
|
||||
}
|
||||
|
||||
// Log if we found the role but the text is empty after processing
|
||||
if (!text || text.trim() === '') {
|
||||
happy_path_error__with_fallback(
|
||||
'Found message but content is empty after processing',
|
||||
{ role, transcriptPath, msgContentType: typeof msgContent, stripSystemReminders }
|
||||
);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
if (stripSystemReminders) {
|
||||
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '');
|
||||
text = text.replace(/\n{3,}/g, '\n\n').trim();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we searched the whole transcript and didn't find any message of this role
|
||||
if (!foundMatchingRole) {
|
||||
happy_path_error__with_fallback(
|
||||
'No message found for role in transcript',
|
||||
{ role, transcriptPath, totalLines: lines.length }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('HOOK', 'Failed to read transcript', { transcriptPath }, error as Error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user