Queries lmstudio and ollama /v1/models endpoints to keep opencode.json model entries up to date, preserving manual overrides. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
152 lines
4.1 KiB
Bash
Executable File
152 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Updates lmstudio and/or ollama model listings in opencode.json
|
|
# by querying their /v1/models endpoints.
|
|
#
|
|
# Usage:
|
|
# ./update-models.sh # update both
|
|
# ./update-models.sh lmstudio # update only lmstudio
|
|
# ./update-models.sh ollama # update only ollama
|
|
#
|
|
# Requires: jq, curl
|
|
|
|
set -uo pipefail
|
|
|
|
CONFIG="${OPENCODE_CONFIG:-${HOME}/.config/opencode/opencode.json}"
|
|
|
|
if [[ ! -f "$CONFIG" ]]; then
|
|
echo "Error: config not found at $CONFIG" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq &>/dev/null; then
|
|
echo "Error: jq is required. Install with: brew install jq" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Map provider name -> base URL (read from config)
|
|
get_base_url() {
|
|
jq -r ".provider.${1}.options.baseURL // empty" "$CONFIG"
|
|
}
|
|
|
|
# Map provider name -> display label (read from config)
|
|
get_display_name() {
|
|
jq -r ".provider.${1}.name // \"${1}\"" "$CONFIG"
|
|
}
|
|
|
|
# Fetch models from API endpoint and build the opencode models object.
|
|
# Preserves any existing entries that have extra metadata (limits, modalities, variants)
|
|
# beyond just a name — so your manual overrides aren't lost.
|
|
build_models_json() {
|
|
local provider="$1"
|
|
local base_url="$2"
|
|
local display_name="$3"
|
|
|
|
local api_response
|
|
api_response=$(curl -sf --connect-timeout 5 "${base_url}/models" 2>/dev/null) || {
|
|
echo "Error: could not reach ${base_url}/models — is ${provider} running?" >&2
|
|
return 1
|
|
}
|
|
|
|
# Get list of model IDs from API
|
|
local model_ids
|
|
model_ids=$(echo "$api_response" | jq -r '.data[].id' | sort)
|
|
|
|
if [[ -z "$model_ids" ]]; then
|
|
echo "Warning: no models returned from ${provider}" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Get existing models object (to preserve manual overrides)
|
|
local existing
|
|
existing=$(jq ".provider.${provider}.models // {}" "$CONFIG")
|
|
|
|
# Build new models object
|
|
local new_models="{}"
|
|
while IFS= read -r model_id; do
|
|
[[ -z "$model_id" ]] && continue
|
|
|
|
# Check if this model has extra config beyond just "name"
|
|
local existing_entry
|
|
existing_entry=$(echo "$existing" | jq -r --arg id "$model_id" '.[$id] // empty')
|
|
|
|
local has_extras="false"
|
|
if [[ -n "$existing_entry" ]]; then
|
|
local key_count
|
|
key_count=$(echo "$existing_entry" | jq 'keys | length')
|
|
if [[ "$key_count" -gt 1 ]]; then
|
|
has_extras="true"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$has_extras" == "true" ]]; then
|
|
# Preserve existing entry with overrides, just update the name
|
|
new_models=$(echo "$new_models" | jq \
|
|
--arg id "$model_id" \
|
|
--argjson entry "$existing_entry" \
|
|
--arg name "${model_id} (${display_name})" \
|
|
'.[$id] = ($entry | .name = $name)')
|
|
else
|
|
# Simple entry with just a name
|
|
new_models=$(echo "$new_models" | jq \
|
|
--arg id "$model_id" \
|
|
--arg name "${model_id} (${display_name})" \
|
|
'.[$id] = { "name": $name }')
|
|
fi
|
|
done <<< "$model_ids"
|
|
|
|
echo "$new_models"
|
|
}
|
|
|
|
update_provider() {
|
|
local provider="$1"
|
|
|
|
# Check provider exists in config
|
|
if ! jq -e ".provider.${provider}" "$CONFIG" &>/dev/null; then
|
|
echo "Skipping ${provider}: not configured in opencode.json" >&2
|
|
return 0
|
|
fi
|
|
|
|
local base_url
|
|
base_url=$(get_base_url "$provider")
|
|
if [[ -z "$base_url" ]]; then
|
|
echo "Skipping ${provider}: no baseURL configured" >&2
|
|
return 0
|
|
fi
|
|
|
|
local display_name
|
|
display_name=$(get_display_name "$provider")
|
|
|
|
echo "Updating ${provider} models from ${base_url}..."
|
|
|
|
local new_models
|
|
new_models=$(build_models_json "$provider" "$base_url" "$display_name") || return 1
|
|
|
|
local count
|
|
count=$(echo "$new_models" | jq 'keys | length')
|
|
|
|
# Update config in-place
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
jq --argjson models "$new_models" \
|
|
".provider.${provider}.models = \$models" \
|
|
"$CONFIG" > "$tmp" && mv "$tmp" "$CONFIG"
|
|
|
|
echo " ✓ ${provider}: ${count} models synced"
|
|
}
|
|
|
|
# --- Main ---
|
|
|
|
targets=("${@:-lmstudio ollama}")
|
|
errors=0
|
|
|
|
for target in $targets; do
|
|
update_provider "$target" || ((errors++))
|
|
done
|
|
|
|
if [[ "$errors" -gt 0 ]]; then
|
|
echo "Done with ${errors} error(s). Run 'opencode models' to verify."
|
|
exit 1
|
|
else
|
|
echo "Done. Run 'opencode models' to verify."
|
|
fi
|