From 81068977ffcfe3b88fea63a50468401e4f0efb40 Mon Sep 17 00:00:00 2001
From: Mantra <87142457+mantrakp04@users.noreply.github.com>
Date: Wed, 17 Jun 2026 15:38:28 -0700
Subject: [PATCH] fix: update AI model selection matrix and custom dashboard
generation (#1615)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What
Refresh the AI model selection matrix and fix a few issues in custom
dashboard generation.
### Models (`apps/backend/src/lib/ai/models.ts`)
- Replace deprecated/placeholder model IDs with current ones:
- `smart/slow` authenticated → `openai/gpt-5.5` (was
`x-ai/grok-build-0.1`)
- `smart/fast` → `google/gemini-3.5-flash`
- `smartest` unauthenticated tiers → `z-ai/glm-5.2` /
`google/gemini-3.5-flash` (was `deepseek/deepseek-v4-flash`)
- `dumb` unauthenticated tiers → `nvidia/nemotron-3-super-120b-a12b`
### Email template rewrite
- Forward `x-stack-*` / `x-hexclave-*` headers from the caller through
the template-source rewrite route so the inner AI call
(`/ai/query/generate`) is authenticated and resolves to the
**authenticated** model tier instead of falling back to the
unauthenticated one.
- Lower rewrite quality to `dumb` / `slow` (sufficient for this task,
cheaper/faster).
### Custom dashboard
- Speed up generation: `smart`/**fast** instead of `smart`/slow (both
`create-dashboard-preview.tsx` and `chat-adapters.ts`).
- Pin `@babel/standalone` to `7.29.7` in the sandbox host (avoid
surprise breakage from `latest`).
- Disable analytics in generated dashboards.
### Misc
- Bump MCP RPC timeout 15s → 45s (`apps/skills/src/mcp-wrapper.ts`).
## Testing
- `pnpm typecheck` ✅
- `pnpm lint` ✅
---
## Summary by cubic
Refreshes the model selection matrix, forwards auth headers so template
rewrites use authenticated tiers, and speeds up custom dashboard
generation with a more stable sandbox.
- **Refactors**
- Update model IDs: `openai/gpt-5.5`, `google/gemini-3.5-flash`,
`z-ai/glm-5.2`, `nvidia/nemotron-3-super-120b-a12b`.
- Use `openai/gpt-5.5` for authenticated fast routes.
- Forward `x-stack-*` / `x-hexclave-*` headers; build via Map to avoid
prototype-pollution; inner generate call uses the authenticated tier.
- Lower email template rewrite quality to `dumb`/`slow`.
- Switch dashboard generation to `smart`/`fast` in
`create-dashboard-preview.tsx` and `chat-adapters.ts`.
- Disable analytics in generated dashboards.
- Bump MCP RPC timeout from 15s to 45s.
- **Dependencies**
- Pin `@babel/standalone` to `7.29.7` in the sandbox host.
Written for commit 94354ae0f6050fae88abd286b1be768e67338152.
Summary will update on new commits.
## Summary by CodeRabbit
## Release Notes
* **Performance**
* Improved AI generation speed for dashboard creation and related chat
flows by using faster AI routing.
* Increased MCP JSON-RPC request timeout to better handle long-running
operations.
* **Technical**
* Template rewriting with AI now forwards authentication-related headers
to downstream AI calls for more consistent authorized behavior.
* Updated AI model routing/selection used by the proxy layer.
* **UI/Integration**
* Pinned the sandbox Babel CDN script to a specific version.
* Disabled analytics in the sandbox SDK configuration.
---
.../internal/rewrite-template-source/route.tsx | 18 ++++++++++++++++--
apps/backend/src/lib/ai/models.ts | 16 ++++++++--------
apps/backend/src/lib/email-template-rewrite.ts | 10 +++++-----
.../create-dashboard-preview.tsx | 2 +-
.../dashboard-sandbox-host.tsx | 8 ++------
.../components/vibe-coding/chat-adapters.ts | 2 +-
apps/skills/src/mcp-wrapper.ts | 2 +-
7 files changed, 34 insertions(+), 24 deletions(-)
diff --git a/apps/backend/src/app/api/latest/internal/rewrite-template-source/route.tsx b/apps/backend/src/app/api/latest/internal/rewrite-template-source/route.tsx
index a81283f92..93bec5d7f 100644
--- a/apps/backend/src/app/api/latest/internal/rewrite-template-source/route.tsx
+++ b/apps/backend/src/app/api/latest/internal/rewrite-template-source/route.tsx
@@ -26,8 +26,22 @@ export const POST = createSmartRouteHandler({
tsx_source: yupString().defined(),
}).defined(),
}),
- handler: async ({ body }) => {
- const rewriteResult = await rewriteTemplateSourceWithAI(body.template_tsx_source);
+ handler: async ({ body }, fullReq) => {
+ // Forward the caller's Hexclave/Stack auth headers so the inner AI call
+ // (which is a fresh HTTP request to /ai/query/generate) is authenticated
+ // and resolves to the authenticated model tier rather than falling back
+ // to the unauthenticated one.
+ const authHeadersMap = new Map();
+ for (const [key, value] of Object.entries(fullReq.headers)) {
+ if (value == null) continue;
+ const lower = key.toLowerCase();
+ if (lower.startsWith("x-stack-") || lower.startsWith("x-hexclave-")) {
+ authHeadersMap.set(key, value.join(","));
+ }
+ }
+ const authHeaders: Record = Object.fromEntries(authHeadersMap);
+
+ const rewriteResult = await rewriteTemplateSourceWithAI(body.template_tsx_source, authHeaders);
if (rewriteResult.status === "error") {
throw new KnownErrors.TemplateSourceRewriteError(rewriteResult.error);
}
diff --git a/apps/backend/src/lib/ai/models.ts b/apps/backend/src/lib/ai/models.ts
index 4cc5ea15d..69c58eaf6 100644
--- a/apps/backend/src/lib/ai/models.ts
+++ b/apps/backend/src/lib/ai/models.ts
@@ -19,31 +19,31 @@ const MODEL_SELECTION_MATRIX: Record<
dumb: {
slow: {
authenticated: { modelId: "z-ai/glm-4.5-air:free" },
- unauthenticated: { modelId: "z-ai/glm-4.5-air:free" },
+ unauthenticated: { modelId: "nvidia/nemotron-3-super-120b-a12b" },
},
fast: {
authenticated: { modelId: "openai/gpt-oss-120b:nitro" },
- unauthenticated: { modelId: "openai/gpt-oss-120b:nitro" },
+ unauthenticated: { modelId: "nvidia/nemotron-3-super-120b-a12b:nitro" },
},
},
smart: {
slow: {
- authenticated: { modelId: "x-ai/grok-build-0.1" },
- unauthenticated: { modelId: "deepseek/deepseek-v4-flash" },
+ authenticated: { modelId: "openai/gpt-5.5" },
+ unauthenticated: { modelId: "z-ai/glm-5.2" },
},
fast: {
- authenticated: { modelId: "x-ai/grok-build-0.1" },
- unauthenticated: { modelId: "nvidia/nemotron-3-super-120b-a12b:nitro" },
+ authenticated: { modelId: "openai/gpt-5.5" },
+ unauthenticated: { modelId: "google/gemini-3.5-flash" },
},
},
smartest: {
slow: {
authenticated: { modelId: "openai/gpt-5.5" },
- unauthenticated: { modelId: "deepseek/deepseek-v4-flash" },
+ unauthenticated: { modelId: "z-ai/glm-5.2" },
},
fast: {
authenticated: { modelId: "openai/gpt-5.5" },
- unauthenticated: { modelId: "deepseek/deepseek-v4-flash:nitro" },
+ unauthenticated: { modelId: "google/gemini-3.5-flash" },
},
},
};
diff --git a/apps/backend/src/lib/email-template-rewrite.ts b/apps/backend/src/lib/email-template-rewrite.ts
index 621391462..fc9d14102 100644
--- a/apps/backend/src/lib/email-template-rewrite.ts
+++ b/apps/backend/src/lib/email-template-rewrite.ts
@@ -13,16 +13,16 @@ function isMockMode() {
return key === MOCK_API_KEY_SENTINEL || key === "FORWARD_TO_PRODUCTION";
}
-async function rewriteTemplateSourceWithCurrentAIPlumbing(templateTsxSource: string): Promise> {
+async function rewriteTemplateSourceWithCurrentAIPlumbing(templateTsxSource: string, authHeaders: Record): Promise> {
const backendUrl = getEnvVariable("NEXT_PUBLIC_STACK_API_URL");
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), AI_REQUEST_TIMEOUT_MS);
try {
const response = await fetch(`${backendUrl}/api/latest/ai/query/generate`, {
method: "POST",
- headers: { "content-type": "application/json" },
+ headers: { "content-type": "application/json", ...authHeaders },
body: JSON.stringify({
- quality: "smart",
+ quality: "dumb",
speed: "slow",
tools: [],
systemPrompt: "rewrite-template-source",
@@ -115,7 +115,7 @@ function stripCodeFences(text: string): string {
return output;
}
-export async function rewriteTemplateSourceWithAI(templateTsxSource: string): Promise> {
+export async function rewriteTemplateSourceWithAI(templateTsxSource: string, authHeaders: Record): Promise> {
if (isMockMode()) {
const mockRewrittenSource = rewriteTemplateSourceInMockMode(templateTsxSource);
const mockRenderResult = await renderEmailWithTemplate(mockRewrittenSource, emptyEmailTheme, {
@@ -130,7 +130,7 @@ export async function rewriteTemplateSourceWithAI(templateTsxSource: string): Pr
let lastError = "Unknown rewrite failure";
for (let attempt = 0; attempt < MAX_REWRITE_ATTEMPTS; attempt++) {
- const rewriteResult = await rewriteTemplateSourceWithCurrentAIPlumbing(templateTsxSource);
+ const rewriteResult = await rewriteTemplateSourceWithCurrentAIPlumbing(templateTsxSource, authHeaders);
if (rewriteResult.status === "error") {
lastError = rewriteResult.error;
continue;
diff --git a/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx b/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx
index 54df195af..d697c1701 100644
--- a/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx
+++ b/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx
@@ -124,7 +124,7 @@ const CreateDashboardPreviewInner = memo(function CreateDashboardPreviewInner({
systemPrompt: "create-dashboard",
tools: ["update-dashboard"],
quality: "smart",
- speed: "slow",
+ speed: "fast",
projectId: projectIdRef.current,
transformMessages: async (userMessages) => {
const contextMessages = await buildDashboardMessages(
diff --git a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx
index 48cfe9214..0867a667d 100644
--- a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx
+++ b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx
@@ -333,12 +333,7 @@ function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashbo
-
-
-
+