fix: block memory agent prose-skip responses at prompt and runtime levels

Observer prompt now explicitly requires XML observation blocks or empty
responses — prose explanations like "Skipping" are discarded. ResponseProcessor
logs a warning when non-XML content is received. Recording focus expanded to
include concrete debugging findings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-04-04 19:39:01 -07:00
parent 3b34feb779
commit 9063c5d8a7
5 changed files with 72 additions and 5 deletions
+20
View File
@@ -0,0 +1,20 @@
import { describe, expect, it } from 'bun:test';
import { buildObservationPrompt } from '../../src/sdk/prompts.js';
describe('buildObservationPrompt', () => {
it('instructs the observer to avoid prose skip responses', () => {
const prompt = buildObservationPrompt({
id: 1,
tool_name: 'exec_command',
tool_input: JSON.stringify({ cmd: 'pwd' }),
tool_output: JSON.stringify({ output: '/repo' }),
created_at_epoch: Date.now(),
cwd: '/repo',
});
expect(prompt).toContain('Return either one or more <observation>...</observation> blocks, or an empty response');
expect(prompt).toContain('Concrete debugging findings from logs, queue state, database rows, session routing, or code-path inspection');
expect(prompt).toContain('Never reply with prose such as "Skipping", "No substantive tool executions"');
});
});
@@ -212,6 +212,36 @@ describe('ResponseProcessor', () => {
});
});
describe('non-XML observer responses', () => {
it('warns when the observer returns prose that will be discarded', async () => {
const session = createMockSession();
const responseText = 'Skipping — repeated log scan with no new findings.';
await processAgentResponse(
responseText,
session,
mockDbManager,
mockSessionManager,
mockWorker,
100,
null,
'TestAgent'
);
expect(logger.warn).toHaveBeenCalledWith(
'PARSER',
'TestAgent returned non-XML response; observation content was discarded',
expect.objectContaining({
sessionId: 1,
preview: responseText
})
);
const [, , observations, summary] = mockStoreObservations.mock.calls[0];
expect(observations).toHaveLength(0);
expect(summary).toBeNull();
});
});
describe('parsing summary from XML response', () => {
it('should parse summary from response', async () => {
const session = createMockSession();