Skip to content

[AISAGE-733] fix(ai-gateway): bill the upstream cost of BYOK-served transcriptions - #8877

Merged
chrarnoldus merged 6 commits into
mainfrom
fix/gateway-transcription-byok-cost
Oct 26, 2026
Merged

chrarnoldus merged 6 commits into
mainfrom
fix/gateway-transcription-byok-cost

Conversation

@chrarnoldus

@chrarnoldus chrarnoldus commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OpenRouter transcriptions report only usage.cost, with no is_byok or cost_details. When OpenRouter serves a transcription with Kilo's BYOK keys, that cost is just its 5% BYOK fee, so we billed 1/20 of the real cost. Production transcription costs match the fee.

The response carries an x-generation-id header. OpenRouter's /generation endpoint for that id returns is_byok and upstream_inference_cost. I checked this by hand for openai/whisper-1 and openai/gpt-4o-mini-transcribe: both return is_byok: true with upstream_inference_cost at 20 times the reported cost, and token counts for the token-based model.

The header now becomes the message id, so the existing generation lookup in processTokenData supplies the real cost. Transcriptions have no inference provider in their response, so the lookup always runs. The missing-is_byok report now fires only when there is no generation id. If the lookup fails, the cost kept from the response may be only the BYOK fee, so processTokenData reports it at error level as "SUSPICIOUS: OpenRouter generation lookup failed, so a cost without BYOK status may be only the BYOK fee" (source: generation_lookup_fallback).

Billing impact: BYOK-served transcriptions will charge their upstream cost instead of OpenRouter's fee.

Every figure comes from upstream data. No token or cost estimates are added.

Split out of #8791.

Verification

  • pnpm --filter @kilocode/web-shared typecheck
  • jest packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.test.ts packages/web-shared/src/lib/ai-gateway/handlers/audio-transcriptions
  • New tests use the response shape OpenRouter returns for a BYOK whisper-1 transcription: the generation id is used and nothing is reported; with no id, the report still fires.
  • processTokenData tests: a failed generation lookup is reported, and a successful one bills upstream_inference_cost without a report.

Models: Claude Opus 5.5 (kilo/anthropic/claude-opus-5.5), no subagents.

The "openrouters cost accounting doesn't make sense" check treated a cost
without is_byok as broken accounting for every upstream. Probing showed
which upstreams report is_byok next to cost: OpenRouter (chat completions,
Messages, Responses, embeddings) and Vercel AI Gateway (chat completions).
Martian reports cost but never is_byok, so every stealth-model response
raised the report. Billing is unchanged.
OpenRouter transcriptions report only usage.cost, without is_byok or
cost_details, so a BYOK-served transcription billed just OpenRouter's 5%
BYOK fee. The response's x-generation-id header now becomes the message id,
so the existing generation lookup in processTokenData supplies is_byok and
upstream_inference_cost. The missing-is_byok report now only fires when
there is no generation id; fetchGeneration already reports lookup failures.
Comment thread packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.ts
@kilo-code-bot

kilo-code-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The only new commit renames the failed-generation-lookup Sentry message and updates its assertion to match; the wording, tag, severity, and extra payload stay consistent, and no other code references the old string, so no new defects found.

Assumptions: [INFERENCE] The merge commit 0027dcdd0 pulls in unrelated main changes (embedding accounting from #8875/#8876/#8878); those are outside this PR's own commits and were not re-reviewed. Tests and typecheck were not run in this read-only review.

Files Reviewed (2 files)
  • packages/web-shared/src/lib/ai-gateway/processUsage.ts
  • packages/web-shared/src/lib/ai-gateway/processUsage.test.ts
Previous Review Summaries (2 snapshots, latest commit 09ec669)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 09ec669)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change resolves the previously reported gap: processTokenData now raises an error-level report (source: generation_lookup_fallback) when an OpenRouter generation lookup fails and leaves is_byok unknown with a non-zero cost, and the new tests cover both the failed and successful lookup paths; no new defects found.

Assumptions: [INFERENCE] The repository tests/typecheck cited in the PR description were not run in this read-only review; correctness was verified by reading the changed code and its callers.

Files Reviewed (2 files)
  • packages/web-shared/src/lib/ai-gateway/processUsage.ts
  • packages/web-shared/src/lib/ai-gateway/processUsage.test.ts

Previous review (commit 3981f39)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.ts 1408 Suppressing the missing-is_byok report whenever a generation id exists also silences the case where the generation lookup itself fails, leaving the BYOK fee billed with only info-level logging
Files Reviewed (2 files)
  • packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.ts - 1 issue
  • packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.test.ts - no issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 46.3K · Output: 5.1K · Cached: 374.5K

Review guidance: REVIEW.md from base branch main

…tatus unknown

With a generation id, the transcription parser no longer reports the missing
is_byok, because the generation lookup resolves it. If that lookup fails,
processTokenData kept the response cost, which for a BYOK-served request is
only OpenRouter's 5% fee, with only an info-level log. Report that case at
error level.
Base automatically changed from fix/gateway-byok-check-providers to main October 26, 2026 09:26
…tion-byok-cost

# Conflicts:
#	packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.test.ts
#	packages/web-shared/src/lib/ai-gateway/llm-proxy-helpers.ts
The report raised when the generation lookup fails reused "openrouters cost
accounting doesn't make sense". Say what happened instead: the lookup failed,
so a cost without a BYOK status may be only the BYOK fee.
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