diff --git a/src/agent-runner.ts b/src/agent-runner.ts index 174baaa..cbb9722 100644 --- a/src/agent-runner.ts +++ b/src/agent-runner.ts @@ -269,7 +269,7 @@ export async function runAgentProcess( } }); - proc.on('close', (code) => { + proc.on('close', (code, signal) => { clearTimeout(timeout); const duration = Date.now() - startTime; @@ -286,6 +286,7 @@ export async function runAgentProcess( `Process: ${processName}`, `Duration: ${duration}ms`, `Exit Code: ${code}`, + `Signal: ${signal}`, `Had Streaming Output: ${hadStreamingOutput}`, ].join('\n'), ); @@ -299,6 +300,7 @@ export async function runAgentProcess( processName, duration, code, + signal, }, 'Agent timed out after output (idle cleanup)', ); @@ -316,6 +318,49 @@ export async function runAgentProcess( return; } + // Signal kill (SIGTERM/SIGKILL) from post-close cleanup or service + // restart. When the agent already delivered streaming output this is + // normal lifecycle — not an error. + if (code === null && signal) { + if (hadStreamingOutput) { + logger.info( + { + group: group.name, + chatJid: input.chatJid, + runId: input.runId, + processName, + duration, + signal, + }, + 'Agent terminated by signal after output delivery (normal cleanup)', + ); + outputChain.then(() => { + resolve({ status: 'success', result: null, newSessionId }); + }); + return; + } + // No output delivered before signal kill — genuine error + logger.error( + { + group: group.name, + chatJid: input.chatJid, + runId: input.runId, + processName, + duration, + signal, + }, + 'Agent killed by signal before producing output', + ); + outputChain.then(() => { + resolve({ + status: 'error', + result: null, + error: `Agent killed by ${signal} before producing output`, + }); + }); + return; + } + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const logFile = path.join( logsDir, @@ -335,6 +380,7 @@ export async function runAgentProcess( `AgentType: ${group.agentType || 'claude-code'}`, `Duration: ${duration}ms`, `Exit Code: ${code}`, + `Signal: ${signal}`, ``, ]; diff --git a/src/message-agent-executor.ts b/src/message-agent-executor.ts index 2a12dd9..112cf68 100644 --- a/src/message-agent-executor.ts +++ b/src/message-agent-executor.ts @@ -140,9 +140,6 @@ export async function runAgentForGroup( const wrappedOnOutput = onOutput ? async (output: AgentOutput) => { - if (persistSessionIds && output.newSessionId) { - deps.persistSession(group.folder, output.newSessionId); - } if ( persistSessionIds && isClaudeCodeAgent && @@ -150,6 +147,13 @@ export async function runAgentForGroup( ) { resetSessionRequested = true; } + if ( + persistSessionIds && + output.newSessionId && + !resetSessionRequested + ) { + deps.persistSession(group.folder, output.newSessionId); + } const evaluation = evaluateStreamedOutput(output, streamedState, { agentType: isClaudeCodeAgent ? 'claude-code' : 'codex', provider,