Skip to content

feat: implement real-time token tracking and API usage visibility with cost#376

Open
SoorejS wants to merge 6 commits into
AOSSIE-Org:mainfrom
SoorejS:feat/token-usage-visibility-v2
Open

feat: implement real-time token tracking and API usage visibility with cost#376
SoorejS wants to merge 6 commits into
AOSSIE-Org:mainfrom
SoorejS:feat/token-usage-visibility-v2

Conversation

@SoorejS

@SoorejS SoorejS commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Addressed Issues:

Fixes #375

Screenshots/Recordings:

Before:

26.03.2026_22.45.28_REC.mp4

After:

26.03.2026_22.55.20_REC.1.1.mp4

Additional Notes:

This PR introduces token observability with actionable insights beyond basic logging.

1. Granular Token Breakdown

Gemini’s PromptTokenCount includes system prompt + history + user input.

To isolate user input, this PR adds a CountTokens() call on raw input.

  • user_input_tokens → CountTokens(userMessage)
  • prompt_tokens → UsageMetadata.PromptTokenCount
  • response_tokens → UsageMetadata.CandidatesTokenCount
  • total_tokens → UsageMetadata.TotalTokenCount

2. Real-Time Cost Estimation

Adds estimated_cost_usd using Gemini 2.5 Flash pricing:

  • Input: $0.075 / 1M tokens
  • Output: $0.30 / 1M tokens

Available in API response and server logs.


3. Persistent Storage

Each message now stores token fields in MongoDB, enabling future analytics (per-user cost, session summaries, dashboards).


4. Observability (No UI Changes)

  • Server logs → real-time token usage
  • Browser → DevTools (Network tab)
  • MongoDB → stored per message

5. Compatibility

  • No breaking changes
  • Uses omitempty
  • Frontend unaffected

AI Usage Disclosure:

  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: Claude

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without review otherwise.

Summary by CodeRabbit

  • New Features

    • API responses for debate messages and judge results now include detailed token usage (user-input, prompt, response, total) and an estimated USD cost.
    • Message history now records per-message token usage for clearer accounting and display.
    • Recent user turns surface derived user-input token counts.
  • Bug Fix / Behavior

    • Judge fallback logic updated so a detected user win takes precedence when determining verdicts.

@coderabbitai

coderabbitai Bot commented Mar 26, 2026

Copy link
Copy Markdown

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
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds token-usage propagation and estimated USD cost from Gemini through services and controllers, persists token counts on messages, logs token metrics, updates service signatures to return usage metadata, and exposes token/cost fields in API JSON responses for debate message and judge endpoints.

Changes

Cohort / File(s) Summary
Controllers
backend/controllers/debatevsbot_controller.go
Add token/cost fields to DebateMessageResponse and JudgeResponse; consume usage from services; count user input tokens via services.CountTokens; compute prompt/response/total tokens and estimated USD cost; log metrics; persist token fields on appended bot models.Message; include fields in HTTP JSON responses.
Models
backend/models/debatevsbot.go
Extended Message with prompt_tokens, response_tokens, total_tokens, and user_input_tokens (JSON/BSON omitempty).
Debate services
backend/services/debatevsbot.go
Exported prompt builder (ConstructPrompt); changed GenerateBotResponse and JudgeDebate to accept context.Context and return (string, *genai.GenerateContentResponseUsageMetadata); propagate usage metadata; adjusted prompt template placeholder.
Gemini wrapper
backend/services/gemini.go
generateModelText/generateDefaultModelText now accept modelName and return usage metadata; added exported CountTokens(ctx, text); propagate resp.UsageMetadata on success.
Call-site adaptations & logging
backend/services/coach.go, backend/services/pros_cons.go, backend/services/transcriptservice.go
Updated callers to capture additional usage return (often _ when unused); added logging and tightened error handling in transcript service; switch-based duplicate-check handling.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as Controller (debatevsbot)
    participant Service as Service (debatevsbot)
    participant Gemini as Gemini API
    participant DB as Database

    Client->>Controller: POST /debate/send (user message)
    activate Controller
    Controller->>Service: GenerateBotResponse(ctx, history, ...)
    activate Service
    Service->>Gemini: generateDefaultModelText(ctx, prompt)
    activate Gemini
    Gemini-->>Service: (botText, usageMetadata)
    deactivate Gemini
    Service-->>Controller: (botText, usageMetadata)
    deactivate Service
    Controller->>Gemini: CountTokens(ctx, user_message_text)
    activate Gemini
    Gemini-->>Controller: user_input_tokens
    deactivate Gemini
    Controller->>DB: Append bot Message with Prompt/Response/Total tokens
    DB-->>Controller: OK
    Controller-->>Client: DebateMessageResponse {response, user_input_tokens, prompt_tokens, response_tokens, total_tokens, estimated_cost_usd}
    deactivate Controller
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇
I nibble prompts beneath the moon’s soft light,
Counting tokens till each line feels right.
Logs hum, carrots tally cost in sight,
Debates hop brighter in the quiet night.
🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.47% 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 and concisely captures the main objective: implementing token tracking with cost visibility across the debate API responses and logging.
Linked Issues check ✅ Passed All core objectives from issue #375 are met: token metadata (prompt/response/total tokens) is exposed in API JSON responses [375], structured logging with token counts is implemented, and cost estimation using Gemini 2.5 Flash pricing is added.
Out of Scope Changes check ✅ Passed Changes align with stated objectives—token tracking, cost estimation, and structured logging. Additional changes to coach.go, pros_cons.go, and transcriptservice.go involve updating function signatures to handle new return values, which are necessary follow-up changes for implementing token visibility.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
backend/controllers/debatevsbot_controller.go (1)

285-290: ⚠️ Potential issue | 🟡 Minor

Operator precedence issue may cause unexpected behavior.

Lines 286 and 290 mix && and || without parentheses. In Go, && has higher precedence than ||, so A || B && C is evaluated as A || (B && C), which may not be the intended logic.

For example, line 286:

strings.Contains(resultLower, "user") && strings.Contains(resultLower, "win")

This expression is evaluated independently from the || conditions before it due to precedence.

Proposed fix for clarity
-		if strings.Contains(resultLower, "user win") || strings.Contains(resultLower, "user wins") ||
-			strings.Contains(resultLower, "user") && strings.Contains(resultLower, "win") {
+		if strings.Contains(resultLower, "user win") || strings.Contains(resultLower, "user wins") ||
+			(strings.Contains(resultLower, "user") && strings.Contains(resultLower, "win")) {
 			resultStatus = "win"
 		} else if strings.Contains(resultLower, "bot win") || strings.Contains(resultLower, "bot wins") ||
 			strings.Contains(resultLower, "lose") || strings.Contains(resultLower, "loss") ||
-			strings.Contains(resultLower, "bot") && strings.Contains(resultLower, "win") {
+			(strings.Contains(resultLower, "bot") && strings.Contains(resultLower, "win")) {
 			resultStatus = "loss"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/debatevsbot_controller.go` around lines 285 - 290, The
conditional that sets resultStatus based on resultLower contains mixed && and ||
without grouping, causing operator-precedence bugs; update the if/else-if that
checks strings.Contains(resultLower, "user win") ... and the subsequent else-if
for bot/lose so that combined checks like strings.Contains(resultLower, "user")
&& strings.Contains(resultLower, "win") are wrapped in parentheses (or
refactored into separate boolean variables) and the ORed alternatives are
clearly grouped—ensure both the "user win" branch and the "bot win/lose" branch
use explicit grouping so the intended logic for resultStatus ("win"/"lose") is
unambiguous.
backend/services/transcriptservice.go (1)

132-241: ⚠️ Potential issue | 🟡 Minor

Silent error swallowing in default case.

The default case (lines 240-241) silently ignores all errors other than nil and mongo.ErrNoDocuments. This could mask database connection issues, timeouts, or other unexpected errors, making debugging difficult.

Consider logging or handling the error:

Proposed fix
 			default:
+				log.Printf("Error checking for existing transcript: %v", err)
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/transcriptservice.go` around lines 132 - 241, The switch on
err currently ignores unexpected errors in the default branch; update the
default case to surface or log the error instead of swallowing it—use the
existing logger or return the error so callers can handle it. Locate the switch
that checks err (the same block that later calls SaveDebateTranscript,
UpdateRatings and db.MongoDatabase.Collection("debates").InsertMany) and replace
the empty default with a call to log the error (including err.Error() and
context like roomID) and return or propagate the error up the call stack to
avoid hiding DB/network failures.
🧹 Nitpick comments (2)
backend/controllers/debatevsbot_controller.go (1)

49-66: Consider adding omitempty for consistency with the Message model.

The DebateMessageResponse and JudgeResponse structs will always include token fields in JSON responses, even when they're zero (e.g., when usage metadata is nil). The Message model uses omitempty for these same fields.

For consistent API behavior and backward compatibility, consider adding omitempty:

Proposed fix
 type DebateMessageResponse struct {
 	DebateId       string `json:"debateId"`
 	BotName        string `json:"botName"`
 	BotLevel       string `json:"botLevel"`
 	Topic          string `json:"topic"`
 	Stance         string `json:"stance"`
 	Response       string `json:"response"`
-	PromptTokens   int    `json:"prompt_tokens"`
-	ResponseTokens int    `json:"response_tokens"`
-	TotalTokens    int    `json:"total_tokens"`
+	PromptTokens   int    `json:"prompt_tokens,omitempty"`
+	ResponseTokens int    `json:"response_tokens,omitempty"`
+	TotalTokens    int    `json:"total_tokens,omitempty"`
 }

 type JudgeResponse struct {
-	Result         string `json:"result"`
-	PromptTokens   int    `json:"prompt_tokens"`
-	ResponseTokens int    `json:"response_tokens"`
-	TotalTokens    int    `json:"total_tokens"`
+	Result         string `json:"result"`
+	PromptTokens   int    `json:"prompt_tokens,omitempty"`
+	ResponseTokens int    `json:"response_tokens,omitempty"`
+	TotalTokens    int    `json:"total_tokens,omitempty"`
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/debatevsbot_controller.go` around lines 49 - 66, Add JSON
`omitempty` tags to the token fields on DebateMessageResponse and JudgeResponse
so zero-value token fields are omitted like Message does; specifically update
DebateMessageResponse's PromptTokens, ResponseTokens, TotalTokens and
JudgeResponse's PromptTokens, ResponseTokens, TotalTokens to use
`json:"prompt_tokens,omitempty"`, `json:"response_tokens,omitempty"`, and
`json:"total_tokens,omitempty"` respectively to ensure consistent API output
when usage metadata is nil.
backend/services/debatevsbot.go (1)

110-113: Consider if exporting ConstructPrompt is intentional.

The function was renamed from constructPrompt to ConstructPrompt, making it part of the public API. Based on the context snippet, it's only called internally by GenerateBotResponse. If this export is for testing purposes, consider adding a comment to document the intent, or keep it unexported if external access isn't needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/debatevsbot.go` around lines 110 - 113, The function
ConstructPrompt was exported (capitalized) but appears only used internally by
GenerateBotResponse; either revert the name to unexported constructPrompt to
keep it internal, or if export is intentional for tests/clients add a brief
comment above ConstructPrompt documenting that it's intentionally public for
external use/testing (mention GenerateBotResponse and ConstructPrompt in the
comment to clarify relationship).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 285-290: The conditional that sets resultStatus based on
resultLower contains mixed && and || without grouping, causing
operator-precedence bugs; update the if/else-if that checks
strings.Contains(resultLower, "user win") ... and the subsequent else-if for
bot/lose so that combined checks like strings.Contains(resultLower, "user") &&
strings.Contains(resultLower, "win") are wrapped in parentheses (or refactored
into separate boolean variables) and the ORed alternatives are clearly
grouped—ensure both the "user win" branch and the "bot win/lose" branch use
explicit grouping so the intended logic for resultStatus ("win"/"lose") is
unambiguous.

In `@backend/services/transcriptservice.go`:
- Around line 132-241: The switch on err currently ignores unexpected errors in
the default branch; update the default case to surface or log the error instead
of swallowing it—use the existing logger or return the error so callers can
handle it. Locate the switch that checks err (the same block that later calls
SaveDebateTranscript, UpdateRatings and
db.MongoDatabase.Collection("debates").InsertMany) and replace the empty default
with a call to log the error (including err.Error() and context like roomID) and
return or propagate the error up the call stack to avoid hiding DB/network
failures.

---

Nitpick comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 49-66: Add JSON `omitempty` tags to the token fields on
DebateMessageResponse and JudgeResponse so zero-value token fields are omitted
like Message does; specifically update DebateMessageResponse's PromptTokens,
ResponseTokens, TotalTokens and JudgeResponse's PromptTokens, ResponseTokens,
TotalTokens to use `json:"prompt_tokens,omitempty"`,
`json:"response_tokens,omitempty"`, and `json:"total_tokens,omitempty"`
respectively to ensure consistent API output when usage metadata is nil.

In `@backend/services/debatevsbot.go`:
- Around line 110-113: The function ConstructPrompt was exported (capitalized)
but appears only used internally by GenerateBotResponse; either revert the name
to unexported constructPrompt to keep it internal, or if export is intentional
for tests/clients add a brief comment above ConstructPrompt documenting that
it's intentionally public for external use/testing (mention GenerateBotResponse
and ConstructPrompt in the comment to clarify relationship).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc56e4f3-93bc-4828-8c0a-c2695ce29a27

📥 Commits

Reviewing files that changed from the base of the PR and between 09ef1bb and b2513ba.

📒 Files selected for processing (7)
  • backend/controllers/debatevsbot_controller.go
  • backend/models/debatevsbot.go
  • backend/services/coach.go
  • backend/services/debatevsbot.go
  • backend/services/gemini.go
  • backend/services/pros_cons.go
  • backend/services/transcriptservice.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
backend/services/transcriptservice.go (1)

194-210: ⚠️ Potential issue | 🟠 Major

Avoid logging raw participant emails here.

These error logs emit email addresses on normal persistence failures. That is avoidable PII exposure; log the room/role or a non-sensitive identifier instead.

🧹 Suggested fix
-					log.Printf("[TRANSCRIPT] Error saving transcript for 'for' user %s in room %s: %v", forUser.Email, roomID, err)
+					log.Printf("[TRANSCRIPT] Error saving transcript for role=for room=%s: %v", roomID, err)
...
-					log.Printf("[TRANSCRIPT] Error saving transcript for 'against' user %s in room %s: %v", againstUser.Email, roomID, err)
+					log.Printf("[TRANSCRIPT] Error saving transcript for role=against room=%s: %v", roomID, err)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/transcriptservice.go` around lines 194 - 210, The error logs
around the SaveDebateTranscript calls leak participant emails (forUser.Email and
againstUser.Email); update the two log.Printf calls to avoid PII by logging a
non-sensitive identifier such as the role ("for"/"against"), the user ID
(forUser.ID / againstUser.ID) or an anonymized token, and include roomID and
context instead; specifically modify the log.Printf invocations immediately
after SaveDebateTranscript (and the earlier one for the "for" user) to replace
raw email values with a safe identifier and keep the existing error and roomID
information.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 188-195: The Message model currently lacks a UserInputTokens field
so user_input_tokens is not persisted; add a UserInputTokens (int) field to
models.Message in backend/models/debatevsbot.go and update any DB marshaling if
necessary, then populate that field when creating updatedHistory in the
controller (the append using updatedHistory and models.Message) so you include
UserInputTokens alongside PromptTokens, ResponseTokens, and TotalTokens; make
the same change in the other similar block (the append at the later section
referenced) so both places persist the user input token split.
- Around line 156-169: The extra CountTokens call uses context.Background(),
which can hang SendDebateMessage; replace that call with a context that has a
short timeout/deadline (e.g., using context.WithTimeout) and ensure you call
cancel() via defer; pass that timed context to services.CountTokens and handle
timeout/errors gracefully (fall back to zero tokens or log) so the RPC cannot
stall SendDebateMessage (refer to the userInputTokens/userInputText block and
services.CountTokens within SendDebateMessage).

In `@backend/services/debatevsbot.go`:
- Around line 285-287: When response is empty you currently return
personalityErrorResponse(...), nil which discards any non-nil UsageMetadata
returned by generateDefaultModelText; instead propagate that UsageMetadata along
with the error response. Update the branch in debatevsbot.go where response ==
"" (and the similar branch around lines 457-463) to capture the UsageMetadata
from generateDefaultModelText and return personalityErrorResponse(botName, "Lost
in translation, my thoughts are."), usageMeta (or wrap/merge as your call sites
expect) rather than nil so token/cost visibility is preserved.

In `@backend/services/transcriptservice.go`:
- Around line 247-255: The duplicate-check FindOne error path should abort the
function instead of continuing to cleanup; change the default/error branch
handling around the duplicate-check (the code that logs "[TRANSCRIPT] Unexpected
error checking existing transcript in room %s") to return or propagate the error
immediately so you do not reach transcriptCollection.DeleteMany(ctx,
bson.M{"roomId": roomID}) and accidentally delete source transcripts after
debate_results was already inserted; update the handler in the function that
performs the FindOne check (and any surrounding judgment flow that writes to
debate_results) to stop execution on unexpected FindOne errors and surface the
error to the caller.

---

Outside diff comments:
In `@backend/services/transcriptservice.go`:
- Around line 194-210: The error logs around the SaveDebateTranscript calls leak
participant emails (forUser.Email and againstUser.Email); update the two
log.Printf calls to avoid PII by logging a non-sensitive identifier such as the
role ("for"/"against"), the user ID (forUser.ID / againstUser.ID) or an
anonymized token, and include roomID and context instead; specifically modify
the log.Printf invocations immediately after SaveDebateTranscript (and the
earlier one for the "for" user) to replace raw email values with a safe
identifier and keep the existing error and roomID information.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30a037f9-fbc8-46a0-91c8-a283e8132b16

📥 Commits

Reviewing files that changed from the base of the PR and between 13dc550 and 7df70d3.

📒 Files selected for processing (3)
  • backend/controllers/debatevsbot_controller.go
  • backend/services/debatevsbot.go
  • backend/services/transcriptservice.go

Comment thread backend/controllers/debatevsbot_controller.go
Comment thread backend/controllers/debatevsbot_controller.go
Comment thread backend/services/debatevsbot.go
Comment thread backend/services/transcriptservice.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
backend/services/transcriptservice.go (1)

195-210: ⚠️ Potential issue | 🔴 Critical

Don't continue into cleanup after post-judgment persistence failures.

These branches only log and continue, but the result document was already inserted earlier. If transcript saves or rating/debate writes fail here, DeleteMany still removes the recoverable source transcripts and later retries short-circuit as “already judged”, so the missing side effects become permanent.

Also applies to: 223-224, 232-233, 253-257

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/transcriptservice.go` around lines 195 - 210, The current
flow logs errors from SaveDebateTranscript (and similar persistence calls) and
proceeds to call DeleteMany, which can permanently remove source transcripts
after the result doc was inserted; change the error handling in the branches
that call SaveDebateTranscript (and the other persistence functions referenced)
to return the error immediately (or propagate it up) instead of just logging and
continuing so cleanup (DeleteMany) is not run when these saves fail; locate
calls to SaveDebateTranscript, any rating/debate write functions, and the
DeleteMany invocation and ensure failures from SaveDebateTranscript cause an
early return/error propagation before DeleteMany is executed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 171-177: The code currently writes userInputTokens into the last
user message (req.History[*].UserInputTokens) and then duplicates the same value
onto the appended bot message, causing double-counting; update the logic so
user_input_tokens is persisted in one canonical place — keep setting
req.History[i].UserInputTokens on the last user message (in the loop that checks
Sender == "User") and remove the duplicate assignment that writes the same
userInputTokens onto the bot message when you append it (also remove the
duplicate in the similar block around the 200-208 region), or alternatively move
storage to a single request-level field and eliminate per-bot-message writes;
adjust any tests/consumers expecting the bot message field accordingly.
- Around line 153-154: The Gemini RPC calls ignore request cancellation because
services.GenerateBotResponse and services.JudgeDebate use context.Background();
change both function signatures to accept a context.Context (e.g., func
GenerateBotResponse(ctx context.Context, ... ) and func JudgeDebate(ctx
context.Context, ... )), update their internal calls to use the passed ctx, and
from the controller pass c.Request.Context() (optionally wrap it with a timeout
via context.WithTimeout before passing) at the existing call sites (the
GenerateBotResponse invocation around the bot response and the JudgeDebate call
near line 271) so client cancellations and deadlines propagate into Gemini
calls.

In `@backend/services/transcriptservice.go`:
- Line 195: Replace instances where log.Printf emits raw participant emails
(forUser.Email / againstUser.Email) with a non-PII identifier such as the user's
internal ID (forUser.ID / againstUser.ID) or the role ("for"/"against") plus
roomID; update the two occurrences around the transcript save error (the
log.Printf at the shown diff and the similar one at line ~210) so they log
roomID and role or internal ID instead of email, and ensure the formatted
message still includes the error variable (err) and context.

---

Duplicate comments:
In `@backend/services/transcriptservice.go`:
- Around line 195-210: The current flow logs errors from SaveDebateTranscript
(and similar persistence calls) and proceeds to call DeleteMany, which can
permanently remove source transcripts after the result doc was inserted; change
the error handling in the branches that call SaveDebateTranscript (and the other
persistence functions referenced) to return the error immediately (or propagate
it up) instead of just logging and continuing so cleanup (DeleteMany) is not run
when these saves fail; locate calls to SaveDebateTranscript, any rating/debate
write functions, and the DeleteMany invocation and ensure failures from
SaveDebateTranscript cause an early return/error propagation before DeleteMany
is executed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: d5d13542-a593-4b61-8d64-1b5ff056a82f

📥 Commits

Reviewing files that changed from the base of the PR and between 7df70d3 and d88fb0b.

📒 Files selected for processing (4)
  • backend/controllers/debatevsbot_controller.go
  • backend/models/debatevsbot.go
  • backend/services/debatevsbot.go
  • backend/services/transcriptservice.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/services/debatevsbot.go

Comment thread backend/controllers/debatevsbot_controller.go Outdated
Comment thread backend/controllers/debatevsbot_controller.go
Comment thread backend/services/transcriptservice.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
backend/controllers/debatevsbot_controller.go (2)

223-224: ⚠️ Potential issue | 🟠 Major

Silent database write failure - errors are discarded.

The empty error handling block means database save failures go unnoticed. This contradicts the PR's observability goals and can cause silent data loss, preventing token analytics from being persisted.

🔧 Proposed fix
-	if err := db.SaveDebateVsBot(debate); err != nil {
-	}
+	if err := db.SaveDebateVsBot(debate); err != nil {
+		log.Printf("[DB ERROR] Failed to save debate: %v", err)
+		// Continue to return response - don't fail the request for DB errors
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/debatevsbot_controller.go` around lines 223 - 224, The
db.SaveDebateVsBot(debate) call currently swallows errors; update the error
handling in the surrounding function (the handler calling db.SaveDebateVsBot) to
log the error via the existing logger (e.g., process or request logger) and
return an appropriate error response (or propagate the error) instead of leaving
the block empty; include context (operation and debate ID) in the log message
and ensure the function returns/handles the error so database write failures are
observable and do not silently drop token analytics data.

288-289: ⚠️ Potential issue | 🟠 Major

Silent database update failure - errors are discarded.

Same issue as above: the empty error block silently ignores failures when updating debate outcomes.

🔧 Proposed fix
-	if err := db.UpdateDebateVsBotOutcome(email, result); err != nil {
-	}
+	if err := db.UpdateDebateVsBotOutcome(email, result); err != nil {
+		log.Printf("[DB ERROR] Failed to update debate outcome: %v", err)
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/debatevsbot_controller.go` around lines 288 - 289, The
UpdateDebateVsBotOutcome call currently swallows errors (if err :=
db.UpdateDebateVsBotOutcome(email, result); err != nil { }), so restore proper
error handling: check the returned err from db.UpdateDebateVsBotOutcome(email,
result), log the error (using the controller's logger or fmt) with context
including email and result, and return or propagate an appropriate error/HTTP
response instead of silently ignoring it; ensure you update the surrounding
handler to handle the failure path (e.g., return a 500 or call next with the
error) so failures are visible and actionable.
🧹 Nitpick comments (1)
backend/services/transcriptservice.go (1)

489-489: Consider capturing usage metadata for observability.

The usage metadata from generateDefaultModelText is discarded here. Given the PR objectives around token tracking and cost visibility, consider logging the token usage for human vs human debate judgments as well:

text, usageMeta, err := generateDefaultModelText(ctx, prompt)
if err != nil {
    return "Unable to judge."
}
if usageMeta != nil {
    log.Printf("[TOKEN USAGE] JudgeHvH | Prompt: %d | Response: %d | Total: %d",
        usageMeta.PromptTokenCount, usageMeta.CandidatesTokenCount, usageMeta.TotalTokenCount)
}

This would provide consistent observability across all AI interactions, aligning with the structured logging pattern mentioned in the PR objectives.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/transcriptservice.go` at line 489, The call to
generateDefaultModelText currently discards the usage metadata; update the call
in transcriptservice.go to capture the second return value (e.g., usageMeta)
alongside text and err, handle err as before, and if usageMeta is non-nil emit a
structured log with PromptTokenCount, CandidatesTokenCount (or
ResponseTokenCount) and TotalTokenCount for the JudgeHvH path; reference the
existing generateDefaultModelText call and the usageMeta fields to ensure token
counts are logged for observability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 223-224: The db.SaveDebateVsBot(debate) call currently swallows
errors; update the error handling in the surrounding function (the handler
calling db.SaveDebateVsBot) to log the error via the existing logger (e.g.,
process or request logger) and return an appropriate error response (or
propagate the error) instead of leaving the block empty; include context
(operation and debate ID) in the log message and ensure the function
returns/handles the error so database write failures are observable and do not
silently drop token analytics data.
- Around line 288-289: The UpdateDebateVsBotOutcome call currently swallows
errors (if err := db.UpdateDebateVsBotOutcome(email, result); err != nil { }),
so restore proper error handling: check the returned err from
db.UpdateDebateVsBotOutcome(email, result), log the error (using the
controller's logger or fmt) with context including email and result, and return
or propagate an appropriate error/HTTP response instead of silently ignoring it;
ensure you update the surrounding handler to handle the failure path (e.g.,
return a 500 or call next with the error) so failures are visible and
actionable.

---

Nitpick comments:
In `@backend/services/transcriptservice.go`:
- Line 489: The call to generateDefaultModelText currently discards the usage
metadata; update the call in transcriptservice.go to capture the second return
value (e.g., usageMeta) alongside text and err, handle err as before, and if
usageMeta is non-nil emit a structured log with PromptTokenCount,
CandidatesTokenCount (or ResponseTokenCount) and TotalTokenCount for the
JudgeHvH path; reference the existing generateDefaultModelText call and the
usageMeta fields to ensure token counts are logged for observability.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a0568da-ae13-456a-ab58-8121b030709b

📥 Commits

Reviewing files that changed from the base of the PR and between d88fb0b and e1301e0.

📒 Files selected for processing (3)
  • backend/controllers/debatevsbot_controller.go
  • backend/services/debatevsbot.go
  • backend/services/transcriptservice.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/services/debatevsbot.go

@SoorejS SoorejS closed this Mar 27, 2026
@SoorejS SoorejS reopened this Mar 27, 2026
@SoorejS

SoorejS commented Mar 27, 2026

Copy link
Copy Markdown
Contributor Author

sorry
i closed this by mistake and i opened to fix that mistake of mine

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.

[FEATURE]: Add real-time token usage visibility via API response and backend logging

1 participant