feat(api): update API spec from langfuse/langfuse d60e520#822
feat(api): update API spec from langfuse/langfuse d60e520#822langfuse-bot wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@claude review |
| /** Comma-separated list of score IDs to filter by (OR within, AND across filters). */ | ||
| id?: string; | ||
| /** Comma-separated list of score names to filter by. */ | ||
| name?: string; | ||
| /** Optional filter to only include scores created on or after a certain datetime (ISO 8601) */ | ||
| fromTimestamp?: string; | ||
| /** Optional filter to only include scores created before a certain datetime (ISO 8601) */ | ||
| toTimestamp?: string; | ||
| /** Optional filter for scores where the environment is one of the provided values. */ | ||
| environment?: string | string[]; | ||
| /** Retrieve only scores from a specific source. */ | ||
| source?: LangfuseAPI.ScoreSource; | ||
| /** Retrieve only scores with <operator> value. */ | ||
| operator?: string; | ||
| /** Retrieve only scores with <operator> value. */ | ||
| value?: number; | ||
| /** Comma-separated list of score IDs to limit the results to. */ | ||
| scoreIds?: string; | ||
| /** Retrieve only scores with a specific configId. */ | ||
| /** Comma-separated list of score sources to filter by (e.g. API, ANNOTATION, EVAL). Case-insensitive — `api` and `API` are equivalent. */ | ||
| source?: string; | ||
| /** Comma-separated list of data types to filter by (NUMERIC, BOOLEAN, CATEGORICAL, TEXT, CORRECTION). Case-insensitive — `numeric` and `NUMERIC` are equivalent. Must be a single value when used with value, valueMin, or valueMax; otherwise the request returns HTTP 400. Must be NUMERIC when used with valueMin or valueMax. */ | ||
| dataType?: string; | ||
| /** Comma-separated list of environments to filter by. */ | ||
| environment?: string; | ||
| /** Comma-separated list of score config IDs to filter by. */ | ||
| configId?: string; | ||
| /** Retrieve only scores with a specific sessionId. */ | ||
| sessionId?: string; | ||
| /** Retrieve only scores with a specific datasetRunId. */ | ||
| datasetRunId?: string; | ||
| /** Retrieve only scores with a specific traceId. */ | ||
| /** Comma-separated list of annotation queue IDs to filter by. */ | ||
| queueId?: string; | ||
| /** Comma-separated list of author user IDs to filter by. */ | ||
| authorUserId?: string; | ||
| /** Comma-separated list of exact values to filter by. Requires a single dataType from NUMERIC, BOOLEAN, or CATEGORICAL; any other dataType, multiple dataTypes, or omitting dataType returns HTTP 400. For BOOLEAN, each value must be "true" or "false"; for NUMERIC, each value must be a finite number. Otherwise the request returns HTTP 400. */ | ||
| value?: string; | ||
| /** Inclusive lower bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400. */ | ||
| valueMin?: number; | ||
| /** Inclusive upper bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400. */ | ||
| valueMax?: number; | ||
| /** Comma-separated list of trace IDs to filter by. Mutually exclusive with sessionId, experimentId. May be combined with observationId to scope the observation lookup to a specific trace. */ | ||
| traceId?: string; | ||
| /** Comma-separated list of observation IDs to filter scores by. */ | ||
| /** Comma-separated list of session IDs to filter by. Mutually exclusive with traceId, observationId, experimentId. */ | ||
| sessionId?: string; | ||
| /** Comma-separated list of observation IDs to filter by. Requires traceId to be specified, because observation IDs are scoped to a trace. Mutually exclusive with sessionId, experimentId. Returns HTTP 400 when used without traceId. */ | ||
| observationId?: string; | ||
| /** Retrieve only scores with a specific annotation queueId. */ | ||
| queueId?: string; | ||
| /** Retrieve only scores with a specific dataType. */ | ||
| dataType?: LangfuseAPI.ScoreDataType; | ||
| /** Only scores linked to traces that include all of these tags will be returned. */ | ||
| traceTags?: string | string[]; | ||
| /** Comma-separated list of field groups to include in the response. Available field groups: 'score' (core score fields), 'trace' (trace properties: userId, tags, environment, sessionId). If not specified, both 'score' and 'trace' are returned by default. Example: 'score' to exclude trace data, 'score,trace' to include both. Note: When filtering by trace properties (using userId or traceTags parameters), the 'trace' field group must be included, otherwise a 400 error will be returned. */ | ||
| fields?: string; | ||
| /** A JSON stringified array of filter objects. Each object requires type, column, operator, and value. Supports filtering by score metadata using the stringObject type. Example: [{"type":"stringObject","column":"metadata","key":"user_id","operator":"=","value":"abc123"}]. Supported types: stringObject (metadata key-value filtering), string, number, datetime, stringOptions, arrayOptions. Supported operators for stringObject: =, contains, does not contain, starts with, ends with. */ | ||
| filter?: string; | ||
| /** Comma-separated list of dataset run IDs (experiment IDs) to filter by. Mutually exclusive with traceId, sessionId, observationId. */ | ||
| experimentId?: string; | ||
| /** Inclusive lower bound on the score timestamp. */ | ||
| fromTimestamp?: string; | ||
| /** Exclusive upper bound on the score timestamp. */ |
There was a problem hiding this comment.
Breaking type changes in
GetScoresRequest
Several field types changed in ways that break existing call sites without a TypeScript diagnostic that is obvious to read:
valuechanged fromnumbertostring— code passingvalue: 0.5must change tovalue: "0.5"orvalue: "true".environmentchanged fromstring | string[]tostring— callers passing an array must now join values into a comma-separated string.sourceanddataTypewere narrowed typed enums (ScoreSource,ScoreDataType) and are now plainstring, losing compile-time exhaustiveness.
Also, the pagination model changed: page is removed and cursor is added, switching from offset-based to cursor-based pagination. Code that iterates pages via page + 1 will silently do nothing (the parameter is stripped from the request type).
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/api/api/resources/scores/client/requests/GetScoresRequest.ts
Line: 16-48
Comment:
**Breaking type changes in `GetScoresRequest`**
Several field types changed in ways that break existing call sites without a TypeScript diagnostic that is obvious to read:
- `value` changed from `number` to `string` — code passing `value: 0.5` must change to `value: "0.5"` or `value: "true"`.
- `environment` changed from `string | string[]` to `string` — callers passing an array must now join values into a comma-separated string.
- `source` and `dataType` were narrowed typed enums (`ScoreSource`, `ScoreDataType`) and are now plain `string`, losing compile-time exhaustiveness.
Also, the pagination model changed: `page` is removed and `cursor` is added, switching from offset-based to cursor-based pagination. Code that iterates pages via `page + 1` will silently do nothing (the parameter is stripped from the request type).
How can I resolve this? If you propose a fix, please make it concise.| import * as LangfuseAPI from "../../../index.js"; | ||
|
|
||
| export interface GetScoresResponse { | ||
| data: LangfuseAPI.GetScoresResponseData[]; | ||
| meta: LangfuseAPI.utils.MetaResponse; | ||
| data: LangfuseAPI.ScoreV3[]; |
There was a problem hiding this comment.
GetScoresResponse shape change breaks pagination consumers
meta was LangfuseAPI.utils.MetaResponse (which exposed page, totalItems, totalPages) and is now GetScoresMeta (which exposes only limit and cursor). Any downstream code accessing response.meta.page, response.meta.totalItems, or response.meta.totalPages will receive undefined at runtime with no TypeScript error on the consumer side until types are regenerated. If any higher-level wrappers in this repo loop on page until they reach totalPages, those loops will now run indefinitely.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/api/api/resources/scores/types/GetScoresResponse.ts
Line: 5-8
Comment:
**`GetScoresResponse` shape change breaks pagination consumers**
`meta` was `LangfuseAPI.utils.MetaResponse` (which exposed `page`, `totalItems`, `totalPages`) and is now `GetScoresMeta` (which exposes only `limit` and `cursor`). Any downstream code accessing `response.meta.page`, `response.meta.totalItems`, or `response.meta.totalPages` will receive `undefined` at runtime with no TypeScript error on the consumer side until types are regenerated. If any higher-level wrappers in this repo loop on `page` until they reach `totalPages`, those loops will now run indefinitely.
How can I resolve this? If you propose a fix, please make it concise.| }); | ||
| case "timeout": | ||
| throw new errors.LangfuseAPITimeoutError( | ||
| "Timeout exceeded when calling GET /api/public/v2/scores/{scoreId}.", | ||
| "Timeout exceeded when calling GET /api/public/v3/scores.", | ||
| ); | ||
| case "unknown": | ||
| throw new errors.LangfuseAPIError({ |
There was a problem hiding this comment.
🔴 This PR removes scores.getById() (moved to legacy.scoresV2.getById()), but tests/e2e/scores.e2e.test.ts still calls assertions.api.scores.getById(...) in 26 places (lines 69, 115, 148, 184, 243-244, 316-317, 391, 437, 488, 531, 596, 691-694, 742, 788, 832, 882, 944, 982, 1029, 1086, 1137). The test-e2e CI job will fail at runtime with TypeError: scores.getById is not a function. Either migrate the call sites to assertions.api.legacy.scoresV2.getById(...) in this PR or keep a backward-compatible alias on Scores. This is also a breaking change for SDK consumers.
Extended reasoning...
What the bug is
In packages/core/src/api/api/resources/scores/client/Client.ts, the Scores class previously exposed two public methods, getMany() (which hit GET /api/public/v2/scores) and getById(scoreId) (which hit GET /api/public/v2/scores/{scoreId}). This PR repoints getMany() at the new GET /api/public/v3/scores endpoint and deletes getById() entirely — the v2 getById has been relocated to legacy.scoresV2.getById (visible in packages/core/src/api/api/resources/legacy/resources/scoresV2/client/Client.ts). After this PR, the public Scores class only has getMany().
The code path that triggers it
tests/e2e/scores.e2e.test.ts is the e2e suite for scores. It uses a shared helper assertions of type ServerAssertions defined in tests/e2e/helpers/serverAssertions.ts, whose public api field is constructed as new LangfuseAPIClient({...}) (lines 12, 26). Because assertions.api is typed as LangfuseAPIClient, assertions.api.scores is the new v3 Scores instance — which no longer has getById.
A grep confirms the test file calls assertions.api.scores.getById(...) at exactly the 26 line numbers listed: 69, 115, 148, 184, 243, 244, 316, 317, 391, 437, 488, 531, 596, 691, 692, 693, 694, 742, 788, 832, 882, 944, 982, 1029, 1086, 1137.
Why existing code does not prevent it
There is no backward-compatibility shim or alias kept on Scores — the entire getById/__getById block (lines ~287–~430 in the previous file) is removed by this diff. The test file has not been updated, so nothing else catches the mismatch.
Impact
The CI workflow .github/workflows/ci.yml defines a test-e2e job that runs pnpm test:e2e, which expands to pnpm run build && vitest run --project=e2e (root package.json line 20). The build excludes test files, so it succeeds, but the vitest e2e project loads tests/e2e/**/*.test.ts (vitest.workspace.ts) and resolves @langfuse/core to packages/core/dist/index.mjs — the freshly built v3 client. Every scores.getById(...) call site will throw TypeError: assertions.api.scores.getById is not a function at runtime, failing 25+ tests as soon as the suite runs against the spun-up Langfuse server. In addition, this is a public breaking change for any SDK consumer who was calling client.scores.getById.
Step-by-step proof
- After this PR,
packages/core/src/api/api/resources/scores/client/Client.tscontains only one public method onScores:getMany()(confirmed:grep -n 'public ' packages/core/src/api/api/resources/scores/client/Client.tsshows onlygetMany). tests/e2e/helpers/serverAssertions.tsdeclarespublic api: LangfuseAPIClientat line 12 and instantiates it at line 26.- In
packages/core/src/api/Client.ts,LangfuseAPIClient#scoresreturnsnew Scores(this._options)(line ~205, unchanged) — i.e. the v3ScoreswhosegetByIdno longer exists. tests/e2e/scores.e2e.test.tsline 69 readsconst retrievedScore = await assertions.api.scores.getById(scoreId);. At runtime,assertions.api.scoresis theScoresinstance;.getByIdisundefined; calling it throwsTypeError: assertions.api.scores.getById is not a function. Each of the 26 call sites follows the same pattern.- CI
test-e2ejob (.github/workflows/ci.ymlline 36) runspnpm test:e2eagainst a real Langfuse server → vitest collects the test file → firstgetByIdcall throws → suite fails →all-tests-passedgate fails → PR is blocked.
How to fix
In this same PR, migrate every assertions.api.scores.getById(...) to assertions.api.legacy.scoresV2.getById(...) (the method was relocated there in this diff at packages/core/src/api/api/resources/legacy/resources/scoresV2/client/Client.ts). Alternatively, add a backward-compatible getById alias on the new Scores class that forwards to legacy.scoresV2.getById (this also preserves the public API for external SDK consumers). The first option is mechanical and self-contained for this auto-generated PR; the second is more defensive for external users.
Greptile Summary
This auto-generated PR restructures the scores API surface to align with the Langfuse API spec update (d60e520): the
scoresclient is promoted to serve the v3 endpoint (/api/public/v3/scoreswith cursor-based pagination and polymorphicScoreV3responses), while the old v2 scores functionality is relocated underclient.legacy.scoresV2.client.scores.getMany()now calls/api/public/v3/scores(cursor-based, returnsScoreV3[]); the former v2getManyandgetByIdmove toclient.legacy.scoresV2.client.scoresV3property and the standalonescoresV3resource module are removed; v3 types (BaseScoreV3,ScoreV3,ScoreSubject*, etc.) are re-exported from thescoresnamespace with some renames (e.g.ScoreSubjectV3→ScoreSubject,GetScoresV3Meta→GetScoresMeta).GetScoresRequestparameters changed significantly:pageremoved in favour ofcursor,valuetype changed fromnumbertostring,environmentfromstring | string[]tostring, andsource/dataTypewidened from typed enums to plainstring.Confidence Score: 3/5
The changes are auto-generated and internally consistent, but they remove
client.scores.getById(), change theGetScoresRequest.valuetype fromnumbertostring, drop array support forenvironment, and switch the pagination model from page-based to cursor-based — all without a migration shim.The restructuring is faithful to the upstream API spec, but multiple breaking changes land simultaneously:
getByIddisappears from the mainscoresclient,GetScoresResponse.metalosespage/totalItems/totalPages, andGetScoresRequest.valueflips fromnumbertostring. Any consumer code that iterates pages, reads total counts, or passes a numericvaluefilter will either fail to compile or produce wrong runtime behaviour.packages/core/src/api/api/resources/scores/client/Client.ts (missing getById), packages/core/src/api/api/resources/scores/client/requests/GetScoresRequest.ts (type changes), and packages/core/src/api/api/resources/scores/types/GetScoresResponse.ts (pagination model change).
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[LangfuseAPIClient] --> B[client.scores] A --> C[client.legacy] B --> B1["getMany()\n→ GET /api/public/v3/scores\nreturns ScoreV3[]\nmeta: GetScoresMeta cursor-based"] C --> D[client.legacy.scoresV2] D --> D1["getMany()\n→ GET /api/public/v2/scores\nreturns GetScoresResponseData[]\nmeta: MetaResponse page-based"] D --> D2["getById(scoreId)\n→ GET /api/public/v2/scores/{id}"] OLD["BEFORE (removed)"] -.->|removed| E["client.scoresV3\n.getManyV3()\n→ /api/public/v3/scores"] OLD -.->|removed| F["client.scores\n.getById(scoreId)\n→ /api/public/v2/scores/{id}"] style OLD fill:#ffcccc,stroke:#cc0000 style E fill:#ffcccc,stroke:#cc0000 style F fill:#ffcccc,stroke:#cc0000 style B1 fill:#ccffcc,stroke:#006600 style D1 fill:#ffffcc,stroke:#999900 style D2 fill:#ffffcc,stroke:#999900Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "feat(api): update API spec from langfuse..." | Re-trigger Greptile