Skip to content

ROB-3618: Add chat-analytics fields to HolmesChat schemas#2058

Merged
alonelish merged 12 commits intomasterfrom
claude/vibrant-tu-afcdd3
May 7, 2026
Merged

ROB-3618: Add chat-analytics fields to HolmesChat schemas#2058
alonelish merged 12 commits intomasterfrom
claude/vibrant-tu-afcdd3

Conversation

@alonelish
Copy link
Copy Markdown
Collaborator

Summary

Declare 6 optional analytics fields on the legacy chat path so they're typed and discoverable end-to-end:

  • request_type
  • request_source
  • source_ref
  • conversation_id
  • conversation_source
  • meta

Added to HolmesChatParams (src/robusta/core/model/base_params.py) and HolmesChatRequest (src/robusta/core/reporting/holmes.py). HolmesIssueChatParams / HolmesIssueChatRequest inherit them automatically.

Why

The Holmes server's /api/chat endpoint is being extended to capture these fields for usage slicing (UI surface, multi-turn grouping, etc.). The FE will start sending them. Both schemas already had extra = "allow" and the runner is on Pydantic v1, so the fields functionally pass through today — this change just makes them first-class so they're typed, IDE-autocompletable, and self-documenting at both runner boundaries.

Notes for reviewers

  • All fields are Optional[...] = None — fully backwards-compatible. Old clients that don't send them keep working; the runner forwards null for missing ones.
  • No action-handler changes needed: holmes_chat already uses params.dict()HolmesChatRequest(**params_dict), so declared fields propagate without extra plumbing.
  • holmes_issue_chat uses an explicit kwarg constructor and does not populate the new fields; they default to None on that path. This is intentional — only the legacy /api/chat path is in scope.
  • extra = "allow" is preserved on both classes as a safety net for future fields.

Test plan

  • Static check: HolmesChatParams.__fields__ and HolmesChatRequest.__fields__ both contain the 6 new field names.
  • Round-trip serialization: construct HolmesChatParams(ask="x", conversation_id="ch-1", request_source="alert_investigation", source_ref="issue-2", meta={"k":"v"}), dump via .dict(exclude={"holmes_url","render_graph_images"}), pass into HolmesChatRequest(**...), and confirm the JSON includes the new fields.
  • Backwards-compat: construct HolmesChatParams(ask="x") only and confirm all 6 fields serialize as null.
  • Existing test suite passes.

🤖 Generated with Claude Code

Declare request_type, request_source, source_ref, conversation_id,
conversation_source, and meta as optional fields on HolmesChatParams
and HolmesChatRequest so they're typed and discoverable end-to-end.
The fields already passed through via extra="allow" + Pydantic v1
dict() semantics; this change makes them first-class. HolmesIssueChat*
inherits the fields automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

Docker image ready for 0371c0a (built in 40s)

⚠️ Warning: does not support ARM (ARM images are built on release only - not on every PR)

Use this tag to pull the image for testing.

📋 Copy commands

⚠️ Temporary images are deleted after 30 days. Copy to a permanent registry before using them:

gcloud auth configure-docker us-central1-docker.pkg.dev
docker pull us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:0371c0a
docker tag us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:0371c0a me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:0371c0a
docker push me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:0371c0a

Patch Helm values in one line:

helm upgrade --install robusta robusta/robusta \
  --reuse-values \
  --set runner.image=me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:0371c0a

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Holmes feedback support and extends Holmes chat params/requests with optional request/conversation metadata, an internal flag, and free-form meta; implements a playbook action that POSTs feedback to Holmes, adds tests, and exposes the action in Helm values.

Changes

Holmes feedback + chat metadata

Layer / File(s) Summary
Data Shape
src/robusta/core/model/base_params.py
Extended HolmesChatParams with request_type, request_source, source_ref, conversation_id, conversation_source, is_internal, meta. Added HolmesFeedbackParams (request_id with min_length=1, sentiment: Literal["thumbs_up","thumbs_down"], optional category, comment, Config.extra = "allow").
Core Request Models
src/robusta/core/reporting/holmes.py
Extended HolmesChatRequest with the same optional metadata fields; added HolmesFeedbackRequest Pydantic model for POST /api/feedback (permits extra fields).
Wiring / Integration
src/robusta/core/playbooks/internal/ai_integration.py
Added holmes_feedback action: validates HolmesFeedbackParams, constructs HolmesFeedbackRequest, POSTs to {holmes_url}/api/feedback with timeout, raises/handles non-success responses via existing error path, and records a Finding on success.
Tests
tests/test_ai_integration.py
Added tests mocking requests.post: asserts POST to /api/feedback, payload includes only feedback fields (omits runner-only fields), null-serializes omitted optionals, validates param errors (missing/empty request_id, invalid sentiment), and checks success/error handling (200 adds finding, 5xx raises ActionException and does not add finding).
Configuration
helm/robusta/values.yaml
Added holmes_feedback to holmes.lightActions to expose the action via Helm values.

Sequence Diagram(s)

sequenceDiagram
    participant Playbook as Playbook Action
    participant Event as ExecutionEvent
    participant Client as Holmes HTTP Client
    participant Holmes as Holmes Server
    participant Store as Findings Store

    Playbook->>Event: receive HolmesFeedbackParams
    Playbook->>Client: build HolmesFeedbackRequest (validate, strip runner-only fields)
    Client->>Holmes: POST /api/feedback (timeout)
    Holmes-->>Client: 200 / 4xx / 5xx
    alt 2xx success
        Client-->>Playbook: response
        Playbook->>Store: add_finding(HolmesFeedbackResult)
    else 5xx or exception
        Client-->>Playbook: error
        Playbook->>Playbook: handle_holmes_error (log request_id, raise ActionException)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • arikalon1
  • moshemorad
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The title refers to 'chat-analytics fields' and adding them to schemas, which aligns with the primary objective stated in PR objectives. However, the changeset includes substantial additional work: a new HolmesFeedbackParams model, HolmesFeedbackRequest model, a holmes_feedback action, tests, and Helm config updates. The title only captures the analytics fields aspect and misses the feedback functionality, which represents significant new functionality. Revise the title to reflect both major changes, such as: 'Add chat-analytics fields and feedback action to Holmes schemas' or split into separate PRs if these are logically distinct features.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the six optional analytics fields being added, their purpose, implementation details, and test plan—all directly relevant to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/vibrant-tu-afcdd3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Proxies user feedback (thumbs up/down) on a Holmes answer from the FE
to the Holmes server's POST /api/feedback, which UPDATEs the
HolmesUsageEvents row keyed by request_id.

Mirrors the holmes_oauth pattern (small synchronous POST with
raise_for_status pass-through), with pydantic-level validation of
request_id presence and sentiment via Literal["thumbs_up", "thumbs_down"]
so bad payloads fail at param construction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
src/robusta/core/reporting/holmes.py (1)

70-80: Align feedback sentiment type with the params contract.

HolmesFeedbackRequest.sentiment is currently unconstrained str; mirroring the Literal contract avoids accidental invalid payloads if this model is used outside the current action path.

💡 Proposed refactor
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Dict, List, Literal, Optional, Union
@@
-    sentiment: str
+    sentiment: Literal["thumbs_up", "thumbs_down"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/robusta/core/reporting/holmes.py` around lines 70 - 80,
HolmesFeedbackRequest currently types sentiment as plain str; change it to a
constrained Literal to match the params contract (e.g.,
Literal['positive','negative','neutral'] or the exact allowed tokens used
elsewhere) and import typing.Literal; update the model declaration (class
HolmesFeedbackRequest) to use that Literal type for sentiment and adjust any
callers/validators to conform to the narrowed set so invalid payloads are caught
at model validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/robusta/core/model/base_params.py`:
- Around line 251-252: The request_id field currently typed as plain str accepts
empty strings; update the model that declares request_id and sentiment to
validate non-empty ids by either changing request_id's type to
pydantic.constr(min_length=1) or by using Field(..., min_length=1) on
request_id, and add/import the needed pydantic symbol; alternatively add a
`@validator` for "request_id" that raises a ValueError on empty/whitespace-only
strings so malformed feedback is rejected at validation time.

---

Nitpick comments:
In `@src/robusta/core/reporting/holmes.py`:
- Around line 70-80: HolmesFeedbackRequest currently types sentiment as plain
str; change it to a constrained Literal to match the params contract (e.g.,
Literal['positive','negative','neutral'] or the exact allowed tokens used
elsewhere) and import typing.Literal; update the model declaration (class
HolmesFeedbackRequest) to use that Literal type for sentiment and adjust any
callers/validators to conform to the narrowed set so invalid payloads are caught
at model validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3228b0cc-f9b3-4d64-82e2-144c6b2fba0a

📥 Commits

Reviewing files that changed from the base of the PR and between 87d95ca and 253f5cd.

📒 Files selected for processing (4)
  • src/robusta/core/model/base_params.py
  • src/robusta/core/playbooks/internal/ai_integration.py
  • src/robusta/core/reporting/holmes.py
  • tests/test_ai_integration.py

Comment thread src/robusta/core/model/base_params.py Outdated
alonelish and others added 4 commits April 30, 2026 06:10
The Helm chart's allowlist gates which action names the relay can
forward to the runner. Without this entry the relay rejects
holmes_feedback before it reaches the action handler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Optional boolean alongside the other chat-analytics fields (request_source,
conversation_id, etc.) so the FE can mark internal/test traffic and the
Holmes server can filter it out of usage dashboards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HolmesFeedbackParams.request_id: enforce non-empty via Field(min_length=1)
  so empty strings are rejected at param construction.
- HolmesFeedbackRequest: mirror the params contract — sentiment is now
  Literal["thumbs_up", "thumbs_down"] and request_id has min_length=1, so
  the request body class can't be misused outside the action path.
- Add a test covering the empty-request_id rejection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alonelish alonelish changed the title Add chat-analytics fields to HolmesChat schemas ROB-3618: Add chat-analytics fields to HolmesChat schemas May 3, 2026
alonelish and others added 4 commits May 4, 2026 12:33
Holmes' POST /api/feedback reads user_id from request.query_params, not
the JSON body (mirrors /api/chat's resolution path used by the relay).
Posting it in the body returns 400 "missing user_id". Pull user_id out
of the action params and forward it via the URL query string.

- Declare user_id: Optional[str] on HolmesFeedbackParams so it's
  discoverable; pop it before constructing the request body.
- Update tests to assert user_id is on params= and not in the body.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- handle_holmes_error: log the upstream response body on HTTPError so
  4xx/5xx diagnostics aren't lost in the generic "Holmes internal
  configuration error" branch (e.g. {"detail":"missing user_id"}
  would otherwise be invisible). Benefits all Holmes proxy actions,
  not just feedback.
- holmes_feedback: drop the no-op Finding on success. The FE shows
  the "Thanks" toast optimistically and never reads the response;
  emitting a TYPE_NONE finding for every thumb click was UI noise.
  Replaced with an info log line carrying request_id + sentiment.
- Tests updated to assert add_finding is no longer called.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The feedback flow has moved off the runner: the FE now records thumbs
up/down directly via a Supabase RPC, bypassing the relay → runner →
Holmes path. Drop the runner-side proxy:

- HolmesFeedbackParams and HolmesFeedbackRequest schemas
- holmes_feedback action handler
- 7 unit tests
- helm chart lightActions allowlist entry

Kept from earlier PR commits:
- Chat-analytics fields on HolmesChat schemas (request_source,
  conversation_id, source_ref, conversation_source, request_type,
  is_internal, meta) — still useful for /api/chat
- handle_holmes_error response-body logging — benefits all Holmes
  proxy actions (chat, oauth, conversation, issue_chat)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alonelish alonelish merged commit b14f68d into master May 7, 2026
4 of 5 checks passed
@alonelish alonelish deleted the claude/vibrant-tu-afcdd3 branch May 7, 2026 09:58
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.

3 participants