/* RFC-1211: the closed `ui` block on capability records plus the generated `ui://` resource document contract (MCP-UI resource projection). A capability whose catalog YAML declares `ui: { resource: true }` gets a deterministic, self-contained HTML projection committed under `public/.well-known/ui/` and served through MCP resources/list + resources/read. The schema lives here (agent-facing contract) and is consumed by the ontology record schema in ontology/schemas/capability.ts — this module imports nothing but zod so the dependency direction stays acyclic. Do not render HTML here — the deterministic projection lives in packages/werkstatt-site/src/codegen/agent-ui.ts. Do not widen the ui block with interactivity flags — v1 resources are read-only text/html (no scripts, no postMessage bridges); widening requires a superseding RFC. RFC-1211: initial contract — capabilityUiSchema, UiResourceDoc envelope, ui:// URI + .well-known path helpers. RFC-1212: metering contract — CapabilityMetering block, CapabilityPricing manifest projection, AgentUsageRecord journal schema. */ import { z } from "zod"; /** RFC-1211: version marker stamped into every generated UI document. */ export const UI_RESOURCE_SCHEMA_ID = "gogol.agent-ui/1"; /** MIME type every ui:// resource carries — v1 emits text/html only. */ export const UI_RESOURCE_MIME = "text/html"; /** Site-relative public directory the committed UI artifacts live under. */ export const UI_RESOURCE_PUBLIC_DIR = ".well-known/ui"; /** * RFC-1211: the closed `ui` block of a capability catalog record. `resource: * true` opts the capability into deterministic HTML projection; unknown keys * are rejected by `.strict()` (AC-1). `preferredFrameSize` is MCP-UI metadata * passthrough — a rendering hint for the host frame, in CSS pixels. */ export const capabilityUiSchema = z .object({ resource: z.literal(true), preferredFrameSize: z .object({ width: z.number().int().positive(), height: z.number().int().positive(), }) .strict() .optional(), }) .strict(); export type CapabilityUi = z.infer; /** * RFC-1211: the document envelope embedded in every generated UI artifact * (kept in-file as a leading HTML comment for auditability). `renderData` is * the props snapshot the deterministic render consumed — never request data. */ export const uiResourceDocSchema = z .object({ schema: z.literal(UI_RESOURCE_SCHEMA_ID), uri: z.string().regex(/^ui:\/\/[^\s]+\/[^\s]+$/, "uri must be ui:///"), mimeType: z.literal(UI_RESOURCE_MIME), title: z.string().min(1), renderData: z.record(z.string(), z.unknown()), }) .strict(); export type UiResourceDoc = z.infer; /** RFC-1211: canonical ui:// URI for a capability on a site. */ export function uiResourceUri(site: string, capabilityId: string): string { return `ui://${site}/${capabilityId}`; } /** RFC-1211: site-relative public path of a capability's committed UI artifact. */ export function uiResourcePath(capabilityId: string): string { return `/${UI_RESOURCE_PUBLIC_DIR}/${capabilityId}.html`; } /** * RFC-1211: parse a ui:// URI back into `/`. Returns null * for non-ui URIs or malformed shapes — callers map null to "unknown resource". */ export function parseUiResourceUri(uri: string): { site: string; capabilityId: string } | null { const match = /^ui:\/\/([^\s/]+)\/([^\s/]+)$/.exec(uri); if (!match) return null; return { site: match[1]!, capabilityId: match[2]! }; } // --------------------------------------------------------------------------- // RFC-1212: metered invocation + machine-readable pricing // --------------------------------------------------------------------------- /** * RFC-1212: the closed `metering` block of a capability catalog record — * opt-in per-call pricing on top of `requires.entitlements`. `product` is a * pricing-catalog reference `.` resolving to a PBP * `usage`-typed Charge in `src/content/business-profile//offerings/`; * `pricePerUnit` is the declared projection, AGM-02 blocks when it diverges * from the catalog charge's unit-rate amount or policy currency. */ export const capabilityMeteringSchema = z .object({ /** Pricing-catalog reference "." (PBP usage Charge). */ product: z .string() .regex( /^[a-z0-9][a-z0-9-]*\.[a-z0-9][a-z0-9-]*$/, "product must be .", ), /** What one unit measures — v1 always meters per invocation. */ unit: z.enum(["invocation", "record", "token"]), /** Declared per-unit price — must match the catalog charge (AGM-02). */ pricePerUnit: z .object({ amount: z.number().positive(), /** ISO-4217 alpha-3, e.g. "EUR". */ currency: z.string().regex(/^[A-Z]{3}$/), }) .strict(), /** Included units per billing window before billing applies. */ freeUnitsPerWindow: z.number().int().nonnegative().optional(), /** Free-allowance window granularity — defaults to "month". */ window: z.enum(["day", "month"]).optional(), }) .strict(); export type CapabilityMetering = z.infer; /** * RFC-1212: the `pricing` object projected into agent.json / OpenAPI per * metered capability — bijective with `metering` (AGM-04 enforces). */ export const capabilityPricingSchema = z .object({ metered: z.literal(true), product: z.string().min(1), unit: z.enum(["invocation", "record", "token"]), pricePerUnit: z .object({ amount: z.number().positive(), currency: z.string().regex(/^[A-Z]{3}$/) }) .strict(), freeUnitsPerWindow: z.number().int().nonnegative(), window: z.enum(["day", "month"]), }) .strict(); export type CapabilityPricing = z.infer; /** RFC-1212: schema marker stamped into every journaled usage record. */ export const AGENT_USAGE_SCHEMA_ID = "gogol.agent-usage/1"; /** * RFC-1212: one journaled usage record per dispatched metered invocation — * a sibling of the traffic telemetry event, emitted post-dispatch only (a * rejected/replayed call never bills). `callerIdentity` is the verified * agentId (pseudonymous billing identity) or "anonymous"; `billable` carries * the free-allowance verdict so the billing bridge can separate included * usage from chargeable usage without re-deriving window state. */ export const agentUsageRecordSchema = z .object({ schema: z.literal(AGENT_USAGE_SCHEMA_ID), siteId: z.string().min(1), capability: z.string().min(1), callerIdentity: z.string().min(1), units: z.number().int().positive(), billable: z.boolean(), /** Dedup anchor — a replayed call never bills twice. */ idempotencyKey: z.string().min(1).optional(), occurredAt: z.string().min(1), }) .strict(); export type AgentUsageRecord = z.infer; /** RFC-1212: project a capability's metering block into the public pricing ref. */ export function capabilityPricingProjection(cap: { metering?: CapabilityMetering; }): CapabilityPricing | undefined { const m = cap.metering; if (!m) return undefined; return { metered: true, product: m.product, unit: m.unit, pricePerUnit: m.pricePerUnit, freeUnitsPerWindow: m.freeUnitsPerWindow ?? 0, window: m.window ?? "month", }; }