UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

81 lines • 3.94 kB
import { COMPONENT_NAME, defineCatalog } from './catalog.js'; import { formatIssues } from './schema.js'; import { componentToText, treeToText } from './text.js'; import { GENUI_TREE_COMPONENT, validateTree } from './tree.js'; export function validateUiCapabilities(value) { if (!record(value) || Object.keys(value).some((key) => key !== 'components') || !Array.isArray(value.components)) throw new TypeError('Invalid UI capabilities'); const seen = new Set(); const components = value.components.map((component) => { if (!record(component) || Object.keys(component).some((key) => key !== 'name' && key !== 'version') || typeof component.name !== 'string' || !COMPONENT_NAME.test(component.name) || !Number.isSafeInteger(component.version) || Number(component.version) <= 0 || seen.has(component.name)) throw new TypeError('Invalid UI component capability'); seen.add(component.name); return { name: component.name, version: Number(component.version) }; }); return { components }; } function record(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } export function negotiateCatalog(catalog, capabilities) { if (capabilities === undefined) return catalog; const supported = validateUiCapabilities(capabilities).components; return defineCatalog(catalog.components.filter((component) => supported.some((entry) => entry.name === component.name && entry.version === (component.version ?? 1))), { jsonSchemaValidator: catalog.validator }); } /** Validate against current trusted definitions before drawing or generating complete text. */ export async function prepareUiEmission(catalog, capabilities, component, props, version) { const drawable = negotiateCatalog(catalog, capabilities); if (component === GENUI_TREE_COMPONENT) { if (version !== undefined && version !== 1) throw new Error('Invalid UI tree version'); const validated = await validateTree(catalog, props.root); if (!validated.ok) throw new Error(`Invalid UI tree: ${formatIssues(validated.issues)}`); const supported = (node) => drawable.has(node.type) && (node.children ?? []).every(supported); const versions = new Map(); const collectVersions = (node) => { versions.set(node.type, catalog.get(node.type)?.version ?? 1); for (const child of node.children ?? []) collectVersions(child); }; collectVersions(validated.value); return supported(validated.value) ? { kind: 'ui', component, props: { root: validated.value }, version: 1, fallbackText: treeToText(catalog, validated.value), componentVersions: Object.fromEntries(versions), } : { kind: 'text', text: treeToText(catalog, validated.value) }; } const definition = catalog.get(component); if (definition === undefined) throw new Error(`Unknown UI component "${component}"`); const currentVersion = definition.version ?? 1; if (version !== undefined && version !== currentVersion) throw new Error(`Invalid UI component version for "${component}"`); const validated = await catalog.validate(component, props); if (!validated.ok) throw new Error(`Invalid UI props: ${formatIssues(validated.issues)}`); return drawable.has(component) ? { kind: 'ui', component, props: validated.value, version: currentVersion, fallbackText: componentToText(catalog, component, validated.value), } : { kind: 'text', text: componentToText(catalog, component, validated.value) }; } //# sourceMappingURL=capabilities.js.map