Skip to content

feat(a2ui): load server catalog from cdn#2778

Open
Sherry-hue wants to merge 1 commit into
lynx-family:mainfrom
Sherry-hue:feat/a2ui-server-cdn-catalog
Open

feat(a2ui): load server catalog from cdn#2778
Sherry-hue wants to merge 1 commit into
lynx-family:mainfrom
Sherry-hue:feat/a2ui-server-cdn-catalog

Conversation

@Sherry-hue
Copy link
Copy Markdown
Collaborator

@Sherry-hue Sherry-hue commented Jun 3, 2026

Summary by CodeRabbit

  • New Features

    • Added buildA2UISystemPromptAsync() for asynchronous system prompt generation.
    • Added loadBasicCatalog() for dynamic catalog loading.
  • Breaking Changes

    • buildA2UISystemPrompt() now requires options parameter (no longer optional).
    • Removed static exports: A2UI_SYSTEM_PROMPT and BASIC_CATALOG constants.
    • Catalog is now dynamically loaded instead of bundled.
  • Updates

    • Catalog source URL updated from a2ui.org to unpkg.com.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 3, 2026

⚠️ No Changeset found

Latest commit: 7a5d69c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR migrates GenUI's basic catalog from static/synchronous imports to dynamic asynchronous fetching with local fallback. It consolidates per-component catalog JSON definitions into a single remotely-hosted catalog.json file, introduces type-validated async catalog loading, refactors the prompt building API to support both sync and async patterns, and updates all consumers (routes, CLI, services) to load catalogs on demand.

Changes

Async Catalog Loading and Consolidation

Layer / File(s) Summary
Catalog loading infrastructure and extraction
packages/genui/server/agent/a2ui-catalog-id.ts, packages/genui/server/agent/a2ui-catalog.ts, packages/genui/server/agent/catalog/catalog.json
New a2ui-catalog-id.ts exports the catalog URL constant. a2ui-catalog.ts refactors to define ExtractedCatalogManifest type shape, replace componentFromManifest with componentFromSchemaEntry, update createA2UICatalogFromManifests to accept optional components or componentManifests, add async loadBasicCatalog() with caching and fetchBasicCatalog() with type-guard validation (isExtractedCatalogManifest, isFunctionSpecs, isFunctionSpec) plus local fallback. Consolidated component schemas are defined in a new unified catalog.json artifact.
Build configuration updates
packages/genui/a2ui-prompt/tsconfig.json, packages/genui/a2ui-prompt/tsconfig.build.json, packages/genui/a2ui-prompt/turbo.json, packages/genui/server/agent/a2ui-examples.ts
TypeScript and Turbo build configuration updated to include a2ui-catalog-id.ts in project inputs and task dependencies. a2ui-examples.ts imports BASIC_CATALOG_ID from the new module instead of defining it locally.
Async prompt building API
packages/genui/server/agent/a2ui-prompt.ts
buildA2UISystemPrompt refactored to require an explicit catalog option (no longer defaults to built-in). New buildA2UISystemPromptAsync function added that loads the basic catalog via loadBasicCatalog() when not provided and then calls buildA2UISystemPrompt with the resolved catalog. Removed the prior A2UI_SYSTEM_PROMPT export.
Public API and export surface updates
packages/genui/a2ui-prompt/README.md, packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md, packages/genui/etc/genui.api.md, packages/genui/index.ts
API reports and documentation updated to reflect removal of A2UI_SYSTEM_PROMPT and BASIC_CATALOG exports, introduction of A2UI_PROTOCOL_VERSION constant, BASIC_CATALOG_ID URL change to unpkg, buildA2UISystemPrompt signature change (catalog now required), addition of buildA2UISystemPromptAsync, and new loadBasicCatalog() function. createA2UICatalogFromManifests options made more flexible. Re-exports in index.ts updated accordingly. README example updated to use async API.
Agent factory and service integration
packages/genui/server/agent/a2ui-agent.ts, packages/genui/server/service/a2ui-agent.ts
createA2UIAgent converted to async function that awaits loadBasicCatalog() when opts.catalog is absent. Service agent getAgent method made async and now resolves catalog dynamically; cache key depends on resolved catalog id. generateValidated similarly updated to await dynamic catalog loading when needed.
Route handler and CLI integration
packages/genui/cli/bin/cli.js, packages/genui/server/app/a2ui/action/stream/route.ts, packages/genui/server/app/a2ui/stream/route.ts
CLI runGeneratePromptCli and both stream route handlers updated to call loadBasicCatalog() when opts.catalog is absent. Catalog loading wrapped in try/catch; failures return CORS 502 JSON error. Resolved catalog threaded through service calls via optsWithCatalog to ensure validation and generation use the loaded catalog consistently. Removed BASIC_CATALOG imports and replaced with loadBasicCatalog.
Catalog file consolidation
packages/genui/server/agent/catalog/Button/, packages/genui/server/agent/catalog/Card/, ... packages/genui/server/agent/catalog/TextField/
Deleted per-component catalog.json files for Button, Card, CheckBox, ChoicePicker, Column, DateTimeInput, Divider, Icon, Image, LineChart, List, Loading, Modal, RadioGroup, Row, Slider, Tabs, Text, TextField. These component schemas are now consolidated in the unified catalog/catalog.json file.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • lynx-family/lynx-stack#2718: Modifies BASIC_CATALOG construction by adding DateTimeInput—directly related to the catalog refactoring in this PR.
  • lynx-family/lynx-stack#2709: Updates the /a2ui/stream route handler—overlaps with this PR's changes to the same route for dynamic catalog loading and SSE flow.

Suggested reviewers

  • PupilTong
  • gaoachao
  • HuJean

🐰 A rabbit hops through async lands,
Where catalogs load when pages stand,
No static imports in sight—just light,
Dynamic promises made it right, 🎯
Now every prompt knows the catalog's might!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(a2ui): load server catalog from cdn' accurately describes the main change—the PR shifts catalog loading from compile-time constants to dynamic runtime loading from a CDN, which is the central theme across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Sherry-hue Sherry-hue marked this pull request as ready for review June 3, 2026 06:45
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/genui/server/agent/a2ui-prompt.ts (1)

175-196: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the sync prompt builder require catalog in its type.

buildA2UISystemPrompt now throws whenever opts.catalog is absent, but BuildSystemPromptOptions still marks catalog as optional. That means buildA2UISystemPrompt({}) still passes type-checking and only fails at runtime for external consumers. Tighten the sync API to a catalog-required options type and keep the async helper as the no-catalog entrypoint.

Proposed fix
 export interface BuildSystemPromptOptions {
   catalog?: A2UICatalog;
   appendix?: string;
 }
 
-export function buildA2UISystemPrompt(opts: BuildSystemPromptOptions): string;
+export interface BuildSystemPromptWithCatalogOptions
+  extends BuildSystemPromptOptions {
+  catalog: A2UICatalog;
+}
+
+export function buildA2UISystemPrompt(
+  opts: BuildSystemPromptWithCatalogOptions,
+): string;
 export function buildA2UISystemPrompt(
-  opts?: BuildSystemPromptOptions,
+  opts?: BuildSystemPromptWithCatalogOptions,
 ): string {
   if (!opts) {
     throw new Error(
       '[a2ui-prompt] buildA2UISystemPrompt requires a catalog. '
         + 'Use buildA2UISystemPromptAsync() to load the basic catalog.',
@@
 export async function buildA2UISystemPromptAsync(
   opts: BuildSystemPromptOptions = {},
 ): Promise<string> {
   const catalog = opts.catalog ?? await loadBasicCatalog();
   return buildA2UISystemPrompt({ ...opts, catalog });
 }
Based on learnings: when editing exported functions or constants reachable through the a2ui-prompt package, use explicit types for exported APIs because `isolatedDeclarations` requires them.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/server/agent/a2ui-prompt.ts` around lines 175 - 196, The sync
API's options type must require a catalog: update BuildSystemPromptOptions to
make the catalog property non-optional (remove the ?), and adjust any exported
overload/signature of buildA2UISystemPrompt to accept that required type; keep
the existing buildA2UISystemPromptAsync as the no-catalog entrypoint for callers
who don't have a catalog, and ensure exported function signatures remain
explicit to satisfy isolatedDeclarations.
packages/genui/server/service/a2ui-agent.ts (1)

108-127: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid caching caller-supplied catalogs by id alone.

The stream/action routes pass request-scoped catalog objects into this service, but this key only distinguishes them by catalog.id. Two different catalogs with the same id will reuse the same cached agent prompt, while generateValidated() still validates against the current request's catalog. That can produce stale instructions and false validation failures on a valid request path. Either hash the full catalog for custom inputs or bypass caching when opts.catalog is provided.

Suggested fix
   private async getAgent(opts: ChatOptions): Promise<A2UIAgent> {
     const startedAt = performance.now();
     const catalog = opts.catalog ?? await loadBasicCatalog();
-    const cacheKey = `${opts.baseURL ?? 'default'}:${opts.model ?? 'default'}:${
-      hashApiKey(opts.apiKey)
-    }:${catalog.id}`;
-    let cached = this.agentCache.get(cacheKey);
+    const cacheKey = opts.catalog
+      ? undefined
+      : `${opts.baseURL ?? 'default'}:${opts.model ?? 'default'}:${
+          hashApiKey(opts.apiKey)
+        }:${catalog.id}`;
+    let cached = cacheKey ? this.agentCache.get(cacheKey) : undefined;
     if (cached) {
       opts.onPerformanceEvent?.('agent.cache.hit', {
         durationMs: performance.now() - startedAt,
         cacheSize: this.agentCache.size,
       });
@@
     cached = createA2UIAgent(pickDefined({
       apiKey: opts.apiKey,
       baseURL: opts.baseURL,
       model: opts.model,
       catalog,
     })).then(({ agent }) => agent);
-    this.agentCache.set(cacheKey, cached);
+    if (cacheKey) {
+      this.agentCache.set(cacheKey, cached);
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/server/service/a2ui-agent.ts` around lines 108 - 127, The
current cacheKey for agentCache only includes catalog.id which lets
caller-supplied catalogs with identical ids reuse cached agents; update the
logic in the function that builds cacheKey (the block that references catalog,
hashApiKey, loadBasicCatalog, and createA2UIAgent) to either (a) bypass caching
when opts.catalog is explicitly provided by the caller, or (b) include a
deterministic hash of the full catalog object (not just catalog.id) in cacheKey
so different catalog contents produce different keys; ensure the rest of the
flow (creating cached via createA2UIAgent and storing in agentCache) remains
consistent with the chosen approach and that generateValidated continues to
validate against the request's catalog.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/genui/server/agent/a2ui-catalog-id.ts`:
- Around line 5-6: BASIC_CATALOG_ID currently points to an unversioned unpkg URL
that will move as new `@lynx-js/genui` releases are published; change
BASIC_CATALOG_ID to reference a versioned immutable asset (for example the same
unpkg URL but including the package version like
'https://unpkg.com/@lynx-js/genui@<version>/a2ui/dist/catalog/catalog.json' or a
build-time substituted artifact URL from your CI/artifacts store) so the shipped
server always loads the catalog that matches the shipped code; update the
constant BASIC_CATALOG_ID accordingly and, if applicable, wire it to read the
package version (package.json) or a build environment variable used during
release to ensure it is pinned per build.

In `@packages/genui/server/agent/a2ui-catalog.ts`:
- Around line 256-274: Add a deadline to the CDN fetch in fetchBasicCatalog by
using an AbortController: create an AbortController, pass its signal to
fetch(BASIC_CATALOG_ID, { signal, cache: 'no-store' }), set a short timeout
(e.g., 2–5s) to call controller.abort(), and clear the timer on success; catch
the abort/FetchError the same as other errors so the function falls back to
returning the local catalog (keep existing isExtractedCatalogManifest and
createA2UICatalogFromExtractedManifest logic). Ensure the timer is cleared on
both success and error to avoid leaks and that aborted fetches are handled in
the existing catch block.
- Around line 301-312: isFunctionSpec currently accepts any string for
spec.returnType; change it to reject unknown returnType values by validating
against the allowed union members instead of just typeof string. Update the
returnType check in isFunctionSpec (and/or add a small helper like
isA2UIReturnType) to test membership against the canonical set of allowed return
types (e.g., the union or enum used for A2UIFunctionSpec.returnType) and only
return true if returnType is one of those values; keep the existing checks for
name, parameters, and description unchanged.

---

Outside diff comments:
In `@packages/genui/server/agent/a2ui-prompt.ts`:
- Around line 175-196: The sync API's options type must require a catalog:
update BuildSystemPromptOptions to make the catalog property non-optional
(remove the ?), and adjust any exported overload/signature of
buildA2UISystemPrompt to accept that required type; keep the existing
buildA2UISystemPromptAsync as the no-catalog entrypoint for callers who don't
have a catalog, and ensure exported function signatures remain explicit to
satisfy isolatedDeclarations.

In `@packages/genui/server/service/a2ui-agent.ts`:
- Around line 108-127: The current cacheKey for agentCache only includes
catalog.id which lets caller-supplied catalogs with identical ids reuse cached
agents; update the logic in the function that builds cacheKey (the block that
references catalog, hashApiKey, loadBasicCatalog, and createA2UIAgent) to either
(a) bypass caching when opts.catalog is explicitly provided by the caller, or
(b) include a deterministic hash of the full catalog object (not just
catalog.id) in cacheKey so different catalog contents produce different keys;
ensure the rest of the flow (creating cached via createA2UIAgent and storing in
agentCache) remains consistent with the chosen approach and that
generateValidated continues to validate against the request's catalog.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3ccecb60-1b43-40b9-ac5c-ebf58dbcff95

📥 Commits

Reviewing files that changed from the base of the PR and between a3e4607 and 7a5d69c.

📒 Files selected for processing (36)
  • packages/genui/a2ui-prompt/README.md
  • packages/genui/a2ui-prompt/etc/genui-a2ui-prompt.api.md
  • packages/genui/a2ui-prompt/tsconfig.build.json
  • packages/genui/a2ui-prompt/tsconfig.json
  • packages/genui/a2ui-prompt/turbo.json
  • packages/genui/cli/bin/cli.js
  • packages/genui/etc/genui.api.md
  • packages/genui/index.ts
  • packages/genui/server/agent/a2ui-agent.ts
  • packages/genui/server/agent/a2ui-catalog-id.ts
  • packages/genui/server/agent/a2ui-catalog.ts
  • packages/genui/server/agent/a2ui-examples.ts
  • packages/genui/server/agent/a2ui-prompt.ts
  • packages/genui/server/agent/catalog/Button/catalog.json
  • packages/genui/server/agent/catalog/Card/catalog.json
  • packages/genui/server/agent/catalog/CheckBox/catalog.json
  • packages/genui/server/agent/catalog/ChoicePicker/catalog.json
  • packages/genui/server/agent/catalog/Column/catalog.json
  • packages/genui/server/agent/catalog/DateTimeInput/catalog.json
  • packages/genui/server/agent/catalog/Divider/catalog.json
  • packages/genui/server/agent/catalog/Icon/catalog.json
  • packages/genui/server/agent/catalog/Image/catalog.json
  • packages/genui/server/agent/catalog/LineChart/catalog.json
  • packages/genui/server/agent/catalog/List/catalog.json
  • packages/genui/server/agent/catalog/Loading/catalog.json
  • packages/genui/server/agent/catalog/Modal/catalog.json
  • packages/genui/server/agent/catalog/RadioGroup/catalog.json
  • packages/genui/server/agent/catalog/Row/catalog.json
  • packages/genui/server/agent/catalog/Slider/catalog.json
  • packages/genui/server/agent/catalog/Tabs/catalog.json
  • packages/genui/server/agent/catalog/Text/catalog.json
  • packages/genui/server/agent/catalog/TextField/catalog.json
  • packages/genui/server/agent/catalog/catalog.json
  • packages/genui/server/app/a2ui/action/stream/route.ts
  • packages/genui/server/app/a2ui/stream/route.ts
  • packages/genui/server/service/a2ui-agent.ts
💤 Files with no reviewable changes (19)
  • packages/genui/server/agent/catalog/Icon/catalog.json
  • packages/genui/server/agent/catalog/Divider/catalog.json
  • packages/genui/server/agent/catalog/ChoicePicker/catalog.json
  • packages/genui/server/agent/catalog/CheckBox/catalog.json
  • packages/genui/server/agent/catalog/Text/catalog.json
  • packages/genui/server/agent/catalog/TextField/catalog.json
  • packages/genui/server/agent/catalog/Tabs/catalog.json
  • packages/genui/server/agent/catalog/DateTimeInput/catalog.json
  • packages/genui/server/agent/catalog/Image/catalog.json
  • packages/genui/server/agent/catalog/List/catalog.json
  • packages/genui/server/agent/catalog/Slider/catalog.json
  • packages/genui/server/agent/catalog/Row/catalog.json
  • packages/genui/server/agent/catalog/Loading/catalog.json
  • packages/genui/server/agent/catalog/Column/catalog.json
  • packages/genui/server/agent/catalog/Card/catalog.json
  • packages/genui/server/agent/catalog/LineChart/catalog.json
  • packages/genui/server/agent/catalog/Button/catalog.json
  • packages/genui/server/agent/catalog/RadioGroup/catalog.json
  • packages/genui/server/agent/catalog/Modal/catalog.json

Comment on lines +5 to +6
export const BASIC_CATALOG_ID =
'https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog/catalog.json';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin BASIC_CATALOG_ID to an immutable artifact.

This URL tracks the latest published @lynx-js/genui package on unpkg, so a future release can change the basic catalog without any server deploy. That breaks the contract between the shipped prompt/examples code and the remotely loaded schema. Please point this at a versioned asset (or another immutable same-build artifact) instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/server/agent/a2ui-catalog-id.ts` around lines 5 - 6,
BASIC_CATALOG_ID currently points to an unversioned unpkg URL that will move as
new `@lynx-js/genui` releases are published; change BASIC_CATALOG_ID to reference
a versioned immutable asset (for example the same unpkg URL but including the
package version like
'https://unpkg.com/@lynx-js/genui@<version>/a2ui/dist/catalog/catalog.json' or a
build-time substituted artifact URL from your CI/artifacts store) so the shipped
server always loads the catalog that matches the shipped code; update the
constant BASIC_CATALOG_ID accordingly and, if applicable, wire it to read the
package version (package.json) or a build environment variable used during
release to ensure it is pinned per build.

Comment on lines +256 to +274
async function fetchBasicCatalog(): Promise<A2UICatalog> {
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,
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout around the CDN fetch.

loadBasicCatalog() is awaited from request-time paths, so this unbounded fetch() can hold the whole request open until the platform times out if the CDN connection hangs. Please abort after a short deadline so the code falls back to catalog.json promptly instead of turning a transient CDN issue into a request outage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/server/agent/a2ui-catalog.ts` around lines 256 - 274, Add a
deadline to the CDN fetch in fetchBasicCatalog by using an AbortController:
create an AbortController, pass its signal to fetch(BASIC_CATALOG_ID, { signal,
cache: 'no-store' }), set a short timeout (e.g., 2–5s) to call
controller.abort(), and clear the timer on success; catch the abort/FetchError
the same as other errors so the function falls back to returning the local
catalog (keep existing isExtractedCatalogManifest and
createA2UICatalogFromExtractedManifest logic). Ensure the timer is cleared on
both success and error to avoid leaks and that aborted fetches are handled in
the existing catch block.

Comment on lines +301 to +312
function isFunctionSpec(value: unknown): value is A2UIFunctionSpec {
if (!isRecord(value)) return false;
const spec = value as Partial<A2UIFunctionSpec>;
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');
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject unknown returnType values during manifest validation.

isFunctionSpec() accepts any string here, so a payload like { returnType: "date" } still passes isExtractedCatalogManifest() and bypasses the local fallback. That weakens the new “validated fetch” path and can leak unsupported function signatures into prompt generation. Constrain this check to the allowed union members before accepting the manifest.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/genui/server/agent/a2ui-catalog.ts` around lines 301 - 312,
isFunctionSpec currently accepts any string for spec.returnType; change it to
reject unknown returnType values by validating against the allowed union members
instead of just typeof string. Update the returnType check in isFunctionSpec
(and/or add a small helper like isA2UIReturnType) to test membership against the
canonical set of allowed return types (e.g., the union or enum used for
A2UIFunctionSpec.returnType) and only return true if returnType is one of those
values; keep the existing checks for name, parameters, and description
unchanged.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jun 3, 2026

Merging this PR will not alter performance

✅ 83 untouched benchmarks
⏩ 26 skipped benchmarks1


Comparing Sherry-hue:feat/a2ui-server-cdn-catalog (7a5d69c) with main (b9d0624)2

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (a3e4607) during the generation of this report, so b9d0624 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant