feat(opencode): multi-provider support with local provider for qwen3.8-27b

This commit is contained in:
Claude
2026-08-22 19:13:06 +00:00
parent 92020d4d46
commit e5d4e252de
2 changed files with 51 additions and 14 deletions
+17
View File
@@ -20,6 +20,23 @@
}
}
}
},
"local": {
"npm": "@ai-sdk/openai-compatible",
"name": "Local AI workstation (qwen3.8-27b)",
"options": {
"baseURL": "http://192.168.1.79:18020/v1",
"apiKey": "PLACEHOLDER_REPLACED_AT_RUNTIME"
},
"models": {
"qwen3.8-27b": {
"name": "Qwen 3.8 27B (local)",
"limit": {
"context": 32768,
"output": 8192
}
}
}
}
},
"lsp": {},
+34 -14
View File
@@ -389,12 +389,26 @@ def sanitize_workdir(workdir: str) -> list[str]:
def install_config(src: str, dst: str) -> bool:
"""Copy `opencode.json` from src to dst, substituting the model endpoint.
"""Copy `opencode.json` from src to dst, substituting per-provider endpoint
+ API key.
The committed `opencode.json` carries a neutral placeholder for the model
provider's `baseURL`, so the repo can be public without publishing the
address of a private network. The real endpoint is supplied at runtime by
`PRAGENT_MODEL_BASE_URL` and patched in here.
The committed `opencode.json` carries neutral placeholders for every
provider's `baseURL`/`apiKey` so the repo can be public without leaking
private-network addresses. Real values are supplied at runtime and patched
in here.
Env var convention (case-sensitive provider name — `headroom`, `local`):
PRAGENT_<NAME>_BASE_URL — per-provider endpoint override
PRAGENT_<NAME>_API_KEY — per-provider API key override
PRAGENT_MODEL_BASE_URL — legacy catchall, applies to every provider
when the per-provider var is unset
PRAGENT_MODEL_API_KEY — legacy catchall (same)
Per-provider wins over the catchall. The first 2 win when the operator
needs a different endpoint per upstream (e.g. headroom → MiniMax, local →
ai-workstation). The catchall keeps the single-provider deploys from
needing any env config.
This is done in Python rather than with opencode's own `{env:VAR}` config
templating because the reviewer subprocess runs with an allow-listed
@@ -405,20 +419,26 @@ def install_config(src: str, dst: str) -> bool:
"""
if not os.path.isfile(src):
return False
base_url = os.environ.get("PRAGENT_MODEL_BASE_URL", "").strip()
api_key = os.environ.get("PRAGENT_MODEL_API_KEY", "").strip()
if not base_url and not api_key:
default_url = os.environ.get("PRAGENT_MODEL_BASE_URL", "").strip()
default_key = os.environ.get("PRAGENT_MODEL_API_KEY", "").strip()
if not default_url and not default_key:
# Fast path: no env at all → commit copy is fine, no rewrite needed.
shutil.copy2(src, dst)
return True
try:
with open(src, encoding="utf-8") as f:
cfg = json.load(f)
for prov in (cfg.get("provider") or {}).values():
if isinstance(prov, dict) and isinstance(prov.get("options"), dict):
if base_url:
prov["options"]["baseURL"] = base_url
if api_key:
prov["options"]["apiKey"] = api_key
for name, prov in (cfg.get("provider") or {}).items():
if not isinstance(prov, dict) or not isinstance(prov.get("options"), dict):
continue
per_url = os.environ.get(f"PRAGENT_{name.upper()}_BASE_URL", "").strip()
per_key = os.environ.get(f"PRAGENT_{name.upper()}_API_KEY", "").strip()
url = per_url or default_url
key = per_key or default_key
if url:
prov["options"]["baseURL"] = url
if key:
prov["options"]["apiKey"] = key
with open(dst, "w", encoding="utf-8") as f:
json.dump(cfg, f, indent=2)
except (OSError, ValueError, AttributeError):