Skip to content

Conversation

@omeraplak
Copy link
Member

@omeraplak omeraplak commented Jan 14, 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

Adds end-to-end feedback support so agents can create short-lived feedback tokens per trace and attach metadata to responses and streams. This enables thumbs, numeric, categorical, and freeform feedback in the Console and custom UIs.

  • New Features

    • Agent-level or per-call feedback via feedback option; tokens created through VoltOps.
    • Feedback metadata added to the last assistant message and included in generateText and streamText results.
    • UI message streams emit a final message-metadata chunk with feedback info.
    • Server API accepts feedback in generate options and returns feedback in responses.
    • VoltOps client adds createFeedbackToken and feedback types.
  • Docs & Examples

    • New example: examples/with-feedback with thumbs, rating, and issue tagging agents.
    • New docs page: Observability → Feedback; updates to Agents Overview and Message Types; sidebar entry added.

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

Summary by CodeRabbit

Release Notes

  • New Features

    • Agents now support configurable feedback collection with multiple feedback types (thumbs, rating, categorical)
    • New "Feedback Templates" example demonstrates per-agent feedback configuration and submission
  • Documentation

    • Added comprehensive feedback documentation covering setup, API usage, and integration patterns
    • Updated agent overview and message type guides with feedback examples and configuration options

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Jan 14, 2026

⚠️ No Changeset found

Latest commit: c21c98d

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

@joggrbot

This comment has been minimized.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 14, 2026

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: c21c98d
Status: ✅  Deploy successful!
Preview URL: https://c2fca7bb.voltagent.pages.dev
Branch Preview URL: https://feat-feedback.voltagent.pages.dev

View logs

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.

2 issues found across 22 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/src/agent/agent.ts">

<violation number="1" location="packages/core/src/agent/agent.ts:539">
P2: `feedbackFlushCompleted` is declared as a `const` but never modified, making the `if (!feedbackFlushCompleted)` check always true. If this is meant to track flush completion state, it should be `let` and set to `true` when the flush occurs. Otherwise, the variable and check should be removed as dead code.</violation>
</file>

<file name="packages/core/src/voltops/client.ts">

<violation number="1" location="packages/core/src/voltops/client.ts:94">
P1: Hardcoding the client base URL to http://localhost:3003 ignores caller-provided options and the intended production default, so every VoltOpsClient now sends requests to localhost instead of the configured API, breaking all remote environments.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive feedback system enabling agents to collect structured user feedback (thumbs, numeric, categorical) via VoltOps integration. It adds new public APIs for feedback token creation, extends agent and result types to carry feedback metadata, integrates feedback lifecycle management into agent generation flows, and includes a complete example project and documentation.

Changes

Cohort / File(s) Summary
Feedback Example Project
examples/with-feedback/*
New complete example project demonstrating feedback-enabled agents with three templates (thumbs, rating, issues), environment configuration, TypeScript setup (tsconfig, package.json), and a documented README with curl examples.
Core Agent Feedback Integration
packages/core/src/agent/agent.ts
Implements feedback lifecycle management: resolves feedback options, creates/attaches feedback metadata asynchronously, persists via VoltOps when available, and threads metadata through generation and streaming paths. Includes helper methods (resolveFeedbackOptions, getFeedbackTraceId, createFeedbackMetadata) and deferred persistence logic.
Feedback Type Definitions
packages/core/src/agent/types.ts, packages/core/src/voltops/types.ts
Adds public types AgentFeedbackOptions, AgentFeedbackMetadata, VoltOpsFeedbackConfig, VoltOpsFeedbackToken, VoltOpsFeedbackExpiresIn, and VoltOpsFeedbackTokenCreateInput. Extends BaseGenerationOptions and AgentOptions with optional feedback field.
VoltOps Client & Exports
packages/core/src/voltops/client.ts, packages/core/src/voltops/index.ts, packages/core/src/index.ts
Adds createFeedbackToken() method to VoltOpsClient to POST feedback token requests to /api/public/feedback/tokens. Exports new feedback-related types across the core package barrel.
Conversation Buffer & Server Handler
packages/core/src/agent/conversation-buffer.ts, packages/server-core/src/handlers/agent.handlers.ts
Adds addMetadataToLastAssistantMessage() method to ConversationBuffer for merging feedback metadata. Handler now includes result.feedback in generate-text API response.
API Schemas
packages/server-core/src/schemas/agent.schemas.ts
Extends GenerateOptionsSchema with optional feedback (boolean or FeedbackOptionsSchema). Augments TextResponseSchema to include feedback metadata with traceId, key, url, tokenId, expiresAt, and optional feedbackConfig.
Documentation & Website
examples/README.md, website/docs/agents/*, website/docs/observability/feedback.md, website/observability/feedback.md, website/sidebarsObservability.ts, website/src/data/tweets.json
Updates examples index with "Feedback Templates" entry. Adds feedback integration guide to agent documentation. Introduces comprehensive observability feedback documentation with schema details, token management, API usage, and integration patterns. Updates sidebar navigation. Reformats JSON array formatting (whitespace only).

Sequence Diagram

sequenceDiagram
    participant UI as UI/Client
    participant Agent as Agent
    participant VoltOps as VoltOps API
    participant Server as Server Handler

    UI->>Agent: Call generateText/streamText with feedback: true
    Agent->>VoltOps: resolveFeedbackOptions + check for client
    VoltOps-->>Agent: Feedback client available
    Agent->>Agent: Create feedback metadata (deferred)
    Agent->>VoltOps: createFeedbackToken(traceId, key, config)
    VoltOps-->>Agent: Return token {id, url, expiresAt, feedbackConfig}
    Agent->>Agent: Attach feedback metadata to result
    Agent-->>Server: Return result with feedback
    Server-->>UI: Include feedback in response
    UI->>UI: Display feedback UI (thumbs, rating, etc.)
    UI->>VoltOps: Submit feedback via token.url
    VoltOps-->>UI: Acknowledge feedback submission
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 Feedback now flows through the agent's core,
Tokens and metadata we did explore,
Thumbs and ratings, a chorus so clear,
Users can speak, and builders will hear!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description includes the template structure with a checklist and an auto-generated summary explaining the new features, docs, and examples. However, all checklist items remain unchecked, suggesting incomplete compliance with repository guidelines. Check off completed items in the PR checklist (commit message, issues linked, tests, docs, changesets) or clarify which requirements are not applicable.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add feedback' accurately summarizes the main change in the PR, which introduces end-to-end feedback support across agents, server, and documentation.

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
website/observability/feedback.md (2)

36-41: Minor style improvement for readability.

The static analysis tool flagged three successive sentences beginning with "If". Consider rewording for better flow.

📝 Suggested rewording
 - If a key exists with `feedback_config`, it is reused when `feedbackConfig` is omitted.
-- If a key does not exist and you pass `feedbackConfig`, the key is created automatically.
-- If a key exists, the stored config wins. Update the key if you need to change the schema.
+- When a key does not exist and you pass `feedbackConfig`, the key is created automatically.
+- For existing keys, the stored config takes precedence. Update the key if you need to change the schema.

114-114: Minor grammar: consider hyphenating compound adjective.

The phrase "thumbs up/down" could be clearer as "thumbs-up/down" when used as a compound adjective modifying "UI".

-When you use the `/agents/:id/chat` endpoint (AI SDK useChat compatible), the assistant message includes feedback metadata under `message.metadata.feedback`. You can render a thumbs up/down UI and submit feedback to `feedback.url`.
+When you use the `/agents/:id/chat` endpoint (AI SDK useChat compatible), the assistant message includes feedback metadata under `message.metadata.feedback`. You can render a thumbs-up/down UI and submit feedback to `feedback.url`.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acc3ef1 and c21c98d.

📒 Files selected for processing (5)
  • website/docs/agents/message-types.md
  • website/docs/agents/overview.md
  • website/docs/observability/feedback.md
  • website/observability/feedback.md
  • website/sidebarsObservability.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/docs/agents/overview.md
  • website/docs/observability/feedback.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Maintain type safety in TypeScript-first codebase
Never use JSON.stringify; use the safeStringify function instead, imported from @voltagent/internal

Files:

  • website/sidebarsObservability.ts
🪛 LanguageTool
website/observability/feedback.md

[style] ~40-~40: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...g`, the key is created automatically. - If a key exists, the stored config wins. U...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~114-~114: Use a hyphen to join words.
Context: ...adata.feedback. You can render a thumbs up/down UI and submit feedback to feedb...

(QB_NEW_EN_HYPHEN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Test server-core
  • GitHub Check: Test postgres
  • GitHub Check: Test core
  • GitHub Check: Test internal
  • GitHub Check: Test logger
  • GitHub Check: Test libsql
  • GitHub Check: Test cli
  • GitHub Check: Test supabase
  • GitHub Check: Test create-voltagent-app
  • GitHub Check: Test voice
  • GitHub Check: Test docs-mcp
  • GitHub Check: Build (Node 20)
  • GitHub Check: Build (Node 24)
  • GitHub Check: Build (Node 22)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (5)
website/observability/feedback.md (3)

50-110: SDK examples are clear and well-structured.

The code examples correctly demonstrate:

  • Agent-level default feedback configuration
  • Per-call feedback with custom config and expiration
  • Using registered keys
  • Streaming feedback metadata access pattern

The streaming example appropriately shows that stream.feedback should be accessed after consuming the stream, which is the correct usage pattern.


162-226: API documentation is comprehensive and well-formatted.

The curl examples clearly demonstrate all three feedback API patterns (token creation, token-based submission, direct submission) with appropriate headers and body structures.


228-253: Good coverage of custom feedback types and edge cases.

The documentation appropriately covers:

  • Continuous (numeric range) feedback type
  • Freeform (text-only) feedback type
  • Important notes about null feedback when keys aren't configured and token expiration

This gives developers a complete picture of the feedback system capabilities.

website/sidebarsObservability.ts (1)

23-27: LGTM!

The sidebar entry follows the established pattern and is correctly positioned. The id: "feedback" matches the expected doc id from the new feedback.md file.

website/docs/agents/message-types.md (1)

154-168: Code and documentation are correct.

The TypeScript code snippet properly demonstrates accessing the optional feedback metadata with appropriate type assertion. The link path /observability-docs/feedback is correct based on the Docusaurus configuration: the observability plugin has routeBasePath: "observability-docs" and the doc id is feedback, making /observability-docs/feedback the correct URL. This path is used consistently throughout the codebase.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

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

🤖 Fix all issues with AI agents
In `@packages/core/src/agent/agent.ts`:
- Around line 1533-1565: attachFeedbackMetadata can miss emitting feedback
metadata because it checks feedbackResolved/feedbackValue immediately after the
base stream finishes; change it so that after draining the baseStream (inside
createAsyncIterableReadable in attachFeedbackMetadata) you await
feedbackDeferred.promise (only if feedbackDeferred exists) before inspecting
feedbackResolved and feedbackValue, then enqueue the metadata if present; ensure
you still handle errors and finally release the reader (preserve the existing
try/catch/finally structure) so the await doesn’t prevent reader.releaseLock or
error propagation.

In `@website/docs/observability/feedback.md`:
- Around line 96-107: The example incorrectly implies that the VoltAgent
feedback metadata is available on the onFinish callback result; clarify that
onFinish receives the underlying AI SDK StreamTextResult and does not include
VoltAgent feedback, and that VoltAgent attaches feedback metadata to the
returned stream object (agent.streamText -> stream.feedback). Update the example
to either remove accessing result.feedback inside onFinish and instead read
stream.feedback after the stream completes, or show consuming stream.textStream
(for await .. of) and then logging stream.feedback once finished, and mention
the types: StreamTextResult vs the VoltAgent stream wrapper.
♻️ Duplicate comments (1)
packages/core/src/agent/agent.ts (1)

539-539: feedbackFlushCompleted is dead code.

This variable is declared as const feedbackFlushCompleted = false and never modified, making the if (!feedbackFlushCompleted) checks at lines 875 and 1306 always evaluate to true. Either remove the variable and the conditional checks, or convert to let and set it to true after the flush completes if this is meant to prevent duplicate flushes.

🧹 Nitpick comments (3)
examples/with-feedback/package.json (1)

1-36: Consider adding a version field.

The package.json is missing a version field. While not strictly required for private packages, including it is a best practice for consistency and tooling compatibility.

Suggested addition
 {
   "name": "voltagent-example-with-feedback",
+  "version": "0.0.0",
   "author": "",
examples/README.md (1)

111-111: Consider alphabetical ordering.

The new "Feedback Templates" entry is placed after "Langfuse", but alphabetically "F" comes before "L". If the list is meant to be alphabetically ordered, this entry should appear earlier in the list (around line 106, after "Dynamic Prompts" and before "Google AI").

website/docs/observability/feedback.md (1)

38-41: Consider rewording for variety (optional).

Three consecutive bullet points start with "If". While the meaning is clear, you could vary the structure for better readability:

Suggested rewording
-- If a key exists with `feedback_config`, it is reused when `feedbackConfig` is omitted.
-- If a key does not exist and you pass `feedbackConfig`, the key is created automatically.
-- If a key exists, the stored config wins. Update the key if you need to change the schema.
+- Existing keys with `feedback_config` are reused when `feedbackConfig` is omitted.
+- New keys are created automatically when you pass `feedbackConfig` for an unregistered key.
+- Stored config takes precedence over request config. Update the key in Console to change the schema.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 969db3a and 07822f0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • examples/README.md
  • examples/with-feedback/.env.example
  • examples/with-feedback/.gitignore
  • examples/with-feedback/README.md
  • examples/with-feedback/package.json
  • examples/with-feedback/src/index.ts
  • examples/with-feedback/tsconfig.json
  • packages/core/src/agent/agent.ts
  • packages/core/src/agent/conversation-buffer.ts
  • packages/core/src/agent/types.ts
  • packages/core/src/index.ts
  • packages/core/src/voltops/client.ts
  • packages/core/src/voltops/index.ts
  • packages/core/src/voltops/types.ts
  • packages/server-core/src/handlers/agent.handlers.ts
  • packages/server-core/src/schemas/agent.schemas.ts
  • website/docs/agents/message-types.md
  • website/docs/agents/overview.md
  • website/docs/observability/feedback.md
  • website/sidebars.ts
  • website/src/data/tweets.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Maintain type safety in TypeScript-first codebase
Never use JSON.stringify; use the safeStringify function instead, imported from @voltagent/internal

Files:

  • packages/server-core/src/handlers/agent.handlers.ts
  • packages/core/src/agent/conversation-buffer.ts
  • examples/with-feedback/src/index.ts
  • website/sidebars.ts
  • packages/core/src/voltops/index.ts
  • packages/core/src/index.ts
  • packages/server-core/src/schemas/agent.schemas.ts
  • packages/core/src/agent/types.ts
  • packages/core/src/voltops/client.ts
  • packages/core/src/agent/agent.ts
  • packages/core/src/voltops/types.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: VoltAgent/voltagent PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T05:09:23.227Z
Learning: Always check existing patterns before implementing new features in VoltAgent
Learnt from: CR
Repo: VoltAgent/voltagent PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T05:09:23.227Z
Learning: Use the established registry patterns for agent and tool management in VoltAgent
📚 Learning: 2026-01-07T05:09:23.227Z
Learnt from: CR
Repo: VoltAgent/voltagent PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T05:09:23.227Z
Learning: Applies to **/*.ts : Maintain type safety in TypeScript-first codebase

Applied to files:

  • examples/with-feedback/tsconfig.json
📚 Learning: 2026-01-07T05:09:23.227Z
Learnt from: CR
Repo: VoltAgent/voltagent PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T05:09:23.227Z
Learning: Applies to **/*.test.ts : Test your changes - ensure all tests pass before committing

Applied to files:

  • examples/with-feedback/tsconfig.json
🧬 Code graph analysis (4)
examples/with-feedback/src/index.ts (3)
packages/core/src/agent/agent.ts (1)
  • Agent (417-4711)
packages/core/src/index.ts (3)
  • Agent (34-34)
  • VoltAgent (228-228)
  • VoltAgent (229-229)
packages/server-hono/src/index.ts (1)
  • honoServer (8-12)
packages/server-core/src/schemas/agent.schemas.ts (1)
packages/server-hono/src/zod-openapi-compat.ts (1)
  • z (91-91)
packages/core/src/agent/types.ts (3)
packages/core/src/index.ts (2)
  • AgentFeedbackOptions (150-150)
  • AgentFeedbackMetadata (151-151)
packages/core/src/voltops/index.ts (2)
  • VoltOpsFeedbackConfig (38-38)
  • VoltOpsFeedbackExpiresIn (39-39)
packages/core/src/voltops/types.ts (2)
  • VoltOpsFeedbackConfig (123-133)
  • VoltOpsFeedbackExpiresIn (135-139)
packages/core/src/voltops/client.ts (2)
packages/core/src/voltops/index.ts (3)
  • VoltOpsFeedbackTokenCreateInput (41-41)
  • VoltOpsFeedbackToken (40-40)
  • VoltOpsFeedbackConfig (38-38)
packages/core/src/voltops/types.ts (3)
  • VoltOpsFeedbackTokenCreateInput (148-154)
  • VoltOpsFeedbackToken (141-146)
  • VoltOpsFeedbackConfig (123-133)
🪛 LanguageTool
website/docs/observability/feedback.md

[style] ~40-~40: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...g`, the key is created automatically. - If a key exists, the stored config wins. U...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Test create-voltagent-app
  • GitHub Check: Test cli
  • GitHub Check: Test server-core
  • GitHub Check: Test logger
  • GitHub Check: Test postgres
  • GitHub Check: Test supabase
  • GitHub Check: Test docs-mcp
  • GitHub Check: Test libsql
  • GitHub Check: Test internal
  • GitHub Check: Test voice
  • GitHub Check: Test core
  • GitHub Check: Build (Node 22)
  • GitHub Check: Lint (Node 20)
  • GitHub Check: Build (Node 24)
  • GitHub Check: Build (Node 20)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (37)
website/sidebars.ts (1)

275-275: LGTM!

The new sidebar entry for feedback documentation is correctly placed within the Observability category and follows the existing pattern.

examples/with-feedback/.env.example (1)

1-3: LGTM!

The environment variable template correctly documents the required keys for the feedback example with appropriate placeholder values.

examples/with-feedback/.gitignore (1)

1-5: LGTM!

The .gitignore correctly excludes build artifacts, environment files with secrets, and local development directories.

examples/with-feedback/tsconfig.json (1)

1-14: LGTM!

The TypeScript configuration is well-suited for the example project with strict mode enabled (maintaining type safety per coding guidelines), ES2022 target, and NodeNext module resolution that aligns with the ES module setup in package.json.

website/docs/agents/message-types.md (1)

154-169: LGTM!

The documentation clearly explains how feedback metadata is attached to assistant UI messages and provides a concise TypeScript example demonstrating safe access patterns with optional chaining. The cross-reference to the full feedback documentation is helpful.

examples/with-feedback/README.md (1)

1-57: LGTM!

The README is well-structured with clear setup instructions, environment configuration steps, and practical curl examples for each feedback template type. The reference to the Console Observability Playground for UI testing is a helpful addition.

website/src/data/tweets.json (1)

8-11: Formatting-only changes.

These changes reformat nested arrays to multi-line representation for improved readability. No functional or semantic changes are introduced.

examples/with-feedback/src/index.ts (5)

1-10: LGTM!

Clean imports and logger setup. The logger configuration with descriptive name and appropriate log level follows VoltAgent patterns.


11-25: LGTM!

The thumbs feedback agent demonstrates a binary categorical feedback schema with clear labels. Using numeric values (0/1) for "Not helpful"/"Helpful" is appropriate for this thumbs-up/down pattern.


27-39: LGTM!

The rating agent correctly demonstrates continuous feedback with a 1-5 scale, which is a common pattern for relevance/quality scoring.


41-57: LGTM!

The issues agent demonstrates multi-category feedback for tagging response quality issues. The categories (Incorrect, Incomplete, Unsafe, Other) cover common feedback scenarios well.


59-67: LGTM!

The VoltAgent instantiation correctly registers all three agents with descriptive keys that match the endpoint paths documented in the README. The server and logger are properly wired.

packages/core/src/agent/conversation-buffer.ts (1)

109-127: LGTM!

The implementation correctly handles edge cases (empty metadata, missing assistant message) and follows established patterns in this class for metadata merging and pending message tracking. The defensive checks at the start ensure safe operation.

packages/core/src/voltops/types.ts (2)

123-154: LGTM!

The feedback types are well-defined with appropriate optionality. The VoltOpsFeedbackConfig index signature [key: string]: any provides extensibility for future config properties, which aligns with the pattern used elsewhere in this file (e.g., PromptApiResponse.config).


942-943: LGTM!

The interface extension correctly declares the createFeedbackToken method signature matching the implementation in client.ts.

packages/core/src/voltops/index.ts (1)

38-41: LGTM!

The new feedback type exports correctly extend the public API surface, following the established pattern in this barrel file.

packages/core/src/voltops/client.ts (2)

58-60: LGTM!

The imports correctly bring in the new feedback types needed for the method implementation.


243-283: LGTM!

The implementation is well-structured:

  • Correctly transforms camelCase to snake_case for the API payload
  • Uses this.request() which internally uses safeStringify (compliant with coding guidelines)
  • Properly validates required response fields before returning
  • The fallback chain for feedbackConfig (line 271) appropriately prefers server response over input

One consideration: if input.expiresAt is a Date object, it will be serialized by safeStringify in the underlying request() method. Verify the API accepts ISO string format for expires_at.

packages/core/src/agent/types.ts (5)

37-39: LGTM!

The imports correctly bring in the VoltOps feedback types for use in agent-level type definitions.


56-70: LGTM!

The feedback type definitions are well-designed:

  • AgentFeedbackOptions mirrors VoltOpsFeedbackTokenCreateInput appropriately, omitting traceId since it's determined at runtime
  • AgentFeedbackMetadata captures all necessary information for consumers to submit feedback, with traceId, key, and url as required fields

487-487: LGTM!

The feedback?: AgentFeedbackOptions | boolean pattern allows both simple enable/disable (feedback: true) and detailed configuration, consistent with similar patterns in this file (e.g., memory?: Memory | false).


689-691: LGTM!

Adding feedback to CommonGenerateOptions enables per-call override of agent-level feedback configuration, following the established pattern for other options like maxSteps.


1007-1009: LGTM!

The feedback field is consistently added to both StreamTextFinishResult and StandardizedTextResult with the same optional/nullable type, ensuring consumers receive feedback metadata regardless of whether they use streaming or non-streaming APIs.

Also applies to: 1069-1070

packages/core/src/index.ts (1)

150-151: LGTM!

The new type exports AgentFeedbackOptions and AgentFeedbackMetadata are correctly placed alongside related agent types and follow the established export pattern in this file.

packages/core/src/agent/agent.ts (6)

310-321: LGTM!

The Deferred<T> type and createDeferred helper implement a standard deferred pattern correctly. The design choice to only expose resolve (not reject) is appropriate here since error cases resolve to null rather than rejecting.


785-802: LGTM!

The feedback flow in generateText correctly:

  1. Initiates feedback token creation asynchronously at the start
  2. Defers persistence when feedback is enabled
  3. Awaits the feedback promise before attaching metadata
  4. Adds feedback to the last assistant message before final persistence
  5. Includes feedback in the returned result

1291-1313: LGTM!

The onFinish feedback handling correctly coordinates the async token creation:

  • Sets feedbackFinalizeRequested to signal stream completion
  • Awaits the deferred promise if feedback hasn't resolved yet
  • Uses scheduleFeedbackPersist with the feedbackApplied guard to prevent duplicates
  • Falls back to regular persistence if feedback is null

2705-2784: LGTM!

The feedback helper methods are well-implemented:

  • resolveFeedbackOptions correctly normalizes true to {} for convenience
  • getFeedbackTraceId safely handles span context errors
  • getFeedbackClient validates the client has valid keys before returning
  • createFeedbackMetadata gracefully handles errors by returning null and logging debug info

1745-1745: LGTM!

Correctly excluding the feedback option from generateObject and streamObject - feedback is only supported for text generation operations per the PR design.


353-353: LGTM!

The feedback field in BaseGenerationOptions correctly supports both a simple boolean toggle (true to enable with defaults) and detailed configuration via AgentFeedbackOptions.

packages/server-core/src/schemas/agent.schemas.ts (3)

75-110: LGTM!

The feedback schemas are well-structured:

  • FeedbackConfigSchema supports all three feedback types (continuous, categorical, freeform) with appropriate optional fields
  • FeedbackExpiresInSchema provides flexible relative expiration
  • FeedbackOptionsSchema correctly uses .nullish().optional() for feedbackConfig to allow both null and undefined
  • All schemas use .passthrough() for forward compatibility

195-198: LGTM!

The feedback field in GenerateOptionsSchema correctly mirrors the BaseGenerationOptions.feedback type, supporting both boolean and detailed configuration.


233-244: LGTM!

The response schema correctly defines the feedback metadata structure matching AgentFeedbackMetadata from core, with appropriate optionality for fields like tokenId and expiresAt.

packages/server-core/src/handlers/agent.handlers.ts (1)

95-95: LGTM!

The feedback metadata is correctly included in the API response. Using ?? null ensures consistent JSON serialization (null rather than undefined) and aligns with the TextResponseSchema which expects a nullable feedback field.

website/docs/observability/feedback.md (2)

7-32: LGTM!

The overview clearly explains how feedback works and the metadata shape example accurately reflects the AgentFeedbackMetadata type from the implementation.


109-158: LGTM!

The useChat integration example is comprehensive, showing:

  • Custom transport configuration with feedback options
  • Accessing feedback from message metadata
  • Submitting feedback to the tokenized URL

Good use of safeStringify from @voltagent/internal as per the coding guidelines.

website/docs/agents/overview.md (1)

114-131: No changes needed—the feedback API documentation is accurate.

The documented feedback option structure (key, feedbackConfig), the feedbackConfig type (type, categories), and the result property (result.feedback?.url) all match the actual TypeScript type definitions in the implementation (AgentFeedbackOptions, VoltOpsFeedbackConfig, and AgentFeedbackMetadata). The example correctly demonstrates the API shape.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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.

2 issues found across 22 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/src/agent/agent.ts">

<violation number="1" location="packages/core/src/agent/agent.ts:1297">
P2: Race condition: `attachFeedbackMetadata` checks `feedbackResolved` synchronously when stream ends, but feedback token creation is async. If stream ends before feedback resolves, metadata won't be attached. Consider awaiting `feedbackDeferred.promise` before the feedback check.</violation>
</file>

<file name="packages/server-core/src/schemas/agent.schemas.ts">

<violation number="1" location="packages/server-core/src/schemas/agent.schemas.ts:106">
P2: `expiresAt` is documented as an ISO-8601 timestamp but is only validated as a generic string. Use `z.string().datetime()` so invalid expiration dates are rejected early.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

.object({
key: z.string().optional().describe("Feedback key for the trace"),
feedbackConfig: FeedbackConfigSchema.nullish().optional(),
expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
Copy link
Contributor

Choose a reason for hiding this comment

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

P2: expiresAt is documented as an ISO-8601 timestamp but is only validated as a generic string. Use z.string().datetime() so invalid expiration dates are rejected early.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-core/src/schemas/agent.schemas.ts, line 106:

<comment>`expiresAt` is documented as an ISO-8601 timestamp but is only validated as a generic string. Use `z.string().datetime()` so invalid expiration dates are rejected early.</comment>

<file context>
@@ -72,6 +72,43 @@ export const BasicJsonSchema = z
+  .object({
+    key: z.string().optional().describe("Feedback key for the trace"),
+    feedbackConfig: FeedbackConfigSchema.nullish().optional(),
+    expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
+    expiresIn: FeedbackExpiresInSchema.optional(),
+  })
</file context>
Suggested change
expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
expiresAt: z.string().datetime().optional().describe("Absolute expiration timestamp (ISO 8601)"),

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: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/agent/agent.ts`:
- Around line 2723-2733: The VoltOpsClient implementation exposes hasValidKeys()
but the VoltOpsClient interface in packages/core/src/voltops/types.ts is missing
that method signature; update the VoltOpsClient interface to include
hasValidKeys(): boolean; so the class correctly implements the interface and
TypeScript type checks pass (ensure the signature matches the class method name
and return type).
🧹 Nitpick comments (1)
website/docs/observability/feedback.md (1)

38-41: Consider varying sentence structure for readability.

Three successive sentences begin with "If a key". While functional, varying the structure improves flow.

Suggested wording
-- If a key exists with `feedback_config`, it is reused when `feedbackConfig` is omitted.
-- If a key does not exist and you pass `feedbackConfig`, the key is created automatically.
-- If a key exists, the stored config wins. Update the key if you need to change the schema.
+- When a key already exists with `feedback_config`, that config is reused if you omit `feedbackConfig`.
+- For new keys, passing `feedbackConfig` automatically creates the key.
+- Stored config takes precedence over request-time config. Update the key if you need to change the schema.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07822f0 and acc3ef1.

📒 Files selected for processing (2)
  • packages/core/src/agent/agent.ts
  • website/docs/observability/feedback.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Maintain type safety in TypeScript-first codebase
Never use JSON.stringify; use the safeStringify function instead, imported from @voltagent/internal

Files:

  • packages/core/src/agent/agent.ts
🧬 Code graph analysis (1)
packages/core/src/agent/agent.ts (2)
packages/core/src/agent/types.ts (2)
  • AgentFeedbackMetadata (63-70)
  • AgentFeedbackOptions (56-61)
packages/core/src/voltops/types.ts (1)
  • VoltOpsClient (929-964)
🪛 LanguageTool
website/docs/observability/feedback.md

[style] ~40-~40: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...g`, the key is created automatically. - If a key exists, the stored config wins. U...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Test libsql
  • GitHub Check: Test voice
  • GitHub Check: Test server-core
  • GitHub Check: Test create-voltagent-app
  • GitHub Check: Test supabase
  • GitHub Check: Test logger
  • GitHub Check: Test core
  • GitHub Check: Test postgres
  • GitHub Check: Test cli
  • GitHub Check: Test internal
  • GitHub Check: Build (Node 20)
  • GitHub Check: Build (Node 24)
  • GitHub Check: Build (Node 22)
  • GitHub Check: Lint (Node 22)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (9)
packages/core/src/agent/agent.ts (7)

310-321: LGTM - Standard deferred pattern implementation.

The createDeferred helper correctly implements the deferred/promise pattern for async coordination between feedback token creation and stream completion.


535-547: LGTM - Feedback initialization in generateText.

Properly resolves feedback options, obtains the client, and sets up deferred persistence. The feedback promise is only created when both options and client are available.


784-801: LGTM - Feedback finalization in generateText.

Correct sequence: awaits feedback promise, adds metadata to last assistant message, then flushes if persistence was deferred. The feedback metadata is properly included in the returned result.


893-944: LGTM - Feedback initialization in streamText.

The deferred pattern with multiple guard flags (feedbackResolved, feedbackFinalizeRequested, feedbackApplied) correctly handles the asynchronous coordination between feedback token creation and stream completion. The resolveFeedbackDeferred function properly guards against double resolution.


1287-1299: LGTM - Feedback finalization in onFinish.

Properly sets the finalize flag, awaits the deferred if not resolved, and schedules persistence. Falls back to flushing deferred messages if feedback is unavailable but persistence was deferred.


1527-1562: LGTM - Race condition addressed in attachFeedbackMetadata.

The function now correctly awaits feedbackDeferred.promise (lines 1544-1546) before checking feedbackResolved && feedbackValue, ensuring metadata is properly attached even if the stream completes before feedback token creation finishes.


2735-2781: LGTM - createFeedbackMetadata implementation.

Correctly handles all failure cases (no options, no client, no trace ID, API error) by returning null. Token creation is properly awaited and metadata is constructed with all relevant fields.

website/docs/observability/feedback.md (2)

92-110: LGTM - Streaming feedback documentation corrected.

The documentation now correctly explains that onFinish receives the AI SDK StreamTextResult (line 94) and the example properly shows accessing stream.feedback after consuming the stream (line 109), not from the callback result.


1-254: LGTM - Comprehensive feedback documentation.

The documentation covers all aspects of the feedback feature: workflow explanation, metadata schema, SDK usage (agent-level, per-call, streaming), useChat integration, API endpoints, and custom configurations. Well-structured with clear examples.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +2723 to +2733
private getFeedbackClient(): VoltOpsClient | undefined {
const voltOpsClient =
this.voltOpsClient || AgentRegistry.getInstance().getGlobalVoltOpsClient();
if (!voltOpsClient || typeof voltOpsClient.hasValidKeys !== "function") {
return undefined;
}
if (!voltOpsClient.hasValidKeys()) {
return undefined;
}
return voltOpsClient;
}
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for hasValidKeys definition in TypeScript files
echo "=== Searching for hasValidKeys ==="
rg -n "hasValidKeys" --type ts -B 2 -A 2

echo ""
echo "=== Searching for VoltOpsClient interface definition ==="
rg -n "interface VoltOpsClient" --type ts -A 20

echo ""
echo "=== Searching for VoltOpsClient class definition ==="
rg -n "class VoltOpsClient" --type ts -A 20

Repository: VoltAgent/voltagent

Length of output: 13439


🏁 Script executed:

#!/bin/bash
# Get the complete VoltOpsClient interface definition
echo "=== VoltOpsClient interface definition ==="
rg -n "interface VoltOpsClient" --type ts -A 100 packages/core/src/voltops/types.ts | head -120

Repository: VoltAgent/voltagent

Length of output: 3538


🏁 Script executed:

#!/bin/bash
# Find IVoltOpsClient interface definition
echo "=== Searching for IVoltOpsClient interface ==="
rg -n "interface IVoltOpsClient" --type ts -A 100

echo ""
echo "=== Verify which interface VoltOpsClient class implements ==="
rg -n "class VoltOpsClient implements" --type ts -A 2

Repository: VoltAgent/voltagent

Length of output: 482


🏁 Script executed:

#!/bin/bash
# Search for IVoltOpsClient everywhere
echo "=== Searching for IVoltOpsClient ==="
rg "IVoltOpsClient" --type ts -B 2 -A 5

echo ""
echo "=== Check imports in client.ts ==="
head -50 packages/core/src/voltops/client.ts

Repository: VoltAgent/voltagent

Length of output: 5020


Add hasValidKeys() method to the VoltOpsClient interface.

The hasValidKeys() method is implemented in the VoltOpsClient class but is missing from the VoltOpsClient interface declaration in packages/core/src/voltops/types.ts. This creates a type safety gap where the class violates its interface contract. Add the method signature hasValidKeys(): boolean; to the interface to maintain proper type safety across the codebase.

🤖 Prompt for AI Agents
In `@packages/core/src/agent/agent.ts` around lines 2723 - 2733, The VoltOpsClient
implementation exposes hasValidKeys() but the VoltOpsClient interface in
packages/core/src/voltops/types.ts is missing that method signature; update the
VoltOpsClient interface to include hasValidKeys(): boolean; so the class
correctly implements the interface and TypeScript type checks pass (ensure the
signature matches the class method name and return type).

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 22 files

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.

2 issues found across 23 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/server-core/src/schemas/agent.schemas.ts">

<violation number="1" location="packages/server-core/src/schemas/agent.schemas.ts:106">
P2: `expiresAt` is declared as an ISO 8601 timestamp but validated as any string, so malformed dates pass schema validation and fail downstream. Use `.datetime()` to enforce the documented format.</violation>
</file>

<file name="packages/core/src/agent/agent.ts">

<violation number="1" location="packages/core/src/agent/agent.ts:935">
P2: `feedbackValue` can be set after `resolveFeedbackDeferred(null)` (e.g., on stream error), leading to inconsistent feedback state and possibly emitting `message-metadata` even though feedback was intentionally nulled. Guard the `.then` handler so it doesn’t mutate state after the deferred has been resolved.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

.object({
key: z.string().optional().describe("Feedback key for the trace"),
feedbackConfig: FeedbackConfigSchema.nullish().optional(),
expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
Copy link
Contributor

Choose a reason for hiding this comment

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

P2: expiresAt is declared as an ISO 8601 timestamp but validated as any string, so malformed dates pass schema validation and fail downstream. Use .datetime() to enforce the documented format.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-core/src/schemas/agent.schemas.ts, line 106:

<comment>`expiresAt` is declared as an ISO 8601 timestamp but validated as any string, so malformed dates pass schema validation and fail downstream. Use `.datetime()` to enforce the documented format.</comment>

<file context>
@@ -72,6 +72,43 @@ export const BasicJsonSchema = z
+  .object({
+    key: z.string().optional().describe("Feedback key for the trace"),
+    feedbackConfig: FeedbackConfigSchema.nullish().optional(),
+    expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
+    expiresIn: FeedbackExpiresInSchema.optional(),
+  })
</file context>
Suggested change
expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"),
expiresAt: z.string().datetime().optional().describe("Absolute expiration timestamp (ISO 8601)"),

if (feedbackPromise) {
feedbackPromise
.then((metadata) => {
feedbackValue = metadata;
Copy link
Contributor

Choose a reason for hiding this comment

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

P2: feedbackValue can be set after resolveFeedbackDeferred(null) (e.g., on stream error), leading to inconsistent feedback state and possibly emitting message-metadata even though feedback was intentionally nulled. Guard the .then handler so it doesn’t mutate state after the deferred has been resolved.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/agent/agent.ts, line 935:

<comment>`feedbackValue` can be set after `resolveFeedbackDeferred(null)` (e.g., on stream error), leading to inconsistent feedback state and possibly emitting `message-metadata` even though feedback was intentionally nulled. Guard the `.then` handler so it doesn’t mutate state after the deferred has been resolved.</comment>

<file context>
@@ -853,6 +915,33 @@ export class Agent {
+      if (feedbackPromise) {
+        feedbackPromise
+          .then((metadata) => {
+            feedbackValue = metadata;
+            resolveFeedbackDeferred(metadata);
+            if (feedbackFinalizeRequested) {
</file context>
Suggested change
feedbackValue = metadata;
if (feedbackResolved) {
return;
}
feedbackValue = metadata;

@omeraplak omeraplak merged commit 74dced8 into main Jan 15, 2026
23 checks passed
@omeraplak omeraplak deleted the feat/feedback branch January 15, 2026 03:09
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.

2 participants