Persist paired turn output before final delivery

This commit is contained in:
ejclaw
2026-04-07 03:38:16 +09:00
parent 58b20fad6c
commit ae12b157be
2 changed files with 46 additions and 13 deletions

View File

@@ -1318,6 +1318,7 @@ describe('runAgentForGroup room memory', () => {
it('stores reviewer turn output before transitioning the paired task back to active', async () => { it('stores reviewer turn output before transitioning the paired task back to active', async () => {
const group = { ...makeGroup(), folder: 'test-group' }; const group = { ...makeGroup(), folder: 'test-group' };
const deps = makeDeps(); const deps = makeDeps();
const onOutput = vi.fn(async () => {});
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({ vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
chat_jid: 'group@test', chat_jid: 'group@test',
@@ -1397,7 +1398,7 @@ describe('runAgentForGroup room memory', () => {
chatJid: 'group@test', chatJid: 'group@test',
runId: 'run-reviewer-output-order', runId: 'run-reviewer-output-order',
forcedRole: 'reviewer', forcedRole: 'reviewer',
onOutput: async () => {}, onOutput,
}); });
expect(result).toBe('success'); expect(result).toBe('success');
@@ -1407,6 +1408,11 @@ describe('runAgentForGroup room memory', () => {
'reviewer', 'reviewer',
'DONE_WITH_CONCERNS\nreviewer feedback', 'DONE_WITH_CONCERNS\nreviewer feedback',
); );
expect(
vi.mocked(db.insertPairedTurnOutput).mock.invocationCallOrder[0],
).toBeLessThan(
onOutput.mock.invocationCallOrder[0],
);
expect( expect(
vi.mocked(db.insertPairedTurnOutput).mock.invocationCallOrder[0], vi.mocked(db.insertPairedTurnOutput).mock.invocationCallOrder[0],
).toBeLessThan( ).toBeLessThan(

View File

@@ -315,9 +315,29 @@ export async function runAgentForGroup(
const effectivePrompt = moaEnrichedPrompt; const effectivePrompt = moaEnrichedPrompt;
let pairedExecutionStatus: 'succeeded' | 'failed' = 'failed'; let pairedExecutionStatus: 'succeeded' | 'failed' = 'failed';
let pairedExecutionSummary: string | null = null; let pairedExecutionSummary: string | null = null;
let pairedFullOutput: string | null = null; let pairedFinalOutput: string | null = null;
let pairedExecutionCompleted = false; let pairedExecutionCompleted = false;
let pairedSawOutput = false; let pairedSawOutput = false;
let pairedTurnOutputPersisted = false;
const persistPairedTurnOutputIfNeeded = (completedRole: PairedRoomRole) => {
if (
!pairedExecutionContext ||
pairedTurnOutputPersisted ||
!pairedFinalOutput ||
pairedFinalOutput.length === 0
) {
return;
}
const turnNumber = getLatestTurnNumber(pairedExecutionContext.task.id) + 1;
insertPairedTurnOutput(
pairedExecutionContext.task.id,
turnNumber,
completedRole,
pairedFinalOutput,
);
pairedTurnOutputPersisted = true;
};
const maybeHandoffToCodex = ( const maybeHandoffToCodex = (
reason: AgentTriggerReason, reason: AgentTriggerReason,
@@ -483,7 +503,6 @@ export async function runAgentForGroup(
if (outputText && outputText.length > 0) { if (outputText && outputText.length > 0) {
pairedExecutionSummary = outputText.slice(0, 500); pairedExecutionSummary = outputText.slice(0, 500);
pairedFullOutput = outputText;
} else if ( } else if (
typeof output.error === 'string' && typeof output.error === 'string' &&
output.error.length > 0 output.error.length > 0
@@ -542,6 +561,22 @@ export async function runAgentForGroup(
if (outputText && outputText.length > 0) { if (outputText && outputText.length > 0) {
streamedOutputHandler.markVisibleOutput(); streamedOutputHandler.markVisibleOutput();
} }
if (
outputPhase === 'final' &&
output.status === 'success' &&
outputText &&
outputText.length > 0
) {
pairedFinalOutput = outputText;
try {
persistPairedTurnOutputIfNeeded(roomRoleContext?.role ?? 'owner');
} catch (err) {
log.warn(
{ pairedTaskId: pairedExecutionContext?.task.id ?? null, err },
'Failed to persist paired turn output before delivery',
);
}
}
if (onOutput) { if (onOutput) {
await onOutput(output); await onOutput(output);
} }
@@ -941,17 +976,9 @@ export async function runAgentForGroup(
!pairedSawOutput !pairedSawOutput
? 'failed' ? 'failed'
: completionStatus; : completionStatus;
// Store full output for direct inter-agent data passing (Discord-independent). if (effectiveStatus === 'succeeded') {
if (pairedFullOutput && effectiveStatus === 'succeeded') {
try { try {
const turnNumber = persistPairedTurnOutputIfNeeded(completedRole);
getLatestTurnNumber(pairedExecutionContext.task.id) + 1;
insertPairedTurnOutput(
pairedExecutionContext.task.id,
turnNumber,
completedRole,
pairedFullOutput,
);
} catch (err) { } catch (err) {
log.warn( log.warn(
{ pairedTaskId: pairedExecutionContext.task.id, err }, { pairedTaskId: pairedExecutionContext.task.id, err },