LLM: keep API key in localStorage only, default to muse-spark-1.3
Secrets must never be baked into the static build. Stop reading VITE_AI_API_KEY from env — key comes only from localStorage via the ⚙️ config dialog (flow-state:llm). Gateway URL / model may still come from env as non-secret defaults. - src/llm/config.js: DEFAULTS model → meta/muse-spark-1.3-contributor (cheap, per user request), readEnv no longer touches apiKey, getLlmConfig resolves key only from stored.apiKey. - .env.example: drop VITE_AI_API_KEY=, document browser-only key flow. - src/main.js: dialog copy now says key is browser-only, never baked. Build + lint:scenes + tests still green. No VITE_AI_API_KEY string remains in source. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
// LLM gateway config — localStorage overrides > VITE env > defaults.
|
||||
// LLM gateway config — localStorage for the secret, env only for non-secrets.
|
||||
//
|
||||
// The app is a static Vite site with no server; the gateway credential lives
|
||||
// in the browser. Never commit a key — paste it in the panel (→ localStorage)
|
||||
// or in an untracked .env.local.
|
||||
// The app is a static Vite site with no server. The API key is a secret and
|
||||
// must never be baked into the build — it lives only in the browser's
|
||||
// localStorage (→ ⚙️ dialog). Gateway URL and model are non-secret and may
|
||||
// come from VITE env as defaults with a localStorage override; the key never
|
||||
// does.
|
||||
|
||||
const STORAGE_KEY = 'flow-state:llm';
|
||||
|
||||
const DEFAULTS = {
|
||||
gatewayUrl: 'https://ai-gateway.vercel.sh/v1',
|
||||
model: 'openai/gpt-4o-mini',
|
||||
model: 'meta/muse-spark-1.3-contributor',
|
||||
apiKey: '',
|
||||
};
|
||||
|
||||
@@ -18,10 +20,10 @@ function readEnv() {
|
||||
return {
|
||||
gatewayUrl: env.VITE_AI_GATEWAY_URL || null,
|
||||
model: env.VITE_AI_MODEL || null,
|
||||
apiKey: env.VITE_AI_API_KEY || null,
|
||||
// apiKey intentionally NOT read from env — see module comment.
|
||||
};
|
||||
} catch {
|
||||
return { gatewayUrl: null, model: null, apiKey: null };
|
||||
return { gatewayUrl: null, model: null };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,14 +38,13 @@ function readStorage() {
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolved config — localStorage wins, then env, then defaults. */
|
||||
/** Resolved config — key from localStorage only (never env); URL/model from localStorage > env > defaults. */
|
||||
export function getLlmConfig() {
|
||||
const env = readEnv();
|
||||
const stored = readStorage();
|
||||
const gatewayUrl = stored.gatewayUrl || env.gatewayUrl || DEFAULTS.gatewayUrl;
|
||||
const model = stored.model || env.model || DEFAULTS.model;
|
||||
const apiKey = stored.apiKey != null ? stored.apiKey : (env.apiKey != null ? env.apiKey : DEFAULTS.apiKey);
|
||||
const key = typeof apiKey === 'string' ? apiKey.trim() : '';
|
||||
const key = typeof stored.apiKey === 'string' ? stored.apiKey.trim() : '';
|
||||
return {
|
||||
gatewayUrl: String(gatewayUrl || DEFAULTS.gatewayUrl).trim() || DEFAULTS.gatewayUrl,
|
||||
model: String(model || DEFAULTS.model).trim() || DEFAULTS.model,
|
||||
|
||||
Reference in New Issue
Block a user