From 141898f7647446bf029a930d0d7b87a936c7b7c3 Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Tue, 31 Mar 2026 17:23:43 +0900 Subject: [PATCH] refactor: scope runtime log context --- src/logger.ts | 23 +++- src/message-agent-executor.test.ts | 13 ++- src/message-agent-executor.ts | 169 +++++++++-------------------- src/message-runtime.test.ts | 13 ++- src/message-runtime.ts | 49 +++++---- src/message-turn-controller.ts | 93 ++++------------ src/task-scheduler.test.ts | 13 ++- src/task-scheduler.ts | 47 +++----- 8 files changed, 167 insertions(+), 253 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index 7411010..398583b 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,4 +1,4 @@ -import pino from 'pino'; +import pino, { type Logger } from 'pino'; const serviceName = (process.env.ASSISTANT_NAME || 'claude').toLowerCase(); @@ -8,6 +8,27 @@ export const logger = pino({ transport: { target: 'pino-pretty', options: { colorize: true } }, }); +type LogBindings = Record; + +function normalizeBindings(bindings: LogBindings): LogBindings { + const normalized = Object.fromEntries( + Object.entries(bindings).filter(([, value]) => value !== undefined), + ); + + if ( + typeof normalized.groupName === 'string' && + normalized.group === undefined + ) { + normalized.group = normalized.groupName; + } + + return normalized; +} + +export function createScopedLogger(bindings: LogBindings): Logger { + return logger.child(normalizeBindings(bindings)); +} + // Route uncaught errors through pino so they get timestamps in stderr process.on('uncaughtException', (err) => { logger.fatal({ err }, 'Uncaught exception'); diff --git a/src/message-agent-executor.test.ts b/src/message-agent-executor.test.ts index fa379b3..127034c 100644 --- a/src/message-agent-executor.test.ts +++ b/src/message-agent-executor.test.ts @@ -70,14 +70,19 @@ vi.mock('./service-routing.js', () => ({ })), })); -vi.mock('./logger.js', () => ({ - logger: { +vi.mock('./logger.js', () => { + const mockLogger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), - }, -})); + child: (_bindings?: Record) => mockLogger, + }; + return { + logger: mockLogger, + createScopedLogger: (_bindings?: Record) => mockLogger, + }; +}); vi.mock('./agent-error-detection.js', async (importOriginal) => { const actual = diff --git a/src/message-agent-executor.ts b/src/message-agent-executor.ts index bd8effc..e865cb5 100644 --- a/src/message-agent-executor.ts +++ b/src/message-agent-executor.ts @@ -21,7 +21,7 @@ import { insertPairedTurnOutput, } from './db.js'; import { GroupQueue } from './group-queue.js'; -import { logger } from './logger.js'; +import { createScopedLogger } from './logger.js'; import { buildRoomMemoryBriefing } from './memento-client.js'; import { completePairedExecutionContext, @@ -193,6 +193,16 @@ export async function runAgentForGroup( pairedExecutionContext.envOverrides[effortKey] = roleConfig.effort; } } + const log = createScopedLogger({ + chatJid, + groupName: group.name, + groupFolder: group.folder, + runId, + messageSeqStart: startSeq ?? undefined, + messageSeqEnd: endSeq ?? undefined, + role: activeRole, + serviceId: effectiveServiceId, + }); // ── MoA prompt enrichment ───────────────────────────────────── // When MoA is enabled and we're in arbiter mode, query external API @@ -202,11 +212,8 @@ export async function runAgentForGroup( let moaEnrichedPrompt = prompt; const moaConfig = getMoaConfig(); if (arbiterMode && moaConfig.enabled && pairedExecutionContext) { - logger.info( + log.info( { - chatJid, - group: group.name, - runId, models: moaConfig.referenceModels.map((m) => m.name), }, 'MoA: collecting reference opinions before arbiter', @@ -224,9 +231,8 @@ export async function runAgentForGroup( const moaSection = formatMoaReferencesForPrompt(references); if (moaSection) { moaEnrichedPrompt = prompt + '\n' + moaSection; - logger.info( + log.info( { - chatJid, successCount: references.filter((r) => !r.error).length, totalCount: references.length, }, @@ -271,10 +277,7 @@ export async function runAgentForGroup( // Per-role fallback toggle const roleConfig = getRoleModelConfig(activeRole); if (!roleConfig.fallbackEnabled) { - logger.info( - { chatJid, group: group.name, role: activeRole, reason }, - 'Fallback disabled for role, skipping handoff', - ); + log.info({ reason }, 'Fallback disabled for role, skipping handoff'); return false; } @@ -291,8 +294,8 @@ export async function runAgentForGroup( end_seq: endSeq ?? null, reason: `arbiter-claude-${reason}`, }); - logger.warn( - { chatJid, group: group.name, runId, reason }, + log.warn( + { reason }, 'Claude arbiter unavailable, handed off arbiter turn to codex', ); return true; @@ -312,8 +315,8 @@ export async function runAgentForGroup( end_seq: endSeq ?? null, reason: `reviewer-claude-${reason}`, }); - logger.warn( - { chatJid, group: group.name, runId, reason }, + log.warn( + { reason }, 'Claude reviewer unavailable, handed off review turn to codex-review', ); return true; @@ -331,8 +334,8 @@ export async function runAgentForGroup( end_seq: endSeq ?? null, reason: `claude-${reason}`, }); - logger.warn( - { chatJid, group: group.name, runId, reason }, + log.warn( + { reason }, 'Claude unavailable, handed off current turn to codex-review', ); return true; @@ -352,14 +355,10 @@ export async function runAgentForGroup( if (pairedExecutionContext?.blockMessage) { pairedExecutionSummary = pairedExecutionContext.blockMessage.slice(0, 500); - logger.warn( + log.warn( { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - serviceId: roomRoleContext?.serviceId, - role: roomRoleContext?.role, + roomRoleServiceId: roomRoleContext?.serviceId, + roomRole: roomRoleContext?.role, }, 'Blocked reviewer execution before review-ready snapshot was available', ); @@ -445,11 +444,8 @@ export async function runAgentForGroup( typeof outputText === 'string' && output.status === 'success' ) { - logger.warn( + log.warn( { - chatJid, - group: group.name, - runId, reason: evaluation.newTrigger.reason, resultPreview: outputText.slice(0, 120), }, @@ -459,11 +455,8 @@ export async function runAgentForGroup( evaluation.newTrigger && typeof output.error === 'string' ) { - logger.warn( + log.warn( { - chatJid, - group: group.name, - runId, reason: evaluation.newTrigger.reason, errorPreview: output.error.slice(0, 120), }, @@ -474,11 +467,8 @@ export async function runAgentForGroup( } if (evaluation.suppressedAuthError) { - logger.warn( + log.warn( { - chatJid, - group: group.name, - runId, resultPreview: typeof outputText === 'string' ? outputText.slice(0, 120) @@ -490,11 +480,8 @@ export async function runAgentForGroup( } if (evaluation.suppressedRetryableSessionFailure) { - logger.warn( + log.warn( { - chatJid, - group: group.name, - runId, resultPreview: typeof outputText === 'string' ? outputText.slice(0, 160) @@ -518,17 +505,11 @@ export async function runAgentForGroup( } : undefined; - logger.info( - { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - provider: effectiveAgentType, - role: activeRole, - }, - `Using provider: ${effectiveAgentType}`, - ); + const providerLog = log.child({ + provider, + agentType: effectiveAgentType, + }); + providerLog.info('Using provider'); try { const output = await runAgentProcess( @@ -547,13 +528,8 @@ export async function runAgentForGroup( deps.persistSession(sessionFolder, output.newSessionId); } - logger.info( + providerLog.info( { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - provider, status: output.status, sawOutput: streamedState.sawOutput, }, @@ -595,8 +571,8 @@ export async function runAgentForGroup( getCodexAccountCount() > 1 && rotateCodexToken(lastRotationMessage) ) { - logger.info( - { chatJid, group: group.name, runId, reason: trigger.reason }, + log.info( + { reason: trigger.reason }, 'Codex account unhealthy, retrying with rotated account', ); @@ -611,15 +587,8 @@ export async function runAgentForGroup( continue; } - logger.error( - { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - provider: 'codex', - err: retryAttempt.error, - }, + log.error( + { provider: 'codex', err: retryAttempt.error }, 'Rotated Codex account also threw', ); return 'error'; @@ -627,14 +596,8 @@ export async function runAgentForGroup( const retryOutput = retryAttempt.output; if (!retryOutput) { - logger.error( - { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - provider: 'codex', - }, + log.error( + { provider: 'codex' }, 'Rotated Codex account produced no output object', ); return 'error'; @@ -671,11 +634,8 @@ export async function runAgentForGroup( continue; } - logger.error( + log.error( { - group: group.name, - chatJid, - runId, provider: 'codex', error: retryOutput.error, }, @@ -760,8 +720,7 @@ export async function runAgentForGroup( if (isRetryableClaudeSessionFailure(primaryAttempt)) { deps.clearSession(sessionFolder); - logger.warn( - { group: group.name, chatJid, runId }, + log.warn( 'Cleared poisoned Claude session before visible output, retrying fresh session', ); @@ -769,13 +728,9 @@ export async function runAgentForGroup( if (isRetryableClaudeSessionFailure(primaryAttempt)) { deps.clearSession(sessionFolder); - logger.warn( - { group: group.name, chatJid, runId }, - 'Fresh Claude retry also hit a retryable session failure', - ); + log.warn('Fresh Claude retry also hit a retryable session failure'); - logger.error( - { group: group.name, chatJid, runId }, + log.error( 'Retryable Claude session failure persisted after fresh retry', ); return 'error'; @@ -829,12 +784,8 @@ export async function runAgentForGroup( } } - logger.error( + log.error( { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, provider, err: primaryAttempt.error, }, @@ -845,16 +796,7 @@ export async function runAgentForGroup( const output = primaryAttempt.output; if (!output) { - logger.error( - { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, - provider, - }, - 'Agent produced no output object', - ); + log.error({ provider }, 'Agent produced no output object'); return 'error'; } @@ -894,8 +836,8 @@ export async function runAgentForGroup( (resetSessionRequested || shouldResetSessionOnAgentFailure(output)) ) { deps.clearSession(sessionFolder); - logger.warn( - { group: group.name, chatJid, runId, sessionFolder }, + log.warn( + { sessionFolder }, 'Cleared poisoned agent session after unrecoverable error', ); } @@ -945,11 +887,8 @@ export async function runAgentForGroup( } } - logger.error( + log.error( { - group: group.name, - chatJid, - runId, provider, error: output.error, }, @@ -988,11 +927,8 @@ export async function runAgentForGroup( ) { return 'success'; } - logger.error( + log.error( { - group: group.name, - chatJid, - runId, reason: primaryAttempt.streamedTriggerReason.reason, }, 'Agent trigger detected but could not be resolved', @@ -1006,8 +942,7 @@ export async function runAgentForGroup( primaryAttempt.sawSuccessNullResultWithoutOutput && !primaryAttempt.sawOutput ) { - logger.error( - { group: group.name, chatJid, runId }, + log.error( 'Agent returned success with null result and no visible output', ); return 'error'; @@ -1046,8 +981,8 @@ export async function runAgentForGroup( pairedFullOutput, ); } catch (err) { - logger.warn( - { taskId: pairedExecutionContext.task.id, err }, + log.warn( + { pairedTaskId: pairedExecutionContext.task.id, err }, 'Failed to store paired turn output', ); } diff --git a/src/message-runtime.test.ts b/src/message-runtime.test.ts index a390e36..bd17e04 100644 --- a/src/message-runtime.test.ts +++ b/src/message-runtime.test.ts @@ -154,14 +154,19 @@ vi.mock('./service-routing.js', () => ({ shouldServiceProcessChat: vi.fn(() => true), })); -vi.mock('./logger.js', () => ({ - logger: { +vi.mock('./logger.js', () => { + const mockLogger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), - }, -})); + child: (_bindings?: Record) => mockLogger, + }; + return { + logger: mockLogger, + createScopedLogger: (_bindings?: Record) => mockLogger, + }; +}); vi.mock('./sender-allowlist.js', () => ({ isTriggerAllowed: vi.fn(() => true), diff --git a/src/message-runtime.ts b/src/message-runtime.ts index c6238d2..d76595d 100644 --- a/src/message-runtime.ts +++ b/src/message-runtime.ts @@ -62,9 +62,12 @@ import { type PairedTask, type PairedTurnOutput, } from './types.js'; -import { logger } from './logger.js'; +import { createScopedLogger, logger } from './logger.js'; import { resolveGroupIpcPath } from './group-folder.js'; -import { getEffectiveChannelLease, hasReviewerLease } from './service-routing.js'; +import { + getEffectiveChannelLease, + hasReviewerLease, +} from './service-routing.js'; /** * Check if a message is a duplicate of the last bot final message in a paired room. @@ -637,10 +640,16 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { const { runId } = context; const group = deps.getRegisteredGroups()[chatJid]; if (!group) return true; + const log = createScopedLogger({ + chatJid, + groupName: group.name, + groupFolder: group.folder, + runId, + }); const channel = findChannel(deps.channels, chatJid); if (!channel) { - logger.warn({ chatJid }, 'No channel owns JID, skipping messages'); + log.warn('No channel owns JID, skipping messages'); return true; } @@ -747,9 +756,8 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { }; if (hasReviewerLease(chatJid)) { - logger.info( + log.info( { - chatJid, reviewerChannelName, foundChannel: foundReviewerChannel?.name ?? null, usingChannel: reviewerChannel.name, @@ -833,8 +841,7 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { lastMessage.seq, ); } - logger.info( - { chatJid, group: group.name, groupFolder: group.folder, runId }, + log.info( 'Skipping bot-only collaboration because no recent human message exists', ); return true; @@ -906,10 +913,7 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { hasImplicitContinuationWindow: continuationTracker.has, }) ) { - logger.info( - { chatJid, group: group.name, groupFolder: group.folder, runId }, - 'Skipping queued run because no allowed trigger was found', - ); + log.info('Skipping queued run because no allowed trigger was found'); return true; } @@ -957,13 +961,11 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { ); } - logger.info( + log.info( { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, messageCount: missedMessages.length, + messageSeqStart: startSeq, + messageSeqEnd: endSeq, }, 'Dispatching queued messages to agent', ); @@ -981,20 +983,21 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { }); if (!deliverySucceeded) { - logger.warn( - { chatJid, group: group.name, groupFolder: group.folder, runId }, + log.warn( + { + messageSeqStart: startSeq, + messageSeqEnd: endSeq, + }, 'Persisted produced output for delivery retry without rerunning agent', ); return false; } - logger.info( + log.info( { - chatJid, - group: group.name, - groupFolder: group.folder, - runId, visiblePhase, + messageSeqStart: startSeq, + messageSeqEnd: endSeq, }, 'Queued run completed successfully', ); diff --git a/src/message-turn-controller.ts b/src/message-turn-controller.ts index 798dbdb..e396e47 100644 --- a/src/message-turn-controller.ts +++ b/src/message-turn-controller.ts @@ -1,6 +1,6 @@ import { type AgentOutput } from './agent-runner.js'; import { getAgentOutputText } from './agent-output.js'; -import { logger } from './logger.js'; +import { createScopedLogger, logger } from './logger.js'; import { formatOutbound } from './router.js'; import { shouldResetSessionOnAgentFailure } from './session-recovery.js'; import { TASK_STATUS_MESSAGE_PREFIX } from './task-watch-status.js'; @@ -35,6 +35,7 @@ interface MessageTurnControllerOptions { } export class MessageTurnController { + private readonly log: typeof logger; private idleTimer: ReturnType | null = null; private visiblePhase: VisiblePhase = 'silent'; private hadError = false; @@ -56,21 +57,24 @@ export class MessageTurnController { private closeRequested = false; private typingActive = false; - constructor(private readonly options: MessageTurnControllerOptions) {} + constructor(private readonly options: MessageTurnControllerOptions) { + this.log = createScopedLogger({ + chatJid: options.chatJid, + groupName: options.group.name, + groupFolder: options.group.folder, + runId: options.runId, + }); + } private async setTyping( isTyping: boolean, source: string, extra?: Record, ): Promise { - logger.debug( + this.log.debug( { transition: isTyping ? 'typing:on' : 'typing:off', source, - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, ...extra, }, 'Typing indicator transition', @@ -85,12 +89,8 @@ export class MessageTurnController { async handleOutput(result: AgentOutput): Promise { if (this.terminalObserved()) { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, resultStatus: result.status, resultPhase: result.phase, }, @@ -108,13 +108,7 @@ export class MessageTurnController { this.hadError = true; this.options.clearSession(); this.requestAgentClose('poisoned-session-detected'); - logger.warn( - { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, - }, + this.log.warn( 'Detected poisoned Claude session from streamed output, forcing close', ); } @@ -123,12 +117,8 @@ export class MessageTurnController { const text = raw ? formatOutbound(raw) : null; if (raw) { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, resultStatus: result.status, resultPhase: result.phase, progressMessageId: this.progressMessageId, @@ -265,12 +255,8 @@ export class MessageTurnController { await this.finalizeProgressMessage(); await this.deliverFinalText(text); } else if (raw) { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, resultStatus: result.status, resultPhase: result.phase, progressMessageId: this.progressMessageId, @@ -312,13 +298,7 @@ export class MessageTurnController { !this.hadError && this.latestProgressTextForFinal ) { - logger.info( - { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, - }, + this.log.info( 'Sending a separate final message from the last progress output after agent completion', ); await this.finalizeProgressMessage(); @@ -503,12 +483,8 @@ export class MessageTurnController { this.progressEditFailCount = 0; } catch (err) { this.progressEditFailCount++; - logger.warn( + this.log.warn( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, progressMessageId: this.progressMessageId, progressEditFailCount: this.progressEditFailCount, err, @@ -539,12 +515,8 @@ export class MessageTurnController { } private async finalizeProgressMessage(): Promise { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, progressMessageId: this.progressMessageId, latestProgressText: this.latestProgressText, }, @@ -594,12 +566,8 @@ export class MessageTurnController { const rendered = this.renderProgressMessage(text); if (this.progressMessageId && this.options.channel.editMessage) { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, progressMessageId: this.progressMessageId, text, }, @@ -623,16 +591,7 @@ export class MessageTurnController { rendered, ); } catch (err) { - logger.warn( - { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, - err, - }, - 'Failed to send tracked progress message', - ); + this.log.warn({ err }, 'Failed to send tracked progress message'); this.latestProgressRendered = rendered; await this.options.channel.sendMessage(this.options.chatJid, rendered); this.visiblePhase = toVisiblePhase('progress'); @@ -640,12 +599,8 @@ export class MessageTurnController { } if (this.progressMessageId) { - logger.info( + this.log.info( { - chatJid: this.options.chatJid, - group: this.options.group.name, - groupFolder: this.options.group.folder, - runId: this.options.runId, progressMessageId: this.progressMessageId, text, }, @@ -692,11 +647,9 @@ export class MessageTurnController { } this.idleTimer = setTimeout(() => { - logger.debug( + this.log.debug( { - group: this.options.group.name, - chatJid: this.options.chatJid, - runId: this.options.runId, + idleTimeoutMs: this.options.idleTimeout, }, 'Idle timeout, closing agent stdin', ); diff --git a/src/task-scheduler.test.ts b/src/task-scheduler.test.ts index 0e8faf5..958ee6d 100644 --- a/src/task-scheduler.test.ts +++ b/src/task-scheduler.test.ts @@ -89,14 +89,19 @@ vi.mock('./agent-runner.js', async () => { }; }); -vi.mock('./logger.js', () => ({ - logger: { +vi.mock('./logger.js', () => { + const mockLogger = { debug: loggerDebugMock, info: vi.fn(), warn: vi.fn(), error: vi.fn(), - }, -})); + child: (_bindings?: Record) => mockLogger, + }; + return { + logger: mockLogger, + createScopedLogger: (_bindings?: Record) => mockLogger, + }; +}); vi.mock('./github-ci.js', () => ({ checkGitHubActionsRun: checkGitHubActionsRunMock, diff --git a/src/task-scheduler.ts b/src/task-scheduler.ts index dacfb84..2734ceb 100644 --- a/src/task-scheduler.ts +++ b/src/task-scheduler.ts @@ -25,7 +25,7 @@ import { resolveGroupIpcPath, resolveTaskRuntimeIpcPath, } from './group-folder.js'; -import { logger } from './logger.js'; +import { createScopedLogger, logger } from './logger.js'; import { createTaskStatusTracker } from './task-status-tracker.js'; import { runClaudeRotationLoop } from './provider-retry.js'; import { @@ -274,11 +274,15 @@ async function runTask( }); return; } + const log = createScopedLogger({ + taskId: task.id, + chatJid: task.chat_jid, + groupName: context.group.name, + groupFolder: task.group_folder, + runtimeTaskId: context.runtimeTaskId, + }); - logger.info( - { taskId: task.id, group: task.group_folder }, - 'Running scheduled task', - ); + log.info('Running scheduled task'); // Update tasks snapshot for agent to read (filtered by group) writeTaskSnapshotForGroup( @@ -360,12 +364,8 @@ async function runTask( typeof streamedOutput.result === 'string' && streamedOutput.status === 'success' ) { - logger.warn( + log.warn( { - taskId: task.id, - taskChatJid: task.chat_jid, - group: context.group.name, - groupFolder: task.group_folder, reason: evaluation.newTrigger.reason, resultPreview: streamedOutput.result.slice(0, 120), }, @@ -375,12 +375,8 @@ async function runTask( evaluation.newTrigger && typeof streamedOutput.error === 'string' ) { - logger.warn( + log.warn( { - taskId: task.id, - taskChatJid: task.chat_jid, - group: context.group.name, - groupFolder: task.group_folder, reason: evaluation.newTrigger.reason, errorPreview: streamedOutput.error.slice(0, 120), }, @@ -486,11 +482,8 @@ async function runTask( getCodexAccountCount() > 1 && rotateCodexToken(lastRotationMessage) ) { - logger.info( + log.info( { - taskId: task.id, - group: context.group.name, - groupFolder: task.group_folder, reason: trigger.reason, }, 'Codex account unhealthy, retrying scheduled task with rotated account', @@ -603,9 +596,8 @@ async function runTask( } } // end else (non-exhausted path) - logger.info( + log.info( { - taskId: task.id, agentType: context.taskAgentType, durationMs: Date.now() - startTime, }, @@ -613,7 +605,7 @@ async function runTask( ); } catch (err) { error = getErrorMessage(err); - logger.error({ taskId: task.id, error }, 'Task failed'); + log.error({ error }, 'Task failed'); } const durationMs = Date.now() - startTime; @@ -622,10 +614,7 @@ async function runTask( if (!currentTask) { await statusTracker.update('completed'); - logger.debug( - { taskId: task.id }, - 'Task deleted during execution, skipping persistence', - ); + log.debug('Task deleted during execution, skipping persistence'); return; } @@ -643,9 +632,8 @@ async function runTask( if (trigger.shouldRotate) { const rotated = getCodexAccountCount() > 1 && rotateCodexToken(error); if (rotated) { - logger.info( + log.info( { - taskId: task.id, agent: effectiveAgentType, reason: trigger.reason, }, @@ -661,9 +649,8 @@ async function runTask( if (trigger.shouldRetry) { const rotated = getTokenCount() > 1 && rotateToken(error); if (rotated) { - logger.info( + log.info( { - taskId: task.id, agent: effectiveAgentType, reason: trigger.reason, },