This commit is contained in:
Frank
2026-08-18 22:55:47 -04:00
parent 844288b99f
commit 275a28f6ae
11 changed files with 3308 additions and 3 deletions
+3
View File
@@ -390,6 +390,8 @@ export const dict = {
"zen.api.error.modelDisabled": "Model is disabled",
"zen.api.error.regionNotAllowed":
"The latest version of this model is only available hosted in China and requires explicit opt in: {{consoleGoUrl}}",
"zen.api.error.nonZdrNotAllowed":
"This model collects data used to improve its quality and requires explicit opt in: {{consoleGoUrl}}",
"zen.api.error.trialEnded":
"Free promotion has ended for {{model}}. You can continue using the model by subscribing to OpenCode Go - {{link}}",
@@ -671,6 +673,7 @@ export const dict = {
'Select "OpenCode Go" as the provider in your opencode configuration to use Go models.',
"workspace.lite.providers.title": "Providers",
"workspace.lite.providers.description": "Control which providers are used for routing.",
"workspace.lite.providers.allowNonZdr": "Enable models without zero data retention",
"workspace.lite.providers.useChina": "Enable models hosted in China",
"workspace.lite.black.message":
"You're currently subscribed to OpenCode Black or on the waitlist. Please unsubscribe first if you'd like to switch to Go.",
@@ -39,6 +39,7 @@ export const queryLiteSubscription = query(async (workspaceID: string) => {
timeCreated: LiteTable.timeCreated,
lite: BillingTable.lite,
region: WorkspaceTable.region,
allowNonZdr: WorkspaceTable.allow_non_zdr,
})
.from(BillingTable)
.innerJoin(LiteTable, eq(LiteTable.workspaceID, BillingTable.workspaceID))
@@ -54,6 +55,7 @@ export const queryLiteSubscription = query(async (workspaceID: string) => {
return {
mine,
useBalance: row.lite?.useBalance ?? false,
allowNonZdr: row.allowNonZdr ?? false,
region:
row.region ?? (await Workspace.setDefaultRegion({ country: countryFromRequest(getRequestEvent()?.request) })),
rollingUsage: Subscription.analyzeRollingUsage({
@@ -154,6 +156,24 @@ const setGoProviderRouting = action(async (form: FormData) => {
)
}, "go.providerRouting.set")
const setGoAllowNonZdr = action(async (form: FormData) => {
"use server"
const workspaceID = form.get("workspaceID") as string | null
if (!workspaceID) return { error: formError.workspaceRequired }
const allowNonZdr = (form.get("allowNonZdr") as string | null) === "true"
return json(
await withActor(
() =>
Workspace.update({ allow_non_zdr: allowNonZdr })
.then(() => ({ error: undefined }))
.catch((e) => ({ error: e.message as string })),
workspaceID,
),
{ revalidate: queryLiteSubscription.key },
)
}, "go.allowNonZdr.set")
function LiteUsageItem(props: { label: string; usage: { usagePercent: number; resetInSec: number } }) {
const i18n = useI18n()
@@ -186,6 +206,7 @@ export function LiteSection(props: { lite: LiteSubscription | undefined }) {
const checkoutSubmission = useSubmission(createLiteCheckoutUrl)
const useBalanceSubmission = useSubmission(setLiteUseBalance)
const providerRoutingSubmission = useSubmission(setGoProviderRouting)
const allowNonZdrSubmission = useSubmission(setGoAllowNonZdr)
const [store, setStore] = createStore({
loading: undefined as undefined | "session" | "checkout" | "alipay" | "upi",
showModal: false,
@@ -264,6 +285,20 @@ export function LiteSection(props: { lite: LiteSubscription | undefined }) {
<h3>{i18n.t("workspace.lite.providers.title")}</h3>
<p>{i18n.t("workspace.lite.providers.description")}</p>
</div>
<form action={setGoAllowNonZdr} method="post" data-slot="setting-row">
<p>{i18n.t("workspace.lite.providers.allowNonZdr")}</p>
<input type="hidden" name="workspaceID" value={params.id} />
<input type="hidden" name="allowNonZdr" value={sub().allowNonZdr ? "false" : "true"} />
<label data-slot="toggle-label">
<input
type="checkbox"
checked={sub().allowNonZdr}
disabled={allowNonZdrSubmission.pending}
onChange={(e) => e.currentTarget.form?.requestSubmit()}
/>
<span></span>
</label>
</form>
<form action={setGoProviderRouting} method="post" data-slot="setting-row">
<p>{i18n.t("workspace.lite.providers.useChina")}</p>
<input type="hidden" name="workspaceID" value={params.id} />
@@ -4,6 +4,7 @@ export class MonthlyLimitError extends Error {}
export class UserLimitError extends Error {}
export class ModelError extends Error {}
export class RegionError extends Error {}
export class DataPolicyError extends Error {}
class LimitError extends Error {
retryAfter?: number
@@ -22,6 +22,7 @@ import {
UserLimitError,
ModelError,
RegionError,
DataPolicyError,
RateLimitError,
FreeUsageLimitError,
GoUsageLimitError,
@@ -128,6 +129,12 @@ export async function handler(
: createKeyRateLimiter(modelInfo.id, modelInfo.rateLimit, zenApiKey, input.request)
await rateLimiter?.check()
const authInfo = await authenticate(modelInfo, zenApiKey)
if (authInfo && opts.modelList === "lite" && modelInfo.id === "muse-spark-1.2" && !authInfo.allowNonZdr)
throw new DataPolicyError(
t("zen.api.error.nonZdrNotAllowed", {
consoleGoUrl: `https://opencode.ai/workspace/${authInfo.workspaceID}/go`,
}),
)
const allowedRegions = authInfo?.region
? authInfo.region
: await (async () => {
@@ -477,7 +484,7 @@ export async function handler(
} catch {}
}
if (error instanceof RegionError)
if (error instanceof RegionError || error instanceof DataPolicyError)
return new Response(
JSON.stringify({
type: "error",
@@ -708,6 +715,7 @@ export async function handler(
workspace: {
id: WorkspaceTable.id,
region: WorkspaceTable.region,
allowNonZdr: WorkspaceTable.allow_non_zdr,
isBlocked: WorkspaceTable.is_blocked,
isFlaggedByAnthropic: WorkspaceTable.is_flagged_by_anthropic,
isFlaggedByOpenAI: WorkspaceTable.is_flagged_by_openai,
@@ -820,6 +828,7 @@ export async function handler(
apiKeyId: data.apiKey,
workspaceID: data.workspace.id,
region: data.workspace.region,
allowNonZdr: data.workspace.allowNonZdr ?? false,
billing: data.billing,
user: data.user,
black: data.black,