Skip to content

feat(dashboard): stream in-flight response bodies into live logs and interactions#495

Merged
SantiagoDePolonia merged 3 commits into
mainfrom
feat/realtime-preview-iterated-over
Jul 6, 2026
Merged

feat(dashboard): stream in-flight response bodies into live logs and interactions#495
SantiagoDePolonia merged 3 commits into
mainfrom
feat/realtime-preview-iterated-over

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What

Completes the remaining piece of #290: while a streamed completion is running, the dashboard now shows the response chunk-by-chunk in near-realtime — in the request log's Response pane and in the Interactions drawer — instead of waiting for the stream to finish. In-flight entries also get progress spinners wherever the UI previously showed "not captured" / "No interaction data available".

User-visible behavior

With LOGGING_ENABLED=true + LOGGING_LOG_BODIES=true and dashboard live logs on (all defaults except body logging):

  • Response pane of an expanded in-flight entry fills with the partially reconstructed response as the model generates, with a pulsing "streaming" badge; before the first chunk it shows a spinner ("Response in progress…") instead of "Response details were not captured."
  • Request pane of an in-flight entry shows "Waiting for request data…" with a spinner instead of the not-captured message.
  • Interactions drawer renders live entries directly from the live preview data (previously it fetched only the persisted store, so it showed "No interaction data available for this entry" until flush). It re-renders as chunks arrive, shows a spinner ("Waiting for request data…" / "Model is responding…") while the request is in flight, and hydrates the full persisted thread once the entry flushes.
  • The in-progress row pulse now persists throughout streaming (streamed entries carry status 200 from the moment headers are committed, which previously would have stopped it).

How

  • New audit.stream live event: StreamLogObserver publishes the partially reconstructed response body while the stream runs. Publishes are throttled to one per 500 ms per stream, skipped when no new content accumulated, and skipped entirely while no dashboard subscriber is connected (Broker.HasLiveSubscribers, surfaced through the logger via the new LiveSubscriberReporter interface). A subscriber connecting mid-stream catches up on the next tick because every preview carries the full accumulated body.
  • The broker fans partial bodies out to connected subscribers only; replay-ring/active-snapshot copies strip them (marked response_body_partial on fan-out copies, never marked response_body_captured, since the body is not persisted yet), so broker memory stays bounded exactly as before.
  • Frontend: _response_partial lifecycle in the live merge (audit.stream sets it, terminal states clear it), streaming/pending states on the audit panes, and a live rendering mode for the Interactions drawer that switches to the persisted fetch on flush.

No new configuration; no behavior change when body logging or live logs are disabled. Non-streamed (and passthrough non-SSE) requests are unaffected.

Refactor (same PR, no behavior change)

The auditlog enrichment API moved from middleware.go (900+ lines) into a new enrich.go, and all ~15 EnrichEntryWith* helpers now use the existing entryFromContext helper instead of repeating the context-get + type-assert boilerplate. Symbol set is identical before/after.

Testing

  • Go: new observer tests (throttling, content-growth gating, no-subscriber skip, Responses API previews) and broker tests (partial-body fan-out vs. stripped retention, HasLiveSubscribers). Full make test-race, e2e, and lint pass.
  • JS: new tests for the _response_partial merge lifecycle, pane pending/streaming states, and a new conversation-drawer.test.cjs covering live rendering, chunk re-renders, flush hydration, and spinner states (431 dashboard tests pass).
  • Verified end-to-end against a slow-streaming mock provider: live SSE feed shows audit.started → audit.updated → audit.stream×9 (accumulated content growing ~2×/s, response_body_partial: true) → audit.completed (final body + usage, no partial flag) → audit.flushed; fresh subscribers replay without partial bodies; the proxied client stream is byte-identical and unaffected.

Refs #290

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Live audit entries now render streamed responses incrementally in the dashboard, with distinct pending and streaming states.
    • The audit pane and interactions drawer include clearer live status messaging while updates are in progress.
  • Bug Fixes

    • Partial streaming content no longer shows as empty; completed entries correctly clear streaming indicators (no stale “streaming” badges).
    • Live updates no longer get hidden by empty-state messaging.
  • Tests

    • Added coverage for live/streaming dashboard state and live preview behavior.

…interactions

While a streamed completion runs, the audit stream observer now publishes
throttled audit.stream live events carrying the partially reconstructed
response body, so connected dashboards render the response chunk-by-chunk
instead of waiting for the stream to finish. Previews are published at most
every 500ms, only when new content accumulated, and only while a dashboard
subscriber is connected; the broker fans partial bodies out live but strips
them from the replay ring, so retention stays bounded.

The request log keeps its in-progress pulse while a partial body is present,
shows a streaming badge on the Response pane, and shows spinners instead of
"not captured" for panes of in-flight entries. The Interactions drawer now
renders live entries directly from the preview data (previously "No
interaction data available" until flush), re-renders as chunks arrive, shows
a progress spinner, and hydrates the persisted thread once the entry flushes.

Also moves the auditlog enrichment API into enrich.go and routes every
context lookup through the existing entryFromContext helper, removing the
repeated boilerplate.

Closes the remaining piece of #290.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

📝 Walkthrough

Walkthrough

This PR adds throttled audit.stream live-preview support for streamed responses, tracks partial response bodies through audit preview retention, extracts auditlog enrichment helpers into a dedicated file, and updates the dashboard UI to show pending, streaming, and live-conversation status states.

Changes

Backend live-stream preview and enrichment refactor

Layer / File(s) Summary
Live event and subscriber-reporting contracts
internal/auditlog/auditlog.go, internal/auditlog/logger.go, internal/live/broker.go
Adds audit.stream, live-subscriber reporting, and broker/logging checks for connected dashboard subscribers.
Throttled live preview publishing
internal/auditlog/stream_observer.go, internal/auditlog/stream_observer_test.go, CLAUDE.md
Publishes throttled partial previews from streamed JSON events and tests the preview gating and Responses API paths; documentation notes the streaming behavior.
Partial-response preview retention
internal/live/broker.go, internal/live/broker_test.go
Carries partial response bodies in live fan-out previews, strips them from retained copies, and tests the live stream payload and subscriber detection.
Auditlog enrichment extraction
internal/auditlog/middleware.go, internal/auditlog/enrich.go
Moves exported enrichment helpers into enrich.go while keeping body capture and audit enablement helpers in middleware.go.

Dashboard live streaming and pending/status UI

Layer / File(s) Summary
Audit list pending and streaming states
internal/admin/dashboard/static/js/modules/audit-list.js, internal/admin/dashboard/static/js/modules/audit-list.test.cjs, internal/admin/dashboard/static/css/dashboard.css, internal/admin/dashboard/templates/audit-pane.html
Updates request/response pane state to distinguish pending, streaming, and empty cases, with matching styles, template badges, and tests.
Live merge notification and partial flags
internal/admin/dashboard/static/js/modules/live-logs.js, internal/admin/dashboard/static/js/modules/live-logs.test.cjs
Marks live entries as partial during audit.stream, clears the flag on completion, and notifies the open conversation drawer after merges.
Conversation drawer live rendering and status
internal/admin/dashboard/static/js/dashboard.js, internal/admin/dashboard/static/js/modules/conversation-drawer.js, internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs, internal/admin/dashboard/static/css/dashboard.css, internal/admin/dashboard/templates/page-audit-logs.html
Adds live drawer state, local rendering for live entries, refresh behavior, and live waiting/status UI in the drawer and page template.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Stream as SSE stream
  participant Observer as StreamLogObserver
  participant Broker as live.Broker
  participant LiveLogs as live-logs.js
  participant Drawer as conversation-drawer.js
  Stream->>Observer: OnJSONEvent(chunk)
  Observer->>Broker: PublishLiveEvent(audit.stream, partial body)
  Broker->>LiveLogs: broadcast live update
  LiveLogs->>LiveLogs: mergeLiveAuditEntry(_response_partial=true)
  LiveLogs->>Drawer: notifyLiveConversation(entry)
  Drawer->>Drawer: refreshLiveConversation(entry)
Loading

Possibly related PRs

  • ENTERPILOT/GoModel#158: Shares the stream-observer parsing path that this PR uses to produce live audit previews from streamed responses.
  • ENTERPILOT/GoModel#317: Updates the streamed response reconstruction logic that feeds the audit.stream previews in this PR.
  • ENTERPILOT/GoModel#488: Directly overlaps with the broker-side live preview and partial-response retention logic updated here.

Poem

A bunny hops through streams of light,
With pending paws and whiskers bright.
audit.stream goes tap, tap, tap,
While dashboards nap? No — catch that snap!
🐰✨

🚥 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 clearly matches the main change: streaming in-flight response bodies into dashboard live logs and the Interactions view.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/realtime-preview-iterated-over

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.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 41.94631% with 173 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/auditlog/enrich.go 34.01% 147 Missing and 14 partials ⚠️
internal/auditlog/logger.go 0.00% 11 Missing ⚠️
internal/auditlog/stream_observer.go 96.29% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

Safe to merge with minimal risk.

The backend gates stream previews behind body logging and live subscribers, strips partial bodies from retained broker state, and preserves final persisted body handling. Frontend state transitions clear partial flags on terminal events and tests cover the new live drawer and pane behavior.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Reviewed the before-state dashboard live-streaming UI video to confirm the pending Response pane spinner and waiting drawer state.
  • Reviewed the after-state dashboard live-streaming UI video to confirm the accumulation of streamed chunks, the streaming badge, live drawer updates, and the final persisted answer.
  • Verified the focused tests reported success with exit code 0 in the dashboard-live-streaming-ui-focused-tests.log.

View all artifacts

T-Rex Ran code and verified through T-Rex

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client as Proxied client
participant Observer as StreamLogObserver
participant Logger as Audit logger
participant Broker as Live broker
participant Dashboard as Dashboard subscriber

Client->>Observer: SSE JSON chunks pass through
Observer->>Observer: Accumulate response body
Observer->>Logger: Check live subscribers
Logger->>Broker: HasLiveSubscribers
Broker-->>Logger: Subscriber status
alt Body grew and throttle elapsed and subscriber connected
    Observer->>Logger: Publish audit stream event
    Logger->>Broker: Publish audit stream preview
    Broker->>Broker: Strip body from retained replay copy
    Broker-->>Dashboard: Fan out partial response body
    Dashboard->>Dashboard: Merge partial flag and rerender UI
end
Observer->>Observer: Apply final body on stream close
Observer->>Logger: Write final entry
Logger->>Broker: Publish final lifecycle events
Broker-->>Dashboard: Send completed or flushed events
Dashboard->>Dashboard: Clear partial flag and hydrate detail
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Client as Proxied client
participant Observer as StreamLogObserver
participant Logger as Audit logger
participant Broker as Live broker
participant Dashboard as Dashboard subscriber

Client->>Observer: SSE JSON chunks pass through
Observer->>Observer: Accumulate response body
Observer->>Logger: Check live subscribers
Logger->>Broker: HasLiveSubscribers
Broker-->>Logger: Subscriber status
alt Body grew and throttle elapsed and subscriber connected
    Observer->>Logger: Publish audit stream event
    Logger->>Broker: Publish audit stream preview
    Broker->>Broker: Strip body from retained replay copy
    Broker-->>Dashboard: Fan out partial response body
    Dashboard->>Dashboard: Merge partial flag and rerender UI
end
Observer->>Observer: Apply final body on stream close
Observer->>Logger: Write final entry
Logger->>Broker: Publish final lifecycle events
Broker-->>Dashboard: Send completed or flushed events
Dashboard->>Dashboard: Clear partial flag and hydrate detail
Loading

Reviews (1): Last reviewed commit: "feat(dashboard): stream in-flight respon..." | Re-trigger Greptile

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/admin/dashboard/static/js/modules/audit-list.js (1)

726-753: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Guard streaming with the live-state completion check
streaming can remain true whenever _response_partial is left set, even after the entry has moved past the streaming phase. Reuse the same completion guard used by auditEntryLiveInProgress:

🐛 Proposed fix
-                    streaming: !!(entry && entry._response_partial && data && data.response_body),
+                    streaming: !!(entry && entry._response_partial && data && data.response_body && this.auditEntryLiveInProgress(entry)),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/admin/dashboard/static/js/modules/audit-list.js` around lines 726 -
753, The auditResponsePane() logic sets streaming based only on
_response_partial, which can stay true after the live response phase has
finished. Update the streaming flag to use the same completion guard as
auditEntryLiveInProgress() so it only reports streaming while the entry is still
actively in progress, and keep the response pane state aligned with the
live-state checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/admin/dashboard/static/js/modules/conversation-drawer.js`:
- Around line 143-151: The conversationLiveWaiting method currently hard-codes a
rank < 30 check, which is tightly coupled to the liveAuditStateRank ordering.
Replace the magic number with a shared named constant or helper owned by the
live-logs/live state ranking module, such as a completion threshold or an
isLiveStateComplete-style function, and update conversationLiveWaiting to use
that exported symbol instead of comparing against a raw numeric value.
- Around line 110-116: The _conversationEntryLivePending method still has a
fallback branch for entry._live_pending even though dashboard.js guarantees
auditEntryLiveDetailPending is available before
dashboardConversationDrawerModule loads. Update _conversationEntryLivePending to
call auditEntryLiveDetailPending directly and remove the dead typeof check and
fallback branch, keeping the logic localized to the existing conversation drawer
module method.

In `@internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs`:
- Around line 44-59: The local test stub for auditEntryLiveDetailPending is too
simplified and does not match the real live-logs.js behavior, so update the stub
in conversation-drawer.test.cjs to mirror the production logic more closely.
Make it handle the audit.failed special case and the _live_state checks for
audit.flushed and audit.detail, using the same entry shape and state handling as
the real implementation so conversation-drawer.js tests exercise the correct
behavior.

In `@internal/admin/dashboard/templates/page-audit-logs.html`:
- Around line 210-214: Make the live status updates announceable to assistive
tech by adding an appropriate live region to the conversation-live-status
container. Update the markup around conversationLiveWaiting() /
conversationLiveStatusText() to include role="status" and/or aria-live="polite"
so screen readers are notified when the streaming status text changes, while
keeping the existing x-show and x-text behavior intact.

In `@internal/auditlog/enrich.go`:
- Around line 287-303: EnrichEntryWithError currently drops ErrorMessage and
ErrorCode when entry.Data is nil, so initialize entry.Data before setting error
details in EnrichEntryWithError and keep the existing error-type assignment and
publishLiveAuditUpdate flow intact. Use entryFromContext and the entry.Data
access in this function to ensure the audit entry always has a data container
before storing errorMessage/errorCode, including early-failure cases.

In `@internal/auditlog/stream_observer.go`:
- Around line 87-104: The live preview path in
StreamLogObserver.maybePublishLivePreview still rebuilds the full response body
on every published tick via applyResponseBody, which can become expensive for
very long streams. Update the preview update flow so applyResponseBody is not
doing a full reconstruction each time; instead reuse or incrementally update the
existing preview state while keeping the same throttle and live-subscriber
gating behavior in maybePublishLivePreview and any related preview publishing
helpers.

---

Outside diff comments:
In `@internal/admin/dashboard/static/js/modules/audit-list.js`:
- Around line 726-753: The auditResponsePane() logic sets streaming based only
on _response_partial, which can stay true after the live response phase has
finished. Update the streaming flag to use the same completion guard as
auditEntryLiveInProgress() so it only reports streaming while the entry is still
actively in progress, and keep the response pane state aligned with the
live-state checks.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 233d1e81-ae00-4587-8ae1-e1d066a5ad13

📥 Commits

Reviewing files that changed from the base of the PR and between 383248d and cd96c63.

📒 Files selected for processing (19)
  • CLAUDE.md
  • internal/admin/dashboard/static/css/dashboard.css
  • internal/admin/dashboard/static/js/dashboard.js
  • internal/admin/dashboard/static/js/modules/audit-list.js
  • internal/admin/dashboard/static/js/modules/audit-list.test.cjs
  • internal/admin/dashboard/static/js/modules/conversation-drawer.js
  • internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs
  • internal/admin/dashboard/static/js/modules/live-logs.js
  • internal/admin/dashboard/static/js/modules/live-logs.test.cjs
  • internal/admin/dashboard/templates/audit-pane.html
  • internal/admin/dashboard/templates/page-audit-logs.html
  • internal/auditlog/auditlog.go
  • internal/auditlog/enrich.go
  • internal/auditlog/logger.go
  • internal/auditlog/middleware.go
  • internal/auditlog/stream_observer.go
  • internal/auditlog/stream_observer_test.go
  • internal/live/broker.go
  • internal/live/broker_test.go
💤 Files with no reviewable changes (1)
  • internal/auditlog/middleware.go

Comment thread internal/admin/dashboard/static/js/modules/conversation-drawer.js
Comment thread internal/admin/dashboard/static/js/modules/conversation-drawer.js
Comment thread internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs Outdated
Comment thread internal/admin/dashboard/templates/page-audit-logs.html
Comment thread internal/auditlog/enrich.go
Comment on lines +87 to +104
func (o *StreamLogObserver) maybePublishLivePreview() {
if o.live == nil || o.entry == nil || o.entry.Data == nil {
return
}
if o.builder.contentLen == o.lastPreviewLen {
return
}
if time.Since(o.lastPreviewAt) < livePreviewInterval {
return
}
o.lastPreviewAt = time.Now()
if !liveSubscribed(o.live) {
return
}
o.lastPreviewLen = o.builder.contentLen
o.applyResponseBody()
o.live.PublishLiveEvent(LiveEventAuditStream, o.entry)
}

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.

🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Solid throttled-preview design; minor scalability note for very long streams.

The throttle ordering (content-length check → time window → subscriber check → publish) correctly amortizes the subscriber-presence check and lets a newly-connected subscriber catch up on the next tick, as confirmed by the accompanying tests. One thing worth keeping in mind: applyResponseBody fully reconstructs the response body from the builder on every published tick (every 500ms while a subscriber is connected), so total preview-rebuild cost grows with stream length. This is bounded by the throttle and by HasLiveSubscribers, so it's unlikely to be a problem for typical completions, but could add up for very long streamed generations with many concurrent dashboard viewers.

Also applies to: 113-122

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/auditlog/stream_observer.go` around lines 87 - 104, The live preview
path in StreamLogObserver.maybePublishLivePreview still rebuilds the full
response body on every published tick via applyResponseBody, which can become
expensive for very long streams. Update the preview update flow so
applyResponseBody is not doing a full reconstruction each time; instead reuse or
incrementally update the existing preview state while keeping the same throttle
and live-subscriber gating behavior in maybePublishLivePreview and any related
preview publishing helpers.

Copilot AI 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.

Pull request overview

This PR adds a new audit.stream live event to deliver throttled, in-flight reconstructed streamed response bodies to connected dashboards, enabling near-realtime “chunk-by-chunk” UI updates while keeping broker retention bounded by stripping partial bodies from replay/active snapshots. It also refactors the auditlog enrichment helpers out of the large middleware file into a dedicated enrich.go.

Changes:

  • Backend: publish throttled audit.stream live previews only when a dashboard subscriber is connected; ensure replay retention strips partial bodies and does not incorrectly mark them as captured.
  • Frontend: merge audit.stream into live log rows with a _response_partial lifecycle; add pending/streaming UI states for request/response panes and live rendering/hydration behavior for the Interactions drawer.
  • Refactor: move auditlog enrichment API helpers from middleware.go into enrich.go while preserving the symbol set.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/live/broker.go Adds audit.stream support, HasLiveSubscribers, and partial-body stripping semantics for retention.
internal/live/broker_test.go Tests for audit.stream preview behavior and subscriber reporting.
internal/auditlog/stream_observer.go Publishes throttled partial-response previews via audit.stream during SSE observation.
internal/auditlog/stream_observer_test.go New tests validating throttling, content gating, subscriber gating, and Responses API previews.
internal/auditlog/middleware.go Removes enrichment helpers after migration to enrich.go.
internal/auditlog/logger.go Adds HasLiveSubscribers passthrough to the live publisher when supported.
internal/auditlog/enrich.go New home for context-based and direct-entry enrichment helpers.
internal/auditlog/auditlog.go Introduces LiveEventAuditStream and the LiveSubscriberReporter interface.
internal/admin/dashboard/templates/page-audit-logs.html Updates Interactions empty-state logic and adds live status block.
internal/admin/dashboard/templates/audit-pane.html Adds streaming badge and pending spinner UI for audit panes.
internal/admin/dashboard/static/js/modules/live-logs.test.cjs Tests for audit.stream merge lifecycle and live conversation drawer notifications.
internal/admin/dashboard/static/js/modules/live-logs.js Merges audit.stream, manages _response_partial, and notifies Interactions drawer on live merges.
internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs New tests covering live rendering, chunk re-renders, flush hydration, and spinner states.
internal/admin/dashboard/static/js/modules/conversation-drawer.js Renders live entries locally, re-renders on live merges, and hydrates persisted thread on flush.
internal/admin/dashboard/static/js/modules/audit-list.test.cjs Adds tests for in-progress behavior and pending/streaming pane states.
internal/admin/dashboard/static/js/modules/audit-list.js Adds pending/streaming state derivation for request/response panes and in-progress logic tweak.
internal/admin/dashboard/static/js/dashboard.js Adds conversationLiveEntryId to dashboard state.
internal/admin/dashboard/static/css/dashboard.css Styles for pane pending/streaming and conversation live status.
CLAUDE.md Documents new live streamed-response behavior under dashboard live logs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 698 to 701
const data = entry && entry.data ? entry.data : null;
const empty = !data || (!data.request_headers && !data.request_body);
const pending = empty && this.auditEntryLiveInProgress(entry);

Comment on lines 727 to +730
const data = entry && entry.data ? entry.data : null;
const errorMessage = this.auditEntryErrorMessage(entry);
const empty = !data || (!errorMessage && !data.response_headers && !data.response_body);
const pending = empty && this.auditEntryLiveInProgress(entry);
Comment on lines +131 to +136
if (state === 'audit.flushed' || state === 'audit.detail') {
this.conversationLiveEntryId = '';
const requestToken = ++this.conversationRequestToken;
this.fetchConversation(entry.id, requestToken);
return;
}
- share liveAuditStateSettled instead of a raw rank comparison in the
  Interactions drawer, and drop the dead _live_pending fallback (the
  presence guard stays: modules mix optionally, matching every other
  cross-module call)
- drawer tests load the real live-logs module instead of drifting stubs
- announce the drawer's live status to assistive tech (role=status)
- EnrichEntryWithError creates the data container when missing instead
  of silently dropping error message/code
- the Response pane streaming badge uses the same completion guard as
  the in-progress pulse so a stale partial flag cannot keep it lit

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/admin/dashboard/static/js/modules/live-logs.js (1)

211-215: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the new liveAuditStateSettled helper instead of the raw rank literal 30.

This file defines liveAuditStateSettled(state) (Lines 306-311) specifically to avoid hardcoding the "completed" rank threshold, and conversation-drawer.js was updated to use it per the latest commit. This call site — in the very file that owns the ranking — still hardcodes 30.

♻️ Proposed fix
                 if (eventType === 'audit.stream') {
                     patch._response_partial = true;
-                } else if (this.liveAuditStateRank(eventType) >= 30) {
+                } else if (this.liveAuditStateSettled(eventType)) {
                     patch._response_partial = false;
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/admin/dashboard/static/js/modules/live-logs.js` around lines 211 -
215, The live audit state check still hardcodes the settled threshold with the
literal 30 in the live logs patching logic, so update that call site to use the
existing liveAuditStateSettled(state) helper instead. In live-logs.js, replace
the raw rank comparison in the eventType handling with the helper so the
settled-state decision stays centralized alongside liveAuditStateRank and
liveAuditStateSettled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/admin/dashboard/static/js/modules/live-logs.js`:
- Around line 211-215: The live audit state check still hardcodes the settled
threshold with the literal 30 in the live logs patching logic, so update that
call site to use the existing liveAuditStateSettled(state) helper instead. In
live-logs.js, replace the raw rank comparison in the eventType handling with the
helper so the settled-state decision stays centralized alongside
liveAuditStateRank and liveAuditStateSettled.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e8a1485e-8c11-4cee-997f-d658409ebeab

📥 Commits

Reviewing files that changed from the base of the PR and between cd96c63 and f8d90ef.

📒 Files selected for processing (7)
  • internal/admin/dashboard/static/js/modules/audit-list.js
  • internal/admin/dashboard/static/js/modules/audit-list.test.cjs
  • internal/admin/dashboard/static/js/modules/conversation-drawer.js
  • internal/admin/dashboard/static/js/modules/conversation-drawer.test.cjs
  • internal/admin/dashboard/static/js/modules/live-logs.js
  • internal/admin/dashboard/templates/page-audit-logs.html
  • internal/auditlog/enrich.go

…eset

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

@SantiagoDePolonia SantiagoDePolonia merged commit 618cf40 into main Jul 6, 2026
18 checks 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.

3 participants