feat: dynamic provider config — pos config ai auto-discovers provider keys
gates / consistency-and-conventions (push) Successful in 1m30s

- lib/ai-providers/*.sh declare # PROVIDER_CONFIG: headers
- lib/config-ui.sh: _cfg_provider_keys() scans providers at runtime
- bin/pos-ai: POS_CONFIG uses *providers marker (no hardcoded keys)
- Adding a new provider auto-populates config UI — no main tool edits needed
This commit is contained in:
Your Name
2026-08-26 02:58:45 -04:00
parent 7ae2e77a44
commit e0c9ba384a
5 changed files with 41 additions and 7 deletions
+4
View File
@@ -3,6 +3,10 @@
# Provider-specific: API call, auth, response parsing, models list
# Part of the R8 provider-agnostic architecture (lib/ai-providers/).
# Provider-specific config variables (auto-discovered by pos config ai):
# PROVIDER_CONFIG: AI_GEMINI_API_KEY=secret:Gemini API key from aistudio.google.com
# PROVIDER_CONFIG: AI_GEMINI_MODEL=:Gemini model id (default: gemini-2.5-flash)
provider_name() { printf 'Google Gemini'; }
provider_default_model() { printf 'gemini-2.5-flash'; }
+4
View File
@@ -3,6 +3,10 @@
# Provider-specific: API call, auth, response parsing, models list
# Part of the R8 provider-agnostic architecture (lib/ai-providers/).
# Provider-specific config variables (auto-discovered by pos config ai):
# PROVIDER_CONFIG: OPENROUTER_API_KEY=secret:OpenRouter API key from openrouter.ai
# PROVIDER_CONFIG: OPENROUTER_MODEL=:OpenRouter model id (default: openrouter/auto)
provider_name() { printf 'OpenRouter'; }
provider_default_model() { printf 'openrouter/auto'; }
+29 -1
View File
@@ -136,6 +136,33 @@ _cfg_plugin_keys() {
return 0
}
# "*providers" expansion: keys declared by the installed AI provider
# adapters' "# PROVIDER_CONFIG:" headers (lib/ai-providers/*.sh).
_cfg_provider_keys() {
local pdir line key desc flags
# Find lib/ai-providers/ relative to config-ui.sh
pdir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib/ai-providers" 2>/dev/null && pwd)"
[ -d "$pdir" ] || return 0
while IFS= read -r line; do
[ -n "$line" ] || continue
# Format: KEY=flags:description (same as POS_CONFIG key fields)
key="${line%%=*}"
[ -n "$key" ] || continue
[ -n "${_cfg_seen[$key]:-}" ] && continue
_cfg_seen[$key]=1
# Parse flags and description from the rest
local rest="${line#*=}" flags="" desc=""
if [[ "$rest" == *":"* ]]; then
flags="${rest%%:*}"
desc="${rest#*:}"
else
flags="$rest"
fi
printf '%s|%s|%s|\n' "$key" "$flags" "$desc"
done < <(grep '^# PROVIDER_CONFIG:' "$pdir"/*.sh 2>/dev/null | sed 's/^.*# PROVIDER_CONFIG:[[:space:]]*//' || true)
return 0
}
# Declared keys for a scope: "KEY|flags|description" lines, deduped.
cfg_scope_keys() {
local scope="$1" dir line s keystring field
@@ -155,7 +182,8 @@ cfg_scope_keys() {
if [ -n "$field" ]; then
if [[ "$field" == "*"* ]]; then
case "$field" in
*plugins*) _cfg_plugin_keys ;;
*plugins*) _cfg_plugin_keys ;;
*providers*) _cfg_provider_keys ;;
esac
else
_cfg_key_line "$field"