From aa6aae4590d1fcb9a04c6b328d94d8a20c6891f1 Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 17 Jun 2026 15:23:30 -0700 Subject: [PATCH 1/2] Update OpenAPI specs --- docs-mintlify/openapi/admin.json | 12 +++++++++++- docs-mintlify/openapi/server.json | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/docs-mintlify/openapi/admin.json b/docs-mintlify/openapi/admin.json index e7cc3fb27..d577870a2 100644 --- a/docs-mintlify/openapi/admin.json +++ b/docs-mintlify/openapi/admin.json @@ -2713,7 +2713,7 @@ "/emails/outbox": { "get": { "summary": "List email outbox", - "description": "Lists all emails in the outbox with optional filtering by status or simple_status.", + "description": "Lists all emails in the outbox with optional filtering by status, simple_status, or user_id.", "parameters": [ { "name": "status", @@ -2731,6 +2731,16 @@ }, "required": false }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "description": "Filter for emails whose recipient is the given user ID." + }, + "description": "Filter for emails whose recipient is the given user ID.", + "required": false + }, { "name": "limit", "in": "query", diff --git a/docs-mintlify/openapi/server.json b/docs-mintlify/openapi/server.json index 1f7f292c3..645cdce0c 100644 --- a/docs-mintlify/openapi/server.json +++ b/docs-mintlify/openapi/server.json @@ -2713,7 +2713,7 @@ "/emails/outbox": { "get": { "summary": "List email outbox", - "description": "Lists all emails in the outbox with optional filtering by status or simple_status.", + "description": "Lists all emails in the outbox with optional filtering by status, simple_status, or user_id.", "parameters": [ { "name": "status", @@ -2731,6 +2731,16 @@ }, "required": false }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "description": "Filter for emails whose recipient is the given user ID." + }, + "description": "Filter for emails whose recipient is the given user ID.", + "required": false + }, { "name": "limit", "in": "query", 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 2/2] 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. Review in cubic ## 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
- - - +