wip: zen · argszero/opencode@bbc9142 · GitHub
Skip to content

Commit bbc9142

Browse files
author
Frank
committed
wip: zen
1 parent 7413c27 commit bbc9142

30 files changed

Lines changed: 837 additions & 572 deletions

File tree

github/sst-env.d.ts

Lines changed: 1 addition & 1 deletion

infra/console.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
116116
// CONSOLE
117117
////////////////
118118

119+
const bucket = new sst.cloudflare.Bucket("ConsoleData")
120+
119121
const AWS_SES_ACCESS_KEY_ID = new sst.Secret("AWS_SES_ACCESS_KEY_ID")
120122
const AWS_SES_SECRET_ACCESS_KEY = new sst.Secret("AWS_SES_SECRET_ACCESS_KEY")
121123

@@ -132,6 +134,7 @@ new sst.cloudflare.x.SolidStart("Console", {
132134
domain,
133135
path: "packages/console/app",
134136
link: [
137+
bucket,
135138
database,
136139
AUTH_API_URL,
137140
STRIPE_WEBHOOK_SECRET,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Resource, waitUntil } from "@opencode-ai/console-resource"
2+
3+
export function createDataDumper(sessionId: string, requestId: string) {
4+
if (Resource.App.stage !== "production") return
5+
6+
let data: Record<string, any> = {}
7+
let modelName: string | undefined
8+
9+
return {
10+
provideModel: (model?: string) => (modelName = model),
11+
provideRequest: (request: string) => (data.request = request),
12+
provideResponse: (response: string) => (data.response = response),
13+
provideStream: (chunk: string) => (data.response = (data.response ?? "") + chunk),
14+
flush: () => {
15+
if (!modelName) return
16+
17+
const str = new Date().toISOString().replace(/[^0-9]/g, "")
18+
const yyyymmdd = str.substring(0, 8)
19+
const hh = str.substring(8, 10)
20+
21+
waitUntil(
22+
Resource.ConsoleData.put(`${yyyymmdd}/${hh}/${modelName}/${sessionId}/${requestId}.json`, JSON.stringify(data)),
23+
)
24+
},
25+
}
26+
}

packages/console/app/src/routes/zen/util/handler.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { googleHelper } from "./provider/google"
1919
import { openaiHelper } from "./provider/openai"
2020
import { oaCompatHelper } from "./provider/openai-compatible"
2121
import { createRateLimiter } from "./rateLimiter"
22+
import { createDataDumper } from "./dataDumper"
2223

2324
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
2425
type RetryOptions = {
@@ -48,16 +49,19 @@ export async function handler(
4849
try {
4950
const url = input.request.url
5051
const body = await input.request.json()
51-
const ip = input.request.headers.get("x-real-ip") ?? ""
5252
const model = opts.parseModel(url, body)
5353
const isStream = opts.parseIsStream(url, body)
54+
const ip = input.request.headers.get("x-real-ip") ?? ""
55+
const sessionId = input.request.headers.get("x-opencode-session")
56+
const requestId = input.request.headers.get("x-opencode-request")
5457
logger.metric({
5558
is_tream: isStream,
56-
session: input.request.headers.get("x-opencode-session"),
57-
request: input.request.headers.get("x-opencode-request"),
59+
session: sessionId,
60+
request: requestId,
5861
})
5962
const zenData = ZenData.list()
6063
const modelInfo = validateModel(zenData, model)
64+
const dataDumper = createDataDumper(sessionId, requestId)
6165
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
6266
await rateLimiter?.check()
6367

@@ -104,10 +108,14 @@ export async function handler(
104108
})
105109
}
106110

107-
return { providerInfo, authInfo, res, startTimestamp }
111+
return { providerInfo, authInfo, reqBody, res, startTimestamp }
108112
}
109113

110-
const { providerInfo, authInfo, res, startTimestamp } = await retriableRequest()
114+
const { providerInfo, authInfo, reqBody, res, startTimestamp } = await retriableRequest()
115+
116+
// Store model request
117+
dataDumper?.provideModel(providerInfo.storeModel)
118+
dataDumper?.provideRequest(reqBody)
111119

112120
// Scrub response headers
113121
const resHeaders = new Headers()
@@ -126,6 +134,8 @@ export async function handler(
126134
const body = JSON.stringify(responseConverter(json))
127135
logger.metric({ response_length: body.length })
128136
logger.debug("RESPONSE: " + body)
137+
dataDumper?.provideResponse(body)
138+
dataDumper?.flush()
129139
await rateLimiter?.track()
130140
await trackUsage(authInfo, modelInfo, providerInfo, json.usage)
131141
await reload(authInfo)
@@ -155,6 +165,7 @@ export async function handler(
155165
response_length: responseLength,
156166
"timestamp.last_byte": Date.now(),
157167
})
168+
dataDumper?.flush()
158169
await rateLimiter?.track()
159170
const usage = usageParser.retrieve()
160171
if (usage) {
@@ -174,6 +185,7 @@ export async function handler(
174185
}
175186
responseLength += value.length
176187
buffer += decoder.decode(value, { stream: true })
188+
dataDumper?.provideStream(buffer)
177189

178190
const parts = buffer.split(providerInfo.streamSeparator)
179191
buffer = parts.pop() ?? ""

packages/console/app/sst-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
/// <reference path="../../../sst-env.d.ts" />
77

88
import "sst"
9-
export {}
9+
export {}

packages/console/core/src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export namespace ZenData {
3232
model: z.string(),
3333
weight: z.number().optional(),
3434
disabled: z.boolean().optional(),
35+
storeModel: z.string().optional(),
3536
}),
3637
),
3738
})

packages/console/core/sst-env.d.ts

Lines changed: 114 additions & 104 deletions

0 commit comments

Comments
 (0)