fix(parser): stop warning on normal observation responses (#2074)
parseSummary runs on every agent response, not just summary turns. When the turn is a normal observation, the LLM correctly emits <observation> and no <summary> — but the fallthrough branch from #1345 treated this as prompt misbehavior and logged "prompt conditioning may need strengthening" every time. That assumption stopped holding after #1633 refactored the caller to always invoke parseSummary with a coerceFromObservation flag. Gate the whole observation-on-summary path on coerceFromObservation. On a real summary turn, coercion still runs and logs the legitimate "coercion failed" warning when the response has no usable content. On an observation turn, parseSummary returns null silently, which is the correct behavior. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
+191
-191
File diff suppressed because one or more lines are too long
+11
-11
File diff suppressed because one or more lines are too long
+16
-15
@@ -137,22 +137,23 @@ export function parseSummary(text: string, sessionId?: number, coerceFromObserva
|
|||||||
const summaryMatch = summaryRegex.exec(text);
|
const summaryMatch = summaryRegex.exec(text);
|
||||||
|
|
||||||
if (!summaryMatch) {
|
if (!summaryMatch) {
|
||||||
// When the LLM returns <observation> tags instead of <summary> tags,
|
// When the LLM returns <observation> tags instead of <summary> tags on a
|
||||||
// coerce the observation content into summary fields rather than discarding it.
|
// summary turn, coerce the observation content into summary fields rather
|
||||||
// This breaks the infinite retry loop described in #1633: without coercion,
|
// than discarding it. This breaks the infinite retry loop described in
|
||||||
// the summary is silently dropped, the session completes without a summary,
|
// #1633: without coercion, the summary is silently dropped, the session
|
||||||
// a new session is spawned with an ever-growing prompt, and the cycle repeats.
|
// completes without a summary, a new session is spawned with an ever-growing
|
||||||
// Only coerce when explicitly requested (i.e., when a summarize message was sent).
|
// prompt, and the cycle repeats.
|
||||||
if (/<observation>/.test(text)) {
|
//
|
||||||
if (coerceFromObservation) {
|
// parseSummary is called on every response (see ResponseProcessor), not just
|
||||||
const coerced = coerceObservationToSummary(text, sessionId);
|
// summary turns — so the absence of <summary> in an observation response is
|
||||||
if (coerced) {
|
// expected, not a prompt-conditioning failure. Only act when the caller
|
||||||
return coerced;
|
// actually expected a summary (coerceFromObservation=true).
|
||||||
}
|
if (coerceFromObservation && /<observation>/.test(text)) {
|
||||||
logger.warn('PARSER', 'Summary response contained <observation> tags instead of <summary> — coercion failed, no usable content', { sessionId });
|
const coerced = coerceObservationToSummary(text, sessionId);
|
||||||
} else {
|
if (coerced) {
|
||||||
logger.warn('PARSER', 'Summary response contained <observation> tags instead of <summary> — prompt conditioning may need strengthening', { sessionId });
|
return coerced;
|
||||||
}
|
}
|
||||||
|
logger.warn('PARSER', 'Summary response contained <observation> tags instead of <summary> — coercion failed, no usable content', { sessionId });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user