Compare commits

...
415 Commits
Author SHA1 Message Date
steffen911 5b77e5835b chore: release v3.52.0 2025-04-22 10:00:35 +02:00
Steffen SchmitzandGitHub 657bb63c3e chore: make custom dashboards available for self-hosters (#6541) 2025-04-22 07:33:56 +00:00
Steffen SchmitzandGitHub b101e7c558 feat: allow optional metadata param on org / project CRUD API (#6524)
* feat: allow optional metadata param on org / project CRUD API

* chore: drop debugger statements

* chore: remove more debuggers

* chore: update tests

* chore: add metadata to fern spec
2025-04-22 07:30:02 +00:00
Steffen SchmitzandGitHub bac6b13145 fix: handle data retention on clustered clickhouse deployments (#6538) 2025-04-22 07:27:09 +00:00
Steffen SchmitzandGitHub 6817cdab0a chore: confirm pagination behaviour for scores-api (#6537)
* chore: confirm pagination behaviour for scores-api

* chore: use correct logger for score errors

* chore: inline error
2025-04-22 07:22:31 +00:00
Steffen SchmitzandGitHub 2d4708921c feat(dashboard): allow filtering by observation name (#6511) 2025-04-18 10:12:44 +00:00
marliessophieandGitHub 756b2f7501 chore(ui-forms): ensure name uniqueness enforced on form-level also (#6503)
* chore(ui-forms): ensure name uniqueness enforced on form-level also

* chore: nits
2025-04-17 14:13:01 +00:00
marliessophieandGitHub 2a685edbfa fix(tables): rename usage column to tokens column (#6498) 2025-04-17 11:58:12 +00:00
Steffen SchmitzandGitHub c1c22a9b9b fix: parse negative integer signs on otel timestamps (#6497) 2025-04-17 11:23:55 +00:00
Marlies Mayerhofer ecd3afb4c9 chore: release v3.51.2 2025-04-17 11:40:15 +02:00
marliessophieandGitHub 362902a69c fix(llm-keys): ensure default openai model supports all model params (#6496) 2025-04-17 11:38:05 +02:00
Marlies Mayerhofer ab14bac8df chore: release v3.51.1 2025-04-17 09:11:58 +02:00
Steffen SchmitzandGitHub 3e92e6b74d chore: add query tags to health check queries (#6493)
* chore: add query tags to health check queries

* chore: update type

* chore: switch to domain_ts instead of created_at
2025-04-17 05:34:59 +00:00
Steffen SchmitzandGitHub 54f3c224a7 chore: configure global posthog processing rate limit (#6492) 2025-04-17 04:44:34 +00:00
marliessophieandGitHub e39dda87f9 chore(cost-tracking): add support for openai o3 and o4-mini models (#6491) 2025-04-16 21:43:38 +00:00
Max DeichmannandGitHub 0b8ad96b18 fix: do not report usage to stripe for projects which have been deleted (#6468)
push
2025-04-16 13:14:58 +00:00
marliessophieandGitHub a4ba66f329 perf(datasets): split metrics and core data into two endpoints (#6481)
* perf(datasets): split metrics and core data into two endpoints

* chore: nit
2025-04-16 10:21:36 +00:00
Marc KlingenandGitHub 9c473be745 chore: Update CONTRIBUTING.md (#6476) 2025-04-16 01:46:33 +00:00
Marc KlingenandGitHub 4da0b9874a fix: preserve new lines when displaying score comments on single trace view (#6475) 2025-04-16 00:24:43 +00:00
Marc KlingenandGitHub 8fd6951a19 fix: window not available at build time (#6472) 2025-04-15 21:11:25 +02:00
Marc KlingenandGitHub b30734f43c fix: plain not available on some page loads (#6471) 2025-04-15 20:53:32 +02:00
Max DeichmannandGitHub 293215d1d4 chore: more error logging improvements for project deletions (#6467)
* fix

* push
2025-04-15 16:41:54 +00:00
Max DeichmannandGitHub ead31c8ca4 chore: improve logging for project deletion queue (#6465)
fix
2025-04-15 16:26:40 +00:00
marliessophieandGitHub 870336a5ed fix(prompts): prompt label popover overflows screen bounds (#6463) 2025-04-15 14:21:29 +00:00
steffen911 40792d6587 chore: release v3.51.0 2025-04-15 15:58:59 +02:00
Steffen SchmitzandGitHub 820de6f30f chore: refactor admin-api handling into ee folder (#6462)
* chore: refactor admin-api handling into ee folder

* chore: lint

* chore: add a license key for testing
2025-04-15 13:41:18 +00:00
marliessophieandGitHub 39fb6d99d4 feat(tables): reorder traces and observations column order; re-style visibility selector; peek on observations table (#6442)
* style(traces-table): re-order columns

* style(observations-table): re-order columns

* feat: add peek view to observations view

* style: revamp column visibility filter

* chore: typo

* chore: css
2025-04-15 13:27:55 +00:00
marliessophieandGitHub c156a961a2 chore(cost-tracking): add support for openai 4.1 models (#6459)
* chore(cost-tracking): add support for openai 4.1 models

* chore: add tokenizer config

* chore: add gpt-4.1 prefix
2025-04-15 11:45:57 +00:00
steffen911 8907056b39 chore: release v3.50.0 2025-04-15 10:42:48 +02:00
Steffen SchmitzandGitHub 7ad6749058 feat: expose project retention via the projects API (#6456)
* feat: expose project retention via the projects API

* chore: adjust docs

* chore: remove unnecessary assertion
2025-04-15 07:55:44 +00:00
Steffen SchmitzandGitHub 2e40330df8 feat: allow management of project api keys via API (#6457)
* feat: allow management of project api keys via API

* chore: add api docs
2025-04-15 07:37:51 +00:00
Jason E. JensenandGitHub 3f36fc1191 fix(users): adjust pagination calculation for user retrieval (#6453) 2025-04-15 08:42:27 +02:00
Steffen SchmitzandGitHub 82d7cb9769 chore: expand project and org name limit to 60 chars (#6455) 2025-04-15 06:22:41 +00:00
Steffen SchmitzandGitHub 9bc75b5081 chore: add reference to full Langfuse API spec (#6454)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* feat: allow org api key management via admin api

* feat: allow the creation of projects using an org api key

* chore: allow deletion of projects via API

* feat: create outline of SCIM Users support

* feat: implement SCIM style user endpoints

* chore: allow set password on user

* chore: lint

* feat: add endpoints to manage project and organization memberships

* chore: add memberships api docs

* chore: reject project membership calls if entitlement is missing

* chore: add team plan to test org

* chore: add reference to full Langfuse API spec
2025-04-15 06:07:05 +00:00
Steffen SchmitzandGitHub 3b4811599d feat: add endpoints to manage project and organization memberships (#6449)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* feat: allow org api key management via admin api

* feat: allow the creation of projects using an org api key

* chore: allow deletion of projects via API

* feat: create outline of SCIM Users support

* feat: implement SCIM style user endpoints

* chore: allow set password on user

* chore: lint

* feat: add endpoints to manage project and organization memberships

* chore: add memberships api docs

* chore: reject project membership calls if entitlement is missing

* chore: add team plan to test org
2025-04-15 05:51:11 +00:00
Steffen SchmitzandGitHub d6eee1687e feat: create outline of SCIM Users support (#6439)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* feat: allow org api key management via admin api

* feat: allow the creation of projects using an org api key

* chore: allow deletion of projects via API

* feat: create outline of SCIM Users support

* feat: implement SCIM style user endpoints

* chore: allow set password on user

* chore: lint

* chore: add scim api docs

* chore: remove outdated generated artifacts
2025-04-15 05:31:22 +00:00
Steffen SchmitzandGitHub 4b36ff8752 feat: allow the creation and deletion of projects using an org api key (#6438)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* feat: allow org api key management via admin api

* feat: allow the creation of projects using an org api key

* chore: allow deletion of projects via API

* chore: add documentation for new project routes

* chore: cleanup

* chore: error updates and handling

* chore: reduce reduntant error handling
2025-04-14 20:05:14 +00:00
Steffen SchmitzandGitHub 64827a0c9d feat: allow org api key management via admin api (#6437)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* feat: allow org api key management via admin api

* chore: add defs

* chore: remove admin api
2025-04-14 19:34:46 +00:00
Steffen SchmitzandGitHub fc84da9508 feat: add new organization routes (#6430)
* feat: add new organizations apiKey route

* chore: implement additional org routes

* chore: add API docs

* chore: checkin openapi spec

* chore: update tests

* chore: move admin-api spec to organizations-api

* chore: add postman collection
2025-04-14 19:00:01 +00:00
Marc KlingenandGitHub 3ca321d9f8 feat(cloud): switch from crisp to plain for in-app chat support (#6433)
* feat(cloud): switch from crisp to plain for in-app chat support

* push

* fix lint

* push
2025-04-14 16:49:56 +02:00
marliessophieandGitHub 66df08e232 chore(evals): fall back to bullmq job.data.timestamp allowing for successful retries (#6450)
* chore(evals): fall back to bullmq `job.data.timestamp` allowing for successful retries

* chore: test

* chore: test

* docs: add diagram and docs

* chore: typo

* chore: typo
2025-04-14 14:33:22 +00:00
Hassieb PakzadandGitHub af3cf6d860 fix(llm-tools): do not strip additional properties in schema (#6445) 2025-04-14 11:02:25 +02:00
marliessophieandGitHub 0edecde6e3 style(compare-runs): label on run metrics visibility settings (#6405) 2025-04-14 08:34:41 +00:00
marliessophieandGitHub 5a2fef1fe9 feat(compare-runs): Allow for variable row height on compare view (#6400)
* feat(dataset-compare-runs): Allow for variable row height on compare view

* chore: import as type
2025-04-14 08:21:47 +00:00
Steffen SchmitzandGitHub 28bada800d chore: add test cases for projects api (#6429)
* chore: add test cases for projects api

* chore: lint

* chore: align project name with pipeline
2025-04-11 15:06:53 +00:00
Steffen SchmitzandGitHub 663d67cbd6 fix: update access check for projects api (#6428) 2025-04-11 16:00:32 +02:00
Steffen SchmitzandGitHub bd651e81b7 chore: refactor authentication for admin apis (#6417)
* chore: refactor authentication for admin apis

* chore: lint

* chore: address feedback

* feat: add post organizations endpoint

* chore: update tests

* chore: update api key data model

* chore: align code with new scoped api keys

* chore: typing

* chore: align tests with new logic

* chore: remove ratelimitoverrides

* chore: remove accesslevel from queue message

* chore: add additional check to ingestion endpoint

* chore: add test for legacy api key format in redis

* chore: map all api keys in auditlog
2025-04-11 12:37:38 +00:00
Steffen SchmitzandGitHub f1547dab58 fix: avoid write after end errors on otel metrics endpoint (#6419) 2025-04-10 14:09:12 +00:00
Steffen SchmitzandGitHub 34b470f1fe fix: allow sessions filter on widgets (#6418) 2025-04-10 14:04:16 +00:00
steffen911 040b720dbf chore: release v3.49.1 2025-04-10 15:04:52 +02:00
Steffen SchmitzandGitHub d56e06d6c9 Revert "fix: access all replicas to create dataset score metrics (#6407) (#6416)"
Revert "fix: access all replicas to create dataset score metrics (#6407)"

This reverts commit a3b407ac92.
2025-04-10 15:04:39 +02:00
steffen911 08af244179 chore: release v3.49.0 2025-04-10 14:39:07 +02:00
c821d06099 chore: disable error log checks in playwright tests (#6414)
* push

* dummy

* chore: lint

---------

Co-authored-by: steffen911 <steffen@langfuse.com>
2025-04-10 12:11:58 +00:00
Steffen SchmitzandGitHub 7ed5f71154 fix(dashboards): support all dashboard filters across views (#6413) 2025-04-10 11:59:46 +00:00
Steffen SchmitzandGitHub 8c44314f56 chore: add dummy route that accepts all otel metrics calls (#6408) 2025-04-10 11:37:54 +00:00
Steffen SchmitzandGitHub a3b407ac92 fix: access all replicas to create dataset score metrics (#6407)
* fix: access all replicas to create dataset score metrics

* fix: access all replicas to create dataset score metrics

* chore: linting

* dummy
2025-04-10 09:31:03 +00:00
marliessophieandGitHub b043cf2600 style(compare-runs): remove duplicate run column selector (#6403) 2025-04-10 09:12:29 +00:00
Steffen SchmitzandGitHub d7f75a5e62 build: update end to end tests after dashboard change (#6406) 2025-04-09 19:28:34 +00:00
Steffen SchmitzandGitHub 9951364ff0 feat(dashboards): add beta preview for customizable dashboards (#6376) 2025-04-09 18:14:51 +02:00
David Alexander PfeifferandGitHub 03cf7bccfc feat(evals): Extend job configuration filter options; Evaluators can run based on environments (#6039)
* added environment filter option to traces

* WIP on multi-select ui inconsistency

* fixed overflow issue in multi select where an item would not take the full width automatically; also changed to overflow-x-auto

* fixed invalid DOM nesting of div within p (FormDescription) that resulted in a hydration error

* fix multiselect to cut overflowing text with ellipsis and take full name as titlte so you can hover over it, removed unnecessary css classes

* WIP on create evaluator page ui issue with filter builder

* Revert "WIP on create evaluator page ui issue with filter builder"

This reverts commit fd6dd507f2df3c5fb404f4e38a2983e8ef6405ef.

* hide empty string from multi-select options, as supporting empty values would require further work - out of scope for now; also checked for side effects, with current usage all good

* Added test suite for eval filtering

* Resolved comment: removed getEnvironmentsForProject from traces router and instead fetched environments inside evaluator-form via api.projects.environmentFilterOptions

* move eval filtering tests into separate test file

* removed redundancy via fixtures, prepared tests for concurrency

* filtering tests run concurrently

* extracted traceFilterOptions fetching into separate hook as it is used in both the evaluator form and the traces table, also fixed traces table since the environment was now missing there

* useTraceFilterOptions Hook after merge

* Make TraceOptions keys partial so that we can update filter options asynchronously

* default to empty object if response undefined

* exclude environment filter builder column from traces table since toolbar already has env

* removed useTraceFilterOptions hook as use case changed such that extraction into hook is no longer warranted
2025-04-09 13:40:52 +00:00
Steffen SchmitzandGitHub 4e737ea6cf fix: update column mapping for categorical score charts (#6399) 2025-04-09 13:39:21 +00:00
marliessophieandGitHub d604ce3ceb feat(run-compare): add detail navigation (#6398)
* feat(run-compare): add detail navigation

* nits

* typo

* eslint
2025-04-09 13:26:41 +00:00
Steffen SchmitzandGitHub 2c2daf6bb4 chore: remove beta flag from blob storage integration (#6397) 2025-04-09 09:45:56 +00:00
Hassieb PakzadandGitHub 8ebafda8a4 fix(prompt-ui): internal type on review chat prompt (#6391) 2025-04-08 21:22:22 +02:00
Steffen SchmitzandGitHub af7384b549 fix: propagate userId correctly to downstream tables (#6389) 2025-04-08 14:14:18 +00:00
Hassieb PakzadandGitHub 9768c2d171 perf(batch-exports): make page size configurable and set to 500 (#6385) 2025-04-08 12:59:44 +02:00
David Alexander PfeifferandGitHub f5aec02277 fix(scores/trpc): byid on deleted score resulted in 5xx error instead of 404 (#6384) 2025-04-08 09:58:31 +00:00
David Alexander PfeifferandGitHub b9cf01dd28 feat: add metadata field to scores (#6046) 2025-04-07 22:13:21 +02:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
7c42cf4357 perf: retry failed S3 deletions (#6378)
* push

* Update packages/shared/src/server/services/StorageService.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-04-07 18:19:19 +00:00
Max DeichmannandGitHub 72f4b88d15 perf: Increase batch export timeouts (#6375)
* push

* push

* push

* fix: flaky playwright

* fix

* push

* push
2025-04-07 13:26:23 +00:00
Max DeichmannandGitHub 99ce7c5093 chore: Increase project deletion retries (#6372)
* fix: flaky playwright

* push

* push
2025-04-07 12:31:09 +00:00
Max DeichmannandGitHub fcb7b82ba4 chore: improve project deletion logs (#6373)
push
2025-04-07 12:30:51 +00:00
Max DeichmannandGitHub ac5017c9ae chore: increase batch export retries and improve observability (#6374)
push
2025-04-07 12:17:57 +00:00
Max DeichmannandGitHub 00ffddad0f chore: Increase delete queue processing observability (#6371)
* fix: flaky playwright

* push
2025-04-07 11:34:37 +00:00
Steffen SchmitzandGitHub 28bf40769e chore: clarify titles in dashboard latency charts (#6370) 2025-04-07 11:33:13 +00:00
Hassieb PakzadandGitHub b65b0e25fc fix(playground): handle undefined content with toolCalls (#6364) 2025-04-07 09:13:31 +00:00
Max DeichmannandGitHub 62f860d9ef fix: flaky playwright (#6365) 2025-04-07 09:02:33 +00:00
Steffen SchmitzandGitHub 3989480a94 fix: update dashboard column accesses after query builder updates (#6363)
* fix: update dashboard column accesses after query builder updates

* chore: modify count
2025-04-07 08:50:09 +00:00
Max DeichmannandGitHub 4a6afddbed chore: create scores domain (#6360)
* push

* security: upgrade next

* fix

* push

* fix

* fix

* fix

* fix

* push

* push

* feat: full text search

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* push

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* security: upgrade nextjs 14.2.26

* push

* push

* playwright

* push

* fix

* remove

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* chore: create score domain

* chore: create score domain

* chore: create score domain

* chore: create score domain

* chore: create score domain
2025-04-07 07:19:04 +00:00
Max DeichmannandGitHub 4c6e8964e3 chore: refactor observations domain (#6353)
* push

* security: upgrade next

* fix

* push

* fix

* fix

* fix

* fix

* push

* push

* feat: full text search

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* push

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* chore: refactor observations domain

* security: upgrade nextjs 14.2.26

* push

* push

* playwright

* push

* fix

* remove

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* chore: create score domain
2025-04-07 07:03:38 +00:00
Max DeichmannandGitHub cb900c61f8 chore: add traces domain layer (#6253)
* push

* security: upgrade next

* fix

* push

* fix

* fix

* fix

* fix

* push

* push

* feat: full text search
2025-04-07 06:42:03 +00:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
9bc745d647 chore: upgrade playwright tests (#6359)
* push

* push

* fix

* fix

* Update web/src/__e2e__/create-project.spec.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix

* fix

* fix

* fix

* fix

* fix

* Update web/src/__e2e__/create-project.spec.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix

* fix

* fix

* fix

* fix

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-04-06 16:41:54 +00:00
Max DeichmannandGitHub 1b6e9e1c8b chore: upgrade tiktoken (#6357) 2025-04-06 12:23:24 +00:00
Max DeichmannandGitHub ce21cf34ae fix: fix model table provided_model_name (#6356)
* fix: fix model table

* fix: fix model table

* fix: fix model table
2025-04-06 12:15:54 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
bf063a72a0 chore(deps): bump next from 14.2.25 to 14.2.26 (#6316)
Bumps [next](https://github.com/vercel/next.js) from 14.2.25 to 14.2.26.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.25...v14.2.26)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 14.2.26
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-05 22:05:30 +00:00
5c2ac78eca feat: add new widget creator page (#6322)
* feat: add new widget creator page

* chore: add widget configuration box to creation screen

* chore: make chart title and description editable

* chore: auto-create cases

* chore: dynamically render chart based on output properties

* chore: linting

* chore: coloring

* chore: allow time series breakdowns

* chore: add support for additional chart types

* chore: conditionally show aggregation and row limit

* chore: add more separation between data selection and visualization in chart builder

* chore: add filter and time selector

* chore: make widget form overflow vertically

* chore: linting

* chore: reuse chart colors

* style: revert padding changes to card.tsx

* style: revert changing card headings to div element in card.tsx

* chore: refactoring and feedback

* chore: remove selected view restrictions

* chore: chart formatting

* chore: lint

---------

Co-authored-by: Marlies Mayerhofer <74332854+marliessophie@users.noreply.github.com>
2025-04-04 14:18:33 +00:00
steffen911 c6dadda96f chore: release v3.48.1 2025-04-04 11:47:13 +02:00
Steffen SchmitzandGitHub f831d1ac21 fix: improve parsing of tags for otel endpoint (#6345) 2025-04-04 09:44:29 +00:00
steffen911 1ca4ec7e28 chore: release v3.48.0 2025-04-03 19:04:59 +02:00
Steffen SchmitzandGitHub a9ca40aa81 fix: include tag filtering support on dashboard (#6338) 2025-04-03 16:58:05 +00:00
Marc KlingenandGitHub 8b0588a786 fix(auth): block duplicate membership invites that lead to sign in issues (#6337) 2025-04-03 16:24:54 +00:00
marliessophieandGitHub cc79604302 style(ui): reduce text size of trace/observation name on detail (#6329) 2025-04-03 13:41:28 +00:00
marliessophieandGitHub f12532c0a2 chore(ui): minor peek ui improvements (#6328)
chore(ui): minor peek ui wording improvements
2025-04-03 12:08:54 +00:00
Steffen SchmitzandGitHub 1c1519555a fix: blob storage export UI consistency (#6327)
* fix: blob storage export UI consistency

* chore: only set field value
2025-04-03 11:39:34 +00:00
SebiandGitHub 8954cf0c82 feat(auth): scope cookies to path for custom BASE_PATH deployments (#6320)
extend cookie paths
2025-04-03 11:10:36 +00:00
marliessophieandGitHub 849428abee feat(dataset-runs): improve UI/UX of runs and compare page (#6296)
* fixup: dataset io cell

* fixup: restructure dataset compare view

* fix: react dom error

* chore: fix margins

* chore: remove dataset details popover

* feat: make dataset runs table resizeable

* fix: react dom error

* fix: show more fraction digits on cost chart for experiment runs

* chore: improve design of observation tree peek view

* chore: refactor peek view pattern

* chore: implement new peek view pattern for compare view

* chore: remove zustand dep

* push

* perf: improve dataset compare view

* chore: eslint

* eslint

* push

* lint

* chore

* push
2025-04-03 10:57:35 +00:00
Hassieb PakzadandGitHub c014612cca feat(playground): allow uppercase in tool / schema names (#6326)
* feat(playground): allow uppercase in tool / schema names

* refactor
2025-04-03 09:59:04 +00:00
Hassieb PakzadandGitHub 803057b5eb fix(localStorage): memoize properly to avoid navigation issues (#6323) 2025-04-03 09:01:42 +00:00
Steffen SchmitzandGitHub 2152447932 perf: reduce search interval for trace existence check (#6315)
* perf: reduce search interval for trace existence check

* chore: add final again
2025-04-03 07:28:08 +00:00
marliessophieandGitHub 70e0b036e5 chore(batch-action): make entitlement prop optional (#5884)
* chore(batch-action): make `entitlement` prop optional

* push
2025-04-02 17:00:54 +00:00
Steffen SchmitzandGitHub bef666a694 feat: add json and jsonl support for scheduled blob exports (#6313)
* feat: add json and jsonl support for scheduled blob exports

* chore: revert schedule and add migration
2025-04-02 15:38:54 +00:00
Hassieb PakzadandGitHub 601a22d42c feat(playground): add tool parsing from Langchain generations (#6314) 2025-04-02 15:26:52 +00:00
Steffen SchmitzandGitHub 5fdde72d64 chore: track dlq length (#6312) 2025-04-02 12:54:06 +00:00
Hassieb Pakzad f9fc778ee7 chore: release v3.47.0 2025-04-02 14:01:27 +02:00
Hassieb PakzadandGitHub 975ef81bb5 feat(prompts): add protected labels (#6306) 2025-04-02 13:57:31 +02:00
Steffen SchmitzandGitHub 28e61fae0b chore: remove obsolete dashboard queries (#6303) 2025-04-02 09:32:41 +00:00
Steffen SchmitzandGitHub 0534ccacb2 perf: reduce input validation for dataset items (#6307) 2025-04-01 19:25:23 +00:00
Steffen SchmitzandGitHub 0c5089fd2b chore: pin dev clickhouse version to 24.3 (#6304)
* chore: pin dev clickhouse version to 24.3

* chore: only add input format flag for cloud

* chore: whitelist accepted cloud regions

* chore: disable test
2025-04-01 15:48:18 +00:00
Max DeichmannandGitHub 37c4c1422c perf: remove sentry tunnel config (#6305)
* fix

* fix
2025-04-01 13:01:48 +00:00
014da40fbf fix(ui): TableWithMetadataWrapper uses contain-layout on its root div so that EvaluatorDetail overflow issue is mitigated (#5982)
* fix: (workaround) evals page overflows when rendering right hand side metadata bar

This is more of a workaround, we should probably disable the overflow on the main wrapper div in layout.tsx and enable it only where needed - or find out why the overflow inside the metadata sidebar trigggers the scrollbar to pop up - some info on what I found:

- The body and other divs close to the root do not increase their size.
- The navigation sidebar does increase its vertical height, but limiting that does not resolve the main scrollbar.
- Limiting specifically the wrapper div in layout.tsx with overflow-hidden does resolve this, but globally disabling it requires most pages to be refactored.

* Revert "fix: (workaround) evals page overflows when rendering right hand side metadata bar"

This reverts commit 313a1c0d8a885a04974399f850f7f9aee58fd714.

* fix(ui): TableWithMetadataWrapper uses contain-layout on its root div so that EvaluatorDetail overflow issue is mitigated

Checked for side effects on the other components using TableWithMetadataWrapper and all work as expected.

---------

Co-authored-by: Marlies Mayerhofer <74332854+marliessophie@users.noreply.github.com>
2025-04-01 10:38:42 +00:00
Hassieb PakzadandGitHub 2317334bff feat(playground): persist selected model (#6292)
* feat(playground): persist selected model

* push

* push
2025-04-01 08:27:48 +00:00
Steffen SchmitzandGitHub 9ed449288b chore: add batch export env variables to docker-compose.yml (#6300) 2025-04-01 06:54:23 +00:00
Steffen SchmitzandGitHub 3b4800c37a chore: migrate score charts to new query builder (#6294) 2025-04-01 08:47:37 +02:00
Hassieb PakzadandGitHub b2ffd05ff8 fix(prompt-form): move prompt reference button (#6289) 2025-03-31 15:09:15 +00:00
Steffen SchmitzandGitHub e4594db953 chore: migrate latency charts to new query builder (#6284)
* chore: migrate latency charts to new query builder

* chore: convert model latencies chart

* chore: typing
2025-03-31 13:00:05 +00:00
marliessophieandGitHub 4b733c4da8 chore(annotation-scores): revert to synchronous delete; upsert on create route (#6282)
* chore(annotation-scores): revert to synchronous delete; upsert on create route

* fix: ensure scores data not only marked as stale but refreshed on score update
2025-03-31 12:36:29 +00:00
Hassieb PakzadandGitHub 378ac1c1a4 feat(llm-connections): add gemini-2.5-pro-exp-03-25 (#6286) 2025-03-31 11:57:18 +00:00
steffen911 9233c7c2d2 chore: release v3.46.0 2025-03-31 12:10:23 +02:00
Steffen SchmitzandGitHub c2170c0c8d feat: add support for GCS buckets (#6269)
* feat: add support for GCS buckets

* chore: cleanup

* chore: trim gcs credentials before parsing

* chore: add logging for redis shutdown in tests

* chore: update timeout for trace delete test

* chore: bump trace delete concurrency for tests
2025-03-31 10:04:49 +00:00
Max DeichmannandGitHub 7faf0e009f chore: revert unintended worker concurrency changes (#6275)
push
2025-03-29 14:42:12 +01:00
Max DeichmannandGitHub 86318ab50b perf: reduce worker deletion concurrency (#6274)
push
2025-03-29 14:39:17 +01:00
Max DeichmannandGitHub 48d280433a perf: reduce delete concurrency (#6273)
push
2025-03-29 14:27:38 +01:00
marliessophieandGitHub 45f29eaad8 fix(patch): hide scores tab on trace/observation preview (#6270)
fix(patch): hide scores tab on peek view
2025-03-28 20:34:52 +00:00
2bca2899f4 feat(evals, ui): enable deletion of evaluator via UI, DeleteButton refactor (#6247)
* feat(evals): enable deletion of evaluators and templates via UI

* Added tests for the evals job and template deletion trpc endpoints

* evals-trpc test refactor, it had a side effect on other tests since it was pruning the db, now instead creates a new org and project per tests and cleans them up after all tests are done

* removed test comments as those are now implemented

* fix wrong wording

* added template version to delete confirmation on template details delete action

* DeleteButton refactoring and moved deletion of templates to LFE-4573

* moving the call to captureDeleteSuccess inside the successful branch of executeDeleteMutation

* Display lock icon when action button in icon mode is unauthorized

* fix: quietly delete scheduled evals for deleted job executions

---------

Co-authored-by: Max Deichmann <m.deichmann@tum.de>
2025-03-28 18:22:21 +00:00
marliessophieandGitHub af6d0f0086 fix(ui): trace timeline width calculation error (#6268)
fix(ui): timeline width
2025-03-28 15:44:01 +00:00
Steffen SchmitzandGitHub 3802b1849d chore: migrate user chart to new query builder (#6262) 2025-03-28 14:28:03 +00:00
Steffen SchmitzandGitHub 19d2ee06e9 chore: update list of allowed blob storage export intervals (#6266) 2025-03-28 14:26:44 +00:00
Hassieb PakzadandGitHub b670abc6bc feat(playground): add tool call support (#6069) 2025-03-28 15:21:51 +01:00
Hassieb PakzadandGitHub 9395e94670 fix(prompts): handle resolvePromptGraph on deleted prompt (#6264) 2025-03-28 14:49:15 +01:00
Hassieb PakzadandGitHub 684e52e11f chore(docker-compose): update default LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT (#6265) 2025-03-28 14:49:00 +01:00
marliessophieandGitHub 4048e807af fix(prompt-ui): state stuck in showing prompt diff cycle (#6258) 2025-03-28 09:31:19 +00:00
Hassieb PakzadandGitHub 0b173f47f7 fix(prompts): dollar sign in replaceValue breaking resolution (#6256) 2025-03-27 23:39:38 +01:00
Max DeichmannandGitHub 15cad50991 chore: add logger for trpc route (#6255) 2025-03-27 21:48:28 +01:00
marliessophieandGitHub 747bfae721 chore(eval-count-tooltip): refactor to extract business logic into hook (#6251)
* chore(eval-count-tooltip): refactor to extract business logic into hook

* eslint
2025-03-27 17:45:50 +00:00
marliessophieandGitHub a01ec32715 feat(evals): allow adding custom value to tags filter (#6250) 2025-03-27 16:22:08 +00:00
Max DeichmannandGitHub 780fd577c4 chore: set sentry profiling sample rate (#6249)
push
2025-03-27 15:49:33 +00:00
marliessophieandGitHub cd33442168 fix(ui): detail navigation on users > traces page (#6248) 2025-03-27 15:39:49 +00:00
Steffen SchmitzandGitHub 6582dbc645 chore: migrate observation by model charts to new query builder (#6245) 2025-03-27 14:50:39 +00:00
Max DeichmannandGitHub 055eb06a4f chore: add sentry remove dd env variables in build step (#6246) 2025-03-27 15:40:26 +01:00
marliessophieandGitHub daeaf0a986 fix(trace-timeline): overflow and scroll behaviour (#6216)
* fix(trace-timeline): overflow and scroll behaviour

* fix(trace-timeline): show maximum of 3 scores and remainder in hover card

* push

* chore: refactor

* chore

* chore
2025-03-27 13:53:55 +00:00
Steffen SchmitzandGitHub f199dcb61c chore: remove warnings on missing domain timestamp (#6235) 2025-03-27 12:09:33 +01:00
Max DeichmannandGitHub 0ec0cca442 chore: enable sentry tunnel (#6234) 2025-03-27 11:38:53 +01:00
Steffen SchmitzandGitHub f4c75b896b chore: bump timeout for posthog export queries (#6233) 2025-03-27 09:57:04 +00:00
Steffen SchmitzandGitHub 16c76b2722 perf: reduce memory usage for posthog export via join_algo overwrite (#6230) 2025-03-27 10:17:44 +01:00
Steffen SchmitzandGitHub 64f6051048 chore: move the traces timeseries chart to new query builder (#6226) 2025-03-26 17:02:03 +00:00
Max DeichmannandGitHub 96dfd86b51 chore: improve sentry setup (#6224) 2025-03-26 16:20:14 +01:00
Steffen SchmitzandGitHub b1aaf57ad5 chore: migrate ModelCostTable to new query mechanism (#6222)
* chore: migrate ModelCostTable to new query mechanism

* chore: lint
2025-03-26 14:58:43 +00:00
steffen911 fae508d820 chore: release v3.45.2 2025-03-26 09:59:47 +01:00
Steffen SchmitzandGitHub a6e581d349 fix: use correct column name for filtering traces bar chart (#6215) 2025-03-26 08:56:09 +00:00
Max DeichmannandGitHub 9e77738a2f fix: fix by model charts (#6208)
* fix

* push

* push

* push
2025-03-25 20:56:00 +00:00
Marc Klingen d15c0a27f5 chore: release v3.45.1 2025-03-25 19:49:44 +01:00
Marc KlingenandGitHub a8626841b5 chore(cloud): update blobstorage integration entitlement (#6209) 2025-03-25 18:40:57 +00:00
marliessophieandGitHub 5945a93b7d fix(evaluator-config): preview execution of dataset run items (#6206)
* chore(evaluator-config): preview execution of dataset run items

* push
2025-03-25 17:44:11 +00:00
Steffen SchmitzandGitHub 9c447de584 chore: auto-close stale issues (#6207) 2025-03-25 17:21:44 +00:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
48df0e04de fix: fix model charts (#6202)
* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* Update packages/shared/src/server/repositories/dashboards.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Update web/src/__tests__/async/repositories/dashboard-repository.servertest.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix

* fix

* fix

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-25 17:12:50 +00:00
Steffen SchmitzandGitHub 0897ac753b feat: add custom-query backend (#6006)
* feat: add self-serve dashboard backend poc

* chore: data model thoughts

* chore: create initial query builder example and test case

* chore: handle empty dimensions and metrics

* chore: lint

* chore: extend filter conditions to account for timestamps

* chore: refactor query builder into sub-functions

* chore: use template queries for user-supplied values

* chore: add query builder tests

* chore: handle time dimension

* chore: add trpc endpoint to execute custom clickhouse query

* chore: add a query playground component to test a couple of queries

* chore: handle multiple joins

* chore: add observations table to data model

* chore: fix bug in data model

* chore: add test case to compare with old dashboard results

* chore: add scaffold for additional views

* expand the users view and add segments to filter scores subviews

* chore: add test cases for score views

* chore: drop users and sessions for now

* chore: add scores aggregate and observations cost tests

* chore: add sql injection tests

* chore: lint

* chore: fix dashboard test cases

* chore: drop users query test

* chore: add order by logic

* chore: fill timeseries values

* chore: use new query function on dashboard

* chore: convert TracesBarListChart.tsx to new query endpoint

* chore: make chart data compile

* chore: update tests

* chore: add tags to custom queries

* chore: typing

* chore: suffix join condition with sql

* chore: add typing in queryBuidler

* chore: limit playground to cloud admin users

* chore: add util to map legacy dashboard columns to new model

* chore: separate time filter state for TracesBarListChart.tsx

* chore: pass timestamps directly into chart components

* chore: add userId and sessionId on observations

* chore: pick auto time granularity based on hours
2025-03-25 14:54:37 +00:00
Marc KlingenandGitHub d00c63100e chore(cloud): remove rate limits from projects api as it is used by auth_check in sdks (#6193)
* chore(cloud): remove rate limits from projects api as it is used by auth_check in sdks

* address feedback

* improve comment
2025-03-25 14:52:23 +00:00
steffen911 e8970bc11c chore: release v3.45.0 2025-03-25 15:52:33 +01:00
Steffen SchmitzGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
eecb253093 feat: add blob storage integration (#6143)
* feat: add page to configure blob storage integration

* chore: remove blob storage logo and include three config options

* chore: add blob storage integration table

* chore: update router for blobstorage

* chore: placeholder for password and type update

* chore: create scaffolding for blobstorage queue processors

* chore: add scheduling logic for blob storage integration

* chore: prepare setup in processing job

* chore: implement extraction fucntion

* chore: add test case and fix generator setup

* chore: lint

* chore: overwrite default region to empty

* chore: remove details from auditlog and add beta

* Update web/src/pages/project/[projectId]/settings/integrations/blobstorage.tsx

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Update worker/src/__tests__/blobStorageIntegrationProcessing.test.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore: correct env name in tests

* Update worker/src/ee/integrations/blobstorage/handleBlobStorageIntegrationProjectJob.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore: update doc urls

* chore: open docs in new tab

* chore: ensure consistent block id length azure

* chore: revert test change

* chore: remove dummy error log

* chore: type annotation

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-25 13:39:33 +00:00
marliessophieGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
4e4fbb5101 fix(prompt-experiments): show form error if name is duplicated (#6189)
* fix(prompt-experiments): show form error if name is duplicated

* chore: fix typo

* Update web/src/ee/features/experiments/hooks/useExperimentNameValidation.tsx

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* eslint

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-25 09:07:16 +00:00
marliessophieandGitHub bb4823aa27 fix(evaluator-templates): control editing state (#6187) 2025-03-24 13:29:19 +00:00
marliessophieandGitHub 174d96c100 feat(evals): preview number of historic items to be evaluated (#6116)
* feat(evals): preview number of historic items to be evaluated

* refactor: split up large evaluator form file

* chore: drop optional pagination

* chore: fix eslint

* chore: rename test
2025-03-24 13:05:50 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8e59b544c9 chore(deps): bump next from 14.2.21 to 14.2.25 (#6175)
Bumps [next](https://github.com/vercel/next.js) from 14.2.21 to 14.2.25.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.21...v14.2.25)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 12:57:26 +00:00
Hassieb PakzadandGitHub cffd84f0e7 chore(azure-llm-connection): update api-version to support reasoning models (#6186) 2025-03-24 14:06:55 +01:00
Hassieb PakzadandGitHub 845faee385 fix(cost-tracking): null values in OpenAI usage schema (#6184) 2025-03-24 13:42:20 +01:00
Hassieb PakzadGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
e45c4af30f chore(prompts): add error logs for resolvePromptGraph (#6181)
* chore(prompts): add error logs for resolvePromptGraph

* Update packages/shared/src/server/services/PromptService/index.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-24 11:31:29 +00:00
Marc KlingenandGitHub 616544a48c chore: apply prettier (#6176) 2025-03-24 09:46:13 +00:00
steffen911 75d64b38b3 chore: release v3.44.0 2025-03-24 09:35:15 +01:00
Steffen SchmitzandGitHub 65cdd75282 chore: drop queue backup option in bullmq (#6141)
* chore: drop queue backup option in bullmq

* chore: lint
2025-03-24 08:26:32 +00:00
Steffen SchmitzandGitHub 2744028f4c feat: extract top-level metadata from langfuse.metadata (#6173)
* feat: extract top-level metadata from langfuse.metadata

* chore: extract metadata based on prefix

* chore: add support for resourceAttributes
2025-03-24 08:09:04 +00:00
Max DeichmannandGitHub 3c02c54de2 fix: fix model paring from redis (#6157)
* push

* fix

* push

* fix

* fix
2025-03-21 18:42:06 +00:00
marliessophieandGitHub 974d2c1007 fix(ui): reference errors in prompt detail screen (#6126)
* chore(ui): convert `action-button` to use forwardRef for compatibility w/ buttons

* fix(ui): ensure prompt item ref points to `command-item`
2025-03-21 17:07:21 +00:00
Max DeichmannandGitHub 008045c771 perf: cache model not found (#6148)
* push

* push

* fix
2025-03-21 14:57:17 +00:00
Marc KlingenandGitHub c6790c6c0e chore(ui): do not auto-generate new api keys in setup-tracing step (#6149)
* chore(ui): do not auto-generate new api keys in setup-tracing step

* fix
2025-03-21 14:17:01 +00:00
Marc KlingenandGitHub 909445ce5b fix(prompts): trim prompt names (#6145)
* fix(prompts): trim prompt names

* push
2025-03-21 13:38:04 +00:00
Max DeichmannandGitHub f4ed4a2635 chore: improve model match observability (#6147)
push
2025-03-21 13:18:39 +00:00
Max DeichmannandGitHub d6206b5269 chore: increase model match observability (#6144) 2025-03-21 13:45:36 +01:00
Max DeichmannandGitHub 62fa43aa78 feat: cache LLM models in Redis (#6129)
* push

* fix

* fix

* fix

* push

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* push

* push

* push

* fix

* fix

* fix

* fix

* push
2025-03-21 11:26:11 +00:00
Steffen SchmitzandGitHub 3c9239a4ab chore: update .env.prod.example (#6140) 2025-03-21 10:24:48 +00:00
marliessophieandGitHub 476cddb4e1 chore(ui): clamp page-header title to one line (#6139) 2025-03-21 10:01:45 +00:00
Steffen SchmitzandGitHub a6c1678da8 feat: add additional input/output parsing for pydantic via OTel (#6138) 2025-03-21 10:00:33 +00:00
Steffen SchmitzandGitHub 129805ebde fix: safely parse big numbers in api responses (#6136)
* fix: safely parse big numbers in api responses

* feat: add additional input/output parsing for pydantic via OTel

* Revert "feat: add additional input/output parsing for pydantic via OTel"

This reverts commit 71d0f3abd951702393aac7ab79a875b888f089cf.
2025-03-21 09:30:24 +00:00
marliessophieandGitHub 59eafb42c3 fix(ui): require annotation queue selection for bulk action (#6127) 2025-03-20 21:08:57 +00:00
marliessophieandGitHub e4695ac717 fix(ui): dom nesting error data-table-row-height-switch (#6125) 2025-03-20 20:12:52 +00:00
marliessophieandGitHub eebd6ea0e9 fix(ui): dom nesting error page-header (#6124) 2025-03-20 20:06:05 +00:00
Marc KlingenandGitHub b4a8b08d3d chore(cloud): add posthog for projects and orgs (#6117)
* chore(cloud): add posthog for projects and orgs

* push
2025-03-20 18:07:17 +00:00
Max DeichmannandGitHub ed44b663ff chore: add dd env variables to github build command (#6119) 2025-03-20 17:36:48 +01:00
Marc KlingenandGitHub 720ebe861e chore(cloud): cache response of cloudStatus api for 5 minutes (#6115)
chore(cloud): keep response of cloudStatus api cached across views for 5 minutes
2025-03-20 14:25:54 +00:00
Max DeichmannandGitHub 9a6f8fd75d refactor: refactor naming of database batch exports (#6111)
* refactor: refactor naming of database batch exports

* refactor: refactor naming of database batch exports
2025-03-20 12:56:38 +00:00
Steffen SchmitzandGitHub f0da1cfa30 chore: reduce cloudwatch flush frequency and batch metrics (#6108)
* chore: reduce cloudwatch flush frequency and batch metrics

* chore: simplify metrics reset

* chore: keep 30s flush

* chore: correct CW metrics
2025-03-20 12:05:07 +00:00
Marc KlingenandGitHub 0c9ebb3da7 feat(cloud): show status page menu item during incidents (#6100)
* feat(cloud): show status page menu item during incidents

* add to support menu
2025-03-20 09:59:49 +00:00
Hassieb PakzadandGitHub 3d16d1ac57 fix(model-params-ui): duplicate model names leading to rendering issues (#6107) 2025-03-20 10:40:59 +01:00
Marc KlingenandGitHub fa462a8bc4 chore(ui): improve padding in peek view header (#6099) 2025-03-19 18:59:29 +00:00
David Alexander PfeifferandGitHub 695b65fe0d chore(tests): fully unpin node version from temporary fix #6063 (#6096) 2025-03-19 15:38:36 +00:00
Hassieb PakzadGitHubjake goldenellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
955388e846 feat(llm-connections): add atla adapter (#6088)
* feat: enable Atla integration (#6022)

* push

* push

* Update packages/shared/src/server/llm/fetchLLMCompletion.ts

* Update web/src/features/public-api/components/CreateLLMApiKeyForm.tsx

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Revert "Update web/src/features/public-api/components/CreateLLMApiKeyForm.tsx"

This reverts commit efb2d3b359a85680224876481421d31bfbd44fd3.

---------

Co-authored-by: jake golden <jackson.golden@gmail.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-19 12:36:12 +00:00
David Alexander PfeifferandGitHub c6864ed8d9 fix(tests): disable --experimental-require-module (default since Node 20.19.0) since it breaks jest-based testing (#6075)
* pin node to problematic version for working on a fix

* added cross-env and disabled the feature flag causing the testing issue - long term fix should probably be switching to vitest

* unpin node version since problematic feature is now disabled fo affected tests
2025-03-19 11:04:59 +00:00
marliessophieandGitHub 917516fa91 chore(ui): control for more specific onClick actions in table with peek view (#6086) 2025-03-19 10:25:03 +00:00
David Alexander PfeifferandGitHub 19017a6709 fix(ui): OpenAiMessageView now renders messages where content is an empty string instead of ignoring them (#6068)
* fix(ui): IOPreview now renders messages where content is an empty string instead of ignoring them

* removed debug logs

* OpenAiMessageView first filters valid messages to render and then executes the "show x more ..." logic, this way we ensure that there can never be a mismatch between messages items and the amount of fields we support displaying

* Render empty string quotation marks if content is empty but not null or undefined

* Change length check to falsy check for conditional display of empty quotes if content is empty

* cleaner falsy check for rendering empty string quotation marks
2025-03-19 09:41:32 +00:00
marliessophieandGitHub ca5e6569f9 fix(peek-view): ensure onClickRow action smoothly keeps peek view open; onClick of select cells independent of peek view state (#6079)
* fix(ui): stop propagation on traces table checkbox

* fix(peek-ui): handle onRowClick action correctly for peek view

* feat(peek): do not close upon any screen button or checkbox clicks

* push
2025-03-19 00:41:36 +00:00
marliessophieandGitHub 101942b98b fix(ui): padding on single prompt page (#6070) 2025-03-18 18:35:32 +00:00
marliessophieandGitHub 1188a21b02 feat(traces): add peek view on traces table (#6048)
* feat: adjust table to new style

* style: filter and column options

* fixup: add peek view

* feat: add detail navigation

* chore: remove duplicated code

* chore: style settings tables

* chore: pin first column on traces table

* style: adjust animation speed of peek view

* fix: padding on score configs table

* style: onClick cursor in table

* fix: eslint

* style

* chore: fix toggle for timeline

* push

* style: add padding
2025-03-18 17:25:52 +00:00
Marc KlingenandGitHub ec72dd840d chore(ui): render min-level hint in a single line (#6051) 2025-03-18 14:55:54 +00:00
steffen911 c2d800ff0e chore: release v3.43.0 2025-03-18 15:15:41 +01:00
Steffen SchmitzandGitHub dcf159ef82 chore: lock dd-trace to 5.36.0 (#6064) 2025-03-18 14:13:30 +00:00
Marc KlingenandGitHub 998984b9ed chore(cloud): improved pricing/packaging (#5664)
* wip

* simplify

* actionbutton for upgrade prompt

* count events for free plan limit

* add sso settings

* rename lite to core

* add product id

* nit

* nits

* fix rate limit test

* ci run on teams plan

* fix

* fix names of pipeline steps

* test tmp

* add better error logs to makeAPICall

* push

* clone to throw better errors

* improve error

* improve error

* fix

* remove comment

* refactor

* push

* next attempt

* nit

* create new auth for failing test suites

* push

* fix rate limit test
2025-03-18 13:47:03 +00:00
Marc KlingenandGitHub 022b234e57 chore: pin node 20.18.3 to avoid issue introduced by 20.19.0 (#6063)
* test commit

* chore: pin node 20.18.3 to avoid issue introduced by 20.19.0

* docker

* revert test commit

* push
2025-03-18 13:30:58 +00:00
b8777aa5d1 chore: better error message when uploading existing dataset item (#6053)
chore: better docstring when uploading existing dataset item to different dataset

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-18 13:07:11 +00:00
Steffen SchmitzandGitHub 2e84feeab7 feat: support external S3 endpoint for batch exports (#6055)
* feat: add media and export external endpoint config

* chore: add docs string

* chore: add external endpoint support for azure

* chore: drop feature for media
2025-03-18 10:57:14 +00:00
Steffen SchmitzandGitHub a508485f88 chore: enable datadog profiling for web (#6020)
* chore: enable datadog profiling for web

* chore: update dockerfile
2025-03-18 07:26:53 +00:00
marliessophieandGitHub d8bb283a44 fix(ui): make models detail page scrollable (#6050) 2025-03-17 19:48:27 +00:00
Steffen SchmitzandGitHub 75ec05e206 Delete .devcontainer/devcontainer.json 2025-03-17 15:01:41 +01:00
Steffen SchmitzandGitHub 19f710abe2 chore: add devcontainer config 2025-03-17 14:56:35 +01:00
David Alexander PfeifferandGitHub ad2d6bee66 chore(ui): remove padding of "Additional Input" field on OpenAiMessageView (#6037) 2025-03-17 10:06:32 +00:00
David Alexander PfeifferandGitHub 40d0acae5f chore(ui): alignment and sizing consitency in ObservationTree / GroupedScoreBadge (#6031)
* Unified design of grouped score badge with trace detail score badges, except that text is no longer medium/semibold

* Made padding of root item of ObservationTree consistent with other items
2025-03-17 09:58:23 +00:00
Marc KlingenandGitHub 4d387cc35c chore(ui): standardize the prompt variable list preview across views (#6027)
* chore(ui): standardize the prompt variable list preview across views

* use ctx prisma
2025-03-17 09:34:44 +00:00
690885c900 fix(ui): fixed scrollbar appearing on IO preview mode switcher in trace and observation details (#5995)
* fixed scrollbar appearing on IO preview mode switcher in trace and observation details

* fix

---------

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-14 19:32:46 +00:00
David Alexander PfeifferandGitHub ef2baa94be fix(ui): fixed misalignment of badges in trace and observation details (#5994)
* fixed alignment issues of badges wrapped in links in trace and observation detail views

* Fixed tooltip of aggregated usage data badge (in trace details) rendering even if there is no underlying data
2025-03-14 19:19:14 +00:00
db6b442832 feat: Add environment tag on trace / observation detail views (#5985)
* feat: Add environment tag on trace / observation detail views

* shorten label

---------

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-14 19:17:19 +00:00
Hassieb Pakzad 8231ebae4a chore: release v3.42.1 2025-03-14 17:05:33 +01:00
Marc KlingenandGitHub 326e8d3189 chore(ui): always show tag buttons in table cells instead of only on hover (#6025) 2025-03-14 15:23:32 +00:00
Hassieb PakzadandGitHub d2001d110d chore(docker-compose): bind services to localhost (#6023) 2025-03-14 14:16:36 +01:00
Hassieb PakzadandGitHub 3f81c6b9d5 feat(cost-tracking): add OpenAIResponseUsageSchema support (#6003) 2025-03-14 12:08:28 +00:00
Marc KlingenandGitHub 991f837ee5 fix(ui): hide jump to playground button when not entitled (#6014) 2025-03-14 00:01:40 +00:00
Marc Klingen 062a7f27b8 chore: release v3.42.0 2025-03-13 19:23:52 +01:00
Steffen SchmitzandGitHub 924b326db6 chore: remove unused prisma query builder (#6005) 2025-03-13 17:21:23 +00:00
Andres CarrilloandGitHub 2780e66c13 feat(auth): add custom Gitlab SSO URL option (#5984) (#6004) 2025-03-13 17:50:16 +01:00
Marc KlingenandGitHub c2f51b8d2d feat(ui): add csv/json export for scores table (#5949)
* feat(ui): add csv/json export for scores table

* Merge branch 'main' into marc/lfe-3466-export-scores

* push

* add test

* fix cols

* clean up diff

* fix
2025-03-13 16:23:30 +00:00
Steffen SchmitzandGitHub 3a3021a176 chore: reduce host port mapping for internal docker compose components (#6002) 2025-03-13 15:36:34 +00:00
Marc KlingenandGitHub 5dd5a39f90 feat(api): add api for annotation queues (#5945)
* feat(api): add api for annotation queues

* fix

* push

* strict zod interfaces

* fix

* fix spec and types

* add additional tests
2025-03-13 15:24:19 +00:00
Steffen SchmitzandGitHub 9ee4544e1d docs: add security notes to docker compose deployment (#5999) 2025-03-13 14:27:10 +00:00
Hassieb PakzadandGitHub 136f8a3e83 fix(llm-connections): show bedrock error (#6000) 2025-03-13 15:06:42 +01:00
Hassieb Pakzad eecf0d680b chore: release v3.41.1 2025-03-13 11:07:07 +01:00
Hassieb PakzadandGitHub d50dbed797 feat(llm-connections): allow extraHeaders for azure (#5996) 2025-03-13 09:46:38 +00:00
Steffen SchmitzandGitHub bb1dbdf824 chore: reproduce clickhouse missing surrogate key error (#5980)
* chore: reproduce clickhouse missing surrogate key error

* chore: add fix candidate

* chore: adjust test cases

* chore: adjust test case
2025-03-13 07:47:31 +00:00
Hassieb Pakzad 0991d44525 chore: release v3.41.0 2025-03-12 18:28:25 +01:00
Max DeichmannandGitHub 449c9360ac fix: search past observations with correct timestamp in evals (#5986)
fix: use readonly for the column definitions
2025-03-12 16:41:14 +00:00
Hassieb PakzadandGitHub cc4a88d6da fix(prompts): block label deletion if dependent exists (#5983)
* fix(prompts): block label deletion if dependent exists

* fix

* Update web/src/features/prompts/server/actions/updatePrompts.ts
2025-03-12 16:05:46 +00:00
Steffen SchmitzandGitHub 11b2411a5b chore: prevent sorting by environment in UI tables (#5978) 2025-03-12 13:45:25 +00:00
d8a5ebc42e chore(cloud): Make UI recognize cloud:enterprise plan and add corresponding access rights and rate limits (#5975)
* chore(cloud): Make UI recognize cloud:enterprise plan and add corresponding access rights and rate limits

- label on project selector
- rate limits same as team
- access rights same as team
- no stripe product id for this (yet), cannot be purchased self-serve in product

* remove comments

---------

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-12 13:44:01 +00:00
Steffen SchmitzandGitHub 9042b005b8 feat: extract logfire.msg as span and trace name (#5977) 2025-03-12 13:23:33 +00:00
Hassieb PakzadandGitHub 7b70b5b678 feat(prompts): add composability (#5882) 2025-03-12 13:26:00 +01:00
Marc KlingenandGitHub c3ce043d47 chore: remove unnecessary comment (#5961) 2025-03-11 13:20:18 +00:00
Marc KlingenandGitHub 8c5737ebea chore: rename batch exports from generation to observation as table was generalized (#5950)
* chore: rename batch exports from generation to observation as table was generalized

* fix test
2025-03-11 13:15:36 +00:00
steffen911 cb928bf3fc chore: release v3.40.0 2025-03-11 13:49:18 +01:00
Steffen SchmitzandGitHub dc8a997324 feat: add score deletion to UI (#5956)
* feat: enable score deletion via Langfuse UI

* chore: add test cases

* chore: typo

* chore: implement deleteAnnotationScore

* chore: lint

* feat: add score deletion to UI

* chore: add trpc tests

* chore: allow multi-score deletion from table view

* chore: typoes and mock resets

* chore: update mock handling
2025-03-11 12:44:17 +00:00
Steffen SchmitzandGitHub 31da4bc5a5 chore: refactor score deletions into async queue (#5939)
* feat: enable score deletion via Langfuse UI

* chore: add test cases

* chore: typo

* chore: implement deleteAnnotationScore

* chore: lint
2025-03-11 08:02:13 +00:00
Max DeichmannandGitHub c0189eecad fix: use readonly for the column definitions (#5948)
* fix: use readonly for the column definitions

* fix: use readonly for the column definitions
2025-03-10 22:13:28 +00:00
Marc KlingenandGitHub a3f85e75dc docs: add zod type strict() to public api cursor rule (#5947) 2025-03-10 21:56:41 +00:00
Marc KlingenandGitHub 88ee2f3823 docs: improve public api cursor rule (#5946) 2025-03-10 21:35:38 +00:00
Max DeichmannandGitHub 0b485ad5d8 fix: fix eval status on details page (#5944)
* fix: fix eval status on details page

* push

* fix: fix eval status on details page

* fix: fix eval status on details page
2025-03-10 20:18:04 +00:00
Marc KlingenandGitHub 4e95550411 feat(datasets): show run name on runitems table (#5943)
* feat(datasets): show run name on runitems table

* perf

* push
2025-03-10 19:50:00 +00:00
Marc KlingenandGitHub ba9e26181b chore: remove models page notification (#5942) 2025-03-10 19:28:48 +00:00
Marc KlingenandGitHub 289a7210ee chore(cloud): add more data masking for posthog (#5941) 2025-03-10 19:27:36 +00:00
Max Deichmann fe0c4dc98d chore: release v3.39.0 2025-03-10 17:09:30 +01:00
Hassieb PakzadandGitHub 61c2ec268a perf(playground): memoizate ChatMessages (#5937)
* perf(playground): memoizate ChatMessages

* push

* add callbacks
2025-03-10 16:07:28 +00:00
Max DeichmannandGitHub 1df2781b59 fix: correctly extract jsonpath form observations for evals (#5938)
* fix: correctly extract jsonpath form observations for evals

* fix: correctly extract jsonpath form observations for evals
2025-03-10 15:42:44 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5478e870b3 chore(deps): bump axios from 1.7.7 to 1.8.2 (#5915)
Bumps [axios](https://github.com/axios/axios) from 1.7.7 to 1.8.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.7...v1.8.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 14:49:50 +00:00
Max DeichmannandGitHub 80c298fa1e chore: limit event id length (#5934) 2025-03-10 14:48:51 +00:00
Steffen SchmitzandGitHub 330cca6978 feat: add trace delete API endpoints (#5931)
* feat: add trace delete API endpoints

* chore: add api docs

* chore: update docs

* chore: typo

* chore: update audit logs

* chore: lint

* chore: update fern docs

* chore: fix return type
2025-03-10 14:13:33 +00:00
Steffen SchmitzandGitHub 286b78a1fe feat: add api key actions to auditlog table (#5932)
* feat: add api key actions to auditlog table

* chore: propagate audit logs to all relevant API routes

* chore: lint
2025-03-10 12:35:10 +00:00
Marc KlingenGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
f0c37c8309 chore: add initial cursor rules (#5926)
* chore: add some initial cursor rules

* Update .cursor/rules/frontend-features.mdc

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Update .cursor/rules/public-api.mdc

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-03-09 22:54:01 +00:00
Marc KlingenandGitHub 326b27cdda fix: ui config in localstorage should persist signing out (#5916)
* fix: ui config in localstorage should persist signing out

* push

* push
2025-03-07 17:50:04 +00:00
Marc KlingenandGitHub 886e352c39 fix: select/highlight text in Compare Dataset view (#5914)
* fix: select/highlight text in Compare Dataset view

* clean diff
2025-03-07 15:59:53 +00:00
steffen911 1cd76a49f1 chore: release v3.38.0 2025-03-07 16:48:21 +01:00
Marc KlingenandGitHub 0639b78468 feat(datasets): add multi-delete for dataset runs table (#5912) 2025-03-07 15:29:50 +00:00
Steffen SchmitzandGitHub 2d6e51e219 chore: test processing of special characters in S3 (#5907)
* chore: test processing of special characters in S3

* chore: reject carriage-return character in IDs

* Update ingestion-api.servertest.ts
2025-03-07 15:20:11 +00:00
Yohan GonçalvesandGitHub 1ed6358738 feat: add customizable claim mapping for SSO (#5858) 2025-03-07 16:19:51 +01:00
4fc339dbac chore: remove redundant readme files (#5900)
chore: remoe redundant readme files

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-06 19:55:34 +00:00
Steffen SchmitzandGitHub 1e64d97b75 feat: create new environment materialized views for quick lookups (#5895)
* feat: create new environment materialized views for quick lookups

* chore: update repository

* chore: lint

* chore: add final to environments query

* chore: always include default in array
2025-03-06 19:09:28 +00:00
Steffen SchmitzandGitHub 4d06482d78 fix: enforce ints on usageDetails (#5889)
* fix: enforce ints on usageDetails

* chore: make test actually test a  generation

* chore: lint
2025-03-06 17:05:10 +00:00
Marc KlingenandGitHub 603e5ca7c9 chore(ui): add env label on env multi-select (#5890) 2025-03-06 16:37:22 +00:00
Steffen SchmitzandGitHub 61c6560f24 chore: return 200 instead of 207 as OTel success status (#5883) 2025-03-06 14:58:40 +00:00
Steffen SchmitzandGitHub 6bff022a88 chore: log dropped data items correctly in clickhouse writer (#5876)
* chore: log dropped data items correctly in clickhouse writer

* chore: update test case
2025-03-06 14:43:11 +00:00
Steffen SchmitzandGitHub 1f7cac2dd8 feat: add environment column to UI tables (#5877)
* feat: add environment column to UI tables

* feat: add environment on sessions table

* chore: add to observations

* chore: add to scores

* chore: add to users table

* chore: lint
2025-03-06 14:08:41 +00:00
Hassieb PakzadandGitHub 49bccb8fa0 fix(ui-graph-view): handle single top most node (#5881) 2025-03-06 15:15:03 +01:00
Marc KlingenandGitHub fea8a3d8d1 chore: add noindex header (#5880) 2025-03-06 13:46:00 +00:00
Max DeichmannandGitHub 08fcdb68be chore: fix contributingmd file (#5879) 2025-03-06 14:34:46 +01:00
f18a120bd8 feat: add environment filter (#5765)
* feat: add environment filter on dashboard

* chore: add a useEffect and dashboard columns for filtering

* chore: add dashboard filters

* fixup: add environment filter hook and barebone code

* chore: add traces table filter

* chore: add sessions environment filter

* chore: do observations, scores, users

* chore make filter bar dynamic and change UI placement

* chore: map environment column specially in dashboard

* chore: add column

* chore: lint

* chore: remove overflow on multi-select

* chore: only load downstream calls once environment is available

* chore: only use isLoading condition

---------

Co-authored-by: Marlies Mayerhofer <74332854+marliessophie@users.noreply.github.com>
2025-03-06 10:45:18 +00:00
Max DeichmannandGitHub 2b3ca85344 chore: fix contributingmd file (#5870)
* chore: fix contributingmd file

* chore: fix contributingmd file

* chore: fix contributingmd file

* chore: fix contributingmd file

* chore: fix contributingmd file
2025-03-06 08:03:39 +00:00
Hassieb PakzadandGitHub 8b408858c4 feat(batch-exports): increase row limit to 1.5M (#5872) 2025-03-06 08:47:56 +01:00
89ad92c0ff chore: consistent casing of README files (#5865)
* docs: fix broken link in CONTRIBUTING.md

* chore: rename files to fix casing

---------

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-03-05 23:23:54 +00:00
Marc Klingen 16e1d19917 chore: release v3.37.0 2025-03-05 23:51:35 +01:00
Marc KlingenandGitHub 18d5ba1bfa feat(auth): add AUTH_WORKOS_ORGANIZATION_ID and AUTH_WORKOS_CONNECTION_ID envs (#5866) 2025-03-05 21:31:45 +00:00
Steffen SchmitzandGitHub 95d6b9fe13 chore: add name mappings to sync prisma schema with reality (#5863) 2025-03-05 16:56:47 +00:00
Max DeichmannandGitHub 23183a71c1 chore: add missing clickhouse writer metrics (#5851)
* chore: add missing clickhouse writer metrics

* chore: add missing clickhouse writer metrics

* Update worker/src/services/ClickhouseWriter/index.ts
2025-03-05 16:37:00 +00:00
5eb0a275a5 feat: add S3_CONCURRENT_READS and S3_CONCURRENT_WRITES config options (#5824)
Co-authored-by: Steffen Schmitz <steffen@langfuse.com>
2025-03-05 16:58:26 +01:00
Steffen SchmitzandGitHub 4c5366fa20 perf: reduce trace scans for scores counts (#5860)
* perf: reduce trace scans for sessions counts

* chore: add countAll test

* chore: add session for testing
2025-03-05 15:18:10 +00:00
Marc Klingen 4ebaf0a24a chore: release v3.36.0 2025-03-05 13:32:42 +01:00
Marc KlingenandGitHub b98b90e635 feat(auth): add workos as idp (#5828)
* feat(auth): add workos as idp

* add button for org and connection based sign in

* fix

* remove client auth method and checks

* remove unnecessary diff
2025-03-05 12:29:26 +00:00
Marc Klingen 36f11a645f chore: release v3.35.1 2025-03-04 22:32:19 +01:00
Marc KlingenandGitHub 3c8b26aa79 chore(api): update api reference and postman collection (#5842) 2025-03-04 22:31:38 +01:00
Marc Klingen 86840e4119 chore: release v3.35.0 2025-03-04 22:23:24 +01:00
Steffen SchmitzandGitHub 4b412fb6ca feat: map pydantic logfire events to langfuse datamodel (#5841)
* feat: map pydantic logfire events to langfuse datamodel

* chore: map events to empty if parsing fails
2025-03-04 20:58:42 +00:00
Steffen SchmitzandGitHub 271f75aa17 chore: reduce default batch size of background migrations (#5838)
* chore: reduce default batch size of background migrations

* chore: update the cli defaults
2025-03-04 15:58:11 +00:00
Marc KlingenandGitHub 669ad4cb92 feat(datasets): deletion of dataset runs via api (#5834)
* public api

* improve public api
2025-03-04 13:41:27 +00:00
Steffen SchmitzandGitHub 9b237d4041 fix: detect openinference LLM calls as generations (#5833)
feat: detect openinference LLM calls as generations
2025-03-04 11:13:42 +00:00
marliessophieandGitHub 15b4ca01ec fix(ui): overlapping status message on trace detail page (#5830) 2025-03-04 09:07:29 +00:00
Marc KlingenandGitHub 196b5319bf feat(datasets): allow for deletion of dataset items in ui and public API (#5816)
* push

* move into drop down menu

* fix

* move copy to the right side

* fern generate

* use trpc errors
2025-03-03 14:03:18 +00:00
Steffen SchmitzandGitHub d88e0456b8 perf: reduce memory consumption on observations query (#5811)
* perf: reduce memory consumption on observations query

* chore: drop skip index list for lint
2025-03-03 13:35:40 +00:00
Marc KlingenandGitHub 78463a9ce3 feat(datasets): copy items between datasets (#5800)
* wip

* push

* push
2025-03-03 12:51:06 +00:00
marliessophieandGitHub 0bd7219eba style(ui): trace view alignment improvements (#5789)
* style(ui): trace view alignment improvements

* fix: test
2025-03-03 12:25:15 +00:00
Steffen SchmitzandGitHub a307270d8c chore: upgrade fern and add java sdk example (#5814) 2025-03-03 11:09:41 +00:00
Max DeichmannandGitHub f1555190c1 fix: use aes-gcm 12 bytes for IV (#5764)
* fix: use aes-gcm 12 bytes for IV

* fix: use aes-gcm 12 bytes for IV

* fix: use aes-gcm 12 bytes for IV
2025-03-03 10:32:22 +00:00
Max DeichmannandGitHub 56c77e0de8 chore: reduce log level for frequent logs (#5804) 2025-03-02 17:54:07 +00:00
Marc KlingenandGitHub 48cbbb694f feat(ui): add LLM connections settings page separate from api keys (#5798) 2025-03-01 19:04:33 +00:00
Marc KlingenandGitHub 168dfd2caa feat(datasets): add archive/unarchive functionality for dataset items on single item view (#5797)
* feat(datasets): add archive/unarchive functionality for dataset items on single item view

* imrpove copy
2025-03-01 19:04:23 +00:00
Marc KlingenandGitHub ae66dd9e6f fix(ui): add playsInline attribute to video players (#5795) 2025-03-01 18:33:46 +00:00
Marc KlingenandGitHub d081aab38f feat(datasets): support adding dataset items to multiple datasets (#5796)
* feat(datasets): support adding dataset items to multiple datasets

* feat(datasets): optimize bulk dataset item creation with createMany
2025-03-01 18:09:46 +00:00
Marc KlingenandGitHub a86f0ab263 fix(cloud): only active evals should count towards plan limit (#5793) 2025-03-01 12:42:39 +00:00
Marc KlingenandGitHub 738df01ab7 feat(ui): add settings deep links to cmd+k (#5680)
* proejct settings

* push

* add org and small fixes
2025-03-01 10:12:04 +00:00
marliessophieandGitHub 549eac6fd3 fix(ui): overflow behaviour on trace timeline (#5792) 2025-03-01 07:50:55 +00:00
Marc KlingenandGitHub 6d125ec274 chore(ui): remove redundant className props from splash screens (#5791) 2025-03-01 00:44:46 +00:00
Marc KlingenandGitHub 4f54577f83 chore(ui): improve perf of sessions hasAny (#5783)
chore: improve performance of sessions hasAny
2025-03-01 00:31:29 +00:00
Steffen SchmitzandGitHub 1ec1bdf849 feat: add environment properties on api routes (#5781)
* feat: add environment properties on api routes

* chore: add env filter to traces

* chore: add observation env and daily metrics env filters

* chore: add env to score endpoints

* chore: filter sessions by environment

* chore: filter traces by environment

* chore: expand trace test assertions

* chore: lint
2025-02-28 16:12:18 +00:00
Hassieb PakzadandGitHub ed5a53b10e fix(ui): llm api key form model name delete (#5786) 2025-02-28 15:57:18 +00:00
marliessophieandGitHub 5b1d9b1dd1 style(page-header): margins (#5784) 2025-02-28 14:42:19 +00:00
marliessophieandGitHub adf4508ffd feat(traces): redesign single trace UI (#5718)
* feat(traces-ui): refactor preview for traces and observations

* fix: typo in use prompt code

* feat(ui): add redesigned timeline

* feat: support all settings on timeline view

* feat: support langgraph trace

* style: langgraph view

* chore: fix other usages of single trace components

* style: comment icon color

* fix: eslint

* style: optimise for reponsive design

* chore: refactor common functions to helpers

* chore(globals): remove comments

* style: expand clickable area; adjust search string

* style: small improvements

* fix: styling of trace preview page

* fix: eslint

* fix: remove duplicated cost in observation preview

* fix: session IO formatting

* style

* style

* style: final margins
2025-02-28 13:37:07 +00:00
Steffen SchmitzandGitHub 45f8b2e97b chore: skip tracing for LLM Api key routes (#5780) 2025-02-28 10:49:40 +00:00
marliessophieandGitHub 39c49b65a4 fix(ui): overlap on dataset runs screen (#5778) 2025-02-28 10:15:26 +00:00
steffen911 d905623cb3 chore: release v3.34.1 2025-02-28 11:11:43 +01:00
Steffen SchmitzandGitHub a87a3505b8 chore: add env.HOSTNAME support for worker container (#5779) 2025-02-28 10:06:41 +00:00
Steffen SchmitzGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
591de20a72 feat: simplify otel input/output and accept string token values (#5777)
* feat: simplify otel input/output and accept string token values

* chore: typo

* Update web/src/features/otel/server/index.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* chore: also beautify event attribute fallback

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-28 09:49:49 +00:00
Marc Klingen 33d3ab80cb chore: release v3.34.0 2025-02-27 22:54:18 +01:00
Marc KlingenandGitHub 6b9773caec feat(models): add openai gpt-4.5-preview (#5772) 2025-02-27 21:47:24 +00:00
Steffen SchmitzandGitHub c90b477d40 fix: disable tracing for resetPassword route (#5763) 2025-02-27 15:36:36 +00:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
0f448ccdde fix: always return 422 for signup error handler (#5761)
* fix: always return 422 for signup error handler

* Update web/src/features/auth-credentials/server/signupApiHandler.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Update web/src/features/auth-credentials/server/signupApiHandler.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-27 15:33:41 +00:00
marliessophieandGitHub 74f93aad79 chore: move dashboard button to the right, unify eval headers (#5762)
chore: move dashboard button to the right
2025-02-27 15:15:40 +00:00
Max DeichmannandGitHub 9650e87f64 fix: standardize way to get sso blocked domains (#5760)
fix: standardise way to get sso blocked domains
2025-02-27 15:15:10 +00:00
Steffen SchmitzandGitHub c5fc30a9d0 feat: map otel environment config to langfuse environment (#5757) 2025-02-27 14:46:43 +00:00
steffen911 4a26f47971 chore: release v3.33.1 2025-02-27 15:34:24 +01:00
Steffen SchmitzGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
e3a9e61d07 perf: filter relevant observation for data set run item stats (#5752)
* perf: filter relevant observation for data set run item stats

* Update web/src/features/datasets/server/service.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-27 14:08:07 +00:00
Hassieb Pakzad a12c2a3a97 fix(model-prices): bedrock claude 3-7 version 2025-02-27 13:14:05 +01:00
Hassieb PakzadandGitHub 80681e08af fix(model-prices): bedrock claude sonnet 3-7 version (#5753) 2025-02-27 13:10:08 +01:00
steffen911 4e97494390 chore: release v3.33.0 2025-02-27 11:58:10 +01:00
Steffen SchmitzandGitHub 346e5fe7b6 feat: map environment to score within eval service (#5749)
* feat: map environment to score within eval service

* chore: adjust tests

* chore: drop unused imports
2025-02-27 10:50:36 +00:00
Steffen SchmitzandGitHub 16482f588a fix: create traces via otel for empty parent span buffer (#5748)
* fix: create traces via otel for empty parent span buffer

* chore: test range for session duration
2025-02-27 10:10:51 +00:00
Marc KlingenandGitHub f047e21e13 chore: improved domain handling and early return in signupApiHandler (#5744) 2025-02-26 21:56:20 +00:00
marliessophieandGitHub 534e832c13 fix(ui): overlapping variables for chat prompt (#5740) 2025-02-26 17:47:03 +00:00
marliessophieandGitHub 5dbfec24f0 fix(ui): experiment from the prompt screen -> window does not fit screen (#5738) 2025-02-26 17:21:05 +00:00
Hassieb PakzadandGitHub 700705be84 chore(llm-keys): update bedrock form description (#5737) 2025-02-26 17:58:49 +01:00
Hassieb Pakzad 611c31ce54 chore: release v3.32.1 2025-02-26 17:06:23 +01:00
Hassieb PakzadandGitHub bdb5ddadd9 fix(ingestion): environment to immutable keys (#5736) 2025-02-26 16:01:26 +00:00
Hassieb PakzadandGitHub 0fd1f065bd fix(api): add environment to ingestion spec (#5735) 2025-02-26 16:02:49 +01:00
Marc KlingenandGitHub 8aa063303a chore(ui): move "configure tracing" to the right in dashboard header (#5731) 2025-02-26 13:59:21 +00:00
Marc KlingenandGitHub d0ff8a87fe chore(ui): minor improvements to onboarding pages (#5730)
chore: minor improvements to onboarding pages
2025-02-26 13:56:39 +00:00
marliessophieandGitHub 0e61ffd621 style(prompts): always show edit label button for prompt versions (#5729) 2025-02-26 13:41:01 +00:00
steffen911 9f20926bc4 chore: release v3.32.0 2025-02-26 14:36:38 +01:00
Steffen SchmitzandGitHub 81a232e4a4 fix: fallback to "default" for missing environment (#5728) 2025-02-26 13:34:33 +00:00
Marc KlingenandGitHub c7e7d62f47 feat(ui): add onboarding screens for core features (#5706)
* feat: add in-ui-onboarding for tracing

* feat(ui): add onboarding screens for core features

* add annotation queues

* move videos to static, add eval onboarding

* push

* push

* push

* push

* push
2025-02-26 13:13:43 +00:00
steffen911 2aa8971dff chore: release v3.31.0 2025-02-26 13:53:58 +01:00
Steffen SchmitzandGitHub 85f4cb0c13 fix: show retention settings for self-hosters (#5727) 2025-02-26 12:34:14 +00:00
Hassieb PakzadandGitHub 4bbba9d983 feat(api): add environment property to traces, scores, obs (#5724) 2025-02-26 13:32:03 +01:00
Steffen SchmitzandGitHub 0b7dd5a1a7 feat: process environment in ingestion pipeline (#5671)
* feat: process environment in ingestion pipeline

* chore: remove unnecessary status

* chore: typing

* chore: more typing

* chore: score env prop

* chore: adjust apis to pass tests

* chore: adjust ingestion service test

* chore: restrict allowed prefix
2025-02-26 12:18:38 +00:00
Steffen SchmitzandGitHub b5cad2693f fix: exclude clickhouse default date from session duration calc (#5726) 2025-02-26 09:51:52 +00:00
Max Deichmann 58d85d66b3 chore: release v3.30.0 2025-02-26 10:30:59 +01:00
Max DeichmannandGitHub 55a5a896f1 chore: track distribution of ingested event body size (#5723)
push
2025-02-26 09:05:08 +00:00
Steffen SchmitzandGitHub 5437beec48 Revert "fix: return nulls for left-joins for correct session durations (#5697)" (#5717)
This reverts commit ce967bac12.
2025-02-25 18:14:26 +01:00
Steffen SchmitzandGitHub 418e33a333 fix: only delete media items with no remaining references (#5713)
* fix: only delete media items with no remaining references

* chore: expand filter condition
2025-02-25 15:18:02 +00:00
Hassieb PakzadandGitHub e9bbd4488f feat(playground+evals): add Google AI Studio support (#5711) 2025-02-25 14:48:22 +01:00
Steffen SchmitzandGitHub 668ca24d5e fix: support gzip encoding on otel endpoint (#5710)
* fix: support gzip encoding on otel endpoint

* chore: check for includes
2025-02-25 10:41:43 +00:00
Hassieb PakzadandGitHub 7c746c7cfc feat(models): add claude-3-7-sonnet-20250219 (#5709) 2025-02-25 10:07:41 +00:00
Hassieb Pakzad de0eb76153 chore: release v3.29.1 2025-02-24 20:53:46 +01:00
Hassieb PakzadandGitHub 85088574b2 fix(public-api): list observations with name filter (#5700) 2025-02-24 20:52:58 +01:00
Steffen SchmitzandGitHub ce967bac12 fix: return nulls for left-joins for correct session durations (#5697)
* fix: return nulls for left-joins for correct session durations

* chore: comment updates

* chore: adjust trace_count
2025-02-24 15:57:47 +00:00
Steffen SchmitzandGitHub b8d0a4bbe8 chore: remove prisma references to traces, observations, scores (#5672)
* chore: remove prisma references to traces, observations, scores

* chore: separate enum and type name

* chore: type overwrites

* chore: chore

* chore: drop views

* chore: reduce diff

* chore: diff

* chore: types gen

* chore: lint

* chore: adjust tests

* chore: remove unused objects in test utils

* chore: adjust tests

* chore: score type parsing

* chore: fix otelmapping

* chore: make observation level internal
2025-02-24 15:43:25 +00:00
marliessophieandGitHub 1e7aeb8fc5 chore(llmCompletion): support system/developer messages for o3 (#5661) 2025-02-24 09:25:33 +00:00
marliessophieandGitHub 9d5cc39cd4 style(ui): improvements to prompt details screen (#5678)
* fix: header

* fix: search always show current version

* chore: adjust code block

* chore: re-add copy in code editor if no title

* chore: do not match current version always

* adjust margins

* chore: remove breadcrumb

* fix: typo

* fix: final margin

* style: eval template

* small design nits
2025-02-22 09:16:44 +00:00
Marc KlingenandGitHub 5c5dfcbac6 chore(ui): improve consistency of prompt and eval template forms (#5679)
* chore(ui): consistency in prompt form labels

* eval prompt form
2025-02-21 18:10:12 +00:00
marliessophieandGitHub 628d180051 feat(ui): new prompt detail screen; adjust design of IO and message view components (#5537)
* style(ui): adjust design of IO and message view components

* chore: adjust final style and fix imports

* style

* nit: show "null" if no output in dataset compare view

* style: add header and tertiary colors

* chore: add Header levels

* chore: add Timeline component

* feat: make JSONView optionally scrollable

* chore: refactor TagManager styling

* style: button variants for header

* chore: ensure chatml message overflow behaves within chat message

* feat: new prompt screen outline

* chore: refactor `extractVariables` to return count

* chore: ensure robust mobile behaviour

* style: small component adjustments

* chore: refactor style of `Comment` button

* feat: add search functionality to prompt nodes

* style: restyle tags

* revert: variable extraction count

* style: prompts page overflow

* chore: control label behaviour

* labels: show buttons on hover

* fix: formatting of titles

* eslint

* push

* push

* fix: overflows

* push

* diabled view
2025-02-21 13:46:59 +00:00
Max Deichmann 57708f0219 chore: release v3.29.0 2025-02-21 13:42:45 +01:00
Max DeichmannandGitHub 5d30aefcb3 fix: do not allow to deactivate eval configs which are only on existing objects (#5675)
* fix: do not allow to deactivate eval configs which rano on historic traces only

* fix: do not allow to deactivate eval configs which rano on historic traces only

* fix: do not allow to deactivate eval configs which rano on historic traces only

* fix: do not allow to deactivate eval configs which rano on historic traces only

* fix: do not allow to deactivate eval configs which rano on historic traces only
2025-02-21 12:40:18 +00:00
Max DeichmannandGitHub dd14e11535 perf: reduce eval create queue concurrency (#5665) 2025-02-20 19:24:38 +00:00
Max DeichmannandGitHub 5f87980013 fix: do not return all executions for eval config list trpc (#5663)
* fix: do not return all executions for eval config list trpc

* fix: do not return all executions for eval config list trpc

* fix: do not return all executions for eval config list trpc

* fix: do not return all executions for eval config list trpc
2025-02-20 17:56:38 +00:00
Max DeichmannandGitHub 2edc2487ae perf: limit concurrency for eval job creations (#5660)
* push

* push
2025-02-20 16:05:41 +00:00
Steffen SchmitzandGitHub 18508187f6 chore: add environment column to trace_sessions (#5656)
* chore: add environment column to trace_sessions

* chore: update test
2025-02-20 15:06:39 +00:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
eb5ee957e6 feat: apply evals on history of datasets + traces (#5488)
* push

* push

* push

* push

* fix

* fix

* add tests

* add tests

* add tests

* add tests

* add tests

* add tests

* fic

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* push

* push

* Update web/src/ee/features/evals/components/evaluator-form.tsx

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* push

* fix: fix dompurify

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-20 13:59:14 +00:00
Steffen SchmitzandGitHub 582f150b72 chore: add environment columns in clickhouse (#5649)
* chore: add environment columns in clickhouse

* chore: replace logger.warning with logger.warn
2025-02-20 13:05:35 +00:00
Steffen SchmitzandGitHub 7ce4e24cab chore: replace logger.warning with logger.warn (#5650) 2025-02-20 12:12:31 +00:00
marliessophieandGitHub b2d3080790 chore(prompts): support developer message (#5639)
* chore(prompts): support developer message

* chore: fix eslint config

* push
2025-02-20 09:40:32 +00:00
steffen911 3590608d30 chore: increase event log deletion timeout to 5min 2025-02-19 15:56:11 +01:00
Steffen SchmitzandGitHub 78e6c882ba chore: reduce attempts and increase delay on trace delete errors (#5637) 2025-02-19 14:24:28 +00:00
Steffen SchmitzandGitHub d5ea44b33c perf: only validate response schema on dev servers (#5630) 2025-02-19 13:11:42 +00:00
Steffen SchmitzandGitHub 8b601eed20 fix: re-enable trace deletion and remove trace S3 files (#5594)
* fix: re-enable trace deletion and remove trace S3 files

* chore: lint

* chore: lint

* chore: increase query timeout

* chore: reduce query result to only return event log

* chore: keep condition pattern

* chore: revert entitlement changes

* chore: move permission check

* chore: explain semi join and shift entitlement comment
2025-02-19 12:45:37 +00:00
Steffen SchmitzandGitHub caebc92051 chore: bump static page generation timeout (#5621) 2025-02-18 14:44:33 +00:00
Steffen SchmitzandGitHub e41f1c5e5b build: notify slack on failed deployment (#5617) 2025-02-18 14:40:29 +01:00
Steffen SchmitzandGitHub c419fd69fa chore: remove superfluous container_name overwrites (#5615) 2025-02-18 13:03:45 +00:00
Steffen SchmitzandGitHub 485dc94444 feat: map langfuse data model to further otel attributes (#5614)
* feat: map langfuse data model to further otel attributes

* chore: expand tests
2025-02-18 11:29:17 +00:00
Steffen SchmitzandGitHub c233c7fa8d feat: parse mlflow attributes on otel spans (#5609)
* feat: parse mlflow attributes on otel spans

* chore: correct failing test
2025-02-18 09:07:12 +00:00
marliessophieandGitHub 0263b40987 perf(sessions): display only first 10 users; show rest in paginated popover (#5599)
* perf(sessions): show only up to 10 initial users and the rest in popover

* nit: fix header on traces page
2025-02-17 19:01:01 +00:00
Marc KlingenandGitHub 44621d0d1f chore: remove the unnecessary file (#5598)
chore: remove unnecessary file
2025-02-17 18:34:01 +00:00
marliessophieandGitHub 5bd891ddc7 style(traces): style traces delete button in more menu in table (#5596) 2025-02-17 14:59:12 +00:00
marliessophieandGitHub 8e02f86fa7 chore(page-header): add new tabsComponent (#5593)
* chore(page-header): add tabs component

* style: replace tabs component on datasets pages

* style: replace tabs component on evals pages

* nit: fix dataset item page formatting

* style: replace tabs component on prompts pages

* chore: adjust col behaviour on header

* eslint
2025-02-17 13:34:57 +00:00
Max DeichmannandGitHub d7582c66ee security: upgrade jsonpath plus (#5591) 2025-02-17 12:41:12 +00:00
marliessophieandGitHub 75bef08f0b style(page-header): optimise for mobile view (#5590)
* chore: fix demo banner

* fix(page-header): info icon relative positioning

* fix: header title wrap behaviour

* fix(page-header): have info icon follow title

* style: move dataset level buttons to more menu

* push

* push
2025-02-17 12:36:33 +00:00
Max Deichmann 5f7b50cea8 chore: release v3.28.3 2025-02-17 09:56:07 +01:00
Steffen SchmitzandGitHub a9757d144f chore: fallback to LLM http status for /api/chatCompletion (#5554) 2025-02-17 08:42:49 +00:00
Steffen SchmitzandGitHub 12fb26388c fix: accept further content type formats on otel endpoint (#5584) 2025-02-17 08:41:14 +00:00
Max Deichmann 95d9aef705 chore: release v3.28.2 2025-02-15 13:29:06 +01:00
Max Deichmann 15fea028c2 chore: release v3.28.1 2025-02-15 01:04:28 +01:00
Max DeichmannandGitHub ac6e94ee3c security: upgrade release-it (#5558)
* security: upgrade release-it

* security: upgrade release-it

* security: upgrade release-it
2025-02-14 18:59:53 +00:00
Max DeichmannandGitHub e7332bd1e5 security: upgrade dompurify (#5557) 2025-02-14 19:39:59 +01:00
Max Deichmann fe8b2ba7ae chore: release v3.28.0 2025-02-14 19:20:25 +01:00
marliessophieandGitHub 652e96ee9d fix(header): breakpoint header behaviour (#5555)
fix(header): fix breakpoint header behaviour
2025-02-14 17:49:13 +00:00
Steffen SchmitzandGitHub 40ce493b06 fix: change numeric type parsing for sessions table filters (#5553) 2025-02-14 16:21:43 +00:00
Max DeichmannGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
aa7ba1a9c5 chore: add dashboard time filter test case (#5526)
* add tests

* Update web/src/__tests__/async/repositories/dashboard-repository.servertest.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-14 15:22:15 +00:00
Jannik MaierhöferandGitHub 869b027110 docs: fix gif on Readme (#5502) 2025-02-14 15:18:05 +00:00
Hassieb PakzadandGitHub 1243d9022e feat(trace-ui): add graph view (#5511)
* feat(trace-ui): add graph view

* push

* rename

* fix build error
2025-02-14 15:08:15 +00:00
marliessophieandGitHub d988c07d46 style(header): adjust minor paddings and relative scroll behaviour (#5551)
* style(header): relative positioning on scroll page

* style: add padding to container layout

* chore: rm top margin
2025-02-14 14:27:46 +00:00
0a53682ed6 chore: Update README.ja.md (#5545)
Update README.ja.md

modification in Japanese and put Japanese support info.

Co-authored-by: Marc Klingen <git@marcklingen.com>
2025-02-14 14:24:15 +00:00
Steffen SchmitzandGitHub ac517c1849 chore: enhance ingestion api documentation (#5550) 2025-02-14 14:17:45 +00:00
Iaroslav VolkovandGitHub 2778be5abb feat: add TLS env variable support for Redis (#5393) 2025-02-14 13:28:15 +01:00
56e4b92fd7 feat(ui): add new langfuse header (#5451)
* chore: extract PageContainer component

* chore: add ItemBadge component

* style: redesign publish trace switch

* style: redesign detail page nav

* chore: extract copybutton

* chore: wrap all pages in `PageContainer`

* chore: add settings-container; style nits

* chore: simplify langfuse header

* chore: replace session icon in itembadge

* chore: mv lg:container to settings-container level

* chore: refactor component logic in ProjectOverview

* style: make project button primary

* style: adjust light mode sidebar colors

* fix: rm unneccessary class

* fix: eslint

* chore: update readme

* chore: adjust page header to <h2/>

* chore: adjust colors

* style: button color

* style: refactor public/private highlight

* push

* chore: rename components

* style: add breadcrumb to pages

* style: add sidebar border

* style: adjust sharing logic

* push

* chore: eslint

* fix: header alignment

* push

* push

* eslint

---------

Co-authored-by: Max Deichmann <m.deichmann@tum.de>
2025-02-14 10:39:42 +00:00
Steffen SchmitzandGitHub 613126bbfb chore: add clickhouse tags to queries (#5535) (#5538)
* chore: add clickhouse tags to queries (#5535)

* chore: add clickhouse tags to queries

* chore: linting

* chore: add dashboard tags

(cherry picked from commit 95d67d65d7)

* chore: move tags to json

* chore: move to json format

* chore: fix build

* chore: remove redundant fallback
2025-02-14 10:09:08 +00:00
Max Deichmann d8738e7594 chore: release v3.27.2 2025-02-13 23:01:58 +01:00
Max DeichmannandGitHub b4f7aded4f chore: increase static page generation timeout nextjs (#5539)
* add tests

* push
2025-02-13 21:59:17 +00:00
729 changed files with 62587 additions and 16995 deletions
+6
View File
@@ -0,0 +1,6 @@
---
description: How to manage authorization and RBAC within full-stack langfuse features
globs: web/
alwaysApply: true
---
See [README.md](mdc:web/src/features/rbac/README.md) for details
+7
View File
@@ -0,0 +1,7 @@
---
description: How to enforce entitlements across full-stack features
globs: web/**
alwaysApply: true
---
Check [README.md](mdc:web/src/features/entitlements/README.md) to learn more about entitlements
+33
View File
@@ -0,0 +1,33 @@
---
description: How we build new full-stack features including frontend APIs, file structure, and components
globs: web/**
alwaysApply: true
---
## Framework
- Next.js
- Pages router
## File Structure
- We generally put all code related to a net-new feature into a folder within web/src/features.
- Checkout other features to learn about the common structure.
## API for frontend features
- We use TRPC.io to power full-stack features of the Langfuse Frontend
- Entry point for all trpc routes: [root.ts](mdc:web/src/server/api/root.ts)
- Authentication, see [authorization-and-rbac.mdc](mdc:.cursor/rules/authorization-and-rbac.mdc)
- Entitlements, see [entitlements.mdc](mdc:.cursor/rules/entitlements.mdc)
## Components
- We use Shadcn/ui
- Components in `@/src/components/ui`
- If a component is not installed yet, ask the user to install it for you
- When creating new custom components that generalize, we add them with a generalizable naming to `@/src/components`
## Styling
- We use Tailwind CSS
- We use a standard color palette which automatically handles light/dark mode, see [globals.css](mdc:web/src/styles/globals.css)
+16
View File
@@ -0,0 +1,16 @@
---
description: How to create new public api routes for Langfuse
globs:
alwaysApply: false
---
# Implementation
- All public api routes are in /web/src/pages/api/public
- New api routes should follow these guidelines:
- Use [withMiddlewares.ts](mdc:web/src/features/public-api/server/withMiddlewares.ts) as a wrapper
- Define types of api request and response in /web/src/features/public-api/types, use strict() for all zod objects
- Add end-to-end test, similar to [datasets-api.servertest.ts](mdc:web/src/__tests__/async/datasets-api.servertest.ts)
- Add fern configuration in /fern, learn more about structure here: https://buildwithfern.com/learn/api-definition/fern/overview
- Prompt user to regenerate the OpenAPI spec via the fern CLI
- Pagination starts at 1, query typing defined in publicApiPaginationZod, return meta in paginationMetaResponseZod
+43 -40
View File
@@ -84,6 +84,7 @@ OTEL_SERVICE_NAME="langfuse"
# AUTH_GITLAB_ISSUER=
# AUTH_GITLAB_CLIENT_AUTH_METHOD=
# AUTH_GITLAB_CHECKS=
# AUTH_GITLAB_URL=
# AUTH_AZURE_AD_CLIENT_ID=
# AUTH_AZURE_AD_CLIENT_SECRET=
# AUTH_AZURE_AD_TENANT_ID=
@@ -114,6 +115,11 @@ OTEL_SERVICE_NAME="langfuse"
# AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING=false
# AUTH_KEYCLOAK_CLIENT_AUTH_METHOD=
# AUTH_KEYCLOAK_CHECKS=
# AUTH_WORKOS_CLIENT_ID=
# AUTH_WORKOS_CLIENT_SECRET=
# AUTH_WORKOS_ALLOW_ACCOUNT_LINKING=false
# AUTH_WORKOS_ORGANIZATION_ID=
# AUTH_WORKOS_CONNECTION_ID=
# AUTH_CUSTOM_CLIENT_ID=
# AUTH_CUSTOM_CLIENT_SECRET=
# AUTH_CUSTOM_ISSUER=
@@ -166,7 +172,32 @@ OTEL_SERVICE_NAME="langfuse"
# LANGFUSE_INIT_USER_NAME=User Name
# LANGFUSE_INIT_USER_PASSWORD=password
# Redis configuration
# REDIS_HOST=
# REDIS_PORT=
# REDIS_AUTH=
# REDIS_CONNECTION_STRING=
# REDIS_ENABLE_AUTO_PIPELINING=
# Cache configuration
# LANGFUSE_CACHE_API_KEY_ENABLED=
# LANGFUSE_CACHE_API_KEY_TTL_SECONDS=
# LANGFUSE_CACHE_PROMPT_ENABLED=
# LANGFUSE_CACHE_PROMPT_TTL_SECONDS=
# Clickhouse configuration
# CLICKHOUSE_URL=
# CLICKHOUSE_CLUSTER_NAME=default
# CLICKHOUSE_DB=default
# CLICKHOUSE_USER=
# CLICKHOUSE_PASSWORD=
# CLICKHOUSE_CLUSTER_ENABLED=true
# Ingestion configuration
# LANGFUSE_INGESTION_QUEUE_DELAY_MS=
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_BATCH_SIZE=
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=
# LANGFUSE_INGESTION_CLICKHOUSE_MAX_ATTEMPTS=
### START Enterprise Edition Configuration
@@ -188,17 +219,6 @@ OTEL_SERVICE_NAME="langfuse"
### END Enterprise Edition Configuration
### START Envs to be deprecated in Langfuse v3.0
# Disable the expensive analytics queries and related features
# LANGFUSE_DISABLE_EXPENSIVE_POSTGRES_QUERIES="true"
### END Envs to be deprecated in Langfuse v3.0
### START Langfuse Cloud Config
# Used for Langfuse Cloud deployments
# Not recommended for self-hosted deployments as these are NOT COVERED BY SEMANTIC VERSIONING
@@ -230,24 +250,14 @@ OTEL_SERVICE_NAME="langfuse"
# NEXT_PUBLIC_DEMO_ORG_ID=
# NEXT_PUBLIC_DEMO_PROJECT_ID=
# Crisp chat
# NEXT_PUBLIC_CRISP_WEBSITE_ID=
# Plain Chat
# NEXT_PUBLIC_PLAIN_APP_ID=
# PLAIN_AUTHENTICATION_SECRET=
# Admin API
# ADMIN_API_KEY=
# Redis
# REDIS_HOST=
# REDIS_PORT=
# REDIS_AUTH=
# REDIS_CONNECTION_STRING=
# REDIS_ENABLE_AUTO_PIPELINING=
# Cache configuration
# LANGFUSE_CACHE_API_KEY_ENABLED=
# LANGFUSE_CACHE_API_KEY_TTL_SECONDS=
# LANGFUSE_CACHE_PROMPT_ENABLED=
# LANGFUSE_CACHE_PROMPT_TTL_SECONDS=
# LANGFUSE_CACHE_MODEL_MATCH_ENABLED=
# LANGFUSE_CACHE_MODEL_MATCH_TTL_SECONDS=
# Rate limiting
# LANGFUSE_RATE_LIMITS_ENABLED=
@@ -256,22 +266,15 @@ OTEL_SERVICE_NAME="langfuse"
# STRIPE_SECRET_KEY=
# STRIPE_WEBHOOK_SIGNING_SECRET=
# Betterstack Status Page
# BETTERSTACK_UPTIME_API_KEY=
# BETTERSTACK_UPTIME_STATUS_PAGE_ID=
### END Langfuse Cloud Config
## START Langfuse V3 Ingestion
### START Langfuse CI Config
# Clickhouse
# CLICKHOUSE_MIGRATION_URL=
# CLICKHOUSE_URL=
# CLICKHOUSE_USER=
# CLICKHOUSE_PASSWORD=
# CLICKHOUSE_DB=
# LANGFUSE_INIT_ORG_CLOUD_PLAN=
# Ingestion
# LANGFUSE_INGESTION_QUEUE_DELAY_MS=
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_BATCH_SIZE=
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=
# LANGFUSE_INGESTION_CLICKHOUSE_MAX_ATTEMPTS=
## END Langfuse V3 Ingestion
### END Langfuse CI Config
+2 -1
View File
@@ -52,10 +52,11 @@ jobs:
--build-arg NEXT_PUBLIC_BUILD_ID=${{ github.sha }} \
--build-arg NEXT_PUBLIC_POSTHOG_KEY=${{ vars.NEXT_PUBLIC_POSTHOG_KEY }} \
--build-arg NEXT_PUBLIC_POSTHOG_HOST=${{ vars.NEXT_PUBLIC_POSTHOG_HOST }} \
--build-arg NEXT_PUBLIC_CRISP_WEBSITE_ID=${{ vars.NEXT_PUBLIC_CRISP_WEBSITE_ID }} \
--build-arg NEXT_PUBLIC_PLAIN_APP_ID=${{ vars.NEXT_PUBLIC_PLAIN_APP_ID }} \
--build-arg SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} \
--build-arg SENTRY_ORG=${{ vars.SENTRY_ORG }} \
--build-arg SENTRY_PROJECT=${{ vars.SENTRY_PROJECT }} \
--build-arg NEXT_PUBLIC_LANGFUSE_TRACING_SAMPLE_RATE=${{ vars.NEXT_PUBLIC_LANGFUSE_TRACING_SAMPLE_RATE }} \
.
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
- name: Render AWS ECS Task Definition
+33 -6
View File
@@ -89,7 +89,7 @@ jobs:
timeout 10 bash -c 'until curl -f http://localhost:3000/api/public/health; do sleep 2; done'
tests-web-sync:
timeout-minutes: 20
timeout-minutes: 30
runs-on: ubuntu-latest
needs:
- pre-job
@@ -134,14 +134,14 @@ jobs:
grep -v -e '^LANGFUSE_S3_BATCH_EXPORT_ENABLED=' -e '^NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT=' .env.dev.example > .env
echo "LANGFUSE_INGESTION_QUEUE_DELAY_MS=1" >> .env
echo "LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=1" >> .env
- name: Run + migrate
- name: Run dev containers
run: |
docker compose -f docker-compose.dev.yml up -d
sleep 5 # Wait for PostgreSQL to accept connections
docker compose ps
env:
POSTGRES_VERSION: ${{ matrix.postgres-version }}
- name: Seed DB
- name: Migrate DB
run: |
pnpm run db:migrate
pnpm --filter=shared ch:up
@@ -152,6 +152,7 @@ jobs:
env:
LANGFUSE_INIT_ORG_ID: "seed-org-id"
LANGFUSE_INIT_ORG_NAME: "Seed Org"
LANGFUSE_INIT_ORG_CLOUD_PLAN: "Team"
LANGFUSE_INIT_PROJECT_ID: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a"
LANGFUSE_INIT_PROJECT_NAME: "Seed Project"
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: "pk-lf-1234567890"
@@ -165,7 +166,7 @@ jobs:
run: pnpm --filter=web run test-client
tests-web-async:
timeout-minutes: 20
timeout-minutes: 30
runs-on: ubuntu-latest
needs:
- pre-job
@@ -211,14 +212,17 @@ jobs:
grep -v -e '^LANGFUSE_S3_BATCH_EXPORT_ENABLED=' -e '^NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT=' .env.dev${{ matrix.blob-provider }}.example > .env
echo "LANGFUSE_INGESTION_QUEUE_DELAY_MS=1" >> .env
echo "LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=1" >> .env
- name: Run + migrate
echo "LANGFUSE_TRACE_DELETE_CONCURRENCY=100" >> .env
echo "ADMIN_API_KEY=admin-api-key" >> .env
echo "LANGFUSE_EE_LICENSE_KEY=langfuse_ee_test" >> .env
- name: Run dev containers
run: |
docker compose -f docker-compose.dev${{ matrix.blob-provider }}.yml up -d
sleep 5 # Wait for PostgreSQL to accept connections
docker compose ps
env:
POSTGRES_VERSION: ${{ matrix.postgres-version }}
- name: Seed DB
- name: Migrate DB
run: |
pnpm run db:migrate
pnpm --filter=shared ch:up
@@ -229,6 +233,7 @@ jobs:
env:
LANGFUSE_INIT_ORG_ID: "seed-org-id"
LANGFUSE_INIT_ORG_NAME: "Seed Org"
LANGFUSE_INIT_ORG_CLOUD_PLAN: "Team"
LANGFUSE_INIT_PROJECT_ID: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a"
LANGFUSE_INIT_PROJECT_NAME: "Seed Project"
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: "pk-lf-1234567890"
@@ -336,14 +341,28 @@ jobs:
run: |
cp .env.dev.example .env
cp .env.dev.example web/.env
- name: Install golang-migrate for Clickhouse migrations
run: |
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.tar.gz | tar xvz
sudo mv migrate /usr/bin/migrate
which migrate
- name: Run + migrate
run: |
docker compose -f docker-compose.dev.yml up -d
docker compose ps
sleep 5 # Wait for PostgreSQL to accept connections
- name: Ensure Docker dependencies are healthy
run: |
if docker-compose ps | grep "(unhealthy)"; then
echo "One or more services are unhealthy"
exit 1
else
echo "All services are healthy"
fi
- name: Seed DB
run: |
pnpm run db:migrate
pnpm --filter=shared run ch:up
pnpm run db:seed
- name: Build
run: pnpm run build
@@ -536,3 +555,11 @@ jobs:
platforms: |
linux/amd64
${{ startsWith(github.ref, 'refs/tags/') && 'linux/arm64' || '' }}
- name: Notify Slack
uses: ravsamhq/notify-slack-action@v2
if: always()
with:
status: ${{ job.status }}
notify_when: "failure"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
+22
View File
@@ -0,0 +1,22 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale. Please reopen if the issue persists."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}
+4 -1
View File
@@ -7,6 +7,7 @@
# testing
/coverage
/certs/
# database
/prisma/db.sqlite
@@ -61,4 +62,6 @@ node_modules
**/.next/*
**/.turbo/*
.yarn
.turbo
.turbo
web/test-results/*
+15 -138
View File
@@ -27,7 +27,7 @@ The maintainers are available on [Discord](https://langfuse.com/discord) in case
## Making a change
_Before making any significant changes, please [open an issue](https://github.com/langfuse/langfuse/issues)._ Discussing your proposed changes ahead of time will make the contribution process smooth for everyone. Large changes that were not discussed in an issue may be rejected.
_Before making any significant changes, please [open an issue](https://github.com/langfuse/langfuse/issues)._ Discussing your proposed changes ahead of time will make the contribution process smooth for everyone. Changes that were not discussed in an issue may be rejected.
Once we've discussed your changes and you've got your code ready, make sure that tests are passing and open your pull request.
@@ -53,117 +53,10 @@ A good first step is to search for open [issues](https://github.com/langfuse/lan
### Architecture Overview
**Langfuse v2**
```mermaid
flowchart TB
subgraph s4["Clients"]
subgraph s2["langfuse/langfuse-python"]
Python["Python low-level SDK"]
Decorator["observe() decorator"] -->|extends| Python
OAI["OpenAI drop-in replacement"] -->|extends| Python
Llamaindex["LlamaIndex Integration"] -->|extends| Python
LCPYTHON["Langchain Python Integration"] -->|extends| Python
Langflow -->|uses| LCPYTHON
LiteLLM -->|uses| Python
end
subgraph s3["langfuse/langfuse-js"]
JS["JS SDK"]
LCJS["Langchain JS Integration"] -->|extends| JS
Flowise -->|uses| LCJS
end
end
DB[Postgres Database]
Redis[Redis]
subgraph s1["Application (langfuse/langfuse/web)"]
API[Public HTTP API]
G[TRPC API]
I[NextAuth]
H[React Frontend]
Prisma[Prisma ORM]
H --> G
H --> I
G --> I
G --- Prisma
API --- Prisma
I --- Prisma
end
Prisma --- DB
JS --- API
Python --- API
```
**Langfuse v3 (work in progress, not released yet)**
> [!NOTE]
> Infrastructure will change in Langfuse version 3.0. More in the [GitHub Discussions](https://github.com/orgs/langfuse/discussions/1902).
> `langfuse/langfuse/worker` is under active development and not recommended for production use in Langfuse 2.x.
```mermaid
flowchart TB
subgraph s4["Clients"]
subgraph s2["langfuse/langfuse-python"]
Python["Python low-level SDK"]
Decorator["observe() decorator"] -->|extends| Python
OAI["OpenAI drop-in replacement"] -->|extends| Python
Llamaindex["LlamaIndex Integration"] -->|extends| Python
LCPYTHON["Langchain Python Integration"] -->|extends| Python
Langflow -->|uses| LCPYTHON
LiteLLM -->|uses| Python
end
subgraph s3["langfuse/langfuse-js"]
JS["JS SDK"]
LCJS["Langchain JS Integration"] -->|extends| JS
Flowise -->|uses| LCJS
end
end
subgraph s9 ["VPC (US and EU separated)"]
DB[Postgres Database]
Redis[Redis Cache/Queue]
Clickhouse[Clickhouse Database]
subgraph s1["Application (langfuse/langfuse/web)"]
API[Public HTTP API]
G[TRPC API]
I[NextAuth]
H[React Frontend]
ORM
H --> G
H --> I
G --> I
G --- ORM
API --- ORM
I --- ORM
end
subgraph s5["Application (langfuse/langfuse/worker)"]
Worker
end
Worker --- DB
Worker --- Redis
Worker --- Clickhouse
ORM --- DB
ORM --- Redis
ORM --- Clickhouse
end
JS --- API
Python --- API
```
See this [diagram](https://langfuse.com/self-hosting#architecture) for an overview of the architecture.
### Network Overview
> [!NOTE]
> This will change in Langfuse version 3.0. More in the [GitHub Discussions](https://github.com/orgs/langfuse/discussions/1902).
```mermaid
flowchart LR
Browser ---|Web UI & TRPC API| App
@@ -209,11 +102,12 @@ Requirements
**Steps**
1. Fork the repository and clone it locally
2. Run the development database
1. Install [golang-migrate](https://github.com/golang-migrate/migrate/tree/master/cmd/migrate#migrate-cli) as CLI
2. Fork the repository and clone it locally
```bash
pnpm run infra:dev:up
git clone https://github.com/langfuse/langfuse.git
cd langfuse
```
3. Create an env file
@@ -222,40 +116,23 @@ Requirements
cp .env.dev.example .env
```
4. Install dependencies
4. Run the entire infrastructure in dev mode
```bash
pnpm install
pnpm run dx
```
5. Run the migrations
You will be asked whether you want to reset Postgres and ClickHouse. Confirm both with 'Y' and press enter.
All database migrations and configs are in the `shared` package.
5. Open the web app in your browser to start using Langfuse:
```bash
pnpm --filter=shared run db:migrate
- [Sign up page, http://localhost:3000](http://localhost:3000)
- [Demo project, http://localhost:3000/project/7a88fb47-b4e2-43b8-a06c-a5ce950dc53a](http://localhost:3000/project/7a88fb47-b4e2-43b8-a06c-a5ce950dc53a)
# Optional: seed the database
# pnpm run db:seed
# pnpm run db:seed:examples
# pnpm --filter=shared run db:seed:load
```
6. Log in as a test user:
6. Start the development server
```bash
pnpm run dev
```
7. Open the web app in the browser:
http://localhost:3000
8. Log in as a test user (after you ran `db:seed` command):
Username: demo@langfuse.com
Password: password
- Username: `demo@langfuse.com`
- Password: `password`
## Monorepo quickstart
+5 -5
View File
@@ -28,7 +28,7 @@
<br/>
<span>Langfuseは、サポートと機能リクエストのために <a href="https://github.com/orgs/langfuse/discussions"><strong>Github Discussions</strong></a> を利用しています。</span>
<br/>
<span><b>採用中です。</b> <a href="https://langfuse.com/careers"><strong>当社で働く</strong></a> (製品エンジニアリングおよびテクニカル・ゴートゥーマーケットのポジション)への応募をお待ちしています。</span>
<span><b>We're hiring.</b> <a href="https://langfuse.com/careers"><strong>チームに加わる</strong></a> (製品エンジニアリングおよびテクニカルGTMのポジション)への応募をお待ちしています。</span>
<br/>
<br/>
<div>
@@ -71,7 +71,7 @@
Langfuseは**オープンソースのLLMエンジニアリング**プラットフォームです。
チームが共同でAIアプリケーションを**開発、監視、評価**、および**デバッグ**するのを支援します。
Langfuseは**数分でセルフホスト可能**で、**実績に裏打ちされた**システムです。
Langfuseは**数分でセルフホスト可能**で、**多くの実績を持つ**システムです。
[![Langfuse Overview Video](https://github.com/user-attachments/assets/3926b288-ff61-4b95-8aa1-45d041c70866)](https://langfuse.com/watch-demo)
@@ -173,6 +173,7 @@ Langfuseチームによるマネージドデプロイメント。充実した無
| [Mirascope](https://langfuse.com/docs/integrations/mirascope) | ライブラリ | LLMアプリケーション構築用のPythonツールキット |
| [Ollama](https://langfuse.com/docs/integrations/ollama) | モデル(ローカル) | オープンソースLLMを手軽にローカルで実行するためのツール |
| [Amazon Bedrock](https://langfuse.com/docs/integrations/amazon-bedrock) | モデル | AWS上でファウンデーションモデルやファインチューニング済みモデルを実行 |
| [Google VertexAI and Gemini](https://langfuse.com/docs/integrations/google-vertex-ai) | モデル | Google上でファウンデーションモデルやファインチューニング済みモデルを実行 |
| [AutoGen](https://langfuse.com/docs/integrations/autogen) | エージェントフレームワーク | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
| [Flowise](https://langfuse.com/docs/integrations/flowise) | チャット/エージェント UI | JS/TSのノーコードビルダーで、カスタマイズ可能なLLMフローを構築 |
| [Langflow](https://langfuse.com/docs/integrations/langflow) | チャット/エージェント UI | PythonベースのUIで、react-flowを用いてLangChainの実験やプロトタイピングを容易に実現 |
@@ -258,6 +259,7 @@ _[Langfuseの公開トレース例](https://cloud.langfuse.com/project/cloramnkj
- 当社の[ドキュメント](https://langfuse.com/docs)は、回答を探すための最良の出発点です。内容が充実しており、継続的なメンテナンスに努めています。GitHubを通じてドキュメントへの修正提案も可能です。
- よくある質問は[Langfuse FAQ](https://langfuse.com/faq)にまとめられています。
- [Ask AI](https://langfuse.com/docs/ask-ai)を利用すれば、質問に対して即座に回答を得ることができます。
- 日本語のサポートや決済, 請求書払いなどをお求めの場合は、日本のリセラー (https://gao-ai.com) にご相談ください。
サポートチャネル:
@@ -348,9 +350,7 @@ Langfuseを利用している主要なオープンソースPythonプロジェク
### テレメトリー
デフォルトでは、Langfuseはセルフホストされたインスタンスの基本的な使用統計情報を中央サーバ(PostHog)へ自動的に報告します。
これにより、以下が可能となります:
デフォルトでは、Langfuseは以下の目的でセルフホストされたインスタンスの基本的な使用統計情報を中央サーバ(PostHog)へ自動的に報告します。
1. Langfuseの利用状況を把握し、最も重要な機能の改善に役立てる
2. 内部および外部(例:資金調達)のレポートのために全体の利用状況を追跡する
+1 -1
View File
@@ -222,7 +222,7 @@ _[Public example trace in Langfuse](https://cloud.langfuse.com/project/cloramnkj
## ⭐️ Star Us
![Star Langfuse](https://langfuse.com/images/docs/github-readme/github-star-howto.gif)
![star-langfuse-on-github](https://github.com/user-attachments/assets/79a1d816-d229-4526-aecc-097d4a19f1ad)
## 💭 Support
+4 -3
View File
@@ -48,6 +48,10 @@ services:
REDIS_HOST: ${REDIS_HOST:-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/public/health"]
@@ -76,8 +80,6 @@ services:
clickhouse:
image: clickhouse/clickhouse-server
user: "101:101"
container_name: clickhouse
hostname: clickhouse
environment:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: clickhouse
@@ -97,7 +99,6 @@ services:
minio:
image: minio/minio
container_name: minio
entrypoint: sh
# create the 'langfuse' bucket before starting the service
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
+1 -4
View File
@@ -1,9 +1,7 @@
services:
clickhouse:
image: clickhouse/clickhouse-server
image: clickhouse/clickhouse-server:24.3
user: "101:101"
container_name: clickhouse
hostname: clickhouse
environment:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: clickhouse
@@ -19,7 +17,6 @@ services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
container_name: azurite
command: azurite-blob --blobHost 0.0.0.0
ports:
- "10000:10000"
+7 -10
View File
@@ -1,9 +1,7 @@
services:
clickhouse:
image: clickhouse/clickhouse-server
image: clickhouse/clickhouse-server:24.3
user: "101:101"
container_name: clickhouse
hostname: clickhouse
environment:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: clickhouse
@@ -12,14 +10,13 @@ services:
- langfuse_clickhouse_data:/var/lib/clickhouse
- langfuse_clickhouse_logs:/var/log/clickhouse-server
ports:
- "8123:8123"
- "9000:9000"
- 127.0.0.1:8123:8123
- 127.0.0.1:9000:9000
depends_on:
- postgres
minio:
image: minio/minio
container_name: minio
entrypoint: sh
# create the 'langfuse' bucket before starting the service
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
@@ -27,8 +24,8 @@ services:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: miniosecret
ports:
- "9090:9000"
- "9091:9001"
- 127.0.0.1:9090:9000
- 127.0.0.1:9091:9001
volumes:
- langfuse_minio_data:/data
healthcheck:
@@ -44,7 +41,7 @@ services:
command: >
--requirepass ${REDIS_AUTH:-myredissecret}
ports:
- 6379:6379
- 127.0.0.1:6379:6379
postgres:
image: postgres:${POSTGRES_VERSION:-latest}
@@ -60,7 +57,7 @@ services:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
ports:
- 5432:5432
- 127.0.0.1:5432:5432
volumes:
- langfuse_postgres_data:/var/lib/postgresql/data
+39 -23
View File
@@ -1,3 +1,8 @@
# Make sure to update the credential placeholders with your own secrets.
# We mark them with # CHANGEME in the file below.
# In addition, we recommend to restrict inbound traffic on the host to langfuse-web (port 3000) and minio (port 9090) only.
# All other components are bound to localhost (127.0.0.1) to only accept connections from the local machine.
# External connections from other machines will not be able to reach these services directly.
services:
langfuse-worker:
image: langfuse/langfuse-worker:3
@@ -12,48 +17,61 @@ services:
clickhouse:
condition: service_healthy
ports:
- "3030:3030"
- 127.0.0.1:3030:3030
environment: &langfuse-worker-env
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
SALT: "mysalt"
ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" # generate via `openssl rand -hex 32`
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres # CHANGEME
SALT: "mysalt" # CHANGEME
ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" # CHANGEME: generate via `openssl rand -hex 32`
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: ${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-true}
CLICKHOUSE_MIGRATION_URL: ${CLICKHOUSE_MIGRATION_URL:-clickhouse://clickhouse:9000}
CLICKHOUSE_URL: ${CLICKHOUSE_URL:-http://clickhouse:8123}
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
CLICKHOUSE_CLUSTER_ENABLED: ${CLICKHOUSE_CLUSTER_ENABLED:-false}
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: ${LANGFUSE_S3_EVENT_UPLOAD_BUCKET:-langfuse}
LANGFUSE_S3_EVENT_UPLOAD_REGION: ${LANGFUSE_S3_EVENT_UPLOAD_REGION:-auto}
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: ${LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT:-http://minio:9000}
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
LANGFUSE_S3_EVENT_UPLOAD_PREFIX: ${LANGFUSE_S3_EVENT_UPLOAD_PREFIX:-events/}
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: ${LANGFUSE_S3_MEDIA_UPLOAD_BUCKET:-langfuse}
LANGFUSE_S3_MEDIA_UPLOAD_REGION: ${LANGFUSE_S3_MEDIA_UPLOAD_REGION:-auto}
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT:-http://minio:9000}
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT:-http://localhost:9090}
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: ${LANGFUSE_S3_MEDIA_UPLOAD_PREFIX:-media/}
LANGFUSE_S3_BATCH_EXPORT_ENABLED: ${LANGFUSE_S3_BATCH_EXPORT_ENABLED:-false}
LANGFUSE_S3_BATCH_EXPORT_BUCKET: ${LANGFUSE_S3_BATCH_EXPORT_BUCKET:-langfuse}
LANGFUSE_S3_BATCH_EXPORT_PREFIX: ${LANGFUSE_S3_BATCH_EXPORT_PREFIX:-exports/}
LANGFUSE_S3_BATCH_EXPORT_REGION: ${LANGFUSE_S3_BATCH_EXPORT_REGION:-auto}
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_ENDPOINT:-http://minio:9000}
LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT:-http://localhost:9090}
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID: ${LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID:-minio}
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY: ${LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE: ${LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE:-true}
LANGFUSE_INGESTION_QUEUE_DELAY_MS: ${LANGFUSE_INGESTION_QUEUE_DELAY_MS:-}
LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS: ${LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS:-}
REDIS_HOST: ${REDIS_HOST:-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
REDIS_AUTH: ${REDIS_AUTH:-myredissecret} # CHANGEME
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
langfuse-web:
image: langfuse/langfuse:3
restart: always
depends_on: *langfuse-depends-on
ports:
- "3000:3000"
- 3000:3000
environment:
<<: *langfuse-worker-env
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: mysecret
NEXTAUTH_SECRET: mysecret # CHANGEME
LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-}
LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-}
LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-}
@@ -68,18 +86,16 @@ services:
image: clickhouse/clickhouse-server
restart: always
user: "101:101"
container_name: clickhouse
hostname: clickhouse
environment:
CLICKHOUSE_DB: default
CLICKHOUSE_USER: clickhouse
CLICKHOUSE_PASSWORD: clickhouse
CLICKHOUSE_PASSWORD: clickhouse # CHANGEME
volumes:
- langfuse_clickhouse_data:/var/lib/clickhouse
- langfuse_clickhouse_logs:/var/log/clickhouse-server
ports:
- "8123:8123"
- "9000:9000"
- 127.0.0.1:8123:8123
- 127.0.0.1:9000:9000
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
interval: 5s
@@ -90,16 +106,15 @@ services:
minio:
image: minio/minio
restart: always
container_name: minio
entrypoint: sh
# create the 'langfuse' bucket before starting the service
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: miniosecret
MINIO_ROOT_PASSWORD: miniosecret # CHANGEME
ports:
- "9090:9000"
- "9091:9001"
- 9090:9000
- 127.0.0.1:9091:9001
volumes:
- langfuse_minio_data:/data
healthcheck:
@@ -112,10 +127,11 @@ services:
redis:
image: redis:7
restart: always
# CHANGEME: row below to secure redis password
command: >
--requirepass ${REDIS_AUTH:-myredissecret}
ports:
- 6379:6379
- 127.0.0.1:6379:6379
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 3s
@@ -132,10 +148,10 @@ services:
retries: 10
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_PASSWORD: postgres # CHANGEME
POSTGRES_DB: postgres
ports:
- 5432:5432
- 127.0.0.1:5432:5432
volumes:
- langfuse_postgres_data:/var/lib/postgresql/data
View File
+2 -2
View File
@@ -26,9 +26,9 @@
"dependencies": {
"@langfuse/shared": "workspace:*",
"@opentelemetry/api": ">=1.0.0 <1.10.0",
"axios": "^1.7.7",
"axios": "^1.8.2",
"https-proxy-agent": "^7.0.6",
"next": "^14.2.21",
"next": "^14.2.26",
"next-auth": "^4.24.11",
"zod": "^3.23.8"
},
+2
View File
@@ -21,6 +21,7 @@ types:
docs: The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false)
observationId: optional<string>
comment: optional<string>
metadata: optional<unknown>
dataType:
type: optional<ScoreDataType>
docs: When set, must match the score value's type. If not set, will be inferred from the score value or config
@@ -76,6 +77,7 @@ types:
updatedAt: datetime
authorUserId: optional<string>
comment: optional<string>
metadata: optional<unknown>
configId:
type: optional<string>
docs: Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range
@@ -0,0 +1,32 @@
name: langfuse-organizations
docs: |
## General Notes
This admin API is only available on self-hosted instances, not on Langfuse Cloud.
An administrator must set the `ADMIN_API_KEY` environment variable to use this API.
## Authentication
Authenticate with the API by setting the Authorization header to `Bearer $ADMIN_API_KEY` where
`$ADMIN_API_KEY` is the API key set via the container environment.
## Exports
- OpenAPI spec: https://cloud.langfuse.com/generated/organizations-api/openapi.yml
- Postman collection: https://cloud.langfuse.com/generated/organizations-postman/collection.json
## Looking for the Langfuse API?
Are you looking for the full Langfuse API?
Check out our [API reference](https://api.reference.langfuse.com/#overview).
error-discrimination:
strategy: status-code
auth: bearer
imports:
commons: commons.yml
errors:
- commons.Error
- commons.UnauthorizedError
- commons.AccessDeniedError
- commons.MethodNotAllowedError
@@ -0,0 +1,13 @@
errors:
Error:
status-code: 400
type: string
UnauthorizedError:
status-code: 401
type: string
AccessDeniedError:
status-code: 403
type: string
MethodNotAllowedError:
status-code: 405
type: string
@@ -0,0 +1,170 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
imports:
commons: ./commons.yml
service:
auth: true
base-path: /api/admin
endpoints:
getAll:
docs: Get all organizations
method: GET
path: /organizations
response: Organizations
errors:
- commons.UnauthorizedError
- commons.MethodNotAllowedError
create:
docs: Create a new organization
method: POST
path: /organizations
request:
name: CreateOrganizationRequest
body:
properties:
name: string
metadata:
type: optional<map<string, unknown>>
docs: Optional metadata for the organization
response: Organization
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
getById:
docs: Get organization by ID
method: GET
path: /organizations/{organizationId}
path-parameters:
organizationId: string
response: Organization
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
update:
docs: Update an organization
method: PUT
path: /organizations/{organizationId}
path-parameters:
organizationId: string
request:
name: UpdateOrganizationRequest
body:
properties:
name: string
metadata:
type: optional<map<string, unknown>>
docs: Optional metadata for the organization
response: Organization
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
delete:
docs: Delete an organization
method: DELETE
path: /organizations/{organizationId}
path-parameters:
organizationId: string
response: DeleteOrganizationResponse
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
# API Key endpoints
getApiKeys:
docs: Get all API keys for an organization
method: GET
path: /organizations/{organizationId}/apiKeys
path-parameters:
organizationId: string
response: ApiKeyList
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
createApiKey:
docs: Create a new API key for an organization
method: POST
path: /organizations/{organizationId}/apiKeys
path-parameters:
organizationId: string
request:
name: CreateApiKeyRequest
body:
properties:
note:
type: optional<string>
docs: Optional note for the API key
response: ApiKeyResponse
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
deleteApiKey:
docs: Delete an API key for an organization
method: DELETE
path: /organizations/{organizationId}/apiKeys/{apiKeyId}
path-parameters:
organizationId: string
apiKeyId: string
response: DeleteOrganizationResponse
errors:
- commons.Error
- commons.UnauthorizedError
- commons.MethodNotAllowedError
types:
Organizations:
docs: List of organizations
properties:
organizations: list<Organization>
Organization:
docs: Organization object
properties:
id: string
name: string
createdAt: datetime
metadata:
type: map<string, unknown>
docs: Metadata for the organization
DeleteOrganizationResponse:
docs: Response for successful organization deletion
properties:
success: boolean
ApiKeyList:
docs: List of API keys for an organization
properties:
apiKeys: list<ApiKeySummary>
ApiKeySummary:
docs: Summary of an API key
properties:
id: string
createdAt: datetime
expiresAt: optional<datetime>
lastUsedAt: optional<datetime>
note: optional<string>
publicKey: string
displaySecretKey: string
ApiKeyResponse:
docs: Response for API key creation
properties:
id: string
createdAt: datetime
publicKey: string
secretKey: string
displaySecretKey: string
note: optional<string>
+17
View File
@@ -0,0 +1,17 @@
default-group: local
groups:
local:
generators:
- name: fernapi/fern-openapi
version: 0.1.7
output:
location: local-file-system
path: ../../../web/public/generated/organizations-api
config:
namespaceExport: Langfuse
allowCustomFetcher: true
- name: fernapi/fern-postman
version: 0.0.45
output:
location: local-file-system
path: ../../../web/public/generated/organizations-postman
@@ -0,0 +1,165 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
imports:
commons: ./commons.yml
pagination: ./utils/pagination.yml
service:
auth: true
base-path: /api/public
endpoints:
listQueues:
docs: Get all annotation queues
method: GET
path: /annotation-queues
request:
name: GetAnnotationQueuesRequest
query-parameters:
page:
type: optional<integer>
docs: page number, starts at 1
limit:
type: optional<integer>
docs: limit of items per page
response: PaginatedAnnotationQueues
getQueue:
docs: Get an annotation queue by ID
method: GET
path: /annotation-queues/{queueId}
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
response: AnnotationQueue
listQueueItems:
docs: Get items for a specific annotation queue
method: GET
path: /annotation-queues/{queueId}/items
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
request:
name: GetAnnotationQueueItemsRequest
query-parameters:
status:
type: optional<AnnotationQueueStatus>
docs: Filter by status
page:
type: optional<integer>
docs: page number, starts at 1
limit:
type: optional<integer>
docs: limit of items per page
response: PaginatedAnnotationQueueItems
getQueueItem:
docs: Get a specific item from an annotation queue
method: GET
path: /annotation-queues/{queueId}/items/{itemId}
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
itemId:
type: string
docs: The unique identifier of the annotation queue item
response: AnnotationQueueItem
createQueueItem:
docs: Add an item to an annotation queue
method: POST
path: /annotation-queues/{queueId}/items
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
request: CreateAnnotationQueueItemRequest
response: AnnotationQueueItem
updateQueueItem:
docs: Update an annotation queue item
method: PATCH
path: /annotation-queues/{queueId}/items/{itemId}
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
itemId:
type: string
docs: The unique identifier of the annotation queue item
request: UpdateAnnotationQueueItemRequest
response: AnnotationQueueItem
deleteQueueItem:
docs: Remove an item from an annotation queue
method: DELETE
path: /annotation-queues/{queueId}/items/{itemId}
path-parameters:
queueId:
type: string
docs: The unique identifier of the annotation queue
itemId:
type: string
docs: The unique identifier of the annotation queue item
response: DeleteAnnotationQueueItemResponse
types:
AnnotationQueueStatus:
enum:
- PENDING
- COMPLETED
AnnotationQueueObjectType:
enum:
- TRACE
- OBSERVATION
AnnotationQueue:
properties:
id: string
name: string
description: optional<string>
scoreConfigIds: list<string>
createdAt: datetime
updatedAt: datetime
AnnotationQueueItem:
properties:
id: string
queueId: string
objectId: string
objectType: AnnotationQueueObjectType
status: AnnotationQueueStatus
completedAt: optional<datetime>
createdAt: datetime
updatedAt: datetime
PaginatedAnnotationQueues:
properties:
data: list<AnnotationQueue>
meta: pagination.MetaResponse
PaginatedAnnotationQueueItems:
properties:
data: list<AnnotationQueueItem>
meta: pagination.MetaResponse
CreateAnnotationQueueItemRequest:
properties:
objectId: string
objectType: AnnotationQueueObjectType
status:
type: optional<AnnotationQueueStatus>
docs: Defaults to PENDING for new queue items
UpdateAnnotationQueueItemRequest:
properties:
status:
type: optional<AnnotationQueueStatus>
DeleteAnnotationQueueItemResponse:
properties:
success: boolean
message: string
+13
View File
@@ -38,6 +38,9 @@ types:
public:
type: optional<boolean>
docs: Public traces are accessible via url without login
environment:
type: optional<string>
docs: The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
TraceWithDetails: # GET /traces
extends: Trace
properties:
@@ -79,6 +82,9 @@ types:
id: string
createdAt: datetime
projectId: string
environment:
type: optional<string>
docs: The environment from which this session originated.
SessionWithTraces:
extends: Session
properties:
@@ -145,6 +151,9 @@ types:
costDetails:
type: optional<map<string, double>>
docs: The cost details of the observation. Key is the name of the cost metric, value is the cost in USD. The total key is the sum of all (non-total) cost metrics or the total value ingested.
environment:
type: optional<string>
docs: The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
ObservationsView:
extends: Observation
@@ -243,12 +252,16 @@ types:
updatedAt: datetime
authorUserId: optional<string>
comment: optional<string>
metadata: optional<unknown>
configId:
type: optional<string>
docs: Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range
queueId:
type: optional<string>
docs: Reference an annotation queue on a score. Populated if the score was initially created in an annotation queue.
environment:
type: optional<string>
docs: The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
NumericScore:
extends: BaseScore
properties:
@@ -37,8 +37,21 @@ service:
type: optional<integer>
docs: limit of items per page
response: PaginatedDatasetItems
delete:
docs: Delete a dataset item and all its run items. This action is irreversible.
method: DELETE
path: /dataset-items/{id}
path-parameters:
id:
type: string
response: DeleteDatasetItemResponse
types:
DeleteDatasetItemResponse:
properties:
message:
type: string
docs: Success message after deletion
CreateDatasetItemRequest:
properties:
datasetName: string
+11
View File
@@ -41,6 +41,14 @@ service:
datasetName: string
runName: string
response: commons.DatasetRunWithItems
deleteRun:
method: DELETE
docs: Delete a dataset run and all its run items. This action is irreversible.
path: /datasets/{datasetName}/runs/{runName}
path-parameters:
datasetName: string
runName: string
response: DeleteDatasetRunResponse
getRuns:
method: GET
docs: Get dataset runs
@@ -72,3 +80,6 @@ types:
properties:
data: list<commons.DatasetRun>
meta: pagination.MetaResponse
DeleteDatasetRunResponse:
properties:
message: string
+93 -5
View File
@@ -8,7 +8,15 @@ service:
endpoints:
batch:
docs: |
Batched ingestion for Langfuse Tracing. If you want to use tracing via the API, such as to build your own Langfuse client implementation, this is the only API route you need to implement.
Batched ingestion for Langfuse Tracing.
If you want to use tracing via the API, such as to build your own Langfuse client implementation, this is the only API route you need to implement.
Within each batch, there can be multiple events.
Each event has a type, an id, a timestamp, metadata and a body.
Internally, we refer to this as the "event envelope" as it tells us something about the event but not the trace.
We use the event id within this envelope to deduplicate messages to avoid processing the same event twice, i.e. the event id should be unique per request.
The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Langfuse App.
I.e. if you want to update a trace, you'd use the same body id, but separate event IDs.
Notes:
- Introduction to data model: https://langfuse.com/docs/tracing-data-model
@@ -29,6 +37,70 @@ service:
response:
type: IngestionResponse
status-code: 207
examples:
# Trace Create Request
- request:
batch:
- id: abcdef-1234-5678-90ab
timestamp: "2022-01-01T00:00:00.000Z"
type: "trace-create"
body:
id: abcdef-1234-5678-90ab
timestamp: "2022-01-01T00:00:00.000Z"
environment: "production"
name: "My Trace"
userId: "1234-5678-90ab-cdef"
input: "My input"
output: "My output"
sessionId: "1234-5678-90ab-cdef"
release: "1.0.0"
version: "1.0.0"
metadata: "My metadata"
tags: ["tag1", "tag2"]
public: true
response:
body:
successes:
- id: abcdef-1234-5678-90ab
status: 201
errors: []
# Observation Create Request
- request:
batch:
- id: abcdef-1234-5678-90ab
timestamp: "2022-01-01T00:00:00.000Z"
type: "span-create"
body:
id: abcdef-1234-5678-90ab
traceId: "1234-5678-90ab-cdef"
startTime: "2022-01-01T00:00:00.000Z"
environment: "test"
response:
body:
successes:
- id: abcdef-1234-5678-90ab
status: 201
errors: []
# Score Create Request
- request:
batch:
- id: abcdef-1234-5678-90ab
timestamp: "2022-01-01T00:00:00.000Z"
type: "score-create"
body:
id: abcdef-1234-5678-90ab
traceId: "1234-5678-90ab-cdef"
name: "My Score"
value: 0.9
environment: "default"
response:
body:
successes:
- id: abcdef-1234-5678-90ab
status: 201
errors: []
types:
IngestionEvent:
@@ -99,6 +171,7 @@ types:
statusMessage: optional<string>
parentObservationId: optional<string>
version: optional<string>
environment: optional<string>
CreateEventBody:
extends: OptionalObservationBody
@@ -163,6 +236,7 @@ types:
level: optional<commons.ObservationLevel>
statusMessage: optional<string>
parentObservationId: optional<string>
environment: optional<string>
TraceBody:
properties:
@@ -177,6 +251,7 @@ types:
version: optional<string>
metadata: optional<unknown>
tags: optional<list<string>>
environment: optional<string>
public:
type: optional<boolean>
docs: Make trace publicly accessible via url
@@ -190,11 +265,13 @@ types:
id: optional<string>
traceId: string
name: string
environment: optional<string>
value:
type: commons.CreateScoreValue
docs: The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false)
observationId: optional<string>
comment: optional<string>
metadata: optional<unknown>
dataType:
type: optional<commons.ScoreDataType>
docs: When set, must match the score value's type. If not set, will be inferred from the score value or config
@@ -318,16 +395,27 @@ types:
successes: list<IngestionSuccess>
errors: list<IngestionError>
OpenAIUsageSchema:
OpenAICompletionUsageSchema:
docs: OpenAI Usage schema from (Chat-)Completion APIs
properties:
prompt_tokens: integer
completion_tokens: integer
total_tokens: integer
prompt_tokens_details: optional<map<string, integer>>
completion_tokens_details: optional<map<string, integer>>
prompt_tokens_details: optional<map<string, optional<integer>>>
completion_tokens_details: optional<map<string, optional<integer>>>
OpenAIResponseUsageSchema:
docs: OpenAI Usage schema from Response API
properties:
input_tokens: integer
output_tokens: integer
total_tokens: integer
input_tokens_details: optional<map<string, optional<integer>>>
output_tokens_details: optional<map<string, optional<integer>>>
UsageDetails:
discriminated: false
union:
- map<string, integer>
- OpenAIUsageSchema
- OpenAICompletionUsageSchema
- OpenAIResponseUsageSchema
@@ -0,0 +1,62 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
imports:
commons: ./commons.yml
pagination: ./utils/pagination.yml
service:
auth: true
base-path: /api/public
endpoints:
getOrganizationMemberships:
docs: Get all memberships for the organization associated with the API key (requires organization-scoped API key)
method: GET
path: /organizations/memberships
response: MembershipsResponse
updateOrganizationMembership:
docs: Create or update a membership for the organization associated with the API key (requires organization-scoped API key)
method: PUT
path: /organizations/memberships
request: MembershipRequest
response: MembershipResponse
getProjectMemberships:
docs: Get all memberships for a specific project (requires organization-scoped API key)
method: GET
path: /projects/{projectId}/memberships
path-parameters:
projectId: string
response: MembershipsResponse
updateProjectMembership:
docs: Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization.
method: PUT
path: /projects/{projectId}/memberships
path-parameters:
projectId: string
request: MembershipRequest
response: MembershipResponse
types:
MembershipRole:
enum:
- OWNER
- ADMIN
- MEMBER
- VIEWER
MembershipRequest:
properties:
userId: string
role: MembershipRole
MembershipResponse:
properties:
userId: string
role: MembershipRole
email: string
name: string
MembershipsResponse:
properties:
memberships: list<MembershipResponse>
+4
View File
@@ -29,6 +29,10 @@ service:
type: optional<string>
allow-multiple: true
docs: Optional filter for metrics where traces include all of these tags
environment:
type: optional<string>
allow-multiple: true
docs: Optional filter for metrics where events include any of these environments
fromTimestamp:
type: optional<datetime>
docs: Optional filter to only include traces and observations on or after a certain datetime (ISO 8601)
@@ -33,6 +33,10 @@ service:
type: optional<string>
traceId: optional<string>
parentObservationId: optional<string>
environment:
type: optional<string>
allow-multiple: true
docs: Optional filter for observations where the environment is one of the provided values.
fromStartTime:
type: optional<datetime>
docs: Retrieve only observations with a start_time or or after this datetime (ISO 8601).
+121
View File
@@ -11,6 +11,85 @@ service:
method: GET
path: /projects
response: Projects
create:
docs: Create a new project (requires organization-scoped API key)
method: POST
path: /projects
request:
name: CreateProjectRequest
body:
properties:
name: string
metadata:
type: optional<map<string, unknown>>
docs: Optional metadata for the project
retention:
type: integer
docs: Number of days to retain data. Must be 0 or at least 7 days. Requires data-retention entitlement for non-zero values. Optional.
response: Project
update:
docs: Update a project by ID (requires organization-scoped API key).
method: PUT
path: /projects/{projectId}
path-parameters:
projectId: string
request:
name: UpdateProjectRequest
body:
properties:
name: string
metadata:
type: optional<map<string, unknown>>
docs: Optional metadata for the project
retention:
type: integer
docs: Number of days to retain data. Must be 0 or at least 7 days. Requires data-retention entitlement for non-zero values. Optional.
response: Project
delete:
docs: Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously.
method: DELETE
path: /projects/{projectId}
path-parameters:
projectId: string
response:
status-code: 202
type: ProjectDeletionResponse
# API Key endpoints
getApiKeys:
docs: Get all API keys for a project (requires organization-scoped API key)
method: GET
path: /projects/{projectId}/apiKeys
path-parameters:
projectId: string
response: ApiKeyList
createApiKey:
docs: Create a new API key for a project (requires organization-scoped API key)
method: POST
path: /projects/{projectId}/apiKeys
path-parameters:
projectId: string
request:
name: CreateApiKeyRequest
body:
properties:
note:
type: optional<string>
docs: Optional note for the API key
response: ApiKeyResponse
deleteApiKey:
docs: Delete an API key for a project (requires organization-scoped API key)
method: DELETE
path: /projects/{projectId}/apiKeys/{apiKeyId}
path-parameters:
projectId: string
apiKeyId: string
response: ApiKeyDeletionResponse
types:
Projects:
@@ -21,3 +100,45 @@ types:
properties:
id: string
name: string
metadata:
type: map<string, unknown>
docs: Metadata for the project
retentionDays:
type: integer
docs: Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured.
ProjectDeletionResponse:
properties:
success: boolean
message: string
ApiKeyList:
docs: List of API keys for a project
properties:
apiKeys: list<ApiKeySummary>
ApiKeySummary:
docs: Summary of an API key
properties:
id: string
createdAt: datetime
expiresAt: optional<datetime>
lastUsedAt: optional<datetime>
note: optional<string>
publicKey: string
displaySecretKey: string
ApiKeyResponse:
docs: Response for API key creation
properties:
id: string
createdAt: datetime
publicKey: string
secretKey: string
displaySecretKey: string
note: optional<string>
ApiKeyDeletionResponse:
docs: Response for API key deletion
properties:
success: boolean
+3
View File
@@ -128,6 +128,9 @@ types:
commitMessage:
type: optional<string>
docs: Commit message for this prompt version.
resolutionGraph:
type: optional<map<string, unknown>>
docs: The dependency resolution graph for the current prompt. Null if prompt has no dependencies.
ChatMessage:
properties:
+199
View File
@@ -0,0 +1,199 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
imports:
commons: ./commons.yml
service:
auth: true
base-path: /api/public/scim
endpoints:
getServiceProviderConfig:
docs: Get SCIM Service Provider Configuration (requires organization-scoped API key)
method: GET
path: /ServiceProviderConfig
response: ServiceProviderConfig
getResourceTypes:
docs: Get SCIM Resource Types (requires organization-scoped API key)
method: GET
path: /ResourceTypes
response: ResourceTypesResponse
getSchemas:
docs: Get SCIM Schemas (requires organization-scoped API key)
method: GET
path: /Schemas
response: SchemasResponse
listUsers:
docs: List users in the organization (requires organization-scoped API key)
method: GET
path: /Users
request:
name: ListUsersRequest
query-parameters:
filter:
docs: Filter expression (e.g. userName eq "value")
type: optional<string>
startIndex:
docs: 1-based index of the first result to return (default 1)
type: optional<integer>
count:
docs: Maximum number of results to return (default 100)
type: optional<integer>
response: ScimUsersListResponse
createUser:
docs: Create a new user in the organization (requires organization-scoped API key)
method: POST
path: /Users
request:
name: CreateUserRequest
body:
properties:
userName:
docs: User's email address (required)
type: string
name:
docs: User's name information
type: ScimName
emails:
docs: User's email addresses
type: optional<list<ScimEmail>>
active:
docs: Whether the user is active
type: optional<boolean>
password:
docs: Initial password for the user
type: optional<string>
response: ScimUser
getUser:
docs: Get a specific user by ID (requires organization-scoped API key)
method: GET
path: /Users/{userId}
path-parameters:
userId: string
response: ScimUser
deleteUser:
docs: Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself.
method: DELETE
path: /Users/{userId}
path-parameters:
userId: string
response: EmptyResponse
types:
ServiceProviderConfig:
properties:
schemas: list<string>
documentationUri: string
patch: ScimFeatureSupport
bulk: BulkConfig
filter: FilterConfig
changePassword: ScimFeatureSupport
sort: ScimFeatureSupport
etag: ScimFeatureSupport
authenticationSchemes: list<AuthenticationScheme>
meta: ResourceMeta
ScimFeatureSupport:
properties:
supported: boolean
BulkConfig:
properties:
supported: boolean
maxOperations: integer
maxPayloadSize: integer
FilterConfig:
properties:
supported: boolean
maxResults: integer
ResourceMeta:
properties:
resourceType: string
location: string
AuthenticationScheme:
properties:
name: string
description: string
specUri: string
type: string
primary: boolean
ResourceTypesResponse:
properties:
schemas: list<string>
totalResults: integer
Resources: list<ResourceType>
ResourceType:
properties:
schemas: optional<list<string>>
id: string
name: string
endpoint: string
description: string
schema: string
schemaExtensions: list<SchemaExtension>
meta: ResourceMeta
SchemaExtension:
properties:
schema: string
required: boolean
SchemasResponse:
properties:
schemas: list<string>
totalResults: integer
Resources: list<SchemaResource>
SchemaResource:
properties:
id: string
name: string
description: string
attributes: list<unknown>
meta: ResourceMeta
ScimUsersListResponse:
properties:
schemas: list<string>
totalResults: integer
startIndex: integer
itemsPerPage: integer
Resources: list<ScimUser>
ScimUser:
properties:
schemas: list<string>
id: string
userName: string
name: ScimName
emails: list<ScimEmail>
meta: UserMeta
UserMeta:
properties:
resourceType: string
created: optional<string>
lastModified: optional<string>
ScimName:
properties:
formatted: optional<string>
ScimEmail:
properties:
primary: boolean
value: string
type: string
EmptyResponse:
docs: Empty response for 204 No Content responses
properties: {}
+13
View File
@@ -37,6 +37,10 @@ service:
toTimestamp:
type: optional<datetime>
docs: Optional filter to only include scores created before a certain datetime (ISO 8601)
environment:
type: optional<string>
allow-multiple: true
docs: Optional filter for scores where the environment is one of the provided values.
source:
type: optional<commons.ScoreSource>
docs: Retrieve only scores from a specific source.
@@ -91,6 +95,10 @@ types:
docs: The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false)
observationId: optional<string>
comment: optional<string>
metadata: optional<unknown>
environment:
type: optional<string>
docs: The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
dataType:
type: optional<commons.ScoreDataType>
docs: The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric.
@@ -113,10 +121,12 @@ types:
dataType: "NUMERIC"
configId: "9203-4567-89ab-cdef"
traceId: "cdef-1234-5678-90ab"
environment: "test"
- value:
name: "toxicity"
value: "not toxic"
traceId: "cdef-1234-5678-90ab"
environment: "production"
- value:
name: "correctness"
value: "partially correct"
@@ -147,6 +157,9 @@ types:
tags:
type: optional<list<string>>
docs: A list of tags associated with the trace referenced by score
environment:
type: optional<string>
docs: The environment of the trace referenced by score
GetScoresResponseDataNumeric:
extends: commons.NumericScore
+4
View File
@@ -25,6 +25,10 @@ service:
toTimestamp:
type: optional<datetime>
docs: Optional filter to only include sessions created before a certain datetime (ISO 8601)
environment:
type: optional<string>
allow-multiple: true
docs: Optional filter for sessions where the environment is one of the provided values.
response: PaginatedSessions
get:
docs: Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=<sessionId>`
+28
View File
@@ -15,6 +15,15 @@ service:
type: string
docs: The unique langfuse identifier of a trace
response: commons.TraceWithFullDetails
delete:
docs: Delete a specific trace
method: DELETE
path: /traces/{traceId}
path-parameters:
traceId:
type: string
docs: The unique langfuse identifier of the trace to delete
response: DeleteTraceResponse
list:
docs: Get list of traces
method: GET
@@ -50,13 +59,32 @@ service:
release:
type: optional<string>
docs: Optional filter to only include traces with a certain release.
environment:
type: optional<string>
allow-multiple: true
docs: Optional filter for traces where the environment is one of the provided values.
response: Traces
deleteMultiple:
docs: Delete multiple traces
method: DELETE
path: /traces
request:
name: DeleteTracesRequest
body:
properties:
traceIds:
type: list<string>
docs: List of trace IDs to delete
response: DeleteTraceResponse
types:
Traces:
properties:
data: list<commons.TraceWithDetails>
meta: pagination.MetaResponse
DeleteTraceResponse:
properties:
message: string
Sort:
properties:
id: string
+7
View File
@@ -19,6 +19,13 @@ groups:
pydantic_config:
require_optional_fields: false
use_str_enums: false
# - name: fernapi/fern-java-sdk
# version: 2.20.1
# output:
# location: local-file-system
# path: ../../../../langfuse-java/src/main/java/com/langfuse/client/
# config:
# client-class-name: LangfuseClient
- name: fernapi/fern-postman
version: 0.0.45
output:
+1 -2
View File
@@ -1,5 +1,4 @@
{
"organization": "langfuse",
"version": "0.43.7"
"version": "0.56.0"
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "langfuse",
"version": "3.27.1",
"version": "3.52.0",
"author": "engineering@langfuse.com",
"license": "MIT",
"private": true,
@@ -29,12 +29,12 @@
"prepare": "husky"
},
"devDependencies": {
"@release-it/bumper": "^6.0.1",
"@release-it/bumper": "^7.0.1",
"braces": "3.0.3",
"dotenv-cli": "^7.4.2",
"husky": "^9.0.11",
"prettier": "^3.3.3",
"release-it": "^17.3.0",
"release-it": "^18.1.2",
"turbo": "^1.13.4"
},
"release-it": {
@@ -0,0 +1,3 @@
ALTER TABLE traces ON CLUSTER default DROP COLUMN IF EXISTS environment;
ALTER TABLE observations ON CLUSTER default DROP COLUMN IF EXISTS environment;
ALTER TABLE scores ON CLUSTER default DROP COLUMN IF EXISTS environment;
@@ -0,0 +1,3 @@
ALTER TABLE traces ON CLUSTER default ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
ALTER TABLE observations ON CLUSTER default ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
ALTER TABLE scores ON CLUSTER default ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
@@ -0,0 +1,7 @@
-- Drop materialized views
DROP VIEW IF EXISTS project_environments_traces_mv ON CLUSTER default;
DROP VIEW IF EXISTS project_environments_observations_mv ON CLUSTER default;
DROP VIEW IF EXISTS project_environments_scores_mv ON CLUSTER default;
-- Drop the project_environments table
DROP TABLE IF EXISTS project_environments ON CLUSTER default;
@@ -0,0 +1,30 @@
-- Create the project_environments table with AggregatingMergeTree engine
CREATE TABLE project_environments ON CLUSTER default (
`project_id` String,
`environments` SimpleAggregateFunction(groupUniqArrayArray, Array(String))
) ENGINE = ReplicatedAggregatingMergeTree
ORDER BY (project_id);
-- Create materialized view for traces
CREATE MATERIALIZED VIEW project_environments_traces_mv ON CLUSTER default TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM traces
GROUP BY project_id;
-- Create materialized view for observations
CREATE MATERIALIZED VIEW project_environments_observations_mv ON CLUSTER default TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM observations
GROUP BY project_id;
-- Create materialized view for scores
CREATE MATERIALIZED VIEW project_environments_scores_mv ON CLUSTER default TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM scores
GROUP BY project_id;
@@ -0,0 +1 @@
ALTER TABLE scores ON CLUSTER default DROP COLUMN IF EXISTS metadata;
@@ -0,0 +1 @@
ALTER TABLE scores ON CLUSTER default ADD COLUMN metadata Map(LowCardinality(String), String) AFTER comment;
@@ -0,0 +1,3 @@
ALTER TABLE traces DROP COLUMN IF EXISTS environment;
ALTER TABLE observations DROP COLUMN IF EXISTS environment;
ALTER TABLE scores DROP COLUMN IF EXISTS environment;
@@ -0,0 +1,3 @@
ALTER TABLE traces ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
ALTER TABLE observations ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
ALTER TABLE scores ADD COLUMN environment LowCardinality(String) DEFAULT 'default' AFTER project_id;
@@ -0,0 +1,7 @@
-- Drop materialized views
DROP VIEW IF EXISTS project_environments_traces_mv;
DROP VIEW IF EXISTS project_environments_observations_mv;
DROP VIEW IF EXISTS project_environments_scores_mv;
-- Drop the project_environments table
DROP TABLE IF EXISTS project_environments;
@@ -0,0 +1,30 @@
-- Create the project_environments table with AggregatingMergeTree engine
CREATE TABLE project_environments (
`project_id` String,
`environments` SimpleAggregateFunction(groupUniqArrayArray, Array(String))
) ENGINE = AggregatingMergeTree
ORDER BY (project_id);
-- Create materialized view for traces
CREATE MATERIALIZED VIEW project_environments_traces_mv TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM traces
GROUP BY project_id;
-- Create materialized view for observations
CREATE MATERIALIZED VIEW project_environments_observations_mv TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM observations
GROUP BY project_id;
-- Create materialized view for scores
CREATE MATERIALIZED VIEW project_environments_scores_mv TO project_environments AS
SELECT
project_id,
groupUniqArray(environment) AS environments
FROM scores
GROUP BY project_id;
@@ -0,0 +1 @@
ALTER TABLE scores DROP COLUMN IF EXISTS metadata;
@@ -0,0 +1 @@
ALTER TABLE scores ADD COLUMN metadata Map(LowCardinality(String), String) AFTER comment;
+1 -6
View File
@@ -1,9 +1,5 @@
import {
clickhouseClient,
ObservationRecordReadType,
} from "@langfuse/shared/src/server";
import { prisma } from "../../src/db";
import { redis } from "@langfuse/shared/src/server";
import { ObservationRecordReadType, redis } from "../../src/server";
import { prepareClickhouse } from "../../scripts/prepareClickhouse";
import { createDatasets } from "../../prisma/seed";
import { queryClickhouse } from "../../src/server/repositories/clickhouse";
@@ -65,7 +61,6 @@ async function main() {
} catch (error) {
console.error("Error during Clickhouse preparation:", error);
} finally {
await clickhouseClient().close();
await prisma.$disconnect();
redis?.disconnect();
console.log("Disconnected from Clickhouse.");
+6 -3
View File
@@ -33,7 +33,7 @@
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 110",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 65",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"db:migrate": "DISABLE_ERD=false dotenv -e ../../.env -- npx prisma migrate dev",
"db:push": "DISABLE_ERD=false dotenv -e ../../.env -- npx prisma db push",
@@ -47,7 +47,7 @@
"ch:down": "bash clickhouse/scripts/down.sh",
"ch:drop": "bash clickhouse/scripts/drop.sh",
"ch:reset": "pnpm run ch:down && pnpm run ch:up && pnpm run ch:seed",
"ch:seed": "dotenv -e ../../.env -- tsx clickhouse/scripts/seed.ts",
"ch:seed": "dotenv -e ../../.env -- ts-node -r tsconfig-paths/register -r dotenv/config --compiler-options '{\"module\":\"CommonJS\"}' clickhouse/scripts/seed.ts",
"load:setup": "dotenv -e ../../.env -- tsx scripts/load-seed.ts"
},
"prisma": {
@@ -61,9 +61,11 @@
"@aws-sdk/s3-request-presigner": "^3.679.0",
"@azure/storage-blob": "^12.26.0",
"@clickhouse/client": "^1.4.0",
"@google-cloud/storage": "^7.15.2",
"@langchain/anthropic": "^0.3.12",
"@langchain/aws": "^0.1.3",
"@langchain/core": "^0.3.37",
"@langchain/google-genai": "^0.1.9",
"@langchain/google-vertexai": "^0.1.8",
"@langchain/openai": "^0.3.17",
"@opentelemetry/api": ">=1.0.0 <1.10.0",
@@ -71,7 +73,7 @@
"@react-email/components": "^0.0.19",
"@react-email/render": "^0.0.15",
"@types/bcryptjs": "^2.4.6",
"axios": "^1.7.7",
"axios": "^1.8.2",
"bcryptjs": "^2.4.3",
"bullmq": "^5.34.10",
"dd-trace": "^5.36.0",
@@ -83,6 +85,7 @@
"langchain": "^0.3.15",
"langfuse-langchain": "3.30.3",
"lodash": "^4.17.21",
"lossless-json": "^4.0.2",
"next-auth": "^4.24.11",
"nodemailer": "^6.9.15",
"prisma-extension-kysely": "^2.1.0",
+211 -146
View File
@@ -4,6 +4,11 @@ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
: ColumnType<T, T | undefined, T>;
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
export const ApiKeyScope = {
ORGANIZATION: "ORGANIZATION",
PROJECT: "PROJECT"
} as const;
export type ApiKeyScope = (typeof ApiKeyScope)[keyof typeof ApiKeyScope];
export const Role = {
OWNER: "OWNER",
ADMIN: "ADMIN",
@@ -12,25 +17,25 @@ export const Role = {
NONE: "NONE"
} as const;
export type Role = (typeof Role)[keyof typeof Role];
export const ObservationType = {
export const LegacyPrismaObservationType = {
SPAN: "SPAN",
EVENT: "EVENT",
GENERATION: "GENERATION"
} as const;
export type ObservationType = (typeof ObservationType)[keyof typeof ObservationType];
export const ObservationLevel = {
export type LegacyPrismaObservationType = (typeof LegacyPrismaObservationType)[keyof typeof LegacyPrismaObservationType];
export const LegacyPrismaObservationLevel = {
DEBUG: "DEBUG",
DEFAULT: "DEFAULT",
WARNING: "WARNING",
ERROR: "ERROR"
} as const;
export type ObservationLevel = (typeof ObservationLevel)[keyof typeof ObservationLevel];
export const ScoreSource = {
export type LegacyPrismaObservationLevel = (typeof LegacyPrismaObservationLevel)[keyof typeof LegacyPrismaObservationLevel];
export const LegacyPrismaScoreSource = {
ANNOTATION: "ANNOTATION",
API: "API",
EVAL: "EVAL"
} as const;
export type ScoreSource = (typeof ScoreSource)[keyof typeof ScoreSource];
export type LegacyPrismaScoreSource = (typeof LegacyPrismaScoreSource)[keyof typeof LegacyPrismaScoreSource];
export const ScoreDataType = {
CATEGORICAL: "CATEGORICAL",
NUMERIC: "NUMERIC",
@@ -59,6 +64,11 @@ export const CommentObjectType = {
PROMPT: "PROMPT"
} as const;
export type CommentObjectType = (typeof CommentObjectType)[keyof typeof CommentObjectType];
export const AuditLogRecordType = {
USER: "USER",
API_KEY: "API_KEY"
} as const;
export type AuditLogRecordType = (typeof AuditLogRecordType)[keyof typeof AuditLogRecordType];
export const JobType = {
EVAL: "EVAL"
} as const;
@@ -75,6 +85,33 @@ export const JobExecutionStatus = {
CANCELLED: "CANCELLED"
} as const;
export type JobExecutionStatus = (typeof JobExecutionStatus)[keyof typeof JobExecutionStatus];
export const BlobStorageIntegrationFileType = {
JSON: "JSON",
CSV: "CSV",
JSONL: "JSONL"
} as const;
export type BlobStorageIntegrationFileType = (typeof BlobStorageIntegrationFileType)[keyof typeof BlobStorageIntegrationFileType];
export const BlobStorageIntegrationType = {
S3: "S3",
S3_COMPATIBLE: "S3_COMPATIBLE",
AZURE_BLOB_STORAGE: "AZURE_BLOB_STORAGE"
} as const;
export type BlobStorageIntegrationType = (typeof BlobStorageIntegrationType)[keyof typeof BlobStorageIntegrationType];
export const DashboardWidgetViews = {
TRACES: "TRACES",
OBSERVATIONS: "OBSERVATIONS",
SCORES_NUMERIC: "SCORES_NUMERIC",
SCORES_CATEGORICAL: "SCORES_CATEGORICAL"
} as const;
export type DashboardWidgetViews = (typeof DashboardWidgetViews)[keyof typeof DashboardWidgetViews];
export const DashboardWidgetChartType = {
LINE_TIME_SERIES: "LINE_TIME_SERIES",
BAR_TIME_SERIES: "BAR_TIME_SERIES",
HORIZONTAL_BAR: "HORIZONTAL_BAR",
VERTICAL_BAR: "VERTICAL_BAR",
PIE: "PIE"
} as const;
export type DashboardWidgetChartType = (typeof DashboardWidgetChartType)[keyof typeof DashboardWidgetChartType];
export type Account = {
id: string;
user_id: string;
@@ -126,15 +163,19 @@ export type ApiKey = {
display_secret_key: string;
last_used_at: Timestamp | null;
expires_at: Timestamp | null;
project_id: string;
project_id: string | null;
organization_id: string | null;
scope: Generated<ApiKeyScope>;
};
export type AuditLog = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
user_id: string;
type: Generated<AuditLogRecordType>;
api_key_id: string | null;
user_id: string | null;
org_id: string;
user_org_role: string;
user_org_role: string | null;
project_id: string | null;
user_project_role: string | null;
resource_type: string;
@@ -181,6 +222,24 @@ export type BillingMeterBackup = {
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
};
export type BlobStorageIntegration = {
project_id: string;
type: BlobStorageIntegrationType;
bucket_name: string;
prefix: string;
access_key_id: string;
secret_access_key: string;
region: string;
endpoint: string | null;
force_path_style: boolean;
next_sync_at: Timestamp | null;
last_sync_at: Timestamp | null;
enabled: boolean;
export_frequency: string;
file_type: Generated<BlobStorageIntegrationFileType>;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
};
export type Comment = {
id: string;
project_id: string;
@@ -197,6 +256,33 @@ export type CronJobs = {
job_started_at: Timestamp | null;
state: string | null;
};
export type Dashboard = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
created_by: string | null;
updated_by: string | null;
project_id: string | null;
name: string;
description: string;
definition: unknown;
};
export type DashboardWidget = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
created_by: string | null;
updated_by: string | null;
project_id: string | null;
name: string;
description: string;
view: DashboardWidgetViews;
dimensions: unknown;
metrics: unknown;
filters: unknown;
chart_type: DashboardWidgetChartType;
chart_config: unknown;
};
export type Dataset = {
id: string;
project_id: string;
@@ -267,6 +353,7 @@ export type JobConfiguration = {
variable_mapping: unknown;
sampling: string;
delay: number;
time_scope: Generated<string[]>;
};
export type JobExecution = {
id: string;
@@ -283,6 +370,77 @@ export type JobExecution = {
job_input_dataset_item_id: string | null;
job_output_score_id: string | null;
};
export type LegacyPrismaObservation = {
id: string;
trace_id: string | null;
project_id: string;
type: LegacyPrismaObservationType;
start_time: Generated<Timestamp>;
end_time: Timestamp | null;
name: string | null;
metadata: unknown | null;
parent_observation_id: string | null;
level: Generated<LegacyPrismaObservationLevel>;
status_message: string | null;
version: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
model: string | null;
internal_model: string | null;
internal_model_id: string | null;
modelParameters: unknown | null;
input: unknown | null;
output: unknown | null;
prompt_tokens: Generated<number>;
completion_tokens: Generated<number>;
total_tokens: Generated<number>;
unit: string | null;
input_cost: string | null;
output_cost: string | null;
total_cost: string | null;
calculated_input_cost: string | null;
calculated_output_cost: string | null;
calculated_total_cost: string | null;
completion_start_time: Timestamp | null;
prompt_id: string | null;
};
export type LegacyPrismaScore = {
id: string;
timestamp: Generated<Timestamp>;
project_id: string;
name: string;
value: number | null;
source: LegacyPrismaScoreSource;
author_user_id: string | null;
comment: string | null;
trace_id: string;
observation_id: string | null;
config_id: string | null;
string_value: string | null;
queue_id: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
data_type: Generated<ScoreDataType>;
};
export type LegacyPrismaTrace = {
id: string;
external_id: string | null;
timestamp: Generated<Timestamp>;
name: string | null;
user_id: string | null;
metadata: unknown | null;
release: string | null;
version: string | null;
project_id: string;
public: Generated<boolean>;
bookmarked: Generated<boolean>;
tags: Generated<string[]>;
input: unknown | null;
output: unknown | null;
session_id: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
};
export type LlmApiKeys = {
id: string;
created_at: Generated<Timestamp>;
@@ -299,6 +457,24 @@ export type LlmApiKeys = {
config: unknown | null;
project_id: string;
};
export type LlmSchema = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
project_id: string;
name: string;
description: string;
schema: unknown;
};
export type LlmTool = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
project_id: string;
name: string;
description: string;
parameters: unknown;
};
export type Media = {
id: string;
sha_256_hash: string;
@@ -339,40 +515,6 @@ export type Model = {
tokenizer_id: string | null;
tokenizer_config: unknown | null;
};
export type Observation = {
id: string;
trace_id: string | null;
project_id: string;
type: ObservationType;
start_time: Generated<Timestamp>;
end_time: Timestamp | null;
name: string | null;
metadata: unknown | null;
parent_observation_id: string | null;
level: Generated<ObservationLevel>;
status_message: string | null;
version: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
model: string | null;
internal_model: string | null;
internal_model_id: string | null;
modelParameters: unknown | null;
input: unknown | null;
output: unknown | null;
prompt_tokens: Generated<number>;
completion_tokens: Generated<number>;
total_tokens: Generated<number>;
unit: string | null;
input_cost: string | null;
output_cost: string | null;
total_cost: string | null;
calculated_input_cost: string | null;
calculated_output_cost: string | null;
calculated_total_cost: string | null;
completion_start_time: Timestamp | null;
prompt_id: string | null;
};
export type ObservationMedia = {
id: string;
project_id: string;
@@ -383,49 +525,13 @@ export type ObservationMedia = {
observation_id: string;
field: string;
};
export type ObservationView = {
id: string;
trace_id: string | null;
project_id: string;
type: ObservationType;
start_time: Timestamp;
end_time: Timestamp | null;
name: string | null;
metadata: unknown | null;
parent_observation_id: string | null;
level: Generated<ObservationLevel>;
status_message: string | null;
version: string | null;
created_at: Timestamp;
updated_at: Timestamp;
model: string | null;
modelParameters: unknown | null;
input: unknown | null;
output: unknown | null;
prompt_tokens: Generated<number>;
completion_tokens: Generated<number>;
total_tokens: Generated<number>;
unit: string | null;
completion_start_time: Timestamp | null;
prompt_id: string | null;
prompt_name: string | null;
prompt_version: number | null;
model_id: string | null;
input_price: string | null;
output_price: string | null;
total_price: string | null;
calculated_input_cost: string | null;
calculated_output_cost: string | null;
calculated_total_cost: string | null;
latency: number | null;
time_to_first_token: number | null;
};
export type Organization = {
id: string;
name: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
cloud_config: unknown | null;
metadata: unknown | null;
};
export type OrganizationMembership = {
id: string;
@@ -459,6 +565,7 @@ export type Project = {
deleted_at: Timestamp | null;
name: string;
retention_days: number | null;
metadata: unknown | null;
};
export type ProjectMembership = {
org_membership_id: string;
@@ -484,30 +591,22 @@ export type Prompt = {
labels: Generated<string[]>;
commit_message: string | null;
};
export type QueueBackUp = {
export type PromptDependency = {
id: string;
project_id: string | null;
queue_name: string;
content: unknown;
created_at: Generated<Timestamp>;
};
export type Score = {
id: string;
timestamp: Generated<Timestamp>;
project_id: string;
name: string;
value: number | null;
source: ScoreSource;
author_user_id: string | null;
comment: string | null;
trace_id: string;
observation_id: string | null;
config_id: string | null;
string_value: string | null;
queue_id: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
data_type: Generated<ScoreDataType>;
project_id: string;
parent_id: string;
child_name: string;
child_label: string | null;
child_version: number | null;
};
export type PromptProtectedLabels = {
id: string;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
project_id: string;
label: string;
};
export type ScoreConfig = {
id: string;
@@ -535,25 +634,6 @@ export type SsoConfig = {
auth_provider: string;
auth_config: unknown | null;
};
export type Trace = {
id: string;
external_id: string | null;
timestamp: Generated<Timestamp>;
name: string | null;
user_id: string | null;
metadata: unknown | null;
release: string | null;
version: string | null;
project_id: string;
public: Generated<boolean>;
bookmarked: Generated<boolean>;
tags: Generated<string[]>;
input: unknown | null;
output: unknown | null;
session_id: string | null;
created_at: Generated<Timestamp>;
updated_at: Generated<Timestamp>;
};
export type TraceMedia = {
id: string;
project_id: string;
@@ -570,26 +650,7 @@ export type TraceSession = {
project_id: string;
bookmarked: Generated<boolean>;
public: Generated<boolean>;
};
export type TraceView = {
id: string;
external_id: string | null;
timestamp: Generated<Timestamp>;
name: string | null;
user_id: string | null;
metadata: unknown | null;
release: string | null;
version: string | null;
project_id: string;
public: Generated<boolean>;
bookmarked: Generated<boolean>;
tags: Generated<string[]>;
input: unknown | null;
output: unknown | null;
session_id: string | null;
created_at: Timestamp;
updated_at: Timestamp;
duration: number | null;
environment: Generated<string>;
};
export type User = {
id: string;
@@ -617,8 +678,11 @@ export type DB = {
background_migrations: BackgroundMigration;
batch_exports: BatchExport;
billing_meter_backups: BillingMeterBackup;
blob_storage_integrations: BlobStorageIntegration;
comments: Comment;
cron_jobs: CronJobs;
dashboard_widgets: DashboardWidget;
dashboards: Dashboard;
dataset_items: DatasetItem;
dataset_run_items: DatasetRunItems;
dataset_runs: DatasetRuns;
@@ -627,28 +691,29 @@ export type DB = {
job_configurations: JobConfiguration;
job_executions: JobExecution;
llm_api_keys: LlmApiKeys;
llm_schemas: LlmSchema;
llm_tools: LlmTool;
media: Media;
membership_invitations: MembershipInvitation;
models: Model;
observation_media: ObservationMedia;
observations: Observation;
observations_view: ObservationView;
observations: LegacyPrismaObservation;
organization_memberships: OrganizationMembership;
organizations: Organization;
posthog_integrations: PosthogIntegration;
prices: Price;
project_memberships: ProjectMembership;
projects: Project;
prompt_dependencies: PromptDependency;
prompt_protected_labels: PromptProtectedLabels;
prompts: Prompt;
queue_backups: QueueBackUp;
score_configs: ScoreConfig;
scores: Score;
scores: LegacyPrismaScore;
Session: Session;
sso_configs: SsoConfig;
trace_media: TraceMedia;
trace_sessions: TraceSession;
traces: Trace;
traces_view: TraceView;
traces: LegacyPrismaTrace;
users: User;
verification_tokens: VerificationToken;
};
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "job_configurations" ADD COLUMN "time_scope" TEXT[] DEFAULT ARRAY['NEW']::TEXT[];
@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "trace_sessions"
ADD COLUMN "environment" TEXT NOT NULL DEFAULT 'default';
@@ -0,0 +1,2 @@
DROP VIEW IF EXISTS "observations_view";
DROP VIEW IF EXISTS "traces_view";
@@ -0,0 +1,18 @@
CREATE TABLE "prompt_dependencies" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"project_id" TEXT NOT NULL,
"parent_id" TEXT NOT NULL,
"child_name" TEXT NOT NULL,
"child_label" TEXT,
"child_version" INTEGER,
CONSTRAINT "prompt_dependencies_pkey" PRIMARY KEY ("id")
);
ALTER TABLE "prompt_dependencies" ADD CONSTRAINT "prompt_dependencies_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "prompt_dependencies" ADD CONSTRAINT "prompt_dependencies_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "prompts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
CREATE INDEX "prompt_dependencies_project_id_parent_id" ON "prompt_dependencies"("project_id", "parent_id");
CREATE INDEX "prompt_dependencies_project_id_child_name" ON "prompt_dependencies"("project_id", "child_name");
@@ -0,0 +1,11 @@
-- CreateEnum
CREATE TYPE "AuditLogRecordType" AS ENUM ('USER', 'API_KEY');
-- AlterTable
ALTER TABLE "audit_logs" ADD COLUMN "api_key_id" TEXT,
ADD COLUMN "type" "AuditLogRecordType" NOT NULL DEFAULT 'USER',
ALTER COLUMN "user_id" DROP NOT NULL,
ALTER COLUMN "user_org_role" DROP NOT NULL;
-- CreateIndex
CREATE INDEX "audit_logs_api_key_id_idx" ON "audit_logs"("api_key_id");
@@ -0,0 +1,2 @@
-- DropTable
DROP TABLE "queue_backups";
@@ -0,0 +1,26 @@
-- CreateEnum
CREATE TYPE "BlobStorageIntegrationType" AS ENUM ('S3', 'S3_COMPATIBLE', 'AZURE_BLOB_STORAGE');
-- CreateTable
CREATE TABLE "blob_storage_integrations" (
"project_id" TEXT NOT NULL,
"type" "BlobStorageIntegrationType" NOT NULL,
"bucket_name" TEXT NOT NULL,
"prefix" TEXT NOT NULL,
"access_key_id" TEXT NOT NULL,
"secret_access_key" TEXT NOT NULL,
"region" TEXT NOT NULL,
"endpoint" TEXT,
"force_path_style" BOOLEAN NOT NULL,
"next_sync_at" TIMESTAMP(3),
"last_sync_at" TIMESTAMP(3),
"enabled" BOOLEAN NOT NULL,
"export_frequency" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "blob_storage_integrations_pkey" PRIMARY KEY ("project_id")
);
-- AddForeignKey
ALTER TABLE "blob_storage_integrations" ADD CONSTRAINT "blob_storage_integrations_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,37 @@
-- CreateTable
CREATE TABLE "llm_schemas" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"project_id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"schema" JSON NOT NULL,
CONSTRAINT "llm_schemas_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "llm_tools" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"project_id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"parameters" JSON NOT NULL,
CONSTRAINT "llm_tools_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "llm_schemas_project_id_name_key" ON "llm_schemas"("project_id", "name");
-- CreateIndex
CREATE UNIQUE INDEX "llm_tools_project_id_name_key" ON "llm_tools"("project_id", "name");
-- AddForeignKey
ALTER TABLE "llm_schemas" ADD CONSTRAINT "llm_schemas_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "llm_tools" ADD CONSTRAINT "llm_tools_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,16 @@
-- CreateTable
CREATE TABLE "prompt_protected_labels" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"project_id" TEXT NOT NULL,
"label" TEXT NOT NULL,
CONSTRAINT "prompt_protected_labels_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "prompt_protected_labels_project_id_label_key" ON "prompt_protected_labels"("project_id", "label");
-- AddForeignKey
ALTER TABLE "prompt_protected_labels" ADD CONSTRAINT "prompt_protected_labels_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
-- CreateEnum
CREATE TYPE "BlobStorageIntegrationFileType" AS ENUM ('JSON', 'CSV', 'JSONL');
-- AlterTable
ALTER TABLE "blob_storage_integrations" ADD COLUMN "file_type" "BlobStorageIntegrationFileType" NOT NULL DEFAULT 'CSV';
@@ -0,0 +1,17 @@
-- Delete duplicate membership invitations, keeping only the newest one for each email and org_id combination
WITH ranked_invitations AS (
SELECT
id,
email,
org_id,
ROW_NUMBER() OVER (PARTITION BY email, org_id ORDER BY updated_at DESC) as rn
FROM membership_invitations
)
DELETE FROM membership_invitations
WHERE id IN (
SELECT id FROM ranked_invitations WHERE rn > 1
);
-- CreateIndex
CREATE UNIQUE INDEX "membership_invitations_email_org_id_key" ON "membership_invitations"("email", "org_id");
@@ -0,0 +1,58 @@
-- CreateEnum
CREATE TYPE "DashboardWidgetViews" AS ENUM ('TRACES', 'OBSERVATIONS', 'SCORES_NUMERIC', 'SCORES_CATEGORICAL');
-- CreateEnum
CREATE TYPE "DashboardWidgetChartType" AS ENUM ('LINE_TIME_SERIES', 'BAR_TIME_SERIES', 'HORIZONTAL_BAR', 'VERTICAL_BAR', 'PIE');
-- CreateTable
CREATE TABLE "dashboards" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT,
"updated_by" TEXT,
"project_id" TEXT,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"definition" JSONB NOT NULL,
CONSTRAINT "dashboards_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "dashboard_widgets" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT,
"updated_by" TEXT,
"project_id" TEXT,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"view" "DashboardWidgetViews" NOT NULL,
"dimensions" JSONB NOT NULL,
"metrics" JSONB NOT NULL,
"filters" JSONB NOT NULL,
"chart_type" "DashboardWidgetChartType" NOT NULL,
"chart_config" JSONB NOT NULL,
CONSTRAINT "dashboard_widgets_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "dashboards" ADD CONSTRAINT "dashboards_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "dashboards" ADD CONSTRAINT "dashboards_updated_by_fkey" FOREIGN KEY ("updated_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "dashboards" ADD CONSTRAINT "dashboards_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "dashboard_widgets" ADD CONSTRAINT "dashboard_widgets_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "dashboard_widgets" ADD CONSTRAINT "dashboard_widgets_updated_by_fkey" FOREIGN KEY ("updated_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "dashboard_widgets" ADD CONSTRAINT "dashboard_widgets_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,13 @@
-- CreateEnum
CREATE TYPE "ApiKeyScope" AS ENUM ('ORGANIZATION', 'PROJECT');
-- AlterTable
ALTER TABLE "api_keys" ADD COLUMN "organization_id" TEXT,
ADD COLUMN "scope" "ApiKeyScope" NOT NULL DEFAULT 'PROJECT',
ALTER COLUMN "project_id" DROP NOT NULL;
-- CreateIndex
CREATE INDEX "api_keys_organization_id_idx" ON "api_keys"("organization_id");
-- AddForeignKey
ALTER TABLE "api_keys" ADD CONSTRAINT "api_keys_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "organizations" ADD COLUMN "metadata" JSONB;
-- AlterTable
ALTER TABLE "projects" ADD COLUMN "metadata" JSONB;
@@ -1,3 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
+350 -237
View File
@@ -3,7 +3,7 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["tracing", "views", "relationJoins", "metrics"]
previewFeatures = ["views", "relationJoins", "metrics"]
}
datasource db {
@@ -82,6 +82,10 @@ model User {
featureFlags String[] @default([]) @map("feature_flags")
annotatedLockedItem AnnotationQueueItem[] @relation("LockedByUser")
annotatedCompletedItem AnnotationQueueItem[] @relation("AnnotatorUser")
dashboardWidgetsCreated DashboardWidget[] @relation("CreatedByUser")
dashboardWidgetsUpdated DashboardWidget[] @relation("UpdatedByUser")
dashboardCreated Dashboard[] @relation("CreatedByUser")
dashboardUpdated Dashboard[] @relation("UpdatedByUser")
@@map("users")
}
@@ -101,63 +105,82 @@ model Organization {
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
cloudConfig Json? @map("cloud_config") // Langfuse Cloud, for zod schema see @/src/features/organizations/utils/cloudConfigSchema
metadata Json?
organizationMemberships OrganizationMembership[]
projects Project[]
MembershipInvitation MembershipInvitation[]
ApiKey ApiKey[]
@@map("organizations")
}
model Project {
id String @id @default(cuid())
orgId String @map("org_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
name String
retentionDays Int? @map("retention_days")
projectMembers ProjectMembership[]
organization Organization @relation(fields: [orgId], references: [id], onUpdate: Cascade, onDelete: Cascade)
traces Trace[]
observations Observation[]
apiKeys ApiKey[]
dataset Dataset[]
invitations MembershipInvitation[]
sessions TraceSession[]
Prompt Prompt[]
Model Model[]
EvalTemplate EvalTemplate[]
JobConfiguration JobConfiguration[]
JobExecution JobExecution[]
LlmApiKeys LlmApiKeys[]
PosthogIntegration PosthogIntegration[]
Score Score[]
scoreConfig ScoreConfig[]
BatchExport BatchExport[]
comment Comment[]
annotationQueue AnnotationQueue[]
annotationQueueItem AnnotationQueueItem[]
TraceMedia TraceMedia[]
Media Media[]
ObservationMedia ObservationMedia[]
id String @id @default(cuid())
orgId String @map("org_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
name String
retentionDays Int? @map("retention_days")
metadata Json?
projectMembers ProjectMembership[]
organization Organization @relation(fields: [orgId], references: [id], onUpdate: Cascade, onDelete: Cascade)
apiKeys ApiKey[]
dataset Dataset[]
invitations MembershipInvitation[]
sessions TraceSession[]
Prompt Prompt[]
Model Model[]
EvalTemplate EvalTemplate[]
JobConfiguration JobConfiguration[]
JobExecution JobExecution[]
LlmApiKeys LlmApiKeys[]
PosthogIntegration PosthogIntegration[]
BlobStorageIntegration BlobStorageIntegration[]
scoreConfig ScoreConfig[]
BatchExport BatchExport[]
comment Comment[]
annotationQueue AnnotationQueue[]
annotationQueueItem AnnotationQueueItem[]
TraceMedia TraceMedia[]
Media Media[]
ObservationMedia ObservationMedia[]
LegacyTrace LegacyPrismaTrace[]
LegacyObservation LegacyPrismaObservation[]
LegacyScore LegacyPrismaScore[]
PromptDependency PromptDependency[]
LlmSchema LlmSchema[]
LlmTool LlmTool[]
PromptProtectedLabels PromptProtectedLabels[]
Dashboard Dashboard[]
DashboardWidget DashboardWidget[]
@@index([orgId])
@@map("projects")
}
model ApiKey {
id String @id @unique @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
note String?
publicKey String @unique @map("public_key")
hashedSecretKey String @unique @map("hashed_secret_key")
fastHashedSecretKey String? @unique @map("fast_hashed_secret_key")
displaySecretKey String @map("display_secret_key")
lastUsedAt DateTime? @map("last_used_at")
expiresAt DateTime? @map("expires_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
enum ApiKeyScope {
ORGANIZATION
PROJECT
}
model ApiKey {
id String @id @unique @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
note String?
publicKey String @unique @map("public_key")
hashedSecretKey String @unique @map("hashed_secret_key")
fastHashedSecretKey String? @unique @map("fast_hashed_secret_key")
displaySecretKey String @map("display_secret_key")
lastUsedAt DateTime? @map("last_used_at")
expiresAt DateTime? @map("expires_at")
projectId String? @map("project_id")
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
orgId String? @map("organization_id")
organization Organization? @relation(fields: [orgId], references: [id], onDelete: Cascade)
scope ApiKeyScope @default(PROJECT) @map("scope")
@@index(orgId)
@@index(projectId)
@@index(publicKey)
@@index(hashedSecretKey)
@@ -252,6 +275,7 @@ model MembershipInvitation {
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
@@unique([email, orgId]) // do not include projectId as this leads to issues when processing the invites, needs new logic
@@index([projectId])
@@index([orgId])
@@index([email])
@@ -267,13 +291,14 @@ enum Role {
}
model TraceSession {
id String @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
bookmarked Boolean @default(false)
public Boolean @default(false)
id String @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
bookmarked Boolean @default(false)
public Boolean @default(false)
environment String @default("default")
@@id([id, projectId])
@@index([projectId])
@@ -282,9 +307,7 @@ model TraceSession {
@@map("trace_sessions")
}
// Update TraceView below when making changes to this model!
model Trace {
model LegacyPrismaTrace {
id String @id @default(cuid())
externalId String? @map("external_id")
timestamp DateTime @default(now())
@@ -315,80 +338,43 @@ model Trace {
@@map("traces")
}
// This view is based on the trace table. Once prisma supports
// inheritance, we should remove code duplication here.
view TraceView {
// trace fields
id String @id @default(cuid())
externalId String? @map("external_id")
timestamp DateTime @default(now())
name String?
userId String? @map("user_id")
metadata Json?
release String?
version String?
projectId String @map("project_id")
public Boolean @default(false)
bookmarked Boolean @default(false)
tags String[] @default([])
input Json?
output Json?
sessionId String? @map("session_id")
createdAt DateTime @map("created_at")
updatedAt DateTime @map("updated_at")
// calculated fields
duration Float? @map("duration") // can be null if no observations in trace
@@map("traces_view")
}
// Update ObservationView below when making changes to this model!
// traceId is optional only due to timing during data injestion
// (traceId is not necessarily known at the time of observation creation)
model Observation {
id String @id @default(cuid())
traceId String? @map("trace_id")
projectId String @map("project_id")
type ObservationType
startTime DateTime @default(now()) @map("start_time")
endTime DateTime? @map("end_time")
name String?
metadata Json?
parentObservationId String? @map("parent_observation_id")
level ObservationLevel @default(DEFAULT)
statusMessage String? @map("status_message")
version String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
model LegacyPrismaObservation {
id String @id @default(cuid())
traceId String? @map("trace_id")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
type LegacyPrismaObservationType
startTime DateTime @default(now()) @map("start_time")
endTime DateTime? @map("end_time")
name String?
metadata Json?
parentObservationId String? @map("parent_observation_id")
level LegacyPrismaObservationLevel @default(DEFAULT)
statusMessage String? @map("status_message")
version String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
// GENERATION ONLY
model String? // user-provided model attribute
internalModel String? @map("internal_model") // matched model.name that is matched at ingestion time, to be deprecated
internalModelId String? @map("internal_model_id") // matched model.id that is matched at ingestion time
modelParameters Json?
input Json?
output Json?
promptTokens Int @default(0) @map("prompt_tokens")
completionTokens Int @default(0) @map("completion_tokens")
totalTokens Int @default(0) @map("total_tokens")
unit String?
model String? // user-provided model attribute
internalModel String? @map("internal_model") // matched model.name that is matched at ingestion time, to be deprecated
internalModelId String? @map("internal_model_id") // matched model.id that is matched at ingestion time
modelParameters Json?
input Json?
output Json?
promptTokens Int @default(0) @map("prompt_tokens")
completionTokens Int @default(0) @map("completion_tokens")
totalTokens Int @default(0) @map("total_tokens")
unit String?
// User provided cost at ingestion
inputCost Decimal? @map("input_cost")
outputCost Decimal? @map("output_cost")
totalCost Decimal? @map("total_cost")
inputCost Decimal? @map("input_cost")
outputCost Decimal? @map("output_cost")
totalCost Decimal? @map("total_cost")
// Calculated cost
calculatedInputCost Decimal? @map("calculated_input_cost")
calculatedOutputCost Decimal? @map("calculated_output_cost")
calculatedTotalCost Decimal? @map("calculated_total_cost")
completionStartTime DateTime? @map("completion_start_time")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
promptId String? @map("prompt_id") // no fk constraint, prompt can be deleted
calculatedInputCost Decimal? @map("calculated_input_cost")
calculatedOutputCost Decimal? @map("calculated_output_cost")
calculatedTotalCost Decimal? @map("calculated_total_cost")
completionStartTime DateTime? @map("completion_start_time")
promptId String? @map("prompt_id") // no fk constraint, prompt can be deleted
@@unique([id, projectId])
@@index([projectId, internalModel, startTime, unit])
@@ -405,88 +391,42 @@ model Observation {
@@map("observations")
}
// This view is a mix of the observation and model. Once prisma supports
// inheritance, we should remove code duplication here.
view ObservationView {
id String @id @default(cuid())
traceId String? @map("trace_id")
projectId String @map("project_id")
type ObservationType
startTime DateTime @map("start_time")
endTime DateTime? @map("end_time")
name String?
metadata Json?
parentObservationId String? @map("parent_observation_id")
level ObservationLevel @default(DEFAULT)
statusMessage String? @map("status_message")
version String?
createdAt DateTime @map("created_at")
updatedAt DateTime @map("updated_at")
// GENERATION ONLY
model String?
modelParameters Json?
input Json?
output Json?
promptTokens Int @default(0) @map("prompt_tokens")
completionTokens Int @default(0) @map("completion_tokens")
totalTokens Int @default(0) @map("total_tokens")
unit String?
completionStartTime DateTime? @map("completion_start_time")
// prompts
promptId String? @map("prompt_id")
promptName String? @map("prompt_name")
promptVersion Int? @map("prompt_version")
// model fields
modelId String? @map("model_id")
inputPrice Decimal? @map("input_price")
outputPrice Decimal? @map("output_price")
totalPrice Decimal? @map("total_price")
// calculated fields
calculatedInputCost Decimal? @map("calculated_input_cost")
calculatedOutputCost Decimal? @map("calculated_output_cost")
calculatedTotalCost Decimal? @map("calculated_total_cost")
latency Float? @map("latency")
timeToFirstToken Float? @map("time_to_first_token")
@@map("observations_view")
}
enum ObservationType {
enum LegacyPrismaObservationType {
SPAN
EVENT
GENERATION
@@map("ObservationType")
}
enum ObservationLevel {
enum LegacyPrismaObservationLevel {
DEBUG
DEFAULT
WARNING
ERROR
@@map("ObservationLevel")
}
model Score {
id String @id @default(cuid())
timestamp DateTime @default(now())
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
model LegacyPrismaScore {
id String @id @default(cuid())
timestamp DateTime @default(now())
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String
value Float? // always defined if data type is NUMERIC or BOOLEAN, optional for CATEGORICAL
source ScoreSource
authorUserId String? @map("author_user_id")
source LegacyPrismaScoreSource
authorUserId String? @map("author_user_id")
comment String?
traceId String @map("trace_id")
observationId String? @map("observation_id")
configId String? @map("config_id")
stringValue String? @map("string_value") // always defined if data type is CATEGORICAL or BOOLEAN, null for NUMERIC
queueId String? @map("queue_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
dataType ScoreDataType @default(NUMERIC) @map("data_type")
scoreConfig ScoreConfig? @relation(fields: [configId], references: [id], onDelete: SetNull)
traceId String @map("trace_id")
observationId String? @map("observation_id")
configId String? @map("config_id")
stringValue String? @map("string_value") // always defined if data type is CATEGORICAL or BOOLEAN, null for NUMERIC
queueId String? @map("queue_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
dataType ScoreDataType @default(NUMERIC) @map("data_type")
scoreConfig ScoreConfig? @relation(fields: [configId], references: [id], onDelete: SetNull)
@@unique([id, projectId]) // used for upserts via prisma
@@index(timestamp)
@@ -501,26 +441,28 @@ model Score {
@@map("scores")
}
enum ScoreSource {
enum LegacyPrismaScoreSource {
ANNOTATION
API
EVAL
@@map("ScoreSource")
}
model ScoreConfig {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String
dataType ScoreDataType @map("data_type")
isArchived Boolean @default(false) @map("is_archived")
minValue Float? @map("min_value")
maxValue Float? @map("max_value")
categories Json? @map("categories")
dataType ScoreDataType @map("data_type")
isArchived Boolean @default(false) @map("is_archived")
minValue Float? @map("min_value")
maxValue Float? @map("max_value")
categories Json? @map("categories")
description String?
score Score[]
legacyScore LegacyPrismaScore[]
@@unique([id, projectId]) // used for upserts via prisma
@@index([dataType])
@@ -722,15 +664,16 @@ model Prompt {
createdBy String @map("created_by")
prompt Json
name String
version Int
type String @default("text")
isActive Boolean? @map("is_active") // Deprecated. To be removed once 'production' labels work as expected.
config Json @default("{}") @db.Json
tags String[] @default([])
labels String[] @default([])
commitMessage String? @map("commit_message")
prompt Json
name String
version Int
type String @default("text")
isActive Boolean? @map("is_active") // Deprecated. To be removed once 'production' labels work as expected.
config Json @default("{}") @db.Json
tags String[] @default([])
labels String[] @default([])
commitMessage String? @map("commit_message")
PromptDependency PromptDependency[]
@@unique([projectId, name, version])
@@index([projectId, id])
@@ -740,6 +683,38 @@ model Prompt {
@@map("prompts")
}
model PromptDependency {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
parentId String @map("parent_id")
parent Prompt @relation(fields: [parentId], references: [id], onDelete: Cascade)
childName String @map("child_name")
childLabel String? @map("child_label")
childVersion Int? @map("child_version")
@@index([projectId, parentId], map: "prompt_dependencies_project_id_parent_id")
@@index([projectId, childName], map: "prompt_dependencies_project_id_child_name")
@@map("prompt_dependencies")
}
model PromptProtectedLabels {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
label String
@@unique([projectId, label])
@@map("prompt_protected_labels")
}
// Update ObservationView below when making changes to this model!
model Model {
id String @id @default(cuid())
@@ -778,23 +753,31 @@ model Price {
@@map("prices")
}
enum AuditLogRecordType {
USER
API_KEY
}
// No FK constraints to preserve audit logs
model AuditLog {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
userId String @map("user_id")
orgId String @map("org_id")
userOrgRole String @map("user_org_role")
projectId String? @map("project_id")
userProjectRole String? @map("user_project_role")
resourceType String @map("resource_type")
resourceId String @map("resource_id")
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
type AuditLogRecordType @default(USER)
apiKeyId String? @map("api_key_id")
userId String? @map("user_id")
orgId String @map("org_id")
userOrgRole String? @map("user_org_role")
projectId String? @map("project_id")
userProjectRole String? @map("user_project_role")
resourceType String @map("resource_type")
resourceId String @map("resource_id")
action String
before String? //stringified JSON
before String? // stringified JSON
after String? // stringified JSON
@@index([projectId])
@@index([apiKeyId])
@@index([userId])
@@index([orgId])
@@index([createdAt])
@@ -853,6 +836,7 @@ model JobConfiguration {
variableMapping Json @map("variable_mapping")
sampling Decimal // ratio of jobs that are executed for sampling (0..1)
delay Int // delay in milliseconds
timeScope String[] @default(["NEW"]) @map("time_scope")
JobExecution JobExecution[]
@@index([projectId, id])
@@ -909,9 +893,9 @@ model SsoConfig {
authProvider String @map("auth_provider") // e.g. "okta", ee/sso/types.ts
authConfig Json? @map("auth_config")
// e.g. { "clientId": "1234", "clientSecret": "5678" }, null if credentials from env should be used
// secrets like clientSecret are encrypted on the application level
@@map("sso_configs")
}
@@ -927,6 +911,49 @@ model PosthogIntegration {
@@map("posthog_integrations")
}
model BlobStorageIntegration {
projectId String @id @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
// Blob Storage Config
type BlobStorageIntegrationType @map("type")
bucketName String @map("bucket_name")
prefix String @map("prefix")
accessKeyId String @map("access_key_id")
secretAccessKey String @map("secret_access_key")
region String @map("region")
endpoint String? @map("endpoint")
forcePathStyle Boolean @map("force_path_style")
// Integration Config
nextSyncAt DateTime? @map("next_sync_at")
lastSyncAt DateTime? @map("last_sync_at")
enabled Boolean
exportFrequency String @map("export_frequency")
fileType BlobStorageIntegrationFileType @default(CSV) @map("file_type")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
@@map("blob_storage_integrations")
}
enum BlobStorageIntegrationFileType {
JSON
CSV
JSONL
@@map("BlobStorageIntegrationFileType")
}
enum BlobStorageIntegrationType {
S3
S3_COMPATIBLE
AZURE_BLOB_STORAGE
@@map("BlobStorageIntegrationType")
}
model BatchExport {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
@@ -1004,17 +1031,6 @@ model ObservationMedia {
@@map("observation_media")
}
model QueueBackUp {
id String @id @default(cuid())
projectId String? @map("project_id")
queueName String @map("queue_name")
content Json
createdAt DateTime @default(now()) @map("created_at")
@@map("queue_backups")
}
model BillingMeterBackup {
// unique
stripeCustomerId String @map("stripe_customer_id")
@@ -1037,3 +1053,100 @@ model BillingMeterBackup {
@@index([stripeCustomerId, meterId, startTime, endTime])
@@map("billing_meter_backups")
}
model LlmSchema {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String @map("name")
description String @map("description")
schema Json @map("schema") @db.Json
@@unique([projectId, name])
@@map("llm_schemas")
}
model LlmTool {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
projectId String @map("project_id")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String @map("name")
description String @map("description")
parameters Json @map("parameters") @db.Json
@@unique([projectId, name])
@@map("llm_tools")
}
model Dashboard {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
createdBy String? @map("created_by")
createdByUser User? @relation("CreatedByUser", fields: [createdBy], references: [id], onDelete: SetNull)
updatedBy String? @map("updated_by")
updatedByUser User? @relation("UpdatedByUser", fields: [updatedBy], references: [id], onDelete: SetNull)
// Optional to account for Langfuse-managed dashboards
projectId String? @map("project_id")
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String @map("name")
description String @map("description")
definition Json @map("definition")
@@map("dashboards")
}
enum DashboardWidgetViews {
TRACES
OBSERVATIONS
SCORES_NUMERIC
SCORES_CATEGORICAL
}
enum DashboardWidgetChartType {
LINE_TIME_SERIES
BAR_TIME_SERIES
HORIZONTAL_BAR
VERTICAL_BAR
PIE
}
model DashboardWidget {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
createdBy String? @map("created_by")
createdByUser User? @relation("CreatedByUser", fields: [createdBy], references: [id], onDelete: SetNull)
updatedBy String? @map("updated_by")
updatedByUser User? @relation("UpdatedByUser", fields: [updatedBy], references: [id], onDelete: SetNull)
// Optional to account for Langfuse-managed dashboards
projectId String? @map("project_id")
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
name String @map("name")
description String @map("description")
view DashboardWidgetViews @map("view")
dimensions Json @map("dimensions")
metrics Json @map("metrics")
filters Json @map("filters")
chartType DashboardWidgetChartType @map("chart_type")
chartConfig Json @map("chart_config")
@@map("dashboard_widgets")
}
+156 -115
View File
@@ -2,8 +2,6 @@ import {
PrismaClient,
type Project,
type Prisma,
ObservationType,
ScoreSource,
ScoreDataType,
AnnotationQueueObjectType,
} from "../src/index";
@@ -16,6 +14,7 @@ import { ModelUsageUnit } from "../src";
import { getDisplaySecretKey, hashSecretKey, logger } from "../src/server";
import { encrypt } from "../src/encryption";
import { redis } from "../src/server/redis/redis";
import { randomUUID } from "crypto";
const LOAD_TRACE_VOLUME = 10_000;
@@ -74,6 +73,9 @@ async function main() {
where: { id: seedOrgId },
update: {
name: "Seed Org",
cloudConfig: {
plan: "Team",
},
},
create: {
id: seedOrgId,
@@ -97,7 +99,7 @@ async function main() {
},
});
const orgMembership = await prisma.organizationMembership.upsert({
await prisma.organizationMembership.upsert({
where: {
orgId_userId: {
userId: user.id,
@@ -127,7 +129,7 @@ async function main() {
update: {},
});
const projectMembership = await prisma.projectMembership.upsert({
await prisma.projectMembership.upsert({
where: {
projectId_userId: {
projectId: project1.id,
@@ -179,6 +181,7 @@ async function main() {
publicKey: seedApiKey.public,
hashedSecretKey: await hashSecretKey(seedApiKey.secret),
displaySecretKey: getDisplaySecretKey(seedApiKey.secret),
scope: "PROJECT",
project: {
connect: {
id: project1.id,
@@ -240,6 +243,7 @@ async function main() {
publicKey: secondKey.public,
hashedSecretKey: await hashSecretKey(secondKey.secret),
displaySecretKey: getDisplaySecretKey(secondKey.secret),
scope: "PROJECT",
project: {
connect: {
id: project2.id,
@@ -266,38 +270,23 @@ async function main() {
const traceVolume = environment === "load" ? LOAD_TRACE_VOLUME : 100;
const {
traces,
observations,
scores,
sessions,
events,
comments,
queueItems,
} = createObjects(
traceVolume,
envTags,
colorTags,
project1,
project2,
promptIds,
queueIds,
configIdsAndNames,
);
const { traces, observations, scores, sessions, comments, queueItems } =
createObjects(
traceVolume,
envTags,
colorTags,
project1,
project2,
promptIds,
queueIds,
configIdsAndNames,
);
logger.info(
`Seeding ${traces.length} traces, ${observations.length} observations, and ${scores.length} scores`,
);
await uploadObjects(
traces,
observations,
scores,
sessions,
events,
comments,
queueItems,
);
await uploadObjects(sessions, comments, queueItems);
// If openai key is in environment, add it to the projects LLM API keys
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
@@ -388,6 +377,48 @@ async function main() {
});
await createDatasets(project1, project2, observations);
await createDashboardsAndWidgets([project1, project2]);
await prisma.llmSchema.createMany({
data: [
{
projectId: project1.id,
name: "get_weather",
description: "Fetches weather in Celsius for a given location",
schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
},
},
required: ["location", "unit"],
},
},
{
projectId: project1.id,
name: "calculator",
description: "Performs basic arithmetic calculations",
schema: {
type: "object",
properties: {
expression: {
type: "string",
description:
"The mathematical expression to evaluate, e.g. '2 + 2'",
},
},
required: ["expression"],
},
},
],
});
}
}
@@ -405,6 +436,85 @@ main()
process.exit(1);
});
async function createDashboardsAndWidgets(projects: Project[]) {
logger.info("Creating dashboards and widgets");
// Process each project
for (const project of projects) {
const widget = await prisma.dashboardWidget.upsert({
where: { id: "cabc" },
create: {
id: "cabc",
projectId: project.id,
name: "Trace Counts",
description: "Trace Counts by Name Over Time",
view: "TRACES",
dimensions: [{ field: "name" }],
metrics: [{ measure: "count", agg: "count" }],
filters: [],
chartType: "BAR_TIME_SERIES",
chartConfig: {
type: "BAR_TIME_SERIES",
},
},
update: {},
});
const widget2 = await prisma.dashboardWidget.upsert({
where: { id: "cdef" },
create: {
id: "cdef",
projectId: project.id,
name: "Observation Latencies by Model",
description: "p95 Observation Latencies by Model Name",
view: "OBSERVATIONS",
dimensions: [{ field: "providedModelName" }],
metrics: [{ measure: "count", agg: "sum" }],
filters: [],
chartType: "LINE_TIME_SERIES",
chartConfig: {
type: "LINE_TIME_SERIES",
},
},
update: {},
});
// Create a dashboard with multiple widgets
await prisma.dashboard.upsert({
where: { id: "seed-dashboard" },
create: {
id: "seed-dashboard",
projectId: project.id,
name: "Performance Overview",
description: "Dashboard with various performance metrics",
definition: {
widgets: [
{
type: "widget",
id: randomUUID(),
widgetId: widget.id,
x: 0,
y: 0,
x_size: 6,
y_size: 2,
},
{
type: "widget",
id: randomUUID(),
widgetId: widget2.id,
x: 6,
y: 0,
x_size: 6,
y_size: 2,
},
],
},
},
update: {},
});
}
}
export async function createDatasets(
project1: {
id: string;
@@ -420,7 +530,7 @@ export async function createDatasets(
updatedAt: Date;
name: string;
},
observations: Prisma.ObservationCreateManyInput[],
observations: { id?: string; projectId?: string; traceId?: string | null }[],
) {
for (let datasetNumber = 0; datasetNumber < 2; datasetNumber++) {
for (const projectId of [project1.id, project2.id]) {
@@ -532,11 +642,7 @@ export async function createDatasets(
}
async function uploadObjects(
traces: Prisma.TraceCreateManyInput[],
observations: Prisma.ObservationCreateManyInput[],
scores: Prisma.ScoreCreateManyInput[],
sessions: Prisma.TraceSessionCreateManyInput[],
events: Prisma.ObservationCreateManyInput[],
comments: Prisma.CommentCreateManyInput[],
queueItems: Prisma.AnnotationQueueItemCreateManyInput[],
) {
@@ -564,73 +670,6 @@ async function uploadObjects(
await promises[i];
}
promises = [];
chunk(traces, chunkSize).forEach((chunk) => {
promises.push(
prisma.trace.createMany({
data: chunk,
}),
);
});
for (let i = 0; i < promises.length; i++) {
if (i + 1 >= promises.length || i % Math.ceil(promises.length / 10) === 0)
logger.info(
`Seeding of Traces ${((i + 1) / promises.length) * 100}% complete`,
);
await promises[i];
}
promises = [];
chunk(observations, chunkSize).forEach((chunk) => {
promises.push(
prisma.observation.createMany({
data: chunk,
}),
);
});
for (let i = 0; i < promises.length; i++) {
if (i + 1 >= promises.length || i % Math.ceil(promises.length / 10) === 0)
logger.info(
`Seeding of Observations ${((i + 1) / promises.length) * 100}% complete`,
);
await promises[i];
}
promises = [];
chunk(events, chunkSize).forEach((chunk) => {
promises.push(
prisma.observation.createMany({
data: chunk,
}),
);
});
for (let i = 0; i < promises.length; i++) {
if (i + 1 >= promises.length || i % Math.ceil(promises.length / 10) === 0)
logger.info(
`Seeding of Events ${((i + 1) / promises.length) * 100}% complete`,
);
await promises[i];
}
promises = [];
chunk(scores, chunkSize).forEach((chunk) => {
promises.push(
prisma.score.createMany({
data: chunk,
}),
);
});
for (let i = 0; i < promises.length; i++) {
if (i + 1 >= promises.length || i % Math.ceil(promises.length / 10) === 0)
logger.info(
`Seeding of Scores ${((i + 1) / promises.length) * 100}% complete`,
);
await promises[i];
}
promises = [];
chunk(comments, chunkSize).forEach((chunk) => {
promises.push(
@@ -682,11 +721,11 @@ function createObjects(
}[]
>,
) {
const traces: Prisma.TraceCreateManyInput[] = [];
const observations: Prisma.ObservationCreateManyInput[] = [];
const scores: Prisma.ScoreCreateManyInput[] = [];
const traces: any[] = [];
const observations: any[] = [];
const scores: any[] = [];
const sessions: Prisma.TraceSessionCreateManyInput[] = [];
const events: Prisma.ObservationCreateManyInput[] = [];
const events: any[] = [];
const configs: Prisma.ScoreConfigCreateManyInput[] = [];
const comments: Prisma.CommentCreateManyInput[] = [];
const queueItems: Prisma.AnnotationQueueItemCreateManyInput[] = [];
@@ -795,7 +834,7 @@ function createObjects(
name: annotationScoreName,
timestamp: traceTs,
createdAt: traceTs,
source: ScoreSource.ANNOTATION,
source: "ANNOTATION",
projectId,
authorUserId: `user-${i}`,
dataType,
@@ -812,9 +851,10 @@ function createObjects(
value: Math.floor(Math.random() * 10) - 5,
timestamp: traceTs,
createdAt: traceTs,
source: ScoreSource.API,
source: "API",
projectId,
dataType: ScoreDataType.NUMERIC,
metadata: {},
},
]
: []),
@@ -825,11 +865,12 @@ function createObjects(
name: "Completeness",
timestamp: traceTs,
createdAt: traceTs,
source: ScoreSource.API,
source: "API",
projectId,
dataType: ScoreDataType.CATEGORICAL,
stringValue:
Math.floor(Math.random() * 2) === 1 ? "Fully" : "Partially",
metadata: {},
},
]
: []),
@@ -859,7 +900,7 @@ function createObjects(
);
const span = {
type: ObservationType.SPAN,
type: "SPAN",
id: `span-${v4()}`,
startTime: spanTsStart,
createdAt: spanTsStart,
@@ -933,7 +974,7 @@ function createObjects(
const { input, output } = getGenerationInputOutput();
const generation = {
type: ObservationType.GENERATION,
type: "GENERATION",
id: `generation-${v4()}`,
startTime: generationTsStart,
createdAt: generationTsStart,
@@ -978,7 +1019,7 @@ function createObjects(
value: Math.random() * 2 - 1,
observationId: generation.id,
traceId: trace.id,
source: ScoreSource.API,
source: "API",
projectId: trace.projectId,
timestamp: generationTsEnd,
createdAt: traceTs,
@@ -989,7 +1030,7 @@ function createObjects(
value: Math.random() * 2 - 1,
observationId: generation.id,
traceId: trace.id,
source: ScoreSource.API,
source: "API",
projectId: trace.projectId,
timestamp: generationTsEnd,
createdAt: traceTs,
@@ -1013,7 +1054,7 @@ function createObjects(
);
events.push({
type: ObservationType.EVENT,
type: "EVENT",
id: `event-${v4()}`,
startTime: eventTs,
createdAt: eventTs,
+5 -7
View File
@@ -1,11 +1,6 @@
import { randomUUID } from "crypto";
import { prisma } from "../src/db";
import {
clickhouseClient,
getDisplaySecretKey,
hashSecretKey,
logger,
} from "../src/server";
import { getDisplaySecretKey, hashSecretKey, logger } from "../src/server";
import { prepareClickhouse } from "./prepareClickhouse";
import { redis } from "../src/server";
@@ -32,6 +27,9 @@ const prepareProjectsAndApiKeys = async (
create: {
id: orgId,
name: `Organization for ${projectId}`,
cloudConfig: {
plan: "Team",
},
},
});
@@ -60,6 +58,7 @@ const prepareProjectsAndApiKeys = async (
publicKey: `pk-${Math.random().toString(36).substr(2, 9)}`,
hashedSecretKey: sk,
displaySecretKey: getDisplaySecretKey(sk),
scope: "PROJECT",
project: {
connect: {
id: projectId,
@@ -124,7 +123,6 @@ async function main() {
} catch (error) {
logger.error("Error during Clickhouse preparation:", error);
} finally {
await clickhouseClient().close();
await prisma.$disconnect();
redis?.disconnect();
logger.info("Disconnected from Clickhouse.");
+5 -1
View File
@@ -67,6 +67,7 @@ export const prepareClickhouse = async (
concat('release_', toString(randUniform(0, 100))) AS release,
concat('version_', toString(randUniform(0, 100))) AS version,
'${projectId}' AS project_id,
'default' AS environment,
if(rand() < 0.8, true, false) as public,
if(rand() < 0.8, true, false) as bookmarked,
array('tag1', 'tag2') as tags,
@@ -85,6 +86,7 @@ export const prepareClickhouse = async (
SELECT toString(number) AS id,
toString(floor(randUniform(0, ${tracesPerProject}))) AS trace_id,
'${projectId}' AS project_id,
'default' AS environment,
if(randUniform(0, 1) < 0.47, 'GENERATION', if(randUniform(0, 1) < 0.94, 'SPAN', 'EVENT')) AS type,
toString(rand()) AS parent_observation_id,
toDateTime(now() - randUniform(0, ${opts.numberOfDays} * 24 * 60 * 60)) AS start_time,
@@ -143,9 +145,10 @@ export const prepareClickhouse = async (
const scoresQuery = `
INSERT INTO scores
SELECT toString(floor(randUniform(0, 100))) AS id,
SELECT toString(number) AS id,
toDateTime(now() - randUniform(0, ${opts.numberOfDays} * 24 * 60 * 60)) AS timestamp,
'${projectId}' AS project_id,
'default' AS environment,
toString(floor(randUniform(0, ${tracesPerProject}))) AS trace_id,
if(
rand() > 0.9,
@@ -156,6 +159,7 @@ export const prepareClickhouse = async (
randUniform(0, 100) as value,
'API' as source,
'comment' as comment,
map('key', 'value') AS metadata,
toString(rand() % 100) as author_user_id,
toString(rand() % 100) as config_id,
if (rand() < 0.33, 'NUMERIC', if (rand() < 0.5, 'CATEGORICAL', 'BOOLEAN')) as data_type,
+3
View File
@@ -0,0 +1,3 @@
export * from "./observations";
export * from "./traces";
export * from "./scores";
@@ -0,0 +1,76 @@
import z from "zod";
import { jsonSchema } from "../utils/zod";
import { MetadataDomain } from "./traces";
export const ObservationType = {
SPAN: "SPAN",
EVENT: "EVENT",
GENERATION: "GENERATION",
} as const;
export const ObservationTypeDomain = z.enum(["SPAN", "EVENT", "GENERATION"]);
export type ObservationType = z.infer<typeof ObservationTypeDomain>;
export const ObservationLevel = {
DEBUG: "DEBUG",
DEFAULT: "DEFAULT",
WARNING: "WARNING",
ERROR: "ERROR",
} as const;
export const ObservationLevelDomain = z.enum([
"DEBUG",
"DEFAULT",
"WARNING",
"ERROR",
]);
export type ObservationLevelType = z.infer<typeof ObservationLevelDomain>;
export const ObservationDomain = z.object({
id: z.string(),
name: z.string(),
timestamp: z.date(),
environment: z.string(),
tags: z.array(z.string()),
});
export type ObservationDomain = z.infer<typeof ObservationDomain>;
export const ObservationSchema = z.object({
id: z.string(),
traceId: z.string().nullable(),
projectId: z.string(),
environment: z.string(),
type: ObservationTypeDomain,
startTime: z.date(),
endTime: z.date().nullable(),
name: z.string().nullable(),
metadata: MetadataDomain,
parentObservationId: z.string().nullable(),
level: ObservationLevelDomain,
statusMessage: z.string().nullable(),
version: z.string().nullable(),
createdAt: z.date(),
updatedAt: z.date(),
model: z.string().nullable(),
internalModelId: z.string().nullable(),
modelParameters: jsonSchema.nullable(),
input: jsonSchema.nullable(),
output: jsonSchema.nullable(),
completionStartTime: z.date().nullable(),
promptId: z.string().nullable(),
promptName: z.string().nullable(),
promptVersion: z.number().nullable(),
latency: z.number().nullable(),
timeToFirstToken: z.number().nullable(),
usageDetails: z.record(z.string(), z.number()),
costDetails: z.record(z.string(), z.number()),
providedCostDetails: z.record(z.string(), z.number()),
// aggregated data from cost_details
inputCost: z.number().nullable(),
outputCost: z.number().nullable(),
totalCost: z.number().nullable(),
// aggregated data from usage_details
inputUsage: z.number(),
outputUsage: z.number(),
totalUsage: z.number(),
});
export type Observation = z.infer<typeof ObservationSchema>;
+35
View File
@@ -0,0 +1,35 @@
import { ScoreDataType } from "@prisma/client";
import z from "zod";
import { MetadataDomain } from "./traces";
export const ScoreSource = {
ANNOTATION: "ANNOTATION",
API: "API",
EVAL: "EVAL",
} as const;
export const ScoreSourceDomain = z.enum(["ANNOTATION", "API", "EVAL"]);
export type ScoreSourceType = z.infer<typeof ScoreSourceDomain>;
export const ScoreSchema = z.object({
id: z.string(),
timestamp: z.date(),
projectId: z.string(),
environment: z.string(),
name: z.string(),
value: z.number().nullable(),
source: ScoreSourceDomain,
authorUserId: z.string().nullable(),
comment: z.string().nullable(),
metadata: MetadataDomain,
traceId: z.string(),
observationId: z.string().nullable(),
configId: z.string().nullable(),
stringValue: z.string().nullable(),
queueId: z.string().nullable(),
createdAt: z.date(),
updatedAt: z.date(),
dataType: z.nativeEnum(ScoreDataType),
});
export type ScoreDomain = z.infer<typeof ScoreSchema>;
+32
View File
@@ -0,0 +1,32 @@
import z from "zod";
import { jsonSchema, jsonSchemaNullable } from "../utils/zod";
export const MetadataDomain = z.record(
z.string(),
jsonSchemaNullable.or(z.undefined()),
);
export type MetadataDomain = z.infer<typeof MetadataDomain>;
// to be used across the application in frontend and backend.
export const TraceDomain = z.object({
id: z.string(),
name: z.string().nullable(),
timestamp: z.date(),
environment: z.string(),
tags: z.array(z.string()),
bookmarked: z.boolean(),
public: z.boolean(),
release: z.string().nullable(),
version: z.string().nullable(),
input: jsonSchema.nullable(),
output: jsonSchema.nullable(),
metadata: MetadataDomain,
createdAt: z.date(),
updatedAt: z.date(),
sessionId: z.string().nullable(),
userId: z.string().nullable(),
projectId: z.string(),
});
export type TraceDomain = z.infer<typeof TraceDomain>;
+3 -3
View File
@@ -2,7 +2,7 @@ import crypto from "crypto";
import { env } from "../env";
const ENCRYPTION_KEY: string | undefined = env.ENCRYPTION_KEY; // Must be 256 bits (32 bytes, 64 hex characters)
const IV_LENGTH: number = 16; // For AES, this is always 16
const IV_LENGTH: number = 12; // For AES-GCM, this is always 12
// Alternatively: openssl rand -hex 32
export function keyGen() {
@@ -23,7 +23,7 @@ export function encrypt(plainText: string): string {
const cipher = crypto.createCipheriv(
"aes-256-gcm",
Buffer.from(ENCRYPTION_KEY, "hex"),
iv
iv,
);
let encrypted = cipher.update(plainText, "utf8", "hex");
encrypted += cipher.final("hex");
@@ -49,7 +49,7 @@ export function decrypt(text: string): string {
const decipher = crypto.createDecipheriv(
"aes-256-gcm",
Buffer.from(ENCRYPTION_KEY, "hex"),
iv
iv,
);
decipher.setAuthTag(authTag);
+13 -1
View File
@@ -2,6 +2,7 @@ import { z } from "zod";
import { removeEmptyEnvVariables } from "./utils/environment";
const EnvSchema = z.object({
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION: z.string().optional(),
NODE_ENV: z
.enum(["development", "test", "production"])
.default("development"),
@@ -10,7 +11,7 @@ const EnvSchema = z.object({
REDIS_PORT: z.coerce
.number({
description:
".env files convert numbers to strings, therefoore we have to enforce them to be numbers",
".env files convert numbers to strings, therefore we have to enforce them to be numbers",
})
.positive()
.max(65536, `options.port should be >= 0 and < 65536`)
@@ -18,6 +19,10 @@ const EnvSchema = z.object({
.nullable(),
REDIS_AUTH: z.string().nullish(),
REDIS_CONNECTION_STRING: z.string().nullish(),
REDIS_TLS_ENABLED: z.enum(["true", "false"]).default("false"),
REDIS_TLS_CA_PATH: z.string().optional(),
REDIS_TLS_CERT_PATH: z.string().optional(),
REDIS_TLS_KEY_PATH: z.string().optional(),
REDIS_ENABLE_AUTO_PIPELINING: z.enum(["true", "false"]).default("true"),
ENCRYPTION_KEY: z
.string()
@@ -46,6 +51,7 @@ const EnvSchema = z.object({
ENABLE_AWS_CLOUDWATCH_METRIC_PUBLISHING: z
.enum(["true", "false"])
.default("false"),
LANGFUSE_S3_CONCURRENT_WRITES: z.coerce.number().positive().default(50),
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: z.string({
required_error: "Langfuse requires a bucket name for S3 Event Uploads.",
}),
@@ -58,6 +64,8 @@ const EnvSchema = z.object({
.enum(["true", "false"])
.default("false"),
LANGFUSE_USE_AZURE_BLOB: z.enum(["true", "false"]).default("false"),
LANGFUSE_USE_GOOGLE_CLOUD_STORAGE: z.enum(["true", "false"]).default("false"),
LANGFUSE_GOOGLE_CLOUD_STORAGE_CREDENTIALS: z.string().optional(),
STRIPE_SECRET_KEY: z.string().optional(),
LANGFUSE_S3_CORE_DATA_EXPORT_IS_ENABLED: z
@@ -66,6 +74,10 @@ const EnvSchema = z.object({
LANGFUSE_POSTGRES_METERING_DATA_EXPORT_IS_ENABLED: z
.enum(["true", "false"])
.default("false"),
LANGFUSE_CUSTOM_SSO_EMAIL_CLAIM: z.string().default("email"),
LANGFUSE_CUSTOM_SSO_NAME_CLAIM: z.string().default("name"),
LANGFUSE_CUSTOM_SSO_SUB_CLAIM: z.string().default("sub"),
});
export const env: z.infer<typeof EnvSchema> =
@@ -0,0 +1,7 @@
import { BaseError } from "./BaseError";
export class LangfuseConflictError extends BaseError {
constructor(description = "Conflict") {
super("LangfuseConflictError", 409, description, true);
}
}
+1
View File
@@ -6,3 +6,4 @@ export { ForbiddenError } from "./ForbiddenError";
export { MethodNotAllowedError } from "./MethodNotAllowedError";
export { ApiError } from "./ApiError";
export { InternalServerError } from "./InternalServerError";
export { LangfuseConflictError } from "./ConflictError";
@@ -28,6 +28,7 @@ const BooleanData = z.object({
const CreateAnnotationScoreBase = z.object({
name: z.string(),
projectId: z.string(),
environment: z.string().default("default"),
traceId: z.string(),
configId: z.string().optional(),
observationId: z.string().optional(),
@@ -10,6 +10,7 @@ export enum BatchActionType {
}
const ActionIdSchema = z.enum([
"score-delete",
"trace-delete",
"trace-add-to-annotation-queue",
]);
@@ -15,12 +15,15 @@ export enum BatchExportStatus {
export enum BatchExportFileFormat {
JSON = "JSON",
CSV = "CSV",
JSONL = "JSONL",
}
export enum BatchExportTableName {
Scores = "scores",
Sessions = "sessions",
Traces = "traces",
Generations = "generations",
Observations = "observations",
DatasetRunItems = "dataset_run_items",
}
export const exportOptions: Record<
@@ -33,6 +36,11 @@ export const exportOptions: Record<
> = {
CSV: { label: "CSV", extension: "csv", fileType: "text/csv" },
JSON: { label: "JSON", extension: "json", fileType: "application/json" },
JSONL: {
label: "JSONL",
extension: "jsonl",
fileType: "application/x-ndjson",
},
} as const;
export const BatchExportQuerySchema = z.object({
@@ -1,8 +1,19 @@
// used on organization.cloudConfig.plan
export const cloudConfigPlans = [
"Hobby",
"Core",
"Pro",
"Team",
"Enterprise",
] as const;
export const planLabels = {
oss: "OSS",
"cloud:hobby": "Hobby",
"cloud:core": "Core",
"cloud:pro": "Pro",
"cloud:team": "Team",
"cloud:enterprise": "Enterprise",
"self-hosted:pro": "Pro (self-hosted)",
"self-hosted:enterprise": "Enterprise (self-hosted)",
} as const;
@@ -12,8 +23,9 @@ export type Plan = keyof typeof planLabels;
export const plans = Object.keys(planLabels) as Plan[];
// These functions are kept here to ensure consistency when updating plan names in the future.
export const isCloudPlan = (plan: Plan) => plan.startsWith("cloud");
export const isSelfHostedPlan = (plan: Plan) => plan.startsWith("self-hosted");
export const isCloudPlan = (plan?: Plan) => plan?.startsWith("cloud");
export const isSelfHostedPlan = (plan?: Plan) =>
plan?.startsWith("self-hosted");
export const isPlan = (value: string): value is Plan =>
plans.includes(value as Plan);
+5 -5
View File
@@ -106,9 +106,9 @@ export const OutputSchema = z.object({
score: z.string(),
});
export enum EvalTargetObject {
Trace = "trace",
Dataset = "dataset",
}
export const DEFAULT_TRACE_JOB_DELAY = 10_000;
export const JobTimeScopeZod = z.enum(["NEW", "EXISTING"]);
export type JobTimeScope = z.infer<typeof JobTimeScopeZod>;
export const TimeScopeSchema = z.array(JobTimeScopeZod).default(["NEW"]);
@@ -0,0 +1,61 @@
import { z } from "zod";
export const PromptDependencyRegex = /@@@langfusePrompt:(.*?)@@@/g;
export const ParsedPromptDependencySchema = z.union([
z.object({
name: z.string(),
type: z.literal("version"),
version: z.coerce.number(),
}),
z.object({ name: z.string(), type: z.literal("label"), label: z.string() }),
]);
export type ParsedPromptDependencyTag = z.infer<
typeof ParsedPromptDependencySchema
>;
export function parsePromptDependencyTags(
content: string | object,
): ParsedPromptDependencyTag[] {
const matchedTags = JSON.stringify(content).match(PromptDependencyRegex);
const validTags: ParsedPromptDependencyTag[] = [];
for (const match of new Set(matchedTags ?? [])) {
const innerContent = match.replace(/^@@@langfusePrompt:|@@@$/g, "");
const parts = innerContent.split("|");
const params: Record<string, string> = {};
// Check if the first parameter is name
const firstPart = parts[0];
if (!firstPart || !firstPart.startsWith("name=")) {
continue; // Skip this tag if name is not the first parameter. This makes it easier to replace the tag with the resolved prompt.
}
// There can be only 2 parts
if (parts.length !== 2) {
continue;
}
parts.forEach((part) => {
const [key, value] = part.split("=");
params[key] = value;
});
if (params.name) {
const parsed = ParsedPromptDependencySchema.safeParse({
name: params.name,
...(params.version
? { version: params.version, type: "version" }
: { label: params.label, type: "label" }),
});
if (parsed.success) {
validTags.push(parsed.data);
}
}
}
return validTags;
}
@@ -1,14 +1,14 @@
import { z } from "zod";
import { Score } from "@prisma/client";
import { isPresent, stringDateTime } from "../../utils/typeChecks";
import {
jsonSchema,
NonEmptyString,
paginationMetaResponseZod,
publicApiPaginationZod,
} from "../../utils/zod";
import { Category as ConfigCategory } from "./scoreConfigTypes";
import { ScoreDomain } from "../../domain";
/**
* Types to use across codebase
@@ -46,10 +46,12 @@ const ScoreBase = z.object({
id: z.string(),
timestamp: z.coerce.date(),
projectId: z.string(),
environment: z.string().default("default"),
name: z.string(),
source: z.enum(ScoreSource),
authorUserId: z.string().nullish(),
comment: z.string().nullish(),
metadata: jsonSchema.nullish(),
traceId: z.string(),
observationId: z.string().nullish(),
configId: z.string().nullish(),
@@ -64,6 +66,8 @@ const BaseScoreBody = z.object({
traceId: z.string(),
observationId: z.string().nullish(),
comment: z.string().nullish(),
metadata: jsonSchema.nullish(),
environment: z.string().default("default"),
});
/**
@@ -154,26 +158,45 @@ export const ScorePropsAgainstConfig = z.union([
* Transformations
*/
type ValidatedAPIScore<IncludeHasMetadata extends boolean> = APIScore & {
hasMetadata: IncludeHasMetadata extends true ? boolean : never;
};
type InputScore = ScoreDomain & { hasMetadata?: boolean };
/**
* Use this function when pulling a list of scores from the database before using in the application to ensure type safety.
* All scores are expected to pass the validation. If a score fails validation, it will be logged to Otel.
* @param scores
* @returns list of validated scores
*/
export const filterAndValidateDbScoreList = (
scores: Score[],
onParseError?: (error: z.ZodError) => void,
): APIScore[] =>
scores.reduce((acc, ts) => {
export const filterAndValidateDbScoreList = <
IncludeHasMetadata extends boolean,
>({
scores,
includeHasMetadata = false as IncludeHasMetadata,
onParseError,
}: {
scores: InputScore[];
includeHasMetadata?: IncludeHasMetadata;
// eslint-disable-next-line no-unused-vars
onParseError?: (error: z.ZodError) => void;
}): ValidatedAPIScore<IncludeHasMetadata>[] => {
return scores.reduce((acc, ts) => {
const result = APIScoreSchema.safeParse(ts);
if (result.success) {
acc.push(result.data);
const score = { ...result.data };
if (includeHasMetadata) {
Object.assign(score, { hasMetadata: ts.hasMetadata ?? false });
}
acc.push(score as ValidatedAPIScore<IncludeHasMetadata>);
} else {
console.error("Score parsing error: ", result.error);
onParseError?.(result.error);
}
return acc;
}, [] as APIScore[]);
}, [] as ValidatedAPIScore<IncludeHasMetadata>[]);
};
/**
* Use this function when pulling a single score from the database before using in the application to ensure type safety.
@@ -182,7 +205,7 @@ export const filterAndValidateDbScoreList = (
* @returns validated score
* @throws error if score fails validation
*/
export const validateDbScore = (score: Score): APIScore =>
export const validateDbScore = (score: ScoreDomain): APIScore =>
APIScoreSchema.parse(score);
/**
@@ -237,6 +260,7 @@ export const GetScoresQuery = z.object({
configId: z.string().nullish(),
queueId: z.string().nullish(),
traceTags: z.union([z.array(z.string()), z.string()]).nullish(),
environment: z.union([z.array(z.string()), z.string()]).nullish(),
name: z.string().nullish(),
fromTimestamp: stringDateTime,
toTimestamp: stringDateTime,
@@ -259,6 +283,7 @@ const LegacyGetScoreResponseDataV1 = z.intersection(
trace: z.object({
userId: z.string().nullish(),
tags: z.array(z.string()).nullish(),
environment: z.string().nullish(),
}),
}),
);
@@ -269,6 +294,7 @@ export const GetScoresResponse = z.object({
export const legacyFilterAndValidateV1GetScoreList = (
scores: unknown[],
// eslint-disable-next-line no-unused-vars
onParseError?: (error: z.ZodError) => void,
): z.infer<typeof LegacyGetScoreResponseDataV1>[] =>
scores.reduce(
@@ -277,7 +303,7 @@ export const legacyFilterAndValidateV1GetScoreList = (
if (result.success) {
acc.push(result.data);
} else {
console.error("Score parsing error: ", result.error);
console.error(`Score parsing error ${JSON.stringify(result.error)}`);
onParseError?.(result.error);
}
return acc;
+13 -6
View File
@@ -1,17 +1,22 @@
import { ScoreDataType, ScoreSource } from "@prisma/client";
import { ScoreDataType } from "@prisma/client";
import { ScoreSourceType, type MetadataDomain } from "../../domain";
export type CategoricalAggregate = {
export type BaseAggregate = {
comment?: string | null;
id?: string | null;
hasMetadata?: boolean | null;
};
export type CategoricalAggregate = BaseAggregate & {
type: "CATEGORICAL";
values: string[];
valueCounts: { value: string; count: number }[];
comment?: string | null;
};
export type NumericAggregate = {
export type NumericAggregate = BaseAggregate & {
type: "NUMERIC";
values: number[];
average: number;
comment?: string | null;
};
export type ScoreAggregate = Record<
@@ -20,11 +25,13 @@ export type ScoreAggregate = Record<
>;
export type ScoreSimplified = {
id: string;
name: string;
dataType: ScoreDataType;
source: ScoreSource;
source: ScoreSourceType;
value?: number | null;
comment?: string | null;
metadata?: MetadataDomain | null;
stringValue?: string | null;
};
+10
View File
@@ -38,11 +38,21 @@ export * from "./features/comments/types";
// experiments
export * from "./features/experiments/utils";
// prompts
export * from "./features/prompts/parsePromptDependencyTags";
// export db types only
export * from "@prisma/client";
export { type DB } from "../prisma/generated/types";
export * from "./server/repositories/types";
// metadata conversion
export * from "./server/utils/metadata_conversion";
// errors
export * from "./errors/index";
export * from "./utils/environment";
// domain
export * from "./domain";
@@ -1,8 +1,9 @@
import { z } from "zod";
import { CloudConfigRateLimit } from "./rate-limits";
import { cloudConfigPlans } from "../features/entitlements/plans";
export const CloudConfigSchema = z.object({
plan: z.enum(["Hobby", "Pro", "Team", "Enterprise"]).optional(),
plan: z.enum(cloudConfigPlans).optional(),
monthlyObservationLimit: z.number().int().positive().optional(),
// used for table and dashboard queries
defaultLookBackDays: z.number().int().positive().optional(),
+10 -5
View File
@@ -1,8 +1,8 @@
import { ObservationLevel } from "@prisma/client";
import { ObservationLevelType } from "./domain";
import {
type OptionsDefinition,
type ColumnDefinition,
} from "./tableDefinitions/types";
} from "./tableDefinitions";
// to be used server side
export const observationsTableCols: ColumnDefinition[] = [
@@ -102,7 +102,12 @@ export const observationsTableCols: ColumnDefinition[] = [
id: "level",
type: "stringOptions",
internal: 'o."level"::text',
options: Object.values(ObservationLevel).map((value) => ({ value })),
options: [
{ value: "DEBUG" },
{ value: "DEFAULT" },
{ value: "WARNING" },
{ value: "ERROR" },
] as { value: ObservationLevelType }[],
},
{
name: "Status Message",
@@ -149,8 +154,8 @@ export const observationsTableCols: ColumnDefinition[] = [
nullable: true,
},
{
name: "Usage",
id: "usage",
name: "Tokens",
id: "tokens",
type: "number",
internal: 'o."total_tokens"',
},
+8 -3
View File
@@ -1,4 +1,4 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient, ApiKeyScope } from "@prisma/client";
import { compare, hash } from "bcryptjs";
import { randomUUID } from "crypto";
import * as crypto from "crypto";
@@ -38,7 +38,8 @@ export function createShaHash(privateKey: string, salt: string): string {
export async function createAndAddApiKeysToDb(p: {
prisma: PrismaClient;
projectId: string;
entityId: string;
scope: ApiKeyScope;
note?: string;
predefinedKeys?: {
secretKey: string;
@@ -59,14 +60,18 @@ export async function createAndAddApiKeysToDb(p: {
const hashFromProvidedKey = createShaHash(sk, salt);
const entity =
p.scope === "PROJECT" ? { projectId: p.entityId } : { orgId: p.entityId };
const apiKey = await p.prisma.apiKey.create({
data: {
projectId: p.projectId,
...entity,
publicKey: pk,
hashedSecretKey: hashedSk,
displaySecretKey: displaySk,
fastHashedSecretKey: hashFromProvidedKey,
note: p.note,
scope: p.scope,
},
});
@@ -1,4 +1,9 @@
import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers/oauth";
import { env } from "../../env";
const CUSTOM_EMAIL_CLAIM = env.LANGFUSE_CUSTOM_SSO_EMAIL_CLAIM;
const CUSTOM_NAME_CLAIM = env.LANGFUSE_CUSTOM_SSO_NAME_CLAIM;
const CUSTOM_SUB_CLAIM = env.LANGFUSE_CUSTOM_SSO_SUB_CLAIM;
interface CustomSSOUser extends Record<string, any> {
email: string;
@@ -7,6 +12,7 @@ interface CustomSSOUser extends Record<string, any> {
verified: boolean;
}
export function CustomSSOProvider<P extends CustomSSOUser>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
@@ -19,9 +25,9 @@ export function CustomSSOProvider<P extends CustomSSOUser>(
checks: ["pkce", "state"],
profile(profile) {
return {
id: profile.sub,
name: profile.name,
email: profile.email,
id: profile[CUSTOM_SUB_CLAIM],
name: profile[CUSTOM_NAME_CLAIM],
email: profile[CUSTOM_EMAIL_CLAIM],
image: null,
};
},
+16 -4
View File
@@ -1,8 +1,9 @@
import z from "zod";
import { Plan, plans } from "../../features/entitlements/plans";
import { CloudConfigRateLimit } from "../../interfaces/rate-limits";
import { ApiKeyScope } from "../../";
export const OrgEnrichedApiKey = z.object({
const ApiKeyBaseSchema = z.object({
id: z.string(),
note: z.string().nullable(),
publicKey: z.string(),
@@ -10,7 +11,6 @@ export const OrgEnrichedApiKey = z.object({
createdAt: z.string().datetime().nullable(),
lastUsedAt: z.string().datetime().nullable(),
expiresAt: z.string().datetime().nullable(),
projectId: z.string(),
fastHashedSecretKey: z.string(),
hashedSecretKey: z.string(),
orgId: z.string(),
@@ -18,6 +18,17 @@ export const OrgEnrichedApiKey = z.object({
rateLimitOverrides: CloudConfigRateLimit.nullish(),
});
export const OrgEnrichedApiKey = z.discriminatedUnion("scope", [
ApiKeyBaseSchema.extend({
scope: z.literal(ApiKeyScope.ORGANIZATION),
projectId: z.null(),
}),
ApiKeyBaseSchema.extend({
scope: z.literal(ApiKeyScope.PROJECT),
projectId: z.string(),
}),
]);
export const API_KEY_NON_EXISTENT = "api-key-non-existent";
export const CachedApiKey = z.union([
@@ -38,9 +49,10 @@ export type AuthHeaderValidVerificationResult = {
};
export type ApiAccessScope = {
projectId: string;
accessLevel: "all" | "scores";
projectId: string | null;
accessLevel: "organization" | "project" | "scores";
orgId: string;
plan: Plan;
rateLimitOverrides: z.infer<typeof CloudConfigRateLimit>;
apiKeyId: string;
};
@@ -6,20 +6,38 @@ import { propagation, context } from "@opentelemetry/api";
export type ClickhouseClientType = ReturnType<typeof createClient>;
export const clickhouseClient = (opts?: NodeClickHouseClientConfigOptions) => {
const headers = opts?.http_headers ?? {};
export const clickhouseClient = (
params: {
tags?: Record<string, string>;
opts?: NodeClickHouseClientConfigOptions;
} = {},
) => {
const headers = params.opts?.http_headers ?? {};
const activeSpan = getCurrentSpan();
if (activeSpan) {
propagation.inject(context.active(), headers);
}
const cloudOptions: Record<string, unknown> = {};
if (
["STAGING", "EU", "US"].includes(
env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION ?? "",
)
) {
cloudOptions.input_format_json_throw_on_bad_escape_sequence = 0;
}
return createClient({
...opts,
...params.opts,
url: env.CLICKHOUSE_URL,
username: env.CLICKHOUSE_USER,
password: env.CLICKHOUSE_PASSWORD,
database: env.CLICKHOUSE_DB,
http_headers: headers,
clickhouse_settings: {
...cloudOptions,
...(params.opts?.clickhouse_settings ?? {}),
log_comment: JSON.stringify(params.tags ?? {}),
async_insert: 1,
wait_for_async_insert: 1, // if disabled, we won't get errors from clickhouse
},
@@ -2,6 +2,11 @@ export const ClickhouseTableNames = {
traces: "traces",
observations: "observations",
scores: "scores",
// Virtual tables for dashboards
// TODO: Check if we can do this more elegantly
scores_numeric: "scores_numeric",
scores_categorical: "scores_categorical",
} as const;
export type ClickhouseTableName = keyof typeof ClickhouseTableNames;
+6 -1
View File
@@ -17,22 +17,25 @@ export * from "./clickhouse/schemaUtils";
export * from "./clickhouse/schema";
export * from "./repositories/definitions";
export * from "../server/ingestion/types";
export * from "./ingestion/modelMatch";
export * from "./ingestion/processEventBatch";
export * from "../server/ingestion/types";
export * from "../server/ingestion/validateAndInflateScore";
export * from "./redis/redis";
export * from "./redis/traceUpsert";
export * from "./redis/createEvalQueue";
export * from "./redis/cloudUsageMeteringQueue";
export * from "./redis/getQueue";
export * from "./redis/traceDelete";
export * from "./redis/projectDelete";
export * from "./redis/scoreDelete";
export * from "./redis/datasetRunItemUpsert";
export * from "./redis/batchExport";
export * from "./redis/batchActionQueue";
export * from "./redis/ingestionQueue";
export * from "./redis/postHogIntegrationQueue";
export * from "./redis/postHogIntegrationProcessingQueue";
export * from "./redis/blobStorageIntegrationQueue";
export * from "./redis/blobStorageIntegrationProcessingQueue";
export * from "./redis/dataRetentionQueue";
export * from "./redis/dataRetentionProcessingQueue";
export * from "./redis/coreDataS3ExportQueue";
@@ -48,6 +51,8 @@ export * from "./queries";
export * from "./repositories";
export * from "./redis/evalExecutionQueue";
export * from "./services/sessions-ui-table-service";
export * from "./services/datasets-ui-table-service";
export * from "./services/DashboardService";
// test utils
export * from "./test-utils";
@@ -1,63 +0,0 @@
import { Model, Observation, Prisma } from "@prisma/client";
import { prisma } from "../../db";
export async function findModel(p: {
event: {
projectId: string;
model?: string;
unit?: string;
startTime?: Date;
};
existingDbObservation?: Omit<Observation, "input" | "output">;
}): Promise<Model | null> {
const { event, existingDbObservation } = p;
// either get the model from the existing observation
// or match pattern on the user provided model name
const modelCondition = event.model
? Prisma.sql`AND ${event.model} ~ match_pattern`
: existingDbObservation?.internalModel
? Prisma.sql`AND model_name = ${existingDbObservation.internalModel}`
: undefined;
if (!modelCondition) return null;
// unit based on the current event or the existing observation, both can be undefined
const mergedUnit = event.unit ?? existingDbObservation?.unit;
const unitCondition = mergedUnit
? Prisma.sql`AND unit = ${mergedUnit}`
: Prisma.empty;
const sql = Prisma.sql`
SELECT
id,
created_at AS "createdAt",
updated_at AS "updatedAt",
project_id AS "projectId",
model_name AS "modelName",
match_pattern AS "matchPattern",
start_date AS "startDate",
input_price AS "inputPrice",
output_price AS "outputPrice",
total_price AS "totalPrice",
unit,
tokenizer_id AS "tokenizerId",
tokenizer_config AS "tokenizerConfig"
FROM
models
WHERE (project_id = ${event.projectId}
OR project_id IS NULL)
${modelCondition}
${unitCondition}
AND (start_date IS NULL OR start_date <= ${
event.startTime ? new Date(event.startTime) : new Date()
}::timestamp with time zone at time zone 'UTC')
ORDER BY
project_id ASC,
start_date DESC NULLS LAST
LIMIT 1
`;
const foundModels = await prisma.$queryRaw<Array<Model>>(sql);
return foundModels[0] ?? null;
}

Some files were not shown because too many files have changed in this diff Show More