diff --git a/packages/genui/a2ui-prompt/README.md b/packages/genui/a2ui-prompt/README.md index 017f57e5a5..a8f3204884 100644 --- a/packages/genui/a2ui-prompt/README.md +++ b/packages/genui/a2ui-prompt/README.md @@ -14,9 +14,9 @@ package. Build a prompt with the built-in A2UI basic catalog: ```ts -import { buildA2UISystemPrompt } from '@lynx-js/genui/a2ui-prompt'; +import { buildA2UISystemPromptAsync } from '@lynx-js/genui/a2ui-prompt'; -const prompt = buildA2UISystemPrompt(); +const prompt = await buildA2UISystemPromptAsync(); ``` Read generated catalog artifacts and build a prompt for a custom catalog: @@ -42,11 +42,11 @@ Use `genui a2ui generate catalog` to create those artifacts. ## Exports - `buildA2UISystemPrompt` -- `A2UI_SYSTEM_PROMPT` -- `BASIC_CATALOG` - `BASIC_CATALOG_ID` - `renderCatalogReference` - `createA2UICatalogFromManifests` +- `loadBasicCatalog` +- `buildA2UISystemPromptAsync` - `readA2UICatalogFromDirectory` ## Local Development diff --git a/packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md b/packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md index eb069bfd1d..3eab75eedf 100644 --- a/packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md +++ b/packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md @@ -9,11 +9,6 @@ // @public (undocumented) export const A2UI_PROTOCOL_VERSION = "v0.9"; -// Warning: (ae-missing-release-tag) "A2UI_SYSTEM_PROMPT" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const A2UI_SYSTEM_PROMPT: string; - // Warning: (ae-missing-release-tag) "A2UICatalog" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -94,11 +89,6 @@ export interface A2UIFunctionSpec { returnType: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'any' | 'void'; } -// Warning: (ae-missing-release-tag) "BASIC_CATALOG" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const BASIC_CATALOG: A2UICatalog; - // Warning: (ae-missing-release-tag) "BASIC_CATALOG_EXAMPLES" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -107,12 +97,17 @@ export const BASIC_CATALOG_EXAMPLES: A2UIExample[]; // Warning: (ae-missing-release-tag) "BASIC_CATALOG_ID" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const BASIC_CATALOG_ID = "https://a2ui.org/specification/v0_9/basic_catalog.json"; +export const BASIC_CATALOG_ID = "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog/catalog.json"; // Warning: (ae-missing-release-tag) "buildA2UISystemPrompt" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function buildA2UISystemPrompt(opts?: BuildSystemPromptOptions): string; +export function buildA2UISystemPrompt(opts: BuildSystemPromptOptions): string; + +// Warning: (ae-missing-release-tag) "buildA2UISystemPromptAsync" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function buildA2UISystemPromptAsync(opts?: BuildSystemPromptOptions): Promise; // Warning: (ae-missing-release-tag) "BuildSystemPromptOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -129,7 +124,8 @@ export interface BuildSystemPromptOptions { // @public (undocumented) export function createA2UICatalogFromManifests(options: { catalogId: string; - componentManifests: Record[]; + componentManifests?: Record[]; + components?: Record; examples?: A2UIExample[]; extraRules?: string[]; functions?: A2UIFunctionSpec[]; @@ -159,6 +155,11 @@ export interface JsonSchema { type?: string; } +// Warning: (ae-missing-release-tag) "loadBasicCatalog" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function loadBasicCatalog(): Promise; + // Warning: (ae-missing-release-tag) "ReadA2UICatalogDirectoryOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/packages/genui/a2ui-prompt/tsconfig.build.json b/packages/genui/a2ui-prompt/tsconfig.build.json index fed4574d75..1b58d303bd 100644 --- a/packages/genui/a2ui-prompt/tsconfig.build.json +++ b/packages/genui/a2ui-prompt/tsconfig.build.json @@ -2,6 +2,7 @@ "extends": "./tsconfig.json", "include": [ "src", + "../server/agent/a2ui-catalog-id.ts", "../server/agent/a2ui-catalog.ts", "../server/agent/a2ui-examples.ts", "../server/agent/a2ui-prompt.ts", diff --git a/packages/genui/a2ui-prompt/tsconfig.json b/packages/genui/a2ui-prompt/tsconfig.json index 9c53a55a0d..22d5c631a9 100644 --- a/packages/genui/a2ui-prompt/tsconfig.json +++ b/packages/genui/a2ui-prompt/tsconfig.json @@ -13,6 +13,7 @@ "include": [ "src", "rslib.config.ts", + "../server/agent/a2ui-catalog-id.ts", "../server/agent/a2ui-catalog.ts", "../server/agent/a2ui-examples.ts", "../server/agent/a2ui-prompt.ts", diff --git a/packages/genui/a2ui-prompt/turbo.json b/packages/genui/a2ui-prompt/turbo.json index 3e395ebab1..c2a1c6a216 100644 --- a/packages/genui/a2ui-prompt/turbo.json +++ b/packages/genui/a2ui-prompt/turbo.json @@ -10,6 +10,7 @@ ], "inputs": [ "src/**", + "../server/agent/a2ui-catalog-id.ts", "../server/agent/a2ui-catalog.ts", "../server/agent/a2ui-examples.ts", "../server/agent/a2ui-prompt.ts", @@ -27,6 +28,7 @@ "dependsOn": [], "inputs": [ "src/**", + "../server/agent/a2ui-catalog-id.ts", "../server/agent/a2ui-catalog.ts", "../server/agent/a2ui-examples.ts", "../server/agent/a2ui-prompt.ts", diff --git a/packages/genui/cli/bin/cli.js b/packages/genui/cli/bin/cli.js index f6ecb62951..1edc27fa58 100755 --- a/packages/genui/cli/bin/cli.js +++ b/packages/genui/cli/bin/cli.js @@ -173,9 +173,10 @@ async function runGeneratePromptCli(args, cwd, cliOptions) { } const { - BASIC_CATALOG, BASIC_CATALOG_ID, buildA2UISystemPrompt, + buildA2UISystemPromptAsync, + loadBasicCatalog, readA2UICatalogFromDirectory, } = await import('../../a2ui-prompt/dist/index.js'); const catalog = options.catalogDir @@ -185,17 +186,20 @@ async function runGeneratePromptCli(args, cwd, cliOptions) { cwd, }) : (options.catalogId - ? { ...BASIC_CATALOG, id: options.catalogId } + ? { ...(await loadBasicCatalog()), id: options.catalogId } : undefined); if (options.catalogDir && catalog && isEmptyCatalog(catalog)) { throw new Error( `[${programName}] No components or functions found in generated catalog directory: ${options.catalogDir}`, ); } - const systemPrompt = buildA2UISystemPrompt({ + const promptOptions = { ...(catalog ? { catalog } : {}), ...(options.appendix ? { appendix: options.appendix } : {}), - }); + }; + const systemPrompt = catalog + ? buildA2UISystemPrompt(promptOptions) + : await buildA2UISystemPromptAsync(promptOptions); if (options.out) { const outPath = path.resolve(cwd, options.out); diff --git a/packages/genui/etc/genui.api.md b/packages/genui/etc/genui.api.md index b27e141ee0..67e42d575b 100644 --- a/packages/genui/etc/genui.api.md +++ b/packages/genui/etc/genui.api.md @@ -36,11 +36,6 @@ export const A2UI: MemoExoticComponent; // @public (undocumented) export const A2UI_PROTOCOL_VERSION = "v0.9"; -// Warning: (ae-missing-release-tag) "A2UI_SYSTEM_PROMPT" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const A2UI_SYSTEM_PROMPT: string; - // Warning: (ae-missing-release-tag) "A2UIClientEventMessage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -197,11 +192,6 @@ export interface ActionProps { surfaceId: string; } -// Warning: (ae-missing-release-tag) "BASIC_CATALOG" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const BASIC_CATALOG: A2UIPromptCatalog; - // Warning: (ae-missing-release-tag) "BASIC_CATALOG_EXAMPLES" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -210,7 +200,7 @@ export const BASIC_CATALOG_EXAMPLES: A2UIExample[]; // Warning: (ae-missing-release-tag) "BASIC_CATALOG_ID" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const BASIC_CATALOG_ID = "https://a2ui.org/specification/v0_9/basic_catalog.json"; +export const BASIC_CATALOG_ID = "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog/catalog.json"; // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -225,7 +215,12 @@ export const basicFunctions: readonly CatalogFunctionEntry[]; // Warning: (ae-missing-release-tag) "buildA2UISystemPrompt" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function buildA2UISystemPrompt(opts?: BuildSystemPromptOptions): string; +export function buildA2UISystemPrompt(opts: BuildSystemPromptOptions): string; + +// Warning: (ae-missing-release-tag) "buildA2UISystemPromptAsync" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function buildA2UISystemPromptAsync(opts?: BuildSystemPromptOptions): Promise; // Warning: (ae-missing-release-tag) "BuildSystemPromptOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -306,7 +301,8 @@ export function createA2UICatalog(options: { // @public (undocumented) export function createA2UICatalogFromManifests(options: { catalogId: string; - componentManifests: Record[]; + componentManifests?: Record[]; + components?: Record; examples?: A2UIExample[]; extraRules?: string[]; functions?: A2UIFunctionSpec[]; @@ -593,6 +589,11 @@ export type LibraryDefinition = LibraryDefinition_2>; export { LibraryJSONSchema } +// Warning: (ae-missing-release-tag) "loadBasicCatalog" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function loadBasicCatalog(): Promise; + // Warning: (ae-missing-release-tag) "MessageProcessor" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1029,6 +1030,8 @@ export function writeCatalogFunctions(functions: CatalogFunction[], options: { // // @public (undocumented) export interface WriteComponentCatalogOptions extends ExtractCatalogOptions { + // (undocumented) + catalogId?: string; // (undocumented) outDir: string; } diff --git a/packages/genui/index.ts b/packages/genui/index.ts index 0ab8d46522..29d27c1bed 100644 --- a/packages/genui/index.ts +++ b/packages/genui/index.ts @@ -59,12 +59,12 @@ export { export * from '@lynx-js/genui/openui'; export { A2UI_PROTOCOL_VERSION, - A2UI_SYSTEM_PROMPT, - BASIC_CATALOG, BASIC_CATALOG_EXAMPLES, BASIC_CATALOG_ID, buildA2UISystemPrompt, + buildA2UISystemPromptAsync, createA2UICatalogFromManifests, + loadBasicCatalog, readA2UICatalogFromDirectory, renderCatalogReference, } from '@lynx-js/genui/a2ui-prompt'; diff --git a/packages/genui/server/agent/a2ui-agent.ts b/packages/genui/server/agent/a2ui-agent.ts index e293b5e6aa..fd1229bcbf 100644 --- a/packages/genui/server/agent/a2ui-agent.ts +++ b/packages/genui/server/agent/a2ui-agent.ts @@ -4,8 +4,8 @@ import { Agent } from '@mastra/core/agent'; -import { BASIC_CATALOG } from './a2ui-catalog'; import type { A2UICatalog } from './a2ui-catalog'; +import { loadBasicCatalog } from './a2ui-catalog'; import { buildA2UISystemPrompt } from './a2ui-prompt'; import { createLLMProvider } from './openai-provider'; import type { OpenAIProviderOptions } from './openai-provider'; @@ -30,10 +30,10 @@ export interface A2UIAgent { ) => unknown; } -export function createA2UIAgent(opts: A2UIAgentOptions = {}) { +export async function createA2UIAgent(opts: A2UIAgentOptions = {}) { const { buildModel, model } = createLLMProvider(opts); - const catalog = opts.catalog ?? BASIC_CATALOG; + const catalog = opts.catalog ?? await loadBasicCatalog(); const promptOptions = { catalog, ...(opts.systemAppendix === undefined diff --git a/packages/genui/server/agent/a2ui-catalog-id.ts b/packages/genui/server/agent/a2ui-catalog-id.ts new file mode 100644 index 0000000000..29e0d4e719 --- /dev/null +++ b/packages/genui/server/agent/a2ui-catalog-id.ts @@ -0,0 +1,6 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +export const BASIC_CATALOG_ID = + 'https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog/catalog.json'; diff --git a/packages/genui/server/agent/a2ui-catalog.ts b/packages/genui/server/agent/a2ui-catalog.ts index 91995f4b02..f765c3c939 100644 --- a/packages/genui/server/agent/a2ui-catalog.ts +++ b/packages/genui/server/agent/a2ui-catalog.ts @@ -2,27 +2,12 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. +import { BASIC_CATALOG_ID } from './a2ui-catalog-id'; import { BASIC_CATALOG_EXAMPLES } from './a2ui-examples'; import type { A2UIExample } from './a2ui-examples'; -import buttonManifest from './catalog/Button/catalog.json'; -import cardManifest from './catalog/Card/catalog.json'; -import checkBoxManifest from './catalog/CheckBox/catalog.json'; -import choicePickerManifest from './catalog/ChoicePicker/catalog.json'; -import columnManifest from './catalog/Column/catalog.json'; -import dateTimeInputManifest from './catalog/DateTimeInput/catalog.json'; -import dividerManifest from './catalog/Divider/catalog.json'; -import iconManifest from './catalog/Icon/catalog.json'; -import imageManifest from './catalog/Image/catalog.json'; -import lineChartManifest from './catalog/LineChart/catalog.json'; -import listManifest from './catalog/List/catalog.json'; -import loadingManifest from './catalog/Loading/catalog.json'; -import modalManifest from './catalog/Modal/catalog.json'; -import radioGroupManifest from './catalog/RadioGroup/catalog.json'; -import rowManifest from './catalog/Row/catalog.json'; -import sliderManifest from './catalog/Slider/catalog.json'; -import tabsManifest from './catalog/Tabs/catalog.json'; -import textManifest from './catalog/Text/catalog.json'; -import textFieldManifest from './catalog/TextField/catalog.json'; +import fallbackCatalogManifest from './catalog/catalog.json'; + +export { BASIC_CATALOG_ID } from './a2ui-catalog-id'; export interface A2UIComponentProp { name: string; @@ -65,9 +50,6 @@ export interface A2UIFunctionSpec { | 'void'; } -export const BASIC_CATALOG_ID = - 'https://a2ui.org/specification/v0_9/basic_catalog.json'; - export interface JsonSchema { type?: string; enum?: unknown; @@ -79,29 +61,14 @@ export interface JsonSchema { additionalProperties?: unknown; } -interface CatalogManifest extends Record {} - -const CATALOG_MANIFESTS = [ - textManifest, - imageManifest, - iconManifest, - dividerManifest, - lineChartManifest, - rowManifest, - columnManifest, - listManifest, - loadingManifest, - cardManifest, - tabsManifest, - modalManifest, - buttonManifest, - textFieldManifest, - checkBoxManifest, - choicePickerManifest, - dateTimeInputManifest, - radioGroupManifest, - sliderManifest, -] as const; +interface ExtractedCatalogManifest { + catalogId?: string; + components?: Record; + functions?: A2UIFunctionSpec[]; +} + +let pendingBasicCatalog: Promise | undefined; +let cachedBasicCatalog: A2UICatalog | undefined; const COMPONENT_SUMMARIES: Record = { Button: @@ -198,10 +165,10 @@ function inferEnums(schema: JsonSchema | undefined): string[] | undefined { return nested.length > 0 ? [...new Set(nested)] : undefined; } -function componentFromManifest( - manifest: CatalogManifest, +function componentFromSchemaEntry( + name: string, + schema: JsonSchema, ): A2UIComponentSpec | null { - const [name, schema] = Object.entries(manifest)[0] ?? []; if (!name || !schema) return null; const properties = isRecord(schema.properties) ? schema.properties : {}; @@ -231,19 +198,26 @@ function componentFromManifest( export function createA2UICatalogFromManifests(options: { catalogId: string; - componentManifests: Record[]; + componentManifests?: Record[]; + components?: Record; examples?: A2UIExample[]; extraRules?: string[]; functions?: A2UIFunctionSpec[]; label?: string; version?: string; }): A2UICatalog { + const components: Record = options.components + ?? (options.componentManifests ?? []).reduce>( + (merged, manifest) => ({ ...merged, ...manifest }), + {}, + ); + return { id: options.catalogId, label: options.label ?? `A2UI catalog (${options.catalogId})`, ...(options.version ? { version: options.version } : {}), - components: options.componentManifests - .map((manifest) => componentFromManifest(manifest as CatalogManifest)) + components: Object.entries(components) + .map(([name, schema]) => componentFromSchemaEntry(name, schema)) .filter((component): component is A2UIComponentSpec => component !== null ), @@ -253,19 +227,89 @@ export function createA2UICatalogFromManifests(options: { }; } -export const BASIC_CATALOG: A2UICatalog = { - id: BASIC_CATALOG_ID, - label: 'Lynx A2UI basic catalog (v0.9)', - version: 'v0.9', - components: CATALOG_MANIFESTS - .map((manifest) => componentFromManifest(manifest as CatalogManifest)) - .filter((component): component is A2UIComponentSpec => component !== null), - extraRules: [ - 'Use only components listed in this catalog; unsupported examples such as Video, AudioPlayer, DatePicker, or Checkbox are not available unless they appear here.', - 'The implemented checkbox component is named "CheckBox" with a capital B.', - ], - examples: BASIC_CATALOG_EXAMPLES, -}; +function createA2UICatalogFromExtractedManifest( + manifest: ExtractedCatalogManifest, +): A2UICatalog { + return createA2UICatalogFromManifests({ + catalogId: manifest.catalogId ?? BASIC_CATALOG_ID, + components: manifest.components ?? {}, + ...(manifest.functions ? { functions: manifest.functions } : {}), + label: 'Lynx A2UI basic catalog (v0.9)', + version: 'v0.9', + extraRules: [ + 'Use only components listed in this catalog; unsupported examples such as Video, AudioPlayer, DatePicker, or Checkbox are not available unless they appear here.', + 'The implemented checkbox component is named "CheckBox" with a capital B.', + ], + examples: BASIC_CATALOG_EXAMPLES, + }); +} + +export async function loadBasicCatalog(): Promise { + if (cachedBasicCatalog) return cachedBasicCatalog; + pendingBasicCatalog ??= fetchBasicCatalog().finally(() => { + pendingBasicCatalog = undefined; + }); + cachedBasicCatalog = await pendingBasicCatalog; + return cachedBasicCatalog; +} + +async function fetchBasicCatalog(): Promise { + try { + const response = await fetch(BASIC_CATALOG_ID, { cache: 'no-store' }); + if (!response.ok) { + throw new Error(`${response.status} ${response.statusText}`); + } + + const manifest = await response.json() as unknown; + if (!isExtractedCatalogManifest(manifest)) { + throw new Error('invalid catalog payload'); + } + return createA2UICatalogFromExtractedManifest(manifest); + } catch (error) { + console.warn( + `[a2ui-catalog] Failed to fetch catalog ${BASIC_CATALOG_ID}; ` + + 'using local fallback catalog.', + error, + ); + } + + return createA2UICatalogFromExtractedManifest( + { + ...(fallbackCatalogManifest as unknown as ExtractedCatalogManifest), + catalogId: BASIC_CATALOG_ID, + }, + ); +} + +function isExtractedCatalogManifest( + value: unknown, +): value is ExtractedCatalogManifest { + if (!isRecord(value)) return false; + const manifest = value as Partial; + const catalogId = manifest.catalogId; + const components = manifest.components; + const functions = manifest.functions; + return (catalogId === undefined || typeof catalogId === 'string') + && (components === undefined || isRecord(components)) + && (functions === undefined || isFunctionSpecs(functions)); +} + +function isFunctionSpecs(value: unknown): value is A2UIFunctionSpec[] { + return Array.isArray(value) && value.every(item => isFunctionSpec(item)); +} + +function isFunctionSpec(value: unknown): value is A2UIFunctionSpec { + if (!isRecord(value)) return false; + const spec = value as Partial; + const name = spec.name; + const parameters = spec.parameters; + const returnType = spec.returnType; + const description = spec.description; + return typeof name === 'string' + && isRecord(parameters) + && typeof returnType === 'string' + && (description === undefined || typeof description === 'string'); +} export function renderCatalogReference(catalog: A2UICatalog): string { const lines: string[] = []; diff --git a/packages/genui/server/agent/a2ui-examples.ts b/packages/genui/server/agent/a2ui-examples.ts index 04eb2f0cae..bc173d530a 100644 --- a/packages/genui/server/agent/a2ui-examples.ts +++ b/packages/genui/server/agent/a2ui-examples.ts @@ -2,15 +2,14 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. +import { BASIC_CATALOG_ID } from './a2ui-catalog-id'; + export interface A2UIExample { name: string; user: string; messages: unknown[]; } -const BASIC_CATALOG_ID = - 'https://a2ui.org/specification/v0_9/basic_catalog.json'; - export const BASIC_CATALOG_EXAMPLES: A2UIExample[] = [ { name: 'login-card', diff --git a/packages/genui/server/agent/a2ui-prompt.ts b/packages/genui/server/agent/a2ui-prompt.ts index 6fad5a2eeb..d27810196c 100644 --- a/packages/genui/server/agent/a2ui-prompt.ts +++ b/packages/genui/server/agent/a2ui-prompt.ts @@ -3,7 +3,7 @@ // LICENSE file in the root directory of this source tree. import type { A2UICatalog } from './a2ui-catalog'; -import { BASIC_CATALOG, renderCatalogReference } from './a2ui-catalog'; +import { loadBasicCatalog, renderCatalogReference } from './a2ui-catalog'; export const A2UI_PROTOCOL_VERSION = 'v0.9'; @@ -177,10 +177,23 @@ export interface BuildSystemPromptOptions { appendix?: string; } +export function buildA2UISystemPrompt(opts: BuildSystemPromptOptions): string; export function buildA2UISystemPrompt( - opts: BuildSystemPromptOptions = {}, + opts?: BuildSystemPromptOptions, ): string { - const catalog = opts.catalog ?? BASIC_CATALOG; + if (!opts) { + throw new Error( + '[a2ui-prompt] buildA2UISystemPrompt requires a catalog. ' + + 'Use buildA2UISystemPromptAsync() to load the basic catalog.', + ); + } + const { catalog } = opts; + if (!catalog) { + throw new Error( + '[a2ui-prompt] buildA2UISystemPrompt requires a catalog. ' + + 'Use buildA2UISystemPromptAsync() to load the basic catalog.', + ); + } const parts = [ 'You are an A2UI (Agent-to-UI) generation agent. Translate the user\'s', 'natural-language request into a stream of A2UI v0.9 JSON messages that a', @@ -201,4 +214,9 @@ export function buildA2UISystemPrompt( return parts.join('\n'); } -export const A2UI_SYSTEM_PROMPT: string = buildA2UISystemPrompt(); +export async function buildA2UISystemPromptAsync( + opts: BuildSystemPromptOptions = {}, +): Promise { + const catalog = opts.catalog ?? await loadBasicCatalog(); + return buildA2UISystemPrompt({ ...opts, catalog }); +} diff --git a/packages/genui/server/agent/catalog/Button/catalog.json b/packages/genui/server/agent/catalog/Button/catalog.json deleted file mode 100644 index bae26f4dde..0000000000 --- a/packages/genui/server/agent/catalog/Button/catalog.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "Button": { - "properties": { - "child": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "borderless" - ] - }, - "isValid": { - "type": "boolean" - }, - "action": { - "oneOf": [ - { - "type": "object", - "properties": { - "event": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "context": { - "type": "object", - "additionalProperties": true, - "description": "Context is a JSON object map in v0.9." - } - }, - "required": [ - "name" - ], - "additionalProperties": false - } - }, - "required": [ - "event" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "functionCall": { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - }, - "required": [ - "functionCall" - ], - "additionalProperties": false - } - ], - "description": "v0.9 actions should use the `event` wrapper for server-dispatched clicks." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ] - }, - "message": { - "type": "string" - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - } - } - }, - "required": [ - "child", - "action" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Card/catalog.json b/packages/genui/server/agent/catalog/Card/catalog.json deleted file mode 100644 index 966fda625f..0000000000 --- a/packages/genui/server/agent/catalog/Card/catalog.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "Card": { - "properties": { - "child": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "elevated", - "outlined", - "filled", - "ghost" - ] - }, - "weight": { - "type": "number" - } - }, - "required": [ - "child" - ] - } -} diff --git a/packages/genui/server/agent/catalog/CheckBox/catalog.json b/packages/genui/server/agent/catalog/CheckBox/catalog.json deleted file mode 100644 index e11548b0ca..0000000000 --- a/packages/genui/server/agent/catalog/CheckBox/catalog.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "CheckBox": { - "properties": { - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ] - }, - "value": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ] - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ] - }, - "message": { - "type": "string" - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - } - } - }, - "required": [ - "label", - "value" - ] - } -} diff --git a/packages/genui/server/agent/catalog/ChoicePicker/catalog.json b/packages/genui/server/agent/catalog/ChoicePicker/catalog.json deleted file mode 100644 index 807339184d..0000000000 --- a/packages/genui/server/agent/catalog/ChoicePicker/catalog.json +++ /dev/null @@ -1,265 +0,0 @@ -{ - "ChoicePicker": { - "properties": { - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The label for the group of options." - }, - "variant": { - "type": "string", - "enum": [ - "multipleSelection", - "mutuallyExclusive" - ], - "description": "A hint for how the choice picker should be displayed and behave." - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The text to display for this option." - }, - "value": { - "type": "string", - "description": "The stable value associated with this option." - } - }, - "required": [ - "label", - "value" - ], - "additionalProperties": false - }, - "description": "The list of available options to choose from." - }, - "value": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The list of currently selected values." - }, - "displayStyle": { - "type": "string", - "enum": [ - "checkbox", - "chips" - ], - "description": "The display style of the component." - }, - "filterable": { - "type": "boolean", - "description": "If true, displays a search input to filter the options." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The condition that indicates whether the check passes." - }, - "message": { - "type": "string", - "description": "The error message to display if the check fails." - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - }, - "description": "A list of checks to perform." - } - }, - "required": [ - "options", - "value" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Column/catalog.json b/packages/genui/server/agent/catalog/Column/catalog.json deleted file mode 100644 index 377bb3ecdb..0000000000 --- a/packages/genui/server/agent/catalog/Column/catalog.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "Column": { - "properties": { - "children": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "componentId": { - "type": "string" - }, - "path": { - "type": "string" - } - }, - "required": [ - "componentId", - "path" - ], - "additionalProperties": false - } - ], - "description": "Static child IDs array or template object." - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "spaceBetween", - "spaceAround", - "spaceEvenly" - ] - } - }, - "required": [ - "children" - ] - } -} diff --git a/packages/genui/server/agent/catalog/DateTimeInput/catalog.json b/packages/genui/server/agent/catalog/DateTimeInput/catalog.json deleted file mode 100644 index c54d7b97e7..0000000000 --- a/packages/genui/server/agent/catalog/DateTimeInput/catalog.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "DateTimeInput": { - "properties": { - "value": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "The current date/time value. Typically bound to a data path." - }, - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The text label for the input field." - }, - "enableDate": { - "type": "boolean", - "description": "Whether to show the date picker." - }, - "enableTime": { - "type": "boolean", - "description": "Whether to show the time picker." - }, - "outputFormat": { - "type": "string", - "description": "Format string for the output value. Supports YYYY, MM, DD, HH, and mm." - }, - "min": { - "type": "string", - "description": "Minimum allowed date/time value." - }, - "max": { - "type": "string", - "description": "Maximum allowed date/time value." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The condition that indicates whether the check passes." - }, - "message": { - "type": "string", - "description": "The error message to display if the check fails." - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - }, - "description": "A list of checks to perform." - } - }, - "required": [ - "value" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Divider/catalog.json b/packages/genui/server/agent/catalog/Divider/catalog.json deleted file mode 100644 index 4dc765578f..0000000000 --- a/packages/genui/server/agent/catalog/Divider/catalog.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Divider": { - "properties": { - "axis": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [] - } -} diff --git a/packages/genui/server/agent/catalog/Icon/catalog.json b/packages/genui/server/agent/catalog/Icon/catalog.json deleted file mode 100644 index 98bb9cf87d..0000000000 --- a/packages/genui/server/agent/catalog/Icon/catalog.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "Icon": { - "properties": { - "name": { - "oneOf": [ - { - "type": "string", - "enum": [ - "account_circle", - "add", - "arrow_back", - "arrow_forward", - "camera", - "check", - "close", - "delete", - "edit", - "error", - "favorite", - "help", - "home", - "info", - "location_on", - "lock", - "mail", - "menu", - "more_vert", - "pause", - "person", - "play_arrow", - "refresh", - "search", - "send", - "settings", - "share", - "star", - "warning" - ] - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "Google Material icon ligature name, e.g. \"info\", \"account_circle\", \"arrow_back\"." - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "color": { - "type": "string", - "enum": [ - "primary", - "muted", - "inherit" - ] - } - }, - "required": [ - "name" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Image/catalog.json b/packages/genui/server/agent/catalog/Image/catalog.json deleted file mode 100644 index 8e8d843b7f..0000000000 --- a/packages/genui/server/agent/catalog/Image/catalog.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "Image": { - "properties": { - "url": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "Image URL or path binding." - }, - "fit": { - "type": "string", - "enum": [ - "contain", - "cover", - "fill", - "none", - "scale-down" - ] - }, - "mode": { - "type": "string", - "enum": [ - "center", - "scaleToFill", - "aspectFit", - "aspectFill" - ] - }, - "variant": { - "type": "string", - "enum": [ - "icon", - "avatar", - "smallFeature", - "mediumFeature", - "largeFeature", - "header" - ] - }, - "weight": { - "type": "number" - } - }, - "required": [ - "url" - ] - } -} diff --git a/packages/genui/server/agent/catalog/LineChart/catalog.json b/packages/genui/server/agent/catalog/LineChart/catalog.json deleted file mode 100644 index d7c880596c..0000000000 --- a/packages/genui/server/agent/catalog/LineChart/catalog.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "LineChart": { - "properties": { - "labels": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "Category labels shown along the x axis." - }, - "series": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "color": { - "type": "string" - } - }, - "required": [ - "name", - "values" - ], - "additionalProperties": false - } - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "One or more line series to render over the shared labels." - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "showGrid": { - "type": "boolean" - }, - "showLegend": { - "type": "boolean" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ] - } -} diff --git a/packages/genui/server/agent/catalog/List/catalog.json b/packages/genui/server/agent/catalog/List/catalog.json deleted file mode 100644 index 4125252039..0000000000 --- a/packages/genui/server/agent/catalog/List/catalog.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "List": { - "properties": { - "children": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "componentId": { - "type": "string" - }, - "path": { - "type": "string" - } - }, - "required": [ - "componentId", - "path" - ], - "additionalProperties": false - } - ], - "description": "Static child IDs array or template object." - }, - "direction": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch" - ] - } - }, - "required": [ - "children" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Loading/catalog.json b/packages/genui/server/agent/catalog/Loading/catalog.json deleted file mode 100644 index 00cb356d9c..0000000000 --- a/packages/genui/server/agent/catalog/Loading/catalog.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Loading": { - "properties": { - "variant": { - "type": "string", - "enum": [ - "inline", - "block" - ] - } - }, - "required": [] - } -} diff --git a/packages/genui/server/agent/catalog/Modal/catalog.json b/packages/genui/server/agent/catalog/Modal/catalog.json deleted file mode 100644 index 4d019b8398..0000000000 --- a/packages/genui/server/agent/catalog/Modal/catalog.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "Modal": { - "properties": { - "trigger": { - "type": "string", - "description": "The ID of the component that opens the modal when interacted with." - }, - "content": { - "type": "string", - "description": "The ID of the component to display inside the modal." - } - }, - "required": [ - "trigger", - "content" - ] - } -} diff --git a/packages/genui/server/agent/catalog/RadioGroup/catalog.json b/packages/genui/server/agent/catalog/RadioGroup/catalog.json deleted file mode 100644 index 9a0d9bede0..0000000000 --- a/packages/genui/server/agent/catalog/RadioGroup/catalog.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "RadioGroup": { - "properties": { - "items": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The list of string options to display." - }, - "value": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The currently selected value." - }, - "usageHint": { - "type": "string", - "enum": [ - "default", - "card", - "row" - ], - "description": "A hint for the visual style of the radio group." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ] - }, - "message": { - "type": "string" - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - } - } - }, - "required": [ - "items", - "value" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Row/catalog.json b/packages/genui/server/agent/catalog/Row/catalog.json deleted file mode 100644 index 4377917d5b..0000000000 --- a/packages/genui/server/agent/catalog/Row/catalog.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "Row": { - "properties": { - "children": { - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "componentId": { - "type": "string" - }, - "path": { - "type": "string" - } - }, - "required": [ - "componentId", - "path" - ], - "additionalProperties": false - } - ], - "description": "Static child IDs array or template object." - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "spaceBetween", - "spaceAround", - "spaceEvenly" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch" - ] - } - }, - "required": [ - "children" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Slider/catalog.json b/packages/genui/server/agent/catalog/Slider/catalog.json deleted file mode 100644 index c0b8a9bd7a..0000000000 --- a/packages/genui/server/agent/catalog/Slider/catalog.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "Slider": { - "properties": { - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The label for the slider." - }, - "min": { - "type": "number", - "description": "The minimum value of the slider." - }, - "max": { - "type": "number", - "description": "The maximum value of the slider." - }, - "value": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The current value of the slider." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "The condition that indicates whether the check passes." - }, - "message": { - "type": "string", - "description": "The error message to display if the check fails." - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - }, - "description": "A list of checks to perform." - } - }, - "required": [ - "max", - "value" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Tabs/catalog.json b/packages/genui/server/agent/catalog/Tabs/catalog.json deleted file mode 100644 index 581ae866af..0000000000 --- a/packages/genui/server/agent/catalog/Tabs/catalog.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "Tabs": { - "properties": { - "tabs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "child": { - "type": "string" - } - }, - "required": [ - "title", - "child" - ], - "additionalProperties": false - } - } - }, - "required": [ - "tabs" - ] - } -} diff --git a/packages/genui/server/agent/catalog/Text/catalog.json b/packages/genui/server/agent/catalog/Text/catalog.json deleted file mode 100644 index 54eca1e997..0000000000 --- a/packages/genui/server/agent/catalog/Text/catalog.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "Text": { - "properties": { - "text": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": true - }, - "returnType": { - "type": "string", - "enum": [ - "string", - "number", - "boolean", - "object", - "array", - "any", - "void" - ] - } - }, - "required": [ - "call", - "args" - ], - "additionalProperties": false - } - ], - "description": "Literal text, path binding, or function call." - }, - "variant": { - "type": "string", - "enum": [ - "h1", - "h2", - "h3", - "h4", - "h5", - "caption", - "body", - "markdown" - ] - }, - "emphasis": { - "type": "string", - "enum": [ - "medium", - "strong" - ] - } - }, - "required": [ - "text" - ] - } -} diff --git a/packages/genui/server/agent/catalog/TextField/catalog.json b/packages/genui/server/agent/catalog/TextField/catalog.json deleted file mode 100644 index 56936d1180..0000000000 --- a/packages/genui/server/agent/catalog/TextField/catalog.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "TextField": { - "properties": { - "label": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "The text label for the input field." - }, - "value": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ], - "description": "The value of the text field." - }, - "variant": { - "type": "string", - "enum": [ - "number", - "longText", - "shortText", - "obscured" - ], - "description": "The type of input field to display." - }, - "validationRegexp": { - "type": "string", - "description": "A regular expression used for client-side validation of the input." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "condition": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "call": { - "type": "string" - }, - "args": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "required": [ - "path" - ], - "additionalProperties": false - } - ] - } - }, - "returnType": { - "type": "string", - "enum": [ - "boolean" - ] - } - }, - "required": [ - "call" - ], - "additionalProperties": false - } - ], - "description": "The condition that indicates whether the check passes." - }, - "message": { - "type": "string", - "description": "The error message to display if the check fails." - } - }, - "required": [ - "condition", - "message" - ], - "additionalProperties": false - }, - "description": "A list of checks to perform." - } - }, - "required": [ - "label" - ] - } -} diff --git a/packages/genui/server/agent/catalog/catalog.json b/packages/genui/server/agent/catalog/catalog.json new file mode 100644 index 0000000000..ca68f3bf10 --- /dev/null +++ b/packages/genui/server/agent/catalog/catalog.json @@ -0,0 +1,2026 @@ +{ + "catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog/catalog.json", + "components": { + "Button": { + "properties": { + "child": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "borderless" + ] + }, + "isValid": { + "type": "boolean" + }, + "action": { + "oneOf": [ + { + "type": "object", + "properties": { + "event": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "context": { + "type": "object", + "additionalProperties": true, + "description": "Context is a JSON object map in v0.9." + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "event" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "functionCall": { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + }, + "required": [ + "functionCall" + ], + "additionalProperties": false + } + ], + "description": "v0.9 actions should use the `event` wrapper for server-dispatched clicks." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + } + } + }, + "required": [ + "child", + "action" + ] + }, + "Card": { + "properties": { + "child": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "elevated", + "outlined", + "filled", + "ghost" + ] + }, + "weight": { + "type": "number" + } + }, + "required": [ + "child" + ] + }, + "CheckBox": { + "properties": { + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ] + }, + "value": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ] + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + } + } + }, + "required": [ + "label", + "value" + ] + }, + "ChoicePicker": { + "properties": { + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The label for the group of options." + }, + "variant": { + "type": "string", + "enum": [ + "multipleSelection", + "mutuallyExclusive" + ], + "description": "A hint for how the choice picker should be displayed and behave." + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The text to display for this option." + }, + "value": { + "type": "string", + "description": "The stable value associated with this option." + } + }, + "required": [ + "label", + "value" + ], + "additionalProperties": false + }, + "description": "The list of available options to choose from." + }, + "value": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The list of currently selected values." + }, + "displayStyle": { + "type": "string", + "enum": [ + "checkbox", + "chips" + ], + "description": "The display style of the component." + }, + "filterable": { + "type": "boolean", + "description": "If true, displays a search input to filter the options." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The condition that indicates whether the check passes." + }, + "message": { + "type": "string", + "description": "The error message to display if the check fails." + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + }, + "description": "A list of checks to perform." + } + }, + "required": [ + "options", + "value" + ] + }, + "Column": { + "properties": { + "children": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "componentId": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "componentId", + "path" + ], + "additionalProperties": false + } + ], + "description": "Static child IDs array or template object." + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "spaceBetween", + "spaceAround", + "spaceEvenly" + ] + } + }, + "required": [ + "children" + ] + }, + "DateTimeInput": { + "properties": { + "value": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "The current date/time value. Typically bound to a data path." + }, + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The text label for the input field." + }, + "enableDate": { + "type": "boolean", + "description": "Whether to show the date picker." + }, + "enableTime": { + "type": "boolean", + "description": "Whether to show the time picker." + }, + "outputFormat": { + "type": "string", + "description": "Format string for the output value. Supports YYYY, MM, DD, HH, and mm." + }, + "min": { + "type": "string", + "description": "Minimum allowed date/time value." + }, + "max": { + "type": "string", + "description": "Maximum allowed date/time value." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The condition that indicates whether the check passes." + }, + "message": { + "type": "string", + "description": "The error message to display if the check fails." + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + }, + "description": "A list of checks to perform." + } + }, + "required": [ + "value" + ] + }, + "Divider": { + "properties": { + "axis": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [] + }, + "Icon": { + "properties": { + "name": { + "oneOf": [ + { + "type": "string", + "enum": [ + "account_circle" + ] + }, + { + "type": "string", + "enum": [ + "add" + ] + }, + { + "type": "string", + "enum": [ + "arrow_back" + ] + }, + { + "type": "string", + "enum": [ + "arrow_forward" + ] + }, + { + "type": "string", + "enum": [ + "camera" + ] + }, + { + "type": "string", + "enum": [ + "check" + ] + }, + { + "type": "string", + "enum": [ + "close" + ] + }, + { + "type": "string", + "enum": [ + "delete" + ] + }, + { + "type": "string", + "enum": [ + "edit" + ] + }, + { + "type": "string", + "enum": [ + "error" + ] + }, + { + "type": "string", + "enum": [ + "favorite" + ] + }, + { + "type": "string", + "enum": [ + "help" + ] + }, + { + "type": "string", + "enum": [ + "home" + ] + }, + { + "type": "string", + "enum": [ + "info" + ] + }, + { + "type": "string", + "enum": [ + "location_on" + ] + }, + { + "type": "string", + "enum": [ + "lock" + ] + }, + { + "type": "string", + "enum": [ + "mail" + ] + }, + { + "type": "string", + "enum": [ + "menu" + ] + }, + { + "type": "string", + "enum": [ + "more_vert" + ] + }, + { + "type": "string", + "enum": [ + "pause" + ] + }, + { + "type": "string", + "enum": [ + "person" + ] + }, + { + "type": "string", + "enum": [ + "play_arrow" + ] + }, + { + "type": "string", + "enum": [ + "refresh" + ] + }, + { + "type": "string", + "enum": [ + "search" + ] + }, + { + "type": "string", + "enum": [ + "send" + ] + }, + { + "type": "string", + "enum": [ + "settings" + ] + }, + { + "type": "string", + "enum": [ + "share" + ] + }, + { + "type": "string", + "enum": [ + "star" + ] + }, + { + "type": "string", + "enum": [ + "warning" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "Google Material icon ligature name, e.g. \"info\", \"account_circle\", \"arrow_back\"." + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "color": { + "type": "string", + "enum": [ + "primary", + "muted", + "inherit" + ] + } + }, + "required": [ + "name" + ] + }, + "Image": { + "properties": { + "url": { + "type": "string", + "description": "Image URL or path binding." + }, + "fit": { + "type": "string", + "enum": [ + "contain", + "cover", + "fill", + "none", + "scale-down" + ] + }, + "mode": { + "type": "string", + "enum": [ + "center", + "scaleToFill", + "aspectFit", + "aspectFill" + ] + }, + "variant": { + "type": "string", + "enum": [ + "icon", + "avatar", + "smallFeature", + "mediumFeature", + "largeFeature", + "header" + ] + }, + "weight": { + "type": "number" + } + }, + "required": [ + "url" + ] + }, + "LineChart": { + "properties": { + "labels": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "Category labels shown along the x axis." + }, + "series": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "color": { + "type": "string" + } + }, + "required": [ + "name", + "values" + ], + "additionalProperties": false + } + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "One or more line series to render over the shared labels." + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "showGrid": { + "type": "boolean" + }, + "showLegend": { + "type": "boolean" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ] + }, + "List": { + "properties": { + "children": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "componentId": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "componentId", + "path" + ], + "additionalProperties": false + } + ], + "description": "Static child IDs array or template object." + }, + "direction": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch" + ] + } + }, + "required": [ + "children" + ] + }, + "Loading": { + "properties": { + "variant": { + "type": "string", + "enum": [ + "inline", + "block" + ], + "description": "Visual density for the skeleton placeholder." + } + }, + "required": [] + }, + "Modal": { + "properties": { + "trigger": { + "type": "string", + "description": "The ID of the component that opens the modal when interacted with." + }, + "content": { + "type": "string", + "description": "The ID of the component to display inside the modal." + } + }, + "required": [ + "trigger", + "content" + ] + }, + "PieChart": { + "properties": { + "data": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "number" + }, + "color": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "additionalProperties": false + } + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "Pie slices to render." + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ], + "description": "Render the chart as a flat pie or a donut." + }, + "title": { + "type": "string", + "description": "Optional title shown above the chart." + }, + "subtitle": { + "type": "string", + "description": "Optional subtitle shown under the title." + }, + "showLegend": { + "type": "boolean", + "description": "Show the legend below the chart." + }, + "showPercentages": { + "type": "boolean", + "description": "Show percentage values in the legend." + }, + "height": { + "type": "number", + "description": "Chart height in pixels." + }, + "paddingAngle": { + "type": "number", + "description": "Padding angle between slices, in degrees." + }, + "colors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Custom color palette for the slices." + } + }, + "required": [ + "data" + ] + }, + "RadioGroup": { + "properties": { + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The list of string options to display." + }, + "value": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The currently selected value." + }, + "usageHint": { + "type": "string", + "enum": [ + "default", + "card", + "row" + ], + "description": "A hint for the visual style of the radio group." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + } + } + }, + "required": [ + "items", + "value" + ] + }, + "Row": { + "properties": { + "children": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "componentId": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "componentId", + "path" + ], + "additionalProperties": false + } + ], + "description": "Static child IDs array or template object." + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "spaceBetween", + "spaceAround", + "spaceEvenly" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch" + ] + } + }, + "required": [ + "children" + ] + }, + "Slider": { + "properties": { + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The label for the slider." + }, + "min": { + "type": "number", + "description": "The minimum value of the slider." + }, + "max": { + "type": "number", + "description": "The maximum value of the slider." + }, + "value": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The current value of the slider." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "The condition that indicates whether the check passes." + }, + "message": { + "type": "string", + "description": "The error message to display if the check fails." + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + }, + "description": "A list of checks to perform." + } + }, + "required": [ + "max", + "value" + ] + }, + "Tabs": { + "properties": { + "tabs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "child": { + "type": "string" + } + }, + "required": [ + "title", + "child" + ], + "additionalProperties": false + } + } + }, + "required": [ + "tabs" + ] + }, + "Text": { + "properties": { + "text": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": true + }, + "returnType": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "any", + "void" + ] + } + }, + "required": [ + "call", + "args" + ], + "additionalProperties": false + } + ], + "description": "Literal text, path binding, or function call." + }, + "variant": { + "type": "string", + "enum": [ + "h1", + "h2", + "h3", + "h4", + "h5", + "caption", + "body", + "markdown" + ] + }, + "emphasis": { + "type": "string", + "enum": [ + "medium", + "strong" + ] + } + }, + "required": [ + "text" + ] + }, + "TextField": { + "properties": { + "label": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "The text label for the input field." + }, + "value": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ], + "description": "The value of the text field." + }, + "variant": { + "type": "string", + "enum": [ + "number", + "longText", + "shortText", + "obscured" + ], + "description": "The type of input field to display." + }, + "validationRegexp": { + "type": "string", + "description": "A regular expression used for client-side validation of the input." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "condition": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "call": { + "type": "string" + }, + "args": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + } + ] + } + }, + "returnType": { + "type": "string", + "enum": [ + "boolean" + ] + } + }, + "required": [ + "call" + ], + "additionalProperties": false + } + ], + "description": "The condition that indicates whether the check passes." + }, + "message": { + "type": "string", + "description": "The error message to display if the check fails." + } + }, + "required": [ + "condition", + "message" + ], + "additionalProperties": false + }, + "description": "A list of checks to perform." + } + }, + "required": [ + "label" + ] + } + }, + "functions": [] +} diff --git a/packages/genui/server/app/a2ui/action/stream/route.ts b/packages/genui/server/app/a2ui/action/stream/route.ts index 260e63f300..0d32924777 100644 --- a/packages/genui/server/app/a2ui/action/stream/route.ts +++ b/packages/genui/server/app/a2ui/action/stream/route.ts @@ -3,7 +3,7 @@ // LICENSE file in the root directory of this source tree. import type { A2UICatalog } from '../../../../agent/a2ui-catalog'; -import { BASIC_CATALOG } from '../../../../agent/a2ui-catalog'; +import { loadBasicCatalog } from '../../../../agent/a2ui-catalog'; import { A2UIProtocolMessageStreamParser, splitA2UIProtocolMessages, @@ -197,6 +197,15 @@ export async function POST(req: Request) { log(event, details); }, }; + let catalog: A2UICatalog; + try { + catalog = opts.catalog ?? await loadBasicCatalog(); + } catch (err: unknown) { + const error = errorMessage(err); + log('catalog.load.failed', error); + return jsonWithCors(req, { ok: false, error }, { status: 502 }); + } + const optsWithCatalog = { ...opts, catalog }; log('request.accepted', { surfaceId: body.surfaceId, @@ -215,7 +224,7 @@ export async function POST(req: Request) { userContentLength: userContent.length, model: opts.model, hasBaseURL: Boolean(opts.baseURL), - catalogId: opts.catalog?.id ?? BASIC_CATALOG.id, + catalogId: catalog.id, maxRepairAttempts: opts.maxRepairAttempts, }); @@ -250,7 +259,7 @@ export async function POST(req: Request) { log('agent.connect.started'); const { textStream, finalize } = await service.streamAsAsyncIterable( [userMessage], - opts, + optsWithCatalog, validatedConversation.conversation, ); log('agent.connect.completed', { @@ -330,7 +339,7 @@ export async function POST(req: Request) { }; const v = validateA2UIOutput( finalText ?? '', - opts.catalog ?? BASIC_CATALOG, + catalog, validationOptions, ); let resolvedMessages = v.ok @@ -357,7 +366,7 @@ export async function POST(req: Request) { }); const repaired = await service.generateValidated( [userMessage], - opts, + optsWithCatalog, validatedConversation.conversation, validationOptions, ); diff --git a/packages/genui/server/app/a2ui/stream/route.ts b/packages/genui/server/app/a2ui/stream/route.ts index f2bd9434e2..b87f345d9d 100644 --- a/packages/genui/server/app/a2ui/stream/route.ts +++ b/packages/genui/server/app/a2ui/stream/route.ts @@ -2,7 +2,7 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. -import { BASIC_CATALOG } from '../../../agent/a2ui-catalog'; +import { loadBasicCatalog } from '../../../agent/a2ui-catalog'; import { A2UIProtocolMessageStreamParser, splitA2UIProtocolMessages, @@ -140,6 +140,15 @@ export async function POST(req: Request) { log(event, details); }, }; + let catalog: A2UIChatBody['catalog']; + try { + catalog = opts.catalog ?? await loadBasicCatalog(); + } catch (err: unknown) { + const error = errorMessage(err); + log('catalog.load.failed', error); + return jsonWithCors(req, { ok: false, error }, { status: 502 }); + } + const optsWithCatalog = { ...opts, catalog }; const service = getA2UIAgentService(); log('request.accepted', { @@ -160,7 +169,7 @@ export async function POST(req: Request) { : 0, model: opts.model, hasBaseURL: Boolean(opts.baseURL), - catalogId: opts.catalog?.id ?? BASIC_CATALOG.id, + catalogId: catalog.id, maxRepairAttempts: opts.maxRepairAttempts, }); @@ -195,7 +204,7 @@ export async function POST(req: Request) { log('agent.connect.started'); const { textStream, finalize } = await service.streamAsAsyncIterable( messages, - opts, + optsWithCatalog, validatedConversation.conversation, ); log('agent.connect.completed', { @@ -265,7 +274,7 @@ export async function POST(req: Request) { }; const v = validateA2UIOutput( finalText ?? '', - opts.catalog ?? BASIC_CATALOG, + catalog, ); let resolvedMessages = v.ok ? await resolveMessagesForStreaming(v.messages) @@ -291,7 +300,7 @@ export async function POST(req: Request) { }); const repaired = await service.generateValidated( messages, - opts, + optsWithCatalog, validatedConversation.conversation, ); repair = { diff --git a/packages/genui/server/service/a2ui-agent.ts b/packages/genui/server/service/a2ui-agent.ts index 9daa220da9..59fb29643c 100644 --- a/packages/genui/server/service/a2ui-agent.ts +++ b/packages/genui/server/service/a2ui-agent.ts @@ -6,8 +6,8 @@ import { createHash } from 'node:crypto'; import { createA2UIAgent } from '../agent/a2ui-agent'; import type { A2UIAgent } from '../agent/a2ui-agent'; -import { BASIC_CATALOG } from '../agent/a2ui-catalog'; import type { A2UICatalog } from '../agent/a2ui-catalog'; +import { loadBasicCatalog } from '../agent/a2ui-catalog'; import { formatErrorsForModel, validateA2UIOutput, @@ -103,11 +103,12 @@ function sumContentChars(messages: ChatMessage[]): number { export default class A2UIAgentService { private agentCache = new Map>(); - private getAgent(opts: ChatOptions): Promise { + private async getAgent(opts: ChatOptions): Promise { const startedAt = performance.now(); + const catalog = opts.catalog ?? await loadBasicCatalog(); const cacheKey = `${opts.baseURL ?? 'default'}:${opts.model ?? 'default'}:${ hashApiKey(opts.apiKey) - }:${opts.catalog?.id ?? 'basic'}`; + }:${catalog.id}`; let cached = this.agentCache.get(cacheKey); if (cached) { opts.onPerformanceEvent?.('agent.cache.hit', { @@ -117,14 +118,12 @@ export default class A2UIAgentService { return cached; } - cached = Promise.resolve( - createA2UIAgent(pickDefined({ - apiKey: opts.apiKey, - baseURL: opts.baseURL, - model: opts.model, - catalog: opts.catalog, - })).agent, - ); + cached = createA2UIAgent(pickDefined({ + apiKey: opts.apiKey, + baseURL: opts.baseURL, + model: opts.model, + catalog, + })).then(({ agent }) => agent); this.agentCache.set(cacheKey, cached); opts.onPerformanceEvent?.('agent.cache.miss', { durationMs: performance.now() - startedAt, @@ -274,7 +273,7 @@ export default class A2UIAgentService { conversation?: ConversationContext, validationOptions?: ValidationOptions, ): Promise { - const catalog = opts.catalog ?? BASIC_CATALOG; + const catalog = opts.catalog ?? await loadBasicCatalog(); const maxAttempts = Math.max(1, opts.maxRepairAttempts ?? 2) + 1; const agent = await this.getAgent({ ...opts, catalog });