Skip to content

fix(gateway): include image input tokens in accounting - #1618

Merged
steebchen merged 4 commits into
mainfrom
image-token-accounting
Feb 9, 2026
Merged

steebchen merged 4 commits into
mainfrom
image-token-accounting

Conversation

@steebchen

@steebchen steebchen commented Feb 9, 2026

Copy link
Copy Markdown
Member

Summary

Fixed image token accounting so that input + completion = total. Image input tokens are now included in the returned promptTokens field rather than being only in the separate imageInputTokens metadata field.

What changed

  • calculateCosts now returns promptTokens that includes image input tokens
  • All database logging paths adjusted to use the updated token values
  • Updated test expectations to match the new accounting

Impact

  • No change to billing (image tokens still charged at their own rate)
  • Fixes the gap where totals didn't add up (input + completion ≠ total)
  • Provides consistent token accounting for analytics and reporting

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Token accounting now consistently includes image input tokens in prompt and total token counts across streaming, cached, upstream, cancelled, and timeout/error flows so reported usage and billing are accurate.
  • Tests
    • Updated cost calculations tests to reflect image input tokens being counted toward prompt token totals.

Include image input tokens in the returned promptTokens so that
input + completion = total tokens. Billing remains unchanged as
image tokens are still charged at their own rate separately.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 9, 2026 12:18
@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Chat gateway token accounting now prefers costs.promptTokens (when provided) and includes image input tokens for specific providers; logging, usage objects, and total token calculations were updated across streaming, cached, cancelled, and error paths to reflect costs-based accounting.

Changes

Cohort / File(s) Summary
Cost calculation logic & tests
apps/gateway/src/lib/costs.ts, apps/gateway/src/lib/costs.spec.ts
calculateCosts now conditionally adds imageInputTokens into returned promptTokens for certain Google-related providers; tests adjusted to expect image tokens included in promptTokens.
Gateway chat token & usage accounting
apps/gateway/src/chat/chat.ts
Reworked token accounting to prefer costs.promptTokens (and cancelledCosts.promptTokens), compute imageInputCount/imageInputTokens from requestedModel, update dataStorageCost and final usage objects for streaming/non-streaming and cached/cancelled/error paths.
Streaming usage chunk construction
apps/gateway/src/chat/chat.ts (streaming-specific sections)
Adjusted streaming chunk creation to compute adjusted prompt/completion tokens with image input adjustments and return structured usage chunks using costs-based values.
Provider-specific handling
apps/gateway/src/lib/costs.ts, apps/gateway/src/chat/chat.ts
Added provider-specific rules (Google / Moonshot paths) to align prompt token reporting with upstream behavior and ensure canonicalization of costs.promptTokens where available.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Gateway
  participant Costs
  participant Provider
  participant Storage

  Client->>Gateway: Send chat request (may include images)
  Gateway->>Costs: calculateCosts(request, provider)
  Costs-->>Gateway: {promptTokens, imageInputTokens, completionTokens, ...}
  Gateway->>Provider: Request/stream model using adjusted accounting
  Provider-->>Gateway: Streamed response / final usage info
  Gateway->>Storage: Persist usage (uses costs.promptTokens + image adjustments)
  Gateway-->>Client: Return response + canonicalized usage (total_tokens from costs)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly and clearly summarizes the main change: fixing gateway token accounting to include image input tokens in the accounting logic.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch image-token-accounting

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
apps/gateway/src/chat/chat.ts (1)

375-379: Hardcoded model check is fragile but acceptable for now.

The image counting gate is tied to a single model string. If additional models need image-input-token accounting in the future, this will need to become a list or a model-property check. Fine for this PR scope.


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.

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

Pull request overview

This PR updates gateway token accounting so that image input tokens are included in promptTokens, making prompt + completion (+ reasoning) = total consistent for analytics/reporting while keeping image billing at its own rate.

Changes:

  • Update calculateCosts() to return promptTokens inclusive of image input tokens.
  • Adjust chat logging paths to prefer the updated costs.promptTokens and to recompute totalTokens where needed.
  • Update unit test expectations for image token accounting.

Reviewed changes

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

File Description
apps/gateway/src/lib/costs.ts Adjusts returned promptTokens to include image input tokens.
apps/gateway/src/lib/costs.spec.ts Updates test expectations to match new promptTokens semantics.
apps/gateway/src/chat/chat.ts Updates DB logging to use the new prompt/total token accounting when images are present.

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

Comment thread apps/gateway/src/chat/chat.ts Outdated
Comment on lines +3908 to +3914
// Include image input tokens in prompt/total for consistent accounting
if (costs.imageInputTokens) {
calculatedPromptTokens =
(calculatedPromptTokens || 0) + costs.imageInputTokens;
calculatedTotalTokens =
(calculatedTotalTokens || 0) + costs.imageInputTokens;
}

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

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

This block mutates calculatedPromptTokens/calculatedTotalTokens by adding costs.imageInputTokens. If calculatedPromptTokens already included image tokens from upstream usage for some providers/models, this will double-count in logs and any later calculations that rely on these variables. Prefer setting these values from costs.promptTokens (which is already the source of truth) or guard the addition behind an explicit “image tokens not included in upstream usage” condition.

Suggested change
// Include image input tokens in prompt/total for consistent accounting
if (costs.imageInputTokens) {
calculatedPromptTokens =
(calculatedPromptTokens || 0) + costs.imageInputTokens;
calculatedTotalTokens =
(calculatedTotalTokens || 0) + costs.imageInputTokens;
}
// Sync token accounting with costs to avoid double-counting image tokens
if (typeof costs.promptTokens === "number") {
calculatedPromptTokens = costs.promptTokens;
}
if (typeof costs.completionTokens === "number") {
calculatedCompletionTokens = costs.completionTokens;
}
if (typeof costs.cachedTokens === "number") {
cachedTokens = costs.cachedTokens;
}
calculatedTotalTokens =
(calculatedPromptTokens || 0) +
(calculatedCompletionTokens || 0) +
(cachedTokens || 0);

Copilot uses AI. Check for mistakes.
Comment thread apps/gateway/src/chat/chat.ts Outdated
Comment on lines +4718 to +4728
// Include image input tokens in prompt/total for consistent accounting
if (costs.imageInputTokens) {
calculatedPromptTokens =
(calculatedPromptTokens || 0) + costs.imageInputTokens;
totalTokens = (
(calculatedPromptTokens || 0) +
(calculatedCompletionTokens || 0) +
(calculatedReasoningTokens || 0)
).toString();
}

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

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

Recomputing calculatedPromptTokens/totalTokens by adding costs.imageInputTokens has the same double-counting risk as the streaming path if upstream promptTokens already include image tokens for a given provider/model. Consider using costs.promptTokens directly as the canonical prompt token count (and only applying a manual image-token adjustment when you know the provider usage excludes image tokens).

Suggested change
// Include image input tokens in prompt/total for consistent accounting
if (costs.imageInputTokens) {
calculatedPromptTokens =
(calculatedPromptTokens || 0) + costs.imageInputTokens;
totalTokens = (
(calculatedPromptTokens || 0) +
(calculatedCompletionTokens || 0) +
(calculatedReasoningTokens || 0)
).toString();
}
// Use costs.promptTokens as the canonical prompt token count to avoid
// double-counting image tokens that may already be included upstream.

Copilot uses AI. Check for mistakes.
Comment thread apps/gateway/src/lib/costs.ts Outdated
Comment thread apps/gateway/src/chat/chat.ts
Only add image input tokens to promptTokens for providers that
exclude them from upstream usage (Google). Other providers like
OpenAI and xAI already include image tokens in their reported
prompt_tokens, so adding them again would double-count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 (1)
apps/gateway/src/chat/chat.ts (1)

3066-3083: ⚠️ Potential issue | 🟠 Major

Streaming [DONE] usage chunk still has prompt + completion ≠ total for Google providers with image inputs.

The PR updates prompt_tokens (line 3067) to use streamingCosts.promptTokens which now includes image input tokens for Google. However, total_tokens (line 3083) still prefers finalTotalTokens — the upstream value that does not include image input tokens. This means the client-facing SSE usage in the common [DONE] path still has the exact mismatch the PR aims to fix.

When finalTotalTokens is non-null (which is the typical case for Google streaming), the fallback to fallbackTotal is never reached.

Proposed fix
 									total_tokens: (() => {
 										const fallbackTotal =
 											(streamingCosts.promptTokens ||
 												finalPromptTokens ||
 												0) +
 											(streamingCosts.completionTokens ||
 												finalCompletionTokens ||
 												0) +
 											(reasoningTokens || 0);
-										return Math.max(1, finalTotalTokens ?? fallbackTotal);
+										// If costs include image input tokens, recompute total
+										// to ensure prompt + completion = total
+										if (streamingCosts.imageInputTokens) {
+											return Math.max(1, fallbackTotal);
+										}
+										return Math.max(1, finalTotalTokens ?? fallbackTotal);
 									})(),
🤖 Fix all issues with AI agents
In `@apps/gateway/src/chat/chat.ts`:
- Around line 4727-4740: totalTokens is being reassigned from number | null to a
string when you do .toString() inside the costs.promptTokens branch, causing a
type mismatch for downstream code (originating from parseProviderResponse). Fix
by keeping totalTokens as a number: when costs.promptTokens >
calculatedPromptTokens set calculatedPromptTokens = costs.promptTokens and
recompute totalTokens as a numeric sum of calculatedPromptTokens,
calculatedCompletionTokens, and calculatedReasoningTokens (do not call
.toString()); only call .toString() where totalTokens is formatted for logging
or output (e.g., the log/print site around line ~4879). Ensure references:
totalTokens, costs.promptTokens, calculatedPromptTokens,
calculatedCompletionTokens, calculatedReasoningTokens, and
parseProviderResponse.
🧹 Nitpick comments (1)
apps/gateway/src/chat/chat.ts (1)

3800-3835: Extract the 560 tokens-per-image constant to avoid duplication and future divergence.

The inputImageCount * 560 calculation at line 3808 duplicates the logic defined in apps/gateway/src/lib/costs.ts:286 as TOKENS_PER_INPUT_IMAGE = 560. If the per-image token rate changes in the costs module, this client-facing usage chunk won't be updated, causing the client to see different token counts than what's billed. Extract this as a shared constant (or reference the one from costs.ts) to ensure both code paths always use the same value.

Comment thread apps/gateway/src/chat/chat.ts
steebchen and others added 2 commits February 9, 2026 23:04
The inputImageCount check compared against modelInput which includes
the provider prefix (e.g. "google-ai-studio/gemini-3-pro-image-preview")
so it never matched. Move the check after parseModelInput and compare
against requestedModel instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensures total_tokens in client-facing SSE responses is always
computed from prompt + completion + reasoning tokens rather
than preferring upstream values that exclude image input tokens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _______________________________\n> < I turn WTF moments into TILs. >\n>  -------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>CodeRabbit can generate a title for your PR based on the changes.</summary>\n> \n> Add `@coderabbitai` placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the `reviews.auto_title_placeholder` setting.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nToken accounting was changed to derive promptTokens from calculateCosts (preferring costs.promptTokens) and to include imageInputTokens for certain providers. Logging and final usage/total token calculations in the chat gateway were adjusted across streaming, cached, cancelled, and error paths to reflect the costs-based token values.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation updates** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally includes `imageInputTokens` in returned `promptTokens` for specific providers; tests updated to expect image tokens included in `promptTokens`.|\n|**Chat gateway token accounting** <br> `apps/gateway/src/chat/chat.ts`|Multiple streaming, cached, cancelled, and error paths now derive `promptTokens` (and adjust `totalTokens`) from `costs.promptTokens`/`cancelledCosts.promptTokens` with `imageInputTokens` applied; usage objects and dataStorageCost calculations rebuilt to include image-input-token accounting consistently.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client as Client\n  participant Gateway as ChatGateway\n  participant Costs as calculateCosts\n  participant Provider as LLMProvider\n  participant Storage as DataStorage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: return {promptTokens, imageInputTokens, completionTokens,...}\n  Gateway->>Provider: Stream/Request model with adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage\n  Gateway->>Storage: Log usage (uses costs.promptTokens + imageInputTokens)\n  Gateway-->>Client: Return response and canonicalized usage\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Modifies token accounting in both `chat.ts` and `costs.ts` to propagate image-input tokens through usage reporting.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling in cost calculations; overlaps with how image tokens are added to promptTokens.  \n- theopenco/llmgateway#1202 — Updates chat token accounting to include image-related token counts and propagate them into usage calculations.\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                                                                  |\n| :----------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                  |\n|     Title check    | ✅ Passed | The title 'fix(gateway): include image input tokens in accounting' directly and clearly summarizes the main change: fixing token accounting by including image input tokens in the promptTokens calculation. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                                                                         |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKPR1AGxJcAZvAAeABRE1CQA7miyAJRc8BgMHthKKMxopCgY3HiQBADWZMhx6AxM2BjiGESQkAYAco4ClFwAjABszQAckIAoBJCwuLjciBwA9CNE6rDYAhpMzCO4sCT43GRMIx4ezCE0EbIjWZsjbZ3VBgCqiE32NCQCDEtYNQDK+NgUDCSQAlTxsLGpUhgPJkMBoEpvcpxKqAJMIYM5SLhvr8HlxUkUXrhqNhhvxVk8DABhCgkUL0ahcABMAAZKa0wLSGQBOaDNSkcTocACsHQAWkZno5Ui5+D5GLBMKRhgYoABJQFfOJZJEgjDIZxfDD4MIZBJJOgZHJLSAk3Dvcj0Xgsbi4aD4fJq+z4I3UDLKyAAagUzG4XnE+CwAF4cvgsR4NDLIAADBhoDwMbAeUKE/CIXCIKOQbDcWhkkMmkhmihYKNWn22+0FTOLV1xPXJeAKt3ZVWICNQACCm0guaxAjQV0gHnwRAmlR41Fg6toQhxNHoBCzg8WX2zvYNqsgEjj2Gk7Zg0nTWZzecXJJ8XjERs14RDDuKpShlQjBnl3HBnEjACF4JtoVm/klA1AkbNIvlbG5fw8cUEQNV0V3gPhtSwKgaCifcADEAmkSBmCQVJcAeHCwiWElmyRL05l9Qt4ADHt4HoLUkRIABHbA4xDMM7wKfcrAofAJAYnCmDVJAaHKbisHBR8KiqHx8D4TA41kcQGHVDB6BJbgFNkl9alDaQuFsHtpAYCh4BtWisDiWh4FjGhCiRCJkFIchUINMJJkgQkk31bzFBIF8LH81h1Fw6REDA5AHCcFwjCgABxdiKHJWglHoRBnVA9IlRbStHQ1fgMA8eQ0DSjdnVLfjyztB0M0geS+CtQSlAoZBAkCogNAAGkgBL8BHLwohdZj/HrcClmYBrquPNMSTQKacTAgBudAJHwBjkFoN4BC8MAZP/RqeH4lrKGQGskTjebaHkOtEgbJsIMCAB5fEO1lXr/He9D4rAQwDBMKAyHofAxTQPBCFc5R529Nhyi4Xh+GEURxCkGR5CYVqVDUTRtF0P6AfAKA4FQVBMBwAhiDIaGDTmOHOBNNAdRi4V5DkBQsdUdQtB0fQjEJ0wDDQbghnGUI9hGRAPhGB5qBliVNHTDgDAAIjVgxgveqm3LzFnnHkUGYMqaR4pgfKH0hWTIC1HVWskHCyxtWqCmmlgFDTNtHYrOrIECHw4w8f9+wYXJ8y9521WG8F+MQGRQ1gPEyHQDTGHBJZLUnRBerQHwfBR/9h1Hf92HMnDMHoXs0GeAgqFIFM01T+NE2oKy20jAgwwjwosCuKQqGgwuxyqXb8BD9qViTubSTwypetjIiMtweaZ6IOe04NLUMDAKeFuhNf4hITYDXfRZEGGm2FA09QrIDjHrTwVdEGLyZKHd9MNGykhZUyPAu99kik68GkOwYavocTXmOtaXAMtrR+isiMeamUMD/iogGdgWd+B8H9t2YOodFxAMEm8RAJUchUBDhVTu+UMFxhoOZccfgMAcU3FpHS0J9wAHVHjemVP+Su1cFJgXrrgXqK4Oaam1EuYSqZ37hyob7BS6AGoB1wcNOIaZSQgzFFQHUsifbR1TMgZgiZxDUSHCOSAJd4B7kjN/G4y8UHSMbgmJM/o1S9QYRxJa6RBAiDEOqMiJIBDYF/CqLK8QFLaXcikMC39lR/zKrONM9N1ILmdAUd44FQxxmQOeS8SJP5gFyrgYE5tpKWzYZGDsPhaGSScc3VxGDRGxk3nZDiuiXbbkSIqZAa48w+BmkwD2Gh2mOkCAAqS25fwqCGtnFOsYm4uLoHaShPsyYzjnAadmoilAeCxPmfIJBuCSWQCJJ+6iJKeUWBY/w4l0oWzKLpSMGEFHNM+EfckKdxBsDeNAyg/EmqZ16iMlJnE4x/wvkAvOfBXmHy8LQIRntqpOzkYEBRh5QLzj4lAruw1FzonKNoLApyxJrHkJchOgz0xgH7FcckEIHkVKgAAWTiAokkc1sBiHeP+Q2sAJFeK+JXFA6pY4kGYLtA0RQd4r2ToxAM28l7T3/CfKc+ZiXnNwCQu6fkClFJKfeBJc5kmGg8dBZhhzWHPkqWla+AYOKGqSeg/M6SyK6p/qEg19KnxVFQOq8SmrSoi0DnBMyBjvjx1moqhasrU4LwasOMIbcNaWC7LQluAZzrOm2aIJMqFW6imuZEmGCisi7TshYqE4gTaRn0uQIwAAZOIwkJTG1oFwD0TJWgjDAAAZg6KrdWMpBbC1FjscIkRJbS0DgIGBQzECrAYBoJWA6VbJsgFrKG7kMpCn1gW2WxtEBGFsQ5I8R15nOOTNIxpxoSD+AXTDYF3wSASkIdCltUoGoKM/uRY5ysoB8RIIQnECMkXexdrZOV+T4j3UVE2IpxzfaUjZNSXQehIDNGpJhn6UB9JhBA9iuR2qlCFDg+6hDgQkM0kgIGNDGHMM5FvRRdDyHomkB+iTaciSjwDiuBQBp+ZckoxGqxxUZGIKFRkhVCIKVIE1TkeXBQFB2XaSvuOSlSbfpgFNvpHg0xA4MBGLeotBp2DqHkEoBIzh02OjCJQL4zBFDwD8HQF8jbyAnPfXQdtlJu2UiMAAUTTBi2mAUCyCVvCQXOOkuBMroPARwK7NNGBHYgMWuwJ1SwM9O2d79l1q1XZrWU2sabbtigbMU+6pRuGNKac0W4dxfFOUvTlrjP1NVA3/ZyuEyqNYDLZVxcYNDWBJEB4hsggUdfkx4PYPTaV1MWbQLFcm6pDdw71JzInYm/zkbesSILRHNSEnwAiRETmUCxEUfqg0SBgBJAtyBp02q+yIANIge1tAKqSLRXqL3rtgD7jQfwvUFGCCfrZTAUQJsEZ9o0OYOFAjnvqXQJbyKfYKOpMNL0n8ttgbVKteOlBPKDjCiSfFJy4wXsxZNlbMAEDnVgkeAMJD52iCc+Ww7rVkAANdaR904myJMV1DB+gRRszSqXGBXqXg0CCXHAT9rAkjuIEAJgEsmbS1JYXx/8ZRKsudp18dlSJDaiNq8WBqViPC0ByWKwlAEc55zEC5/ma7U3Q3zYubNlm80ZoLUZnSBoS16fLaZqth6a1oIbU2jzQE22egw925oAWgsERC8kEbVidSRcagzWLtkEv5d+v9QGFbNEU0htTLdsN2BcG0fYHdIp2aY2UFzXGvMCbF7puoAA+ptLv6fwh0C72mZwSI+YCyBgAFmaBPjoJAJ9oEpB0BgPauQkEpBPpk8+mQdAnxPnwTJqQT9aDyfsfaADsJBWg+DPxP/Ghhi/X932f1QlJN+v8pDnCfqgOgX57RPs/DAZ+lIZ+HQaAPaaATIi+zQXIZ+tAPad+xgRMsM3eve/etmtAXewMCBxeQCXebAFApAXeREY8Q+WIfGCBBgAA3gYNUCrEgLYF+MOOQvCiwPTFYNInQCrL4NkiQN1DQZACrIgHyomLQIwaPLkLYFwUoh4FcHwbQUgM9H3OZOVBgFIdgrIfwSrBBjYGUAACKjzVx0JECICEhLAhxSHNa8GaHaFlDuCaokCmGiC5AWEUC7hyECE2EYC6GmTmSWQBiOHmHcEyFWG0GBwYD5C0Cyixy7iICGFSFqzuEqxJhpgBG5A2DSDGKIBSEADa/B1Q1B1QhRAhxBuQtQC0JA8R3hiAZkFkrWqRKs7hRRghWIZoWRXAlhjRhRKsRmSYjCri8RqR9guQFkqw9AUAKYSgNg2M6gyuyACARAsAYAXgUg0EesIoqAZA0yLmDReRXRDmSg8R0myClQOxRRtBCk8AY4cYqRZRbA8RxGNRfhqhuxAAvp0QUWcSrCUbcRUVwCrHYV4OKE4acZ8cPq0S4W4bsbQT0UpP0X8XAOBJ4F8AAOR+BBBjp7AxBC46q855SrJSReqyTIn0QkhiAkIKYJCkgUDM717wAABeOEoi+KRspAvgAQ/4m4ZSDK447MRG/4368GEERQB21OLsiOLiVkGgIJTR+xvxAhRx0I0pXRpJAYfgRAGSahPBnR5x5kVxHgNx5R8R4g9hq6RRbxuxHxTR3xhpfx+hakS8/4KYfcYESptBYJOIEJIRnxMJfRVklRo8c0DizpOUyAdGGgmGAApJACRHZAnKgA4LnHZFYuUENgiQWGxIhBuLAOynypbsKpAB0NSOGdSBGVKdqQIbKYcc4McUQK6QIRcXqQaXcX8dtPaUYVka8fwQALqJHJG4C2BVGPFwkCGtD/5L4MACDUgL5ciqAlBoAdBcgMAz6tACC0ACBMi0CLmtCtCxhlQ+AdDNBLloBn5MgMCUg9pn48hLlsitBMg+BchMgYb9hrkglJEDj9k2AAlykqxoCdAbnT7NDNBMg9rNACA+Cn60DUg+AT60Bn4+A9qtAXkr4zlMgkAdALkkBcjtCkigG0CAVKA76tDgjUhcjUg74MBchoBcivmtmBmVBOnKCkDfy0KMIeDVyhBSGWkCEpZpbjr7CZYbDwAzrqZLptGQBcW0EdxxgYQ64NJSHNDlkqw+CyWtzsKTB2l0XGHyWdnVAvEGB6Xj7HQkB4GUCEElGICYEpx8zF7gwEBd7vg4jGVglOVkGj4ExUFvlphWDgy0odi4DpHhboEpihS4ApgPJcHUgGU2UQz2U+UuWhCWVjF/RAA -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:24:40 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8856:21AE59:F7E543:42C1142:698A0A44","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4973","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"27","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _______________________________\n> < I turn WTF moments into TILs. >\n>  -------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>CodeRabbit can generate a title for your PR based on the changes.</summary>\n> \n> Add `@coderabbitai` placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the `reviews.auto_title_placeholder` setting.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nToken accounting was changed to derive promptTokens from calculateCosts (preferring costs.promptTokens) and to include imageInputTokens for certain providers. Logging and final usage/total token calculations in the chat gateway were adjusted across streaming, cached, cancelled, and error paths to reflect the costs-based token values.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation updates** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally includes `imageInputTokens` in returned `promptTokens` for specific providers; tests updated to expect image tokens included in `promptTokens`.|\n|**Chat gateway token accounting** <br> `apps/gateway/src/chat/chat.ts`|Multiple streaming, cached, cancelled, and error paths now derive `promptTokens` (and adjust `totalTokens`) from `costs.promptTokens`/`cancelledCosts.promptTokens` with `imageInputTokens` applied; usage objects and dataStorageCost calculations rebuilt to include image-input-token accounting consistently.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client as Client\n  participant Gateway as ChatGateway\n  participant Costs as calculateCosts\n  participant Provider as LLMProvider\n  participant Storage as DataStorage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: return {promptTokens, imageInputTokens, completionTokens,...}\n  Gateway->>Provider: Stream/Request model with adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage\n  Gateway->>Storage: Log usage (uses costs.promptTokens + imageInputTokens)\n  Gateway-->>Client: Return response and canonicalized usage\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Modifies token accounting in both `chat.ts` and `costs.ts` to propagate image-input tokens through usage reporting.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling in cost calculations; overlaps with how image tokens are added to promptTokens.  \n- theopenco/llmgateway#1202 — Updates chat token accounting to include image-related token counts and propagate them into usage calculations.\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                                                                  |\n| :----------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                  |\n|     Title check    | ✅ Passed | The title 'fix(gateway): include image input tokens in accounting' directly and clearly summarizes the main change: fixing token accounting by including image input tokens in the promptTokens calculation. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                                                                         |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:24:40 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8856:21AE59:F7E543:42C1142:698A0A44","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4973","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"27","x-xss-protection":"0"},"data":""}}

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _______________________________\n> < I turn WTF moments into TILs. >\n>  -------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>CodeRabbit can generate a title for your PR based on the changes.</summary>\n> \n> Add `@coderabbitai` placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the `reviews.auto_title_placeholder` setting.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nToken accounting was changed to derive promptTokens from calculateCosts (preferring costs.promptTokens) and to include imageInputTokens for certain providers. Logging and final usage/total token calculations in the chat gateway were adjusted across streaming, cached, cancelled, and error paths to reflect the costs-based token values.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation updates** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally includes `imageInputTokens` in returned `promptTokens` for specific providers; tests updated to expect image tokens included in `promptTokens`.|\n|**Chat gateway token accounting** <br> `apps/gateway/src/chat/chat.ts`|Multiple streaming, cached, cancelled, and error paths now derive `promptTokens` (and adjust `totalTokens`) from `costs.promptTokens`/`cancelledCosts.promptTokens` with `imageInputTokens` applied; usage objects and dataStorageCost calculations rebuilt to include image-input-token accounting consistently.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client as Client\n  participant Gateway as ChatGateway\n  participant Costs as calculateCosts\n  participant Provider as LLMProvider\n  participant Storage as DataStorage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: return {promptTokens, imageInputTokens, completionTokens,...}\n  Gateway->>Provider: Stream/Request model with adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage\n  Gateway->>Storage: Log usage (uses costs.promptTokens + imageInputTokens)\n  Gateway-->>Client: Return response and canonicalized usage\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Modifies token accounting in both `chat.ts` and `costs.ts` to propagate image-input tokens through usage reporting.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling in cost calculations; overlaps with how image tokens are added to promptTokens.  \n- theopenco/llmgateway#1202 — Updates chat token accounting to include image-related token counts and propagate them into usage calculations.\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                                                                  |\n| :----------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                  |\n|     Title check    | ✅ Passed | The title 'fix(gateway): include image input tokens in accounting' directly and clearly summarizes the main change: fixing token accounting by including image input tokens in the promptTokens calculation. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                                                                         |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:24:40 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8856:21AE59:F7E543:42C1142:698A0A44","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4973","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"27","x-xss-protection":"0"},"data":""}}

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _______________________________\n> < I turn WTF moments into TILs. >\n>  -------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>CodeRabbit can generate a title for your PR based on the changes.</summary>\n> \n> Add `@coderabbitai` placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the `reviews.auto_title_placeholder` setting.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nToken accounting was changed to derive promptTokens from calculateCosts (preferring costs.promptTokens) and to include imageInputTokens for certain providers. Logging and final usage/total token calculations in the chat gateway were adjusted across streaming, cached, cancelled, and error paths to reflect the costs-based token values.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation updates** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally includes `imageInputTokens` in returned `promptTokens` for specific providers; tests updated to expect image tokens included in `promptTokens`.|\n|**Chat gateway token accounting** <br> `apps/gateway/src/chat/chat.ts`|Multiple streaming, cached, cancelled, and error paths now derive `promptTokens` (and adjust `totalTokens`) from `costs.promptTokens`/`cancelledCosts.promptTokens` with `imageInputTokens` applied; usage objects and dataStorageCost calculations rebuilt to include image-input-token accounting consistently.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client as Client\n  participant Gateway as ChatGateway\n  participant Costs as calculateCosts\n  participant Provider as LLMProvider\n  participant Storage as DataStorage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: return {promptTokens, imageInputTokens, completionTokens,...}\n  Gateway->>Provider: Stream/Request model with adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage\n  Gateway->>Storage: Log usage (uses costs.promptTokens + imageInputTokens)\n  Gateway-->>Client: Return response and canonicalized usage\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Modifies token accounting in both `chat.ts` and `costs.ts` to propagate image-input tokens through usage reporting.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling in cost calculations; overlaps with how image tokens are added to promptTokens.  \n- theopenco/llmgateway#1202 — Updates chat token accounting to include image-related token counts and propagate them into usage calculations.\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                                                                  |\n| :----------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                  |\n|     Title check    | ✅ Passed | The title 'fix(gateway): include image input tokens in accounting' directly and clearly summarizes the main change: fixing token accounting by including image input tokens in the promptTokens calculation. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                                                                         |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:24:40 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8856:21AE59:F7E543:42C1142:698A0A44","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4973","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"27","x-xss-protection":"0"},"data":""}}

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nChat gateway token accounting now prefers costs.promptTokens (when provided) and includes image input tokens for specific providers; logging, usage objects, and total token calculations were updated across streaming, cached, cancelled, and error paths to reflect costs-based accounting.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation logic & tests** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally adds `imageInputTokens` into returned `promptTokens` for certain Google-related providers; tests adjusted to expect image tokens included in `promptTokens`.|\n|**Gateway chat token & usage accounting** <br> `apps/gateway/src/chat/chat.ts`|Reworked token accounting to prefer `costs.promptTokens` (and `cancelledCosts.promptTokens`), compute `imageInputCount`/`imageInputTokens` from `requestedModel`, update `dataStorageCost` and final usage objects for streaming/non-streaming and cached/cancelled/error paths.|\n|**Streaming usage chunk construction** <br> `apps/gateway/src/chat/chat.ts` (streaming-specific sections)|Adjusted streaming chunk creation to compute adjusted prompt/completion tokens with image input adjustments and return structured usage chunks using costs-based values.|\n|**Provider-specific handling** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/chat/chat.ts`|Added provider-specific rules (Google / Moonshot paths) to align prompt token reporting with upstream behavior and ensure canonicalization of `costs.promptTokens` where available.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client\n  participant Gateway\n  participant Costs\n  participant Provider\n  participant Storage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: {promptTokens, imageInputTokens, completionTokens, ...}\n  Gateway->>Provider: Request/stream model using adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage info\n  Gateway->>Storage: Persist usage (uses costs.promptTokens + image adjustments)\n  Gateway-->>Client: Return response + canonicalized usage (total_tokens from costs)\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Implements adding/counting input images for cost/token accounting in `chat.ts` and `costs.ts`.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling used by cost calculations; overlaps with promptTokens adjustments.  \n- theopenco/llmgateway#1556 — Modifies `calculateCosts` return and prompt token computation, directly related to provider-specific prompt token behavior.\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                    |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                    |\n|     Title check    | ✅ Passed | The pull request title directly and clearly summarizes the main change: fixing gateway token accounting to include image input tokens in the accounting logic. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                           |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>apps/gateway/src/chat/chat.ts (1)</summary><blockquote>\n\n`375-379`: **Hardcoded model check is fragile but acceptable for now.**\n\nThe image counting gate is tied to a single model string. If additional models need image-input-token accounting in the future, this will need to become a list or a model-property check. Fine for this PR scope.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKPR1AGxJcAZvAAeABRE1CQA7miyAJRc8BgMHthKKMxopCgY3HiQBADWZMhx6AxM2BjiGESQkAYAco4ClFwAjABszQAckIAoBJCwuLjciBwA9CNE6rDYAhpMzCO4sCT43GRMIx4ezCE0EbIjWZsjbZ3VBgCqiE32NCQCDEtYNQDK+NgUDCSQAlTxsLGpUhgPJkMBoEpvcpxKqAJMIYM5SLhvr8HlxUkUXrhqNhhvxVk8DABhCgkUL0ahcABMAAZKa0wLSGQBOaDNSkcTocACsHQAWkZno5Ui5+D5GLBMKRhgYoABJQFfOJZJEgjDIZyK+KJJT0IqLL4k3Dvcj0AAGvBY3Fw0Hw+TVpvs+ByEqRpqV2QA1ApmNwvOJ8FgALw5fBYjymjQyyCmhhoDwMbAeUKE/CIXCIB0YfBhSCG43Ic0US3W20FB2LagZBJJRUKjLKkN2xCRqAAEWoKjQV0gHnwRAmlR41FgyDClC+2G4tDJIcgOK++tzJAkSDojbIkAkcew0hbMGk6cgY5Jc6nM4IkFSuAezq+5BzquKpShlT3tkgWZoyArSLUm2hKDIGUDySmugTwHWqrICS6JYCBFCkOSKpLPAfDZlgVA0FE6AYPQP63uKoGQH4/jSJeSBXg8ZFhEsJ7ukiXpzL6JD+lgtDwPQn6QCQACO2BxiGYbrmqkYGAAgrQ7GsQJn7eNYdhKIgDAUPAVrwAGGTsbGX4oEiETIKQ5CYWuYSTJAhJJjW5mKCQokWNZrDqJe0iIGkZEOE4LhGFAABiASXjZHhgBgaBsH0mC0B4AE+PgfAQW5ChlEiVEMLkaL4FIBH0fKbkpkl4qiLk6A+DQfDcM4iAAYuzCBfW2QRd65Unmk2hqshXxNVctAjCSfEHmuNVKB4jo8EWK5KBQYC8CQJEDbVaYqZUyCBLZRAaAANJAABERD4H2XhgvAYBpkk6kjBoF1bdhlGwAoFAkmIHiyHuACiarvF8C2kswAHPM8L1Log3ABlcyBMXgXymgQYYAPpQQ6PhFswo3FpAjGWn66lYF6JJdgGVWlmqkDgVqp2DvF6T0cJiDYZhtHOpgc6VYOk5faFm7bmR+GlB49AkP41bJBTmoNlBon6MY4BQGQ9D4GKaB4IQhnKDQ9BzGw5RcLw/DCKI4hSDI8hMBNKhqJo2i6GAhgmFAcCoKgjMKwQxBkCra7q+wXBUDmHnCvIcgKCbqjqFoOgS5LpgGGg3BDOMoR7CMiAfCMIG4CnLoaOmHAGFtucGPZYmyi7Rkzr7zjyHLhGVNI3mQDYJA1VI5JYKSFBPYlL5VAIvapcRsV1UiwvLTFfCDSQw30dhDUknEuBFrQ2CfLqmTZMLHcVF3XZrhpi73u3E2SGuvU7mmdAALK1YEO0N3ER0AMxTUWYDC4/y7wOEV0ZARRZ4NCIxblFacrFiK9jCHuWU5R56LzXNlBUeVyiMDjAmJMrFChYGYImcQzEeD4FnogTaOIALH36rQC+Q1ZxKFKj9cgR4lj6j4BeZ8g8V6DwVMgRGLBnKIFclKPufAmBpkQfGRM1AsZ7nOGeVWwknyQg3hQygh8UY+hLE2HCeFQxxhtKojhyMBHpg0BaZRWiCjExohuNAW54BJm7iQKeylUwyFDLdFY5jcKIKovQcqix8FHjMj4OMHgBDglyN+J000VxvEQO3OewS1xQQANzFR8HrZAVwpBUGGr2fsAFp7SGBmqL4TA2oUEXsArxI49wSSEDiKRQC0DPAIFQUgKZBHgyxKg2c84FBpmbIYq0xiiaBH7vqVCxEAlBNSrTYclAGYYTQDmPpKiTFFDScoTJfZuKQPfs2KM9cwixXyPQPwIVho4gSoIEQYh2H9zZtQqoDUswYGOnPb6AFymhKrLFYGxkUhuQgcqAZ6o3HC3+XgeBSI0C0GqWmDW6ZNoNQvAUD6gk4zQRml4MQ3T0xgCCV1GRSVoSbTiILAC94UUeDhoTMGSCRGoMqZJNcWT4AMFnLGR5zK4zwAAF6FNTPoxZgL0DfiWI6d4nxRQ5BKYsPhSj+lUrUTKycQCAKxmESgugNowyCrMXBPlvSkZytUagBARB6YViwOE9SOJ26quQTORZOyoAvX8DQXC7tMCfE2KIjSCKILLGyBKXCUVBzvNnA4AQaZ1AQ0QfEceXhaAtP5QapZgz+4HniqrKwybAXYRHrKlNQL1FavlUULJmy57bIVXUm4sU3KbSRYtKoRTKqn3iPIUy0q9GIBxVvckEICWvl2TNOIa5bkATOekB4ZQirKVJMAxhlpo2QqEFm1GDVl0ph9JjDSHbbprypsumpsKfF5goBgHJNwSliA+vQCdXwLl60gOxB6uB255sXMcgSd7xTTvAZAxQ0DPFjQ4pQY6qwGDwD8Cyw9ML2AfO/QiwmS5vlyJWhoNam0ADie0iBeAVRfEGsBQybJUg8WFQ5vHYQvJyogWBd0ETJV2nteLwRMJyTHIs4JYD0p1DgtMYAf5yKzBQVIUUuXeqwKfbgs4aNwRpeq9Rqj6NdoMdm+VZiTxdpRuNL4aAY341VRzRIJB4VQpqQTYtqjWOxXYpUJ6e4z5xH7iSBapT3gE02Q4OidYqaPmswOqoqBm1IFda++Q0dfTvz7UWbhp5bkKtjB4kB2YfHEu1ABIoAgnGXteYOB5AZnm4zuRRip5hLBiQ8KVCTHzFxKASM4arEr+Yoe3mVaYUUWXsHUNs2utQAwkCMGfNAQhYowyVaERARgAAyI6waBsQlwD0zRqStBGGALklIc55xlJHCLiA467EiInZOUUBApz1RoIGohM7SlzltfO5Wi7K2MvQMuIpK4gWrpNgwECcgHmufw+TyY9WbUXM1vWa4BXysaBKCJ/D5tkTzfulh1Ns5QCzW/SJWs1OqPYpxYjaWrLI9FvKwIlI2TUl0HoSAy3qTUiiHuPrYRsfFkFYTxSvzKYo6gsTcnNJICBmp7TynNAXVoxpxTzntjIx23VGZnpQqrgUA6ReEkPgMXIUrMT7IPONTrzidmZwQHWfyoakwe6eSAy2abRdow3lI5QD6zwdrzKRjNdilIrruB5B1aTJhLGo5xwBXYn4OgokZvkDm6BWgi3KRrc2wYF6karzuxskuFc4RuI+BHpwSAZ86DwEcFt+7O2wBGD2wd8IR2k4MA2PAM7Kms7F4e5AQuxc3avaFOXCVn2pRuBFaerAACdwKGKaUrGMqodKa7JeSFvLcLdYDHGDQ1gSQROtbITaU+TFxj2EBPFtraV0FXUYqlK+mdErFCClhgr+YhcLQRC0OnR7UComDSgWIijYf2iQAT497XAYTTLS7Q/6HTPKnT4CbQgG4a/7pKi6bT9yCCVTsSYBRBb444mKNBzBkSBCH4KYn6GomL9z07i7X4ApUqJJOKUCmTdhOQwStTUpqpkgEEFor6y45AIgsTIABjtxXYQZQbaYgYUCji0S1gJS+am4nhcTs4wJYCswvLsx3qbReAWIARUFlSAGUCICACYBPmtIiSChuOn8NHmwQPgeBKouIPsRO/LzGirBHOCFNnhDrQKJGVq3pVirAHrOLVqIH7o1pXO7srq1s7t3MyuWt1jXFGH1uQNNrNlXAtmjMtmts0EYEnuICnmrGnmvu/DmDNDnlwPnuxEXndvboYAYDbJsrLPLIrO3i9t6LCl7PMvYF3iKAHMbMoMHObGHFbOUVLPUeoDDBxIgDDNkeEHQDDGmM4EiOHBUSQAACzNBzEdDzFoCUgdAMB3xcgkCUhzFMhzFoBMgdBzFzE+BMjUhzGtA8hBJ3wdAADsJArQPgtxcxls1sfRTxxxtxqglIexPxlIaAPgcxqgdxJAd8cxtxDAtxlItxHQaAd8BxaxzQXItxtAd8rxvREAkAuxDAuxHQzQd8dO1IJAbQ9wtAXITIXIzQTI8JOJDAZJ1ItAcx1ITIoJd8LJemMxfR6sAxQxIxb8YxtAMMMs6JFR00MMbACEJAMMKUISExWIyu6JBgAA3gYNUFtEgLYAAEI9yHKbqwpWB8p0BbS+CoomaqnbSIBEaJi0Dan4CpS2DGljIeBXDrTmnqmIAADy6SKkDKGAjp/izpZpapeONgZQrYdpDSjaiAhISwqUjpc8O4rpwZHEoZGA7gr6JAMZhU8ZJSQZ20IZYZ0gykqkrEWZcZJpgZSZ20wahyso3CJ8kZjpucVZW0SYaYZZuQ9cDglWiAjpAA2uadUCqdUCOdtDKbUKFCQE2a2EWSpGpBpB2VtFWaOVtJMUaL2VwAmXmSuc1kmCFKxE2R2fYLkKpKsPQFACmEoDYKbOoNocgCarAGAF4FIMNG9vIKgGQCoPGhoEuYOSOVtGPE2REGetCL+aOWqbFPAAOHGB2ROWwE2YpMWfOX6X+QAL7LmQDDngVbTjmTlNnpl4YylgXYVrk4g5mJl/lqm7mYASb4UiqHDDTEKCLiAZlPqoR6ztxm4qFtzyBvbcpcwir2G95yQkQAQ7BV7yB+b9qdyzgyFS4DzUxfyLj+YyVMoMA/kYVqmAVcBbTAXnqVDEUrkPQBh+BEAfT+mmmaXbSQXQUeCwV4U6UsVeD3ajnoV/lYUrm4XwU6XhkMALQAQpjpJuSGX/mkUbmSoUXgXbTUX7lYzTl2n+WDhMBBWUzIC04aB04ACktCzKe6qS2A2ezK785QphBovE2A7FeEsALmRGvMgEkAHQ1IGV1ImVGllF202l20eloFVlW0NlcQMFsZuQcFU5OltACVFaS0LlI5qF5pAAui2W2bgLYDOUpHOQeTpa0OCesQwAINSKsVyKoCUGgB0FyDiR0K0AILQAIEyGSQwK0K0LGJCj4HiTiWgLcUyAwJSHfLcTyDiWyK0EyD4OSctkEtdcRa2V2MtTYARaNdtGgJ0LdYsc0FSXfM0AID4NcbQNSICbQLcT4HfK0D9ZsYdSyR0KdSQFyO0KSLCbQCjUoEca0OCNSFyNSEcQwFyGgFyBDeNX5ZNUQIFcoKQBAqVCcg0qEI6R5fDTHPtuJQnDXnXg3hdumJLe1VtNDHGD5MBKgo6c0L1T4NrQHgAOqTC+WJVEDhUpGuXmmzWzUYlQBikSmkDSlDXDHCkSwVFOz4AwzlTzhymhD+0KnhxKmQ1phWAKxdRiS4D1wZ5jgJosA/S4DgrGnUh22e2Kw+0R1SlrlSnu1WxAA -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:54 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"804A:257C3F:11C1AC6:4C7760E:698A0BBD","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4941","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"59","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nChat gateway token accounting now prefers costs.promptTokens (when provided) and includes image input tokens for specific providers; logging, usage objects, and total token calculations were updated across streaming, cached, cancelled, and error paths to reflect costs-based accounting.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation logic & tests** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally adds `imageInputTokens` into returned `promptTokens` for certain Google-related providers; tests adjusted to expect image tokens included in `promptTokens`.|\n|**Gateway chat token & usage accounting** <br> `apps/gateway/src/chat/chat.ts`|Reworked token accounting to prefer `costs.promptTokens` (and `cancelledCosts.promptTokens`), compute `imageInputCount`/`imageInputTokens` from `requestedModel`, update `dataStorageCost` and final usage objects for streaming/non-streaming and cached/cancelled/error paths.|\n|**Streaming usage chunk construction** <br> `apps/gateway/src/chat/chat.ts` (streaming-specific sections)|Adjusted streaming chunk creation to compute adjusted prompt/completion tokens with image input adjustments and return structured usage chunks using costs-based values.|\n|**Provider-specific handling** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/chat/chat.ts`|Added provider-specific rules (Google / Moonshot paths) to align prompt token reporting with upstream behavior and ensure canonicalization of `costs.promptTokens` where available.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client\n  participant Gateway\n  participant Costs\n  participant Provider\n  participant Storage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: {promptTokens, imageInputTokens, completionTokens, ...}\n  Gateway->>Provider: Request/stream model using adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage info\n  Gateway->>Storage: Persist usage (uses costs.promptTokens + image adjustments)\n  Gateway-->>Client: Return response + canonicalized usage (total_tokens from costs)\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Implements adding/counting input images for cost/token accounting in `chat.ts` and `costs.ts`.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling used by cost calculations; overlaps with promptTokens adjustments.  \n- theopenco/llmgateway#1556 — Modifies `calculateCosts` return and prompt token computation, directly related to provider-specific prompt token behavior.\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                    |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                    |\n|     Title check    | ✅ Passed | The pull request title directly and clearly summarizes the main change: fixing gateway token accounting to include image input tokens in the accounting logic. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                           |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>apps/gateway/src/chat/chat.ts (1)</summary><blockquote>\n\n`375-379`: **Hardcoded model check is fragile but acceptable for now.**\n\nThe image counting gate is tied to a single model string. If additional models need image-input-token accounting in the future, this will need to become a list or a model-property check. Fine for this PR scope.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:54 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"804A:257C3F:11C1AC6:4C7760E:698A0BBD","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4941","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"59","x-xss-protection":"0"},"data":""}}

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nChat gateway token accounting now prefers costs.promptTokens (when provided) and includes image input tokens for specific providers; logging, usage objects, and total token calculations were updated across streaming, cached, cancelled, and error paths to reflect costs-based accounting.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation logic & tests** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally adds `imageInputTokens` into returned `promptTokens` for certain Google-related providers; tests adjusted to expect image tokens included in `promptTokens`.|\n|**Gateway chat token & usage accounting** <br> `apps/gateway/src/chat/chat.ts`|Reworked token accounting to prefer `costs.promptTokens` (and `cancelledCosts.promptTokens`), compute `imageInputCount`/`imageInputTokens` from `requestedModel`, update `dataStorageCost` and final usage objects for streaming/non-streaming and cached/cancelled/error paths.|\n|**Streaming usage chunk construction** <br> `apps/gateway/src/chat/chat.ts` (streaming-specific sections)|Adjusted streaming chunk creation to compute adjusted prompt/completion tokens with image input adjustments and return structured usage chunks using costs-based values.|\n|**Provider-specific handling** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/chat/chat.ts`|Added provider-specific rules (Google / Moonshot paths) to align prompt token reporting with upstream behavior and ensure canonicalization of `costs.promptTokens` where available.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client\n  participant Gateway\n  participant Costs\n  participant Provider\n  participant Storage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: {promptTokens, imageInputTokens, completionTokens, ...}\n  Gateway->>Provider: Request/stream model using adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage info\n  Gateway->>Storage: Persist usage (uses costs.promptTokens + image adjustments)\n  Gateway-->>Client: Return response + canonicalized usage (total_tokens from costs)\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Implements adding/counting input images for cost/token accounting in `chat.ts` and `costs.ts`.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling used by cost calculations; overlaps with promptTokens adjustments.  \n- theopenco/llmgateway#1556 — Modifies `calculateCosts` return and prompt token computation, directly related to provider-specific prompt token behavior.\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                    |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                    |\n|     Title check    | ✅ Passed | The pull request title directly and clearly summarizes the main change: fixing gateway token accounting to include image input tokens in the accounting logic. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                           |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>apps/gateway/src/chat/chat.ts (1)</summary><blockquote>\n\n`375-379`: **Hardcoded model check is fragile but acceptable for now.**\n\nThe image counting gate is tied to a single model string. If additional models need image-input-token accounting in the future, this will need to become a list or a model-property check. Fine for this PR scope.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKPR1AGxJcAZvAAeABRE1CQA7miyAJRc8BgMHthKKMxopCgY3HiQBADWZMhx6AxM2BjiGESQkAYAco4ClFwAjABszQAckIAoBJCwuLjciBwA9CNE6rDYAhpMzCO4sCT43GRMIx4ezCE0EbIjWZsjbZ3VBgCqiE32NCQCDEtYNQDK+NgUDCSQAlTxsLGpUhgPJkMBoEpvcpxKqAJMIYM5SLhvr8HlxUkUXrhqNhhvxVk8DABhCgkUL0ahcABMAAZKa0wLSGQBOaDNSkcTocACsHQAWkZno5Ui5+D5GLBMKRhgYoABJQFfOJZJEgjDIZyK+KJJT0IqLL4k3Dvcj0AAGvBY3Fw0Hw+TVpvs+ByEqRpqV2QA1ApmNwvOJ8FgALw5fBYjymjQyyCmhhoDwMbAeUKE/CIXCIB0YfBhSCG43Ic0US3W20FB2LagZBJJRUKjLKkN2xCRqAAEWoKjQV0gHnwRAmlR41FgyDClC+2G4tDJIcgOK++tzJAkSDojbIkAkcew0hbMGk6cgY5Jc6nM4IkFSuAezq+5BzquKpShlT3tkgWZoyArSLUm2hKDIGUDySmugTwHWqrICS6JYCBFCkOSKpLPAfDZlgVA0FE6AYPQP63uKoGQH4/jSJeSBXg8ZFhEsJ7ukiXpzL6JD+lgtDwPQn6QCQACO2BxiGYbrmqkYGAAgrQ7GsQJn7eNYdhKIgDAUPAVrwAGGTsbGX4oEiETIKQ5CYWuYSTJAhJJjW5mKCQokWNZrDqJe0iIGkZEOE4LhGFAABiASXjZHhgBgaBsH0mC0B4AE+PgfAQW5ChlEiVEMLkaL4FIBH0fKbkpkl4qiLk6A+DQfDcM4iAAYuzCBfW2QRd65Unmk2hqshXxNVctAjCSfEHmuNVKB4jo8EWK5KBQYC8CQJEDbVaYqZUyCBLZRAaAANJAABERD4H2XhgvAYBpkk6kjBoF1bdhlGwAoFAkmIHiyHuACiarvF8C2kswAHPM8L1Log3ABlcyBMXgXymgQYYAPpQQ6PhFswo3FpAjGWn66lYF6JJdgGVWlmqkDgVqp2DvF6T0cJiDYZhtHOpgc6VYOk5faFm7bmR+GlB49AkP41bJBTmoNlBon6MY4BQGQ9D4GKaB4IQhnKDQ9BzGw5RcLw/DCKI4hSDI8hMBNKhqJo2i6GAhgmFAcCoKgjMKwQxBkCra7q+wXBUDmHnCvIcgKCbqjqFoOgS5LpgGGg3BDOMoR7CMiAfCMIG4CnLoaOmHAGFtucGPZYmyi7Rkzr7zjyHLhGVNI3mQDYJA1VI5JYKSFBPYlL5VAIvapcRsV1UiwvLTFfCDSQw30dhDUknEuBFrQ2CfLqmTZMLHcVF3XZrhpi73u3E2SGuvU7mmdAALK1YEO0N3ER0AMxTUWYDC4/y7wOEV0ZARRZ4NCIxblFacrFiK9jCHuWU5R56LzXNlBUeVyiMDjAmJMrFChYGYImcQzEeD4FnogTaOIALH36rQC+Q1ZxKFKj9cgR4lj6j4BeZ8g8V6DwVMgRGLBnKIFclKPufAmBpkQfGRM1AsZ7nOGeVWwknyQg3hQygh8UY+hLE2HCeFQxxhtKojhyMBHpg0BaZRWiCjExohuNAW54BJm7iQKeylUwyFDLdFY5jcKIKovQcqix8FHjMj4OMHgBDglyN+J000VxvEQO3OewS1xQQANzFR8HrZAVwpBUGGr2fsAFp7SGBmqL4TA2oUEXsArxI49wSSEDiKRQC0DPAIFQUgKZBHgyxKg2c84FBpmbIYq0xiiaBH7vqVCxEAlBNSrTYclAGYYTQDmPpKiTFFDScoTJfZuKQPfs2KM9cwixXyPQPwIVho4gSoIEQYh2H9zZtQqoDUswYGOnPb6AFymhKrLFYGxkUhuQgcqAZ6o3HC3+XgeBSI0C0GqWmDW6ZNoNQvAUD6gk4zQRml4MQ3T0xgCCV1GRSVoSbTiILAC94UUeDhoTMGSCRGoMqZJNcWT4AMFnLGR5zK4zwAAF6FNTPoxZgL0DfiWI6d4nxRQ5BKYsPhSj+lUrUTKycQCAKxmESgugNowyCrMXBPlvSkZytUagBARB6YViwOE9SOJ26quQTORZOyoAvX8DQXC7tMCfE2KIjSCKILLGyBKXCUVBzvNnA4AQaZ1AQ0QfEceXhaAtP5QapZgz+4HniqrKwybAXYRHrKlNQL1FavlUULJmy57bIVXUm4sU3KbSRYtKoRTKqn3iPIUy0q9GIBxVvckEICWvl2TNOIa5bkATOekB4ZQirKVJMAxhlpo2QqEFm1GDVl0ph9JjDSHbbprypsumpsKfF5goBgHJNwSliA+vQCdXwLl60gOxB6uB255sXMcgSd7xTTvAZAxQ0DPFjQ4pQY6qwGDwD8Cyw9ML2AfO/QiwmS5vlyJWhoNam0ADie0iBeAVRfEGsBQybJUg8WFQ5vHYQvJyogWBd0ETJV2nteLwRMJyTHIs4JYD0p1DgtMYAf5yKzBQVIUUuXeqwKfbgs4aNwRpeq9Rqj6NdoMdm+VZiTxdpRuNL4aAY341VRzRIJB4VQpqQTYtqjWOxXYpUJ6e4z5xH7iSBapT3gE02Q4OidYqaPmswOqoqBm1IFda++Q0dfTvz7UWbhp5bkKtjB4kB2YfHEu1ABIoAgnGXteYOB5AZnm4zuRRip5hLBiQ8KVCTHzFxKASM4arEr+Yoe3mVaYUUWXsHUNs2utQAwkCMGfNAQhYowyVaERARgAAyI6waBsQlwD0zRqStBGGALklIc55xlJHCLiA467EiInZOUUBApz1RoIGohM7SlzltfO5Wi7K2MvQMuIpK4gWrpNgwECcgHmufw+TyY9WbUXM1vWa4BXysaBKCJ/D5tkTzfulh1Ns5QCzW/SJWs1OqPYpxYjaWrLI9FvKwIlI2TUl0HoSAy3qTUiiHuPrYRsfFkFYTxSvzKYo6gsTcnNJICBmp7TynNAXVoxpxTzntjIx23VGZnpQqrgUA6ReEkPgMXIUrMT7IPONTrzidmZwQHWfyoakwe6eSAy2abRdow3lI5QD6zwdrzKRjNdilIrruB5B1aTJhLGo5xwBXYn4OgokZvkDm6BWgi3KRrc2wYF6karzuxskuFc4RuI+BHpwSAZ86DwEcFt+7O2wBGD2wd8IR2k4MA2PAM7Kms7F4e5AQuxc3avaFOXCVn2pRuBFaerAACdwKGKaUrGMqodKa7JeSFvLcLdYDHGDQ1gSQROtbITaU+TFxj2EBPFtraV0FXUYqlK+mdErFCClhgr+YhcLQRC0OnR7UComDSgWIijYf2iQAT497XAYTTLS7Q/6HTPKnT4CbQgG4a/7pKi6bT9yCCVTsSYBRBb444mKNBzBkSBCH4KYn6GomL9z07i7X4ApUqJJOKUCmTdhOQwStTUpqpkgEEFor6y45AIgsTIABjtxXYQZQbaYgYUCji0S1gJS+am4nhcTs4wJYCswvLsx3qbReAWIARUFlSAGUCICACYBPmtIiSChuOn8NHmwQPgeBKouIPsRO/LzGirBHOCFNnhDrQKJGVq3pVirAHrOLVqIH7o1pXO7srq1s7t3MyuWt1jXFGH1uQNNrNlXAtmjMtmts0EYEnuICnmrGnmvu/DmDNDnlwPnuxEXndvboYAYDbJsrLPLIrO3i9t6LCl7PMvYF3iKAHMbMoMHObGHFbOUVLPUeoDDBxIgDDNkeEHQDDGmM4EiOHBUSQAACzNBzEdDzFoCUgdAMB3xcgkCUhzFMhzFoBMgdBzFzE+BMjUhzGtA8hBJ3wdAADsJArQPgtxcxls1sfRTxxxtxqglIexPxlIaAPgcxqgdxJAd8cxtxDAtxlItxHQaAd8BxaxzQXItxtAd8rxvREAkAuxDAuxHQzQd8dO1IJAbQ9wtAXITIXIzQTI8JOJDAZJ1ItAcx1ITIoJd8LJemMxfR6sAxQxIxb8YxtAMMMs6JFR00MMbACEJAMMKUISExWIyu6JBgAA3gYNUFtEgLYAAEI9yHKbqwpWB8p0BbS+CoomaqnbSIBEaJi0Dan4CpS2DGljIeBXDrTmnqmIAADy6SKkDKGAjp/izpZpapeONgZQrYdpDSjaiAhISwqUjpc8O4rpwZHEoZGA7gr6JAMZhU8ZJSQZ20IZYZ0gykqkrEWZcZJpgZSZ20wahyso3CJ8kZjpucVZW0SYaYZZuQ9cDglWiAjpAA2uadUCqdUCOdtDKbUKFCQE2a2EWSpGpBpB2VtFWaOVtJMUaL2VwAmXmSuc1kmCFKxE2R2fYLkKpKsPQFACmEoDYKbOoNocgCarAGAF4FIMNG9vIKgGQCoPGhoEuYOSOVtGPE2REGetCL+aOWqbFPAAOHGB2ROWwE2YpMWfOX6X+QAL7LmQDDngVbTjmTlNnpl4YylgXYVrk4g5mJl/lqm7mYASb4UiqHDDTEKCLiAZlPqoR6ztxm4qFtzyBvbcpcwir2G95yQkQAQ7BV7yB+b9qdyzgyFS4DzUxfyLj+YyVMoMA/kYVqmAVcBbTAXnqVDEUrkPQBh+BEAfT+mmmaXbSQXQUeCwV4U6UsVeD3ajnoV/lYUrm4XwU6XhkMALQAQpjpJuSGX/mkUbmSoUXgXbTUX7lYzTl2n+WDhMBBWUzIC04aB04ACktCzKe6qS2A2ezK785QphBovE2A7FeEsALmRGvMgEkAHQ1IGV1ImVGllF202l20eloFVlW0NlcQMFsZuQcFU5OltACVFaS0LlI5qF5pAAui2W2bgLYDOUpHOQeTpa0OCesQwAINSKsVyKoCUGgB0FyDiR0K0AILQAIEyGSQwK0K0LGJCj4HiTiWgLcUyAwJSHfLcTyDiWyK0EyD4OSctkEtdcRa2V2MtTYARaNdtGgJ0LdYsc0FSXfM0AID4NcbQNSICbQLcT4HfK0D9ZsYdSyR0KdSQFyO0KSLCbQCjUoEca0OCNSFyNSEcQwFyGgFyBDeNX5ZNUQIFcoKQBAqVCcg0qEI6R5fDTHPtuJQnDXnXg3hdumJLe1VtNDHGD5MBKgo6c0L1T4NrQHgAOqTC+WJVEDhUpGuXmmzWzUYlQBikSmkDSlDXDHCkSwVFOz4AwzlTzhymhD+0KnhxKmQ1phWAKxdRiS4D1wZ5jgJosA/S4DgrGnUh22e2Kw+0R1SlrlSnu1WxAA -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:54 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"804A:257C3F:11C1AC6:4C7760E:698A0BBD","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4941","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"59","x-xss-protection":"0"},"data":""}}

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nChat gateway token accounting now prefers costs.promptTokens (when provided) and includes image input tokens for specific providers; logging, usage objects, and total token calculations were updated across streaming, cached, cancelled, and error paths to reflect costs-based accounting.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Cost calculation logic & tests** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/lib/costs.spec.ts`|`calculateCosts` now conditionally adds `imageInputTokens` into returned `promptTokens` for certain Google-related providers; tests adjusted to expect image tokens included in `promptTokens`.|\n|**Gateway chat token & usage accounting** <br> `apps/gateway/src/chat/chat.ts`|Reworked token accounting to prefer `costs.promptTokens` (and `cancelledCosts.promptTokens`), compute `imageInputCount`/`imageInputTokens` from `requestedModel`, update `dataStorageCost` and final usage objects for streaming/non-streaming and cached/cancelled/error paths.|\n|**Streaming usage chunk construction** <br> `apps/gateway/src/chat/chat.ts` (streaming-specific sections)|Adjusted streaming chunk creation to compute adjusted prompt/completion tokens with image input adjustments and return structured usage chunks using costs-based values.|\n|**Provider-specific handling** <br> `apps/gateway/src/lib/costs.ts`, `apps/gateway/src/chat/chat.ts`|Added provider-specific rules (Google / Moonshot paths) to align prompt token reporting with upstream behavior and ensure canonicalization of `costs.promptTokens` where available.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Client\n  participant Gateway\n  participant Costs\n  participant Provider\n  participant Storage\n\n  Client->>Gateway: Send chat request (may include images)\n  Gateway->>Costs: calculateCosts(request, provider)\n  Costs-->>Gateway: {promptTokens, imageInputTokens, completionTokens, ...}\n  Gateway->>Provider: Request/stream model using adjusted accounting\n  Provider-->>Gateway: Streamed response / final usage info\n  Gateway->>Storage: Persist usage (uses costs.promptTokens + image adjustments)\n  Gateway-->>Client: Return response + canonicalized usage (total_tokens from costs)\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- theopenco/llmgateway#1271 — Implements adding/counting input images for cost/token accounting in `chat.ts` and `costs.ts`.  \n- theopenco/llmgateway#1210 — Changes image-token accounting and image-size handling used by cost calculations; overlaps with promptTokens adjustments.  \n- theopenco/llmgateway#1556 — Modifies `calculateCosts` return and prompt token computation, directly related to provider-specific prompt token behavior.\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                                    |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                    |\n|     Title check    | ✅ Passed | The pull request title directly and clearly summarizes the main change: fixing gateway token accounting to include image input tokens in the accounting logic. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.                                                                           |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `image-token-accounting`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>apps/gateway/src/chat/chat.ts (1)</summary><blockquote>\n\n`375-379`: **Hardcoded model check is fragile but acceptable for now.**\n\nThe image counting gate is tied to a single model string. If additional models need image-input-token accounting in the future, this will need to become a list or a model-property check. Fine for this PR scope.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=theopenco/llmgateway&utm_content=1618)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/theopenco/llmgateway/issues/comments/3871386687","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:54 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"804A:257C3F:11C1AC6:4C7760E:698A0BBD","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4941","x-ratelimit-reset":"1770657833","x-ratelimit-resource":"core","x-ratelimit-used":"59","x-xss-protection":"0"},"data":""}}

@steebchen
steebchen merged commit bab445b into main Feb 9, 2026
12 of 13 checks passed
@steebchen
steebchen deleted the image-token-accounting branch February 9, 2026 16:38
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