Files
Linux_post_install/lib/ai-providers/gemini.sh
T
Your Name e0c9ba384a
gates / consistency-and-conventions (push) Successful in 1m30s
feat: dynamic provider config — pos config ai auto-discovers provider keys
- 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
2026-08-26 02:58:45 -04:00

64 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Gemini provider adapter for pos-ai
# 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'; }
# $1=model $2=messages JSON ({"messages":[{role,content}]}) $3=optional system prompt
provider_generate() {
local model="$1" messages="$2" system="${3:-}" body resp code body_out errmsg
# Convert OpenAI messages format to Gemini contents format
body="$(printf '%s' "$messages" | jq -c '{
contents: [.messages[]? | {role: (.role | gsub("assistant";"model")), parts: [{text: .content}]}]
}')"
if [ -n "$system" ]; then
body="$(printf '%s' "$body" | jq -c --arg s "$system" \
'. + {systemInstruction:{role:"system",parts:[{text:$s}]}}')"
fi
resp="$(curl -sS -m 60 -X POST "https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent" \
-H "x-goog-api-key: ${AI_API_KEY}" \
-H "Content-Type: application/json" \
--write-out $'\n%{http_code}' \
--data "$body")" || { echo "request failed (curl exit $?)" >&2; return 1; }
code="${resp##*$'\n'}"
body_out="${resp%$'\n'*}"
if [ "$code" != "200" ]; then
errmsg="$(printf '%s' "$body_out" | jq -r '.error.message // empty' 2>/dev/null || true)"
echo "API error $code${errmsg:+: $errmsg}" >&2
return 1
fi
printf '%s' "$body_out" | jq -r '[.candidates[0].content.parts[]?.text] | join("")'
}
# $1=current default model → stdout=formatted model list
provider_models_list() {
local model="$1" resp code body m
resp="$(curl -sS -m 30 -G "https://generativelanguage.googleapis.com/v1beta/models" \
-H "x-goog-api-key: ${AI_API_KEY}" \
--data-urlencode "pageSize=1000" \
--write-out $'\n%{http_code}')" || err "request failed (curl exit $?)"
code="${resp##*$'\n'}"
body="${resp%$'\n'*}"
[ "$code" = "200" ] || err "API error $code: $(printf '%s' "$body" | jq -r '.error.message // empty')"
local list
list="$(printf '%s' "$body" | jq -r '.models[]? | select((.supportedGenerationMethods // []) | index("generateContent")) | .name' | sed 's#^models/##' | sort)"
echo "Gemini models (generateContent-capable):"
while IFS= read -r m; do
[ -n "$m" ] || continue
if [ "$m" = "$model" ]; then
printf ' %-32s <- default\n' "$m"
else
printf ' %-32s\n' "$m"
fi
done <<< "$list"
if ! grep -qxF "$model" <<< "$list" 2>/dev/null; then
warn "configured default '$model' is not in the list — set AI_MODEL or AI_GEMINI_MODEL"
fi
}