Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/agents/core/session/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface BaseNormalizedMessage {
/**
* Correlation status
*/
export type CorrelationStatus = 'pending' | 'matched' | 'failed';
export type CorrelationStatus = 'pending' | 'matched' | 'failed' | 'file_not_found';

/**
* Correlation result
Expand Down
32 changes: 29 additions & 3 deletions src/cli/commands/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -807,9 +807,22 @@ async function createSessionRecord(event: SessionStartEvent, sessionId: string,
existing.status = 'active';
if (gitBranch) existing.gitBranch = gitBranch;
if (remoteRepository) existing.repository = remoteRepository;

// Check if the transcript file actually exists on disk before marking correlation as matched
const { existsSync } = await import('node:fs');
const transcriptFileExists = event.transcript_path ? existsSync(event.transcript_path) : false;
const correlationStatus = transcriptFileExists ? 'matched' as const : 'file_not_found' as const;

if (!transcriptFileExists && event.transcript_path) {
logger.warn(
`[hook:SessionStart] Transcript path reported but file does not exist: ${event.transcript_path}. ` +
`Correlation status set to 'file_not_found' to prevent metrics processing failures.`
);
}

existing.correlation = {
...existing.correlation,
status: 'matched',
status: correlationStatus,
...(event.session_id && { agentSessionId: event.session_id }),
...(event.transcript_path && { agentSessionFile: event.transcript_path }),
};
Expand Down Expand Up @@ -837,12 +850,25 @@ async function createSessionRecord(event: SessionStartEvent, sessionId: string,
const { appendTranscriptMarker, appendAuditEvent, isExternalOrigin } = await import(
'../../agents/core/session/session-origin-audit.js'
);
const { existsSync } = await import('node:fs');
const origin =
getConfigValue(SESSION_ORIGIN_ENV_KEY, config) === SESSION_ORIGIN.EXTERNAL_RESUME
? SESSION_ORIGIN.EXTERNAL_RESUME
: undefined;

// Create session record with correlation already matched
// Check if the transcript file actually exists on disk before marking correlation as matched
// This prevents metrics processing from failing on non-existent files (e.g., interactive PTY sessions)
const transcriptFileExists = event.transcript_path ? existsSync(event.transcript_path) : false;
const correlationStatus = transcriptFileExists ? 'matched' as const : 'file_not_found' as const;

if (!transcriptFileExists && event.transcript_path) {
logger.warn(
`[hook:SessionStart] Transcript path reported but file does not exist: ${event.transcript_path}. ` +
`Correlation status set to 'file_not_found' to prevent metrics processing failures.`
);
}

// Create session record with correlation status based on file existence
const session = {
sessionId,
agentName,
Expand All @@ -856,7 +882,7 @@ async function createSessionRecord(event: SessionStartEvent, sessionId: string,
activeDurationMs: 0, // Initialize active duration tracking
...(origin && { origin }),
correlation: {
status: 'matched' as const,
status: correlationStatus,
agentSessionId: event.session_id,
agentSessionFile: event.transcript_path,
retryCount: 0
Expand Down
13 changes: 13 additions & 0 deletions src/providers/plugins/sso/session/SessionSyncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ export class SessionSyncer {
}

if (!sessionMetadata.correlation || sessionMetadata.correlation.status !== 'matched') {
// Handle 'file_not_found' status specially - this is expected for some interactive sessions
if (sessionMetadata.correlation?.status === 'file_not_found') {
logger.info(
`[SessionSyncer] Skipping session ${sessionId} - transcript file not found (status: file_not_found). ` +
`This is expected for some interactive PTY sessions where the transcript is not persisted.`
);
return {
success: true,
message: 'Session skipped - transcript file not found (expected for some interactive sessions)',
processorResults: {},
failedProcessors: []
};
}
return {
success: false,
message: `Session not correlated (status: ${sessionMetadata.correlation?.status || 'unknown'})`,
Expand Down
Loading