فهرست منبع

zen: data share

Frank 4 ماه پیش
والد
کامیت
9420d80b73

+ 1 - 0
bun.lock

@@ -56,6 +56,7 @@
         "@solidjs/start": "^1.1.0",
         "solid-js": "catalog:",
         "vinxi": "^0.5.7",
+        "zod": "catalog:",
       },
     },
     "packages/console/core": {

+ 1 - 1
github/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 2 - 16
infra/console.ts

@@ -99,11 +99,7 @@ export const stripeWebhook = new WebhookEndpoint("StripeWebhookEndpoint", {
   ],
 })
 
-const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY")
-const OPENAI_API_KEY = new sst.Secret("OPENAI_API_KEY")
-const XAI_API_KEY = new sst.Secret("XAI_API_KEY")
-const BASETEN_API_KEY = new sst.Secret("BASETEN_API_KEY")
-const FIREWORKS_API_KEY = new sst.Secret("FIREWORKS_API_KEY")
+const ZEN_MODELS = new sst.Secret("ZEN_MODELS")
 const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
 const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
   properties: { value: auth.url.apply((url) => url!) },
@@ -128,17 +124,7 @@ if ($app.stage === "production" || $app.stage === "frank") {
 new sst.cloudflare.x.SolidStart("Console", {
   domain,
   path: "packages/console/app",
-  link: [
-    database,
-    AUTH_API_URL,
-    STRIPE_WEBHOOK_SECRET,
-    STRIPE_SECRET_KEY,
-    ANTHROPIC_API_KEY,
-    OPENAI_API_KEY,
-    XAI_API_KEY,
-    BASETEN_API_KEY,
-    FIREWORKS_API_KEY,
-  ],
+  link: [database, AUTH_API_URL, STRIPE_WEBHOOK_SECRET, STRIPE_SECRET_KEY, ZEN_MODELS],
   environment: {
     //VITE_DOCS_URL: web.url.apply((url) => url!),
     //VITE_API_URL: gateway.url.apply((url) => url!),

+ 1 - 1
packages/app/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 2 - 1
packages/console/app/package.json

@@ -12,12 +12,13 @@
   "dependencies": {
     "@ibm/plex": "6.4.1",
     "@openauthjs/openauth": "0.0.0-20250322224806",
+    "@opencode/console-core": "workspace:*",
     "@solidjs/meta": "^0.29.4",
     "@solidjs/router": "^0.15.0",
     "@solidjs/start": "^1.1.0",
     "solid-js": "catalog:",
     "vinxi": "^0.5.7",
-    "@opencode/console-core": "workspace:*"
+    "zod": "catalog:"
   },
   "engines": {
     "node": ">=22"

+ 114 - 0
packages/console/app/src/component/workspace/privacy-section.module.css

@@ -0,0 +1,114 @@
+.root {
+  [data-slot="section-content"] {
+    display: flex;
+    flex-direction: column;
+    gap: var(--space-3);
+  }
+
+  [data-slot="reload-error"] {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: var(--space-4);
+    padding: var(--space-4);
+    border: 1px solid var(--color-border);
+    border-radius: var(--border-radius-sm);
+
+    p {
+      color: var(--color-danger);
+      font-size: var(--font-size-sm);
+      line-height: 1.4;
+      margin: 0;
+      flex: 1;
+    }
+
+    [data-slot="create-form"] {
+      display: flex;
+      gap: var(--space-2);
+      margin: 0;
+      flex-shrink: 0;
+    }
+  }
+  [data-slot="payment"] {
+    display: flex;
+    flex-direction: column;
+    gap: var(--space-3);
+    padding: var(--space-4);
+    border: 1px solid var(--color-border);
+    border-radius: var(--border-radius-sm);
+    min-width: 14.5rem;
+    width: fit-content;
+
+    @media (max-width: 30rem) {
+      width: 100%;
+    }
+
+    [data-slot="credit-card"] {
+      padding: var(--space-3-5) var(--space-4);
+      background-color: var(--color-bg-surface);
+      border-radius: var(--border-radius-sm);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+
+      [data-slot="card-icon"] {
+        display: flex;
+        align-items: center;
+        color: var(--color-text-muted);
+      }
+
+      [data-slot="card-details"] {
+        display: flex;
+        align-items: baseline;
+        gap: var(--space-1);
+
+        [data-slot="secret"] {
+          position: relative;
+          bottom: 2px;
+          font-size: var(--font-size-lg);
+          color: var(--color-text-muted);
+          font-weight: 400;
+        }
+
+        [data-slot="number"] {
+          font-size: var(--font-size-3xl);
+          font-weight: 500;
+          color: var(--color-text);
+        }
+      }
+    }
+
+    [data-slot="button-row"] {
+      display: flex;
+      gap: var(--space-2);
+      align-items: center;
+
+      @media (max-width: 30rem) {
+        flex-direction: column;
+
+        > button {
+          width: 100%;
+        }
+      }
+
+      [data-slot="create-form"] {
+        margin: 0;
+      }
+
+      /* Make Enable Billing button full width when it's the only button */
+      > button {
+        flex: 1;
+      }
+    }
+  }
+  [data-slot="usage"] {
+    p {
+      font-size: var(--font-size-sm);
+      line-height: 1.5;
+      color: var(--color-text-secondary);
+      b {
+        font-weight: 600;
+      }
+    }
+  }
+}

+ 98 - 0
packages/console/app/src/component/workspace/privacy-section.tsx

@@ -0,0 +1,98 @@
+import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
+import { withActor } from "~/context/auth.withActor"
+import styles from "./billing-section.module.css"
+import { Database, eq } from "@opencode/console-core/drizzle/index.js"
+import { WorkspaceTable } from "@opencode/console-core/schema/workspace.sql.js"
+import { Show } from "solid-js"
+
+const updateShare = action(async (form: FormData) => {
+  "use server"
+  const workspaceID = form.get("workspaceID")?.toString()
+  if (!workspaceID) return { error: "Workspace ID is required" }
+  const dataShare = form.get("dataShare")?.toString() === "true" ? true : null
+  return json(
+    await withActor(() => {
+      return Database.use((tx) =>
+        tx
+          .update(WorkspaceTable)
+          .set({
+            dataShare,
+          })
+          .where(eq(WorkspaceTable.id, workspaceID)),
+      )
+    }, workspaceID),
+    { revalidate: getWorkspaceInfo.key },
+  )
+}, "workspace.disableShare")
+
+const getWorkspaceInfo = query(async (workspaceID: string) => {
+  "use server"
+  return withActor(() => {
+    return Database.use((tx) =>
+      tx
+        .select({
+          dataShare: WorkspaceTable.dataShare,
+        })
+        .from(WorkspaceTable)
+        .where(eq(WorkspaceTable.id, workspaceID))
+        .then((r) => r[0]),
+    )
+  }, workspaceID)
+}, "workspace.get")
+
+export function PrivacySection() {
+  const params = useParams()
+  const workspaceInfo = createAsync(() => getWorkspaceInfo(params.id))
+  const updateShareSubmission = useSubmission(updateShare)
+
+  return (
+    <section class={styles.root}>
+      <div data-slot="section-title">
+        <h2>Privacy controls</h2>
+        <p>
+          Some providers offer data-sharing programs. If you opt in, you voluntarily <b>share your usage data</b> with
+          them, which they may use to improve their services, including <b>model training</b>.
+        </p>
+        <br />
+        <p>
+          By opting in, you gain access to <b>discounted pricing</b> from the provider. You can opt in or out at any
+          time.
+        </p>
+        <br />
+        <p>
+          <a target="_blank" href="/docs/zen">
+            Learn more
+          </a>
+        </p>
+      </div>
+      <Show when={workspaceInfo()?.dataShare}>
+        <div data-slot="payment">
+          <div data-slot="credit-card">
+            <div data-slot="card-details">
+              <span data-slot="number">You are currently opted in to the data-sharing program.</span>
+            </div>
+          </div>
+        </div>
+      </Show>
+      <div data-slot="section-content">
+        <div data-slot="payment">
+          <div data-slot="button-row">
+            <form action={updateShare} method="post" data-slot="create-form">
+              <input type="hidden" name="workspaceID" value={params.id} />
+              <input type="hidden" name="dataShare" value={workspaceInfo()?.dataShare ? "false" : "true"} />
+              <button data-color="ghost" type="submit" disabled={updateShareSubmission.pending}>
+                {workspaceInfo()?.dataShare
+                  ? updateShareSubmission.pending
+                    ? "Opting out..."
+                    : "Opt out"
+                  : updateShareSubmission.pending
+                    ? "Opting in..."
+                    : "Opt in"}
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+    </section>
+  )
+}

+ 15 - 0
packages/console/app/src/routes/workspace/[id].tsx

@@ -2,11 +2,15 @@ import "./[id].css"
 import { MonthlyLimitSection } from "~/component/workspace/monthly-limit-section"
 import { NewUserSection } from "~/component/workspace/new-user-section"
 import { BillingSection } from "~/component/workspace/billing-section"
+import { PrivacySection } from "~/component/workspace/privacy-section"
 import { PaymentSection } from "~/component/workspace/payment-section"
 import { UsageSection } from "~/component/workspace/usage-section"
 import { KeySection } from "~/component/workspace/key-section"
+import { Show } from "solid-js"
+import { useParams } from "@solidjs/router"
 
 export default function () {
+  const params = useParams()
   return (
     <div data-page="workspace-[id]">
       <section data-component="title-section">
@@ -25,9 +29,20 @@ export default function () {
         <KeySection />
         <BillingSection />
         <MonthlyLimitSection />
+        <Show when={isBeta(params.id)}>
+          <PrivacySection />
+        </Show>
         <UsageSection />
         <PaymentSection />
       </div>
     </div>
   )
 }
+
+export function isBeta(workspaceID: string) {
+  return [
+    "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // production
+    "wrk_01K4NFRR5P7FSYWH88307B4DDS", // dev
+    "wrk_01K4PJRKJ2WPQZN3FFYRV4673F", // frank
+  ].includes(workspaceID)
+}

+ 260 - 414
packages/console/app/src/routes/zen/handler.ts

@@ -1,37 +1,15 @@
+import { z } from "zod"
 import type { APIEvent } from "@solidjs/start/server"
 import path from "node:path"
 import { and, Database, eq, isNull, lt, or, sql } from "@opencode/console-core/drizzle/index.js"
 import { KeyTable } from "@opencode/console-core/schema/key.sql.js"
-import { BillingTable, PaymentTable, UsageTable } from "@opencode/console-core/schema/billing.sql.js"
+import { BillingTable, UsageTable } from "@opencode/console-core/schema/billing.sql.js"
 import { centsToMicroCents } from "@opencode/console-core/util/price.js"
 import { Identifier } from "@opencode/console-core/identifier.js"
 import { Resource } from "@opencode/console-resource"
 import { Billing } from "../../../../core/src/billing"
 import { Actor } from "@opencode/console-core/actor.js"
-
-type ModelCost = {
-  input: number
-  output: number
-  cacheRead?: number
-  cacheWrite5m?: number
-  cacheWrite1h?: number
-}
-
-type Model = {
-  id: string
-  auth: boolean
-  cost: ModelCost | ((usage: any) => ModelCost)
-  headerMappings: Record<string, string>
-  providers: Record<
-    string,
-    {
-      api: string
-      apiKey: string
-      model: string
-      weight?: number
-    }
-  >
-}
+import { WorkspaceTable } from "@opencode/console-core/schema/workspace.sql.js"
 
 export async function handler(
   input: APIEvent,
@@ -56,184 +34,32 @@ export async function handler(
   class MonthlyLimitError extends Error {}
   class ModelError extends Error {}
 
-  const MODELS: Record<string, Model> = {
-    "claude-opus-4-1": {
-      id: "claude-opus-4-1" as const,
-      auth: true,
-      cost: {
-        input: 0.000015,
-        output: 0.000075,
-        cacheRead: 0.0000015,
-        cacheWrite5m: 0.00001875,
-        cacheWrite1h: 0.00003,
-      },
-      headerMappings: {},
-      providers: {
-        anthropic: {
-          api: "https://api.anthropic.com",
-          apiKey: Resource.ANTHROPIC_API_KEY.value,
-          model: "claude-opus-4-1-20250805",
-        },
-      },
-    },
-    "claude-sonnet-4": {
-      id: "claude-sonnet-4" as const,
-      auth: true,
-      cost: (usage: any) => {
-        const totalInputTokens =
-          usage.inputTokens + usage.cacheReadTokens + usage.cacheWrite5mTokens + usage.cacheWrite1hTokens
-        return totalInputTokens <= 200_000
-          ? {
-              input: 0.000003,
-              output: 0.000015,
-              cacheRead: 0.0000003,
-              cacheWrite5m: 0.00000375,
-              cacheWrite1h: 0.000006,
-            }
-          : {
-              input: 0.000006,
-              output: 0.0000225,
-              cacheRead: 0.0000006,
-              cacheWrite5m: 0.0000075,
-              cacheWrite1h: 0.000012,
-            }
-      },
-      headerMappings: {},
-      providers: {
-        anthropic: {
-          api: "https://api.anthropic.com",
-          apiKey: Resource.ANTHROPIC_API_KEY.value,
-          model: "claude-sonnet-4-20250514",
-        },
-      },
-    },
-    "claude-3-5-haiku": {
-      id: "claude-3-5-haiku" as const,
-      auth: true,
-      cost: {
-        input: 0.0000008,
-        output: 0.000004,
-        cacheRead: 0.00000008,
-        cacheWrite5m: 0.000001,
-        cacheWrite1h: 0.0000016,
-      },
-      headerMappings: {},
-      providers: {
-        anthropic: {
-          api: "https://api.anthropic.com",
-          apiKey: Resource.ANTHROPIC_API_KEY.value,
-          model: "claude-3-5-haiku-20241022",
-        },
-      },
-    },
-    "gpt-5": {
-      id: "gpt-5" as const,
-      auth: true,
-      cost: {
-        input: 0.00000125,
-        output: 0.00001,
-        cacheRead: 0.000000125,
-      },
-      headerMappings: {},
-      providers: {
-        openai: {
-          api: "https://api.openai.com",
-          apiKey: Resource.OPENAI_API_KEY.value,
-          model: "gpt-5",
-        },
-      },
-    },
-    "qwen3-coder": {
-      id: "qwen3-coder" as const,
-      auth: true,
-      cost: {
-        input: 0.00000045,
-        output: 0.0000018,
-      },
-      headerMappings: {},
-      providers: {
-        baseten: {
-          api: "https://inference.baseten.co",
-          apiKey: Resource.BASETEN_API_KEY.value,
-          model: "Qwen/Qwen3-Coder-480B-A35B-Instruct",
-          weight: 4,
-        },
-        fireworks: {
-          api: "https://api.fireworks.ai/inference",
-          apiKey: Resource.FIREWORKS_API_KEY.value,
-          model: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct",
-          weight: 1,
-        },
-      },
-    },
-    "kimi-k2": {
-      id: "kimi-k2" as const,
-      auth: true,
-      cost: {
-        input: 0.0000006,
-        output: 0.0000025,
-      },
-      headerMappings: {},
-      providers: {
-        baseten: {
-          api: "https://inference.baseten.co",
-          apiKey: Resource.BASETEN_API_KEY.value,
-          model: "moonshotai/Kimi-K2-Instruct-0905",
-          //weight: 4,
-        },
-        //fireworks: {
-        //  api: "https://api.fireworks.ai/inference",
-        //  apiKey: Resource.FIREWORKS_API_KEY.value,
-        //  model: "accounts/fireworks/models/kimi-k2-instruct-0905",
-        //  weight: 1,
-        //},
-      },
-    },
-    "grok-code": {
-      id: "grok-code" as const,
-      auth: false,
-      cost: {
-        input: 0,
-        output: 0,
-        cacheRead: 0,
-      },
-      headerMappings: {
-        "x-grok-conv-id": "x-opencode-session",
-        "x-grok-req-id": "x-opencode-request",
-      },
-      providers: {
-        xai: {
-          api: "https://api.x.ai",
-          apiKey: Resource.XAI_API_KEY.value,
-          model: "grok-code",
-        },
-      },
-    },
-    // deprecated
-    "qwen/qwen3-coder": {
-      id: "qwen/qwen3-coder" as const,
-      auth: true,
-      cost: {
-        input: 0.00000038,
-        output: 0.00000153,
-      },
-      headerMappings: {},
-      providers: {
-        baseten: {
-          api: "https://inference.baseten.co",
-          apiKey: Resource.BASETEN_API_KEY.value,
-          model: "Qwen/Qwen3-Coder-480B-A35B-Instruct",
-          weight: 5,
-        },
-        fireworks: {
-          api: "https://api.fireworks.ai/inference",
-          apiKey: Resource.FIREWORKS_API_KEY.value,
-          model: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct",
-          weight: 1,
-        },
-      },
-    },
-  }
+  const ModelCostSchema = z.object({
+    input: z.number(),
+    output: z.number(),
+    cacheRead: z.number().optional(),
+    cacheWrite5m: z.number().optional(),
+    cacheWrite1h: z.number().optional(),
+  })
+
+  const ModelSchema = z.object({
+    cost: ModelCostSchema,
+    cost200K: ModelCostSchema.optional(),
+    providers: z.array(
+      z.object({
+        id: z.string(),
+        api: z.string(),
+        apiKey: z.string(),
+        model: z.string(),
+        weight: z.number().optional(),
+        allowAnonymous: z.boolean().optional(),
+        headerMappings: z.record(z.string(), z.string()).optional(),
+        disabled: z.boolean().optional(),
+      }),
+    ),
+  })
+
+  type Model = z.infer<typeof ModelSchema>
 
   const FREE_WORKSPACES = [
     "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
@@ -259,31 +85,28 @@ export async function handler(
       session: input.request.headers.get("x-opencode-session"),
       request: input.request.headers.get("x-opencode-request"),
     })
-    const MODEL = validateModel()
-    const apiKey = await authenticate()
-    const isFree = FREE_WORKSPACES.includes(apiKey?.workspaceID ?? "")
-    await checkCreditsAndLimit()
-    const providerName = selectProvider()
-    const providerData = MODEL.providers[providerName]
-    logger.metric({ provider: providerName })
+    const authInfo = await authenticate()
+    const modelInfo = validateModel(body.model, authInfo)
+    const providerInfo = selectProvider(modelInfo, authInfo)
+    logger.metric({ provider: providerInfo.id })
 
     // Request to model provider
     const startTimestamp = Date.now()
-    const res = await fetch(path.posix.join(providerData.api, url.pathname.replace(/^\/zen/, "") + url.search), {
+    const res = await fetch(path.posix.join(providerInfo.api, url.pathname.replace(/^\/zen/, "") + url.search), {
       method: "POST",
       headers: (() => {
         const headers = input.request.headers
         headers.delete("host")
         headers.delete("content-length")
-        opts.setAuthHeader(headers, providerData.apiKey)
-        Object.entries(MODEL.headerMappings ?? {}).forEach(([k, v]) => {
+        opts.setAuthHeader(headers, providerInfo.apiKey)
+        Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => {
           headers.set(k, headers.get(v)!)
         })
         return headers
       })(),
       body: JSON.stringify({
         ...(opts.modifyBody?.(body) ?? body),
-        model: providerData.model,
+        model: providerInfo.model,
       }),
     })
 
@@ -302,8 +125,8 @@ export async function handler(
       const body = JSON.stringify(json)
       logger.metric({ response_length: body.length })
       logger.debug(body)
-      await trackUsage(json.usage)
-      await reload()
+      await trackUsage(authInfo, modelInfo, providerInfo.id, json.usage)
+      await reload(authInfo)
       return new Response(body, {
         status: res.status,
         statusText: res.statusText,
@@ -326,8 +149,8 @@ export async function handler(
                 logger.metric({ response_length: responseLength })
                 const usage = opts.getStreamUsage()
                 if (usage) {
-                  await trackUsage(usage)
-                  await reload()
+                  await trackUsage(authInfo, modelInfo, providerInfo.id, usage)
+                  await reload(authInfo)
                 }
                 c.close()
                 return
@@ -337,6 +160,7 @@ export async function handler(
                 logger.metric({ time_to_first_byte: Date.now() - startTimestamp })
               }
               responseLength += value.length
+              console.log(decoder.decode(value, { stream: true }))
               buffer += decoder.decode(value, { stream: true })
 
               const parts = buffer.split("\n\n")
@@ -363,202 +187,6 @@ export async function handler(
       statusText: res.statusText,
       headers: resHeaders,
     })
-
-    function validateModel() {
-      if (!(body.model in MODELS)) {
-        throw new ModelError(`Model ${body.model} not supported`)
-      }
-      const model = MODELS[body.model as keyof typeof MODELS]
-      logger.metric({ model: model.id })
-      return model
-    }
-
-    async function authenticate() {
-      try {
-        const apiKey = opts.parseApiKey(input.request.headers)
-        if (!apiKey) throw new AuthError("Missing API key.")
-
-        const key = await Database.use((tx) =>
-          tx
-            .select({
-              id: KeyTable.id,
-              workspaceID: KeyTable.workspaceID,
-            })
-            .from(KeyTable)
-            .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
-            .then((rows) => rows[0]),
-        )
-
-        if (!key) throw new AuthError("Invalid API key.")
-        logger.metric({
-          api_key: key.id,
-          workspace: key.workspaceID,
-        })
-        return key
-      } catch (e) {
-        // ignore error if model does not require authentication
-        if (!MODEL.auth) return
-        throw e
-      }
-    }
-
-    async function checkCreditsAndLimit() {
-      if (!apiKey || !MODEL.auth || isFree) return
-
-      const billing = await Database.use((tx) =>
-        tx
-          .select({
-            balance: BillingTable.balance,
-            paymentMethodID: BillingTable.paymentMethodID,
-            monthlyLimit: BillingTable.monthlyLimit,
-            monthlyUsage: BillingTable.monthlyUsage,
-            timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
-          })
-          .from(BillingTable)
-          .where(eq(BillingTable.workspaceID, apiKey.workspaceID))
-          .then((rows) => rows[0]),
-      )
-
-      if (!billing.paymentMethodID) throw new CreditsError("No payment method")
-      if (billing.balance <= 0) throw new CreditsError("Insufficient balance")
-      if (
-        billing.monthlyLimit &&
-        billing.monthlyUsage &&
-        billing.timeMonthlyUsageUpdated &&
-        billing.monthlyUsage >= centsToMicroCents(billing.monthlyLimit * 100)
-      ) {
-        const now = new Date()
-        const currentYear = now.getUTCFullYear()
-        const currentMonth = now.getUTCMonth()
-        const dateYear = billing.timeMonthlyUsageUpdated.getUTCFullYear()
-        const dateMonth = billing.timeMonthlyUsageUpdated.getUTCMonth()
-        if (currentYear === dateYear && currentMonth === dateMonth)
-          throw new MonthlyLimitError(`You have reached your monthly spending limit of $${billing.monthlyLimit}.`)
-      }
-    }
-
-    function selectProvider() {
-      const picks = Object.entries(MODEL.providers).flatMap(([name, provider]) =>
-        Array<string>(provider.weight ?? 1).fill(name),
-      )
-      return picks[Math.floor(Math.random() * picks.length)]
-    }
-
-    async function trackUsage(usage: any) {
-      const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
-        opts.normalizeUsage(usage)
-
-      const modelCost = typeof MODEL.cost === "function" ? MODEL.cost(usage) : MODEL.cost
-
-      const inputCost = modelCost.input * inputTokens * 100
-      const outputCost = modelCost.output * outputTokens * 100
-      const reasoningCost = (() => {
-        if (!reasoningTokens) return undefined
-        return modelCost.output * reasoningTokens * 100
-      })()
-      const cacheReadCost = (() => {
-        if (!cacheReadTokens) return undefined
-        if (!modelCost.cacheRead) return undefined
-        return modelCost.cacheRead * cacheReadTokens * 100
-      })()
-      const cacheWrite5mCost = (() => {
-        if (!cacheWrite5mTokens) return undefined
-        if (!modelCost.cacheWrite5m) return undefined
-        return modelCost.cacheWrite5m * cacheWrite5mTokens * 100
-      })()
-      const cacheWrite1hCost = (() => {
-        if (!cacheWrite1hTokens) return undefined
-        if (!modelCost.cacheWrite1h) return undefined
-        return modelCost.cacheWrite1h * cacheWrite1hTokens * 100
-      })()
-      const totalCostInCent =
-        inputCost +
-        outputCost +
-        (reasoningCost ?? 0) +
-        (cacheReadCost ?? 0) +
-        (cacheWrite5mCost ?? 0) +
-        (cacheWrite1hCost ?? 0)
-
-      logger.metric({
-        "tokens.input": inputTokens,
-        "tokens.output": outputTokens,
-        "tokens.reasoning": reasoningTokens,
-        "tokens.cache_read": cacheReadTokens,
-        "tokens.cache_write_5m": cacheWrite5mTokens,
-        "tokens.cache_write_1h": cacheWrite1hTokens,
-        "cost.input": Math.round(inputCost),
-        "cost.output": Math.round(outputCost),
-        "cost.reasoning": reasoningCost ? Math.round(reasoningCost) : undefined,
-        "cost.cache_read": cacheReadCost ? Math.round(cacheReadCost) : undefined,
-        "cost.cache_write_5m": cacheWrite5mCost ? Math.round(cacheWrite5mCost) : undefined,
-        "cost.cache_write_1h": cacheWrite1hCost ? Math.round(cacheWrite1hCost) : undefined,
-        "cost.total": Math.round(totalCostInCent),
-      })
-
-      if (!apiKey) return
-
-      const cost = isFree ? 0 : centsToMicroCents(totalCostInCent)
-      await Database.transaction(async (tx) => {
-        await tx.insert(UsageTable).values({
-          workspaceID: apiKey.workspaceID,
-          id: Identifier.create("usage"),
-          model: MODEL.id,
-          provider: providerName,
-          inputTokens,
-          outputTokens,
-          reasoningTokens,
-          cacheReadTokens,
-          cacheWrite5mTokens,
-          cacheWrite1hTokens,
-          cost,
-        })
-        await tx
-          .update(BillingTable)
-          .set({
-            balance: sql`${BillingTable.balance} - ${cost}`,
-            monthlyUsage: sql`
-              CASE
-                WHEN MONTH(${BillingTable.timeMonthlyUsageUpdated}) = MONTH(now()) AND YEAR(${BillingTable.timeMonthlyUsageUpdated}) = YEAR(now()) THEN ${BillingTable.monthlyUsage} + ${cost}
-                ELSE ${cost}
-              END
-            `,
-            timeMonthlyUsageUpdated: sql`now()`,
-          })
-          .where(eq(BillingTable.workspaceID, apiKey.workspaceID))
-      })
-
-      await Database.use((tx) =>
-        tx
-          .update(KeyTable)
-          .set({ timeUsed: sql`now()` })
-          .where(eq(KeyTable.id, apiKey.id)),
-      )
-    }
-
-    async function reload() {
-      if (!apiKey) return
-
-      const lock = await Database.use((tx) =>
-        tx
-          .update(BillingTable)
-          .set({
-            timeReloadLockedTill: sql`now() + interval 1 minute`,
-          })
-          .where(
-            and(
-              eq(BillingTable.workspaceID, apiKey.workspaceID),
-              eq(BillingTable.reload, true),
-              lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)),
-              or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)),
-            ),
-          ),
-      )
-      if (lock.rowsAffected === 0) return
-
-      await Actor.provide("system", { workspaceID: apiKey.workspaceID }, async () => {
-        await Billing.reload()
-      })
-    }
   } catch (error: any) {
     logger.metric({
       "error.type": error.constructor.name,
@@ -591,4 +219,222 @@ export async function handler(
       { status: 500 },
     )
   }
+
+  async function authenticate() {
+    const apiKey = opts.parseApiKey(input.request.headers)
+    if (!apiKey) return
+
+    const data = await Database.use((tx) =>
+      tx
+        .select({
+          apiKey: KeyTable.id,
+          workspaceID: KeyTable.workspaceID,
+          dataShare: WorkspaceTable.dataShare,
+          balance: BillingTable.balance,
+          paymentMethodID: BillingTable.paymentMethodID,
+          monthlyLimit: BillingTable.monthlyLimit,
+          monthlyUsage: BillingTable.monthlyUsage,
+          timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
+        })
+        .from(KeyTable)
+        .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
+        .innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID))
+        .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
+        .then((rows) => rows[0]),
+    )
+
+    if (!data) throw new AuthError("Invalid API key.")
+    logger.metric({
+      api_key: data.apiKey,
+      workspace: data.workspaceID,
+    })
+
+    const isFree = FREE_WORKSPACES.includes(data.workspaceID)
+    if (!isFree) {
+      if (!data.paymentMethodID) throw new CreditsError("No payment method")
+      if (data.balance <= 0) throw new CreditsError("Insufficient balance")
+      if (
+        data.monthlyLimit &&
+        data.monthlyUsage &&
+        data.timeMonthlyUsageUpdated &&
+        data.monthlyUsage >= centsToMicroCents(data.monthlyLimit * 100)
+      ) {
+        const now = new Date()
+        const currentYear = now.getUTCFullYear()
+        const currentMonth = now.getUTCMonth()
+        const dateYear = data.timeMonthlyUsageUpdated.getUTCFullYear()
+        const dateMonth = data.timeMonthlyUsageUpdated.getUTCMonth()
+        if (currentYear === dateYear && currentMonth === dateMonth)
+          throw new MonthlyLimitError(`You have reached your monthly spending limit of $${data.monthlyLimit}.`)
+      }
+    }
+
+    return {
+      apiKeyId: data.apiKey,
+      workspaceID: data.workspaceID,
+      dataShare: data.dataShare,
+      isFree,
+    }
+  }
+
+  function validateModel(reqModel: string, authInfo: Awaited<ReturnType<typeof authenticate>>) {
+    const json = JSON.parse(Resource.ZEN_MODELS.value)
+
+    const allModels = z
+      .record(
+        z.string(),
+        z.object({
+          standard: ModelSchema,
+          dataShare: ModelSchema.optional(),
+        }),
+      )
+      .parse(json)
+
+    if (!(reqModel in allModels)) {
+      throw new ModelError(`Model ${reqModel} not supported`)
+    }
+    const modelId = reqModel as keyof typeof allModels
+    const modelData = authInfo?.dataShare
+      ? (allModels[modelId].dataShare ?? allModels[modelId].standard)
+      : allModels[modelId].standard
+    logger.metric({ model: modelId })
+    return { id: modelId, ...modelData }
+  }
+
+  function selectProvider(model: Model, authInfo: Awaited<ReturnType<typeof authenticate>>) {
+    let providers = model.providers.filter((provider) => !provider.disabled)
+
+    if (!authInfo) {
+      providers = providers.filter((provider) => provider.allowAnonymous)
+      if (providers.length === 0) throw new AuthError("Missing API key.")
+    }
+
+    const picks = providers.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
+    return picks[Math.floor(Math.random() * picks.length)]
+  }
+
+  async function trackUsage(
+    authInfo: Awaited<ReturnType<typeof authenticate>>,
+    modelInfo: ReturnType<typeof validateModel>,
+    providerId: string,
+    usage: any,
+  ) {
+    const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
+      opts.normalizeUsage(usage)
+
+    const modelCost =
+      modelInfo.cost200K &&
+      usage.inputTokens + usage.cacheReadTokens + usage.cacheWrite5mTokens + usage.cacheWrite1hTokens > 200_000
+        ? modelInfo.cost200K
+        : modelInfo.cost
+
+    const inputCost = modelCost.input * inputTokens * 100
+    const outputCost = modelCost.output * outputTokens * 100
+    const reasoningCost = (() => {
+      if (!reasoningTokens) return undefined
+      return modelCost.output * reasoningTokens * 100
+    })()
+    const cacheReadCost = (() => {
+      if (!cacheReadTokens) return undefined
+      if (!modelCost.cacheRead) return undefined
+      return modelCost.cacheRead * cacheReadTokens * 100
+    })()
+    const cacheWrite5mCost = (() => {
+      if (!cacheWrite5mTokens) return undefined
+      if (!modelCost.cacheWrite5m) return undefined
+      return modelCost.cacheWrite5m * cacheWrite5mTokens * 100
+    })()
+    const cacheWrite1hCost = (() => {
+      if (!cacheWrite1hTokens) return undefined
+      if (!modelCost.cacheWrite1h) return undefined
+      return modelCost.cacheWrite1h * cacheWrite1hTokens * 100
+    })()
+    const totalCostInCent =
+      inputCost +
+      outputCost +
+      (reasoningCost ?? 0) +
+      (cacheReadCost ?? 0) +
+      (cacheWrite5mCost ?? 0) +
+      (cacheWrite1hCost ?? 0)
+
+    logger.metric({
+      "tokens.input": inputTokens,
+      "tokens.output": outputTokens,
+      "tokens.reasoning": reasoningTokens,
+      "tokens.cache_read": cacheReadTokens,
+      "tokens.cache_write_5m": cacheWrite5mTokens,
+      "tokens.cache_write_1h": cacheWrite1hTokens,
+      "cost.input": Math.round(inputCost),
+      "cost.output": Math.round(outputCost),
+      "cost.reasoning": reasoningCost ? Math.round(reasoningCost) : undefined,
+      "cost.cache_read": cacheReadCost ? Math.round(cacheReadCost) : undefined,
+      "cost.cache_write_5m": cacheWrite5mCost ? Math.round(cacheWrite5mCost) : undefined,
+      "cost.cache_write_1h": cacheWrite1hCost ? Math.round(cacheWrite1hCost) : undefined,
+      "cost.total": Math.round(totalCostInCent),
+    })
+
+    if (!authInfo) return
+
+    const cost = authInfo.isFree ? 0 : centsToMicroCents(totalCostInCent)
+    await Database.transaction(async (tx) => {
+      await tx.insert(UsageTable).values({
+        workspaceID: authInfo.workspaceID,
+        id: Identifier.create("usage"),
+        model: modelInfo.id,
+        provider: providerId,
+        inputTokens,
+        outputTokens,
+        reasoningTokens,
+        cacheReadTokens,
+        cacheWrite5mTokens,
+        cacheWrite1hTokens,
+        cost,
+      })
+      await tx
+        .update(BillingTable)
+        .set({
+          balance: sql`${BillingTable.balance} - ${cost}`,
+          monthlyUsage: sql`
+              CASE
+                WHEN MONTH(${BillingTable.timeMonthlyUsageUpdated}) = MONTH(now()) AND YEAR(${BillingTable.timeMonthlyUsageUpdated}) = YEAR(now()) THEN ${BillingTable.monthlyUsage} + ${cost}
+                ELSE ${cost}
+              END
+            `,
+          timeMonthlyUsageUpdated: sql`now()`,
+        })
+        .where(eq(BillingTable.workspaceID, authInfo.workspaceID))
+    })
+
+    await Database.use((tx) =>
+      tx
+        .update(KeyTable)
+        .set({ timeUsed: sql`now()` })
+        .where(eq(KeyTable.id, authInfo.apiKeyId)),
+    )
+  }
+
+  async function reload(authInfo: Awaited<ReturnType<typeof authenticate>>) {
+    if (!authInfo) return
+
+    const lock = await Database.use((tx) =>
+      tx
+        .update(BillingTable)
+        .set({
+          timeReloadLockedTill: sql`now() + interval 1 minute`,
+        })
+        .where(
+          and(
+            eq(BillingTable.workspaceID, authInfo.workspaceID),
+            eq(BillingTable.reload, true),
+            lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)),
+            or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)),
+          ),
+        ),
+    )
+    if (lock.rowsAffected === 0) return
+
+    await Actor.provide("system", { workspaceID: authInfo.workspaceID }, async () => {
+      await Billing.reload()
+    })
+  }
 }

+ 4 - 1
packages/console/app/src/routes/zen/v1/chat/completions.ts

@@ -5,6 +5,9 @@ type Usage = {
   prompt_tokens?: number
   completion_tokens?: number
   total_tokens?: number
+  // used by moonshot
+  cached_tokens?: number
+  // used by xai
   prompt_tokens_details?: {
     text_tokens?: number
     audio_tokens?: number
@@ -48,7 +51,7 @@ export function POST(input: APIEvent) {
       inputTokens: usage.prompt_tokens ?? 0,
       outputTokens: usage.completion_tokens ?? 0,
       reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? undefined,
-      cacheReadTokens: usage.prompt_tokens_details?.cached_tokens ?? undefined,
+      cacheReadTokens: usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined,
     }),
   })
 }

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

@@ -6,4 +6,4 @@
 /// <reference path="../../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 1 - 0
packages/console/core/migrations/0014_demonic_princess_powerful.sql

@@ -0,0 +1 @@
+ALTER TABLE `workspace` ADD `data_share` boolean;

+ 681 - 0
packages/console/core/migrations/meta/0014_snapshot.json

@@ -0,0 +1,681 @@
+{
+  "version": "5",
+  "dialect": "mysql",
+  "id": "12189a4e-5083-4b17-b8e3-8279c9a3e61a",
+  "prevId": "28336c91-553c-4d1d-9875-1ee761e47582",
+  "tables": {
+    "account": {
+      "name": "account",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "email": {
+          "name": "email",
+          "columns": [
+            "email"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "billing": {
+      "name": "billing",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_id": {
+          "name": "payment_method_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_last4": {
+          "name": "payment_method_last4",
+          "type": "varchar(4)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "balance": {
+          "name": "balance",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "monthly_limit": {
+          "name": "monthly_limit",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "monthly_usage": {
+          "name": "monthly_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_monthly_usage_updated": {
+          "name": "time_monthly_usage_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload": {
+          "name": "reload",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_error": {
+          "name": "reload_error",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_error": {
+          "name": "time_reload_error",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_locked_till": {
+          "name": "time_reload_locked_till",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_customer_id": {
+          "name": "global_customer_id",
+          "columns": [
+            "customer_id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "billing_workspace_id_id_pk": {
+          "name": "billing_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "payment": {
+      "name": "payment",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_id": {
+          "name": "payment_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "amount": {
+          "name": "amount",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "payment_workspace_id_id_pk": {
+          "name": "payment_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "usage": {
+      "name": "usage",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "input_tokens": {
+          "name": "input_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "output_tokens": {
+          "name": "output_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "reasoning_tokens": {
+          "name": "reasoning_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_read_tokens": {
+          "name": "cache_read_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_5m_tokens": {
+          "name": "cache_write_5m_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_1h_tokens": {
+          "name": "cache_write_1h_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cost": {
+          "name": "cost",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "usage_workspace_id_id_pk": {
+          "name": "usage_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "key": {
+      "name": "key",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "actor": {
+          "name": "actor",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "old_name": {
+          "name": "old_name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_used": {
+          "name": "time_used",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_key": {
+          "name": "global_key",
+          "columns": [
+            "key"
+          ],
+          "isUnique": true
+        },
+        "name": {
+          "name": "name",
+          "columns": [
+            "workspace_id",
+            "name"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "key_workspace_id_id_pk": {
+          "name": "key_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "user": {
+      "name": "user",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_seen": {
+          "name": "time_seen",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "color": {
+          "name": "color",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "user_email": {
+          "name": "user_email",
+          "columns": [
+            "workspace_id",
+            "email"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "user_workspace_id_id_pk": {
+          "name": "user_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "workspace": {
+      "name": "workspace",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "slug": {
+          "name": "slug",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "data_share": {
+          "name": "data_share",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "slug": {
+          "name": "slug",
+          "columns": [
+            "slug"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "workspace_id": {
+          "name": "workspace_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    }
+  },
+  "views": {},
+  "_meta": {
+    "schemas": {},
+    "tables": {},
+    "columns": {}
+  },
+  "internal": {
+    "tables": {},
+    "indexes": {}
+  }
+}

+ 8 - 1
packages/console/core/migrations/meta/_journal.json

@@ -99,6 +99,13 @@
       "when": 1757956978089,
       "tag": "0013_absurd_hobgoblin",
       "breakpoints": true
+    },
+    {
+      "idx": 14,
+      "version": "5",
+      "when": 1758289919722,
+      "tag": "0014_demonic_princess_powerful",
+      "breakpoints": true
     }
   ]
-}
+}

+ 2 - 1
packages/console/core/src/schema/workspace.sql.ts

@@ -1,4 +1,4 @@
-import { primaryKey, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
+import { primaryKey, mysqlTable, uniqueIndex, varchar, boolean } from "drizzle-orm/mysql-core"
 import { timestamps, ulid } from "../drizzle/types"
 
 export const WorkspaceTable = mysqlTable(
@@ -7,6 +7,7 @@ export const WorkspaceTable = mysqlTable(
     id: ulid("id").notNull().primaryKey(),
     slug: varchar("slug", { length: 255 }),
     name: varchar("name", { length: 255 }),
+    dataShare: boolean("data_share"),
     ...timestamps,
   },
   (table) => [uniqueIndex("slug").on(table.slug)],

+ 0 - 1
packages/console/core/src/workspace.ts

@@ -1,6 +1,5 @@
 import { z } from "zod"
 import { fn } from "./util/fn"
-import { centsToMicroCents } from "./util/price"
 import { Actor } from "./actor"
 import { Database, eq } from "./drizzle"
 import { Identifier } from "./identifier"

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

@@ -6,4 +6,4 @@
 /// <reference path="../../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 63 - 79
packages/console/function/sst-env.d.ts

@@ -6,91 +6,75 @@
 import "sst"
 declare module "sst" {
   export interface Resource {
-    ANTHROPIC_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    AUTH_API_URL: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    BASETEN_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    Console: {
-      type: "sst.cloudflare.SolidStart"
-      url: string
-    }
-    Database: {
-      database: string
-      host: string
-      password: string
-      port: number
-      type: "sst.sst.Linkable"
-      username: string
-    }
-    FIREWORKS_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_PRIVATE_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_ID_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_SECRET_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GOOGLE_CLIENT_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    HONEYCOMB_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    OPENAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_SECRET_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_WEBHOOK_SECRET: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    Web: {
-      type: "sst.cloudflare.Astro"
-      url: string
-    }
-    XAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "AUTH_API_URL": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Console": {
+      "type": "sst.cloudflare.SolidStart"
+      "url": string
+    }
+    "Database": {
+      "database": string
+      "host": string
+      "password": string
+      "port": number
+      "type": "sst.sst.Linkable"
+      "username": string
+    }
+    "GITHUB_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_APP_PRIVATE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_ID_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_SECRET_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GOOGLE_CLIENT_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "HONEYCOMB_API_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_SECRET_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_WEBHOOK_SECRET": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Web": {
+      "type": "sst.cloudflare.Astro"
+      "url": string
+    }
+    "ZEN_MODELS": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
   }
 }
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types"
+// cloudflare 
+import * as cloudflare from "@cloudflare/workers-types";
 declare module "sst" {
   export interface Resource {
-    Api: cloudflare.Service
-    AuthApi: cloudflare.Service
-    AuthStorage: cloudflare.KVNamespace
-    Bucket: cloudflare.R2Bucket
-    LogProcessor: cloudflare.Service
+    "Api": cloudflare.Service
+    "AuthApi": cloudflare.Service
+    "AuthStorage": cloudflare.KVNamespace
+    "Bucket": cloudflare.R2Bucket
+    "LogProcessor": cloudflare.Service
   }
 }
 
 import "sst"
-export {}
+export {}

+ 63 - 79
packages/console/resource/sst-env.d.ts

@@ -6,91 +6,75 @@
 import "sst"
 declare module "sst" {
   export interface Resource {
-    ANTHROPIC_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    AUTH_API_URL: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    BASETEN_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    Console: {
-      type: "sst.cloudflare.SolidStart"
-      url: string
-    }
-    Database: {
-      database: string
-      host: string
-      password: string
-      port: number
-      type: "sst.sst.Linkable"
-      username: string
-    }
-    FIREWORKS_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_PRIVATE_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_ID_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_SECRET_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GOOGLE_CLIENT_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    HONEYCOMB_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    OPENAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_SECRET_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_WEBHOOK_SECRET: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    Web: {
-      type: "sst.cloudflare.Astro"
-      url: string
-    }
-    XAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "AUTH_API_URL": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Console": {
+      "type": "sst.cloudflare.SolidStart"
+      "url": string
+    }
+    "Database": {
+      "database": string
+      "host": string
+      "password": string
+      "port": number
+      "type": "sst.sst.Linkable"
+      "username": string
+    }
+    "GITHUB_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_APP_PRIVATE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_ID_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_SECRET_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GOOGLE_CLIENT_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "HONEYCOMB_API_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_SECRET_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_WEBHOOK_SECRET": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Web": {
+      "type": "sst.cloudflare.Astro"
+      "url": string
+    }
+    "ZEN_MODELS": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
   }
 }
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types"
+// cloudflare 
+import * as cloudflare from "@cloudflare/workers-types";
 declare module "sst" {
   export interface Resource {
-    Api: cloudflare.Service
-    AuthApi: cloudflare.Service
-    AuthStorage: cloudflare.KVNamespace
-    Bucket: cloudflare.R2Bucket
-    LogProcessor: cloudflare.Service
+    "Api": cloudflare.Service
+    "AuthApi": cloudflare.Service
+    "AuthStorage": cloudflare.KVNamespace
+    "Bucket": cloudflare.R2Bucket
+    "LogProcessor": cloudflare.Service
   }
 }
 
 import "sst"
-export {}
+export {}

+ 1 - 1
packages/console/scripts/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 63 - 79
packages/function/sst-env.d.ts

@@ -6,91 +6,75 @@
 import "sst"
 declare module "sst" {
   export interface Resource {
-    ANTHROPIC_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    AUTH_API_URL: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    BASETEN_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    Console: {
-      type: "sst.cloudflare.SolidStart"
-      url: string
-    }
-    Database: {
-      database: string
-      host: string
-      password: string
-      port: number
-      type: "sst.sst.Linkable"
-      username: string
-    }
-    FIREWORKS_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_APP_PRIVATE_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_ID_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GITHUB_CLIENT_SECRET_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    GOOGLE_CLIENT_ID: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    HONEYCOMB_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    OPENAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_SECRET_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_WEBHOOK_SECRET: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    Web: {
-      type: "sst.cloudflare.Astro"
-      url: string
-    }
-    XAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "AUTH_API_URL": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Console": {
+      "type": "sst.cloudflare.SolidStart"
+      "url": string
+    }
+    "Database": {
+      "database": string
+      "host": string
+      "password": string
+      "port": number
+      "type": "sst.sst.Linkable"
+      "username": string
+    }
+    "GITHUB_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_APP_PRIVATE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_ID_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GITHUB_CLIENT_SECRET_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "GOOGLE_CLIENT_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "HONEYCOMB_API_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_SECRET_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "STRIPE_WEBHOOK_SECRET": {
+      "type": "sst.sst.Linkable"
+      "value": string
+    }
+    "Web": {
+      "type": "sst.cloudflare.Astro"
+      "url": string
+    }
+    "ZEN_MODELS": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
   }
 }
-// cloudflare
-import * as cloudflare from "@cloudflare/workers-types"
+// cloudflare 
+import * as cloudflare from "@cloudflare/workers-types";
 declare module "sst" {
   export interface Resource {
-    Api: cloudflare.Service
-    AuthApi: cloudflare.Service
-    AuthStorage: cloudflare.KVNamespace
-    Bucket: cloudflare.R2Bucket
-    LogProcessor: cloudflare.Service
+    "Api": cloudflare.Service
+    "AuthApi": cloudflare.Service
+    "AuthStorage": cloudflare.KVNamespace
+    "Bucket": cloudflare.R2Bucket
+    "LogProcessor": cloudflare.Service
   }
 }
 
 import "sst"
-export {}
+export {}

+ 1 - 1
packages/opencode/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 1 - 1
packages/plugin/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 1 - 1
packages/sdk/js/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 1 - 1
packages/web/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 1 - 1
sdks/vscode/sst-env.d.ts

@@ -6,4 +6,4 @@
 /// <reference path="../../sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}

+ 57 - 73
sst-env.d.ts

@@ -5,99 +5,83 @@
 
 declare module "sst" {
   export interface Resource {
-    ANTHROPIC_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "AUTH_API_URL": {
+      "type": "sst.sst.Linkable"
+      "value": string
     }
-    AUTH_API_URL: {
-      type: "sst.sst.Linkable"
-      value: string
+    "Api": {
+      "type": "sst.cloudflare.Worker"
+      "url": string
     }
-    Api: {
-      type: "sst.cloudflare.Worker"
-      url: string
+    "AuthApi": {
+      "type": "sst.cloudflare.Worker"
+      "url": string
     }
-    AuthApi: {
-      type: "sst.cloudflare.Worker"
-      url: string
+    "AuthStorage": {
+      "type": "sst.cloudflare.Kv"
     }
-    AuthStorage: {
-      type: "sst.cloudflare.Kv"
+    "Bucket": {
+      "name": string
+      "type": "sst.cloudflare.Bucket"
     }
-    BASETEN_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "Console": {
+      "type": "sst.cloudflare.SolidStart"
+      "url": string
     }
-    Bucket: {
-      name: string
-      type: "sst.cloudflare.Bucket"
+    "Database": {
+      "database": string
+      "host": string
+      "password": string
+      "port": number
+      "type": "sst.sst.Linkable"
+      "username": string
     }
-    Console: {
-      type: "sst.cloudflare.SolidStart"
-      url: string
+    "GITHUB_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    Database: {
-      database: string
-      host: string
-      password: string
-      port: number
-      type: "sst.sst.Linkable"
-      username: string
+    "GITHUB_APP_PRIVATE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    FIREWORKS_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "GITHUB_CLIENT_ID_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    GITHUB_APP_ID: {
-      type: "sst.sst.Secret"
-      value: string
+    "GITHUB_CLIENT_SECRET_CONSOLE": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    GITHUB_APP_PRIVATE_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "GOOGLE_CLIENT_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    GITHUB_CLIENT_ID_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
+    "HONEYCOMB_API_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    GITHUB_CLIENT_SECRET_CONSOLE: {
-      type: "sst.sst.Secret"
-      value: string
+    "LogProcessor": {
+      "type": "sst.cloudflare.Worker"
     }
-    GOOGLE_CLIENT_ID: {
-      type: "sst.sst.Secret"
-      value: string
+    "STRIPE_SECRET_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
-    HONEYCOMB_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "STRIPE_WEBHOOK_SECRET": {
+      "type": "sst.sst.Linkable"
+      "value": string
     }
-    LogProcessor: {
-      type: "sst.cloudflare.Worker"
+    "Web": {
+      "type": "sst.cloudflare.Astro"
+      "url": string
     }
-    OPENAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_SECRET_KEY: {
-      type: "sst.sst.Secret"
-      value: string
-    }
-    STRIPE_WEBHOOK_SECRET: {
-      type: "sst.sst.Linkable"
-      value: string
-    }
-    Web: {
-      type: "sst.cloudflare.Astro"
-      url: string
-    }
-    XAI_API_KEY: {
-      type: "sst.sst.Secret"
-      value: string
+    "ZEN_MODELS": {
+      "type": "sst.sst.Secret"
+      "value": string
     }
   }
 }
 /// <reference path="sst-env.d.ts" />
 
 import "sst"
-export {}
+export {}