feat(a2ui): add catalog example, json valid, stream repair#2686
Conversation
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds catalog examples and per-prop JsonSchema to the A2UI catalog, renders catalog examples into the system prompt, implements catalog-driven component/schema validation with wildcard path matching, and adds a repair/regeneration workflow to SSE stream handlers that attempts to regenerate invalid model outputs. ChangesA2UI Examples, Validation, and Repair Workflows
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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-validator.ts`:
- Around line 409-421: The isPathCovered function does pure prefix string checks
and thus misses wildcard segment semantics (e.g., referencedPath "/items/*/name"
should match providedPath "/items/0/name"); update isPathCovered to split
referencedPath and providedPath into path segments (normalize leading/trailing
slashes), then compare segment-by-segment: treat a segment equal if they are
identical or either segment is the wildcard "*" (match single segment), and
allow coverage when all segments match or when one path is a prefix of the other
with remaining segments being empty; use the function name isPathCovered and the
referencedPath/providedPath parameters to locate and replace the current logic.
- Around line 579-585: The object branch in the switch (case 'object') currently
uses isRecord(value) which treats arrays as records; change the check to
explicitly reject arrays (e.g., add an Array.isArray check) or update isRecord
to return false for arrays so arrays no longer pass type: "object" validation;
ensure the logic in the case 'object' (and subsequent call to
validateObjectAgainstSchema) only runs for true plain objects and not for
arrays.
🪄 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: ef72c936-4bf3-4a77-9e19-989b82ada49b
📒 Files selected for processing (7)
packages/genui/server/.npmrcpackages/genui/server/agent/a2ui-catalog.tspackages/genui/server/agent/a2ui-examples.tspackages/genui/server/agent/a2ui-prompt.tspackages/genui/server/agent/a2ui-validator.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/stream/route.ts
1d7284c to
3794e14
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/genui/server/app/a2ui/action/stream/route.ts (1)
142-150: 💤 Low valueConsider extracting shared repair type.
The
repairobject type is defined identically in both route files. Extracting to a shared type in_shared.tswould reduce duplication and ensure consistency.// In _shared.ts export interface RepairResult { attempted: true; sourceErrors: string[]; ok: boolean; attempts: number; }Also applies to: 95-102
🤖 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/app/a2ui/action/stream/route.ts` around lines 142 - 150, The inline union type for the local variable repair is duplicated and should be extracted to a shared interface; create an exported interface RepairResult (fields: attempted: true, sourceErrors: string[], ok: boolean, attempts: number) in _shared.ts, import it into this route (packages/genui/server/app/a2ui/action/stream/route.ts) and replace the local inline type declaration for repair with RepairResult | undefined, and do the same replacement in the other route file where the same type appears (lines referenced 95-102) to remove duplication and ensure consistency.
🤖 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-prompt.ts`:
- Line 74: Update the prompt text in a2ui-prompt.ts so the overview and the
example use the same canonical wording for list bindings: replace references to
a “template object” with the explicit shape children: { path, componentId } (or
explicitly document both allowed forms), and ensure the JSON example
("children": { "path": "/items", "componentId": "itemRow" }) and any description
of children-binding use identical terminology and field names so the model
receives a single, consistent spec.
---
Nitpick comments:
In `@packages/genui/server/app/a2ui/action/stream/route.ts`:
- Around line 142-150: The inline union type for the local variable repair is
duplicated and should be extracted to a shared interface; create an exported
interface RepairResult (fields: attempted: true, sourceErrors: string[], ok:
boolean, attempts: number) in _shared.ts, import it into this route
(packages/genui/server/app/a2ui/action/stream/route.ts) and replace the local
inline type declaration for repair with RepairResult | undefined, and do the
same replacement in the other route file where the same type appears (lines
referenced 95-102) to remove duplication and ensure consistency.
🪄 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: ce19da09-4df3-464d-bba3-c81445da6658
📒 Files selected for processing (7)
packages/genui/server/.npmrcpackages/genui/server/agent/a2ui-catalog.tspackages/genui/server/agent/a2ui-examples.tspackages/genui/server/agent/a2ui-prompt.tspackages/genui/server/agent/a2ui-validator.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/stream/route.ts
✅ Files skipped from review due to trivial changes (1)
- packages/genui/server/.npmrc
3794e14 to
e523a40
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/app/a2ui/action/stream/route.ts`:
- Around line 176-205: Wrap the call to service.generateValidated inside a
try/catch so any exception during the repair step is handled as non-fatal: call
service.generateValidated(...) in a try block and build the repair object and
enqueue('repair', repair) on success as before; in the catch, set repair = {
attempted: true, sourceErrors: v.errors, ok: false, attempts: 0, error: <caught
error> } (or otherwise record the exception), enqueue('repair', repair), and
leave validation set to the original validation failure (i.e., keep validation =
{ ok: false, errors: v.errors, messages: [] }) without emitting an error or
closing the stream; ensure finalText/usage/finishReason/resolvedMessages remain
unchanged when repair fails or throws.
In `@packages/genui/server/app/a2ui/stream/route.ts`:
- Around line 123-151: The repair call to service.generateValidated inside the
try block must not be allowed to throw out and convert a finished SSE into an
error; wrap the generateValidated(...) call in its own try/catch so any
exception is handled locally: on success keep the existing logic (set repair,
enqueue('repair', repair), and update finalText/usage/finishReason/validation),
but on catch create a repair object marking attempted: true, ok: false,
sourceErrors: v.errors and include the caught error details (or a stringified
error) in repair.errors or attempts as appropriate, call enqueue('repair',
repair), set validation to reflect the failed repair (ok: false, errors: [ ...
]) and do not rethrow so finalText and the original generation result remain
returned and the stream can still emit done.
🪄 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: c6e5cc69-d326-4d1e-b3e8-3264af0a7959
📒 Files selected for processing (8)
.github/lynx-stack-pr.instructions.mdpackages/genui/server/.npmrcpackages/genui/server/agent/a2ui-catalog.tspackages/genui/server/agent/a2ui-examples.tspackages/genui/server/agent/a2ui-prompt.tspackages/genui/server/agent/a2ui-validator.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/stream/route.ts
✅ Files skipped from review due to trivial changes (2)
- packages/genui/server/.npmrc
- .github/lynx-stack-pr.instructions.md
e523a40 to
8dd5938
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/genui/server/app/a2ui/stream/route.ts (1)
123-135:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep repair failures non-fatal.
If
service.generateValidated(...)throws here, the outercatchturns a completed generation into anerrorevent and skipsdone. The repair pass should be best-effort: handle its failure locally and preserve the original validation result in the final SSE payload.💡 Minimal fix
if (!v.ok) { - const repaired = await service.generateValidated( - messages, - opts, - validatedConversation.conversation, - ); - repair = { - attempted: true, - sourceErrors: v.errors, - ok: repaired.ok, - attempts: repaired.attempts, - }; - enqueue('repair', repair); - if (repaired.ok) { - finalText = repaired.text; - usage = repaired.usage; - finishReason = repaired.finishReason; - resolvedMessages = repaired.messages; - validation = { - ok: true, - errors: [], - messages: resolvedMessages, - }; - } else { - validation = { - ok: false, - errors: repaired.errors, - messages: [], - }; - } + try { + const repaired = await service.generateValidated( + messages, + opts, + validatedConversation.conversation, + ); + repair = { + attempted: true, + sourceErrors: v.errors, + ok: repaired.ok, + attempts: repaired.attempts, + }; + enqueue('repair', repair); + if (repaired.ok) { + finalText = repaired.text; + usage = repaired.usage; + finishReason = repaired.finishReason; + resolvedMessages = repaired.messages; + validation = { + ok: true, + errors: [], + messages: resolvedMessages, + }; + } else { + validation = { + ok: false, + errors: repaired.errors, + messages: [], + }; + } + } catch { + repair = { + attempted: true, + sourceErrors: v.errors, + ok: false, + attempts: 0, + }; + enqueue('repair', repair); + } }🤖 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/app/a2ui/stream/route.ts` around lines 123 - 135, Wrap the call to service.generateValidated(...) in a try/catch so any exception is handled locally and does not bubble out; on success set repair as you already do, and on catch set repair to a non-fatal failure object (e.g., { attempted: true, sourceErrors: v.errors, ok: false, attempts: [], error: err?.message || String(err) }) and still call enqueue('repair', repair); do not rethrow the error so the original validatedConversation/result is preserved and the final SSE will still emit done.packages/genui/server/app/a2ui/action/stream/route.ts (1)
176-189:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep repair failures non-fatal.
If
service.generateValidated(...)throws here, the outercatchemitserrorand the stream never sendsdone, even though the original generation already finished. Catch the repair attempt locally and fall back to the original validation result instead of aborting the SSE.💡 Minimal fix
if (!v.ok) { - const repaired = await service.generateValidated( - [userMessage], - opts, - validatedConversation.conversation, - validationOptions, - ); - repair = { - attempted: true, - sourceErrors: v.errors, - ok: repaired.ok, - attempts: repaired.attempts, - }; - enqueue('repair', repair); - if (repaired.ok) { - finalText = repaired.text; - usage = repaired.usage; - finishReason = repaired.finishReason; - resolvedMessages = repaired.messages; - validation = { - ok: true, - errors: [], - messages: resolvedMessages, - }; - } else { - validation = { - ok: false, - errors: repaired.errors, - messages: [], - }; - } + try { + const repaired = await service.generateValidated( + [userMessage], + opts, + validatedConversation.conversation, + validationOptions, + ); + repair = { + attempted: true, + sourceErrors: v.errors, + ok: repaired.ok, + attempts: repaired.attempts, + }; + enqueue('repair', repair); + if (repaired.ok) { + finalText = repaired.text; + usage = repaired.usage; + finishReason = repaired.finishReason; + resolvedMessages = repaired.messages; + validation = { + ok: true, + errors: [], + messages: resolvedMessages, + }; + } else { + validation = { + ok: false, + errors: repaired.errors, + messages: [], + }; + } + } catch { + repair = { + attempted: true, + sourceErrors: v.errors, + ok: false, + attempts: 0, + }; + enqueue('repair', repair); + } }🤖 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/app/a2ui/action/stream/route.ts` around lines 176 - 189, Wrap the call to service.generateValidated(...) (the block that sets repair and calls enqueue('repair', repair)) in a local try/catch so any exception from generateValidated is handled locally; on catch, set repair to a non-fatal fallback (e.g. { attempted: true, sourceErrors: v.errors, ok: false, attempts: [] } or similar), optionally log the caught error, and still call enqueue('repair', repair) so the stream can finish and emit done instead of letting the outer catch abort the SSE; target the code that references v, userMessage, opts, validatedConversation, validationOptions, repair and enqueue.
🤖 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-validator.ts`:
- Around line 409-425: isPathCovered currently returns true for any matching
prefix; change it so a provided path only covers a referenced path when segments
themselves match (respecting '*' wildcards) and the provided path either has the
same length as the referenced path or explicitly ends with a '*' to indicate it
replaces the entire subtree. Concretely, inside isPathCovered (and using
normalizePathSegments) keep the existing per-segment comparison loop, but after
it finishes add checks: if providedSegments.length === referencedSegments.length
return true; if providedSegments.length < referencedSegments.length return true
only if the last segment of providedSegments === '*'; otherwise return false;
similarly if providedSegments.length > referencedSegments.length return false.
This ensures prefixes alone don’t imply subtree coverage.
---
Duplicate comments:
In `@packages/genui/server/app/a2ui/action/stream/route.ts`:
- Around line 176-189: Wrap the call to service.generateValidated(...) (the
block that sets repair and calls enqueue('repair', repair)) in a local try/catch
so any exception from generateValidated is handled locally; on catch, set repair
to a non-fatal fallback (e.g. { attempted: true, sourceErrors: v.errors, ok:
false, attempts: [] } or similar), optionally log the caught error, and still
call enqueue('repair', repair) so the stream can finish and emit done instead of
letting the outer catch abort the SSE; target the code that references v,
userMessage, opts, validatedConversation, validationOptions, repair and enqueue.
In `@packages/genui/server/app/a2ui/stream/route.ts`:
- Around line 123-135: Wrap the call to service.generateValidated(...) in a
try/catch so any exception is handled locally and does not bubble out; on
success set repair as you already do, and on catch set repair to a non-fatal
failure object (e.g., { attempted: true, sourceErrors: v.errors, ok: false,
attempts: [], error: err?.message || String(err) }) and still call
enqueue('repair', repair); do not rethrow the error so the original
validatedConversation/result is preserved and the final SSE will still emit
done.
🪄 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: 853ab9b3-58d9-456a-af52-5628d2938d31
📒 Files selected for processing (7)
packages/genui/server/.npmrcpackages/genui/server/agent/a2ui-catalog.tspackages/genui/server/agent/a2ui-examples.tspackages/genui/server/agent/a2ui-prompt.tspackages/genui/server/agent/a2ui-validator.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/stream/route.ts
8dd5938 to
a655d94
Compare
React MTF Example#1693 Bundle Size — 208.75KiB (0%).dc8fd2e(current) vs 7e6ff74 main#1678(baseline) Bundle metrics
|
| Current #1693 |
Baseline #1678 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
3 |
3 |
|
195 |
195 |
|
77 |
77 |
|
44.17% |
44.17% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #1693 |
Baseline #1678 |
|
|---|---|---|
111.23KiB |
111.23KiB |
|
97.52KiB |
97.52KiB |
Bundle analysis report Branch Sherry-hue:feat/agent-server-opt... Project dashboard
Generated by RelativeCI Documentation Report issue
React External#1675 Bundle Size — 698.01KiB (0%).dc8fd2e(current) vs 7e6ff74 main#1660(baseline) Bundle metrics
|
| Current #1675 |
Baseline #1660 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
3 |
3 |
|
17 |
17 |
|
5 |
5 |
|
8.59% |
8.59% |
|
0 |
0 |
|
0 |
0 |
Bundle analysis report Branch Sherry-hue:feat/agent-server-opt... Project dashboard
Generated by RelativeCI Documentation Report issue
Web Explorer#10134 Bundle Size — 903.53KiB (0%).dc8fd2e(current) vs 7e6ff74 main#10119(baseline) Bundle metrics
Bundle size by type
|
| Current #10134 |
Baseline #10119 |
|
|---|---|---|
499.15KiB |
499.15KiB |
|
402.16KiB |
402.16KiB |
|
2.22KiB |
2.22KiB |
Bundle analysis report Branch Sherry-hue:feat/agent-server-opt... Project dashboard
Generated by RelativeCI Documentation Report issue
React Example#8560 Bundle Size — 237.81KiB (0%).dc8fd2e(current) vs 7e6ff74 main#8545(baseline) Bundle metrics
|
| Current #8560 |
Baseline #8545 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
4 |
4 |
|
200 |
200 |
|
80 |
80 |
|
44.68% |
44.68% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #8560 |
Baseline #8545 |
|
|---|---|---|
145.76KiB |
145.76KiB |
|
92.05KiB |
92.05KiB |
Bundle analysis report Branch Sherry-hue:feat/agent-server-opt... Project dashboard
Generated by RelativeCI Documentation Report issue
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/genui/server/app/a2ui/stream/route.ts (1)
111-124:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRepair empty responses as well.
This
if (finalText)guard means an empty finalized response never reachesservice.generateValidated(...); the route just returnsvalidation.errors = ['no text produced']. That leaves a recoverable invalid-output case outside the new repair flow.🤖 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/app/a2ui/stream/route.ts` around lines 111 - 124, The current if (finalText) guard prevents empty finalized responses from entering the repair flow; always run validateA2UIOutput on finalText (even when it's empty), use the resulting v to populate validation and to await resolveA2UIImageUrls(v.messages) (empty array if invalid), and ensure that when v.ok is false you call service.generateValidated(...) (the same repair path used for other invalid outputs) so empty outputs are repairable; adjust the code around validateA2UIOutput, resolveA2UIImageUrls, and the service.generateValidated invocation to remove the finalText-only shortcut and always feed validation into the repair logic.
♻️ Duplicate comments (1)
packages/genui/server/agent/a2ui-validator.ts (1)
409-425:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftTighten path coverage semantics to avoid false positives.
At Line 425, returning
trueafter only shared-prefix matching lets shallow updates (for example,"/status"or"/items") satisfy deeper bindings like"/status/message"or"/items/*/name"even when nested fields are not populated.Suggested direction
function isPathCovered(referencedPath: string, providedPath: string): boolean { const referencedSegments = normalizePathSegments(referencedPath); const providedSegments = normalizePathSegments(providedPath); const comparableLength = Math.min( referencedSegments.length, providedSegments.length, ); for (let i = 0; i < comparableLength; i++) { const referenced = referencedSegments[i]; const provided = providedSegments[i]; if (referenced !== provided && referenced !== '*' && provided !== '*') { return false; } } - return true; + // Only treat as covered when provided path is at least as specific + // as the referenced path. + return providedSegments.length >= referencedSegments.length; }🤖 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-validator.ts` around lines 409 - 425, The isPathCovered function currently returns true as long as the shared prefix matches, causing shallow paths like "/status" to incorrectly cover deeper bindings; update isPathCovered (and keep using normalizePathSegments) so that after the for-loop you also verify there are no unmatched non-wildcard segments remaining: require that either both referencedSegments and providedSegments lengths are equal, or any extra segments on one side are all '*' (i.e., check referencedSegments.slice(comparableLength).every(s => s==='*') || providedSegments.slice(comparableLength).every(s => s==='*')); if not, return false—this ensures deeper bindings like "/status/message" or "/items/*/name" are not satisfied by shallower updates.
🧹 Nitpick comments (2)
packages/genui/server/app/a2ui/action/stream/route.ts (1)
192-200: ⚡ Quick winRun repaired messages through the same image post-processing path.
The first-pass success branch resolves image URLs before filling
validation.messages, but the repaired-success branch assignsrepaired.messagesdirectly. Keeping both branches on the same post-processing path avoids divergent SSE payloads.♻️ Proposed fix
if (repaired.ok) { finalText = repaired.text; usage = repaired.usage; finishReason = repaired.finishReason; - resolvedMessages = repaired.messages; + resolvedMessages = await resolveA2UIImageUrls( + repaired.messages, + ); validation = { ok: true, errors: [], messages: resolvedMessages, };🤖 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/app/a2ui/action/stream/route.ts` around lines 192 - 200, The repaired-success branch currently assigns repaired.messages directly to validation.messages and resolvedMessages; instead, run repaired.messages through the same image post-processing path used in the first-pass success branch (the code that produced resolvedMessages) — process repaired.messages with that image-resolution/post-processing function, then set resolvedMessages to the processed array and set validation.messages to it so both branches emit the same SSE payload shape.packages/genui/server/app/a2ui/stream/route.ts (1)
138-146: ⚡ Quick winKeep repaired messages on the same resolver path.
The non-repair success branch resolves image URLs before returning
validation.messages, but the repaired-success branch skips that step. Reusing the same post-processing here keeps repaired and non-repaired payloads consistent.♻️ Proposed fix
if (repaired.ok) { finalText = repaired.text; usage = repaired.usage; finishReason = repaired.finishReason; - resolvedMessages = repaired.messages; + resolvedMessages = await resolveA2UIImageUrls( + repaired.messages, + ); validation = { ok: true, errors: [], messages: resolvedMessages, };🤖 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/app/a2ui/stream/route.ts` around lines 138 - 146, The repaired-success branch (when repaired.ok is true) sets finalText, usage, finishReason, resolvedMessages and validation but skips the image-URL post-processing that the non-repair branch runs; update the repaired.ok path to run the same image URL resolution step used elsewhere (i.e., call the same resolver function used for the non-repair success branch to transform validation.messages / resolvedMessages) before returning so repaired and non-repaired payloads are consistent (refer to repaired.ok, repaired.text, resolvedMessages, validation).
🤖 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/app/a2ui/action/stream/route.ts`:
- Around line 159-177: The code currently skips validation and repair when
finalize() returns an empty string because of the if (finalText) guard; remove
or adjust that guard so service.generateValidated(...) and
validateA2UIOutput(...) are invoked even when finalText === '' (i.e., call the
same validation flow for empty finalText), ensuring the validation result v and
subsequent repair logic (including resolveA2UIImageUrls and the repair branch)
run for the empty-output case; update the block around finalText /
validateA2UIOutput / service.generateValidated to handle empty string inputs
rather than short-circuiting them.
---
Outside diff comments:
In `@packages/genui/server/app/a2ui/stream/route.ts`:
- Around line 111-124: The current if (finalText) guard prevents empty finalized
responses from entering the repair flow; always run validateA2UIOutput on
finalText (even when it's empty), use the resulting v to populate validation and
to await resolveA2UIImageUrls(v.messages) (empty array if invalid), and ensure
that when v.ok is false you call service.generateValidated(...) (the same repair
path used for other invalid outputs) so empty outputs are repairable; adjust the
code around validateA2UIOutput, resolveA2UIImageUrls, and the
service.generateValidated invocation to remove the finalText-only shortcut and
always feed validation into the repair logic.
---
Duplicate comments:
In `@packages/genui/server/agent/a2ui-validator.ts`:
- Around line 409-425: The isPathCovered function currently returns true as long
as the shared prefix matches, causing shallow paths like "/status" to
incorrectly cover deeper bindings; update isPathCovered (and keep using
normalizePathSegments) so that after the for-loop you also verify there are no
unmatched non-wildcard segments remaining: require that either both
referencedSegments and providedSegments lengths are equal, or any extra segments
on one side are all '*' (i.e., check
referencedSegments.slice(comparableLength).every(s => s==='*') ||
providedSegments.slice(comparableLength).every(s => s==='*')); if not, return
false—this ensures deeper bindings like "/status/message" or "/items/*/name" are
not satisfied by shallower updates.
---
Nitpick comments:
In `@packages/genui/server/app/a2ui/action/stream/route.ts`:
- Around line 192-200: The repaired-success branch currently assigns
repaired.messages directly to validation.messages and resolvedMessages; instead,
run repaired.messages through the same image post-processing path used in the
first-pass success branch (the code that produced resolvedMessages) — process
repaired.messages with that image-resolution/post-processing function, then set
resolvedMessages to the processed array and set validation.messages to it so
both branches emit the same SSE payload shape.
In `@packages/genui/server/app/a2ui/stream/route.ts`:
- Around line 138-146: The repaired-success branch (when repaired.ok is true)
sets finalText, usage, finishReason, resolvedMessages and validation but skips
the image-URL post-processing that the non-repair branch runs; update the
repaired.ok path to run the same image URL resolution step used elsewhere (i.e.,
call the same resolver function used for the non-repair success branch to
transform validation.messages / resolvedMessages) before returning so repaired
and non-repaired payloads are consistent (refer to repaired.ok, repaired.text,
resolvedMessages, validation).
🪄 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: 1b6f94c0-4857-43d5-81fb-9b57860adb9a
📒 Files selected for processing (7)
packages/genui/server/.npmrcpackages/genui/server/agent/a2ui-catalog.tspackages/genui/server/agent/a2ui-examples.tspackages/genui/server/agent/a2ui-prompt.tspackages/genui/server/agent/a2ui-validator.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/stream/route.ts
f998b6a to
ab96b21
Compare
ab96b21 to
dc8fd2e
Compare
Merging this PR will degrade performance by 14.91%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | transform 1000 view elements |
40 ms | 47 ms | -14.91% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing Sherry-hue:feat/agent-server-optimization (dc8fd2e) with main (7e6ff74)
Footnotes
-
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. ↩
React Example with Element Template#828 Bundle Size — 202.16KiB (0%).dc8fd2e(current) vs 7e6ff74 main#814(baseline) Bundle metrics
|
| Current #828 |
Baseline #814 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
4 |
4 |
|
100 |
100 |
|
30 |
30 |
|
39.22% |
39.22% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #828 |
Baseline #814 |
|
|---|---|---|
145.76KiB |
145.76KiB |
|
56.41KiB |
56.41KiB |
Bundle analysis report Branch Sherry-hue:feat/agent-server-opt... Project dashboard
Generated by RelativeCI Documentation Report issue
Summary by CodeRabbit
New Features
Improvements
Documentation
Checklist