Skip to content

feat(session-log): switch to local lazy dev log files - #40

Merged
HusseinBaraja merged 8 commits into
mainfrom
feat/owner-conversation-session-log
Apr 21, 2026
Merged

feat(session-log): switch to local lazy dev log files#40
HusseinBaraja merged 8 commits into
mainfrom
feat/owner-conversation-session-log

Conversation

@HusseinBaraja

@HusseinBaraja HusseinBaraja commented Apr 21, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added AI trace logging to capture detailed information about AI model interactions, including system prompts, grounding context, provider details, and API responses.
    • Implemented automatic retry logic for session startup when transient network failures occur.
  • Improvements

    • Enhanced conversation session log formatting with improved timestamp handling and structured payload organization for better readability and troubleshooting.

@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@HusseinBaraja has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 29 minutes and 1 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 29 minutes and 1 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d837aa50-9183-4d97-9e07-d117107ab13a

📥 Commits

Reviewing files that changed from the base of the PR and between 1a3d9e4 and 9fe7894.

📒 Files selected for processing (2)
  • packages/core/src/conversationSessionLog.ts
  • packages/rag/src/catalogChatAiTrace.ts
📝 Walkthrough

Walkthrough

This PR introduces structured background trace logging with AI diagnostic data capture, adds transient error handling with session manager retry logic, and propagates AI traces through conversation routing and RAG orchestration. Session identifiers now use local DD-MM-HH-mm format, and logging payloads shift from plain strings to discriminated union objects supporting both notes and AI trace data.

Changes

Cohort / File(s) Summary
Session Logging Infrastructure
packages/core/src/conversationSessionLog.ts, packages/core/src/conversationSessionLog.test.ts, packages/core/src/conversationSessionLogBackgroundPayload.ts
Restructured background trace entries to use payload: ConversationSessionLogBackgroundPayload (discriminated union: "note" or "ai") instead of plain details string. Added formatConversationSessionLogTimestamp for consistent local time rendering. Changed session ID generation to deterministic DD-MM-HH-mm format and added companyId/conversationId to session headers. Modified session path API to use repoRoot instead of logDirectory.
AI Trace Types & Builders
packages/rag/src/catalogChatAiTrace.ts, packages/rag/src/retrievalRewriteTrace.ts
Introduced CatalogChatAiTrace interface capturing event, systemPrompt, optional groundingContext, provider, optional usage, and apiResult. Added RetrievalRewriteTrace with extraction of system prompts from chat requests. Provided conversion helpers (toCatalogChatAiTrace, toAnswerGenerationAiTrace, withCatalogChatAiTraces, buildRetrievalRewriteTrace).
Bot Conversation Routing & Session Logging
apps/bot/src/customerConversationRouter.ts, apps/bot/src/customerConversationRouter.test.ts, apps/bot/src/customerConversationLogHelpers.ts
Added appendConversationSessionLogAiTracesSafely helper to write AI traces as background entries. Updated assistant timeline entries to use structured payload: { kind: "note", text: ... } instead of details. Wired orchestrator-provided response.aiTraces into session log via new helper.
Worker Assistant Session Logging
apps/worker/src/pendingAssistantSessionLog.ts, apps/worker/src/pendingAssistantReconciliation.test.ts
Replaced details: string field with note: string in session log append input. Changed logged entries (reconciled, analytics\_replayed, owner\_notification\_replayed) to emit payload: { kind: "note", text: ... } structure.
RAG Orchestration AI Traces
packages/rag/src/index.ts, packages/rag/src/catalogChat.test.ts, packages/rag/src/catalogChatLogging.ts, packages/rag/src/retrievalRewrite.ts, packages/rag/src/retrievalRewrite.test.ts
Extended CatalogChatResult with optional aiTraces field. Added catalogChatLogging module with query/provider text summarizers and log context builders. Updated retrieval rewrite to attach optional trace field to rewrite attempts. Integrated trace collection and propagation throughout response path in orchestrator.
Session Manager Retry Logic
apps/bot/src/sessionManager.ts, apps/bot/src/sessionManagerStartupRetry.ts, apps/bot/src/sessionManager.test.ts
Introduced retryInitialSessionReconcile with bounded retry loop for transient Convex transport errors using fixed delay sequence [250, 500, 1000] ms. Updated session manager to use dedicated bound logger and invoke retry helper on startup. Added test coverage for transient failure retry scheduling.
Convex Transport Error Detection
packages/core/src/convexTransport.ts, packages/core/src/convexTransport.test.ts
Expanded RetryableConvexTransportErrorLike to support error cause chain traversal. Added UND_ERR_CONNECT_TIMEOUT to recognized transient codes and multi-pattern message matching (TRANSIENT_CONVEX_MESSAGE_PATTERNS). Enhanced isTransientConvexTransportError to inspect nested error chains up to bounded depth.
Documentation & Scripts
CONTEXT.md, scripts/dev-session-log.ts, scripts/dev-session-log.test.ts
Removed language/relationships/example dialogue sections from CONTEXT.md. Updated dev session log utilities to use local DD-MM-HH-mm session IDs and repoRoot instead of explicit logDirectory path construction.

Sequence Diagram(s)

sequenceDiagram
    participant Chat as Chat Request
    participant Orch as Orchestrator
    participant Rewrite as Rewrite Service
    participant Provider as LLM Provider
    participant Trace as Trace Builder
    participant Log as Session Log

    Chat->>Orch: query with context
    Orch->>Rewrite: attempt retrieval rewrite
    Rewrite->>Provider: rewrite request
    Provider-->>Rewrite: rewrite response
    Rewrite->>Trace: buildRetrievalRewriteTrace(request, response)
    Trace-->>Rewrite: RetrievalRewriteTrace (systemPrompt, provider, usage, apiResult)
    Rewrite-->>Orch: RetrievalRewriteAttempt with trace
    
    Orch->>Provider: answer generation request
    Provider-->>Orch: provider response (text, usage)
    Orch->>Trace: toAnswerGenerationAiTrace(systemPrompt, grounding, provider, usage, apiResult)
    Trace-->>Orch: CatalogChatAiTrace (ai.answer_generation)
    
    Orch->>Log: appendConversationSessionLogAiTracesSafely(aiTraces)
    Log-->>Log: write bts entries with payload.kind="ai"
    Orch-->>Chat: CatalogChatResult with aiTraces
Loading
sequenceDiagram
    participant Boot as Bot Startup
    participant Mgr as Session Manager
    participant Retry as Retry Handler
    participant Store as Store (Convex)
    participant Logger as Logger

    Boot->>Mgr: initialize
    Mgr->>Retry: retryInitialSessionReconcile(reconcileManagedSessions, onRetry)
    Retry->>Store: reconcile managed sessions (attempt 1)
    Store-->>Retry: transient error (UND_ERR_CONNECT_TIMEOUT)
    
    Retry->>Logger: warn bot.session.initial_reconcile_retry_scheduled (attempt 2, delay 250ms)
    Retry->>Retry: sleep(250)
    
    Retry->>Store: reconcile managed sessions (attempt 2)
    Store-->>Retry: transient error (socket closed)
    
    Retry->>Logger: warn bot.session.initial_reconcile_retry_scheduled (attempt 3, delay 500ms)
    Retry->>Retry: sleep(500)
    
    Retry->>Store: reconcile managed sessions (attempt 3)
    Store-->>Retry: success
    Retry-->>Mgr: resolved
    Mgr-->>Boot: ready
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Traces flow like morning dew,
Through AI paths both old and new,
Session logs now tell their tale,
With payloads structured—none shall fail!
Retries dance on bounded spree, 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main architectural change: converting session log files from eager, centralized storage to local, lazily-created development logs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/owner-conversation-session-log

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/conversationSessionLog.test.ts`:
- Around line 14-21: The session id produced by
createConversationSessionLogSessionId uses DD-MM-HH-mm which can collide for
sessions started in the same minute and cause logs at paths built by
createConversationSessionLogSessionPath to be commingled or overwritten; update
createConversationSessionLogSessionId to increase uniqueness (e.g., include
seconds to produce DD-MM-HH-mm-ss or append a short random suffix) and ensure
downstream code that relies on the format
(createConversationSessionLogSessionPath) still composes file names correctly or
is updated to accept the extended id format; alternatively, if
minute-granularity is intentional, add a docstring comment on
createConversationSessionLogSessionId and
createConversationSessionLogSessionPath to document the behavior.

In `@packages/core/src/conversationSessionLog.ts`:
- Line 1: When mkdir throws EEXIST and the code proceeds to appendFile, validate
that the existing file belongs to the same conversation/company by reading and
parsing its header before appending; if the header does not match the in-memory
conversationIdentity, fail closed (throw or return error) instead of appending.
Update the logic in conversationSessionLog (the code paths using mkdir,
appendFile, writeFile and the header-write routine referenced around lines 1 and
165-171) to: on EEXIST read the existing file, parse/compare its header to
conversationIdentity, and only call appendFile when it matches; otherwise abort
and surface an error.
- Around line 75-80: The session ID generator in conversationSessionLog.ts
currently builds IDs with toTwoDigits(value.getDate()),
toTwoDigits(value.getMonth() + 1), toTwoDigits(value.getHours()), and
toTwoDigits(value.getMinutes()), which can collide for sessions started in the
same minute; modify the generator (the code calling toTwoDigits and producing
the sessionId used in `${sessionId}.md`) to append higher-precision time
(seconds and/or milliseconds via value.getSeconds() and value.getMilliseconds())
or a short random suffix (e.g., 4 hex chars) while preserving the readable
DD-MM-HH-mm prefix so each sessionId is unique even on quick restarts.

In `@packages/rag/src/catalogChatAiTrace.ts`:
- Around line 13-38: The Catalog AI trace builders inconsistently include usage:
toCatalogChatAiTrace and toAnswerGenerationAiTrace always set usage (potentially
as undefined); change both factories to only include usage when defined by
conditionally spreading it like groundingContext is handled so that
CatalogChatAiTrace objects do not contain an explicit usage: undefined property
— update toCatalogChatAiTrace and toAnswerGenerationAiTrace to check trace.usage
/ input.usage and spread { usage: ... } only when present.

In `@packages/rag/src/retrievalRewriteTrace.ts`:
- Around line 10-22: The extractSystemPromptFromRequest arrow function
unnecessarily wraps its logic in an IIFE; remove the immediate-invoked function
and make the body direct, and when handling request.messages (ChatRequest) avoid
mapping non-text parts to empty strings—filter parts that have "text" first and
then join their text fields so you don't generate extra blank lines; update the
function that inspects request.messages and the conditional handling of content
accordingly.

In `@scripts/dev-session-log.ts`:
- Around line 12-16: The session file names created by
createConversationSessionLogSessionPath use the minute-level ID from
createConversationSessionLogSessionId, causing collisions for runs started
within the same minute; update the session ID generation to append a compact
unique suffix (e.g., input.now.getTime() or input.now.toISOString() millis + a
short random or process.pid/crypto.randomUUID() fragment) while preserving the
human-readable prefix produced by createConversationSessionLogSessionId, or
alter createConversationSessionLogSessionPath to tack such a unique token onto
the filename it builds so each run yields a unique <prefix>-<unique> session
path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4d7db13d-fa7e-4401-be94-72d1d0eb4fb2

📥 Commits

Reviewing files that changed from the base of the PR and between a91d6f8 and 1a3d9e4.

📒 Files selected for processing (23)
  • CONTEXT.md
  • apps/bot/src/customerConversationLogHelpers.ts
  • apps/bot/src/customerConversationRouter.test.ts
  • apps/bot/src/customerConversationRouter.ts
  • apps/bot/src/sessionManager.test.ts
  • apps/bot/src/sessionManager.ts
  • apps/bot/src/sessionManagerStartupRetry.ts
  • apps/worker/src/pendingAssistantReconciliation.test.ts
  • apps/worker/src/pendingAssistantSessionLog.ts
  • packages/core/src/conversationSessionLog.test.ts
  • packages/core/src/conversationSessionLog.ts
  • packages/core/src/conversationSessionLogBackgroundPayload.ts
  • packages/core/src/convexTransport.test.ts
  • packages/core/src/convexTransport.ts
  • packages/rag/src/catalogChat.test.ts
  • packages/rag/src/catalogChatAiTrace.ts
  • packages/rag/src/catalogChatLogging.ts
  • packages/rag/src/index.ts
  • packages/rag/src/retrievalRewrite.test.ts
  • packages/rag/src/retrievalRewrite.ts
  • packages/rag/src/retrievalRewriteTrace.ts
  • scripts/dev-session-log.test.ts
  • scripts/dev-session-log.ts
💤 Files with no reviewable changes (1)
  • CONTEXT.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: For core logic .ts files, do not add a new responsibility to an existing file when it should be a sibling module
No new core logic .ts file may exceed 240 LOC without an explicit entry in modularity-policy.json
If a core logic file already exceeds 240 LOC, it must not grow unless its modularity-policy.json entry is intentionally updated with rationale
Files classified as must_split in modularity-policy.json are debt containers: patches are allowed, but adding unrelated responsibilities is not

Files:

  • scripts/dev-session-log.ts
  • apps/bot/src/sessionManager.test.ts
  • apps/bot/src/sessionManager.ts
  • packages/core/src/convexTransport.test.ts
  • apps/bot/src/customerConversationRouter.test.ts
  • apps/bot/src/customerConversationRouter.ts
  • scripts/dev-session-log.test.ts
  • apps/bot/src/sessionManagerStartupRetry.ts
  • packages/core/src/convexTransport.ts
  • packages/rag/src/retrievalRewriteTrace.ts
  • packages/rag/src/retrievalRewrite.test.ts
  • apps/bot/src/customerConversationLogHelpers.ts
  • packages/rag/src/catalogChat.test.ts
  • apps/worker/src/pendingAssistantReconciliation.test.ts
  • packages/rag/src/catalogChatAiTrace.ts
  • apps/worker/src/pendingAssistantSessionLog.ts
  • packages/rag/src/retrievalRewrite.ts
  • packages/core/src/conversationSessionLog.ts
  • packages/rag/src/catalogChatLogging.ts
  • packages/core/src/conversationSessionLog.test.ts
  • packages/rag/src/index.ts
  • packages/core/src/conversationSessionLogBackgroundPayload.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use the @cs/* path aliases from tsconfig.base.json for cross-package imports

Files:

  • scripts/dev-session-log.ts
  • apps/bot/src/sessionManager.test.ts
  • apps/bot/src/sessionManager.ts
  • packages/core/src/convexTransport.test.ts
  • apps/bot/src/customerConversationRouter.test.ts
  • apps/bot/src/customerConversationRouter.ts
  • scripts/dev-session-log.test.ts
  • apps/bot/src/sessionManagerStartupRetry.ts
  • packages/core/src/convexTransport.ts
  • packages/rag/src/retrievalRewriteTrace.ts
  • packages/rag/src/retrievalRewrite.test.ts
  • apps/bot/src/customerConversationLogHelpers.ts
  • packages/rag/src/catalogChat.test.ts
  • apps/worker/src/pendingAssistantReconciliation.test.ts
  • packages/rag/src/catalogChatAiTrace.ts
  • apps/worker/src/pendingAssistantSessionLog.ts
  • packages/rag/src/retrievalRewrite.ts
  • packages/core/src/conversationSessionLog.ts
  • packages/rag/src/catalogChatLogging.ts
  • packages/core/src/conversationSessionLog.test.ts
  • packages/rag/src/index.ts
  • packages/core/src/conversationSessionLogBackgroundPayload.ts
🔇 Additional comments (9)
packages/core/src/convexTransport.ts (1)

1-58: LGTM — cause-chain traversal is bounded and safe.

getErrorChain caps traversal at MAX_CAUSE_DEPTH = 6, so a cyclic cause reference cannot infinite-loop. The added UND_ERR_CONNECT_TIMEOUT code and the three substring patterns correctly cover the undici/Convex connectivity failures that should be retried. Pattern matching is substring-based on specific, unambiguous strings, so false-positive risk is low.

packages/core/src/convexTransport.test.ts (1)

11-55: LGTM — coverage matches the new transient cases.

The three added cases (connectivity message, UND_ERR_CONNECT_TIMEOUT code, and a nested cause chain) exercise each branch added to isTransientConvexTransportError.

apps/bot/src/sessionManagerStartupRetry.ts (1)

10-36: LGTM — retry loop terminates deterministically.

The for (;;) loop is bounded in practice: once attempt exceeds INITIAL_RECONCILE_RETRY_DELAYS_MS.length, retryDelayMs is undefined and the caught error is rethrown. Delays [250, 500, 1000] cap startup latency at ~1.75s before falling through to the heartbeat retry path, which is a reasonable tradeoff.

Minor observation (non-blocking): there is no cancellation signal, so a SIGINT during the retry window cannot short-circuit the sleep. Given the sub-2-second worst case and that process signal handlers are installed by startTenantSessionManager only after this returns, this is acceptable.

apps/bot/src/sessionManager.ts (1)

277-277: LGTM — bound logger and retry wiring are consistent.

sessionManagerLogger is bound with { runtimeOwnerId, surface: "session_manager" } and reused for the retry-scheduled warn (line 941), the final initial-reconcile error (line 953), and the ongoing reconcile failure (line 892), giving a uniform surface in logs. The explicit runtimeOwnerId/surface fields in each payload are redundant with the bindings but preserve the existing payload contract that tests rely on.

The catch block intentionally swallows the terminal error so the heartbeat loop can keep attempting reconciliation — consistent with the pre-existing "continues manager startup after the initial reconcile fails" behavior.

Also applies to: 939-961

apps/bot/src/sessionManager.test.ts (1)

967-1031: LGTM — test correctly validates the transient-retry path.

The test uses new Error("fetch failed", { cause: new Error("Connect Timeout Error ...") }) to exercise the cause-chain detection added in convexTransport.ts, asserts the bot.session.initial_reconcile_retry_scheduled warn payload (with retryDelayMs: 250), and asserts that bot.session.initial_reconcile_failed is not emitted on the transient path.

Minor note (non-blocking): because sleep() in retryInitialSessionReconcile uses the real setTimeout, this test adds ~250 ms of real wall-clock latency per run. If retry-delay timing becomes a test-performance concern later, consider injecting a sleep/clock into retryInitialSessionReconcile.

apps/bot/src/customerConversationLogHelpers.ts (1)

98-107: No action needed — apiResult is already properly declared and rendered in the core payload type.

The ConversationSessionLogAiPayload interface in packages/core/src/conversationSessionLogBackgroundPayload.ts already includes apiResult: unknown (line 12), and the markdown renderer already explicitly outputs it (line 66). The helper function correctly passes the field through without any type mismatch.

			> Likely an incorrect or invalid review comment.
apps/bot/src/customerConversationRouter.ts (1)

181-181: Modularity-policy exception already exists with explicit rationale—revert this comment.

The modularity-policy.json entry for this file explicitly sets maxLines: 570 with documented reason: "Couples persistence, orchestration, delivery, analytics, and handoff side effects." The file is at its allowed limit, not exceeding it. Line 181 delegates AI trace persistence to a helper module (customerConversationLogHelpers), extending the existing session-log persistence concern rather than introducing a new unrelated responsibility. No further action required.

			> Likely an incorrect or invalid review comment.
packages/core/src/conversationSessionLog.test.ts (2)

107-110: No issue found. The function formatConversationSessionLogTimestamp properly accepts both Date and number types, as shown by its signature (input: Date | number): string and implementation that converts numeric inputs to Date objects. The calls at lines 107-110 with epoch-millisecond timestamps are type-safe and correct.

			> Likely an incorrect or invalid review comment.

41-48: Implementation is timezone-stable.

The formatConversationSessionLogTimestamp implementation correctly derives hour/minute/second from Date.prototype.getHours(), getMinutes(), and getSeconds() (local time), matching how createConversationSessionLogSessionId formats components. Tests will not fail across timezones.

Comment thread packages/core/src/conversationSessionLog.test.ts
Comment thread packages/core/src/conversationSessionLog.ts Outdated
Comment thread packages/core/src/conversationSessionLog.ts
Comment thread packages/rag/src/catalogChatAiTrace.ts
Comment thread packages/rag/src/retrievalRewriteTrace.ts
Comment thread scripts/dev-session-log.ts
HusseinBaraja and others added 2 commits April 21, 2026 18:35
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@HusseinBaraja
HusseinBaraja merged commit d021a02 into main Apr 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant