From bbc9142fc54fef532039f2a91c63ac2f2873af41 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 23 Nov 2025 15:21:47 -0500 Subject: wip: zen --- .../console/app/src/routes/zen/util/dataDumper.ts | 26 ++++++++++++++++++++++ .../console/app/src/routes/zen/util/handler.ts | 22 +++++++++++++----- 2 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 packages/console/app/src/routes/zen/util/dataDumper.ts (limited to 'packages/console/app/src') diff --git a/packages/console/app/src/routes/zen/util/dataDumper.ts b/packages/console/app/src/routes/zen/util/dataDumper.ts new file mode 100644 index 000000000..6a064138a --- /dev/null +++ b/packages/console/app/src/routes/zen/util/dataDumper.ts @@ -0,0 +1,26 @@ +import { Resource, waitUntil } from "@opencode-ai/console-resource" + +export function createDataDumper(sessionId: string, requestId: string) { + if (Resource.App.stage !== "production") return + + let data: Record = {} + let modelName: string | undefined + + return { + provideModel: (model?: string) => (modelName = model), + provideRequest: (request: string) => (data.request = request), + provideResponse: (response: string) => (data.response = response), + provideStream: (chunk: string) => (data.response = (data.response ?? "") + chunk), + flush: () => { + if (!modelName) return + + const str = new Date().toISOString().replace(/[^0-9]/g, "") + const yyyymmdd = str.substring(0, 8) + const hh = str.substring(8, 10) + + waitUntil( + Resource.ConsoleData.put(`${yyyymmdd}/${hh}/${modelName}/${sessionId}/${requestId}.json`, JSON.stringify(data)), + ) + }, + } +} diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 3453a6d38..c40db6e1d 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -19,6 +19,7 @@ import { googleHelper } from "./provider/google" import { openaiHelper } from "./provider/openai" import { oaCompatHelper } from "./provider/openai-compatible" import { createRateLimiter } from "./rateLimiter" +import { createDataDumper } from "./dataDumper" type ZenData = Awaited> type RetryOptions = { @@ -48,16 +49,19 @@ export async function handler( try { const url = input.request.url const body = await input.request.json() - const ip = input.request.headers.get("x-real-ip") ?? "" const model = opts.parseModel(url, body) const isStream = opts.parseIsStream(url, body) + const ip = input.request.headers.get("x-real-ip") ?? "" + const sessionId = input.request.headers.get("x-opencode-session") + const requestId = input.request.headers.get("x-opencode-request") logger.metric({ is_tream: isStream, - session: input.request.headers.get("x-opencode-session"), - request: input.request.headers.get("x-opencode-request"), + session: sessionId, + request: requestId, }) const zenData = ZenData.list() const modelInfo = validateModel(zenData, model) + const dataDumper = createDataDumper(sessionId, requestId) const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip) await rateLimiter?.check() @@ -104,10 +108,14 @@ export async function handler( }) } - return { providerInfo, authInfo, res, startTimestamp } + return { providerInfo, authInfo, reqBody, res, startTimestamp } } - const { providerInfo, authInfo, res, startTimestamp } = await retriableRequest() + const { providerInfo, authInfo, reqBody, res, startTimestamp } = await retriableRequest() + + // Store model request + dataDumper?.provideModel(providerInfo.storeModel) + dataDumper?.provideRequest(reqBody) // Scrub response headers const resHeaders = new Headers() @@ -126,6 +134,8 @@ export async function handler( const body = JSON.stringify(responseConverter(json)) logger.metric({ response_length: body.length }) logger.debug("RESPONSE: " + body) + dataDumper?.provideResponse(body) + dataDumper?.flush() await rateLimiter?.track() await trackUsage(authInfo, modelInfo, providerInfo, json.usage) await reload(authInfo) @@ -155,6 +165,7 @@ export async function handler( response_length: responseLength, "timestamp.last_byte": Date.now(), }) + dataDumper?.flush() await rateLimiter?.track() const usage = usageParser.retrieve() if (usage) { @@ -174,6 +185,7 @@ export async function handler( } responseLength += value.length buffer += decoder.decode(value, { stream: true }) + dataDumper?.provideStream(buffer) const parts = buffer.split(providerInfo.streamSeparator) buffer = parts.pop() ?? "" -- cgit v1.2.3