fix(billing): Skip billing on streamed workflows with byok#4056
fix(billing): Skip billing on streamed workflows with byok#4056TheodoreSpeaks merged 10 commits intostagingfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Updates streaming tokenization to not recalculate/overwrite cost when the billing layer has already set Reviewed by Cursor Bugbot for commit 3792e01. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR fixes a billing bug where BYOK (Bring Your Own Key) users were incorrectly charged when using streamed workflow responses. It introduces Confidence Score: 3/5The fix addresses the core billing bug for streaming BYOK users, but two reliability gaps could allow incorrect billing to slip through in edge cases. The ZERO_COST constant uses updatedAt: '' inconsistently with the synchronous path, and the zeroCostForBYOK guard silently exits without logging when output is absent, making it impossible to detect provider-specific gaps in production. These are correctness risks in the billing path that warrant attention before merging. apps/sim/providers/index.ts — specifically ZERO_COST.pricing.updatedAt and the early-return path in zeroCostForBYOK
|
| Filename | Overview |
|---|---|
| apps/sim/providers/index.ts | Adds zeroCostForBYOK to intercept streaming cost writes for BYOK users; has a minor updatedAt: '' inconsistency vs the synchronous zero-cost path, and a potential gap if providers replace output entirely during streaming rather than mutating it in-place. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[executeProviderRequest] --> B{workspaceId present?}
B -->|Yes| C[getApiKeyWithBYOK]
C --> D[isBYOK set]
B -->|No| E[isBYOK = false]
D --> F[provider.executeRequest]
E --> F
F --> G{Response type?}
G -->|StreamingExecution| H{isBYOK?}
H -->|Yes| I[zeroCostForBYOK\nObject.defineProperty cost trap]
I --> J[Return StreamingExecution]
H -->|No| J
G -->|ReadableStream| K[Return stream\n⚠️ No BYOK check]
G -->|ProviderResponse| L{shouldBillModelUsage AND not isBYOK?}
L -->|Yes| M[calculateCost → response.cost]
L -->|No| N[Zero cost → response.cost]
M --> O[Return response]
N --> O
Reviews (1): Last reviewed commit: "Simplify logic" | Re-trigger Greptile
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 762bc43. Configure here.
762bc43 to
90535f1
Compare
* fix(webhook): throw webhook errors as 4xxs * Fix shadowing body var --------- Co-authored-by: Theodore Li <theo@sim.ai>
* feat(enterprise): cloud whitelabeling for enterprise orgs * fix(enterprise): scope enterprise plan check to target org in whitelabel PUT * fix(enterprise): use isOrganizationOnEnterprisePlan for org-scoped enterprise check * fix(enterprise): allow clearing whitelabel fields and guard against empty update result * fix(enterprise): remove webp from logo accept attribute to match upload hook validation * improvement(billing): use isBillingEnabled instead of isProd for plan gate bypasses * fix(enterprise): show whitelabeling nav item when billing is enabled on non-hosted environments * fix(enterprise): accept relative paths for logoUrl since upload API returns /api/files/serve/ paths * fix(whitelabeling): prevent logo flash on refresh by hiding logo while branding loads * fix(whitelabeling): wire hover color through CSS token on tertiary buttons * fix(whitelabeling): show sim logo by default, only replace when org logo loads * fix(whitelabeling): cache org logo url in localstorage to eliminate flash on repeat visits * feat(whitelabeling): add wordmark support with drag/drop upload * updated turbo * fix(whitelabeling): defer localstorage read to effect to prevent hydration mismatch * fix(whitelabeling): use layout effect for cache read to eliminate logo flash before paint * fix(whitelabeling): cache theme css to eliminate color flash before org settings resolve * fix(whitelabeling): deduplicate HEX_COLOR_REGEX into lib/branding and remove mutation from useCallback deps * fix(whitelabeling): use cookie-based SSR cache to eliminate brand flash on all page loads * fix(whitelabeling): use !orgSettings condition to fix SSR brand cache injection React Query returns isLoading: false with data: undefined during SSR, so the previous brandingLoading condition was always false on the server — initialCache was never injected into brandConfig. Changing to !orgSettings correctly applies the cookie cache both during SSR and while the client-side query loads, eliminating the logo flash on hard refresh.
…connected to starter (#4054)
…ntext (#4055) Auto-layout was reading from getWorkflowState() without merging subblock store values, then persisting stale subblock data to the database. This caused runtime-edited values (e.g. router_v2 context) to be overwritten with their initial/empty values whenever auto-layout was triggered.
…ver-side (#4057) * fix(whitelabeling): eliminate logo flash by fetching org settings server-side * improvement(whitelabeling): add SVG support for logo and wordmark uploads * skelly in workspace header * remove dead code * fix(whitelabeling): hydration error, SVG support, skeleton shimmer, dead code removal * fix(whitelabeling): blob preview dep cycle and missing color fallback * fix(whitelabeling): use brand-accent as color fallback when workspace color is undefined * chore(whitelabeling): inline hasOrgBrand

Summary
BYOK users were incorrectly billed when using the streamed response. This was because the byok check is skipped for streamed responses because they're streamed live to the user. Added helper method
zeroCostForBYOKto zero out cost from the execution stream, while keeping tool costs.Also added tool cost to the execution log cost summary so that the total lines up.
Also upgraded logging byok so we can see the logic in prod.
Type of Change
Testing
Checklist
Screenshots/Videos