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
188 lines
5.8 KiB
TypeScript
188 lines
5.8 KiB
TypeScript
/** Accessible HUX-06 mode intent selector. The feature is default-off. */
|
|
|
|
import { useMemo } from "react";
|
|
|
|
import {
|
|
buildModeRequest,
|
|
friendlyModesEnabled,
|
|
normalizeAdvancedRoutes,
|
|
normalizeModeCatalog,
|
|
normalizeResolvedRoute,
|
|
} from "./model.ts";
|
|
import type {
|
|
FriendlyModeIntent,
|
|
FriendlyModeName,
|
|
RawAdvancedRouteChoice,
|
|
RawModeIntent,
|
|
RawResolvedRoute,
|
|
} from "./types.ts";
|
|
|
|
interface FriendlyModeSelectorProps {
|
|
flags?: Iterable<string>;
|
|
modes: readonly RawModeIntent[];
|
|
selectedMode: FriendlyModeName;
|
|
advancedRoutes?: readonly RawAdvancedRouteChoice[];
|
|
resolvedRoute?: RawResolvedRoute;
|
|
disabled?: boolean;
|
|
onChange(intent: FriendlyModeIntent): void;
|
|
}
|
|
|
|
const MODE_HELP: Readonly<Record<FriendlyModeName, string>> = {
|
|
fast: "Quick, direct answers with light reasoning.",
|
|
thoughtful: "More reasoning for careful decisions.",
|
|
research: "Source-backed investigation with citations.",
|
|
create: "Generative work with artifact support.",
|
|
private: "Local-only processing with ephemeral retention.",
|
|
};
|
|
|
|
const PROVIDER_LABELS = {
|
|
codex: "OpenAI",
|
|
claude: "Anthropic",
|
|
local: "Local",
|
|
} as const;
|
|
|
|
/** Render nothing unless HUX-11 and HUX-06 are both explicitly enabled. */
|
|
export function FriendlyModeSelector({
|
|
flags,
|
|
modes,
|
|
selectedMode,
|
|
advancedRoutes = [],
|
|
resolvedRoute,
|
|
disabled = false,
|
|
onChange,
|
|
}: FriendlyModeSelectorProps) {
|
|
const enabled = friendlyModesEnabled(flags);
|
|
const catalog = useMemo(() => normalizeModeCatalog(modes), [modes]);
|
|
const choices = useMemo(
|
|
() => normalizeAdvancedRoutes(advancedRoutes),
|
|
[advancedRoutes],
|
|
);
|
|
const resolved = useMemo(
|
|
() => normalizeResolvedRoute(resolvedRoute),
|
|
[resolvedRoute],
|
|
);
|
|
if (!enabled) return null;
|
|
|
|
if (!catalog) {
|
|
return (
|
|
<p className="hux-modes-error" role="alert">
|
|
Mode choices are unavailable because their safety contract could not be
|
|
verified.
|
|
</p>
|
|
);
|
|
}
|
|
const selected = catalog.find((mode) => mode.mode === selectedMode);
|
|
if (!selected) {
|
|
return (
|
|
<p className="hux-modes-error" role="alert">
|
|
The selected mode could not be verified. No routing change was made.
|
|
</p>
|
|
);
|
|
}
|
|
const compatibleChoices = choices.filter((choice) =>
|
|
selected.mode === "private"
|
|
? choice.localOnly && choice.provider === "local"
|
|
: !choice.localOnly && selected.constraints.providers.includes(choice.provider),
|
|
);
|
|
|
|
return (
|
|
<section className="hux-modes" aria-labelledby="hux-modes-heading">
|
|
<div className="hux-modes-heading">
|
|
<div>
|
|
<h2 id="hux-modes-heading">Response mode</h2>
|
|
<p>Choose the intent; Switchyard selects from the allowed pool.</p>
|
|
</div>
|
|
<span className="hux-modes-active" aria-live="polite">
|
|
{selected.label}
|
|
</span>
|
|
</div>
|
|
|
|
<fieldset disabled={disabled} className="hux-mode-grid">
|
|
<legend className="sr-only">Choose a response mode</legend>
|
|
{catalog.map((mode) => (
|
|
<label className="hux-mode-card" key={mode.mode}>
|
|
<input
|
|
type="radio"
|
|
name="hermes-friendly-mode"
|
|
value={mode.mode}
|
|
checked={mode.mode === selected.mode}
|
|
aria-describedby={`hux-mode-help-${mode.mode}`}
|
|
onChange={() => {
|
|
const request = buildModeRequest(mode);
|
|
if (request) onChange(request);
|
|
}}
|
|
/>
|
|
<span className="hux-mode-card-copy">
|
|
<strong>{mode.label}</strong>
|
|
<span id={`hux-mode-help-${mode.mode}`}>{MODE_HELP[mode.mode]}</span>
|
|
</span>
|
|
</label>
|
|
))}
|
|
</fieldset>
|
|
|
|
<details className="hux-modes-advanced">
|
|
<summary>Advanced routing details</summary>
|
|
<div className="hux-modes-advanced-panel">
|
|
<dl>
|
|
<div>
|
|
<dt>Allowed pools</dt>
|
|
<dd>
|
|
{selected.constraints.providers
|
|
.map((provider) => PROVIDER_LABELS[provider])
|
|
.join(" + ")}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Requested route</dt>
|
|
<dd>{selected.switchyard.route_id}</dd>
|
|
</div>
|
|
{resolved?.target && (
|
|
<div>
|
|
<dt>Resolved route</dt>
|
|
<dd>{resolved.target}</dd>
|
|
</div>
|
|
)}
|
|
{resolved?.provider && (
|
|
<div>
|
|
<dt>Resolved provider</dt>
|
|
<dd>{PROVIDER_LABELS[resolved.provider]}</dd>
|
|
</div>
|
|
)}
|
|
{resolved?.effort && (
|
|
<div>
|
|
<dt>Resolved effort</dt>
|
|
<dd>{resolved.effort}</dd>
|
|
</div>
|
|
)}
|
|
</dl>
|
|
|
|
<label className="hux-route-pin">
|
|
<span>Exact route pin</span>
|
|
<select
|
|
disabled={disabled}
|
|
defaultValue=""
|
|
onChange={(event) => {
|
|
const request = event.currentTarget.value
|
|
? buildModeRequest(selected, event.currentTarget.value, choices)
|
|
: buildModeRequest(selected);
|
|
if (request) onChange(request);
|
|
}}
|
|
>
|
|
<option value="">Automatic — use all allowed pools</option>
|
|
{compatibleChoices.map((choice) => (
|
|
<option key={choice.routeId} value={choice.routeId}>
|
|
{choice.label} — {PROVIDER_LABELS[choice.provider]}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<p className="hux-route-pin-help">
|
|
Pinning bypasses automatic selection for this choice. Automatic
|
|
modes otherwise keep both OpenAI and Anthropic eligible.
|
|
</p>
|
|
</div>
|
|
</details>
|
|
</section>
|
|
);
|
|
}
|