jenkins b66c762f5d hermes(webui): add HUX card UI models with contract-locked suites
Standalone per-card browser model/security/view modules for HUX-01..10
plus node+pytest suites that read the hux.v1 contract schemas directly.
Reconciled drift found on integration: the activity model now accepts
all 32 hux.event.v1 kinds (delegation.*, memory.suppressed,
memory.retrieval_removed, budget.exhausted, side_effect.*), the
autonomy model carries the external_side_effect capability, and the
foundation boundary test now asserts the shipped static HUX surface
exists on disk and that images never bake activated HUX_FLAGS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
2026-08-24 04:12:03 -03:00

313 lines
10 KiB
TypeScript

/** Fail-closed HUX-06 intent validation and HUX foundation adapter. */
import type {
AdvancedRouteChoice,
FriendlyModeIntent,
FriendlyModeName,
FriendlyModesAdapter,
HuxFoundationClient,
ModeConstraints,
ModeEffort,
ModeProvider,
RawAdvancedRouteChoice,
RawModeIntent,
RawResolvedRoute,
ResolvedRouteDisclosure,
} from "./types.ts";
export const FOUNDATION_FLAG = "hux.foundation";
export const FRIENDLY_MODES_FLAG = "hux.friendly_modes";
export const MODE_ORDER: readonly FriendlyModeName[] = [
"fast",
"thoughtful",
"research",
"create",
"private",
];
const MODE_LABELS: Readonly<Record<FriendlyModeName, string>> = {
fast: "Fast",
thoughtful: "Thoughtful",
research: "Research",
create: "Create",
private: "Private",
};
const PROVIDERS = new Set<ModeProvider>(["codex", "claude", "local"]);
const EFFORTS: readonly ModeEffort[] = ["low", "medium", "high", "xhigh"];
const ROUTE = /^atlas\/(auto|manual|fallback|worker)\/[a-z0-9/-]+$/;
const MANUAL_ROUTE = /^atlas\/manual\/[a-z0-9/-]+$/;
const REMOTE_PROVIDER_NAME = /\b(?:anthropic|claude|codex|openai)\b/i;
function record(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
return value as Record<string, unknown>;
}
function exactKeys(
value: Record<string, unknown>,
required: readonly string[],
optional: readonly string[] = [],
): boolean {
const allowed = new Set([...required, ...optional]);
return (
required.every((key) => Object.prototype.hasOwnProperty.call(value, key)) &&
Object.keys(value).every((key) => allowed.has(key))
);
}
function boundedString(value: unknown, min: number, max: number): value is string {
return typeof value === "string" && value.length >= min && value.length <= max;
}
function oneOf<T extends string>(value: unknown, values: readonly T[]): value is T {
return typeof value === "string" && values.includes(value as T);
}
function normalizeConstraints(value: unknown): ModeConstraints | null {
const constraints = record(value);
const required = [
"providers",
"local_only",
"effort",
"tools",
"memory",
"citations_required",
"retention",
];
if (!constraints || !exactKeys(constraints, required)) return null;
if (!Array.isArray(constraints.providers) || constraints.providers.length < 1)
return null;
const providers = constraints.providers;
if (
providers.some((provider) => !PROVIDERS.has(provider as ModeProvider)) ||
new Set(providers).size !== providers.length ||
typeof constraints.local_only !== "boolean"
)
return null;
const effort = record(constraints.effort);
const tools = record(constraints.tools);
const memory = record(constraints.memory);
if (
!effort ||
!exactKeys(effort, ["min", "max"]) ||
!oneOf(effort.min, EFFORTS) ||
!oneOf(effort.max, EFFORTS) ||
EFFORTS.indexOf(effort.min) > EFFORTS.indexOf(effort.max)
)
return null;
if (
!tools ||
!exactKeys(tools, ["web", "shell", "artifacts", "delegate"]) ||
!oneOf(tools.web, ["required", "allowed", "denied"] as const) ||
!oneOf(tools.shell, ["allowed", "denied"] as const) ||
!oneOf(tools.artifacts, ["encouraged", "allowed", "denied"] as const) ||
!oneOf(tools.delegate, ["allowed", "denied"] as const)
)
return null;
if (
!memory ||
!exactKeys(memory, ["read", "write"]) ||
typeof memory.read !== "boolean" ||
typeof memory.write !== "boolean" ||
typeof constraints.citations_required !== "boolean" ||
!oneOf(constraints.retention, ["default", "ephemeral"] as const)
)
return null;
// Provider arrays are semantically sets. Canonical ordering prevents their
// transport order from becoming an accidental routing preference.
const canonicalProviders = (["codex", "claude", "local"] as const).filter(
(provider) => providers.includes(provider),
);
return {
providers: [...canonicalProviders],
local_only: constraints.local_only,
effort: { min: effort.min, max: effort.max },
tools: {
web: tools.web,
shell: tools.shell,
artifacts: tools.artifacts,
delegate: tools.delegate,
},
memory: { read: memory.read, write: memory.write },
citations_required: constraints.citations_required,
retention: constraints.retention,
};
}
function modeSemanticsAreSafe(
mode: FriendlyModeName,
constraints: ModeConstraints,
routeId: string,
): boolean {
const providers = new Set(constraints.providers);
if (mode === "private") {
return (
constraints.local_only &&
providers.size === 1 &&
providers.has("local") &&
routeId.startsWith("atlas/auto/")
);
}
return (
!constraints.local_only &&
providers.has("codex") &&
providers.has("claude") &&
!REMOTE_PROVIDER_NAME.test(routeId.replaceAll("/", " ")) &&
routeId.startsWith("atlas/auto/")
);
}
export function friendlyModesEnabled(flags?: Iterable<string>): boolean {
if (!flags) return false;
const enabled = new Set(flags);
return enabled.has(FOUNDATION_FLAG) && enabled.has(FRIENDLY_MODES_FLAG);
}
export function normalizeMode(raw: RawModeIntent): FriendlyModeIntent | null {
const root = record(raw);
if (
!root ||
!exactKeys(root, ["schema", "mode", "label", "intent", "constraints", "switchyard"]) ||
root.schema !== "hux.mode.v1" ||
!oneOf(root.mode, MODE_ORDER) ||
root.label !== MODE_LABELS[root.mode] ||
!boundedString(root.intent, 1, 400) ||
REMOTE_PROVIDER_NAME.test(root.intent)
)
return null;
const constraints = normalizeConstraints(root.constraints);
const switchyard = record(root.switchyard);
if (
!constraints ||
!switchyard ||
!exactKeys(switchyard, ["route_id"]) ||
typeof switchyard.route_id !== "string" ||
!ROUTE.test(switchyard.route_id) ||
!modeSemanticsAreSafe(root.mode, constraints, switchyard.route_id)
)
return null;
return {
schema: "hux.mode.v1",
mode: root.mode,
label: root.label,
intent: root.intent,
constraints,
switchyard: { route_id: switchyard.route_id },
};
}
export function normalizeModeCatalog(raw: unknown): FriendlyModeIntent[] | null {
if (!Array.isArray(raw) || raw.length !== MODE_ORDER.length) return null;
const modes = raw.map((value) => normalizeMode(value as RawModeIntent));
if (modes.some((mode) => mode === null)) return null;
const byName = new Map(
(modes as FriendlyModeIntent[]).map((mode) => [mode.mode, mode]),
);
if (byName.size !== MODE_ORDER.length) return null;
return MODE_ORDER.map((name) => byName.get(name) as FriendlyModeIntent);
}
export function normalizeAdvancedRoutes(raw: unknown): AdvancedRouteChoice[] {
if (!Array.isArray(raw)) return [];
const seen = new Set<string>();
const choices: AdvancedRouteChoice[] = [];
for (const value of raw.slice(0, 100)) {
const choice = record(value as RawAdvancedRouteChoice);
if (
!choice ||
!exactKeys(choice, ["route_id", "label", "provider", "effort", "local_only"]) ||
typeof choice.route_id !== "string" ||
!MANUAL_ROUTE.test(choice.route_id) ||
seen.has(choice.route_id) ||
!boundedString(choice.label, 1, 80) ||
!PROVIDERS.has(choice.provider as ModeProvider) ||
!oneOf(choice.effort, EFFORTS) ||
typeof choice.local_only !== "boolean"
)
continue;
seen.add(choice.route_id);
choices.push({
routeId: choice.route_id,
label: choice.label,
provider: choice.provider as ModeProvider,
effort: choice.effort,
localOnly: choice.local_only,
});
}
return choices;
}
export function buildModeRequest(
mode: FriendlyModeIntent,
advancedRouteId?: string,
choices: readonly AdvancedRouteChoice[] = [],
): FriendlyModeIntent | null {
const normalized = normalizeMode(mode);
if (!normalized) return null;
if (advancedRouteId === undefined) return normalized;
const choice = choices.find((item) => item.routeId === advancedRouteId);
if (!choice || !MANUAL_ROUTE.test(advancedRouteId)) return null;
const allowed = normalized.constraints.providers.includes(choice.provider);
const privateSafe =
normalized.mode !== "private" ||
(choice.localOnly && choice.provider === "local");
const automaticSafe =
normalized.mode === "private" || (!choice.localOnly && allowed);
if (!allowed || !privateSafe || !automaticSafe) return null;
return {
...normalized,
switchyard: {
route_id: normalized.switchyard.route_id,
override_route_id: advancedRouteId,
},
};
}
export function normalizeResolvedRoute(raw: unknown): ResolvedRouteDisclosure | null {
const route = record(raw as RawResolvedRoute);
if (!route || !exactKeys(route, ["requested"], ["resolved_target", "provider", "effort"]))
return null;
if (!boundedString(route.requested, 1, 120)) return null;
if (
route.resolved_target !== undefined &&
!boundedString(route.resolved_target, 1, 120)
)
return null;
if (route.provider !== undefined && !PROVIDERS.has(route.provider as ModeProvider))
return null;
if (route.effort !== undefined && !oneOf(route.effort, EFFORTS)) return null;
return {
requested: route.requested,
target: route.resolved_target as string | undefined,
provider: route.provider as ModeProvider | undefined,
effort: route.effort as ModeEffort | undefined,
};
}
export function createFriendlyModesAdapter(
foundation: HuxFoundationClient,
): FriendlyModesAdapter {
if (
!foundation ||
foundation.apiVersion !== "hux.v1" ||
typeof foundation.enabled !== "function" ||
typeof foundation.endpoint !== "function"
)
throw new TypeError("A hux.v1 foundation client is required");
return Object.freeze({
apiVersion: "hux.v1" as const,
enabled: () =>
foundation.enabled(FOUNDATION_FLAG) && foundation.enabled(FRIENDLY_MODES_FLAG),
endpoint: () => foundation.endpoint("/modes"),
adaptCatalog: normalizeModeCatalog,
adaptResolvedRoute: normalizeResolvedRoute,
buildRequest: (
mode: FriendlyModeIntent,
advancedRouteId?: string,
choices?: readonly AdvancedRouteChoice[],
) => buildModeRequest(mode, advancedRouteId, choices),
});
}