diff --git a/src/services/worker/agents/ResponseProcessor.ts b/src/services/worker/agents/ResponseProcessor.ts index 3487764f..74bd87ef 100644 --- a/src/services/worker/agents/ResponseProcessor.ts +++ b/src/services/worker/agents/ResponseProcessor.ts @@ -85,6 +85,27 @@ export async function processAgentResponse( // Convert nullable fields to empty strings for storeSummary (if summary exists) const summaryForStore = normalizeSummaryForStorage(summary); + // Fallback: When summary parse fails but observations exist, salvage a synthetic summary. + // Fixes Issue #1312: AI sometimes returns instead of despite clear instructions. + // Observations are stored normally; this only affects the session summary. + let finalSummaryForStore = summaryForStore; + if (!summaryForStore && observations.length > 0) { + const primary = observations[0]; + finalSummaryForStore = { + request: primary.title || `Session observations (${observations.length} items)`, + investigated: primary.narrative || primary.facts?.join('; ') || '', + learned: primary.facts?.join('; ') || '', + completed: primary.type === 'feature' || primary.type === 'bugfix' ? (primary.title || '') : '', + next_steps: '', + notes: `[Salvaged from ${observations.length} observation(s)] AI returned instead of ` + }; + logger.warn('PARSER', `SALVAGED summary from ${observations.length} observation(s) — AI did not output tags`, { + sessionId: session.sessionDbId, + agentName, + observationIds: observations.map(o => o.title).filter(Boolean).slice(0, 3) + }); + } + // Get session store for atomic transaction const sessionStore = dbManager.getSessionStore(); @@ -102,7 +123,7 @@ export async function processAgentResponse( sessionStore.ensureMemorySessionIdRegistered(session.sessionDbId, session.memorySessionId); // Log pre-storage with session ID chain for verification - logger.info('DB', `STORING | sessionDbId=${session.sessionDbId} | memorySessionId=${session.memorySessionId} | obsCount=${observations.length} | hasSummary=${!!summaryForStore}`, { + logger.info('DB', `STORING | sessionDbId=${session.sessionDbId} | memorySessionId=${session.memorySessionId} | obsCount=${observations.length} | hasSummary=${!!finalSummaryForStore}`, { sessionId: session.sessionDbId, memorySessionId: session.memorySessionId }); @@ -113,7 +134,7 @@ export async function processAgentResponse( session.memorySessionId, session.project, observations, - summaryForStore, + finalSummaryForStore, session.lastPromptNumber, discoveryTokens, originalTimestamp ?? undefined, @@ -153,7 +174,7 @@ export async function processAgentResponse( // Sync and broadcast summary if present await syncAndBroadcastSummary( summary, - summaryForStore, + finalSummaryForStore, result, session, dbManager,