Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.8k
fix(billing): Skip billing on streamed workflows with byok#4056
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
a7839a1582b2622584bb890535f1edfdc162824421d4ab895096bb48e47f6aa3792e01File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -54,6 +54,38 @@ function isReadableStream(response: any): response is ReadableStream { | ||
| return response instanceof ReadableStream | ||
| } | ||
| const ZERO_COST = Object.freeze({ | ||
| input: 0, | ||
| output: 0, | ||
| total: 0, | ||
| pricing: Object.freeze({ input: 0, output: 0, updatedAt: new Date(0).toISOString() }), | ||
| }) | ||
| /** | ||
| * Prevents streaming callbacks from writing non-zero model cost for BYOK users | ||
| * while preserving tool costs. The property is frozen via defineProperty because | ||
| * providers set cost inside streaming callbacks that fire after this function returns. | ||
| */ | ||
| function zeroCostForBYOK(response: StreamingExecution): void { | ||
| const output = response.execution?.output | ||
| if (!output || typeof output !== 'object') { | ||
| logger.warn('zeroCostForBYOK: output not available at intercept time; cost may not be zeroed') | ||
| return | ||
| } | ||
| let toolCost = 0 | ||
| Object.defineProperty(output, 'cost', { | ||
| get: () => (toolCost > 0 ? { ...ZERO_COST, toolCost, total: toolCost } : ZERO_COST), | ||
| set: (value: Record<string, unknown>) => { | ||
| if (value?.toolCost && typeof value.toolCost === 'number') { | ||
| toolCost = value.toolCost | ||
| } | ||
| }, | ||
| configurable: true, | ||
| enumerable: true, | ||
| }) | ||
TheodoreSpeaks marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
TheodoreSpeaks marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. cursor[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| export async function executeProviderRequest( | ||
| providerId: string, | ||
| request: ProviderRequest | ||
| @@ -80,6 +112,12 @@ export async function executeProviderRequest( | ||
| ) | ||
| resolvedRequest = { ...resolvedRequest, apiKey: result.apiKey } | ||
| isBYOK = result.isBYOK | ||
| logger.info('API key resolved', { | ||
| provider: providerId, | ||
| model: request.model, | ||
| workspaceId: request.workspaceId, | ||
| isBYOK, | ||
| }) | ||
| } catch (error) { | ||
| logger.error('Failed to resolve API key:', { | ||
| provider: providerId, | ||
| @@ -118,7 +156,10 @@ export async function executeProviderRequest( | ||
| const response = await provider.executeRequest(sanitizedRequest) | ||
| if (isStreamingExecution(response)) { | ||
| logger.info('Provider returned StreamingExecution') | ||
| logger.info('Provider returned StreamingExecution', { isBYOK }) | ||
| if (isBYOK) { | ||
| zeroCostForBYOK(response) | ||
| } | ||
| return response | ||
| } | ||
| @@ -154,9 +195,9 @@ export async function executeProviderRequest( | ||
| }, | ||
| } | ||
| if (isBYOK) { | ||
| logger.debug(`Not billing model usage for ${response.model} - workspace BYOK key used`) | ||
| logger.info(`Not billing model usage for ${response.model} - workspace BYOK key used`) | ||
| } else { | ||
| logger.debug( | ||
| logger.info( | ||
| `Not billing model usage for ${response.model} - user provided API key or not hosted model` | ||
| ) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.