From c86f9dfdc20f6343f73a82235b5caa321e742c4f Mon Sep 17 00:00:00 2001 From: Fini Date: Tue, 21 Apr 2026 00:35:07 +0800 Subject: [PATCH] fix(ai): rename element-tools flag to VITE_ENABLE_ELEMENT_TOOLS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Browser-side helper (`isElementToolsFlagEnabled` in model-profiles.ts) reads via `import.meta.env` as the client fallback, but Vite's default `envPrefix` only exposes `VITE_`-prefixed variables to the browser bundle. The previous name `ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR` would be inlined as `undefined` at build time for client code — meaning flipping the flag in `.env.local` could NEVER actually enable the feature from the embedded orchestrator, defeating the Phase 2 rollout plan. Rename to `VITE_ENABLE_ELEMENT_TOOLS` so client code can actually see the toggle. Server-side `process.env` reads work with any name, so one variable name now covers both sides of the SSR boundary. Docstring in model-profiles.ts now explicitly calls out the VITE_ prefix requirement so future edits don't regress — the "bare name would be inlined as undefined" point is worth preserving in-file. Also updated the orchestrator-sub-agent.ts error message that points users at the flag so its instructions match the real var name. Tests: 23 → 23 (renamed FLAG constant, all cases still pass). Full suite 1866/1866 green. --- .../ai/__tests__/model-profiles-element-tools.test.ts | 4 ++-- apps/web/src/services/ai/model-profiles.ts | 11 ++++++++++- apps/web/src/services/ai/orchestrator-sub-agent.ts | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/web/src/services/ai/__tests__/model-profiles-element-tools.test.ts b/apps/web/src/services/ai/__tests__/model-profiles-element-tools.test.ts index f2b988665..adb1280d7 100644 --- a/apps/web/src/services/ai/__tests__/model-profiles-element-tools.test.ts +++ b/apps/web/src/services/ai/__tests__/model-profiles-element-tools.test.ts @@ -8,7 +8,7 @@ import type { ModelProfile } from '../model-profiles'; * Contract (per plan §3.1 — openpencil-docs * superpowers/plans/2026-04-21-element-tools-orchestrator-integration.md): * needsElementTools(p) === true - * iff ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR env var is truthy + * iff VITE_ENABLE_ELEMENT_TOOLS env var is truthy * AND p.tier is 'basic' or 'standard' * * Why the tier gate: A/B v1 showed ceiling regression on the one @@ -17,7 +17,7 @@ import type { ModelProfile } from '../model-profiles'; * by default even when the global flag is on. */ -const FLAG = 'ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR'; +const FLAG = 'VITE_ENABLE_ELEMENT_TOOLS'; function profile(tier: ModelProfile['tier']): ModelProfile { return { match: '', tier, label: `Test ${tier}` }; diff --git a/apps/web/src/services/ai/model-profiles.ts b/apps/web/src/services/ai/model-profiles.ts index 816b876f0..987ccc5f4 100644 --- a/apps/web/src/services/ai/model-profiles.ts +++ b/apps/web/src/services/ai/model-profiles.ts @@ -110,13 +110,22 @@ export function needsSimplifiedPrompt(profile: ModelProfile): boolean { * unchanged until the flag is explicitly flipped. Any truthy value * (`"1"`, `"true"`, `"yes"`, case-insensitive) enables the feature. * + * Name MUST start with `VITE_` — the sub-agent that reads this helper + * runs inside the Vite browser bundle, and Vite's default `envPrefix` + * only exposes `VITE_`-prefixed variables to `import.meta.env`. A + * bare name (e.g. `ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR`) would be + * inlined as `undefined` at build time for the client, silently + * defeating the rollout flip. Server-side `process.env` reads work + * fine with any name, so this dual-compatible name is an alias that + * functions on both sides of the SSR boundary. + * * Rollout per plan §4 (openpencil-docs * superpowers/plans/2026-04-21-element-tools-orchestrator-integration.md): * Phase 1: ship with flag off (scaffolding only, zero behavior change) * Phase 2: flip on for basic + standard tiers in a canary env * Phase 3: remove the flag once stable across a monitoring window */ -const ELEMENT_TOOLS_FLAG_ENV = 'ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR'; +const ELEMENT_TOOLS_FLAG_ENV = 'VITE_ENABLE_ELEMENT_TOOLS'; /** * Read the element-tools feature flag from env in a way that's safe diff --git a/apps/web/src/services/ai/orchestrator-sub-agent.ts b/apps/web/src/services/ai/orchestrator-sub-agent.ts index e88359001..6be893ab1 100644 --- a/apps/web/src/services/ai/orchestrator-sub-agent.ts +++ b/apps/web/src/services/ai/orchestrator-sub-agent.ts @@ -363,7 +363,7 @@ async function executeSubAgent( const hasDesignMdContent = designMdContent.length > 0; // Feature-flagged gate for N-tool element-surface integration. - // Only fires when ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR env var is + // Only fires when VITE_ENABLE_ELEMENT_TOOLS env var is // truthy AND the model is in the basic/standard tier; full-tier // models stay on the legacy path per A/B v1 ceiling-effect finding // (Kimi K2.5 Δ M1 -12.5pp). Default production state is off, so @@ -517,8 +517,8 @@ async function executeSubAgent( error: `Element-tool output detected (${detectedName}) but the ` + `apply pipeline is not yet wired into the embedded ` + - `orchestrator. Set ENABLE_ELEMENT_TOOLS_IN_ORCHESTRATOR=0 ` + - `to fall back to the legacy JSONL path, or wait for ` + + `orchestrator. Unset VITE_ENABLE_ELEMENT_TOOLS (or set ` + + `it to 0) to fall back to the legacy JSONL path, or wait for ` + `integration plan §3.5 (openpencil-docs ` + `superpowers/plans/2026-04-21-element-tools-orchestrator-integration.md).`, };