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": {}, "lsp": {},
+34 -14
View File
@@ -389,12 +389,26 @@ def sanitize_workdir(workdir: str) -> list[str]:
def install_config(src: str, dst: str) -> bool: 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 The committed `opencode.json` carries neutral placeholders for every
provider's `baseURL`, so the repo can be public without publishing the provider's `baseURL`/`apiKey` so the repo can be public without leaking
address of a private network. The real endpoint is supplied at runtime by private-network addresses. Real values are supplied at runtime and patched
`PRAGENT_MODEL_BASE_URL` and patched in here. 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 This is done in Python rather than with opencode's own `{env:VAR}` config
templating because the reviewer subprocess runs with an allow-listed 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): if not os.path.isfile(src):
return False return False
base_url = os.environ.get("PRAGENT_MODEL_BASE_URL", "").strip() default_url = os.environ.get("PRAGENT_MODEL_BASE_URL", "").strip()
api_key = os.environ.get("PRAGENT_MODEL_API_KEY", "").strip() default_key = os.environ.get("PRAGENT_MODEL_API_KEY", "").strip()
if not base_url and not api_key: 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) shutil.copy2(src, dst)
return True return True
try: try:
with open(src, encoding="utf-8") as f: with open(src, encoding="utf-8") as f:
cfg = json.load(f) cfg = json.load(f)
for prov in (cfg.get("provider") or {}).values(): for name, prov in (cfg.get("provider") or {}).items():
if isinstance(prov, dict) and isinstance(prov.get("options"), dict): if not isinstance(prov, dict) or not isinstance(prov.get("options"), dict):
if base_url: continue
prov["options"]["baseURL"] = base_url per_url = os.environ.get(f"PRAGENT_{name.upper()}_BASE_URL", "").strip()
if api_key: per_key = os.environ.get(f"PRAGENT_{name.upper()}_API_KEY", "").strip()
prov["options"]["apiKey"] = api_key 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: with open(dst, "w", encoding="utf-8") as f:
json.dump(cfg, f, indent=2) json.dump(cfg, f, indent=2)
except (OSError, ValueError, AttributeError): except (OSError, ValueError, AttributeError):