CB-591: plan the move onto the LLM/MCP gateway, and check AI_GATEWAY_TOKEN
The gateway (llm.ltms.dev) replaced Bifrost on 2026-08-15 and serves an Anthropic surface and an OpenAI surface, so both member kinds can point at it. The plan is in docs/CB-591-Gateway-Migration.md; gitea #76 tracks the work. The opencode half needs no code: OpenCodeLauncher already pins an OpenAI-compatible endpoint (CB-508), so baseUrl + tokenEnv + provider/model is a config change. That matters more than it looks — every opencode member today is sol or terra, and both sit on one OpenAI account via credentialId: openai-shared, so an exhaustion on either locks out both. A gateway-backed opencode profile is free and off that credential, which retires a single point of failure rather than only adding capacity. Also extends the redeploy script's --check to AI_GATEWAY_TOKEN. A profile's tokenEnv is resolved from the DAEMON's own environment by HerdrPeerLauncher.resolveEnv, so a token added to secrets.sh after the daemon started is simply absent: the launcher injects an empty token and the gateway answers 401, long after the restart and with nothing tying the two together. That is the same trap as WORKER_GITEA_TOKEN, and it gets the same login-shell check that never prints the value.
This commit is contained in:
@@ -8,8 +8,10 @@
|
||||
# This script exists to turn five remembered traps into one auditable command:
|
||||
#
|
||||
# 1. A piped `mvn` hides BUILD FAILURE behind a zero exit, so the build here is never piped.
|
||||
# 2. The daemon must start from a LOGIN shell, or WORKER_GITEA_TOKEN is empty and workers cannot
|
||||
# open a PR. Nothing in the daemon logs this, so the script checks it and says so out loud.
|
||||
# 2. The daemon must start from a LOGIN shell, or the tokens it hands to members are empty:
|
||||
# WORKER_GITEA_TOKEN (workers cannot open a PR) and AI_GATEWAY_TOKEN (401 at llm.ltms.dev).
|
||||
# Both are read from the DAEMON's own environment at spawn time, so a value added to
|
||||
# secrets.sh after startup is absent. Nothing logs this, so the script checks and says so.
|
||||
# 3. An old daemon that never actually died looks identical from the outside, so the script waits
|
||||
# for the process to exit and for the port to free before it starts a new one.
|
||||
# 4. "It started" is not "it works": the script polls /healthz until it answers, and reports the
|
||||
@@ -82,6 +84,18 @@ else
|
||||
warn "Fix \${SHARED_ENV}/tools/secrets.sh before relying on worker checkpoints."
|
||||
fi
|
||||
|
||||
# Same trap, second variable (CB-591). A profile's `tokenEnv:` is resolved from the DAEMON's own
|
||||
# process environment by HerdrPeerLauncher.resolveEnv, so a token added to secrets.sh after the
|
||||
# daemon started is simply absent. The launcher then injects an empty token and llm.ltms.dev answers
|
||||
# 401 — long after the restart, and with nothing tying the two together.
|
||||
if zsh -lc '[ -n "${AI_GATEWAY_TOKEN:-}" ]' 2>/dev/null; then
|
||||
ok "AI_GATEWAY_TOKEN resolves in a login shell"
|
||||
else
|
||||
warn "AI_GATEWAY_TOKEN is EMPTY in a login shell."
|
||||
warn "Any profile whose tokenEnv is AI_GATEWAY_TOKEN will get an empty token and 401 at the gateway."
|
||||
warn "This only matters once a profile points at llm.ltms.dev — harmless before that."
|
||||
fi
|
||||
|
||||
if [ "$CHECK_ONLY" = 1 ]; then
|
||||
say "--check: nothing changed"
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user