Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions langfuse/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
scim,
score_configs,
scores,
skills,
trace,
unstable,
utils,
Expand Down Expand Up @@ -384,6 +385,22 @@
ScoreV3_Text,
TextScoreV3,
)
from .skills import (
CreateSkillVersionRequest,
DeleteSkillVersionResponse,
SkillFile,
SkillFileContent,
SkillFileContentsResponse,
SkillListPagination,
SkillMeta,
SkillMetaListResponse,
SkillVersion,
SkillVersionFileCreateInput,
SkillVersionFileInput,
SkillVersionFileReference,
UpdateSkillLabelsRequest,
UpdateSkillRequest,
)
from .trace import DeleteTraceResponse
_dynamic_imports: typing.Dict[str, str] = {
"AccessDeniedError": ".commons",
Expand Down Expand Up @@ -462,6 +479,7 @@
"CreateScoreValue": ".commons",
"CreateScoresRequest": ".scores",
"CreateScoresResponse": ".scores",
"CreateSkillVersionRequest": ".skills",
"CreateTextPromptRequest": ".prompts",
"CreateTextPromptType": ".prompts",
"Creator": ".evaluators",
Expand All @@ -478,6 +496,7 @@
"DeleteDatasetItemResponse": ".dataset_items",
"DeleteLlmConnectionResponse": ".llm_connections",
"DeleteMembershipRequest": ".organizations",
"DeleteSkillVersionResponse": ".skills",
"DeleteTraceResponse": ".trace",
"DeletedEvaluationRule": ".evaluation_rules",
"DeletedEvaluator": ".evaluators",
Expand Down Expand Up @@ -680,6 +699,16 @@
"Score_Text": ".commons",
"ServiceProviderConfig": ".scim",
"ServiceUnavailableError": ".health",
"SkillFile": ".skills",
"SkillFileContent": ".skills",
"SkillFileContentsResponse": ".skills",
"SkillListPagination": ".skills",
"SkillMeta": ".skills",
"SkillMetaListResponse": ".skills",
"SkillVersion": ".skills",
"SkillVersionFileCreateInput": ".skills",
"SkillVersionFileInput": ".skills",
"SkillVersionFileReference": ".skills",
"StringEvaluationRuleFilter": ".evaluation_commons",
"StringObjectEvaluationRuleFilter": ".evaluation_commons",
"StringOptionsEvaluationRuleFilter": ".evaluation_commons",
Expand All @@ -697,6 +726,8 @@
"UpdateEvaluatorRequest": ".evaluators",
"UpdateLlmAsJudgeEvaluatorRequest": ".evaluators",
"UpdateScoreConfigRequest": ".score_configs",
"UpdateSkillLabelsRequest": ".skills",
"UpdateSkillRequest": ".skills",
"UpsertLlmConnectionRequest": ".llm_connections",
"Usage": ".commons",
"UserMeta": ".scim",
Expand Down Expand Up @@ -726,6 +757,7 @@
"scim": ".scim",
"score_configs": ".score_configs",
"scores": ".scores",
"skills": ".skills",
"trace": ".trace",
"unstable": ".unstable",
"utils": ".utils",
Expand Down Expand Up @@ -836,6 +868,7 @@ def __dir__():
"CreateScoreValue",
"CreateScoresRequest",
"CreateScoresResponse",
"CreateSkillVersionRequest",
"CreateTextPromptRequest",
"CreateTextPromptType",
"Creator",
Expand All @@ -852,6 +885,7 @@ def __dir__():
"DeleteDatasetItemResponse",
"DeleteLlmConnectionResponse",
"DeleteMembershipRequest",
"DeleteSkillVersionResponse",
"DeleteTraceResponse",
"DeletedEvaluationRule",
"DeletedEvaluator",
Expand Down Expand Up @@ -1054,6 +1088,16 @@ def __dir__():
"Score_Text",
"ServiceProviderConfig",
"ServiceUnavailableError",
"SkillFile",
"SkillFileContent",
"SkillFileContentsResponse",
"SkillListPagination",
"SkillMeta",
"SkillMetaListResponse",
"SkillVersion",
"SkillVersionFileCreateInput",
"SkillVersionFileInput",
"SkillVersionFileReference",
"StringEvaluationRuleFilter",
"StringObjectEvaluationRuleFilter",
"StringOptionsEvaluationRuleFilter",
Expand All @@ -1071,6 +1115,8 @@ def __dir__():
"UpdateEvaluatorRequest",
"UpdateLlmAsJudgeEvaluatorRequest",
"UpdateScoreConfigRequest",
"UpdateSkillLabelsRequest",
"UpdateSkillRequest",
"UpsertLlmConnectionRequest",
"Usage",
"UserMeta",
Expand Down Expand Up @@ -1100,6 +1146,7 @@ def __dir__():
"scim",
"score_configs",
"scores",
"skills",
"trace",
"unstable",
"utils",
Expand Down
4 changes: 2 additions & 2 deletions langfuse/api/blob_storage_integrations/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def upsert_blob_storage_integration(
**Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected.

export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]]
Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved.
Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved.

`exportFieldGroups` requires `exportSource` to be provided in the same request.

Expand Down Expand Up @@ -438,7 +438,7 @@ async def upsert_blob_storage_integration(
**Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected.

export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]]
Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved.
Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved.

`exportFieldGroups` requires `exportSource` to be provided in the same request.

Expand Down
4 changes: 2 additions & 2 deletions langfuse/api/blob_storage_integrations/raw_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def upsert_blob_storage_integration(
**Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected.

export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]]
Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved.
Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved.

`exportFieldGroups` requires `exportSource` to be provided in the same request.

Expand Down Expand Up @@ -713,7 +713,7 @@ async def upsert_blob_storage_integration(
**Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected.

export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]]
Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved.
Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved.

`exportFieldGroups` requires `exportSource` to be provided in the same request.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

class BlobStorageExportFieldGroup(enum.StrEnum):
"""
Field group selecting which observation columns are included in the export. Applies to all export sources; groups without a counterpart in the legacy data model (e.g. `trace_context`) are omitted from the legacy observations export.
Field group selecting which columns are included in the export. Applies to all export sources.
- Observation groups (`core` through `trace_context`) select observation columns; groups without a counterpart in the legacy data model (e.g. `trace_context`) are omitted from the legacy observations export.
- Score groups (`score_` prefix) add optional columns to the scores export. The core score columns (`id`, `timestamp`, `trace_id`, `name`, `value`, …) are always exported and are not a selectable group; score groups add columns on top of them. `score_metadata` adds the score `metadata` column. `score_provenance` adds the references to where a score came from: `author_user_id`, `config_id`, `queue_id`, `evaluator_id`, `evaluation_rule_id`, `execution_trace_id`. Score groups are never selected by default.
"""

CORE = "core"
Expand All @@ -23,6 +25,8 @@ class BlobStorageExportFieldGroup(enum.StrEnum):
METRICS = "metrics"
TOOLS = "tools"
TRACE_CONTEXT = "trace_context"
SCORE_METADATA = "score_metadata"
SCORE_PROVENANCE = "score_provenance"

def visit(
self,
Expand All @@ -37,6 +41,8 @@ def visit(
metrics: typing.Callable[[], T_Result],
tools: typing.Callable[[], T_Result],
trace_context: typing.Callable[[], T_Result],
score_metadata: typing.Callable[[], T_Result],
score_provenance: typing.Callable[[], T_Result],
Comment on lines +44 to +45

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 Existing enum calls fail

Adding two required callbacks to BlobStorageExportFieldGroup.visit() breaks callers supplying the previous eleven callbacks. Even visiting an unchanged value such as CORE now raises TypeError before any callback runs. Give the new callbacks defaults so existing calls keep working for existing values.

Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/api/blob_storage_integrations/types/blob_storage_export_field_group.py
Line: 44-45

Comment:
**Existing enum calls fail**

Adding two required callbacks to `BlobStorageExportFieldGroup.visit()` breaks callers supplying the previous eleven callbacks. Even visiting an unchanged value such as `CORE` now raises `TypeError` before any callback runs. Give the new callbacks defaults so existing calls keep working for existing values.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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.

🤖 Written by Claude (an AI agent) on behalf of Niklas.

Declining. This is the visitor that Fern generates for every enum: adding a value always adds a required callback, and this PR follows the same pattern as earlier enum additions. Nothing in the SDK calls visit(), and the files under langfuse/api/ are regenerated from upstream, so a hand edit here would be overwritten on the next regeneration. If we want default callbacks, that has to be a Fern generator setting.

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.

That context is fair. My concern was source compatibility for downstream consumers that invoke the generated visitor directly, but since Fern intentionally makes every enum variant callback required and this file is regenerated, adding defaults here would be inconsistent and get overwritten. With no SDK-internal callers, I withdraw the finding for this PR.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

) -> T_Result:
if self is BlobStorageExportFieldGroup.CORE:
return core()
Expand All @@ -60,3 +66,7 @@ def visit(
return tools()
if self is BlobStorageExportFieldGroup.TRACE_CONTEXT:
return trace_context()
if self is BlobStorageExportFieldGroup.SCORE_METADATA:
return score_metadata()
if self is BlobStorageExportFieldGroup.SCORE_PROVENANCE:
return score_provenance()
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class BlobStorageIntegrationResponse(UniversalBaseModel):
FieldMetadata(alias="exportFieldGroups"),
] = pydantic.Field(default=None)
"""
Field groups included in each exported observation row. An empty list is treated as all groups during export.
Field groups included in each exported observation and score row. An empty list is treated as all observation groups and no score groups during export. Core score columns are always exported.
"""

next_sync_at: typing_extensions.Annotated[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class CreateBlobStorageIntegrationRequest(UniversalBaseModel):
FieldMetadata(alias="exportFieldGroups"),
] = pydantic.Field(default=None)
"""
Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved.
Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved.

`exportFieldGroups` requires `exportSource` to be provided in the same request.
"""
Expand Down
19 changes: 19 additions & 0 deletions langfuse/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from .scim.client import AsyncScimClient, ScimClient
from .score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient
from .scores.client import AsyncScoresClient, ScoresClient
from .skills.client import AsyncSkillsClient, SkillsClient
from .trace.client import AsyncTraceClient, TraceClient
from .unstable.client import AsyncUnstableClient, UnstableClient

Expand Down Expand Up @@ -147,6 +148,7 @@ def __init__(
self._scim: typing.Optional[ScimClient] = None
self._score_configs: typing.Optional[ScoreConfigsClient] = None
self._scores: typing.Optional[ScoresClient] = None
self._skills: typing.Optional[SkillsClient] = None
self._trace: typing.Optional[TraceClient] = None
self._unstable: typing.Optional[UnstableClient] = None

Expand Down Expand Up @@ -352,6 +354,14 @@ def scores(self):
self._scores = ScoresClient(client_wrapper=self._client_wrapper)
return self._scores

@property
def skills(self):
if self._skills is None:
from .skills.client import SkillsClient # noqa: E402

self._skills = SkillsClient(client_wrapper=self._client_wrapper)
return self._skills

@property
def trace(self):
if self._trace is None:
Expand Down Expand Up @@ -472,6 +482,7 @@ def __init__(
self._scim: typing.Optional[AsyncScimClient] = None
self._score_configs: typing.Optional[AsyncScoreConfigsClient] = None
self._scores: typing.Optional[AsyncScoresClient] = None
self._skills: typing.Optional[AsyncSkillsClient] = None
self._trace: typing.Optional[AsyncTraceClient] = None
self._unstable: typing.Optional[AsyncUnstableClient] = None

Expand Down Expand Up @@ -685,6 +696,14 @@ def scores(self):
self._scores = AsyncScoresClient(client_wrapper=self._client_wrapper)
return self._scores

@property
def skills(self):
if self._skills is None:
from .skills.client import AsyncSkillsClient # noqa: E402

self._skills = AsyncSkillsClient(client_wrapper=self._client_wrapper)
return self._skills

@property
def trace(self):
if self._trace is None:
Expand Down
6 changes: 5 additions & 1 deletion langfuse/api/commons/types/score_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ class ScoreConfig(UniversalBaseModel):
"""

id: str
name: str
name: str = pydantic.Field()
"""
Score config name. Maximum 80 characters.
"""

created_at: typing_extensions.Annotated[
dt.datetime, FieldMetadata(alias="createdAt")
]
Expand Down
Loading
Loading