Ver código fonte

fix(zen): emit cost chunk in client-facing format, not upstream format (#16817)

Kit Langton 5 meses atrás
pai
commit
6a64177589

+ 6 - 6
packages/console/app/src/routes/zen/util/handler.ts

@@ -24,7 +24,7 @@ import {
   FreeUsageLimitError,
   FreeUsageLimitError,
   SubscriptionUsageLimitError,
   SubscriptionUsageLimitError,
 } from "./error"
 } from "./error"
-import { createBodyConverter, createStreamPartConverter, createResponseConverter, UsageInfo } from "./provider/provider"
+import { buildCostChunk, createBodyConverter, createStreamPartConverter, createResponseConverter, UsageInfo } from "./provider/provider"
 import { anthropicHelper } from "./provider/anthropic"
 import { anthropicHelper } from "./provider/anthropic"
 import { googleHelper } from "./provider/google"
 import { googleHelper } from "./provider/google"
 import { openaiHelper } from "./provider/openai"
 import { openaiHelper } from "./provider/openai"
@@ -90,7 +90,7 @@ export async function handler(
     const projectId = input.request.headers.get("x-opencode-project") ?? ""
     const projectId = input.request.headers.get("x-opencode-project") ?? ""
     const ocClient = input.request.headers.get("x-opencode-client") ?? ""
     const ocClient = input.request.headers.get("x-opencode-client") ?? ""
     logger.metric({
     logger.metric({
-      is_tream: isStream,
+      is_stream: isStream,
       session: sessionId,
       session: sessionId,
       request: requestId,
       request: requestId,
       client: ocClient,
       client: ocClient,
@@ -230,7 +230,7 @@ export async function handler(
       const body = JSON.stringify(
       const body = JSON.stringify(
         responseConverter({
         responseConverter({
           ...json,
           ...json,
-          cost: calculateOccuredCost(billingSource, costInfo),
+          cost: calculateOccurredCost(billingSource, costInfo),
         }),
         }),
       )
       )
       logger.metric({ response_length: body.length })
       logger.metric({ response_length: body.length })
@@ -274,8 +274,8 @@ export async function handler(
                   await trialLimiter?.track(usageInfo)
                   await trialLimiter?.track(usageInfo)
                   await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
                   await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
                   await reload(billingSource, authInfo, costInfo)
                   await reload(billingSource, authInfo, costInfo)
-                  const cost = calculateOccuredCost(billingSource, costInfo)
-                  c.enqueue(encoder.encode(usageParser.buidlCostChunk(cost)))
+                  const cost = calculateOccurredCost(billingSource, costInfo)
+                  c.enqueue(encoder.encode(buildCostChunk(opts.format, cost)))
                 }
                 }
                 c.close()
                 c.close()
                 return
                 return
@@ -818,7 +818,7 @@ export async function handler(
     }
     }
   }
   }
 
 
-  function calculateOccuredCost(billingSource: BillingSource, costInfo: CostInfo) {
+  function calculateOccurredCost(billingSource: BillingSource, costInfo: CostInfo) {
     return billingSource === "balance" ? (costInfo.totalCostInCent / 100).toFixed(8) : "0"
     return billingSource === "balance" ? (costInfo.totalCostInCent / 100).toFixed(8) : "0"
   }
   }
 
 

+ 0 - 1
packages/console/app/src/routes/zen/util/provider/anthropic.ts

@@ -167,7 +167,6 @@ export const anthropicHelper: ProviderHelper = ({ reqModel, providerModel }) =>
           }
           }
         },
         },
         retrieve: () => usage,
         retrieve: () => usage,
-        buidlCostChunk: (cost: string) => `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`,
       }
       }
     },
     },
     normalizeUsage: (usage: Usage) => ({
     normalizeUsage: (usage: Usage) => ({

+ 0 - 1
packages/console/app/src/routes/zen/util/provider/google.ts

@@ -56,7 +56,6 @@ export const googleHelper: ProviderHelper = ({ providerModel }) => ({
         usage = json.usageMetadata
         usage = json.usageMetadata
       },
       },
       retrieve: () => usage,
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `data: ${JSON.stringify({ type: "ping", cost })}\n\n`,
     }
     }
   },
   },
   normalizeUsage: (usage: Usage) => {
   normalizeUsage: (usage: Usage) => {

+ 0 - 1
packages/console/app/src/routes/zen/util/provider/openai-compatible.ts

@@ -54,7 +54,6 @@ export const oaCompatHelper: ProviderHelper = () => ({
         usage = json.usage
         usage = json.usage
       },
       },
       retrieve: () => usage,
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `data: ${JSON.stringify({ choices: [], cost })}\n\n`,
     }
     }
   },
   },
   normalizeUsage: (usage: Usage) => {
   normalizeUsage: (usage: Usage) => {

+ 0 - 1
packages/console/app/src/routes/zen/util/provider/openai.ts

@@ -44,7 +44,6 @@ export const openaiHelper: ProviderHelper = () => ({
         usage = json.response.usage
         usage = json.response.usage
       },
       },
       retrieve: () => usage,
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`,
     }
     }
   },
   },
   normalizeUsage: (usage: Usage) => {
   normalizeUsage: (usage: Usage) => {

+ 13 - 1
packages/console/app/src/routes/zen/util/provider/provider.ts

@@ -43,7 +43,6 @@ export type ProviderHelper = (input: { reqModel: string; providerModel: string }
   createUsageParser: () => {
   createUsageParser: () => {
     parse: (chunk: string) => void
     parse: (chunk: string) => void
     retrieve: () => any
     retrieve: () => any
-    buidlCostChunk: (cost: string) => string
   }
   }
   normalizeUsage: (usage: any) => UsageInfo
   normalizeUsage: (usage: any) => UsageInfo
 }
 }
@@ -162,6 +161,19 @@ export interface CommonChunk {
   }
   }
 }
 }
 
 
+export function buildCostChunk(format: ZenData.Format, cost: string): string {
+  switch (format) {
+    case "anthropic":
+      return `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`
+    case "openai":
+      return `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`
+    case "oa-compat":
+      return `data: ${JSON.stringify({ choices: [], cost })}\n\n`
+    default:
+      return `data: ${JSON.stringify({ type: "ping", cost })}\n\n`
+  }
+}
+
 export function createBodyConverter(from: ZenData.Format, to: ZenData.Format) {
 export function createBodyConverter(from: ZenData.Format, to: ZenData.Format) {
   return (body: any): any => {
   return (body: any): any => {
     if (from === to) return body
     if (from === to) return body