Skip to content

Commit bcf740f

Browse files
committed
zen: make session provider sticky
1 parent 6b80fff commit bcf740f

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { oaCompatHelper } from "./provider/openai-compatible"
2121
import { createRateLimiter } from "./rateLimiter"
2222
import { createDataDumper } from "./dataDumper"
2323
import { createTrialLimiter } from "./trialLimiter"
24+
import { createStickyTracker } from "./stickyProviderTracker"
2425

2526
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
2627
type RetryOptions = {
@@ -68,9 +69,11 @@ export async function handler(
6869
const isTrial = await trialLimiter?.isTrial()
6970
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
7071
await rateLimiter?.check()
72+
const stickyTracker = createStickyTracker(modelInfo.stickyProvider ?? false, sessionId)
73+
const stickyProvider = await stickyTracker?.get()
7174

7275
const retriableRequest = async (retry: RetryOptions = { excludeProviders: [], retryCount: 0 }) => {
73-
const providerInfo = selectProvider(zenData, modelInfo, sessionId, isTrial ?? false, retry)
76+
const providerInfo = selectProvider(zenData, modelInfo, sessionId, isTrial ?? false, retry, stickyProvider)
7477
const authInfo = await authenticate(modelInfo, providerInfo)
7578
validateBilling(authInfo, modelInfo)
7679
validateModelSettings(authInfo)
@@ -121,6 +124,9 @@ export async function handler(
121124
dataDumper?.provideModel(providerInfo.storeModel)
122125
dataDumper?.provideRequest(reqBody)
123126

127+
// Store sticky provider
128+
await stickyTracker?.set(providerInfo.id)
129+
124130
// Scrub response headers
125131
const resHeaders = new Headers()
126132
const keepHeaders = ["content-type", "cache-control"]
@@ -289,12 +295,18 @@ export async function handler(
289295
sessionId: string,
290296
isTrial: boolean,
291297
retry: RetryOptions,
298+
stickyProvider: string | undefined,
292299
) {
293300
const provider = (() => {
294301
if (isTrial) {
295302
return modelInfo.providers.find((provider) => provider.id === modelInfo.trial!.provider)
296303
}
297304

305+
if (stickyProvider) {
306+
const provider = modelInfo.providers.find((provider) => provider.id === stickyProvider)
307+
if (provider) return provider
308+
}
309+
298310
if (retry.retryCount === MAX_RETRIES) {
299311
return modelInfo.providers.find((provider) => provider.id === modelInfo.fallbackProvider)
300312
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Resource } from "@opencode-ai/console-resource"
2+
3+
export function createStickyTracker(stickyProvider: boolean, session: string) {
4+
if (!stickyProvider) return
5+
if (!session) return
6+
const key = `sticky:${session}`
7+
8+
return {
9+
get: async () => {
10+
return await Resource.GatewayKv.get(key)
11+
},
12+
set: async (providerId: string) => {
13+
await Resource.GatewayKv.put(key, providerId, { expirationTtl: 86400 })
14+
},
15+
}
16+
}

packages/console/core/src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export namespace ZenData {
2424
cost: ModelCostSchema,
2525
cost200K: ModelCostSchema.optional(),
2626
allowAnonymous: z.boolean().optional(),
27+
stickyProvider: z.boolean().optional(),
2728
trial: z
2829
.object({
2930
limit: z.number(),

0 commit comments

Comments
 (0)