-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathconfig.yml
More file actions
1854 lines (1790 loc) · 105 KB
/
Copy pathconfig.yml
File metadata and controls
1854 lines (1790 loc) · 105 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
# https://www.dropwizard.io/en/stable/manual/configuration.html#logging
logging:
# Default: INFO
# Description: Logback logging level
level: ${GENERAL_LOG_LEVEL:-INFO}
# Default: com.comet: INFO
# Description: Individual logger configuration
loggers:
com.comet: ${OPIK_LOG_LEVEL:-INFO}
# Default: INFO
# Description: Set to DEBUG to see complete assembled LLM streaming responses (application-level logging)
com.comet.opik.infrastructure.llm: ${LLM_PROXY_REQUEST_LOG_LEVEL:-INFO}
# Description: state database configuration
# https://www.dropwizard.io/en/stable/manual/configuration.html#database
database:
# Default: jdbc:mysql://localhost:3306/opik?createDatabaseIfNotExist=true&rewriteBatchedStatements=true&connectionTimeZone=UTC&forceConnectionTimeZoneToSession=true
# Description: The URL of the server.
url: ${STATE_DB_PROTOCOL:-jdbc:mysql://}${STATE_DB_URL:-localhost:3306/opik?createDatabaseIfNotExist=true&rewriteBatchedStatements=true&connectionTimeZone=UTC&forceConnectionTimeZoneToSession=true}
# Default: opik
# Description: The username used to connect to the server
user: ${STATE_DB_USER:-opik}
# Default: opik
# Description: The password used to connect to the server
password: ${STATE_DB_PASS:-opik}
# Default: com.mysql.cj.jdbc.Driver
# Description: The fully qualified class name of the JDBC driver class.
# Only required if there were no JDBC drivers registered in META-INF/services/java.sql.Driver.
driverClass: ${STATE_DB_DRIVER_CLASS:-com.mysql.cj.jdbc.Driver}
# Default: Empty
# Description: Any additional JDBC driver parameters
properties:
wrapperPlugins: ${STATE_DB_PLUGINS:-''}
useSSL: ${MYSQL_USE_SSL:-''}
requireSSL: ${MYSQL_REQUIRE_SSL:-''}
verifyServerCertificate: ${MYSQL_VERIFY_SSL:-''}
trustCertificateKeyStoreUrl: ${MYSQL_TRUSTSTORE_URL:-''}
trustCertificateKeyStorePassword: ${MYSQL_TRUSTSTORE_PASSWORD:-''}
trustCertificateKeyStoreType: ${MYSQL_TRUSTSTORE_TYPE:-''}
clientCertificateKeyStoreUrl: ${MYSQL_CLIENTSTORE_URL:-''}
clientCertificateKeyStorePassword: ${MYSQL_CLIENTSTORE_PASSWORD:-''}
clientCertificateKeyStoreType: ${MYSQL_CLIENTSTORE_TYPE:-''}
# Description: analytics database configuration for migrations connection
databaseAnalyticsMigrations:
# Default: jdbc:clickhouse://localhost:8123/opik
# Description: The URL of the server
url: ${ANALYTICS_DB_MIGRATIONS_URL:-jdbc:clickhouse://localhost:8123/opik}
# Default: opik
# Description: The username used to connect to the server
user: ${ANALYTICS_DB_MIGRATIONS_USER:-opik}
# Default: opik
# Description: The password used to connect to the server
password: ${ANALYTICS_DB_MIGRATIONS_PASS:-opik}
# Default: ru.yandex.clickhouse.ClickHouseDriver
# Description: The fully qualified class name of the JDBC driver class.
# Community support only. Requires an old driver for migrations to work
driverClass: ru.yandex.clickhouse.ClickHouseDriver
# Description: analytics database configuration for service connection
databaseAnalytics:
# Default: http
# Description: The protocol used to connect to the server
protocol: ${ANALYTICS_DB_PROTOCOL:-HTTP}
# Default: localhost
# Description: The host used to connect to the server
host: ${ANALYTICS_DB_HOST:-localhost}
# Default: 8123
# Description: The port used to connect to the server
port: ${ANALYTICS_DB_PORT:-8123}
# Default: opik
# Description: The username used to connect to the server
username: ${ANALYTICS_DB_USERNAME:-opik}
# Default: opik
# Description: The password used to connect to the server
password: ${ANALYTICS_DB_PASS:-opik}
# Default: opik
# Description: The database name
databaseName: ${ANALYTICS_DB_DATABASE_NAME:-opik}
# Default:
# - health_check_interval=2000
# - compress=1
# - auto_discovery=true
# - failover=3
# - custom_http_params=max_query_size=100000000
# Description: query parameters that will be added to the connection string
queryParameters: ${ANALYTICS_DB_QUERY_PARAMETERS:-health_check_interval=2000&compress=1&auto_discovery=true&failover=3&custom_http_params=max_query_size=100000000,async_insert_busy_timeout_max_ms=250,async_insert_busy_timeout_min_ms=100,async_insert=1,wait_for_async_insert=1,async_insert_use_adaptive_busy_timeout=1,async_insert_deduplicate=1,use_skip_indexes_if_final=1,optimize_skip_unused_shards=1,do_not_merge_across_partitions_select_final=1,distributed_product_mode=local}
# Default: unset (the async_insert_busy_timeout_max_ms=250 carried by queryParameters above applies)
# Description: Optional override (ms) for async_insert_busy_timeout_max_ms. When set it is applied to the
# custom_http_params chain (overriding the value there, or added if absent); when unset the queryParameters value
# is left untouched. With async_insert_use_adaptive_busy_timeout=1 this is the ceiling of the adaptive buffer window.
asyncInsertBusyTimeoutMaxMs: ${ANALYTICS_DB_ASYNC_INSERT_BUSY_TIMEOUT_MAX_MS:-}
# Default: unset (the async_insert_busy_timeout_min_ms=100 carried by queryParameters above applies)
# Description: Optional override (ms) for async_insert_busy_timeout_min_ms, the floor of the adaptive buffer window;
# same override semantics as asyncInsertBusyTimeoutMaxMs above.
asyncInsertBusyTimeoutMinMs: ${ANALYTICS_DB_ASYNC_INSERT_BUSY_TIMEOUT_MIN_MS:-}
# Default: unset (async_insert_max_data_size is not carried by queryParameters above, so the ClickHouse/server value applies)
# Description: Optional override (bytes) for async_insert_max_data_size, the buffered size that forces an
# async-insert flush; same override semantics as asyncInsertBusyTimeoutMaxMs above. Larger values yield fewer,
# larger parts at the cost of more buffer memory.
asyncInsertMaxDataSize: ${ANALYTICS_DB_ASYNC_INSERT_MAX_DATA_SIZE:-}
# Default: 1s
# Description: Timeout for the ClickHouse health check query (e.g. 1s, 500ms, 2 minutes)
healthCheckTimeout: ${ANALYTICS_DB_HEALTH_CHECK_TIMEOUT:-1s}
# Default: false
# Description: Gates the 'clickhouse-cluster' health check, which fails readiness when the Distributed cluster
# definition ('cluster') isn't visible from the node. Leave false for single-shard / non-Distributed deployments;
# turn true only for the Distributed (Hyperscale) topology.
clusterHealthCheckEnabled: ${ANALYTICS_DB_CLUSTER_HEALTH_CHECK_ENABLED:-false}
# Default: false
# Description: Gates the 'clickhouse-cold-storage-disk' health check, which fails readiness when the 'cold_s3'
# tiered-storage disk isn't reachable from the node. Leave false for deployments without tier storage (OSS Docker);
# turn true only once the S3 disk is activated.
coldStorageDiskHealthCheckEnabled: ${ANALYTICS_DB_COLD_STORAGE_DISK_HEALTH_CHECK_ENABLED:-false}
# Description: Cutover toggles migrating the trace analytics columns to non-nullable, sentinel-defaulted form.
databaseAnalyticsDataModel:
# Default: false
# Description: Leave false while the traces table still has Nullable end_time/duration/ttft columns; trace writes
# bind null for absent end_time/ttft. Set true once replaced with sentinel-defaulted
# non-nullable columns so writes bind the sentinels (end_time->epoch, ttft->NaN) instead. Gates reads too, so
# while false a legitimate epoch end time round-trips unchanged instead of reading as null.
# Flip in lockstep with the cutover EXCHANGE.
traceColumnsNonNullable: ${ANALYTICS_DB_DATA_MODEL_TRACE_COLUMNS_NON_NULLABLE:-false}
# Default: false
# Description: Spans sibling of traceColumnsNonNullable. Leave false while the spans table still has Nullable
# end_time/duration/ttft columns; span writes bind null for absent end_time/ttft. Set true once replaced with
# sentinel-defaulted non-nullable columns so writes bind the sentinels (end_time->epoch, ttft->NaN) instead. Gates
# reads too. Flip in lockstep with the Slice 3 cutover EXCHANGE, independently of the trace flag.
spanColumnsNonNullable: ${ANALYTICS_DB_DATA_MODEL_SPAN_COLUMNS_NON_NULLABLE:-false}
# Default: false
# Description: Leave false at deploy time. Turn true once the trace backfill starts so trace deletes also
# record the deleted ids in the deletion_events_local bridge; without it those deletes are lost from the table
# copy. Scope capture to the backfill-to-cutover window.
traceDeletionEventsCaptureEnabled: ${ANALYTICS_DB_DATA_MODEL_TRACE_DELETION_EVENTS_CAPTURE_ENABLED:-false}
# Default: false
# Description: Spans sibling of traceDeletionEventsCaptureEnabled. Spans have no standalone delete, so this captures
# the span ids removed by the trace-delete cascade into the deletion_events_local bridge (source_table=spans) so they
# survive the spans table copy. Leave false at deploy time; turn true once the span backfill starts, independently of
# the trace flag.
spanDeletionEventsCaptureEnabled: ${ANALYTICS_DB_DATA_MODEL_SPAN_DELETION_EVENTS_CAPTURE_ENABLED:-false}
# Default: 1000
# Description: Rows per INSERT into the deletion_events_local bridge. A single delete batch can carry more ids
# than the ClickHouse driver binds reliably in one statement (5 columns per row), so the insert is split into
# chunks of this size.
deletionEventsInsertBatchSize: ${ANALYTICS_DB_DATA_MODEL_DELETION_EVENTS_INSERT_BATCH_SIZE:-1000}
# Default: false
# Description: The final sharding-readiness step wraps `traces` as a Distributed table over the `traces_local`
# shard. A Distributed table supports SELECT and INSERT but NOT mutations, so once the wrap is live every trace
# mutation must target the local shard. Leave false at deploy time and while `traces` is still a MergeTree (deletes
# work directly); set true in lockstep with applying the wrap (exchange_and_wrap.sh --with-wrap / --wrap-only). While
# true, TraceDAO routes delete/retention mutations to `traces_local`; reads and inserts stay on the Distributed
# `traces`. Post-wrap, changes to `traces` split by kind: row mutations (DELETE) + MATERIALIZE COLUMN/ADD INDEX/
# MODIFY TTL target `traces_local` only (the Distributed `traces` rejects them); ADD/DROP/MODIFY COLUMN must target
# both `traces_local` and `traces`, else reads can't see the column (code 47).
tracesDistributedWrapEnabled: ${ANALYTICS_DB_DATA_MODEL_TRACES_DISTRIBUTED_WRAP_ENABLED:-false}
# Default: false
# Description: Enables partition-aware PRUNING of trace deletes - it does NOT create or activate any partitioning.
# With it on, a trace DELETE bounds itself to the weekly partitions its own ids resolve to instead of being planned
# against every part of the table. Turning it on therefore ASSERTS a schema fact rather than causing one: that the
# live mutation target already IS the weekly partitioned successor, id_at as DateTime64(0,'UTC') under
# PARTITION BY toYYYYMMDD(toDate32(id_at) - toIntervalDay(toDayOfWeek(id_at, 1))). Installing that schema is the
# EXCHANGE step of the cutover, never this flag. Purely an optimisation: false keeps the unbounded mutation, which
# is always correct and merely slower. A third flag on purpose - the partitioning appears at the EXCHANGE, and
# neither sibling marks it:
# traceColumnsNonNullable must be rolled out BEFORE the EXCHANGE, tracesDistributedWrapEnabled flips at the wrap,
# which may be deferred long after it. Leave false at deploy time; set true once the EXCHANGE is confirmed, and back
# to false BEFORE a rollback promotes the original `traces` (legacy `traces` has no PARTITION BY and a 32-bit
# DateTime id_at that overflows past 2106, so the predicate would silently match zero rows for a far-future id).
tracesWeeklyPartitionPruningEnabled: ${ANALYTICS_DB_DATA_MODEL_TRACES_WEEKLY_PARTITION_PRUNING_ENABLED:-false}
# Description: UUIDv7 ingestion validation. Rejects writes whose `id` embeds a timestamp outside the
# window, protecting data quality.
uuidValidation:
# Default: false
# Description: Operational kill-switch. When false, ids are not checked against the window (the
# window is still validated to be a sane value).
enabled: ${UUID_VALIDATION_ENABLED:-false}
# Default: false
# Description: Audit (shadow / log-only) mode. Only takes effect when enabled is true. When true,
# out-of-window ids are counted (opik.ingestion.uuid_v7.rejected, tagged by workspace) and logged
# but NOT rejected, so offenders surface without breaking ingestion. When false, out-of-window ids
# are rejected with HTTP 400. Effective mode: enabled=false -> disabled; enabled=true & auditOnly=true
# -> audit; enabled=true & auditOnly=false -> reject.
auditOnly: ${UUID_VALIDATION_AUDIT_ONLY:-false}
# Default: 24h
# Description: Validation window (between 12h and 45d). Writes whose `id` is a UUIDv7 with an
# embedded timestamp more than this far in the past or future are rejected.
window: ${UUID_VALIDATION_WINDOW:-24h}
# Description: credentials for the Agent Insights read-only free-form SQL ClickHouse user (restricted user with a
# read-only profile + row policies, provisioned by OPIK-6846). Only the user/password live here; the connection
# params (protocol/host/port/database) are reused from databaseAnalytics above (same ClickHouse instance). Only used
# when the serviceToggles.ollieEnabled toggle is on.
databaseAnalyticsReadOnlyFreeFormSql:
# Default: comet_readonly_freeform_sql_user
# Description: The read-only username used to connect to the server
username: ${ANALYTICS_DB_READ_ONLY_FREEFORM_SQL_USER:-comet_readonly_freeform_sql_user}
# Default: opik
# Description: The read-only user password used to connect to the server
password: ${ANALYTICS_DB_READ_ONLY_FREEFORM_SQL_PASS:-opik}
# Default: 200s
# Description: Socket read timeout for the read-only client (client-v2 default is 0/none). Kept
# above the read-only profile's max_execution_time (180s) so the server-side cap fires first.
socketTimeout: ${ANALYTICS_DB_READ_ONLY_FREEFORM_SQL_SOCKET_TIMEOUT:-200s}
# https://www.dropwizard.io/en/stable/manual/configuration.html#health
health:
# Default: ["/health-check"]
# Description: URLs to expose the app’s health check on.
healthCheckUrlPaths: ["/health-check"]
# Options around a particular health check which is registered in an Application
# https://www.dropwizard.io/en/stable/manual/configuration.html#man-configuration-health-checks
healthChecks:
- name: deadlocks
critical: true
type: alive
# Gates liveness (type: alive) so a pod whose shared outbound HTTP pool has been shut down gets restarted and
# recreates the pool. A shut-down pool is unrecoverable without a restart, so removing it from rotation isn't
# enough. Fails only on the local "Connection pool shut down" condition, never on transient upstream errors, so a
# blip in any outbound dependency cannot restart-storm the fleet.
- name: shared_http_client
critical: true
type: alive
- name: db
critical: true
type: ready
- name: redis
critical: true
type: ready
- name: clickhouse
critical: true
type: ready
# Non-critical on purpose: this is an optional, toggle-gated feature (Agent Insights freeform SQL). A
# provisioning issue or transient CH rejection on the read-only user must degrade only that feature, not pull
# the whole backend out of readiness/traffic.
- name: clickhouse-readonly-freeform-sql
critical: false
type: ready
# Toggle-gated (databaseAnalytics.clusterHealthCheckEnabled). When the toggle is off the probe reports healthy
# without querying ClickHouse, so single-shard / OSS environments are unaffected. When on, a node that can't see
# the Distributed cluster definition can't serve distributed queries and must be pulled from rotation.
- name: clickhouse-cluster
critical: true
type: ready
# Toggle-gated (databaseAnalytics.coldStorageDiskHealthCheckEnabled). Off by default so deployments without tier
# storage are unaffected. When on, a node that can't reach the cold_s3 S3 disk must be pulled from rotation.
- name: clickhouse-cold-storage-disk
critical: true
type: ready
- name: mysql
critical: true
type: ready
# Configuration for distributed locking using redis
distributedLock:
# Default: 500
# Description: Lease time in milliseconds
lockTimeoutMS: ${DISTRIBUTED_LOCK_TIME_OUT:-500}
# Default: 5
# Description: This value has to be considerably higher than the lockTimeoutMS value, as it has to guarantee that the
# last thread to join the queue to acquire the lock will have enough time to execute the action. Then, the lock will
# be deleted from redis after the specified period of time.
# This is needed as Redisson by default doesn't delete the lock from redis after the lease time expires, it just
# releases the lock. The expiration time will be reset every time the lock is acquired.
ttlInSeconds: ${DISTRIBUTED_LOCK_TTL_IN_SEC:-5}
# Redis configuration
redis:
# Default: redis://:opik@localhost:6379/0
# Description: single node redis's URL
singleNodeUrl: ${REDIS_URL:-redis://:opik@localhost:6379/0}
# Default: 1s
# Description: Timeout for the Redis health check ping
healthCheckTimeout: ${REDIS_HEALTH_CHECK_TIMEOUT:-1s}
# AWS IAM authentication configuration (optional)
# When enabled, takes precedence over singleNodeUrl authentication
awsIamAuth:
# Default: false
# Description: Enable AWS IAM authentication for ElasticCache Redis
enabled: ${OPIK_REDIS_AWS_IAM_AUTH_ENABLED:-false}
# Description: AWS User ID for IAM authentication
awsUserId: ${OPIK_REDIS_AWS_USER_ID:-''}
# Default: us-east-1
# Description: AWS region where ElastiCache is deployed
awsRegion: ${AWS_REGION:-us-east-1}
# Default: opik-redis
# Description: ElasticCache resource name (replication group/cluster/serverless name)
awsResourceName: ${OPIK_REDIS_AWS_RESOURCE_NAME:-''}
# Default: 13m
# Description: How often to refresh the AWS authentication token
tokenCacheRefreshAfter: ${OPIK_REDIS_AWS_TOKEN_CACHE_REFRESH_AFTER:-13m}
# Default: 14m
# Description: How long the AWS authentication token will be cached locally
tokenCacheExpireAfter: ${OPIK_REDIS_AWS_TOKEN_CACHE_EXPIRE_AFTER:-14m}
# Default: 15m
# Description: How long the AWS authentication token is valid
tokenExpiryDuration: ${OPIK_REDIS_AWS_TOKEN_EXPIRY_DURATION:-15m}
openTelemetry:
# Default: 3h
# Description: how long it takes to expire non-used keys
ttl: ${OTEL_TTL_INTERVAL:-3h}
# Authentication configuration. This is not enabled by default for open source installations.
authentication:
# Default: false
# Description: Whether or not to enable authentication
enabled: ${AUTH_ENABLED:-false}
# Default: 5
# Description: API key resolution cache TTL (seconds). Setting this value to 0 means no caching.
apiKeyResolutionCacheTTLInSec: ${AUTH_API_KEY_RESOLUTION_CACHE_TTL_IN_SEC:-5}
# Default: http://react-svc:8080
# Description: Configures base url for React service, used for user management and authentication
reactService:
url: ${REACT_SERVICE_URL:-http://react-svc:8080}
# Liveness health check for the shared outbound HTTP client (see shared_http_client under healthChecks)
sharedHttpClientHealthCheck:
# Default: 1s
# Description: Probe timeout (connect + read) for the shared_http_client liveness health check.
timeout: ${SHARED_HTTP_CLIENT_HEALTH_CHECK_TIMEOUT:-1s}
# OAuth 2.1 Authorization Server for hosted/local Opik MCP
mcpOAuth:
# Default: false
# Description: Whether to enable the MCP OAuth Authorization Server endpoints
enabled: ${MCP_OAUTH_ENABLED:-false}
# Default: empty
# Description: Public base URL of this deployment; drives the RFC 8414 issuer and the default RFC 8707 resource audience (baseUrl + /api/v1/mcp)
baseUrl: ${OPIK_BASE_URL:-}
# Default: empty (derived from baseUrl + /api/v1/mcp)
# Description: Canonical MCP resource URI for the OAuth instance. Set to a distinct path (e.g. .../api/v2/mcp) to run the OAuth-based opik-mcp alongside the existing API-key opik-mcp during migration.
mcpResourceUri: ${MCP_OAUTH_RESOURCE_URI:-}
# Default: PT1H
# Description: Access token lifetime
accessTokenTtl: ${MCP_OAUTH_ACCESS_TOKEN_TTL:-PT1H}
# Default: P7D
# Description: Refresh token absolute lifetime (not sliding)
refreshTokenTtl: ${MCP_OAUTH_REFRESH_TOKEN_TTL:-P7D}
# Default: PT60S
# Description: Authorization code lifetime
codeTtl: ${MCP_OAUTH_CODE_TTL:-PT60S}
# Default: PT30S
# Description: Grace window during which a just-rotated refresh token is still accepted
refreshRotationGrace: ${MCP_OAUTH_REFRESH_ROTATION_GRACE:-PT30S}
# Default: PT5M
# Description: TTL of the Redis lock held by the scrub job. The lock is held until expiry (not released after the scrub), so keeping it close to the 5-minute schedule prevents staggered replicas from re-scrubbing within the same cycle.
scrubLockTimeout: ${MCP_OAUTH_SCRUB_LOCK_TIMEOUT:-PT5M}
# Default: PT0.1S
# Description: Maximum time the scrub job waits to acquire the Redis lock before giving up for this cycle
scrubLockWaitTime: ${MCP_OAUTH_SCRUB_LOCK_WAIT_TIME:-PT0.1S}
# https://www.dropwizard.io/en/stable/manual/configuration.html#servers
server:
# Default: false
# Description: Whether to enable virtual threads for Jetty's thread pool.
enableVirtualThreads: ${ENABLE_VIRTUAL_THREADS:-false}
# https://www.dropwizard.io/en/stable/manual/configuration.html#gzip
gzip:
# Default: true
# Description: If true, all requests with gzip in the Accept-Encoding header will have their response entities
# compressed and requests with gzip in the Content-Encoding header will have their request entities decompressed.
enabled: true
# HTTP connector configuration for handling large request headers
# Default: 16KB (16000 bytes) - matches ALB/Nginx request line limit
# Description: Maximum size of request headers to prevent 431 errors from long URLs with many filters
applicationConnectors:
- type: http
# Default: 8080
# Description: The port on which the application HTTP connector listens
port: ${SERVER_APPLICATION_PORT:-8080}
maxRequestHeaderSize: ${SERVER_MAX_REQUEST_HEADER_SIZE:-16KB}
# Default: 1m
# Description: The maximum idle time for a connection, after which it will be closed.
idleTimeout: ${SERVER_IDLE_TIMEOUT:-1m}
adminConnectors:
- type: http
# Default: 8081
# Description: The port on which the admin HTTP connector listens
port: ${SERVER_ADMIN_PORT:-8081}
# Jackson JSON processing configuration
# Controls limits for JSON deserialization to prevent memory exhaustion
jacksonConfig:
# Default: 104857600 (100MB)
# Description: Maximum size for individual string values during JSON deserialization.
# A JSON with 3 fields up to this size will work, but a single larger string will fail.
# This configuration is used by both HTTP layer and internal JSON processing for consistency,
# preventing memory exhaustion from extremely large base64-encoded attachments before they can be stripped
maxStringLength: ${JACKSON_MAX_STRING_LENGTH:-104857600}
# Default: 536870912 (512MB)
# Description: Maximum size of an entire JSON document (the whole decompressed batch). Unlike
# maxStringLength (a single string value), this caps the whole document, catching an oversized
# batch built from many small values. Must stay above maxStringLength.
maxDocumentLength: ${JACKSON_MAX_DOCUMENT_LENGTH:-536870912}
# Default: 536870912 (512MB)
# Description: Maximum incoming request body size, checked against the Content-Length header and
# rejected with 413 before the body is read. Requests without a Content-Length (e.g. chunked)
# fall through and are bounded by maxDocumentLength during parsing.
maxRequestSizeBytes: ${JACKSON_MAX_REQUEST_SIZE_BYTES:-536870912}
# Configuration for batch operations
batchOperations:
datasets:
# Default: 5000
# Description: The maximal number of ids to be used for IN clause. Find requests with a larger number of ids will
# involve the use of temp tables for querying
maxExperimentInClauseSize: ${BATCH_OPERATIONS_MAX_EXPERIMENT_IN_CLAUSE_SIZE:-5000}
# Default: 1000
# Description: The batch size for processing CSV files. Dataset items are saved to the database in batches of this size.
csvBatchSize: ${BATCH_OPERATIONS_CSV_BATCH_SIZE:-1000}
# Configuration for experiment aggregates population
experimentAggregates:
# Default: 1000
# Description: Number of experiment items processed per batch when populating experiment_item_aggregates table. Higher values improve performance but increase memory usage. Recommended range: 100-5000.
batchSize: ${EXPERIMENT_AGGREGATES_BATCH_SIZE:-1000}
# Configuration for experiment denormalization (debounced re-computation of experiment aggregates)
experimentDenormalization:
# Default: true
# Description: Whether the experiment denormalization job and subscriber are enabled
enabled: ${EXPERIMENT_DENORMALIZATION_ENABLED:-true}
# Default: experiment_denormalization_stream
# Description: The name of the Redis Stream used for experiment aggregates recomputation
streamName: ${OPIK_REDIS_EXPERIMENT_DENORM_STREAM_NAME:-'experiment_denormalization_stream'}
# Default: experiment_denormalization
# Description: A consumer group name so multiple instances can share the stream load
consumerGroupName: ${OPIK_REDIS_EXPERIMENT_DENORM_CONSUMER_GROUP_NAME:-'experiment_denormalization'}
# Default: 100
# Description: Maximum number of messages returned within a Redis Stream get
consumerBatchSize: ${OPIK_REDIS_EXPERIMENT_DENORM_CONSUMER_BATCH_SIZE:-100}
# Default: 500ms
# Description: How often the experiment denormalization consumer will check Redis for new messages
poolingInterval: ${OPIK_REDIS_EXPERIMENT_DENORM_POOLING_INTERVAL:-500ms}
# Default: 5s
# Description: Timeout for blocking read operations on Redis streams (long polling duration)
longPollingDuration: ${OPIK_REDIS_EXPERIMENT_DENORM_LONG_POLLING_DURATION:-5s}
# Default: 1m
# Description: Debounce delay before an experiment is published to the denormalization stream. Each new write resets the timer.
debounceDelay: ${OPIK_EXPERIMENT_DENORM_DEBOUNCE_DELAY:-1m}
# Default: 4s
# Description: The time to wait for the denormalization scan job to finish before releasing the lock
jobLockTime: ${OPIK_EXPERIMENT_DENORM_JOB_LOCK_TIME:-4s}
# Default: 300ms
# Description: The time to wait for the denormalization scan job to acquire the lock before giving up
jobLockWaitTime: ${OPIK_EXPERIMENT_DENORM_JOB_LOCK_WAIT_TIME:-300ms}
# Default: 10m
# Description: Maximum duration for the per-experiment aggregation lock held by the stream subscriber
aggregationLockTime: ${OPIK_EXPERIMENT_DENORM_AGGREGATION_LOCK_TIME:-10m}
# Default: 500ms
# Description: Time to wait when trying to acquire the per-experiment aggregation lock before skipping (fail-fast). Must be between 100ms and 5s.
lockAcquireWait: ${OPIK_EXPERIMENT_DENORM_LOCK_ACQUIRE_WAIT:-500ms}
# Default: 3
# Description: Maximum automatic re-trigger attempts per (workspace, experiment) when the aggregation lock TTL is exceeded. Must be between 1 and 10.
maxLockExpiryRetries: ${OPIK_EXPERIMENT_DENORM_MAX_LOCK_EXPIRY_RETRIES:-3}
# Default: 30m
# Description: TTL applied to the per-(workspace, experiment) lock-expiry retry counter in Redis (minimum 1m). Prevents stale counters from accumulating when an experiment stops producing events.
retryCounterTtl: ${OPIK_EXPERIMENT_DENORM_RETRY_COUNTER_TTL:-30m}
# Default: 10
# Description: Claim pending messages every N polling intervals
claimIntervalRatio: ${OPIK_REDIS_EXPERIMENT_DENORM_CLAIM_INTERVAL_RATIO:-10}
# Default: 10m
# Description: Time before a message is considered orphaned and eligible for claiming
pendingMessageDuration: ${OPIK_REDIS_EXPERIMENT_DENORM_PENDING_MESSAGE_DURATION:-10m}
# Default: 3
# Description: Maximum number of retry attempts for failed messages (1-10)
maxRetries: ${OPIK_REDIS_EXPERIMENT_DENORM_MAX_RETRIES:-3}
# Default: 100
# Description: Maximum number of ZSET entries to read per page when flushing pending experiments (10-1000)
jobBatchSize: ${OPIK_EXPERIMENT_DENORM_JOB_BATCH_SIZE:-100}
# Default: 5s
# Description: Interval at which the denormalization job runs to flush pending experiments (min 1s)
jobInterval: ${OPIK_EXPERIMENT_DENORM_JOB_INTERVAL:-5s}
# Default: 10000
# Description: Maximum length of the Redis stream. Older entries are trimmed when this limit is exceeded.
streamMaxLen: ${OPIK_REDIS_EXPERIMENT_DENORM_STREAM_MAX_LEN:-10000}
# Default: 100
# Description: Number of entries to trim in a single operation when streamMaxLen is exceeded.
streamTrimLimit: ${OPIK_REDIS_EXPERIMENT_DENORM_STREAM_TRIM_LIMIT:-100}
# Configuration for buffering projects.last_updated_trace_at updates in Redis and flushing them to MySQL
# periodically, instead of writing MySQL synchronously on every trace-created/updated event. Keeps the
# high-frequency ingestion path off the contended `projects` row (avoids lock contention / connection churn).
projectLastUpdatedFlush:
# Default: false
# Description: When enabled, trace events buffer the per-project last-updated timestamp in Redis and a job
# flushes it to MySQL; when disabled, the timestamp is written to MySQL synchronously per event (legacy).
enabled: ${PROJECT_LAST_UPDATED_FLUSH_ENABLED:-false}
# Default: true
# Description: When enabled (and the feature above is on), schedule the periodic flush job. Set false to buffer in
# Redis without a scheduler (e.g. tests that invoke the job manually).
jobEnabled: ${PROJECT_LAST_UPDATED_FLUSH_JOB_ENABLED:-true}
# Default: 30s
# Description: Interval at which the flush job drains the Redis buffer into MySQL (min 1s)
jobInterval: ${PROJECT_LAST_UPDATED_FLUSH_JOB_INTERVAL:-30s}
# Default: 25s
# Description: Time the flush job holds the distributed lock (kept below jobInterval so it releases each cycle)
jobLockTime: ${PROJECT_LAST_UPDATED_FLUSH_JOB_LOCK_TIME:-25s}
# Default: 500ms
# Description: Time the flush job waits to acquire the lock before giving up (100ms-5s)
jobLockWaitTime: ${PROJECT_LAST_UPDATED_FLUSH_JOB_LOCK_WAIT_TIME:-500ms}
# Default: 500
# Description: Maximum number of ZSET entries to read per page when flushing pending projects (10-5000)
jobBatchSize: ${PROJECT_LAST_UPDATED_FLUSH_JOB_BATCH_SIZE:-500}
# Configuration for rate limit. This is not enabled by default for open source installations.
# If enabled, rate limit is applied to creation and update of various entities including traces, spans, projects,
# prompts, feedback definitions, experiments, datasets and dataset items
rateLimit:
# Default: false
# Description: Whether or not rate limit is enabled
enabled: ${RATE_LIMIT_ENABLED:-false}
# This uses as a fallback rate limit configuration in case an entity specific configuration doesn't exist
generalLimit:
# Default: 10000
# Description: how many events are allowed in the specified time bucket
limit: ${RATE_LIMIT_GENERAL_EVENTS_LIMIT:-10000}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_GENERAL_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: User
# Description: User facing bucket name
userFacingBucketName: general_events
# Description: Rate limit error message
errorMessage: "You have exceeded the general rate limit for this user. Please try again later."
workspaceLimit:
# Default: 5000
# Description: how many events per workspace are allowed in the specified time bucket
limit: ${RATE_LIMIT_WORKSPACE_EVENTS_LIMIT:-5000}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Workspace
# Description: User facing bucket name
userFacingBucketName: workspace_events
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this user in this workspace. Please try again later."
customLimits:
getSpanById:
# Default: 250
# Description: how many events are allowed in the specified time bucket
limit: ${RATE_LIMIT_GET_SPANS_BY_ID_EVENTS_PER_WORKSPACE_LIMIT:-250}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Get-Span-Id
# Description: User facing bucket name
userFacingBucketName: get_span_by_id
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
singleTracingOps:
# Default: 800
# Description: how many events are allowed in the specified time bucket
limit: ${RATE_LIMIT_SINGLE_TRACING_OPS_EVENTS_PER_WORKSPACE_LIMIT:-800}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Single-Tracing-Ops
# Description: User facing bucket name
userFacingBucketName: single_tracing_ops
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for single tracing operations. Please try again later."
ollieStateUpload:
# Default: 4
# Description: how many ollie state uploads are allowed in the specified time bucket (per API key)
limit: ${RATE_LIMIT_OLLIE_STATE_UPLOAD:-4}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_OLLIE_STATE_UPLOAD_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Ollie-State-Upload
# Description: User facing bucket name
userFacingBucketName: ollie_state_upload
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for ollie state uploads. Please try again later."
getSpans:
# Default: 30
# Description: how many getSpansByProject queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_GET_SPANS_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Get-Spans
# Description: User facing bucket name
userFacingBucketName: get_spans
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
search_spans:
# Default: 30
# Description: how many searchSpans queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_SEARCH_SPANS_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Search-Spans
# Description: User facing bucket name
userFacingBucketName: search_spans
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
getSpanStats:
# Default: 30
# Description: how many getSpanStats queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_GET_SPAN_STATS_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Get-Span-Stats
# Description: User facing bucket name
userFacingBucketName: get_span_stats
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
getTraces:
# Default: 30
# Description: how many getTracesByProject queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_GET_TRACES_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Get-Traces
# Description: User facing bucket name
userFacingBucketName: get_traces
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
searchTraces:
# Default: 30
# Description: how many searchTraces queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_SEARCH_TRACES_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Search-Traces
# Description: User facing bucket name
userFacingBucketName: search_traces
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
getTraceStats:
# Default: 30
# Description: how many getTraceStats queries are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_GET_TRACE_STATS_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Get-Trace-Stats
# Description: User facing bucket name
userFacingBucketName: get_trace_stats
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
tracesExist:
# Default: 30
# Description: how many tracesExist empty-state probes are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_TRACES_EXIST_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Traces-Exist
# Description: User facing bucket name
userFacingBucketName: traces_exist
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
spansExist:
# Default: 30
# Description: how many spansExist empty-state probes are allowed per workspace in the specified time bucket
limit: ${RATE_LIMIT_SPANS_EXIST_EVENTS_PER_WORKSPACE_LIMIT:-30}
# Default: 60
# Description: Time bucket size in seconds
durationInSeconds: ${RATE_LIMIT_WORKSPACE_EVENTS_DURATION_IN_SEC:-60}
# Description: Header name to use for rate limiting
headerName: Spans-Exist
# Description: User facing bucket name
userFacingBucketName: spans_exist
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for this operation. Please try again later."
mcpOAuthRegister:
# Default: 20
# Description: Max dynamic client registrations (RFC 7591) accepted per source IP in the specified time bucket
limit: ${MCP_OAUTH_REGISTRATION_RATE_LIMIT:-20}
# Default: 3600
# Description: Time bucket size in seconds
durationInSeconds: ${MCP_OAUTH_REGISTRATION_RATE_LIMIT_DURATION_IN_SEC:-3600}
# Description: Header name to use for rate limiting
headerName: Mcp-OAuth-Register
# Description: User facing bucket name
userFacingBucketName: mcp_oauth_register
# Description: Rate limit error message
errorMessage: "You have exceeded the rate limit for MCP OAuth client registration. Please try again later."
# Configuration for usage limit. This is not enabled by default for open source installations.
# In order to support that, the remote authentication server must contain a `quotas` object in its authentication
# response.
usageLimit:
# Description: The error to be displayed when submitting entities to a workspace where the usage limit is exceeded
errorMessage: ${USAGE_LIMIT_ERROR_MESSAGE:-You have exceeded the usage limit for this operation.}
# Configuration for product analytics events
analytics:
# Default: false
# Description: Whether or not to send product analytics events
enabled: ${OPIK_ANALYTICS_ENABLED:-false}
# Default: empty
# Description: Environment name included in every analytics event (e.g. "staging", "production")
environment: ${OPIK_ANALYTICS_ENVIRONMENT:-}
# Configuration for anonymous usage reporting
usageReport:
# Default: true
# Description: Whether or not to send anonymous usage reports
enabled: ${OPIK_USAGE_REPORT_ENABLED:-true}
# Default: https://stats.comet.com/notify/event/
# Description: URL to send the anonymous usage reports to
url: ${OPIK_USAGE_REPORT_URL:-https://stats.comet.com/notify/event/}
# Default: 5s
# Description: HTTP connect timeout for usage report
connectTimeout: ${OPIK_USAGE_REPORT_CONNECT_TIMEOUT:-5s}
# Default: 10s
# Description: HTTP read timeout for usage report
readTimeout: ${OPIK_USAGE_REPORT_READ_TIMEOUT:-10s}
# Description: Configuration for anonymous ID used to identify the installation
# Default: empty
anonymousId: ${OPIK_ANONYMOUS_ID:-}
# Configuration for application metadata
metadata:
# Default: latest
# Description: The application version
version: ${OPIK_VERSION:-latest}
# CORS related configuration
cors:
# Default: false
# Description: Whether or not to allow cross site scripting
enabled: ${CORS:-false}
# Encryption related configuration
encryption:
# Default: GiTHubiLoVeYouAA
# Description: Encryption key to use when storing sensitive information
key: ${OPIK_ENCRYPTION_KEY:-'GiTHubiLoVeYouAA'}
# Configuration for Online Scoring
onlineScoring:
# Default: 500 ms
# Description: How often Online Scoring will check Redis for new messages (in milliseconds)
# This is the global default value, can be overridden per stream
poolingInterval: ${REDIS_SCORING_CONSUMER_POOL_INTERVAL:-500ms}
# Default: 5s
# Description: Timeout for blocking read operations on Redis streams (long polling duration)
# This is the global default value, can be overridden per stream
longPollingDuration: ${REDIS_SCORING_LONG_POLLING_DURATION:-5s}
# Default: online_scoring
# Description: A consumer group name so multiple instances can share the stream load
consumerGroupName: ${REDIS_SCORING_CONSUMER_GROUP_NAME:-'online_scoring'}
# Default: 10
# Description: Maximum number of messages returned within a Redis Stream get
# This is the global default value, can be overridden per stream
consumerBatchSize: ${REDIS_SCORING_CONSUMER_BATCH_SIZE:-10}
# Default: 10
# Description: Claim pending messages every N polling intervals (global default)
claimIntervalRatio: ${REDIS_SCORING_CLAIM_INTERVAL_RATIO:-10}
# Default: 10m
# Description: Time before message considered orphaned and eligible for claiming (global default)
pendingMessageDuration: ${REDIS_SCORING_PENDING_MESSAGE_DURATION:-10m}
# Default: 3
# Description: Maximum number of retry attempts for failed messages (1-10, global default)
maxRetries: ${REDIS_SCORING_MAX_RETRIES:-3}
# Default: 10000
# Description: Max number of entries (approx) when publishing to the Redis stream. Oldest are evicted if exceeded
streamMaxLen: ${REDIS_SCORING_STREAM_MAX_LEN:-10000}
# Default: 100
# Description: Max number of entries to evict when publishing to the Redis stream (0 = no limit) if over max length
streamTrimLimit: ${REDIS_SCORING_STREAM_TRIM_LIMIT:-100}
# Default: 50000
# Description: Estimated-tokens threshold above which the LLM-as-judge online scorer routes through the
# agentic-tools path (skeleton initial prompt + read/jq/search tools). Below the threshold the inline
# path is used.
agenticToolsThresholdTokens: ${ONLINE_SCORING_AGENTIC_TOOLS_THRESHOLD_TOKENS:-50000}
# Default: 4
# Description: Characters-per-token ratio used to estimate a trace's token count from its serialized JSON
# length. 4 ≈ natural-language English. Lower for code/JSON-heavy workloads (≈ 2) — yields a more
# pessimistic estimate so the agentic-tools path engages earlier.
agenticToolsCharsPerToken: ${ONLINE_SCORING_AGENTIC_TOOLS_CHARS_PER_TOKEN:-4}
# Default: 52428800 (50 MB)
# Description: Maximum total bytes of attachment data injected as multimodal content per judge invocation.
# Every injected attachment is re-sent on every follow-up tool round, so cost is multiplicative.
# Lower this on memory-constrained deployments.
agenticToolsMaxInjectedBytes: ${ONLINE_SCORING_AGENTIC_TOOLS_MAX_INJECTED_BYTES:-52428800}
# Default: 32
# Description: Hard heap cap (in MB) on the trace-thread span preload used to size the
# inline-vs-agentic-tools routing decision. Spans stream under this cap; once crossed, the thread
# routes to the agentic-tools path (which drills per-trace on demand) instead of being buffered in
# full. Lower on memory-constrained deployments. See OPIK-7454.
agenticToolsMaxPreloadMb: ${ONLINE_SCORING_AGENTIC_TOOLS_MAX_PRELOAD_MB:-32}
# Default: 120
# Description: TTL in seconds for S3 presigned download URLs generated by the get_attachment agentic
# tool. The URL is consumed within a single tool-call round; 120 s is ample for most providers.
# Capped at 3600 s — longer-lived URLs are a security risk if the URL leaks.
agenticToolsS3PresignTtlSeconds: ${ONLINE_SCORING_AGENTIC_TOOLS_S3_PRESIGN_TTL_SECONDS:-120}
# Default: 4000
# Description: Per-variable substitution cap (in characters) for the {{trace}}/{{span}} structure-injection
# and agentic-tools paths. Large enough that small entity input/output renders inline, small enough that a
# huge entity doesn't blow context (the agent fetches the rest via the read tool). 500-100000.
maxPromptFieldChars: ${ONLINE_SCORING_MAX_PROMPT_FIELD_CHARS:-4000}
# Default: 5
# Description: Attachment-upload race tolerance for the {{trace}}/{{span}} structures — how many times the
# attachment lookup is retried when the entity references an attachment that isn't persisted yet. Interim
# guard (0-20; 0 disables retrying) pending the pre-evaluation dispatch delay (OPIK-7224).
attachmentFetchMaxRetries: ${ONLINE_SCORING_ATTACHMENT_FETCH_MAX_RETRIES:-5}
# Default: 300ms
# Description: Delay between attachment-lookup retries (see attachmentFetchMaxRetries). Worst-case added
# latency ≈ attachmentFetchMaxRetries × this, and only for entities that expect an attachment. 50ms-5s.
attachmentFetchRetryDelay: ${ONLINE_SCORING_ATTACHMENT_FETCH_RETRY_DELAY:-300ms}
## scorer: options from AutomationRuleEvaluatorType
## streamName: the name of the stream in redis
## codec: 'json' when there are non-java consumers, 'java' for java consumers only
## poolingInterval: (optional, but highly recommended) per stream pooling interval, overrides global value
## longPollingDuration: (optional, but highly recommended) per stream long polling duration, overrides global value
## consumerBatchSize: (optional, but highly recommended) per stream batch size, overrides global value
## claimIntervalRatio: (optional) per stream claim interval ratio, overrides global value
## pendingMessageDuration: (optional) per stream pending message duration, overrides global value
## maxRetries: (optional) per stream max retries, overrides global value
## streamMaxLen: (optional) per stream max length, overrides global streamMaxLen value
## streamTrimLimit: (optional) per stream trim limit, overrides global streamTrimLimit value
streams:
- scorer: llm_as_judge
streamName: stream_scoring_llm_as_judge
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_LLM_AS_JUDGE_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_LLM_AS_JUDGE_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_LLM_AS_JUDGE_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_LLM_AS_JUDGE_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_LLM_AS_JUDGE_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_LLM_AS_JUDGE_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_LLM_AS_JUDGE_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_LLM_AS_JUDGE_STREAM_TRIM_LIMIT:-}
- scorer: user_defined_metric_python
streamName: stream_scoring_user_defined_metric_python
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_USER_DEFINED_METRIC_PYTHON_STREAM_TRIM_LIMIT:-}
- scorer: trace_thread_llm_as_judge
streamName: stream_scoring_trace_thread_llm_as_judge
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_TRACE_THREAD_LLM_AS_JUDGE_STREAM_TRIM_LIMIT:-}
- scorer: trace_thread_user_defined_metric_python
streamName: stream_scoring_trace_thread_user_defined_metric_python
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_TRACE_THREAD_USER_DEFINED_METRIC_PYTHON_STREAM_TRIM_LIMIT:-}
- scorer: span_llm_as_judge
streamName: stream_scoring_span_llm_as_judge
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_SPAN_LLM_AS_JUDGE_STREAM_TRIM_LIMIT:-}
- scorer: span_user_defined_metric_python
streamName: stream_scoring_span_user_defined_metric_python
codec: java
# Optional per stream configuration (falls back to global if not specified)
poolingInterval: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_CONSUMER_POOL_INTERVAL:-}
longPollingDuration: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_LONG_POLLING_DURATION:-}
consumerBatchSize: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_CONSUMER_BATCH_SIZE:-}
claimIntervalRatio: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_CLAIM_INTERVAL_RATIO:-}
pendingMessageDuration: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_PENDING_MESSAGE_DURATION:-}
maxRetries: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_MAX_RETRIES:-}
streamMaxLen: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_STREAM_MAX_LEN:-}
streamTrimLimit: ${REDIS_SCORING_SPAN_USER_DEFINED_METRIC_PYTHON_STREAM_TRIM_LIMIT:-}
# Configuration for Test Suite assertions
testSuite:
# Default: 1
# Description: Number of LLM runs per dataset item during test suite execution
defaultRunsPerItem: ${TEST_SUITE_DEFAULT_RUNS_PER_ITEM:-1}
# Default: 10
# Description: Timeout in seconds for fetching dataset evaluators and item evaluators
fetchTimeoutSeconds: ${TEST_SUITE_FETCH_TIMEOUT_SECONDS:-10}
# Configuration for Experiment Execution (Redis Streams-based processing)
experimentExecution:
# Default: playground
# Description: Default project name when experiments are run from the playground without an explicit project
defaultProjectName: ${EXPERIMENT_EXECUTION_DEFAULT_PROJECT_NAME:-playground}
# Default: true
# Description: Whether the experiment item processing subscriber is enabled
enabled: ${EXPERIMENT_EXECUTION_ENABLED:-true}
# Default: experiment_item_processing_stream
# Description: Redis Stream name for experiment item processing messages
streamName: ${EXPERIMENT_EXECUTION_STREAM_NAME:-'experiment_item_processing_stream'}
# Default: experiment_item_processing
# Description: Consumer group name for experiment item processing
consumerGroupName: ${EXPERIMENT_EXECUTION_CONSUMER_GROUP_NAME:-'experiment_item_processing'}
# Default: 10
# Description: Maximum number of messages returned within a Redis Stream get
consumerBatchSize: ${EXPERIMENT_EXECUTION_CONSUMER_BATCH_SIZE:-10}
# Default: 500ms
# Description: How often the consumer checks Redis for new messages
poolingInterval: ${EXPERIMENT_EXECUTION_POOLING_INTERVAL:-500ms}
# Default: 5s
# Description: Duration for long-polling reads on the Redis Stream
longPollingDuration: ${EXPERIMENT_EXECUTION_LONG_POLLING_DURATION:-5s}
# Default: 10000
# Description: Maximum length of the Redis Stream (trimmed non-strictly)
streamMaxLen: ${EXPERIMENT_EXECUTION_STREAM_MAX_LEN:-10000}
# Default: 100
# Description: Trim limit for the Redis Stream
streamTrimLimit: ${EXPERIMENT_EXECUTION_STREAM_TRIM_LIMIT:-100}
# Default: 10
# Description: Ratio for claim interval calculation
claimIntervalRatio: ${EXPERIMENT_EXECUTION_CLAIM_INTERVAL_RATIO:-10}
# Default: 10m
# Description: Duration after which a pending message is eligible for claiming
pendingMessageDuration: ${EXPERIMENT_EXECUTION_PENDING_MESSAGE_DURATION:-10m}
# Default: 3
# Description: Maximum number of retries for failed messages
maxRetries: ${EXPERIMENT_EXECUTION_MAX_RETRIES:-3}
# Default: 24h
# Description: TTL for the batch completion counter in Redis
batchCounterTtl: ${EXPERIMENT_EXECUTION_BATCH_COUNTER_TTL:-24h}
# Configuration for Dataset Export
datasetExport:
# Default: false
# Description: Whether dataset export feature is enabled
enabled: ${DATASET_EXPORT_ENABLED:-false}
# Default: dataset-export
# Description: Redis stream name for dataset export jobs
streamName: ${DATASET_EXPORT_STREAM_NAME:-'dataset-export'}
# Default: dataset-export-consumers
# Description: Consumer group name for dataset export job processing
consumerGroupName: ${DATASET_EXPORT_CONSUMER_GROUP_NAME:-'dataset-export-consumers'}
# Default: 10
# Description: Maximum number of export jobs to process in a single batch
consumerBatchSize: ${DATASET_EXPORT_CONSUMER_BATCH_SIZE:-10}
# Default: 1s
# Description: How often to poll Redis for new export jobs
poolingInterval: ${DATASET_EXPORT_POOLING_INTERVAL:-1s}
# Default: 5s
# Description: Timeout for blocking read operations on Redis streams (long polling)
longPollingDuration: ${DATASET_EXPORT_LONG_POLLING_DURATION:-5s}
# Default: 3
# Description: Maximum number of retry attempts for failed export jobs (1-10)
maxRetries: ${DATASET_EXPORT_MAX_RETRIES:-3}
# Default: 2
# Description: Claim pending messages every N polling intervals
claimIntervalRatio: ${DATASET_EXPORT_CLAIM_INTERVAL_RATIO:-2}
# Default: 5m
# Description: Time before export job message considered orphaned and eligible for claiming
pendingMessageDuration: ${DATASET_EXPORT_PENDING_MESSAGE_DURATION:-5m}
# Default: 10000
# Description: Max number of entries (approx) when publishing to the Redis stream. Oldest are evicted if exceeded
streamMaxLen: ${DATASET_EXPORT_STREAM_MAX_LEN:-10000}
# Default: 100
# Description: Max number of entries to evict when publishing to the Redis stream (0 = no limit) if over max length
streamTrimLimit: ${DATASET_EXPORT_STREAM_TRIM_LIMIT:-100}
# Default: 24h
# Description: Default time-to-live for exported CSV files before automatic cleanup
defaultTtl: ${DATASET_EXPORT_DEFAULT_TTL:-24h}