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

62 lines
3.1 KiB
TypeScript

/** Same-origin endpoint descriptors for the future HUX-07 backend. */
import type { ArtifactScope, HuxIdentity } from "../artifacts/types.ts";
import { multimodalEnabled } from "./model.ts";
import { normalizeIdentity, normalizeScope, safeEndpointPart, sameIdentity, sameScope } from "./security.ts";
import type {
CaptureKind, MultimodalEndpoint, MultimodalEndpointContract,
} from "./types.ts";
interface FoundationClient {
apiVersion: string;
identity: HuxIdentity;
endpoint(path: string): string;
}
function endpoint(method: MultimodalEndpoint["method"], path: string,
responseSchema: string, requiredBody?: readonly string[]): MultimodalEndpoint {
return Object.freeze({method, path, responseSchema, ...(requiredBody ? {requiredBody} : {})});
}
/** Describe endpoints only. The caller owns authenticated transport and approval execution. */
export function createMultimodalEndpointContract(client: FoundationClient, scope: ArtifactScope,
flags?: Iterable<string>): MultimodalEndpointContract | null {
if (!multimodalEnabled(flags)) return null;
if (client.apiVersion !== "hux.v1" || !sameIdentity(normalizeIdentity(client.identity), client.identity) ||
!sameScope(normalizeScope(scope), scope)) throw new TypeError("Scoped HUX v1 client required");
const base = client.endpoint(`/projects/${safeEndpointPart(scope.projectId, "prj")}` +
`/conversations/${safeEndpointPart(scope.conversationId, "conv")}/multimodal`);
const child = (root: string, id: unknown, prefix: string, suffix = "") =>
`${base}/${root}/${safeEndpointPart(id, prefix)}${suffix}`;
return Object.freeze({
page: endpoint("GET", base, "hux.multimodal_page.v1"),
beginUpload: endpoint("POST", `${base}/uploads`, "hux.media_upload.v1",
["file_name", "mime", "bytes", "authorization_id"]),
finalizeUpload(uploadId) {
return endpoint("POST", child("uploads", uploadId, "upl", "/finalize"), "hux.media.v1",
["content_ref", "expected_upload_id"]);
},
editImage(mediaId) {
return endpoint("POST", child("media", mediaId, "med", "/edits"), "hux.media.v1",
["artifact_id", "expected_current_version", "instruction", "lineage"]);
},
annotate(mediaId) {
return endpoint("POST", child("media", mediaId, "med", "/annotations"), "hux.media.v1",
["artifact_id", "expected_current_version", "page", "note"]);
},
correctTranscript(transcriptId) {
return endpoint("POST", child("transcripts", transcriptId, "trn", "/corrections"),
"hux.voice_transcript.v1", ["turn_id", "expected_revision", "corrected_text"]);
},
requestCapture(kind: CaptureKind) {
if (!['camera', 'screen'].includes(kind)) throw new TypeError("Capture kind is invalid");
return endpoint("POST", `${base}/captures/${kind}/approvals`, "hux.approval.v1",
["capability", "required_decision", "conversation_id"]);
},
createVariant(threadId) {
return endpoint("POST", child("threads", threadId, "thr", "/variants"),
"hux.generation_thread.v1", ["media_id", "artifact_id", "artifact_version", "parent_variant_id"]);
},
});
}