diff --git a/src/message-runtime-prompts.test.ts b/src/message-runtime-prompts.test.ts index 83b9234..1d04561 100644 --- a/src/message-runtime-prompts.test.ts +++ b/src/message-runtime-prompts.test.ts @@ -111,7 +111,9 @@ describe('message-runtime-prompts carry-forward guidance', () => { 'Do not repeat, continue, or answer that carried-forward final directly.', ); }); +}); +describe('message-runtime-prompts output-only context', () => { it('keeps reviewer pending prompts output-only when current task outputs exist', () => { const prompt = buildReviewerPendingPrompt({ chatJid: 'group@test', @@ -196,6 +198,34 @@ describe('message-runtime-prompts carry-forward guidance', () => { expect(prompt).not.toContain('예전 유저 지시'); }); + it('limits arbiter prompts to recent turn outputs', () => { + const prompt = buildArbiterPromptForTask({ + task: makeTask({ status: 'arbiter_requested' }), + chatJid: 'group@test', + timezone: 'UTC', + turnOutputs: Array.from({ length: 8 }, (_, index) => { + const turnNumber = index + 1; + return makeTurnOutput( + `arbiter-context-output-${String(turnNumber).padStart(2, '0')}`, + turnNumber % 2 === 0 ? 'reviewer' : 'owner', + { + id: turnNumber, + turn_number: turnNumber, + created_at: `2026-04-20T02:${String(turnNumber).padStart(2, '0')}:00.000Z`, + }, + ); + }), + recentMessages: [makeHumanMessage('예전 유저 지시')], + labeledRecentMessages: [makeHumanMessage('예전 유저 지시')], + }); + + expect(prompt).not.toContain('arbiter-context-output-01'); + expect(prompt).not.toContain('arbiter-context-output-02'); + expect(prompt).toContain('arbiter-context-output-03'); + expect(prompt).toContain('arbiter-context-output-08'); + expect(prompt).not.toContain('예전 유저 지시'); + }); + it('preserves turn output order instead of timestamp interleaving', () => { const prompt = buildReviewerPendingPrompt({ chatJid: 'group@test', diff --git a/src/message-runtime-prompts.ts b/src/message-runtime-prompts.ts index f7ec805..58f0d5a 100644 --- a/src/message-runtime-prompts.ts +++ b/src/message-runtime-prompts.ts @@ -8,6 +8,8 @@ const CARRIED_FORWARD_OWNER_FINAL_MARKER = const CARRIED_FORWARD_OWNER_FINAL_GUIDANCE = `System note: If you see a message beginning with "${CARRIED_FORWARD_OWNER_FINAL_MARKER}", treat it as background only. Do not repeat, continue, or answer that carried-forward final directly. Respond only to the latest human request and the current task.`; +const ARBITER_TURN_OUTPUT_CONTEXT_LIMIT = 6; + function turnOutputsToMessages( outputs: PairedTurnOutput[], chatJid: string, @@ -35,6 +37,16 @@ function mergeHumanAndTurnOutputMessages( ].sort((a, b) => a.timestamp.localeCompare(b.timestamp)); } +function latestTurnOutputs( + outputs: PairedTurnOutput[], + limit: number, +): PairedTurnOutput[] { + if (outputs.length <= limit) { + return outputs; + } + return outputs.slice(-limit); +} + function hasCarriedForwardOwnerFinal(outputs: PairedTurnOutput[]): boolean { return outputs.some((output) => output.output_text.startsWith(CARRIED_FORWARD_OWNER_FINAL_MARKER), @@ -136,7 +148,13 @@ export function buildArbiterPromptForTask(args: { }): string { const messages = args.turnOutputs.length > 0 - ? turnOutputsToMessages(args.turnOutputs, args.chatJid) + ? turnOutputsToMessages( + latestTurnOutputs( + args.turnOutputs, + ARBITER_TURN_OUTPUT_CONTEXT_LIMIT, + ), + args.chatJid, + ) : args.labeledRecentMessages; return buildArbiterContextPrompt({