gateway: phase-6 kill switches + hot-state/revoke admin routes - #1683
Merged
Merged
Conversation
PreLLMHook PIPELINE 1 now also checks bifrost:kill:<run_id> for every chain layer and bifrost:kill:agent:<leaf agent>, rejecting with 402 run_killed / agent_killed (gated by enforce_macaroons; shadow logs). Revocation 401s win when both apply. New admin routes: - POST/DELETE /_plugin/runs/:id/kill, GET /_plugin/runs/:id/state - POST/DELETE /_plugin/agents/:name/kill, GET /_plugin/agents/:name/state - POST/DELETE /_plugin/revoke/nonce/:nonce, PUT/GET/DELETE /_plugin/revoke/user/:id (wires the previously unreachable auth/admin.go helpers) 402 short-circuits carry Type=enforcement_rejected so clients can tell them apart from macaroon_verification_failed.
Evanfeenstra
added a commit
that referenced
this pull request
Sep 14, 2026
) Operator half of the phase-6 kill switches (#1683, #1684) in the admin SPA. Scope is kill/unkill + live hot state only; no config editing, no bulk actions, no analytics changes. - api/types.ts: RunStateResponse, AgentStateResponse, KillRunResponse, KillAgentResponse mirroring hotstate.go (hand-maintained; no tygo). - api/queries.ts: useRunState (2s in flight / 30s done / 500ms for 30s after a kill), useAgentState (10s), useAgentStates (30s per row), useKillRun / useUnkillRun / useKillAgent / useUnkillAgent. 503 (no Redis) folds into data === null with a 60s retry. - components/KillConfirmModal: one modal, two modes — plain confirm for runs, typed agent name for agents. Explains scope, TTL (1h / 24h) and "takes effect on the next LLM call; enforced only with enforce_macaroons=true". No window.confirm (Hive iframe sandbox). - components/StatusBadge: running / killed / exceeded / done with the derivation documented in one place. - RunDetail: live-state card (cost, steps, last tools, kill flag, "state expires in") + Kill / Unkill; 503 renders as an inline note with the switch disabled. - AgentDetail: killed / exceeded badge in the header + Kill / Unkill agent. Agents: kill-state column read from /state per row. - icons: StopIcon. - vite.config: bypass /_plugin/ui/* in the dev proxy so Vite serves the SPA instead of the gateway's embedded bundle (local edits never showed otherwise); GATEWAY_URL override for the proxy target. - .claude/launch.json: gateway-ui dev-server entry. dist/ stays the tracked placeholder — the repo doesn't commit builds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase-6 read side, part 1: kill switches. Doesn't depend on accumulated spend data, so it's useful before the cap walk lands.
Hot path
CheckRevocations(PIPELINE 1) now also issuesEXISTS bifrost:kill:<run_id>for every distinct run_id inClaims.Chain(parent kill ⇒ every descendant dies) andEXISTS bifrost:kill:agent:<agents[last]>.run_killed/agent_killed. Revocation 401s win when both apply.enforce_macaroonslike the rest of the hook; shadow mode logs the would-be rejection.Type=enforcement_rejected(vsmacaroon_verification_failedfor 401s) so clients can tell "re-issue" from "an operator stopped you".Admin routes
POST/DELETE /_plugin/runs/:id/killSET bifrost:kill:<id> 1 EX 3600/DELGET /_plugin/runs/:id/statePOST/DELETE /_plugin/agents/:name/killSET bifrost:kill:agent:<name> 1 EX 86400/DELGET /_plugin/agents/:name/state?window=POST/DELETE /_plugin/revoke/nonce/:nonce{exp}(default 7d ceiling)PUT/GET/DELETE /_plugin/revoke/user/:idrevoke_user_beforecutoff (default now)The revoke routes wire up the
auth/admin.gohelpers that existed but had no HTTP surface.Not in this PR
hard_ceiling,/_plugin/config/*overrides.types.tsnot regenerated —make tygocurrently rewrites the whole hand-maintained file (Gateway: reconcile tygo codegen with SPA and enforce in CI #1563).Tests
miniredis-backed: leaf kill, ancestor kill kills child, agent kill (leaf name only), revoked-beats-killed, end-to-end 402 through
ApplyToLLMPrein enforce mode / pass-through in shadow, admin round-trips, 503 without Redis, 401 without auth.