Skip to main content

What are agent comments?

Agent comments let your AI agents participate in collaboration the same way humans do — by leaving comments and findings anchored to a document. Instead of building a separate UI for agent output, your agent calls the Velt Comment Annotations REST APIs to create annotations that render in the standard Velt comments experience. Agent comments are built on top of the same Comments feature, but they render with a special UI: each agent finding is a suggestion with Accept and Reject buttons on the comment dialog. When a reviewer accepts or rejects a finding, the outcome is emitted on the comment element as the suggestionAccepted / suggestionRejected events, so you can apply the change to your own data or trigger follow-up logic. Any agent that can make an HTTP request can do this — a custom agent you register in the Velt Console, or an external agent running in your own framework (LangChain, CrewAI, a cron job, etc.).

How it works

  1. Your agent runs and produces a finding (a spelling error, an accessibility issue, a code-review note, etc.).
  2. Your agent calls the Add Comment Annotations API with an agent block attached to the root comment. The server stamps sourceType: "agent" on both the comment and the annotation, and generates the annotation-level agent block.
  3. The finding renders in Velt as a suggestion that humans can review, accept, or reject.
  4. You read agent annotations back with the Get Comment Annotations API using agent-specific filters (agentId, executionId, agentSource, and more).

The agent block

Attach an agent object to the root comment (commentData[0]). It is discriminated on agentSource:
FieldRequiredDescription
agentSourceYesOrigin of the agent. One of velt or external.
agentIdRequired for velt, optional for externalA custom agent ID verified server-side. Opaque (never validated) for external agents.
agentNameRequired for externalDisplay name for the agent. The only source of truth for an external agent’s name. (For velt agents the name is resolved server-side.)
executionIdNoExecution / run ID for this agent invocation.
urlNoPage URL associated with the finding.
reasonYesFinding details (title, description, severity, findingType, confidence, suggestedFix, etc.). Custom fields are preserved.
Set the annotation type to "suggestion" so the finding is classified as an agent suggestion rather than a regular comment.

The reason object

The reason object carries the finding’s details. Here’s each field with a description and an example value.
FieldRequiredTypeDescriptionExample
titlestringShort finding title — a quick label for the issue."Low color contrast"
descriptionstringFuller explanation of what the agent found."Contrast ratio is 2.1:1, below the 4.5:1 WCAG AA threshold."
severitystringHow serious the finding is. One of critical, high, medium, low, info."high"
findingIdstringYour own unique ID for the finding, useful for dedup/tracking."finding_a11y_0427"
findingTypestringWhat kind of target the finding is on. One of text, pin, page."pin"
issueTypestringCustom classification you define for your own taxonomy."accessibility"
confidencenumberHow confident the agent is. Integer 0–100.92
suggestionstringSuggested change in plain text (human-readable advice)."Darken the button background to at least #1A1A1A."
suggestedFixstringThe concrete fix value to apply."Welcome"
htmlSnippetstringThe relevant chunk of HTML where the issue lives."<button class='cta'>Buy now</button>"
htmlSelectorstringCSS/HTML selector pointing to the finding’s location.".cta-primary > button"
sourcestringWhere the triggering rule came from. One of instructions, knowledge."knowledge"
knowledgeSectionstringWhich knowledge section fired (pairs with source: "knowledge")."brand-guidelines/accessibility"
A note on the difference between the two “fix” fields, since it’s easy to conflate them: suggestion is prose meant for a human to read in the comment, while suggestedFix is the actual replacement value. For a spelling correction, for instance, suggestedFix would be just "Welcome" — the corrected word itself, not a sentence about it. Putting it together, a fully-populated reason looks like:
"reason": {
  "title": "Low color contrast",
  "description": "Contrast ratio is 2.1:1, below the 4.5:1 WCAG AA threshold.",
  "severity": "high",
  "findingId": "finding_a11y_0427",
  "findingType": "pin",
  "issueType": "accessibility",
  "confidence": 92,
  "suggestion": "Darken the button background to at least #1A1A1A.",
  "suggestedFix": "#1A1A1A",
  "htmlSnippet": "<button class='cta'>Buy now</button>",
  "htmlSelector": ".cta-primary > button",
  "source": "knowledge",
  "knowledgeSection": "brand-guidelines/accessibility"
}
Only the first three (title, description, severity) are required — everything else is optional, and any extra custom fields you add beyond this list are preserved by the server.

Example: leave a comment from an external agent

This is the most common path — an agent running in your own framework leaves a finding. Use agentSource: "external" and supply your own agentName.
curl -X POST 'https://api.velt.dev/v2/commentannotations/add' \
  -H 'x-velt-api-key: YOUR_API_KEY' \
  -H 'x-velt-auth-token: YOUR_AUTH_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
      "organizationId": "acme-corp",
      "documentId": "design-mockup-v2",
      "commentAnnotations": [
        {
          "type": "suggestion",
          "commentData": [
            {
              "commentText": "This button has insufficient color contrast.",
              "from": { "userId": "a11y-bot" },
              "agent": {
                "agentSource": "external",
                "agentName": "Accessibility Bot",
                "agentId": "a11y-bot",
                "executionId": "run_8f21",
                "url": "https://example.com/design-mockup-v2",
                "reason": {
                  "title": "Low color contrast",
                  "description": "Contrast ratio is 2.1:1, below the 4.5:1 WCAG AA threshold.",
                  "severity": "high",
                  "findingType": "pin"
                }
              }
            }
          ]
        }
      ]
    }
  }'

Reading agent comments back

Use the Get Comment Annotations API with agent-specific filters to fetch what your agents have left. Only one agent filter may be supplied per request.
FilterDescription
agentIdAnnotations created by a specific agent.
executionIdAnnotations from a specific agent run.
agentSourcevelt or external.
agentSuggestionsWhen true, returns only fresh (unaccepted) agent suggestions.
agentCommentsWhen true, returns all agent annotations regardless of status.
cURL
curl -X POST 'https://api.velt.dev/v2/commentannotations/get' \
  -H 'x-velt-api-key: YOUR_API_KEY' \
  -H 'x-velt-auth-token: YOUR_AUTH_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
      "organizationId": "acme-corp",
      "documentId": "design-mockup-v2",
      "agentId": "a11y-bot"
    }
  }'
Agent annotations in the response carry type: "suggestion" and sourceType: "agent" at the annotation root, an annotation-root agent block, and an agent block on each agent-authored comment (comments[].agent).
The Get Comment Annotations API requires the advanced queries option to be enabled in the Velt Console and the v4 series of the Velt SDK. See the API reference for details.

Handle accept / reject in your app

Because agent findings render with Accept and Reject buttons on the comment dialog, the outcome is emitted on the comment element. Subscribe to the suggestionAccepted and suggestionRejected events to apply the change to your own data or trigger follow-up logic. The SDK records the outcome and persists the suggestion — applying the change is your code’s job.
import { useCommentEventCallback } from '@veltdev/react';

export function AgentSuggestionListener() {
  const accepted = useCommentEventCallback('suggestionAccepted');
  const rejected = useCommentEventCallback('suggestionRejected');

  useEffect(() => {
    if (accepted) {
      // accepted.commentAnnotation contains the agent finding
      console.log('Suggestion accepted', accepted.commentAnnotation);
    }
  }, [accepted]);

  useEffect(() => {
    if (rejected) {
      console.log('Suggestion rejected', rejected.rejectReason);
    }
  }, [rejected]);

  return null;
}
For the full suggestion lifecycle — statuses, applying newValue, and the other suggestion-stream events — see the Suggestions guide.

API reference

  • Add Comment Annotations — full reference for the Add API, including the agent block and agent suggestion examples.
  • Get Comment Annotations — full reference for the Get API, including all agent filters and response field notes.
  • Comment Events — subscribe to the suggestionAccepted and suggestionRejected comment events to react to accept/reject outcomes.