Skip to content

Commit 4addcae

Browse files
authored
Merge branch 'main' into ido/opik-1386-guardrails-ingestion
2 parents d5b0048 + 3a72f0f commit 4addcae

File tree

97 files changed

+3958
-907
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+3958
-907
lines changed

Diff for: .github/workflows/span_cost_upload_daily.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Update Span Cost Daily
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * *' # Runs daily at midnight UTC
6+
workflow_dispatch: # Allows manual trigger
7+
8+
jobs:
9+
update-span-cost:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout Repository
14+
uses: actions/checkout@v4
15+
# with:
16+
# persist-credentials: false # Prevent issues with GitHub token
17+
18+
- name: Set branch name and update the file
19+
run: |
20+
echo "BRANCH_NAME=span-cost-update-$(date +%Y-%m-%d)" >> $GITHUB_ENV
21+
curl -o apps/opik-backend/src/main/resources/model_prices_and_context_window.json https://raw.githubusercontent.com/BerriAI/litellm/refs/heads/main/model_prices_and_context_window.json
22+
23+
- name: Create branch
24+
uses: JosiahSiegel/[email protected]
25+
with:
26+
branch: ${{ env.BRANCH_NAME }}
27+
28+
- name: Push updated file
29+
uses: comet-ml/push-files@main
30+
with:
31+
branch: ${{ env.BRANCH_NAME }}
32+
files: apps/opik-backend/src/main/resources/model_prices_and_context_window.json:apps/opik-backend/src/main/resources/model_prices_and_context_window.json
33+
github_token: ${{ secrets.GH_PAT_TO_ACCESS_GITHUB_API }}
34+
repository: 'comet-ml/opik'
35+
commit_user_email: [email protected]
36+
commit_user_name: 'Github Actions (${{ github.actor }})'
37+
commit_message: "Update span cost file"
38+
39+
- name: Create Pull Request
40+
uses: peter-evans/create-pull-request@v6
41+
with:
42+
token: ${{ secrets.GITHUB_TOKEN }}
43+
branch: ${{ env.BRANCH_NAME }}
44+
title: "Update span cost from LiteLLM"
45+
body: "Automated update of model_prices_and_context_window.json file, which includes span prices information from the LiteLLM repo."
46+
base: main

Diff for: .gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,9 @@ deployment/helm_chart/opik/charts
6363
deployment/helm_chart/opik/values-*.yaml
6464
temp
6565
opik-sandbox-executor-python.tar.gz
66+
67+
# init
68+
.opik_install_reported
69+
70+
# Update span cost workflow
71+
response.txt

Diff for: apps/opik-backend/src/main/java/com/comet/opik/api/Identifier.java renamed to apps/opik-backend/src/main/java/com/comet/opik/api/ExperimentStreamRequest.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,23 @@
33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
55
import com.fasterxml.jackson.databind.annotation.JsonNaming;
6+
import jakarta.validation.constraints.Max;
7+
import jakarta.validation.constraints.Min;
68
import jakarta.validation.constraints.NotBlank;
79
import lombok.Builder;
810

11+
import java.util.UUID;
12+
913
@Builder(toBuilder = true)
1014
@JsonIgnoreProperties(ignoreUnknown = true)
1115
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
12-
public record Identifier(@NotBlank String name) {
16+
public record ExperimentStreamRequest(
17+
@NotBlank String name,
18+
@Min(1) @Max(2000) Integer limit,
19+
UUID lastRetrievedId) {
20+
21+
@Override
22+
public Integer limit() {
23+
return limit == null ? 500 : limit;
24+
}
1325
}

Diff for: apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ExperimentsResource.java

+19-18
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import com.comet.opik.api.ExperimentItemsBatch;
99
import com.comet.opik.api.ExperimentItemsDelete;
1010
import com.comet.opik.api.ExperimentSearchCriteria;
11+
import com.comet.opik.api.ExperimentStreamRequest;
1112
import com.comet.opik.api.ExperimentsDelete;
1213
import com.comet.opik.api.FeedbackDefinition;
1314
import com.comet.opik.api.FeedbackScoreNames;
14-
import com.comet.opik.api.Identifier;
1515
import com.comet.opik.api.resources.v1.priv.validate.IdParamsValidator;
1616
import com.comet.opik.api.sorting.ExperimentSortingFactory;
1717
import com.comet.opik.api.sorting.SortingField;
@@ -190,25 +190,26 @@ public Response deleteExperimentsById(
190190
}
191191

192192
@POST
193-
@Path("/retrieve")
194-
@Operation(operationId = "getExperimentByName", summary = "Get experiment by name", description = "Get experiment by name", responses = {
195-
@ApiResponse(responseCode = "200", description = "Experiments resource", content = @Content(schema = @Schema(implementation = Experiment.class))),
196-
@ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = ErrorMessage.class)))
193+
@Path("/stream")
194+
@Produces(MediaType.APPLICATION_OCTET_STREAM)
195+
@Operation(operationId = "streamExperiments", summary = "Stream experiments", description = "Stream experiments", responses = {
196+
@ApiResponse(responseCode = "200", description = "Experiments stream or error during process", content = @Content(array = @ArraySchema(schema = @Schema(anyOf = {
197+
Experiment.class,
198+
ErrorMessage.class
199+
}), maxItems = 2000)))
197200
})
198201
@JsonView(Experiment.View.Public.class)
199-
public Response getExperimentByName(
200-
@RequestBody(content = @Content(schema = @Schema(implementation = Identifier.class))) @NotNull @Valid Identifier identifier) {
201-
202-
String workspaceId = requestContext.get().getWorkspaceId();
203-
String name = identifier.name();
204-
205-
log.info("Finding experiment by name '{}' on workspace_id '{}'", name, workspaceId);
206-
var experiment = experimentService.getByName(name)
207-
.contextWrite(ctx -> setRequestContext(ctx, requestContext))
208-
.block();
209-
log.info("Found experiment by name '{}' on workspace_id '{}'", name, workspaceId);
210-
211-
return Response.ok(experiment).build();
202+
public ChunkedOutput<JsonNode> streamExperiments(
203+
@RequestBody(content = @Content(schema = @Schema(implementation = ExperimentStreamRequest.class))) @NotNull @Valid ExperimentStreamRequest request) {
204+
var workspaceId = requestContext.get().getWorkspaceId();
205+
var userName = requestContext.get().getUserName();
206+
log.info("Streaming experiments by '{}', workspaceId '{}', userName '{}'", request, workspaceId, userName);
207+
var experiments = experimentService.get(request)
208+
.contextWrite(ctx -> ctx.put(RequestContext.USER_NAME, userName)
209+
.put(RequestContext.WORKSPACE_ID, workspaceId));
210+
var stream = streamer.getOutputStream(experiments);
211+
log.info("Streamed experiments by '{}', workspaceId '{}', userName '{}'", request, workspaceId, userName);
212+
return stream;
212213
}
213214

214215
// Experiment Item Resources

Diff for: apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ServiceTogglesResource.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import com.codahale.metrics.annotation.Timed;
44
import com.comet.opik.infrastructure.OpikConfiguration;
5-
import io.swagger.v3.oas.annotations.Hidden;
5+
import com.comet.opik.infrastructure.ServiceTogglesConfig;
66
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.media.Content;
8+
import io.swagger.v3.oas.annotations.media.Schema;
9+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
710
import io.swagger.v3.oas.annotations.tags.Tag;
811
import jakarta.inject.Inject;
912
import jakarta.ws.rs.GET;
@@ -20,14 +23,14 @@
2023
@Timed
2124
@Slf4j
2225
@RequiredArgsConstructor(onConstructor_ = @Inject)
23-
@Tag(name = "Service Toggles", description = "Service Toggles")
26+
@Tag(name = "Service Toggles", description = "Service Toggles resources")
2427
public class ServiceTogglesResource {
2528

2629
private final @NonNull OpikConfiguration config;
2730

2831
@GET
29-
@Operation(operationId = "getServiceToggles", summary = "Get Service Toggles", description = "Get Service Toggles")
30-
@Hidden
32+
@Operation(operationId = "getServiceToggles", summary = "Get Service Toggles", description = "Get Service Toggles", responses = {
33+
@ApiResponse(responseCode = "200", description = "Service Toggles", content = @Content(schema = @Schema(implementation = ServiceTogglesConfig.class)))})
3134
public Response getToggles() {
3235
return Response.ok()
3336
.entity(config.getServiceToggles())

Diff for: apps/opik-backend/src/main/java/com/comet/opik/domain/AutomationRuleEvaluatorService.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import com.comet.opik.api.LogCriteria;
1111
import com.comet.opik.api.error.EntityAlreadyExistsException;
1212
import com.comet.opik.api.error.ErrorMessage;
13-
import com.comet.opik.infrastructure.ServiceTogglesConfig;
13+
import com.comet.opik.infrastructure.OpikConfiguration;
1414
import com.comet.opik.infrastructure.cache.CacheEvict;
1515
import com.comet.opik.infrastructure.cache.Cacheable;
1616
import com.google.inject.ImplementedBy;
@@ -24,7 +24,6 @@
2424
import lombok.extern.slf4j.Slf4j;
2525
import org.jdbi.v3.core.statement.UnableToExecuteStatementException;
2626
import reactor.core.publisher.Mono;
27-
import ru.vyarus.dropwizard.guice.module.yaml.bind.Config;
2827
import ru.vyarus.guicey.jdbi3.tx.TransactionTemplate;
2928

3029
import java.sql.SQLIntegrityConstraintViolationException;
@@ -70,7 +69,7 @@ class AutomationRuleEvaluatorServiceImpl implements AutomationRuleEvaluatorServi
7069
private final @NonNull IdGenerator idGenerator;
7170
private final @NonNull TransactionTemplate template;
7271
private final @NonNull AutomationRuleEvaluatorLogsDAO logsDAO;
73-
private final @NonNull @Config("serviceToggles") ServiceTogglesConfig serviceTogglesConfig;
72+
private final @NonNull OpikConfiguration opikConfiguration;
7473

7574
@Override
7675
@CacheEvict(name = "automation_rule_evaluators_find_all", key = "$projectId + '-' + $workspaceId")
@@ -97,7 +96,7 @@ public <E, T extends AutomationRuleEvaluator<E>> T save(@NonNull T inputRuleEval
9796
yield AutomationModelEvaluatorMapper.INSTANCE.map(definition);
9897
}
9998
case AutomationRuleEvaluatorUserDefinedMetricPython userDefinedMetricPython -> {
100-
if (!serviceTogglesConfig.isPythonEvaluatorEnabled()) {
99+
if (!opikConfiguration.getServiceToggles().isPythonEvaluatorEnabled()) {
101100
throw new ServerErrorException("Python evaluator is disabled", 501);
102101
}
103102
var definition = userDefinedMetricPython.toBuilder()
@@ -153,7 +152,7 @@ public void update(@NonNull UUID id, @NonNull UUID projectId, @NonNull String wo
153152
.lastUpdatedBy(userName)
154153
.build();
155154
case AutomationRuleEvaluatorUpdateUserDefinedMetricPython evaluatorUpdateUserDefinedMetricPython -> {
156-
if (!serviceTogglesConfig.isPythonEvaluatorEnabled()) {
155+
if (!opikConfiguration.getServiceToggles().isPythonEvaluatorEnabled()) {
157156
throw new ServerErrorException("Python evaluator is disabled", 501);
158157
}
159158
yield UserDefinedMetricPythonAutomationRuleEvaluatorModel.builder()

0 commit comments

Comments
 (0)