diff --git a/cmd/opencodereview/shared.go b/cmd/opencodereview/shared.go index bfa89989..c1fb8e61 100644 --- a/cmd/opencodereview/shared.go +++ b/cmd/opencodereview/shared.go @@ -405,7 +405,7 @@ func emitRunResult( if !machineReadable { telemetry.PrintTraceSummary(ag.FilesReviewed(), int64(len(comments)), ag.TotalInputTokens(), ag.TotalOutputTokens(), ag.TotalTokensUsed(), - ag.TotalCacheReadTokens(), ag.TotalCacheWriteTokens(), duration) + ag.TotalCacheReadTokens(), ag.TotalCacheWriteTokens(), duration, ag.SessionID()) } if outputFormat == "json" { diff --git a/internal/telemetry/events.go b/internal/telemetry/events.go index 34d3994a..64616e73 100644 --- a/internal/telemetry/events.go +++ b/internal/telemetry/events.go @@ -69,7 +69,8 @@ func FormatDuration(dur time.Duration) string { } // PrintTraceSummary prints a one-line summary of the review to stdout. -func PrintTraceSummary(filesReviewed, commentsGenerated int64, inputTokens, outputTokens, totalTokens int64, cacheReadTokens, cacheWriteTokens int64, duration time.Duration) { +// If sessionID is non-empty, an "[ocr] Session: " line follows the summary. +func PrintTraceSummary(filesReviewed, commentsGenerated int64, inputTokens, outputTokens, totalTokens int64, cacheReadTokens, cacheWriteTokens int64, duration time.Duration, sessionID string) { elapsed := duration.Round(time.Second).String() if inputTokens > 0 || outputTokens > 0 { base := fmt.Sprintf("[ocr] Summary: %d file(s) reviewed, %d comment(s), ~%d token(s) used (input: ~%d, output: ~%d)", @@ -82,6 +83,9 @@ func PrintTraceSummary(filesReviewed, commentsGenerated int64, inputTokens, outp fmt.Fprintf(stdout.Writer(), "[ocr] Summary: %d file(s) reviewed, %d comment(s), ~%d token(s) used, %s elapsed\n", filesReviewed, commentsGenerated, totalTokens, elapsed) } + if sessionID != "" { + fmt.Fprintf(stdout.Writer(), "[ocr] Session: %s\n", sessionID) + } } // PrintToolCallStarted prints a line when a tool begins execution. diff --git a/internal/telemetry/events_test.go b/internal/telemetry/events_test.go index 3f6b5dc2..dfdcb57e 100644 --- a/internal/telemetry/events_test.go +++ b/internal/telemetry/events_test.go @@ -125,15 +125,29 @@ func TestPhaseEvent_WithError(t *testing.T) { } func TestPrintTraceSummary_WithTokenDetails(t *testing.T) { - PrintTraceSummary(5, 10, 1000, 200, 1200, 0, 0, 3*time.Second) + PrintTraceSummary(5, 10, 1000, 200, 1200, 0, 0, 3*time.Second, "") } func TestPrintTraceSummary_WithCacheTokens(t *testing.T) { - PrintTraceSummary(3, 2, 500, 100, 600, 200, 50, 2*time.Second) + PrintTraceSummary(3, 2, 500, 100, 600, 200, 50, 2*time.Second, "") } func TestPrintTraceSummary_NoTokenDetails(t *testing.T) { - PrintTraceSummary(2, 1, 0, 0, 500, 0, 0, 1*time.Second) + PrintTraceSummary(2, 1, 0, 0, 500, 0, 0, 1*time.Second, "") +} + +func TestPrintTraceSummary_WithSessionID(t *testing.T) { + // A non-empty session ID prints the session line after the summary. + // Mirrors the smoke-test style of the existing PrintTraceSummary tests; + // stdout.Writer() captures os.Stdout at init, so output text is not asserted here. + PrintTraceSummary(5, 10, 1000, 200, 1200, 0, 0, 3*time.Second, "3a7f2b1c-9d4e-4f8a-b2c1-6e7f8a9b0c1d") +} + +func TestPrintTraceSummary_WithoutSessionID(t *testing.T) { + // An empty session ID exercises the omit path (no session line printed). + // The empty case arises when session persistence is unavailable, not from + // preview mode (preview does not reach PrintTraceSummary). + PrintTraceSummary(2, 1, 0, 0, 500, 0, 0, 1*time.Second, "") } func TestPrintToolCallStarted_WithArgs(t *testing.T) {