Skip to content

feat(api): update API spec from langfuse/langfuse d60e520#822

Closed
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-d60e520
Closed

feat(api): update API spec from langfuse/langfuse d60e520#822
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-d60e520

Conversation

@langfuse-bot

@langfuse-bot langfuse-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Greptile Summary

This auto-generated PR restructures the scores API surface to align with the Langfuse API spec update (d60e520): the scores client is promoted to serve the v3 endpoint (/api/public/v3/scores with cursor-based pagination and polymorphic ScoreV3 responses), while the old v2 scores functionality is relocated under client.legacy.scoresV2.

  • client.scores.getMany() now calls /api/public/v3/scores (cursor-based, returns ScoreV3[]); the former v2 getMany and getById move to client.legacy.scoresV2.
  • client.scoresV3 property and the standalone scoresV3 resource module are removed; v3 types (BaseScoreV3, ScoreV3, ScoreSubject*, etc.) are re-exported from the scores namespace with some renames (e.g. ScoreSubjectV3ScoreSubject, GetScoresV3MetaGetScoresMeta).
  • GetScoresRequest parameters changed significantly: page removed in favour of cursor, value type changed from number to string, environment from string | string[] to string, and source/dataType widened from typed enums to plain string.

Confidence Score: 3/5

The changes are auto-generated and internally consistent, but they remove client.scores.getById(), change the GetScoresRequest.value type from number to string, drop array support for environment, 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: getById disappears from the main scores client, GetScoresResponse.meta loses page/totalItems/totalPages, and GetScoresRequest.value flips from number to string. Any consumer code that iterates pages, reads total counts, or passes a numeric value filter 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:#999900
Loading
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
packages/core/src/api/api/resources/scores/client/Client.ts:56-95
**`getById` removed from `Scores`**

The `getById` method that previously lived on `client.scores` is gone from this class entirely. It was moved to `client.legacy.scoresV2.getById()`. Any caller using `client.scores.getById(scoreId)` will fail to compile after this update and must be migrated to `client.legacy.scoresV2.getById(scoreId)`.

### Issue 2 of 4
packages/core/src/api/api/resources/scores/client/requests/GetScoresRequest.ts:16-48
**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).

### Issue 3 of 4
packages/core/src/api/api/resources/scores/types/GetScoresResponse.ts:5-8
**`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.

### Issue 4 of 4
packages/core/src/api/api/resources/legacy/resources/scoresV2/client/Client.ts:261-270
**Redundant identity map on array parameters**

`environment.map((item) => item)` and `traceTags.map((item) => item)` are identity transforms that return the same array unchanged. They have no effect and add unnecessary iteration. The values can be assigned directly: `_queryParams["environment"] = environment`.

Reviews (1): Last reviewed commit: "feat(api): update API spec from langfuse..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
langfuse-js Ready Ready Preview Jun 9, 2026 3:41pm

Request Review

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

@claude review

Comment on lines +16 to +48
/** 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. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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).

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.

Comment on lines 5 to +8
import * as LangfuseAPI from "../../../index.js";

export interface GetScoresResponse {
data: LangfuseAPI.GetScoresResponseData[];
meta: LangfuseAPI.utils.MetaResponse;
data: LangfuseAPI.ScoreV3[];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Comment on lines 287 to 293
});
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({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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

  1. After this PR, packages/core/src/api/api/resources/scores/client/Client.ts contains only one public method on Scores: getMany() (confirmed: grep -n 'public ' packages/core/src/api/api/resources/scores/client/Client.ts shows only getMany).
  2. tests/e2e/helpers/serverAssertions.ts declares public api: LangfuseAPIClient at line 12 and instantiates it at line 26.
  3. In packages/core/src/api/Client.ts, LangfuseAPIClient#scores returns new Scores(this._options) (line ~205, unchanged) — i.e. the v3 Scores whose getById no longer exists.
  4. tests/e2e/scores.e2e.test.ts line 69 reads const retrievedScore = await assertions.api.scores.getById(scoreId);. At runtime, assertions.api.scores is the Scores instance; .getById is undefined; calling it throws TypeError: assertions.api.scores.getById is not a function. Each of the 26 call sites follows the same pattern.
  5. CI test-e2e job (.github/workflows/ci.yml line 36) runs pnpm test:e2e against a real Langfuse server → vitest collects the test file → first getById call throws → suite fails → all-tests-passed gate 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.

@wochinge wochinge deleted the api-spec-bot-d60e520 branch June 11, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant