g1t/apps/web/app/lib/guardrails.ts
Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API | 1 | import type { GuardrailSettings, RunKind } from "@g1t/contracts"; |
| 2 | ||
| 3 | /** What a level's form field means: inherit, or a choice of its own. */ | |
| 4 | export type Tri = "inherit" | "on" | "off"; | |
| 5 | ||
| 6 | export function tri(value: boolean | null | undefined): Tri { | |
| 7 | return value == null ? "inherit" : value ? "on" : "off"; | |
| 8 | } | |
| 9 | ||
| 10 | /** Lines of a textarea, trimmed, without blanks or repeats. */ | |
| 11 | export function lines(value: FormDataEntryValue | null): string[] { | |
| 12 | const seen = new Set<string>(); | |
| 13 | for (const line of String(value ?? "").split(/\r?\n/)) { | |
| 14 | const trimmed = line.trim(); | |
| 15 | if (trimmed) seen.add(trimmed); | |
| 16 | } | |
| 17 | return [...seen]; | |
| 18 | } | |
| 19 | ||
| 20 | /** A number from a field; empty means inherit. Not a number is kept, to be refused. */ | |
| 21 | function amount(value: FormDataEntryValue | null): number | null { | |
| 22 | const text = String(value ?? "").trim().replace(/^\$/, ""); | |
| 23 | if (!text) return null; | |
| 24 | const number = Number(text); | |
| 25 | return Number.isFinite(number) ? number : Number.NaN; | |
| 26 | } | |
| 27 | ||
| 28 | /** What one level's form says, as the settings that level keeps. */ | |
| 29 | export function settingsFromForm( | |
| 30 | form: FormData, | |
| 31 | catalog: { registries: string[]; rules: string[]; kinds: readonly RunKind[] }, | |
| 32 | ): GuardrailSettings { | |
| 33 | const choice = (name: string): boolean | null => { | |
| 34 | const value = form.get(name); | |
| 35 | return value === "on" ? true : value === "off" ? false : null; | |
| 36 | }; | |
| 37 | const rules: Record<string, boolean> = {}; | |
| 38 | for (const id of catalog.rules) { | |
| 39 | const on = choice(`rule:${id}`); | |
| 40 | if (on != null) rules[id] = on; | |
| 41 | } | |
| 42 | const minutes: Record<string, number> = {}; | |
| 43 | for (const kind of catalog.kinds) { | |
| 44 | const cap = amount(form.get(`minutes:${kind}`)); | |
| 45 | if (cap != null) minutes[kind] = Number.isNaN(cap) ? 0 : Math.trunc(cap); | |
| 46 | } | |
| 47 | const budget = amount(form.get("budgetUsd")); | |
| 48 | return { | |
| 49 | restrictNetwork: choice("restrictNetwork"), | |
| 50 | registries: | |
| 51 | form.get("registries") === "custom" | |
| 52 | ? catalog.registries.filter((id) => form.get(`registry:${id}`) === "on") | |
| 53 | : null, | |
| 54 | domains: lines(form.get("domains")), | |
| 55 | rules, | |
| 56 | deny: lines(form.get("deny")), | |
| 57 | // Not a number is sent as one the service refuses, with why. | |
| 58 | budgetUsd: budget == null ? null : Number.isNaN(budget) ? -1 : budget, | |
| 59 | minutes, | |
| 60 | }; | |
| 61 | } | |
| 62 | ||
| 63 | /** A cost in dollars, or "no cap". */ | |
| 64 | export function formatCap(usd: number | null | undefined): string { | |
| 65 | return usd == null ? "no cap" : `$${usd.toFixed(2)}`; | |
| 66 | } | |
| 67 | ||
| 68 | /** How full a cap is, from 0 to 1, or null with no cap. */ | |
| 69 | export function capShare(used: number | null | undefined, cap: number | null | undefined): number | null { | |
| 70 | if (cap == null || cap <= 0 || used == null) return null; | |
| 71 | return Math.min(1, Math.max(0, used / cap)); | |
| 72 | } |