personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add cogitate auth mode toggle to settings UI

Expose the providers.auth config through the settings API and add a
per-provider dropdown in the cogitate section. Users can choose between
platform account auth (default, CLI's own login) and API key auth.
The key warning is suppressed when platform auth is active since
no API key is needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+95 -6
+41
apps/settings/routes.py
··· 255 255 - context_defaults: Context registry with labels/groups for UI 256 256 (includes muse configs with type, schedule, disabled, extract) 257 257 - api_keys: Boolean status for each provider's API key 258 + - auth: Per-provider auth mode for cogitate ("platform" or "api_key") 258 259 """ 259 260 try: 260 261 from think.models import ( ··· 324 325 env_key = p.get("env_key", "") 325 326 api_keys[p["name"]] = bool(os.getenv(env_key)) if env_key else False 326 327 328 + # Build auth settings (default "platform" for all providers) 329 + auth_config = providers_config.get("auth", {}) 330 + auth = {p["name"]: auth_config.get(p["name"], "platform") for p in providers_list} 331 + 327 332 return jsonify( 328 333 { 329 334 "providers": providers_list, ··· 332 337 "contexts": contexts, 333 338 "context_defaults": context_defaults, 334 339 "api_keys": api_keys, 340 + "auth": auth, 335 341 } 336 342 ) 337 343 except Exception as e: ··· 345 351 Accepts JSON with optional keys: 346 352 - generate: {provider?, tier?, backup?} - Set generate defaults 347 353 - cogitate: {provider?, tier?, backup?} - Set cogitate defaults 354 + - auth: {provider: "platform"|"api_key"} - Cogitate CLI auth mode 348 355 - contexts: {pattern: {provider?, tier?, disabled?, extract?} | null} 349 356 Set or clear context overrides 350 357 ··· 439 446 "new": backup, 440 447 } 441 448 config["providers"][agent_type]["backup"] = backup 449 + 450 + # Handle auth mode updates 451 + if "auth" in request_data: 452 + auth_data = request_data["auth"] 453 + if not isinstance(auth_data, dict): 454 + return jsonify({"error": "auth must be an object"}), 400 455 + 456 + if "auth" not in config["providers"]: 457 + config["providers"]["auth"] = {} 458 + 459 + old_auth = old_providers.get("auth", {}) 460 + 461 + for provider, mode in auth_data.items(): 462 + if provider not in PROVIDER_REGISTRY: 463 + return ( 464 + jsonify({"error": f"Invalid provider in auth: {provider}"}), 465 + 400, 466 + ) 467 + if mode not in ("platform", "api_key"): 468 + return ( 469 + jsonify( 470 + { 471 + "error": f"Invalid auth mode: {mode}. " 472 + "Must be 'platform' or 'api_key'." 473 + } 474 + ), 475 + 400, 476 + ) 477 + if old_auth.get(provider) != mode: 478 + changed_fields[f"auth.{provider}"] = { 479 + "old": old_auth.get(provider, "platform"), 480 + "new": mode, 481 + } 482 + config["providers"]["auth"][provider] = mode 442 483 443 484 # Handle context overrides 444 485 if "contexts" in request_data:
+54 -6
apps/settings/workspace.html
··· 1724 1724 <small></small> 1725 1725 </div> 1726 1726 </div> 1727 + <div class="provider-row" style="max-width:16em"> 1728 + <div class="settings-field"> 1729 + <label for="field-cogitate-auth">Auth</label> 1730 + <select id="field-cogitate-auth"> 1731 + <option value="platform">Platform Account</option> 1732 + <option value="api_key">API Key</option> 1733 + </select> 1734 + <small>How the CLI authenticates with the provider</small> 1735 + </div> 1736 + </div> 1727 1737 <div id="cogitateProviderKeyWarning" class="provider-key-warning" style="display:none"> 1728 1738 <span>&#9888;</span> 1729 1739 <span>API key not configured for cogitate provider.</span> ··· 2965 2975 document.getElementById(`field-${type}-backup`).value = typeData.backup || ''; 2966 2976 2967 2977 // Update key warnings 2968 - updateTypeProviderKeyWarning(type, typeData.provider, data.api_keys); 2978 + updateTypeProviderKeyWarning(type, typeData.provider, data.api_keys, data.auth); 2979 + } 2980 + 2981 + // Set cogitate auth mode from API response 2982 + const cogitateProvider = (data.cogitate || {}).provider || ''; 2983 + const authSelect = document.getElementById('field-cogitate-auth'); 2984 + if (authSelect && data.auth) { 2985 + authSelect.value = data.auth[cogitateProvider] || 'platform'; 2969 2986 } 2970 2987 2971 2988 // Update status text ··· 2975 2992 renderContextGroups(data); 2976 2993 } 2977 2994 2978 - function updateTypeProviderKeyWarning(type, provider, apiKeys) { 2995 + function updateTypeProviderKeyWarning(type, provider, apiKeys, auth) { 2979 2996 const warning = document.getElementById(`${type}ProviderKeyWarning`); 2980 2997 const link = document.getElementById(`${type}ProviderKeyLink`); 2981 2998 if (!warning || !link) return; 2982 2999 2983 - if (provider && !apiKeys[provider]) { 3000 + // For cogitate, hide key warning when using platform auth 3001 + const authMode = (auth && type === 'cogitate') ? (auth[provider] || 'platform') : 'api_key'; 3002 + if (authMode === 'platform' || !provider || apiKeys[provider]) { 3003 + warning.style.display = 'none'; 3004 + } else { 2984 3005 warning.style.display = 'flex'; 2985 3006 link.onclick = (e) => { 2986 3007 e.preventDefault(); 2987 3008 switchSection('apikeys'); 2988 3009 }; 2989 - } else { 2990 - warning.style.display = 'none'; 2991 3010 } 2992 3011 } 2993 3012 ··· 3165 3184 3166 3185 providersData = result; 3167 3186 if (field === 'provider') { 3168 - updateTypeProviderKeyWarning(type, value, result.api_keys); 3187 + updateTypeProviderKeyWarning(type, value, result.api_keys, result.auth); 3188 + // Update cogitate auth select when provider changes 3189 + if (type === 'cogitate') { 3190 + const authSelect = document.getElementById('field-cogitate-auth'); 3191 + if (authSelect && result.auth) { 3192 + authSelect.value = result.auth[value] || 'platform'; 3193 + } 3194 + } 3169 3195 } 3170 3196 showFieldStatus(el, 'saved'); 3171 3197 } catch (err) { ··· 3175 3201 }); 3176 3202 } 3177 3203 } 3204 + 3205 + // Cogitate auth mode change handler 3206 + document.getElementById('field-cogitate-auth')?.addEventListener('change', async function() { 3207 + const authSelect = this; 3208 + const provider = document.getElementById('field-cogitate-provider')?.value; 3209 + if (!provider) return; 3210 + try { 3211 + const response = await fetch('api/providers', { 3212 + method: 'PUT', 3213 + headers: { 'Content-Type': 'application/json' }, 3214 + body: JSON.stringify({ auth: { [provider]: authSelect.value } }) 3215 + }); 3216 + const result = await response.json(); 3217 + if (result.error) throw new Error(result.error); 3218 + providersData = result; 3219 + updateTypeProviderKeyWarning('cogitate', provider, result.api_keys, result.auth); 3220 + showFieldStatus(authSelect, 'saved'); 3221 + } catch (err) { 3222 + console.error('Error saving cogitate auth:', err); 3223 + showFieldStatus(authSelect, 'error', err.message); 3224 + } 3225 + }); 3178 3226 3179 3227 // ========== TRANSCRIPTION ========== 3180 3228 // Backend metadata loaded from API