fix: ai — per-provider API keys (remove shared AI_API_KEY)
gates / consistency-and-conventions (push) Failing after 11s

Each provider now has its own key: AI_GEMINI_API_KEY and OPENROUTER_API_KEY.
No more shared AI_API_KEY that caused cross-provider key leakage (gemini
getting openrouter key → 400 error). resolve_key() sets AI_API_KEY internally
from the active provider's key for adapter use. Config UI shows both keys.
This commit is contained in:
Your Name
2026-08-26 02:36:48 -04:00
parent 88ea660891
commit 7ae2e77a44
2 changed files with 23 additions and 31 deletions
+11 -22
View File
@@ -3,7 +3,7 @@ set -euo pipefail
# POS: ai ask — AI assistant: ask, chat, sessions, capture, models, providers # POS: ai ask — AI assistant: ask, chat, sessions, capture, models, providers
# POS_SUBCMDS: ask chat sessions capture models providers # POS_SUBCMDS: ask chat sessions capture models providers
# POS_FLAGS: --provider --model --session --system --full --last # POS_FLAGS: --provider --model --session --system --full --last
# POS_CONFIG: ai | ai.env | AI_PROVIDER=:Provider (gemini or openrouter, default gemini) | AI_API_KEY=secret:API key for the active provider | AI_MODEL=:Model id (default per provider) | AI_SYSTEM_PROMPT=:Custom system prompt (overrides built-in, empty to reset) # POS_CONFIG: ai | ai.env | AI_PROVIDER=:Provider (gemini or openrouter, default gemini) | AI_GEMINI_API_KEY=secret:Gemini API key from aistudio.google.com | OPENROUTER_API_KEY=secret:OpenRouter API key from openrouter.ai | AI_MODEL=:Model id (default per provider) | AI_SYSTEM_PROMPT=:Custom system prompt (overrides built-in, empty to reset)
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
@@ -76,12 +76,10 @@ Options:
Config: $CONFIG_FILE (edit with 'pos config ai') Config: $CONFIG_FILE (edit with 'pos config ai')
AI_PROVIDER Provider to use (gemini|openrouter, default gemini) AI_PROVIDER Provider to use (gemini|openrouter, default gemini)
AI_API_KEY API key for the active provider (secret) AI_GEMINI_API_KEY Gemini API key from aistudio.google.com
OPENROUTER_API_KEY OpenRouter API key from openrouter.ai
AI_MODEL Model id (default depends on provider) AI_MODEL Model id (default depends on provider)
AI_SYSTEM_PROMPT Custom system prompt (overrides built-in; empty to reset) AI_SYSTEM_PROMPT Custom system prompt (overrides built-in; empty to reset)
AI_GEMINI_API_KEY Legacy: Gemini API key fallback
AI_GEMINI_MODEL Legacy: Gemini model fallback
OPENROUTER_API_KEY Legacy: OpenRouter API key fallback
OPENROUTER_MODEL Legacy: OpenRouter model fallback OPENROUTER_MODEL Legacy: OpenRouter model fallback
Notes: Notes:
@@ -164,16 +162,11 @@ load_config() {
resolve_key() { resolve_key() {
load_config load_config
local p="${PROVIDER:-gemini}" local p="${PROVIDER:-gemini}"
# 1. Unified AI_API_KEY # Each provider has its own API key — set AI_API_KEY internally for adapters
if [ -n "${AI_API_KEY:-}" ]; then
return 0
fi
# 2. Provider-specific fallback
case "$p" in case "$p" in
gemini) [ -n "${AI_GEMINI_API_KEY:-}" ] && export AI_API_KEY="$AI_GEMINI_API_KEY" && return 0 ;; gemini) [ -n "${AI_GEMINI_API_KEY:-}" ] && export AI_API_KEY="$AI_GEMINI_API_KEY" && return 0 ;;
openrouter) [ -n "${OPENROUTER_API_KEY:-}" ] && export AI_API_KEY="$OPENROUTER_API_KEY" && return 0 ;; openrouter) [ -n "${OPENROUTER_API_KEY:-}" ] && export AI_API_KEY="$OPENROUTER_API_KEY" && return 0 ;;
esac esac
# 3. No key found — return 1 (require_key handles the error message)
return 1 return 1
} }
@@ -181,10 +174,10 @@ require_key() {
if ! resolve_key >/dev/null 2>&1; then if ! resolve_key >/dev/null 2>&1; then
local p="${PROVIDER:-gemini}" local p="${PROVIDER:-gemini}"
case "$p" in case "$p" in
gemini) err "No Gemini API key — run 'pos config ai' or set AI_API_KEY / AI_GEMINI_API_KEY" ;; gemini) err "No Gemini API key — run 'pos config ai' and set AI_GEMINI_API_KEY" ;;
openrouter) err "No OpenRouter API key — run 'pos config ai' or set AI_API_KEY / OPENROUTER_API_KEY" ;; openrouter) err "No OpenRouter API key — run 'pos config ai' and set OPENROUTER_API_KEY" ;;
esac esac
err "No API key for provider '$p' — run 'pos config ai' or set AI_API_KEY" err "No API key for provider '$p' — run 'pos config ai'"
fi fi
} }
@@ -569,14 +562,10 @@ cmd_providers() {
[ -n "$pmodel" ] || pmodel="unknown" [ -n "$pmodel" ] || pmodel="unknown"
# Check if API key exists for this provider # Check if API key exists for this provider
configured="not configured" configured="not configured"
if [ -n "${AI_API_KEY:-}" ]; then case "$name" in
configured="configured" gemini) [ -n "${AI_GEMINI_API_KEY:-}" ] && configured="configured" ;;
else openrouter) [ -n "${OPENROUTER_API_KEY:-}" ] && configured="configured" ;;
case "$name" in esac
gemini) [ -n "${AI_GEMINI_API_KEY:-}" ] && configured="configured" ;;
openrouter) [ -n "${OPENROUTER_API_KEY:-}" ] && configured="configured" ;;
esac
fi
current="" current=""
[ "$name" = "$active" ] && current=" ← active" [ "$name" = "$active" ] && current=" ← active"
printf ' %-16s %s (model: %s)%s\n' "$name" "$configured" "$pmodel" "$current" printf ' %-16s %s (model: %s)%s\n' "$name" "$configured" "$pmodel" "$current"
+12 -9
View File
@@ -2,14 +2,17 @@
# Copied to ~/.config/linux_post_install/ai.env on install (no clobber). # Copied to ~/.config/linux_post_install/ai.env on install (no clobber).
# Edit with: pos config ai # Edit with: pos config ai
# #
# Syntax: # Provider selection:
# AI_PROVIDER=gemini # provider: gemini|openrouter (default gemini) # AI_PROVIDER=gemini # provider: gemini|openrouter (default gemini)
# AI_API_KEY=<key> # API key for the active provider (secret)
# AI_MODEL=<model> # model id (default depends on provider)
# AI_SYSTEM_PROMPT=<prompt> # custom system prompt (overrides built-in; empty to reset)
# #
# Legacy provider-specific keys (still supported as fallback): # API keys (each provider needs its own):
# AI_GEMINI_API_KEY=<key> # Gemini API key (used when AI_API_KEY is empty) # AI_GEMINI_API_KEY=<key> # Gemini API key from aistudio.google.com
# AI_GEMINI_MODEL=<model> # Gemini model id (used when AI_MODEL is empty) # OPENROUTER_API_KEY=<key> # OpenRouter API key from openrouter.ai
# OPENROUTER_API_KEY=<key> # OpenRouter API key (used when AI_API_KEY is empty) #
# OPENROUTER_MODEL=<model> # OpenRouter model id (used when AI_MODEL is empty) # Model overrides (optional, defaults per provider):
# AI_GEMINI_MODEL=<model> # Gemini model id (default: gemini-2.5-flash)
# OPENROUTER_MODEL=<model> # OpenRouter model id (default: openrouter/auto)
# AI_MODEL=<model> # Override for all providers (takes priority)
#
# System prompt:
# AI_SYSTEM_PROMPT=<prompt> # Custom system prompt (overrides built-in; empty to reset)