-
Notifications
You must be signed in to change notification settings - Fork 957
[issue-2572] [FE] Update experiment name metadata in UI #3136
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
base: main
Are you sure you want to change the base?
[issue-2572] [FE] Update experiment name metadata in UI #3136
Conversation
…hub.com/riturajFi/opik into feature/update-experiment-name-metadata
…hub.com/riturajFi/opik into feature/update-experiment-name-metadata
Hi @yaricom @Lothiraldan @dsblank @vincentkoc , would like this PR to be reviewd |
@riturajFi can you please address the linter and test failures please before team can review. Thanks for your contribution. |
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.
Pull Request Overview
This PR introduces functionality to update experiment names and metadata across all Opik applications. The feature enables users to modify existing experiments through API endpoints, frontend UI, and SDK methods.
Key changes:
- Added API endpoint for updating experiment name and metadata with validation and change detection
- Created interactive frontend dialog with Monaco editor for JSON metadata editing
- Extended both Python and TypeScript SDKs with update methods
Reviewed Changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
File | Description |
---|---|
apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ExperimentsResource.java |
REST endpoint for experiment updates with change detection |
apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentService.java |
Business logic for planning and applying experiment updates |
apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentDAO.java |
Database operations for updating experiment name and metadata |
apps/opik-frontend/src/components/shared/UpdateExperimentDialog/UpdateExperimentDialog.tsx |
React dialog component with Monaco editor for experiment editing |
apps/opik-frontend/src/api/datasets/useExperimentUpdate.ts |
Frontend mutation hook for experiment updates |
sdks/python/src/opik/api_objects/opik_client.py |
Python SDK method for updating experiments |
sdks/typescript/src/opik/client/Client.ts |
TypeScript SDK method for updating experiments |
sdks/typescript/tests/experiment/client-experiment.test.ts |
Unit and integration tests for TypeScript SDK |
Files not reviewed (1)
- apps/opik-frontend/package-lock.json: Language not supported
datasetName: "test-dataset", | ||
}); | ||
|
||
console.log(JSON.stringify(created)) |
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.
Debug console.log statement should be removed from test code. Use proper test logging or assertions instead.
console.log(JSON.stringify(created)) |
Copilot uses AI. Check for mistakes.
try { | ||
parsedMetadata = metadata ? JSON.parse(metadata) : {}; | ||
} catch (e) { | ||
alert("Invalid JSON in 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.
Using browser alert() for error messages is not consistent with the application's UI patterns. Use the toast notification system instead, similar to other components in the codebase.
Copilot uses AI. Check for mistakes.
export function UpdateExperimentDialog({ | ||
open, | ||
setOpen, | ||
onConfirm, | ||
latestName, | ||
latestMetadata | ||
}) { |
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.
Function parameters lack TypeScript type definitions. Define an interface for the props to ensure type safety and better developer experience.
export function UpdateExperimentDialog({ | |
open, | |
setOpen, | |
onConfirm, | |
latestName, | |
latestMetadata | |
}) { | |
interface UpdateExperimentDialogProps { | |
open: boolean; | |
setOpen: (open: boolean) => void; | |
onConfirm: () => void; | |
latestName: string; | |
latestMetadata: any; | |
} | |
export function UpdateExperimentDialog({ | |
open, | |
setOpen, | |
onConfirm, | |
latestName, | |
latestMetadata | |
}: UpdateExperimentDialogProps) { |
Copilot uses AI. Check for mistakes.
------------------- | ||
id: str | ||
newName: Optional[str] | ||
newMetadata: Optional[str] |
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.
The docstring parameter type annotation is incorrect. newMetadata
should be Optional[Dict[str, Any]]
not Optional[str]
to match the actual parameter type.
newMetadata: Optional[str] | |
newMetadata: Optional[Dict[str, Any]] |
Copilot uses AI. Check for mistakes.
@@ -43,9 +53,17 @@ const ExperimentRowActionsCell: React.FunctionComponent< | |||
onConfirm={deleteExperimentsHandler} | |||
title="Delete experiment" | |||
description="Deleting an experiment will remove all samples in the experiment. Related traces won’t be affected. This action can’t be undone. Are you sure you want to continue?" | |||
confirmText="Delete experiment" | |||
confirmText="Delete experiments" |
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.
The confirm text should be "Delete experiment" (singular) since the action deletes only one experiment, not multiple experiments.
confirmText="Delete experiments" | |
confirmText="Delete experiment" |
Copilot uses AI. Check for mistakes.
ObjectMapper mapper = new ObjectMapper(); | ||
JsonNode meta; | ||
|
||
try { | ||
meta = mapper.readTree(plan.targetMetadata()); | ||
} catch (JsonProcessingException e) { | ||
log.error("Invalid metadata JSON stored for experiment {}: {}", id, plan.targetMetadata(), e); | ||
meta = mapper.createObjectNode().put("raw", plan.targetMetadata()); | ||
} |
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.
Inconsistent indentation after the blocking call. The ObjectMapper instantiation should be aligned with the surrounding code block.
ObjectMapper mapper = new ObjectMapper(); | |
JsonNode meta; | |
try { | |
meta = mapper.readTree(plan.targetMetadata()); | |
} catch (JsonProcessingException e) { | |
log.error("Invalid metadata JSON stored for experiment {}: {}", id, plan.targetMetadata(), e); | |
meta = mapper.createObjectNode().put("raw", plan.targetMetadata()); | |
} | |
ObjectMapper mapper = new ObjectMapper(); | |
JsonNode meta; | |
try { | |
meta = mapper.readTree(plan.targetMetadata()); | |
} catch (JsonProcessingException e) { | |
log.error("Invalid metadata JSON stored for experiment {}: {}", id, plan.targetMetadata(), e); | |
meta = mapper.createObjectNode().put("raw", plan.targetMetadata()); | |
} |
Copilot uses AI. Check for mistakes.
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.
Hi @riturajFi
Thanks a lot for your contribution.
I left a review on the backend part, with the general guidelines to follow in this service.
The main question here is how to handle the ClickHouse updates, which isn't straight forward and probably one of the reasons why we haven't implemented this ourselves yet.
I'll discuss and double check the approach with the team for that, but for now, the best option is to handle the update with a INSERT + SELECT query (see examples in this DAO already) and document that the endpoint is only meant for the UI and doesn't handle concurrent scenarios for the SDK (already the case).
Other members of the team will review the FE and SDK parts. In the meantime, please remove changes on the auto-generated code.
Thank you very much for all this work!
private static final String UPDATE_BY_ID = """ | ||
ALTER TABLE experiments | ||
UPDATE | ||
name = :name, | ||
metadata = :metadata, | ||
last_updated_by = :last_updated_by | ||
WHERE id = :id | ||
AND workspace_id = :workspace_id | ||
; | ||
"""; |
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.
Per architectural reasons, we don't do mutations in ClickHouse, as they're not performant:
Regarding entities stored in CH, only spans and traces are PATCHED. The approach is to query and re-insert only the data that changes, in this case it'd be name
and metadata
. In this approach is tricky to keep data consistency for concurrent SDK flows. But maybe is reasonable to just document that this endpoint is for UI purposes only.
Another alternative is lightweight updates:
But considering that is a Beta feature, has some performance implications, and it'd have the same concurrency issues, I'd go with the previous approach.
@@ -484,4 +488,59 @@ public Response findFeedbackScoreNames(@QueryParam("experiment_ids") String expe | |||
|
|||
return Response.ok(feedbackScoreNames).build(); | |||
} | |||
|
|||
@POST |
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.
This should be a PATCH operation.
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.
You need tests for this new endpoint. Please follow the conventions in the code base.
@@ -484,4 +488,59 @@ public Response findFeedbackScoreNames(@QueryParam("experiment_ids") String expe | |||
|
|||
return Response.ok(feedbackScoreNames).build(); | |||
} | |||
|
|||
@POST | |||
@Path("/update/{id}") |
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.
After updating to PATCH, the verb should be removed from the path. It isn't a good REST practice.
|
||
@POST | ||
@Path("/update/{id}") | ||
public Response updateExperimentById( |
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.
Minor: let's rename the method to update
.
@@ -0,0 +1,13 @@ | |||
package com.comet.opik.domain; |
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.
Move to package com.comet.opik.api;
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) |
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.
Add @Builder(toBuilder = true)
.
|
||
import io.reactivex.rxjava3.annotations.Nullable; | ||
|
||
public record ExperimentUpdatePlan( |
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.
This won't be needed.
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.
We have an automation for everything under sdks/python/src/opik/rest_api/
folder, please remove these changes. They'll be auto-generated.
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.
Same for the typescript SDK, we have an automation for everything under rest_api
folder, please remove these changes. They'll be auto-generated.
Great insights @andrescrz ! Will do the changes right away! |
Details
Summary
Introduced a new API for updating an experiment’s name and metadata.
Changes
Screencast.from.2025-09-01.20-23-22.webm
Change checklist
Issues
Testing
Documentation