Skip to content

feat(audit): log audio endpoint bodies with dashboard playback#364

Merged
SantiagoDePolonia merged 6 commits into
mainfrom
feat/audit-audio-bodies
Jun 3, 2026
Merged

feat(audit): log audio endpoint bodies with dashboard playback#364
SantiagoDePolonia merged 6 commits into
mainfrom
feat/audit-audio-bodies

Conversation

@SantiagoDePolonia
Copy link
Copy Markdown
Contributor

@SantiagoDePolonia SantiagoDePolonia commented Jun 2, 2026

Summary

Audio endpoints (/v1/audio/speech, /v1/audio/transcriptions) were invisible to the audit log, and when bodies were captured the binary audio was corrupted. This PR makes audio fully auditable and adds opt-in, playable audio capture.

Two logical commits:

  1. fix(audit): log audio endpoints as model interactions — the audio paths were missing from the endpoint classifier, so they defaulted to ModelInteraction:false and were dropped by the audit middleware's OnlyModelInteractions gate. They are now classified (incl. /v1/audio/translations) with correct body modes. Not IngressManaged — the handlers parse their own bodies.

  2. feat(audit): capture audio bodies behind LOGGING_LOG_AUDIO_BODIES — a new env var (default false), independent of LOGGING_LOG_BODIES, controls audio input/output logging.

Why

  • The audit body path coerced binary audio through toValidUTF8String, replacing invalid bytes with U+FFFD — irreversibly corrupting the MP3, so a player could never reconstruct it.
  • Audio request bodies were never captured: request-body capture reads only from the ingress snapshot, which doesn't exist for non-ingress-managed audio routes.

Behavior

LOGGING_LOG_AUDIO_BODIES TTS request TTS response Dashboard
false (default) not stored {__audio__, content_type, bytes, stored:false} placeholder 🔊 labeled placeholder
true JSON input (text, voice, format) lossless base64 audio (≤10 MB, else too_large) <audio controls> player

STT logs upload metadata (filename, model, params) when enabled — never the raw audio bytes; its JSON response is captured by the normal path either way.

Implementation

  • Capture (internal/auditlog/audio_body.go): IsAudioContentType + BuildAudioResponseBody; new EnrichEntryWith{Request,Response}Body helpers. The audit middleware now skips audio Content-Types so it neither corrupts nor clobbers handler-set bodies.
  • Service (internal/server/audio_service.go): captures request input before dispatch and audio output in respondAudio, from the full untruncated bytes.
  • Config (config/logging.go, auditlog.Config, factory, startup log, .env.template).
  • Dashboard (conversation-helpers.js, audit-list.js, dashboard.css): renders the player or placeholder; content-type and base64 are sanitized before building the data: URL.

Testing

  • Go: new audio_body_test.go (lossless round-trip / no-UTF8-corruption, gating, too-large) + extended endpoints_test.go and IsModelInteractionPath cases. make test-race + make lint pass via pre-commit.
  • JS: 6 new audit-list.test.cjs cases (player rendering, placeholder, XSS sanitization of content-type/base64) — 30/30 pass.
  • Manual: with the flag on, a TTS round trip stored base64 that decodes byte-identical to the served MP3; STT stored metadata + JSON text; with the flag off, only a placeholder is stored (no bytes, no corruption).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Audit dashboard can display and play captured audio from audio endpoints and shows informative placeholders when audio is absent or too large.
  • Configuration

    • New LOGGING_LOG_AUDIO_BODIES option (default: false). When enabled alongside general body-logging, generated audio is stored as base64 for inline playback (capped at 8 MB); transcription uploads record metadata, not raw audio.
  • Documentation

    • Docs updated with guidance, storage caps, and privacy/storage warnings for audio logging.
  • Tests

    • Added tests for audio logging, rendering/playback, sanitization, and size/placeholder behaviors.

SantiagoDePolonia and others added 2 commits June 2, 2026 17:47
The /v1/audio/speech and /v1/audio/transcriptions endpoints were absent
from the endpoint classifier, so they defaulted to ModelInteraction:false
and were skipped by the audit middleware's OnlyModelInteractions gate.
Classify them (and /v1/audio/translations) as model interactions with the
appropriate body modes so they appear in audit and request logs.

They are intentionally not IngressManaged: the audio handlers parse their
own bodies and do not run through the translated-inference pipeline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h dashboard playback

Audio responses are binary, so the audit body-capture path corrupted them
via UTF-8 coercion (invalid bytes -> U+FFFD), making them unrecoverable.
Audio request bodies were never captured at all (audio is not
ingress-managed, so there is no request snapshot to read from).

Add a dedicated LOGGING_LOG_AUDIO_BODIES env var (default false), independent
of LOGGING_LOG_BODIES, that controls audio input/output logging:

- Response: the audio handler captures the output. When the flag is on it is
  stored losslessly as base64 (capped at 10MB, else a too-large placeholder)
  for playback; otherwise a lightweight {content_type, bytes} placeholder is
  stored. The audit middleware now skips audio Content-Types so it neither
  corrupts the bytes nor clobbers the handler-set body.
- Request: speech logs its JSON input (text, voice, format); transcription
  logs upload metadata (filename, model, params) but never the raw audio.

Dashboard: render an <audio> player for stored audio (base64 data URL,
content-type and payload sanitized) and a labeled placeholder otherwise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ae946f9c-7018-46e5-a1f7-6414e374691b

📥 Commits

Reviewing files that changed from the base of the PR and between 6a43c80 and 99dc76c.

📒 Files selected for processing (5)
  • CLAUDE.md
  • docs/advanced/audio-api.mdx
  • docs/advanced/configuration.mdx
  • internal/admin/dashboard/static/css/dashboard.css
  • internal/auditlog/audio_body.go

📝 Walkthrough

Walkthrough

Adds audit logging for OpenAI-compatible audio endpoints (/v1/audio/speech, /v1/audio/transcriptions): audio audit data contract, LogAudioBodies config and propagation, middleware/service enrichment APIs to record metadata and optional base64 payloads (size-capped), endpoint classification, and dashboard playback rendering.

Changes

Audio endpoint audit logging

Layer / File(s) Summary
Audio audit body contract and helpers
internal/auditlog/audio_body.go, internal/auditlog/audio_body_test.go
AudioBodyLog struct with __audio__ marker plus metadata and optional base64 Data. IsAudioContentType and BuildAudioResponseBody implement detection, capped embedding, and placeholders; tests cover MIME parsing, size limit, storage behavior, and byte-preservation.
Audit configuration and integration
config/logging.go, .env.template, internal/auditlog/auditlog.go, internal/auditlog/factory.go, internal/app/app.go, internal/auditlog/auditlog_test.go, CLAUDE.md, docs/advanced/configuration.mdx
Adds LogAudioBodies / LOGGING_LOG_AUDIO_BODIES, documents behavior and default false, propagates the flag via factory and startup logs, and updates tests to include audio endpoints as model interactions.
Endpoint routing and body mode registration
internal/core/endpoints.go, internal/core/endpoints_test.go
Introduces OperationAudioSpeech and OperationAudioTranscriptions. Classifier maps /v1/audio/speech to BodyModeJSON and /v1/audio/transcriptions to BodyModeMultipart, marking both as ModelInteraction.
Middleware audio handling and live enrichment
internal/auditlog/middleware.go
Skips response decompression/JSON parsing for audio content to preserve raw bytes; adds EnrichEntryWithRequestBody, EnrichEntryWithResponseBody, and entryFromContext for live audit updates; tests validate middleware behavior for oversized audio.
Handler and service integration
internal/server/handlers.go, internal/server/audio_service.go, internal/server/audio_service_test.go
audioService now receives logBodies and logAudioBodies. CreateSpeech/CreateTranscription conditionally enrich audit inputs; responses proxied through (*audioService).respondAudio use auditlog.BuildAudioResponseBody when appropriate. Tests validate combinations and base64 round-trip.
Dashboard audit UI for audio rendering
internal/admin/dashboard/static/js/modules/conversation-helpers.js, 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
Exports isAudioBody and renderAudioBody to detect __audio__ entries and render an <audio> player with data:audio/*;base64 when bytes are stored, or a sanitized placeholder/too-large message otherwise. auditPaneState now routes audio bodies through these helpers; CSS and tests added.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AudioService
  participant AuditMiddleware
  Client->>AudioService: POST /v1/audio/speech
  AudioService->>AudioService: serialize speech params
  AudioService->>AuditMiddleware: EnrichEntryWithRequestBody
  AudioService->>Client: return audio response
  AudioService->>AudioService: detect audio content type
  AudioService->>AuditMiddleware: EnrichEntryWithResponseBody
  AuditMiddleware->>AuditMiddleware: publish live audit update
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ENTERPILOT/GoModel#241: Edits to internal/admin/dashboard/static/js/modules/audit-list.js affecting audit pane rendering and copy-state logic.
  • ENTERPILOT/GoModel#362: Related changes to audio endpoint plumbing in internal/server/audio_service.go and handlers.

Suggested labels

release:internal

Poem

🐇 I tuck base64 in my tiny paws,
Logs remember audio and text because,
The dashboard hums the playback tune,
A rabbit listens by the moon,
Hop — the audit keeps the cause.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 changes: adding audit logging for audio endpoint bodies with dashboard playback support, matching the core objectives.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/audit-audio-bodies

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 2, 2026

Greptile Summary

This PR makes audio endpoints visible and playable in audit logs. It changes:

  • Classifies speech and transcription routes as model interactions.
  • Adds LOGGING_LOG_AUDIO_BODIES for opt-in audio body capture.
  • Stores speech audio as base64 with dashboard playback or a placeholder.
  • Captures speech inputs and transcription upload metadata from the audio service.
  • Adds dashboard rendering and tests for audio audit bodies.

Confidence Score: 4/5

This is close, but the storage cap should be fixed before merging.

  • Audio capture can still create audit entries that exceed MongoDB document limits.
  • The latest update documents the risk but does not prevent the failing insert path.
  • The translations route mismatch appears addressed by the latest changes.

internal/auditlog/audio_body.go

Important Files Changed

Filename Overview
internal/auditlog/audio_body.go Defines the audio audit payload and capture cap; the raw cap still permits oversized stored documents.
internal/auditlog/middleware.go Skips normal response body parsing for audio content types so handler-captured audio is not corrupted.
internal/server/audio_service.go Captures configured audio request and response bodies directly from the audio handler path.

Reviews (2): Last reviewed commit: "fix(audit): address PR review on audio b..." | Re-trigger Greptile

Comment thread internal/core/endpoints.go Outdated
Comment on lines +127 to +132
case path == "/v1/audio/transcriptions" || path == "/v1/audio/translations":
return EndpointDescriptor{
ModelInteraction: true,
Dialect: "openai_compat",
Operation: OperationAudioTranscriptions,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Translations route missing

This classifies /v1/audio/translations as a model interaction, but the server only registers /v1/audio/speech and /v1/audio/transcriptions. A client posting to /v1/audio/translations still gets a 404 instead of reaching an audio handler, so this endpoint remains unavailable even though the audit classifier and tests now say it is supported.

Comment thread internal/auditlog/audio_body.go Outdated
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jun 2, 2026

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

Codecov Report

❌ Patch coverage is 40.86957% with 68 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/auditlog/middleware.go 0.00% 36 Missing and 1 partial ⚠️
internal/server/audio_service.go 35.13% 20 Missing and 4 partials ⚠️
internal/server/handlers.go 42.85% 3 Missing and 1 partial ⚠️
internal/app/app.go 0.00% 1 Missing ⚠️
internal/auditlog/auditlog.go 0.00% 1 Missing ⚠️
internal/auditlog/factory.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
internal/auditlog/auditlog.go (1)

259-269: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add explicit LogAudioBodies initialization for consistency.

DefaultConfig() explicitly sets all other boolean fields (Enabled: false, LogBodies: false, LogHeaders: false) but omits the new LogAudioBodies field. While the zero value is correct, explicitly setting it maintains consistency with the existing pattern in this function.

♻️ Proposed addition
 func DefaultConfig() Config {
 	return Config{
 		Enabled:               false,
 		LogBodies:             false,
+		LogAudioBodies:        false,
 		LogHeaders:            false,
 		BufferSize:            1000,
 		FlushInterval:         5 * time.Second,
 		RetentionDays:         30,
 		OnlyModelInteractions: true,
 	}
 }
🤖 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/auditlog.go` around lines 259 - 269, The DefaultConfig
function currently initializes most boolean fields explicitly but omits the new
LogAudioBodies field; update DefaultConfig (the function named DefaultConfig
returning Config) to include an explicit LogAudioBodies: false entry alongside
Enabled, LogBodies, and LogHeaders so the new boolean is initialized
consistently with the others in the Config literal.
internal/auditlog/middleware.go (1)

137-166: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

ResponseBodyTooBigToHandle is set for audio responses despite lossless handler capture.

The truncation flag (Lines 139-141) is evaluated before the IsAudioContentType guard. For audio responses, responseCapture still buffers bytes up to MaxBodyCapture and sets truncated when exceeded — even though the audio handler captures the body losslessly via its own path (with the separate 10 MB too_large cap). If MaxBodyCapture is smaller than the audio payload, the entry is incorrectly marked ResponseBodyTooBigToHandle = true alongside a fully-stored audio body, producing conflicting audit metadata. Move the flag inside the non-audio branch.

🐛 Proposed fix: gate the truncation flag on non-audio responses
-			// Set truncation flag if response body exceeded limit
-			if responseCapture.truncated {
-				entry.Data.ResponseBodyTooBigToHandle = true
-			}
-
 			bodyBytes := responseCapture.body.Bytes()

 			// Audio responses are binary; the audio handler captures them
 			// losslessly as base64 (gated by LogAudioBodies) before this
 			// runs. Skip here so we neither corrupt the bytes via UTF-8
 			// coercion nor clobber the handler-set body.
 			if !IsAudioContentType(c.Response().Header().Get("Content-Type")) {
+				// Set truncation flag if response body exceeded limit
+				if responseCapture.truncated {
+					entry.Data.ResponseBodyTooBigToHandle = true
+				}
+
 				// Decompress if Content-Encoding header is present
 				if contentEncoding := c.Response().Header().Get("Content-Encoding"); contentEncoding != "" {
 					if decompressed, ok := decompressBody(bodyBytes, contentEncoding); ok {
 						bodyBytes = decompressed
 					}
 				}
🤖 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/middleware.go` around lines 137 - 166, The truncation flag
entry.Data.ResponseBodyTooBigToHandle is being set for all responses before
checking IsAudioContentType, causing audio responses (which are captured
losslessly by the audio handler) to be incorrectly marked too-big; update the
block in the middleware so that after verifying cfg.LogBodies, responseCapture
!= nil, shouldCaptureResponseBody(c) and responseCapture.body.Len() > 0 you do
NOT set ResponseBodyTooBigToHandle until after the IsAudioContentType check —
move the existing truncated check (responseCapture.truncated ->
entry.Data.ResponseBodyTooBigToHandle) inside the non-audio branch where
IsAudioContentType(...) is false, keeping the rest of the JSON
unmarshalling/decompression logic (decompressBody, json.Unmarshal,
toValidUTF8String) unchanged.
🤖 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/css/dashboard.css`:
- Around line 2896-2914: The CSS uses an undefined custom property --muted in
the .audit-audio-meta and .audit-audio-note rules; update those rules to use
var(--text-muted, `#888`) instead of var(--muted, `#888`) so they match the rest of
the stylesheet's theme variable (--text-muted) and inherit correct colors in
light/dark modes.

---

Outside diff comments:
In `@internal/auditlog/auditlog.go`:
- Around line 259-269: The DefaultConfig function currently initializes most
boolean fields explicitly but omits the new LogAudioBodies field; update
DefaultConfig (the function named DefaultConfig returning Config) to include an
explicit LogAudioBodies: false entry alongside Enabled, LogBodies, and
LogHeaders so the new boolean is initialized consistently with the others in the
Config literal.

In `@internal/auditlog/middleware.go`:
- Around line 137-166: The truncation flag entry.Data.ResponseBodyTooBigToHandle
is being set for all responses before checking IsAudioContentType, causing audio
responses (which are captured losslessly by the audio handler) to be incorrectly
marked too-big; update the block in the middleware so that after verifying
cfg.LogBodies, responseCapture != nil, shouldCaptureResponseBody(c) and
responseCapture.body.Len() > 0 you do NOT set ResponseBodyTooBigToHandle until
after the IsAudioContentType check — move the existing truncated check
(responseCapture.truncated -> entry.Data.ResponseBodyTooBigToHandle) inside the
non-audio branch where IsAudioContentType(...) is false, keeping the rest of the
JSON unmarshalling/decompression logic (decompressBody, json.Unmarshal,
toValidUTF8String) unchanged.
🪄 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: 2c8b7190-476f-444b-945e-29068e968693

📥 Commits

Reviewing files that changed from the base of the PR and between c34ea8d and fdfef29.

📒 Files selected for processing (17)
  • .env.template
  • config/logging.go
  • internal/admin/dashboard/static/css/dashboard.css
  • 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-helpers.js
  • internal/app/app.go
  • internal/auditlog/audio_body.go
  • internal/auditlog/audio_body_test.go
  • internal/auditlog/auditlog.go
  • internal/auditlog/auditlog_test.go
  • internal/auditlog/factory.go
  • internal/auditlog/middleware.go
  • internal/core/endpoints.go
  • internal/core/endpoints_test.go
  • internal/server/audio_service.go
  • internal/server/handlers.go

Comment thread internal/admin/dashboard/static/css/dashboard.css
Add the new env var to the audit logging configuration table and CLAUDE.md
reference, and describe audio body capture (base64 storage + dashboard
playback when enabled, placeholder when disabled) in the Audio API guide.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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 `@CLAUDE.md`:
- Line 119: Update the logging documentation for LOGGING_LOG_AUDIO_BODIES to
state that base64-encoded audio is capped at 10 MB and that any audio payloads
exceeding this limit are marked "too_large" rather than being logged; mention
this applies to the /v1/audio/speech endpoint (base64 audio for playback) and
transcription uploads, and clarify that this cap is independent of
LOGGING_LOG_BODIES so users understand the behavior when audio exceeds the
threshold.
- Line 119: Update the CLAUDE.md audit logging line to include the same storage
warning present in config/logging.go for LOGGING_LOG_AUDIO_BODIES: add a clear
note that enabling LOGGING_LOG_AUDIO_BODIES stores full audio in the audit log
and can grow storage quickly, and include guidance on when to change the default
(e.g., only enable for short-term debugging or with retention/purging policies).
Reference the setting name LOGGING_LOG_AUDIO_BODIES and mirror the warning
phrasing from config/logging.go so users see the storage implications before
enabling it.
- Line 119: Update the audit logging docs entry that currently lists
`/v1/audio/speech` to also include `/v1/audio/translations`; specifically, when
describing `LOGGING_LOG_AUDIO_BODIES` and the logged audio endpoints, add
`/v1/audio/translations` alongside `/v1/audio/speech` and mention that it will
log base64 audio inputs/outputs (and dashboard playback) and upload metadata for
translations, and clarify that this behavior is independent of
`LOGGING_LOG_BODIES`.

In `@docs/advanced/audio-api.mdx`:
- Around line 95-98: Update the audit-logging documentation to include the
missing /v1/audio/translations endpoint: modify the paragraph that lists enabled
endpoints (currently mentions /v1/audio/speech and /v1/audio/transcriptions) to
also describe /v1/audio/translations' audit behavior (what is stored/omitted and
any size or format constraints), matching the style used for /v1/audio/speech
and /v1/audio/transcriptions so readers know all three endpoints are covered.
- Line 94: The doc's placeholder `{content_type, bytes}` is outdated; update the
documented placeholder to match the implementation by replacing it with
`{__audio__, content_type, bytes, stored:false}`, ensuring the sentinel
`__audio__` is first, `content_type` and `bytes` follow in that order, and the
`stored:false` flag is present to indicate audio bytes are not stored.

In `@docs/advanced/configuration.mdx`:
- Line 115: Update the documented placeholder format string that currently reads
"{content_type, bytes}" to reflect the actual implementation by replacing it
with the full placeholder "{__audio__, content_type, bytes, stored: false}";
look for the exact literal "{content_type, bytes}" in the configuration docs and
change it to the new format so the docs match the PR's response placeholder
structure.
- Line 112: Update the sentence that currently mentions
"/v1/audio/transcriptions" so it also includes "/v1/audio/translations" (e.g.,
"and `/v1/audio/transcriptions` and `/v1/audio/translations` stores upload
metadata"), ensuring both STT endpoints are documented as behaving identically
(storing metadata only); edit the line containing "dashboard can play it back,
and `/v1/audio/transcriptions` stores upload" to list both endpoints in the same
style.
🪄 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: 360a450a-f8f7-48bc-8733-1a20146d6b1f

📥 Commits

Reviewing files that changed from the base of the PR and between fdfef29 and 720d3bc.

📒 Files selected for processing (3)
  • CLAUDE.md
  • docs/advanced/audio-api.mdx
  • docs/advanced/configuration.mdx

Comment thread CLAUDE.md Outdated
- **Storage:** `STORAGE_TYPE` (sqlite), `SQLITE_PATH` (data/gomodel.db), `POSTGRES_URL`, `MONGODB_URL`
- **Models:** `MODELS_ENABLED_BY_DEFAULT` (true), `MODEL_OVERRIDES_ENABLED` (true), `KEEP_ONLY_ALIASES_AT_MODELS_ENDPOINT` (false), `CONFIGURED_PROVIDER_MODELS_MODE` (`fallback` or `allowlist`, default `fallback`; `allowlist` skips upstream `/models` for providers with configured lists); persisted overrides restrict/allow selectors with `user_paths`. When alias-only models listing is enabled, `GET /v1/models` returns only model aliases, not full concrete model specs, to operators.
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document the 10 MB size cap and too-large handling.

The PR objectives specify that base64 encoding is "capped at 10 MB; larger marked too_large." Users should be informed of this size limit to understand the behavior when audio exceeds this threshold.

📝 Suggested documentation update
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback (capped at 10 MB), upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
🤖 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 `@CLAUDE.md` at line 119, Update the logging documentation for
LOGGING_LOG_AUDIO_BODIES to state that base64-encoded audio is capped at 10 MB
and that any audio payloads exceeding this limit are marked "too_large" rather
than being logged; mention this applies to the /v1/audio/speech endpoint (base64
audio for playback) and transcription uploads, and clarify that this cap is
independent of LOGGING_LOG_BODIES so users understand the behavior when audio
exceeds the threshold.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add storage warning for audio logging.

The code comment in config/logging.go includes a critical warning: "WARNING: stores full audio in the audit log; grows storage quickly." This warning should be included in the user-facing documentation to help users understand the storage implications before enabling this feature.

Based on learnings, documentation should "explain when to change" defaults—the storage warning is essential context for that decision.

📝 Suggested documentation addition
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`; ⚠️ stores full audio, grows storage quickly), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`; ⚠️ stores full audio, grows storage quickly), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
🤖 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 `@CLAUDE.md` at line 119, Update the CLAUDE.md audit logging line to include
the same storage warning present in config/logging.go for
LOGGING_LOG_AUDIO_BODIES: add a clear note that enabling
LOGGING_LOG_AUDIO_BODIES stores full audio in the audit log and can grow storage
quickly, and include guidance on when to change the default (e.g., only enable
for short-term debugging or with retention/purging policies). Reference the
setting name LOGGING_LOG_AUDIO_BODIES and mirror the warning phrasing from
config/logging.go so users see the storage implications before enabling it.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document the /v1/audio/translations endpoint.

The PR objectives and endpoint registration include /v1/audio/translations as a supported audio endpoint, but the documentation only mentions /v1/audio/speech and transcriptions. Please add translations to the list of supported endpoints for completeness.

📝 Suggested documentation update
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions/translations; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions/translations; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
🤖 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 `@CLAUDE.md` at line 119, Update the audit logging docs entry that currently
lists `/v1/audio/speech` to also include `/v1/audio/translations`; specifically,
when describing `LOGGING_LOG_AUDIO_BODIES` and the logged audio endpoints, add
`/v1/audio/translations` alongside `/v1/audio/speech` and mention that it will
log base64 audio inputs/outputs (and dashboard playback) and upload metadata for
translations, and clarify that this behavior is independent of
`LOGGING_LOG_BODIES`.

Comment thread docs/advanced/audio-api.mdx Outdated
Comment thread docs/advanced/audio-api.mdx Outdated
Comment thread docs/advanced/configuration.mdx Outdated
Comment thread docs/advanced/configuration.mdx Outdated
Make LOGGING_LOG_AUDIO_BODIES a refinement of the master LOGGING_LOG_BODIES
switch rather than an independent flag. Audio bodies are only captured when
body logging is enabled; LOGGING_LOG_AUDIO_BODIES then decides whether the
audio bytes are embedded as base64 (playable) or recorded as a placeholder.

This avoids a privacy footgun: disabling LOGGING_LOG_BODIES for compliance
now guarantees no content bodies are stored, including audio. The useful
"log text but skip heavy audio" case is preserved (bodies on, audio off).

Update docs/env/config comments accordingly and add gating tests covering
the full matrix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (3)
CLAUDE.md (1)

119-119: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include the 10 MB cap, storage warning, and /v1/audio/translations endpoint.

Three documentation gaps:

  1. The 10 MB cap for base64 audio (documented in configuration.mdx) should be mentioned here
  2. The storage growth warning (present in config/logging.go and .env.template) is missing
  3. /v1/audio/translations is a supported endpoint but only speech and transcriptions are listed
🤖 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 `@CLAUDE.md` at line 119, Update the CLAUDE.md logging description to include
the 10 MB base64 audio cap, the storage growth warning, and the missing audio
translations endpoint: mention the 10 MB cap for base64 audio uploads (as in
configuration.mdx), add the storage growth warning text present in
config/logging.go and .env.template (explain logs can grow quickly and suggest
retention or disabling), and list /v1/audio/translations alongside
/v1/audio/speech and transcriptions in the supported endpoints sentence;
reference the existing LOGGING_* flags (LOGGING_LOG_BODIES,
LOGGING_LOG_AUDIO_BODIES, LOGGING_RETENTION_DAYS) when noting the audio size
limit and retention behavior.
docs/advanced/audio-api.mdx (1)

91-101: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Correct the placeholder format and add /v1/audio/translations.

Same two documentation issues as in configuration.mdx:

  1. Placeholder format incomplete. Line 97 documents {content_type, bytes} but should be {__audio__: true, content_type, bytes, stored: false} to match the actual AudioBodyLog structure.

  2. Missing /v1/audio/translations. Line 100 mentions /v1/audio/transcriptions but not /v1/audio/translations. Both STT endpoints behave identically (storing upload metadata, never raw audio bytes) and should be documented together.

🤖 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 `@docs/advanced/audio-api.mdx` around lines 91 - 101, Update the docs: replace
the incomplete placeholder `{content_type, bytes}` with the actual AudioBodyLog
shape `{__audio__: true, content_type, bytes, stored: false}` for the "Body
logging on, audio off" case, and add `/v1/audio/translations` alongside
`/v1/audio/transcriptions` noting that both STT endpoints store only upload
metadata (filename, model, params) and never raw uploaded audio bytes; ensure
the sentence mentions both endpoints behave identically and that
`/v1/audio/speech` still stores full generated audio when audio logging is on.
docs/advanced/configuration.mdx (1)

109-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Correct the placeholder format and add /v1/audio/translations.

Two documentation issues:

  1. Placeholder format is incomplete. Line 115 documents {content_type, bytes} but the actual AudioBodyLog structure includes the __audio__ marker field (see internal/auditlog/audio_body.go). The complete placeholder is {__audio__: true, content_type, bytes, stored: false}. The __audio__ marker is essential for the dashboard to detect and render audio bodies.

  2. Missing /v1/audio/translations. The PR adds audit logging for three endpoints (/v1/audio/speech, /v1/audio/transcriptions, and /v1/audio/translations), but line 112 only mentions transcriptions. Translations should be listed alongside transcriptions since both STT endpoints store upload metadata identically.

🤖 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 `@docs/advanced/configuration.mdx` around lines 109 - 117, Update the docs to
match the actual AudioBodyLog structure and list all three audio endpoints:
replace the incomplete placeholder `{content_type, bytes}` with the full marker
form used by AudioBodyLog (`{__audio__: true, content_type, bytes, stored:
false}` so the dashboard can detect audio), and add `/v1/audio/translations`
alongside `/v1/audio/transcriptions` when describing STT endpoints that store
upload metadata (also ensure `/v1/audio/speech` remains listed for the speech
endpoint).
🤖 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.

Duplicate comments:
In `@CLAUDE.md`:
- Line 119: Update the CLAUDE.md logging description to include the 10 MB base64
audio cap, the storage growth warning, and the missing audio translations
endpoint: mention the 10 MB cap for base64 audio uploads (as in
configuration.mdx), add the storage growth warning text present in
config/logging.go and .env.template (explain logs can grow quickly and suggest
retention or disabling), and list /v1/audio/translations alongside
/v1/audio/speech and transcriptions in the supported endpoints sentence;
reference the existing LOGGING_* flags (LOGGING_LOG_BODIES,
LOGGING_LOG_AUDIO_BODIES, LOGGING_RETENTION_DAYS) when noting the audio size
limit and retention behavior.

In `@docs/advanced/audio-api.mdx`:
- Around line 91-101: Update the docs: replace the incomplete placeholder
`{content_type, bytes}` with the actual AudioBodyLog shape `{__audio__: true,
content_type, bytes, stored: false}` for the "Body logging on, audio off" case,
and add `/v1/audio/translations` alongside `/v1/audio/transcriptions` noting
that both STT endpoints store only upload metadata (filename, model, params) and
never raw uploaded audio bytes; ensure the sentence mentions both endpoints
behave identically and that `/v1/audio/speech` still stores full generated audio
when audio logging is on.

In `@docs/advanced/configuration.mdx`:
- Around line 109-117: Update the docs to match the actual AudioBodyLog
structure and list all three audio endpoints: replace the incomplete placeholder
`{content_type, bytes}` with the full marker form used by AudioBodyLog
(`{__audio__: true, content_type, bytes, stored: false}` so the dashboard can
detect audio), and add `/v1/audio/translations` alongside
`/v1/audio/transcriptions` when describing STT endpoints that store upload
metadata (also ensure `/v1/audio/speech` remains listed for the speech
endpoint).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: cdef5216-54df-4c19-8a7a-0b7053eef2b7

📥 Commits

Reviewing files that changed from the base of the PR and between 720d3bc and 88fb970.

📒 Files selected for processing (8)
  • .env.template
  • CLAUDE.md
  • config/logging.go
  • docs/advanced/audio-api.mdx
  • docs/advanced/configuration.mdx
  • internal/auditlog/auditlog.go
  • internal/server/audio_service.go
  • internal/server/audio_service_test.go

Validated automated review findings (greptile, CodeRabbit) and applied the
valid ones:

- Drop /v1/audio/translations from the endpoint classifier, tests, and docs:
  the route is not registered or implemented, so classifying it was misleading
  (greptile P1). Rejected the conflicting suggestion to document it.
- Move the response-writer truncation flag inside the non-audio branch so an
  oversized audio response is not marked ResponseBodyTooBigToHandle while its
  body is fully captured by the audio handler (CodeRabbit). Add a regression test.
- Dashboard CSS: use the defined --text-muted variable instead of the undefined
  --muted (CodeRabbit).
- Clarify the audioBodyMaxBytes comment: the cap is on raw bytes; base64 is ~4/3
  larger, which matters on document stores with a hard per-record limit such as
  MongoDB's 16 MB (greptile P2).
- Set LogAudioBodies explicitly in DefaultConfig; correct the documented
  placeholder shape to {__audio__, content_type, bytes, stored: false}; note the
  10 MB cap in the CLAUDE.md reference (CodeRabbit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
docs/advanced/configuration.mdx (1)

91-100: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the audit-logging defaults in this table.

LOGGING_LOG_BODIES and LOGGING_LOG_HEADERS are documented as true here, but the audit config default in internal/auditlog.DefaultConfig() is false for both. Leaving the table as-is gives operators the wrong baseline for what gets persisted by default.

As per coding guidelines, documentation should be concise, practical, and user-focused, showing defaults.

🤖 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 `@docs/advanced/configuration.mdx` around lines 91 - 100, Update the defaults
in the configuration table to match the actual code defaults: change the
LOGGING_LOG_BODIES and LOGGING_LOG_HEADERS entries from `true` to `false` so
they align with internal/auditlog.DefaultConfig() (which sets both to false);
ensure the table reflects the real defaults shown by that function and keep the
rest of the variable descriptions unchanged.
docs/advanced/audio-api.mdx (1)

94-101: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Complete the body-logging behavior matrix.

This section currently describes the placeholder audio response, but it omits two load-bearing details from the feature contract: with audio logging off, the /v1/audio/speech request JSON is also not stored; with audio logging on, transcription responses still follow normal body logging while only the uploaded audio bytes stay excluded. Without those, the retention behavior is easy to misread.

As per coding guidelines, documentation should be concise, practical, and user-focused, showing defaults, explaining when to change them, and including minimal examples when useful.

🤖 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 `@docs/advanced/audio-api.mdx` around lines 94 - 101, The docs fragment about
body-logging for audio is missing two contract details: update the paragraph
that mentions LOGGING_LOG_BODIES and the `{__audio__, content_type, bytes,
stored: false}` placeholder to state that when LOGGING_LOG_BODIES=false the
`/v1/audio/speech` request JSON is not stored at all; and when body logging is
on, clarify that `/v1/audio/transcriptions` responses follow normal body-logging
semantics (metadata and text saved) but the raw uploaded audio bytes are never
persisted. Keep the three-mode matrix (logging off / logging on audio off /
logging on audio on), explicitly state the default, reference `/v1/audio/speech`
and `/v1/audio/transcriptions`, and ensure the placeholder description and
storage rules for request JSON vs. audio bytes are unambiguous.
🤖 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/css/dashboard.css`:
- Line 2898: Replace the unnecessary fallback usage "var(--text-muted, `#888`)"
with the consistent "var(--text-muted)" wherever it appears (e.g., the color
declarations currently using var(--text-muted, `#888`)); remove the hardcoded
"`#888`" fallback so the stylesheet consistently relies on the :root variable and
matches other usages of --text-muted.

---

Outside diff comments:
In `@docs/advanced/audio-api.mdx`:
- Around line 94-101: The docs fragment about body-logging for audio is missing
two contract details: update the paragraph that mentions LOGGING_LOG_BODIES and
the `{__audio__, content_type, bytes, stored: false}` placeholder to state that
when LOGGING_LOG_BODIES=false the `/v1/audio/speech` request JSON is not stored
at all; and when body logging is on, clarify that `/v1/audio/transcriptions`
responses follow normal body-logging semantics (metadata and text saved) but the
raw uploaded audio bytes are never persisted. Keep the three-mode matrix
(logging off / logging on audio off / logging on audio on), explicitly state the
default, reference `/v1/audio/speech` and `/v1/audio/transcriptions`, and ensure
the placeholder description and storage rules for request JSON vs. audio bytes
are unambiguous.

In `@docs/advanced/configuration.mdx`:
- Around line 91-100: Update the defaults in the configuration table to match
the actual code defaults: change the LOGGING_LOG_BODIES and LOGGING_LOG_HEADERS
entries from `true` to `false` so they align with
internal/auditlog.DefaultConfig() (which sets both to false); ensure the table
reflects the real defaults shown by that function and keep the rest of the
variable descriptions unchanged.
🪄 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: 2eeb2574-f490-429e-96ea-d879698ce690

📥 Commits

Reviewing files that changed from the base of the PR and between 88fb970 and 6a43c80.

📒 Files selected for processing (10)
  • CLAUDE.md
  • docs/advanced/audio-api.mdx
  • docs/advanced/configuration.mdx
  • internal/admin/dashboard/static/css/dashboard.css
  • internal/auditlog/audio_body.go
  • internal/auditlog/auditlog.go
  • internal/auditlog/auditlog_test.go
  • internal/auditlog/middleware.go
  • internal/core/endpoints.go
  • internal/core/endpoints_test.go
💤 Files with no reviewable changes (1)
  • internal/core/endpoints_test.go

Comment thread internal/admin/dashboard/static/css/dashboard.css Outdated
Comment thread internal/auditlog/audio_body.go Outdated
// ~4/3 of this (≈13.3 MB at the cap). On document stores with a hard per-record
// ceiling (e.g. MongoDB's 16 MB BSON limit) a near-cap clip plus other entry
// fields can approach that ceiling; lower this if you log audio to such a store.
const audioBodyMaxBytes = 10 * 1024 * 1024
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Encoded audio still exceeds storage

The cap is still applied to the raw audio size, so BuildAudioResponseBody accepts a 10 MiB speech response and then stores about 13.3 MiB of base64 in the audit entry. With MongoDB, that leaves very little room for request body, headers, workflow data, and BSON overhead before the 16 MiB document limit is exceeded. An otherwise allowed audio capture can fail the audit insert and lose the playback entry. The limit needs to be based on the stored representation or lowered enough to leave document headroom.

Context Used: CLAUDE.md (source)

Address the second round of PR review:

- greptile (P1): the 10 MB cap was on raw bytes, so the stored base64 (~13.3 MB)
  left too little room under MongoDB's 16 MB BSON document limit once request,
  header, and workflow fields were added — a near-cap clip could fail the audit
  insert and drop the whole entry. Lower the raw cap to 8 MB (~10.7 MB base64),
  leaving comfortable headroom, and update the docs (8 MB).
- CodeRabbit: drop the unnecessary `#888` fallback on `var(--text-muted)` to match
  the rest of the stylesheet (the variable is always defined in :root).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
docs/advanced/configuration.mdx (1)

112-112: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include /v1/audio/translations in the documentation.

The PR adds audit logging for three endpoints (/v1/audio/speech, /v1/audio/transcriptions, and /v1/audio/translations), but /v1/audio/translations is not mentioned here. Both STT endpoints behave identically (storing metadata only).

📝 Proposed fix
-  dashboard can play it back, and `/v1/audio/transcriptions` stores upload metadata
-  (never the raw audio bytes). It defaults to `false` because audio payloads are
+  dashboard can play it back, and `/v1/audio/transcriptions` and
+  `/v1/audio/translations` store upload metadata (never the raw audio bytes).
+  It defaults to `false` because audio payloads are
🤖 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 `@docs/advanced/configuration.mdx` at line 112, Update the sentence that
currently reads "dashboard can play it back, and `/v1/audio/transcriptions`
stores upload metadata" to also mention `/v1/audio/translations`, e.g., state
that both `/v1/audio/transcriptions` and `/v1/audio/translations` store upload
metadata and behave identically to `/v1/audio/speech`; ensure the new text
references `/v1/audio/translations` explicitly so the docs reflect the added
audit logging for that endpoint.
docs/advanced/audio-api.mdx (1)

100-101: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include /v1/audio/translations in the documentation.

The PR adds audit logging for three endpoints, but /v1/audio/translations is not mentioned. It should be documented alongside /v1/audio/transcriptions since both STT endpoints behave identically (storing metadata only).

📝 Proposed fix
-  player**, and `/v1/audio/transcriptions` stores upload metadata (filename, model,
-  params) but never the raw uploaded audio bytes.
+  player**, and `/v1/audio/transcriptions` and `/v1/audio/translations` store
+  upload metadata (filename, model, params) but never the raw uploaded audio bytes.
🤖 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 `@docs/advanced/audio-api.mdx` around lines 100 - 101, Update the sentence that
currently references `/v1/audio/transcriptions` to also include
`/v1/audio/translations`, clarifying that both STT endpoints store only upload
metadata (filename, model, params) and not raw audio bytes; locate the sentence
mentioning `/v1/audio/transcriptions` in docs/advanced/audio-api.mdx and change
it to list both endpoints together (e.g., "/v1/audio/transcriptions and
/v1/audio/translations store upload metadata...") so the documentation matches
the added audit logging.
CLAUDE.md (2)

119-119: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document /v1/audio/translations endpoint.

The PR objectives include /v1/audio/translations as a supported audio endpoint, but the documentation only mentions /v1/audio/speech and transcriptions. Based on learnings, documentation should be complete and practical.

📝 Proposed fix
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions/translations; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
🤖 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 `@CLAUDE.md` at line 119, Update the audit-logging documentation sentence that
currently only mentions `/v1/audio/speech` to also include
`/v1/audio/translations` as a supported audio endpoint and describe how it
interacts with the logging flags: state that when LOGGING_LOG_BODIES and
LOGGING_LOG_AUDIO_BODIES are enabled, audio payloads for both `/v1/audio/speech`
and `/v1/audio/translations` are recorded as base64 (capped at ≤8 MB, otherwise
recorded as `too_large`) and available for dashboard playback, and when
LOGGING_LOG_BODIES is off a placeholder is recorded; keep the references to
LOGGING_ENABLED, LOGGING_LOG_HEADERS, and LOGGING_RETENTION_DAYS unchanged.

119-119: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add storage warning for audio logging.

Based on learnings, documentation should explain when to change defaults. The code comment in config/logging.go includes a storage warning that should appear in user-facing docs to help users understand the implications before enabling this feature.

📝 Proposed fix
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; ⚠️ stores full audio, grows storage quickly; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
🤖 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 `@CLAUDE.md` at line 119, The docs list LOGGING_LOG_AUDIO_BODIES but lack the
storage/usage warning present in config/logging.go; update CLAUDE.md to include
a clear storage warning next to the LOGGING_LOG_AUDIO_BODIES description
explaining that enabling audio body logging stores base64 audio (≤8 MB, else
recorded as `too_large`), can significantly increase storage and retention
costs, and only takes effect when LOGGING_LOG_BODIES is enabled; reference the
same behavior and limits as defined by LOGGING_LOG_BODIES,
LOGGING_LOG_AUDIO_BODIES and LOGGING_RETENTION_DAYS so users know when to change
defaults.
🤖 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.

Duplicate comments:
In `@CLAUDE.md`:
- Line 119: Update the audit-logging documentation sentence that currently only
mentions `/v1/audio/speech` to also include `/v1/audio/translations` as a
supported audio endpoint and describe how it interacts with the logging flags:
state that when LOGGING_LOG_BODIES and LOGGING_LOG_AUDIO_BODIES are enabled,
audio payloads for both `/v1/audio/speech` and `/v1/audio/translations` are
recorded as base64 (capped at ≤8 MB, otherwise recorded as `too_large`) and
available for dashboard playback, and when LOGGING_LOG_BODIES is off a
placeholder is recorded; keep the references to LOGGING_ENABLED,
LOGGING_LOG_HEADERS, and LOGGING_RETENTION_DAYS unchanged.
- Line 119: The docs list LOGGING_LOG_AUDIO_BODIES but lack the storage/usage
warning present in config/logging.go; update CLAUDE.md to include a clear
storage warning next to the LOGGING_LOG_AUDIO_BODIES description explaining that
enabling audio body logging stores base64 audio (≤8 MB, else recorded as
`too_large`), can significantly increase storage and retention costs, and only
takes effect when LOGGING_LOG_BODIES is enabled; reference the same behavior and
limits as defined by LOGGING_LOG_BODIES, LOGGING_LOG_AUDIO_BODIES and
LOGGING_RETENTION_DAYS so users know when to change defaults.

In `@docs/advanced/audio-api.mdx`:
- Around line 100-101: Update the sentence that currently references
`/v1/audio/transcriptions` to also include `/v1/audio/translations`, clarifying
that both STT endpoints store only upload metadata (filename, model, params) and
not raw audio bytes; locate the sentence mentioning `/v1/audio/transcriptions`
in docs/advanced/audio-api.mdx and change it to list both endpoints together
(e.g., "/v1/audio/transcriptions and /v1/audio/translations store upload
metadata...") so the documentation matches the added audit logging.

In `@docs/advanced/configuration.mdx`:
- Line 112: Update the sentence that currently reads "dashboard can play it
back, and `/v1/audio/transcriptions` stores upload metadata" to also mention
`/v1/audio/translations`, e.g., state that both `/v1/audio/transcriptions` and
`/v1/audio/translations` store upload metadata and behave identically to
`/v1/audio/speech`; ensure the new text references `/v1/audio/translations`
explicitly so the docs reflect the added audit logging for that endpoint.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 019aca29-b954-42d4-a09f-07e5560f8625

📥 Commits

Reviewing files that changed from the base of the PR and between 6a43c80 and 99dc76c.

📒 Files selected for processing (5)
  • CLAUDE.md
  • docs/advanced/audio-api.mdx
  • docs/advanced/configuration.mdx
  • internal/admin/dashboard/static/css/dashboard.css
  • internal/auditlog/audio_body.go

@SantiagoDePolonia SantiagoDePolonia merged commit d8f5eff into main Jun 3, 2026
20 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.

2 participants