Преглед изворни кода

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

Kit Langton пре 4 недеља
родитељ
комит
6a64177589

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

@@ -24,7 +24,7 @@ import {
   FreeUsageLimitError,
   SubscriptionUsageLimitError,
 } 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 { googleHelper } from "./provider/google"
 import { openaiHelper } from "./provider/openai"
@@ -90,7 +90,7 @@ export async function handler(
     const projectId = input.request.headers.get("x-opencode-project") ?? ""
     const ocClient = input.request.headers.get("x-opencode-client") ?? ""
     logger.metric({
-      is_tream: isStream,
+      is_stream: isStream,
       session: sessionId,
       request: requestId,
       client: ocClient,
@@ -230,7 +230,7 @@ export async function handler(
       const body = JSON.stringify(
         responseConverter({
           ...json,
-          cost: calculateOccuredCost(billingSource, costInfo),
+          cost: calculateOccurredCost(billingSource, costInfo),
         }),
       )
       logger.metric({ response_length: body.length })
@@ -274,8 +274,8 @@ export async function handler(
                   await trialLimiter?.track(usageInfo)
                   await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, 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()
                 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"
   }
 

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

@@ -167,7 +167,6 @@ export const anthropicHelper: ProviderHelper = ({ reqModel, providerModel }) =>
           }
         },
         retrieve: () => usage,
-        buidlCostChunk: (cost: string) => `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`,
       }
     },
     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
       },
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `data: ${JSON.stringify({ type: "ping", cost })}\n\n`,
     }
   },
   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
       },
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `data: ${JSON.stringify({ choices: [], cost })}\n\n`,
     }
   },
   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
       },
       retrieve: () => usage,
-      buidlCostChunk: (cost: string) => `event: ping\ndata: ${JSON.stringify({ type: "ping", cost })}\n\n`,
     }
   },
   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: () => {
     parse: (chunk: string) => void
     retrieve: () => any
-    buidlCostChunk: (cost: string) => string
   }
   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) {
   return (body: any): any => {
     if (from === to) return body