-
-
Notifications
You must be signed in to change notification settings - Fork 462
feat: add feedback #940
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add feedback #940
Conversation
|
This comment has been minimized.
This comment has been minimized.
Deploying voltagent with
|
| Latest commit: |
c21c98d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c2fca7bb.voltagent.pages.dev |
| Branch Preview URL: | https://feat-feedback.voltagent.pages.dev |
There was a problem hiding this 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.
|
Note Other AI code review bot(s) detectedCodeRabbit 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. 📝 WalkthroughWalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used📓 Path-based instructions (1)**/*.ts📄 CodeRabbit inference engine (AGENTS.md)
Files:
🪛 LanguageToolwebsite/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. (ENGLISH_WORD_REPEAT_BEGINNING_RULE) [grammar] ~114-~114: Use a hyphen to join words. (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)
🔇 Additional comments (5)
✏️ Tip: You can disable this entire section by setting Comment |
There was a problem hiding this 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:feedbackFlushCompletedis dead code.This variable is declared as
const feedbackFlushCompleted = falseand never modified, making theif (!feedbackFlushCompleted)checks at lines 875 and 1306 always evaluate totrue. Either remove the variable and the conditional checks, or convert toletand set it totrueafter the flush completes if this is meant to prevent duplicate flushes.
🧹 Nitpick comments (3)
examples/with-feedback/package.json (1)
1-36: Consider adding aversionfield.The package.json is missing a
versionfield. 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
examples/README.mdexamples/with-feedback/.env.exampleexamples/with-feedback/.gitignoreexamples/with-feedback/README.mdexamples/with-feedback/package.jsonexamples/with-feedback/src/index.tsexamples/with-feedback/tsconfig.jsonpackages/core/src/agent/agent.tspackages/core/src/agent/conversation-buffer.tspackages/core/src/agent/types.tspackages/core/src/index.tspackages/core/src/voltops/client.tspackages/core/src/voltops/index.tspackages/core/src/voltops/types.tspackages/server-core/src/handlers/agent.handlers.tspackages/server-core/src/schemas/agent.schemas.tswebsite/docs/agents/message-types.mdwebsite/docs/agents/overview.mdwebsite/docs/observability/feedback.mdwebsite/sidebars.tswebsite/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 thesafeStringifyfunction instead, imported from@voltagent/internal
Files:
packages/server-core/src/handlers/agent.handlers.tspackages/core/src/agent/conversation-buffer.tsexamples/with-feedback/src/index.tswebsite/sidebars.tspackages/core/src/voltops/index.tspackages/core/src/index.tspackages/server-core/src/schemas/agent.schemas.tspackages/core/src/agent/types.tspackages/core/src/voltops/client.tspackages/core/src/agent/agent.tspackages/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
VoltOpsFeedbackConfigindex signature[key: string]: anyprovides 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
createFeedbackTokenmethod signature matching the implementation inclient.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 usessafeStringify(compliant with coding guidelines)- Properly validates required response fields before returning
- The fallback chain for
feedbackConfig(line 271) appropriately prefers server response over inputOne consideration: if
input.expiresAtis aDateobject, it will be serialized bysafeStringifyin the underlyingrequest()method. Verify the API accepts ISO string format forexpires_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:
AgentFeedbackOptionsmirrorsVoltOpsFeedbackTokenCreateInputappropriately, omittingtraceIdsince it's determined at runtimeAgentFeedbackMetadatacaptures all necessary information for consumers to submit feedback, withtraceId,key, andurlas required fields
487-487: LGTM!The
feedback?: AgentFeedbackOptions | booleanpattern 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
feedbacktoCommonGenerateOptionsenables per-call override of agent-level feedback configuration, following the established pattern for other options likemaxSteps.
1007-1009: LGTM!The
feedbackfield is consistently added to bothStreamTextFinishResultandStandardizedTextResultwith 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
AgentFeedbackOptionsandAgentFeedbackMetadataare 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 andcreateDeferredhelper implement a standard deferred pattern correctly. The design choice to only exposeresolve(notreject) is appropriate here since error cases resolve tonullrather than rejecting.
785-802: LGTM!The feedback flow in
generateTextcorrectly:
- Initiates feedback token creation asynchronously at the start
- Defers persistence when feedback is enabled
- Awaits the feedback promise before attaching metadata
- Adds feedback to the last assistant message before final persistence
- Includes feedback in the returned result
1291-1313: LGTM!The
onFinishfeedback handling correctly coordinates the async token creation:
- Sets
feedbackFinalizeRequestedto signal stream completion- Awaits the deferred promise if feedback hasn't resolved yet
- Uses
scheduleFeedbackPersistwith thefeedbackAppliedguard to prevent duplicates- Falls back to regular persistence if feedback is null
2705-2784: LGTM!The feedback helper methods are well-implemented:
resolveFeedbackOptionscorrectly normalizestrueto{}for conveniencegetFeedbackTraceIdsafely handles span context errorsgetFeedbackClientvalidates the client has valid keys before returningcreateFeedbackMetadatagracefully handles errors by returningnulland logging debug info
1745-1745: LGTM!Correctly excluding the
feedbackoption fromgenerateObjectandstreamObject- feedback is only supported for text generation operations per the PR design.
353-353: LGTM!The
feedbackfield inBaseGenerationOptionscorrectly supports both a simple boolean toggle (trueto enable with defaults) and detailed configuration viaAgentFeedbackOptions.packages/server-core/src/schemas/agent.schemas.ts (3)
75-110: LGTM!The feedback schemas are well-structured:
FeedbackConfigSchemasupports all three feedback types (continuous, categorical, freeform) with appropriate optional fieldsFeedbackExpiresInSchemaprovides flexible relative expirationFeedbackOptionsSchemacorrectly uses.nullish().optional()forfeedbackConfigto allow bothnullandundefined- All schemas use
.passthrough()for forward compatibility
195-198: LGTM!The
feedbackfield inGenerateOptionsSchemacorrectly mirrors theBaseGenerationOptions.feedbacktype, supporting both boolean and detailed configuration.
233-244: LGTM!The response schema correctly defines the feedback metadata structure matching
AgentFeedbackMetadatafrom core, with appropriate optionality for fields liketokenIdandexpiresAt.packages/server-core/src/handlers/agent.handlers.ts (1)
95-95: LGTM!The feedback metadata is correctly included in the API response. Using
?? nullensures consistent JSON serialization (null rather than undefined) and aligns with theTextResponseSchemawhich 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
AgentFeedbackMetadatatype from the implementation.
109-158: LGTM!The
useChatintegration example is comprehensive, showing:
- Custom transport configuration with feedback options
- Accessing feedback from message metadata
- Submitting feedback to the tokenized URL
Good use of
safeStringifyfrom@voltagent/internalas 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), thefeedbackConfigtype (type,categories), and the result property (result.feedback?.url) all match the actual TypeScript type definitions in the implementation (AgentFeedbackOptions,VoltOpsFeedbackConfig, andAgentFeedbackMetadata). The example correctly demonstrates the API shape.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this 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)"), |
There was a problem hiding this comment.
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>
| expiresAt: z.string().optional().describe("Absolute expiration timestamp (ISO 8601)"), | |
| expiresAt: z.string().datetime().optional().describe("Absolute expiration timestamp (ISO 8601)"), |
There was a problem hiding this 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
📒 Files selected for processing (2)
packages/core/src/agent/agent.tswebsite/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 thesafeStringifyfunction 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
createDeferredhelper 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. TheresolveFeedbackDeferredfunction 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 checkingfeedbackResolved && 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
onFinishreceives the AI SDKStreamTextResult(line 94) and the example properly shows accessingstream.feedbackafter 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.
| 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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 20Repository: 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 -120Repository: 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 2Repository: 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.tsRepository: 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).
There was a problem hiding this 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
There was a problem hiding this 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)"), |
There was a problem hiding this comment.
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>
| 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; |
There was a problem hiding this comment.
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>
| feedbackValue = metadata; | |
| if (feedbackResolved) { | |
| return; | |
| } | |
| feedbackValue = metadata; |
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
feedbackoption; tokens created through VoltOps.generateTextandstreamTextresults.message-metadatachunk with feedback info.feedbackin generate options and returnsfeedbackin responses.createFeedbackTokenand feedback types.Docs & Examples
examples/with-feedbackwith thumbs, rating, and issue tagging agents.Written for commit c21c98d. Summary will update on new commits.
Summary by CodeRabbit
Release Notes
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.