Skip to content

fix: ag UI feedback metadata stream#1076

Merged
omeraplak merged 6 commits intomainfrom
fix/ag-ui-feedback-metadata-stream
Feb 17, 2026
Merged

fix: ag UI feedback metadata stream#1076
omeraplak merged 6 commits intomainfrom
fix/ag-ui-feedback-metadata-stream

Conversation

@omeraplak
Copy link
Member

@omeraplak omeraplak commented Feb 17, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

What is the new behavior?

fixes (issue)

Notes for reviewers


Summary by cubic

Fixes lost assistant feedback metadata in AG-UI streams by mapping VoltAgent message-metadata to a stable CUSTOM event. Fully removes legacy markers and filtering for reliable delivery, and adds docs for wiring CopilotKit thumbs to VoltOps feedback via these events.

  • Bug Fixes
    • Map VoltAgent message-metadata parts to AG-UI CUSTOM events (voltagent.message_metadata) with messageId and metadata.
    • Remove legacy metadata tooling: stop emitting tool-result markers and drop the filter that skipped metadata-carrier tool messages in conversion.

Written for commit a5e7c7b. Summary will update on new commits.

Summary by CodeRabbit

  • Improvements

    • Preserves assistant feedback metadata across real-time streams and emits application-native message metadata events for reliable delivery.
    • Removes legacy metadata markers and filters to prevent duplication and simplify event handling.
  • Documentation

    • Adds CopilotKit feedback integration guide with examples for capturing metadata events and submitting thumbs up/down feedback.

@changeset-bot
Copy link

changeset-bot bot commented Feb 17, 2026

⚠️ No Changeset found

Latest commit: a5e7c7b

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 changesets to release 1 package
Name Type
@voltagent/ag-ui Patch

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

@joggrbot

This comment has been minimized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

Maps VoltAgent "message-metadata" stream parts to a voltagent.message_metadata CustomEvent emitted to AG-UI and removes legacy internal tool-result metadata marker emission and filtering in the conversion path. Also adds documentation showing how to wire CopilotKit feedback to these events.

Changes

Cohort / File(s) Summary
Changelog
\.changeset/wise-pans-arrive.md
Adds a patch changelog entry describing preservation of assistant feedback metadata via message-metadata event handling.
VoltAgent stream conversion
packages/ag-ui/src/voltagent-agent.ts
Restructures convertAGUIMessagesToVoltMessages to accumulate converted messages instead of early-returning; converts message-metadata stream parts into a CustomEvent (voltagent.message_metadata) containing messageId and metadata; removes legacy tool-result metadata marker emission and filtering; extends stream event typings to include CustomEvent.
Docs / example integration
website/docs/ui/copilotkit.md
Adds a guide and code samples for wiring AG-UI voltagent.message_metadata events to CopilotKit/VoltOps feedback submission and local feedback state management.

Sequence Diagram(s)

sequenceDiagram
  participant Volt as VoltAgent Stream
  participant Conv as AG-UI Converter
  participant AGUI as AG-UI (Event Bus / DOM)
  participant App as App Consumer

  Volt->>Conv: emit stream parts (start / text / message-metadata / ...)
  alt part.type == "message-metadata"
    Conv->>AGUI: dispatch CustomEvent "voltagent.message_metadata" { messageId, metadata }
    AGUI->>App: listener receives metadata event -> map messageId to feedback URL
    App->>App: post feedback (thumbs up/down) to VoltOps
  else other part types
    Conv->>AGUI: emit converted events (start / text / tool / ...)
    AGUI->>App: listener handles normal events
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I hop through streams on tiny feet,
Carrying metadata soft and neat.
Old crumbs are gone, new signals sing,
Events go forth on feathered spring.
Feedback saved — a carrot treat!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete; critical sections like 'What is the current behavior?' and 'What is the new behavior?' are empty, and the checklist items remain unchecked despite completed work (docs, changesets, code changes). Fill in the empty sections describing current vs. new behavior, check completed checklist items (docs, changesets), and add details about what bug/feature this addresses or which issue it resolves.
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 (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: ag UI feedback metadata stream' accurately summarizes the main change—fixing feedback metadata handling in AG-UI streams through proper event mapping.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/ag-ui-feedback-metadata-stream

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.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 17, 2026

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: a5e7c7b
Status: ✅  Deploy successful!
Preview URL: https://5799935c.voltagent.pages.dev
Branch Preview URL: https://fix-ag-ui-feedback-metadata.voltagent.pages.dev

View logs

Copy link
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.

🧹 Nitpick comments (1)
packages/ag-ui/src/voltagent-agent.ts (1)

415-426: Nit: the messageId || undefined coercion on line 433 is effectively a no-op.

messageId falls back to fallbackMessageId (line 419), which is always a non-empty UUID from generateId(). The || undefined guard on line 433 can never trigger. Not harmful, but it's dead code that might confuse future readers into thinking an empty/missing messageId is a realistic scenario here.

Proposed simplification
       value: {
-        messageId: messageId || undefined,
+        messageId,
         metadata: messageMetadata,
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ag-ui/src/voltagent-agent.ts` around lines 415 - 426, The messageId
null-coercion is dead code: in the message-metadata branch computeMessageId (the
variable named messageId which already falls back to fallbackMessageId generated
by generateId()) can never be empty, so remove the "|| undefined" coercion and
use messageId directly where it is passed/returned; update any references in the
message-metadata handling block (partType === "message-metadata") to rely on
messageId without the redundant "|| undefined".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/ag-ui/src/voltagent-agent.ts`:
- Around line 415-426: The messageId null-coercion is dead code: in the
message-metadata branch computeMessageId (the variable named messageId which
already falls back to fallbackMessageId generated by generateId()) can never be
empty, so remove the "|| undefined" coercion and use messageId directly where it
is passed/returned; update any references in the message-metadata handling block
(partType === "message-metadata") to rely on messageId without the redundant "||
undefined".

Copy link
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.

🧹 Nitpick comments (2)
packages/ag-ui/src/voltagent-agent.ts (2)

402-403: Minor inconsistency: partType extracted but unused in the switch.

partType is extracted on line 403 for the "message-metadata" check, but the switch on line 431 uses part.type directly. This works but is slightly confusing — either use partType consistently or inline the check on line 405.

Use partType in the switch for consistency
-  switch (part.type) {
+  switch (partType) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ag-ui/src/voltagent-agent.ts` around lines 402 - 403, The code
extracts partType but then uses part.type in the switch, which is inconsistent;
update the switch in the function containing payload and partType so it uses the
extracted partType variable (or remove the partType extraction if you prefer
inline access) ensuring the case that checks "message-metadata" uses partType
consistently with the earlier extraction; reference the variables payload and
partType and the switch that handles "message-metadata" to locate and apply the
change.

405-429: Metadata validation looks good; consider exporting the constant for downstream consumers.

The guard on line 414 (!messageMetadata || typeof messageMetadata !== "object") correctly rejects nullish and primitive values before emitting the event. The dual fallback for messageMetadata vs metadata (lines 411-412) is a reasonable compat measure.

One thing to note: VOLTAGENT_MESSAGE_METADATA_EVENT_NAME is module-scoped (const at line 278) but not exported. If downstream AG-UI consumers need to match on this event name (e.g. event.name === "voltagent.message_metadata"), they'll end up duplicating the string. Consider exporting it.

Export the constant
-const VOLTAGENT_MESSAGE_METADATA_EVENT_NAME = "voltagent.message_metadata";
+export const VOLTAGENT_MESSAGE_METADATA_EVENT_NAME = "voltagent.message_metadata";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ag-ui/src/voltagent-agent.ts` around lines 405 - 429,
VOLTAGENT_MESSAGE_METADATA_EVENT_NAME is currently a module-scoped const but
should be exported so downstream consumers can reference the canonical event
name; change its declaration from "const VOLTAGENT_MESSAGE_METADATA_EVENT_NAME"
to "export const VOLTAGENT_MESSAGE_METADATA_EVENT_NAME" where it is defined
(line ~278) and ensure it is re-exported from the package's public API/barrel if
one exists so consumers can import it instead of duplicating the string; leave
all internal uses (e.g., in the message-metadata branch that constructs
CustomEvent) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/ag-ui/src/voltagent-agent.ts`:
- Around line 402-403: The code extracts partType but then uses part.type in the
switch, which is inconsistent; update the switch in the function containing
payload and partType so it uses the extracted partType variable (or remove the
partType extraction if you prefer inline access) ensuring the case that checks
"message-metadata" uses partType consistently with the earlier extraction;
reference the variables payload and partType and the switch that handles
"message-metadata" to locate and apply the change.
- Around line 405-429: VOLTAGENT_MESSAGE_METADATA_EVENT_NAME is currently a
module-scoped const but should be exported so downstream consumers can reference
the canonical event name; change its declaration from "const
VOLTAGENT_MESSAGE_METADATA_EVENT_NAME" to "export const
VOLTAGENT_MESSAGE_METADATA_EVENT_NAME" where it is defined (line ~278) and
ensure it is re-exported from the package's public API/barrel if one exists so
consumers can import it instead of duplicating the string; leave all internal
uses (e.g., in the message-metadata branch that constructs CustomEvent)
unchanged.

…tadata-stream

# Conflicts:
#	.changeset/wise-pans-arrive.md
#	packages/ag-ui/src/voltagent-agent.ts
Copy link
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: 2

🧹 Nitpick comments (1)
website/docs/ui/copilotkit.md (1)

247-283: Consider safer type narrowing for event payload.

The type assertion at lines 260-267 uses as to cast event.value without runtime validation. If the event payload doesn't match the expected shape, this could lead to runtime errors or unexpected behavior. Consider adding runtime validation or using a type guard.

🛡️ Example with runtime validation
        const payload = event.value as
          | {
              messageId?: string;
              metadata?: {
                feedback?: VoltFeedbackMetadata;
              };
            }
          | undefined;

        const messageId = payload?.messageId;
        const feedback = payload?.metadata?.feedback;

-        if (!messageId || !feedback?.url) return;
+        if (
+          !messageId ||
+          typeof messageId !== 'string' ||
+          !feedback?.url ||
+          typeof feedback.url !== 'string'
+        ) return;
+
        setFeedbackByMessageId((prev) => ({ ...prev, [messageId]: feedback }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/docs/ui/copilotkit.md` around lines 247 - 283, The handler in
useVoltFeedbackMap currently casts event.value with "as" which is unsafe;
replace the assertion with runtime validation or a type guard: inside
agent.subscribe onCustomEvent check that event.value is a non-null object, that
messageId is a string, and that metadata is an object containing a feedback
object with a url string before using them; update the logic around
VOLTAGENT_MESSAGE_METADATA_EVENT_NAME to derive messageId and feedback only
after these checks (or call a small type-guard function like
isVoltPayload(value) that returns a typed predicate) and then call
setFeedbackByMessageId.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/docs/ui/copilotkit.md`:
- Around line 289-320: submitVoltFeedback currently posts to feedback.url
without validation; validate the URL before sending to prevent SSRF: parse
feedback.url with the URL constructor inside submitVoltFeedback, ensure protocol
is https: (or a safe protocol) and that the origin (hostname+port) matches a
configured allowlist or the app's same-origin, and return early if parsing fails
or the origin is not allowed; add or call a small helper like
isAllowedFeedbackOrigin(url) and wrap the fetch call in that guard so fetch is
only executed for validated, trusted origins.
- Around line 289-320: submitVoltFeedback currently performs fetch and
response.json() without try/catch which can cause unhandled rejections on
network or parse failures; wrap the network call and JSON parsing in a try/catch
around the fetch(...) and await response.json() so any errors are caught, return
early on errors (do not mark feedback as provided), and record or log the error
(e.g., include an error field in setFeedbackByMessageId update or call a logger)
so callers can surface failure; keep existing checks for response.ok and only
set provided: true and feedbackId when the request and parsing succeed.

---

Nitpick comments:
In `@website/docs/ui/copilotkit.md`:
- Around line 247-283: The handler in useVoltFeedbackMap currently casts
event.value with "as" which is unsafe; replace the assertion with runtime
validation or a type guard: inside agent.subscribe onCustomEvent check that
event.value is a non-null object, that messageId is a string, and that metadata
is an object containing a feedback object with a url string before using them;
update the logic around VOLTAGENT_MESSAGE_METADATA_EVENT_NAME to derive
messageId and feedback only after these checks (or call a small type-guard
function like isVoltPayload(value) that returns a typed predicate) and then call
setFeedbackByMessageId.

Comment on lines +289 to +320
async function submitVoltFeedback(input: {
message: Message;
type: "thumbsUp" | "thumbsDown";
feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
}) {
const feedback = input.feedbackByMessageId[input.message.id];
if (!feedback?.url || isProvided(feedback)) return;

const score = input.type === "thumbsUp" ? 1 : 0;

const response = await fetch(feedback.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: safeStringify({
score,
feedback_source_type: "app",
}),
});

if (!response.ok) return;

const data = (await response.json()) as { id?: string };
setFeedbackByMessageId((prev) => ({
...prev,
[input.message.id]: {
...feedback,
provided: true,
feedbackId: data.id,
},
}));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add URL validation to prevent SSRF attacks.

The function makes a POST request to feedback.url without validating that the URL belongs to a trusted origin. If the metadata stream is compromised or misconfigured, this could allow an attacker to make arbitrary POST requests from the client to any URL (SSRF).

🛡️ Proposed fix with origin validation
+const TRUSTED_FEEDBACK_ORIGINS = [
+  'https://api.voltagent.dev',
+  // Add other trusted origins
+];
+
+function isUrlTrusted(url: string): boolean {
+  try {
+    const parsed = new URL(url);
+    return TRUSTED_FEEDBACK_ORIGINS.some(origin => parsed.origin === origin);
+  } catch {
+    return false;
+  }
+}
+
 async function submitVoltFeedback(input: {
   message: Message;
   type: "thumbsUp" | "thumbsDown";
   feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
   setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
 }) {
   const feedback = input.feedbackByMessageId[input.message.id];
   if (!feedback?.url || isProvided(feedback)) return;
+  
+  if (!isUrlTrusted(feedback.url)) {
+    console.error('Untrusted feedback URL:', feedback.url);
+    return;
+  }

   const score = input.type === "thumbsUp" ? 1 : 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function submitVoltFeedback(input: {
message: Message;
type: "thumbsUp" | "thumbsDown";
feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
}) {
const feedback = input.feedbackByMessageId[input.message.id];
if (!feedback?.url || isProvided(feedback)) return;
const score = input.type === "thumbsUp" ? 1 : 0;
const response = await fetch(feedback.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: safeStringify({
score,
feedback_source_type: "app",
}),
});
if (!response.ok) return;
const data = (await response.json()) as { id?: string };
setFeedbackByMessageId((prev) => ({
...prev,
[input.message.id]: {
...feedback,
provided: true,
feedbackId: data.id,
},
}));
}
const TRUSTED_FEEDBACK_ORIGINS = [
'https://api.voltagent.dev',
// Add other trusted origins
];
function isUrlTrusted(url: string): boolean {
try {
const parsed = new URL(url);
return TRUSTED_FEEDBACK_ORIGINS.some(origin => parsed.origin === origin);
} catch {
return false;
}
}
async function submitVoltFeedback(input: {
message: Message;
type: "thumbsUp" | "thumbsDown";
feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
}) {
const feedback = input.feedbackByMessageId[input.message.id];
if (!feedback?.url || isProvided(feedback)) return;
if (!isUrlTrusted(feedback.url)) {
console.error('Untrusted feedback URL:', feedback.url);
return;
}
const score = input.type === "thumbsUp" ? 1 : 0;
const response = await fetch(feedback.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: safeStringify({
score,
feedback_source_type: "app",
}),
});
if (!response.ok) return;
const data = (await response.json()) as { id?: string };
setFeedbackByMessageId((prev) => ({
...prev,
[input.message.id]: {
...feedback,
provided: true,
feedbackId: data.id,
},
}));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/docs/ui/copilotkit.md` around lines 289 - 320, submitVoltFeedback
currently posts to feedback.url without validation; validate the URL before
sending to prevent SSRF: parse feedback.url with the URL constructor inside
submitVoltFeedback, ensure protocol is https: (or a safe protocol) and that the
origin (hostname+port) matches a configured allowlist or the app's same-origin,
and return early if parsing fails or the origin is not allowed; add or call a
small helper like isAllowedFeedbackOrigin(url) and wrap the fetch call in that
guard so fetch is only executed for validated, trusted origins.

⚠️ Potential issue | 🟡 Minor

Add error handling for network and parsing failures.

The function lacks try-catch blocks around the fetch call and response.json() parsing. Network failures, timeouts, or malformed JSON responses would result in unhandled promise rejections. This could lead to silent failures where users believe their feedback was submitted but it actually failed.

🛡️ Proposed fix with error handling
 async function submitVoltFeedback(input: {
   message: Message;
   type: "thumbsUp" | "thumbsDown";
   feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
   setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
 }) {
   const feedback = input.feedbackByMessageId[input.message.id];
   if (!feedback?.url || isProvided(feedback)) return;

   const score = input.type === "thumbsUp" ? 1 : 0;

+  try {
-  const response = await fetch(feedback.url, {
+    const response = await fetch(feedback.url, {
-    method: "POST",
+      method: "POST",
-    headers: { "Content-Type": "application/json" },
+      headers: { "Content-Type": "application/json" },
-    body: safeStringify({
+      body: safeStringify({
-      score,
+        score,
-      feedback_source_type: "app",
+        feedback_source_type: "app",
-    }),
+      }),
-  });
+      signal: AbortSignal.timeout(5000), // 5s timeout
+    });

-  if (!response.ok) return;
+    if (!response.ok) {
+      console.error('Feedback submission failed:', response.status);
+      return;
+    }

-  const data = (await response.json()) as { id?: string };
-  setFeedbackByMessageId((prev) => ({
+    const data = (await response.json()) as { id?: string };
+    input.setFeedbackByMessageId((prev) => ({
-    ...prev,
+      ...prev,
-    [input.message.id]: {
+      [input.message.id]: {
-      ...feedback,
+        ...feedback,
-      provided: true,
+        provided: true,
-      feedbackId: data.id,
+        feedbackId: data.id,
-    },
+      },
-  }));
+    }));
+  } catch (error) {
+    console.error('Failed to submit feedback:', error);
+    // Optionally: show user notification
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function submitVoltFeedback(input: {
message: Message;
type: "thumbsUp" | "thumbsDown";
feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
}) {
const feedback = input.feedbackByMessageId[input.message.id];
if (!feedback?.url || isProvided(feedback)) return;
const score = input.type === "thumbsUp" ? 1 : 0;
const response = await fetch(feedback.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: safeStringify({
score,
feedback_source_type: "app",
}),
});
if (!response.ok) return;
const data = (await response.json()) as { id?: string };
setFeedbackByMessageId((prev) => ({
...prev,
[input.message.id]: {
...feedback,
provided: true,
feedbackId: data.id,
},
}));
}
async function submitVoltFeedback(input: {
message: Message;
type: "thumbsUp" | "thumbsDown";
feedbackByMessageId: Record<string, VoltFeedbackMetadata>;
setFeedbackByMessageId: Dispatch<SetStateAction<Record<string, VoltFeedbackMetadata>>>;
}) {
const feedback = input.feedbackByMessageId[input.message.id];
if (!feedback?.url || isProvided(feedback)) return;
const score = input.type === "thumbsUp" ? 1 : 0;
try {
const response = await fetch(feedback.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: safeStringify({
score,
feedback_source_type: "app",
}),
signal: AbortSignal.timeout(5000), // 5s timeout
});
if (!response.ok) {
console.error('Feedback submission failed:', response.status);
return;
}
const data = (await response.json()) as { id?: string };
input.setFeedbackByMessageId((prev) => ({
...prev,
[input.message.id]: {
...feedback,
provided: true,
feedbackId: data.id,
},
}));
} catch (error) {
console.error('Failed to submit feedback:', error);
// Optionally: show user notification
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/docs/ui/copilotkit.md` around lines 289 - 320, submitVoltFeedback
currently performs fetch and response.json() without try/catch which can cause
unhandled rejections on network or parse failures; wrap the network call and
JSON parsing in a try/catch around the fetch(...) and await response.json() so
any errors are caught, return early on errors (do not mark feedback as
provided), and record or log the error (e.g., include an error field in
setFeedbackByMessageId update or call a logger) so callers can surface failure;
keep existing checks for response.ok and only set provided: true and feedbackId
when the request and parsing succeed.

@omeraplak omeraplak merged commit e5fefef into main Feb 17, 2026
23 checks passed
@omeraplak omeraplak deleted the fix/ag-ui-feedback-metadata-stream branch February 17, 2026 18:54
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

Comments