From 6d03f47677ec0e00e346f900d259f3bd81352508 Mon Sep 17 00:00:00 2001
From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com>
Date: Wed, 28 May 2025 18:25:48 +0200
Subject: [PATCH 1/4] feat(scores): add session and dataset run scores
---
langfuse/_client/client.py | 15 +-
langfuse/_client/observe.py | 7 +-
langfuse/_client/resource_manager.py | 19 +-
langfuse/api/__init__.py | 90 +-
langfuse/api/client.py | 14 +
langfuse/api/reference.md | 1965 +++++++++++++++--
langfuse/api/resources/__init__.py | 105 +-
langfuse/api/resources/commons/__init__.py | 18 +
.../api/resources/commons/types/__init__.py | 15 +
.../api/resources/commons/types/base_score.py | 13 +-
.../resources/commons/types/base_score_v_1.py | 73 +
.../types/boolean_score_v_1.py} | 28 +-
.../commons/types/categorical_score_v_1.py | 53 +
langfuse/api/resources/commons/types/model.py | 11 +-
.../types/model_price.py} | 8 +-
.../commons/types/numeric_score_v_1.py | 48 +
langfuse/api/resources/commons/types/score.py | 39 +-
.../api/resources/commons/types/score_v_1.py | 189 ++
.../commons/types/trace_with_full_details.py | 4 +-
.../resources/dataset_run_items/__init__.py | 4 +-
.../api/resources/dataset_run_items/client.py | 267 +++
.../dataset_run_items/types/__init__.py | 3 +-
.../types/paginated_dataset_run_items.py} | 10 +-
.../resources/ingestion/types/score_body.py | 15 +-
langfuse/api/resources/metrics/__init__.py | 4 +-
langfuse/api/resources/metrics/client.py | 212 +-
.../api/resources/metrics/types/__init__.py | 6 +-
.../metrics/types/metrics_response.py | 46 +
langfuse/api/resources/observations/client.py | 4 +-
.../api/resources/organizations/__init__.py | 19 +
.../api/resources/organizations/client.py | 750 +++++++
.../resources/organizations/types/__init__.py | 17 +
.../organizations/types/membership_request.py | 46 +
.../types/membership_response.py | 48 +
.../organizations/types/membership_role.py | 29 +
.../types/memberships_response.py | 43 +
.../types/organization_project.py | 48 +
.../types/organization_projects_response.py | 43 +
langfuse/api/resources/projects/__init__.py | 20 +-
langfuse/api/resources/projects/client.py | 975 +++++++-
.../api/resources/projects/types/__init__.py | 15 +-
.../types/api_key_deletion_response.py | 46 +
.../types/api_key_list.py} | 12 +-
.../projects/types/api_key_response.py | 53 +
.../projects/types/api_key_summary.py | 58 +
.../api/resources/projects/types/project.py | 11 +
.../types/project_deletion_response.py | 43 +
langfuse/api/resources/scim/__init__.py | 41 +
langfuse/api/resources/scim/client.py | 1042 +++++++++
langfuse/api/resources/scim/types/__init__.py | 39 +
.../scim/types/authentication_scheme.py | 48 +
.../api/resources/scim/types/bulk_config.py | 46 +
.../resources/scim/types/empty_response.py | 44 +
.../api/resources/scim/types/filter_config.py | 45 +
.../api/resources/scim/types/resource_meta.py | 45 +
.../api/resources/scim/types/resource_type.py | 55 +
.../scim/types/resource_types_response.py | 47 +
.../resources/scim/types/schema_extension.py | 45 +
.../resources/scim/types/schema_resource.py | 47 +
.../resources/scim/types/schemas_response.py | 47 +
.../api/resources/scim/types/scim_email.py | 44 +
.../scim/types/scim_feature_support.py | 42 +
.../api/resources/scim/types/scim_name.py | 42 +
.../api/resources/scim/types/scim_user.py | 52 +
.../scim/types/scim_users_list_response.py | 49 +
.../scim/types/service_provider_config.py | 60 +
.../api/resources/scim/types/user_meta.py | 48 +
langfuse/api/resources/score/__init__.py | 28 +-
langfuse/api/resources/score/client.py | 448 +---
.../api/resources/score/types/__init__.py | 25 +-
.../score/types/create_score_request.py | 15 +-
langfuse/api/resources/score_v_2/__init__.py | 25 +
langfuse/api/resources/score_v_2/client.py | 463 ++++
.../api/resources/score_v_2/types/__init__.py | 25 +
.../types/get_scores_response.py | 0
.../types/get_scores_response_data.py | 45 +-
.../types/get_scores_response_data_boolean.py | 2 +-
.../get_scores_response_data_categorical.py | 2 +-
.../types/get_scores_response_data_numeric.py | 2 +-
.../types/get_scores_response_trace_data.py | 0
80 files changed, 7616 insertions(+), 953 deletions(-)
create mode 100644 langfuse/api/resources/commons/types/base_score_v_1.py
rename langfuse/api/resources/{metrics/types/usage_by_model.py => commons/types/boolean_score_v_1.py} (61%)
create mode 100644 langfuse/api/resources/commons/types/categorical_score_v_1.py
rename langfuse/api/resources/{ingestion/types/open_ai_usage_schema.py => commons/types/model_price.py} (81%)
create mode 100644 langfuse/api/resources/commons/types/numeric_score_v_1.py
create mode 100644 langfuse/api/resources/commons/types/score_v_1.py
rename langfuse/api/resources/{metrics/types/daily_metrics.py => dataset_run_items/types/paginated_dataset_run_items.py} (83%)
create mode 100644 langfuse/api/resources/metrics/types/metrics_response.py
create mode 100644 langfuse/api/resources/organizations/__init__.py
create mode 100644 langfuse/api/resources/organizations/client.py
create mode 100644 langfuse/api/resources/organizations/types/__init__.py
create mode 100644 langfuse/api/resources/organizations/types/membership_request.py
create mode 100644 langfuse/api/resources/organizations/types/membership_response.py
create mode 100644 langfuse/api/resources/organizations/types/membership_role.py
create mode 100644 langfuse/api/resources/organizations/types/memberships_response.py
create mode 100644 langfuse/api/resources/organizations/types/organization_project.py
create mode 100644 langfuse/api/resources/organizations/types/organization_projects_response.py
create mode 100644 langfuse/api/resources/projects/types/api_key_deletion_response.py
rename langfuse/api/resources/{metrics/types/daily_metrics_details.py => projects/types/api_key_list.py} (77%)
create mode 100644 langfuse/api/resources/projects/types/api_key_response.py
create mode 100644 langfuse/api/resources/projects/types/api_key_summary.py
create mode 100644 langfuse/api/resources/projects/types/project_deletion_response.py
create mode 100644 langfuse/api/resources/scim/__init__.py
create mode 100644 langfuse/api/resources/scim/client.py
create mode 100644 langfuse/api/resources/scim/types/__init__.py
create mode 100644 langfuse/api/resources/scim/types/authentication_scheme.py
create mode 100644 langfuse/api/resources/scim/types/bulk_config.py
create mode 100644 langfuse/api/resources/scim/types/empty_response.py
create mode 100644 langfuse/api/resources/scim/types/filter_config.py
create mode 100644 langfuse/api/resources/scim/types/resource_meta.py
create mode 100644 langfuse/api/resources/scim/types/resource_type.py
create mode 100644 langfuse/api/resources/scim/types/resource_types_response.py
create mode 100644 langfuse/api/resources/scim/types/schema_extension.py
create mode 100644 langfuse/api/resources/scim/types/schema_resource.py
create mode 100644 langfuse/api/resources/scim/types/schemas_response.py
create mode 100644 langfuse/api/resources/scim/types/scim_email.py
create mode 100644 langfuse/api/resources/scim/types/scim_feature_support.py
create mode 100644 langfuse/api/resources/scim/types/scim_name.py
create mode 100644 langfuse/api/resources/scim/types/scim_user.py
create mode 100644 langfuse/api/resources/scim/types/scim_users_list_response.py
create mode 100644 langfuse/api/resources/scim/types/service_provider_config.py
create mode 100644 langfuse/api/resources/scim/types/user_meta.py
create mode 100644 langfuse/api/resources/score_v_2/__init__.py
create mode 100644 langfuse/api/resources/score_v_2/client.py
create mode 100644 langfuse/api/resources/score_v_2/types/__init__.py
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response.py (100%)
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response_data.py (84%)
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response_data_boolean.py (95%)
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response_data_categorical.py (95%)
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response_data_numeric.py (95%)
rename langfuse/api/resources/{score => score_v_2}/types/get_scores_response_trace_data.py (100%)
diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py
index d262f5047..97f5ca72b 100644
--- a/langfuse/_client/client.py
+++ b/langfuse/_client/client.py
@@ -1221,6 +1221,7 @@ def create_score(
data_type: Optional[Literal["NUMERIC", "BOOLEAN"]] = None,
comment: Optional[str] = None,
config_id: Optional[str] = None,
+ metadata: Optional[Any] = None,
) -> None: ...
@overload
@@ -1235,6 +1236,7 @@ def create_score(
data_type: Optional[Literal["CATEGORICAL"]] = "CATEGORICAL",
comment: Optional[str] = None,
config_id: Optional[str] = None,
+ metadata: Optional[Any] = None,
) -> None: ...
def create_score(
@@ -1242,12 +1244,15 @@ def create_score(
*,
name: str,
value: Union[float, str],
- trace_id: str,
+ session_id: Optional[str] = None,
+ dataset_run_id: Optional[str] = None,
+ trace_id: Optional[str] = None,
observation_id: Optional[str] = None,
score_id: Optional[str] = None,
data_type: Optional[ScoreDataType] = None,
comment: Optional[str] = None,
config_id: Optional[str] = None,
+ metadata: Optional[Any] = None,
) -> None:
"""Create a score for a specific trace or observation.
@@ -1257,12 +1262,15 @@ def create_score(
Args:
name: Name of the score (e.g., "relevance", "accuracy")
value: Score value (can be numeric for NUMERIC/BOOLEAN types or string for CATEGORICAL)
+ session_id: ID of the Langfuse session to associate the score with
+ dataset_run_id: ID of the Langfuse dataset run to associate the score with
trace_id: ID of the Langfuse trace to associate the score with
- observation_id: Optional ID of the specific observation to score
+ observation_id: Optional ID of the specific observation to score. Trace ID must be provided too.
score_id: Optional custom ID for the score (auto-generated if not provided)
data_type: Type of score (NUMERIC, BOOLEAN, or CATEGORICAL)
comment: Optional comment or explanation for the score
config_id: Optional ID of a score config defined in Langfuse
+ metadata: Optional metadata to be attached to the score
Example:
```python
@@ -1293,6 +1301,8 @@ def create_score(
try:
score_event = {
"id": score_id,
+ "session_id": session_id,
+ "dataset_run_id": dataset_run_id,
"trace_id": trace_id,
"observation_id": observation_id,
"name": name,
@@ -1301,6 +1311,7 @@ def create_score(
"comment": comment,
"config_id": config_id,
"environment": self._environment,
+ "metadata": metadata,
}
new_body = ScoreBody(**score_event)
diff --git a/langfuse/_client/observe.py b/langfuse/_client/observe.py
index 8416ffd46..cdfb04d7b 100644
--- a/langfuse/_client/observe.py
+++ b/langfuse/_client/observe.py
@@ -145,10 +145,9 @@ def sub_process():
- For async functions, the decorator returns an async function wrapper.
- For sync functions, the decorator returns a synchronous wrapper.
"""
- function_io_capture_enabled = (
- os.environ.get(LANGFUSE_OBSERVE_DECORATOR_IO_CAPTURE_ENABLED, "True")
- .lower() not in ("false", "0")
- )
+ function_io_capture_enabled = os.environ.get(
+ LANGFUSE_OBSERVE_DECORATOR_IO_CAPTURE_ENABLED, "True"
+ ).lower() not in ("false", "0")
def decorator(func: F) -> F:
return (
diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py
index 1c07de57c..548a637d9 100644
--- a/langfuse/_client/resource_manager.py
+++ b/langfuse/_client/resource_manager.py
@@ -256,13 +256,18 @@ def add_score_task(self, event: dict):
# Sample scores with the same sampler that is used for tracing
tracer_provider = cast(TracerProvider, otel_trace_api.get_tracer_provider())
should_sample = (
- tracer_provider.sampler.should_sample(
- parent_context=None,
- trace_id=int(event["body"].trace_id, 16),
- name="score",
- ).decision
- == Decision.RECORD_AND_SAMPLE
- if hasattr(event["body"], "trace_id")
+ (
+ tracer_provider.sampler.should_sample(
+ parent_context=None,
+ trace_id=int(event["body"].trace_id, 16),
+ name="score",
+ ).decision
+ == Decision.RECORD_AND_SAMPLE
+ if hasattr(event["body"], "trace_id")
+ else True
+ )
+ if event["body"].trace_id
+ is not None # do not sample out session / dataset run scores
else True
)
diff --git a/langfuse/api/__init__.py b/langfuse/api/__init__.py
index d59e65d4c..bf6bdb508 100644
--- a/langfuse/api/__init__.py
+++ b/langfuse/api/__init__.py
@@ -6,11 +6,20 @@
AnnotationQueueItem,
AnnotationQueueObjectType,
AnnotationQueueStatus,
+ ApiKeyDeletionResponse,
+ ApiKeyList,
+ ApiKeyResponse,
+ ApiKeySummary,
+ AuthenticationScheme,
BaseEvent,
BasePrompt,
BaseScore,
+ BaseScoreV1,
BooleanScore,
+ BooleanScoreV1,
+ BulkConfig,
CategoricalScore,
+ CategoricalScoreV1,
ChatMessage,
ChatPrompt,
Comment,
@@ -39,8 +48,6 @@
CreateSpanBody,
CreateSpanEvent,
CreateTextPromptRequest,
- DailyMetrics,
- DailyMetricsDetails,
Dataset,
DatasetItem,
DatasetRun,
@@ -51,7 +58,9 @@
DeleteDatasetItemResponse,
DeleteDatasetRunResponse,
DeleteTraceResponse,
+ EmptyResponse,
Error,
+ FilterConfig,
GetCommentsResponse,
GetMediaResponse,
GetMediaUploadUrlRequest,
@@ -83,11 +92,18 @@
IngestionUsage,
MapValue,
MediaContentType,
+ MembershipRequest,
+ MembershipResponse,
+ MembershipRole,
+ MembershipsResponse,
MethodNotAllowedError,
+ MetricsResponse,
Model,
+ ModelPrice,
ModelUsageUnit,
NotFoundError,
NumericScore,
+ NumericScoreV1,
Observation,
ObservationBody,
ObservationLevel,
@@ -99,21 +115,36 @@
OpenAiResponseUsageSchema,
OpenAiUsage,
OptionalObservationBody,
+ OrganizationProject,
+ OrganizationProjectsResponse,
PaginatedAnnotationQueueItems,
PaginatedAnnotationQueues,
PaginatedDatasetItems,
+ PaginatedDatasetRunItems,
PaginatedDatasetRuns,
PaginatedDatasets,
PaginatedModels,
PaginatedSessions,
PatchMediaBody,
Project,
+ ProjectDeletionResponse,
Projects,
Prompt,
PromptMeta,
PromptMetaListResponse,
Prompt_Chat,
Prompt_Text,
+ ResourceMeta,
+ ResourceType,
+ ResourceTypesResponse,
+ SchemaExtension,
+ SchemaResource,
+ SchemasResponse,
+ ScimEmail,
+ ScimFeatureSupport,
+ ScimName,
+ ScimUser,
+ ScimUsersListResponse,
Score,
ScoreBody,
ScoreConfig,
@@ -121,11 +152,16 @@
ScoreDataType,
ScoreEvent,
ScoreSource,
+ ScoreV1,
+ ScoreV1_Boolean,
+ ScoreV1_Categorical,
+ ScoreV1_Numeric,
Score_Boolean,
Score_Categorical,
Score_Numeric,
SdkLogBody,
SdkLogEvent,
+ ServiceProviderConfig,
ServiceUnavailableError,
Session,
SessionWithTraces,
@@ -146,8 +182,8 @@
UpdateSpanBody,
UpdateSpanEvent,
Usage,
- UsageByModel,
UsageDetails,
+ UserMeta,
annotation_queues,
comments,
commons,
@@ -160,11 +196,14 @@
metrics,
models,
observations,
+ organizations,
projects,
prompt_version,
prompts,
+ scim,
score,
score_configs,
+ score_v_2,
sessions,
trace,
utils,
@@ -176,11 +215,20 @@
"AnnotationQueueItem",
"AnnotationQueueObjectType",
"AnnotationQueueStatus",
+ "ApiKeyDeletionResponse",
+ "ApiKeyList",
+ "ApiKeyResponse",
+ "ApiKeySummary",
+ "AuthenticationScheme",
"BaseEvent",
"BasePrompt",
"BaseScore",
+ "BaseScoreV1",
"BooleanScore",
+ "BooleanScoreV1",
+ "BulkConfig",
"CategoricalScore",
+ "CategoricalScoreV1",
"ChatMessage",
"ChatPrompt",
"Comment",
@@ -209,8 +257,6 @@
"CreateSpanBody",
"CreateSpanEvent",
"CreateTextPromptRequest",
- "DailyMetrics",
- "DailyMetricsDetails",
"Dataset",
"DatasetItem",
"DatasetRun",
@@ -221,7 +267,9 @@
"DeleteDatasetItemResponse",
"DeleteDatasetRunResponse",
"DeleteTraceResponse",
+ "EmptyResponse",
"Error",
+ "FilterConfig",
"GetCommentsResponse",
"GetMediaResponse",
"GetMediaUploadUrlRequest",
@@ -253,11 +301,18 @@
"IngestionUsage",
"MapValue",
"MediaContentType",
+ "MembershipRequest",
+ "MembershipResponse",
+ "MembershipRole",
+ "MembershipsResponse",
"MethodNotAllowedError",
+ "MetricsResponse",
"Model",
+ "ModelPrice",
"ModelUsageUnit",
"NotFoundError",
"NumericScore",
+ "NumericScoreV1",
"Observation",
"ObservationBody",
"ObservationLevel",
@@ -269,21 +324,36 @@
"OpenAiResponseUsageSchema",
"OpenAiUsage",
"OptionalObservationBody",
+ "OrganizationProject",
+ "OrganizationProjectsResponse",
"PaginatedAnnotationQueueItems",
"PaginatedAnnotationQueues",
"PaginatedDatasetItems",
+ "PaginatedDatasetRunItems",
"PaginatedDatasetRuns",
"PaginatedDatasets",
"PaginatedModels",
"PaginatedSessions",
"PatchMediaBody",
"Project",
+ "ProjectDeletionResponse",
"Projects",
"Prompt",
"PromptMeta",
"PromptMetaListResponse",
"Prompt_Chat",
"Prompt_Text",
+ "ResourceMeta",
+ "ResourceType",
+ "ResourceTypesResponse",
+ "SchemaExtension",
+ "SchemaResource",
+ "SchemasResponse",
+ "ScimEmail",
+ "ScimFeatureSupport",
+ "ScimName",
+ "ScimUser",
+ "ScimUsersListResponse",
"Score",
"ScoreBody",
"ScoreConfig",
@@ -291,11 +361,16 @@
"ScoreDataType",
"ScoreEvent",
"ScoreSource",
+ "ScoreV1",
+ "ScoreV1_Boolean",
+ "ScoreV1_Categorical",
+ "ScoreV1_Numeric",
"Score_Boolean",
"Score_Categorical",
"Score_Numeric",
"SdkLogBody",
"SdkLogEvent",
+ "ServiceProviderConfig",
"ServiceUnavailableError",
"Session",
"SessionWithTraces",
@@ -316,8 +391,8 @@
"UpdateSpanBody",
"UpdateSpanEvent",
"Usage",
- "UsageByModel",
"UsageDetails",
+ "UserMeta",
"annotation_queues",
"comments",
"commons",
@@ -330,11 +405,14 @@
"metrics",
"models",
"observations",
+ "organizations",
"projects",
"prompt_version",
"prompts",
+ "scim",
"score",
"score_configs",
+ "score_v_2",
"sessions",
"trace",
"utils",
diff --git a/langfuse/api/client.py b/langfuse/api/client.py
index 77a09a416..87b46c2f8 100644
--- a/langfuse/api/client.py
+++ b/langfuse/api/client.py
@@ -22,14 +22,20 @@
from .resources.metrics.client import AsyncMetricsClient, MetricsClient
from .resources.models.client import AsyncModelsClient, ModelsClient
from .resources.observations.client import AsyncObservationsClient, ObservationsClient
+from .resources.organizations.client import (
+ AsyncOrganizationsClient,
+ OrganizationsClient,
+)
from .resources.projects.client import AsyncProjectsClient, ProjectsClient
from .resources.prompt_version.client import (
AsyncPromptVersionClient,
PromptVersionClient,
)
from .resources.prompts.client import AsyncPromptsClient, PromptsClient
+from .resources.scim.client import AsyncScimClient, ScimClient
from .resources.score.client import AsyncScoreClient, ScoreClient
from .resources.score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient
+from .resources.score_v_2.client import AsyncScoreV2Client, ScoreV2Client
from .resources.sessions.client import AsyncSessionsClient, SessionsClient
from .resources.trace.client import AsyncTraceClient, TraceClient
@@ -118,10 +124,13 @@ def __init__(
self.metrics = MetricsClient(client_wrapper=self._client_wrapper)
self.models = ModelsClient(client_wrapper=self._client_wrapper)
self.observations = ObservationsClient(client_wrapper=self._client_wrapper)
+ self.organizations = OrganizationsClient(client_wrapper=self._client_wrapper)
self.projects = ProjectsClient(client_wrapper=self._client_wrapper)
self.prompt_version = PromptVersionClient(client_wrapper=self._client_wrapper)
self.prompts = PromptsClient(client_wrapper=self._client_wrapper)
+ self.scim = ScimClient(client_wrapper=self._client_wrapper)
self.score_configs = ScoreConfigsClient(client_wrapper=self._client_wrapper)
+ self.score_v_2 = ScoreV2Client(client_wrapper=self._client_wrapper)
self.score = ScoreClient(client_wrapper=self._client_wrapper)
self.sessions = SessionsClient(client_wrapper=self._client_wrapper)
self.trace = TraceClient(client_wrapper=self._client_wrapper)
@@ -213,14 +222,19 @@ def __init__(
self.metrics = AsyncMetricsClient(client_wrapper=self._client_wrapper)
self.models = AsyncModelsClient(client_wrapper=self._client_wrapper)
self.observations = AsyncObservationsClient(client_wrapper=self._client_wrapper)
+ self.organizations = AsyncOrganizationsClient(
+ client_wrapper=self._client_wrapper
+ )
self.projects = AsyncProjectsClient(client_wrapper=self._client_wrapper)
self.prompt_version = AsyncPromptVersionClient(
client_wrapper=self._client_wrapper
)
self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper)
+ self.scim = AsyncScimClient(client_wrapper=self._client_wrapper)
self.score_configs = AsyncScoreConfigsClient(
client_wrapper=self._client_wrapper
)
+ self.score_v_2 = AsyncScoreV2Client(client_wrapper=self._client_wrapper)
self.score = AsyncScoreClient(client_wrapper=self._client_wrapper)
self.sessions = AsyncSessionsClient(client_wrapper=self._client_wrapper)
self.trace = AsyncTraceClient(client_wrapper=self._client_wrapper)
diff --git a/langfuse/api/reference.md b/langfuse/api/reference.md
index c52f406fc..4b249b575 100644
--- a/langfuse/api/reference.md
+++ b/langfuse/api/reference.md
@@ -1277,6 +1277,154 @@ client.dataset_run_items.create(
+
+
+
+
+client.dataset_run_items.list(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+List dataset run items
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import datetime
+
+from langfuse import DatasetRunItem, PaginatedDatasetRunItems
+from langfuse.client import FernLangfuse
+from langfuse.resources.utils import MetaResponse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.dataset_run_items.list(
+ dataset_id="datasetId",
+ run_name="runName",
+ response=PaginatedDatasetRunItems(
+ data=[
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ ],
+ meta=MetaResponse(
+ page=1,
+ limit=1,
+ total_items=1,
+ total_pages=1,
+ ),
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**dataset_id:** `str`
+
+
+
+
+
+-
+
+**run_name:** `str`
+
+
+
+
+
+-
+
+**response:** `PaginatedDatasetRunItems`
+
+
+
+
+
+-
+
+**page:** `typing.Optional[int]` — page number, starts at 1
+
+
+
+
+
+-
+
+**limit:** `typing.Optional[int]` — limit of items per page
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -2202,7 +2350,7 @@ client.media.get_upload_url(
## Metrics
-client.metrics.daily(...)
+client.metrics.metrics(...)
-
@@ -2214,7 +2362,7 @@ client.media.get_upload_url(
-
-Get daily metrics of the Langfuse project
+Get metrics from the Langfuse project using a query object
@@ -2239,7 +2387,9 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.metrics.daily()
+client.metrics.metrics(
+ query="query",
+)
```
@@ -2255,63 +2405,45 @@ client.metrics.daily()
-
-**page:** `typing.Optional[int]` — page number, starts at 1
-
-
-
-
-
--
-
-**limit:** `typing.Optional[int]` — limit of items per page
-
-
-
-
-
--
-
-**trace_name:** `typing.Optional[str]` — Optional filter by the name of the trace
-
-
-
-
-
--
-
-**user_id:** `typing.Optional[str]` — Optional filter by the userId associated with the trace
-
-
-
-
-
--
-
-**tags:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for metrics where traces include all of these tags
-
-
-
-
-
--
-
-**environment:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for metrics where events include any of these environments
-
-
-
-
-
--
-
-**from_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include traces and observations on or after a certain datetime (ISO 8601)
-
-
-
-
-
--
-
-**to_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include traces and observations before a certain datetime (ISO 8601)
+**query:** `str`
+
+JSON string containing the query parameters with the following structure:
+```json
+{
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
+ "dimensions": [ // Optional. Default: []
+ {
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
+ }
+ ],
+ "metrics": [ // Required. At least one metric must be provided
+ {
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95"
+ }
+ ],
+ "filters": [ // Optional. Default: []
+ {
+ "column": string, // Column to filter on
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
+ "value": any, // Value to compare against
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
+ "key": string // Required only when filtering on metadata
+ }
+ ],
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
+ },
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
+ "orderBy": [ // Optional. Default: null
+ {
+ "field": string, // Field to order by
+ "direction": string // "asc" or "desc"
+ }
+ ]
+}
+```
@@ -2835,7 +2967,7 @@ client.observations.get_many()
-
-**from_start_time:** `typing.Optional[dt.datetime]` — Retrieve only observations with a start_time or or after this datetime (ISO 8601).
+**from_start_time:** `typing.Optional[dt.datetime]` — Retrieve only observations with a start_time on or after this datetime (ISO 8601).
@@ -2871,8 +3003,8 @@ client.observations.get_many()
-## Projects
-client.projects.get()
+## Organizations
+client.organizations.get_organization_memberships()
-
@@ -2884,7 +3016,7 @@ client.observations.get_many()
-
-Get Project associated with API key
+Get all memberships for the organization associated with the API key (requires organization-scoped API key)
@@ -2909,7 +3041,7 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.projects.get()
+client.organizations.get_organization_memberships()
```
@@ -2937,8 +3069,7 @@ client.projects.get()
-## PromptVersion
-client.prompt_version.update(...)
+client.organizations.update_organization_membership(...)
-
@@ -2950,7 +3081,7 @@ client.projects.get()
-
-Update labels for a specific prompt version
+Create or update a membership for the organization associated with the API key (requires organization-scoped API key)
@@ -2965,6 +3096,7 @@ Update labels for a specific prompt version
-
```python
+from langfuse import MembershipRequest, MembershipRole
from langfuse.client import FernLangfuse
client = FernLangfuse(
@@ -2975,10 +3107,11 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.prompt_version.update(
- name="name",
- version=1,
- new_labels=["newLabels", "newLabels"],
+client.organizations.update_organization_membership(
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
)
```
@@ -2995,23 +3128,7 @@ client.prompt_version.update(
-
-**name:** `str` — The name of the prompt
-
-
-
-
-
--
-
-**version:** `int` — Version of the prompt to update
-
-
-
-
-
--
-
-**new_labels:** `typing.Sequence[str]` — New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse.
+**request:** `MembershipRequest`
@@ -3031,8 +3148,7 @@ client.prompt_version.update(
-## Prompts
-client.prompts.get(...)
+client.organizations.get_project_memberships(...)
-
@@ -3044,7 +3160,7 @@ client.prompt_version.update(
-
-Get a prompt
+Get all memberships for a specific project (requires organization-scoped API key)
@@ -3069,8 +3185,8 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.prompts.get(
- prompt_name="promptName",
+client.organizations.get_project_memberships(
+ project_id="projectId",
)
```
@@ -3087,23 +3203,7 @@ client.prompts.get(
-
-**prompt_name:** `str` — The name of the prompt
-
-
-
-
-
--
-
-**version:** `typing.Optional[int]` — Version of the prompt to be retrieved.
-
-
-
-
-
--
-
-**label:** `typing.Optional[str]` — Label of the prompt to be retrieved. Defaults to "production" if no label or version is set.
+**project_id:** `str`
@@ -3123,7 +3223,7 @@ client.prompts.get(
-client.prompts.list(...)
+client.organizations.update_project_membership(...)
-
@@ -3135,7 +3235,7 @@ client.prompts.get(
-
-Get a list of prompt names with versions and labels
+Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization.
@@ -3150,6 +3250,7 @@ Get a list of prompt names with versions and labels
-
```python
+from langfuse import MembershipRequest, MembershipRole
from langfuse.client import FernLangfuse
client = FernLangfuse(
@@ -3160,7 +3261,13 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.prompts.list()
+client.organizations.update_project_membership(
+ project_id="projectId",
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
+)
```
@@ -3176,7 +3283,7 @@ client.prompts.list()
-
-**name:** `typing.Optional[str]`
+**project_id:** `str`
@@ -3184,7 +3291,7 @@ client.prompts.list()
-
-**label:** `typing.Optional[str]`
+**request:** `MembershipRequest`
@@ -3192,63 +3299,971 @@ client.prompts.list()
-
-**tag:** `typing.Optional[str]`
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
-
-
--
-
-**page:** `typing.Optional[int]` — page number, starts at 1
-
-
--
-**limit:** `typing.Optional[int]` — limit of items per page
-
+
+client.organizations.get_organization_projects()
-
-**from_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601)
-
-
-
+#### 📝 Description
-
-**to_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601)
-
-
-
-
-
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
-
-
-
+Get all projects for the organization associated with the API key (requires organization-scoped API key)
-
-
-
-
-client.prompts.create(...)
-
--
-#### 📝 Description
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.organizations.get_organization_projects()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Projects
+client.projects.get()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get Project associated with API key
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.get()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.create(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a new project (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.create(
+ name="name",
+ retention=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**name:** `str`
+
+
+
+
+
+-
+
+**retention:** `int` — Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+
+
+
+
+-
+
+**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]` — Optional metadata for the project
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.update(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Update a project by ID (requires organization-scoped API key).
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.update(
+ project_id="projectId",
+ name="name",
+ retention=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**name:** `str`
+
+
+
+
+
+-
+
+**retention:** `int` — Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+
+
+
+
+-
+
+**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]` — Optional metadata for the project
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.delete(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.delete(
+ project_id="projectId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.get_api_keys(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get all API keys for a project (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.get_api_keys(
+ project_id="projectId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.create_api_key(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a new API key for a project (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.create_api_key(
+ project_id="projectId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**note:** `typing.Optional[str]` — Optional note for the API key
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.delete_api_key(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Delete an API key for a project (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.projects.delete_api_key(
+ project_id="projectId",
+ api_key_id="apiKeyId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**api_key_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## PromptVersion
+client.prompt_version.update(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Update labels for a specific prompt version
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.prompt_version.update(
+ name="name",
+ version=1,
+ new_labels=["newLabels", "newLabels"],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**name:** `str` — The name of the prompt
+
+
+
+
+
+-
+
+**version:** `int` — Version of the prompt to update
+
+
+
+
+
+-
+
+**new_labels:** `typing.Sequence[str]` — New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Prompts
+client.prompts.get(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get a prompt
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.prompts.get(
+ prompt_name="promptName",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**prompt_name:** `str` — The name of the prompt
+
+
+
+
+
+-
+
+**version:** `typing.Optional[int]` — Version of the prompt to be retrieved.
+
+
+
+
+
+-
+
+**label:** `typing.Optional[str]` — Label of the prompt to be retrieved. Defaults to "production" if no label or version is set.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.prompts.list(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get a list of prompt names with versions and labels
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.prompts.list()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**name:** `typing.Optional[str]`
+
+
+
+
+
+-
+
+**label:** `typing.Optional[str]`
+
+
+
+
+
+-
+
+**tag:** `typing.Optional[str]`
+
+
+
+
+
+-
+
+**page:** `typing.Optional[int]` — page number, starts at 1
+
+
+
+
+
+-
+
+**limit:** `typing.Optional[int]` — limit of items per page
+
+
+
+
+
+-
+
+**from_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601)
+
+
+
+
+
+-
+
+**to_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601)
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.prompts.create(...)
+
+-
+
+#### 📝 Description
-
@@ -3271,7 +4286,380 @@ Create a new version for the prompt with the given `name`
-
```python
-from langfuse import ChatMessage, CreatePromptRequest_Chat
+from langfuse import ChatMessage, CreatePromptRequest_Chat
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.prompts.create(
+ request=CreatePromptRequest_Chat(
+ name="name",
+ prompt=[
+ ChatMessage(
+ role="role",
+ content="content",
+ ),
+ ChatMessage(
+ role="role",
+ content="content",
+ ),
+ ],
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request:** `CreatePromptRequest`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Scim
+client.scim.get_service_provider_config()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get SCIM Service Provider Configuration (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.scim.get_service_provider_config()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scim.get_resource_types()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get SCIM Resource Types (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.scim.get_resource_types()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scim.get_schemas()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Get SCIM Schemas (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.scim.get_schemas()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scim.list_users(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+List users in the organization (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.scim.list_users()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**filter:** `typing.Optional[str]` — Filter expression (e.g. userName eq "value")
+
+
+
+
+
+-
+
+**start_index:** `typing.Optional[int]` — 1-based index of the first result to return (default 1)
+
+
+
+
+
+-
+
+**count:** `typing.Optional[int]` — Maximum number of results to return (default 100)
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scim.create_user(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a new user in the organization (requires organization-scoped API key)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse import ScimName
from langfuse.client import FernLangfuse
client = FernLangfuse(
@@ -3282,20 +4670,9 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.prompts.create(
- request=CreatePromptRequest_Chat(
- name="name",
- prompt=[
- ChatMessage(
- role="role",
- content="content",
- ),
- ChatMessage(
- role="role",
- content="content",
- ),
- ],
- ),
+client.scim.create_user(
+ user_name="userName",
+ name=ScimName(),
)
```
@@ -3312,7 +4689,39 @@ client.prompts.create(
-
-**request:** `CreatePromptRequest`
+**user_name:** `str` — User's email address (required)
+
+
+
+
+
+-
+
+**name:** `ScimName` — User's name information
+
+
+
+
+
+-
+
+**emails:** `typing.Optional[typing.Sequence[ScimEmail]]` — User's email addresses
+
+
+
+
+
+-
+
+**active:** `typing.Optional[bool]` — Whether the user is active
+
+
+
+
+
+-
+
+**password:** `typing.Optional[str]` — Initial password for the user
@@ -3332,8 +4741,7 @@ client.prompts.create(
-## ScoreConfigs
-client.score_configs.create(...)
+client.scim.get_user(...)
-
@@ -3345,7 +4753,7 @@ client.prompts.create(
-
-Create a score configuration (config). Score configs are used to define the structure of scores
+Get a specific user by ID (requires organization-scoped API key)
@@ -3360,7 +4768,6 @@ Create a score configuration (config). Score configs are used to define the stru
-
```python
-from langfuse import CreateScoreConfigRequest, ScoreDataType
from langfuse.client import FernLangfuse
client = FernLangfuse(
@@ -3371,11 +4778,8 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score_configs.create(
- request=CreateScoreConfigRequest(
- name="name",
- data_type=ScoreDataType.NUMERIC,
- ),
+client.scim.get_user(
+ user_id="userId",
)
```
@@ -3392,7 +4796,7 @@ client.score_configs.create(
-
-**request:** `CreateScoreConfigRequest`
+**user_id:** `str`
@@ -3412,7 +4816,7 @@ client.score_configs.create(
-client.score_configs.get(...)
+client.scim.delete_user(...)
-
@@ -3424,7 +4828,7 @@ client.score_configs.create(
-
-Get all score configs
+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.
@@ -3449,7 +4853,9 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score_configs.get()
+client.scim.delete_user(
+ user_id="userId",
+)
```
@@ -3465,7 +4871,7 @@ client.score_configs.get()
-
-**page:** `typing.Optional[int]` — Page number, starts at 1.
+**user_id:** `str`
@@ -3473,7 +4879,79 @@ client.score_configs.get()
-
-**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## ScoreConfigs
+client.score_configs.create(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a score configuration (config). Score configs are used to define the structure of scores
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse import CreateScoreConfigRequest, ScoreDataType
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.score_configs.create(
+ request=CreateScoreConfigRequest(
+ name="name",
+ data_type=ScoreDataType.NUMERIC,
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request:** `CreateScoreConfigRequest`
@@ -3493,7 +4971,7 @@ client.score_configs.get()
-client.score_configs.get_by_id(...)
+client.score_configs.get(...)
-
@@ -3505,7 +4983,7 @@ client.score_configs.get()
-
-Get a score config
+Get all score configs
@@ -3530,9 +5008,7 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score_configs.get_by_id(
- config_id="configId",
-)
+client.score_configs.get()
```
@@ -3548,7 +5024,15 @@ client.score_configs.get_by_id(
-
-**config_id:** `str` — The unique langfuse identifier of a score config
+**page:** `typing.Optional[int]` — Page number, starts at 1.
+
+
+
+
+
+-
+
+**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit
@@ -3568,8 +5052,7 @@ client.score_configs.get_by_id(
-## Score
-client.score.create(...)
+client.score_configs.get_by_id(...)
-
@@ -3581,7 +5064,7 @@ client.score_configs.get_by_id(
-
-Create a score
+Get a score config
@@ -3596,7 +5079,6 @@ Create a score
-
```python
-from langfuse import CreateScoreRequest
from langfuse.client import FernLangfuse
client = FernLangfuse(
@@ -3607,12 +5089,8 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score.create(
- request=CreateScoreRequest(
- trace_id="traceId",
- name="name",
- value=1.1,
- ),
+client.score_configs.get_by_id(
+ config_id="configId",
)
```
@@ -3629,7 +5107,7 @@ client.score.create(
-
-**request:** `CreateScoreRequest`
+**config_id:** `str` — The unique langfuse identifier of a score config
@@ -3649,7 +5127,8 @@ client.score.create(
-client.score.get(...)
+## ScoreV2
+client.score_v_2.get(...)
-
@@ -3661,7 +5140,7 @@ client.score.create(
-
-Get a list of scores
+Get a list of scores (supports both trace and session scores)
@@ -3686,7 +5165,7 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score.get()
+client.score_v_2.get()
```
@@ -3834,7 +5313,7 @@ client.score.get()
-client.score.get_by_id(...)
+client.score_v_2.get_by_id(...)
-
@@ -3846,7 +5325,7 @@ client.score.get()
-
-Get a score
+Get a score (supports both trace and session scores)
@@ -3871,7 +5350,7 @@ client = FernLangfuse(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
-client.score.get_by_id(
+client.score_v_2.get_by_id(
score_id="scoreId",
)
@@ -3905,6 +5384,86 @@ client.score.get_by_id(
+
+
+
+
+## Score
+client.score.create(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a score (supports both trace and session scores)
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from langfuse import CreateScoreRequest
+from langfuse.client import FernLangfuse
+
+client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+)
+client.score.create(
+ request=CreateScoreRequest(
+ name="name",
+ value=1.1,
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request:** `CreateScoreRequest`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -3921,7 +5480,7 @@ client.score.get_by_id(
-
-Delete a score
+Delete a score (supports both trace and session scores)
diff --git a/langfuse/api/resources/__init__.py b/langfuse/api/resources/__init__.py
index b65a40b49..6ddea00eb 100644
--- a/langfuse/api/resources/__init__.py
+++ b/langfuse/api/resources/__init__.py
@@ -13,11 +13,14 @@
metrics,
models,
observations,
+ organizations,
projects,
prompt_version,
prompts,
+ scim,
score,
score_configs,
+ score_v_2,
sessions,
trace,
utils,
@@ -37,8 +40,11 @@
from .commons import (
AccessDeniedError,
BaseScore,
+ BaseScoreV1,
BooleanScore,
+ BooleanScoreV1,
CategoricalScore,
+ CategoricalScoreV1,
Comment,
CommentObjectType,
ConfigCategory,
@@ -53,9 +59,11 @@
MapValue,
MethodNotAllowedError,
Model,
+ ModelPrice,
ModelUsageUnit,
NotFoundError,
NumericScore,
+ NumericScoreV1,
Observation,
ObservationLevel,
ObservationsView,
@@ -63,6 +71,10 @@
ScoreConfig,
ScoreDataType,
ScoreSource,
+ ScoreV1,
+ ScoreV1_Boolean,
+ ScoreV1_Categorical,
+ ScoreV1_Numeric,
Score_Boolean,
Score_Categorical,
Score_Numeric,
@@ -79,7 +91,7 @@
DeleteDatasetItemResponse,
PaginatedDatasetItems,
)
-from .dataset_run_items import CreateDatasetRunItemRequest
+from .dataset_run_items import CreateDatasetRunItemRequest, PaginatedDatasetRunItems
from .datasets import (
CreateDatasetRequest,
DeleteDatasetRunResponse,
@@ -138,10 +150,26 @@
MediaContentType,
PatchMediaBody,
)
-from .metrics import DailyMetrics, DailyMetricsDetails, UsageByModel
+from .metrics import MetricsResponse
from .models import CreateModelRequest, PaginatedModels
from .observations import Observations, ObservationsViews
-from .projects import Project, Projects
+from .organizations import (
+ MembershipRequest,
+ MembershipResponse,
+ MembershipRole,
+ MembershipsResponse,
+ OrganizationProject,
+ OrganizationProjectsResponse,
+)
+from .projects import (
+ ApiKeyDeletionResponse,
+ ApiKeyList,
+ ApiKeyResponse,
+ ApiKeySummary,
+ Project,
+ ProjectDeletionResponse,
+ Projects,
+)
from .prompts import (
BasePrompt,
ChatMessage,
@@ -158,9 +186,28 @@
Prompt_Text,
TextPrompt,
)
-from .score import (
- CreateScoreRequest,
- CreateScoreResponse,
+from .scim import (
+ AuthenticationScheme,
+ BulkConfig,
+ EmptyResponse,
+ FilterConfig,
+ ResourceMeta,
+ ResourceType,
+ ResourceTypesResponse,
+ SchemaExtension,
+ SchemaResource,
+ SchemasResponse,
+ ScimEmail,
+ ScimFeatureSupport,
+ ScimName,
+ ScimUser,
+ ScimUsersListResponse,
+ ServiceProviderConfig,
+ UserMeta,
+)
+from .score import CreateScoreRequest, CreateScoreResponse
+from .score_configs import CreateScoreConfigRequest, ScoreConfigs
+from .score_v_2 import (
GetScoresResponse,
GetScoresResponseData,
GetScoresResponseDataBoolean,
@@ -171,7 +218,6 @@
GetScoresResponseData_Numeric,
GetScoresResponseTraceData,
)
-from .score_configs import CreateScoreConfigRequest, ScoreConfigs
from .sessions import PaginatedSessions
from .trace import DeleteTraceResponse, Sort, Traces
@@ -181,11 +227,20 @@
"AnnotationQueueItem",
"AnnotationQueueObjectType",
"AnnotationQueueStatus",
+ "ApiKeyDeletionResponse",
+ "ApiKeyList",
+ "ApiKeyResponse",
+ "ApiKeySummary",
+ "AuthenticationScheme",
"BaseEvent",
"BasePrompt",
"BaseScore",
+ "BaseScoreV1",
"BooleanScore",
+ "BooleanScoreV1",
+ "BulkConfig",
"CategoricalScore",
+ "CategoricalScoreV1",
"ChatMessage",
"ChatPrompt",
"Comment",
@@ -214,8 +269,6 @@
"CreateSpanBody",
"CreateSpanEvent",
"CreateTextPromptRequest",
- "DailyMetrics",
- "DailyMetricsDetails",
"Dataset",
"DatasetItem",
"DatasetRun",
@@ -226,7 +279,9 @@
"DeleteDatasetItemResponse",
"DeleteDatasetRunResponse",
"DeleteTraceResponse",
+ "EmptyResponse",
"Error",
+ "FilterConfig",
"GetCommentsResponse",
"GetMediaResponse",
"GetMediaUploadUrlRequest",
@@ -258,11 +313,18 @@
"IngestionUsage",
"MapValue",
"MediaContentType",
+ "MembershipRequest",
+ "MembershipResponse",
+ "MembershipRole",
+ "MembershipsResponse",
"MethodNotAllowedError",
+ "MetricsResponse",
"Model",
+ "ModelPrice",
"ModelUsageUnit",
"NotFoundError",
"NumericScore",
+ "NumericScoreV1",
"Observation",
"ObservationBody",
"ObservationLevel",
@@ -274,21 +336,36 @@
"OpenAiResponseUsageSchema",
"OpenAiUsage",
"OptionalObservationBody",
+ "OrganizationProject",
+ "OrganizationProjectsResponse",
"PaginatedAnnotationQueueItems",
"PaginatedAnnotationQueues",
"PaginatedDatasetItems",
+ "PaginatedDatasetRunItems",
"PaginatedDatasetRuns",
"PaginatedDatasets",
"PaginatedModels",
"PaginatedSessions",
"PatchMediaBody",
"Project",
+ "ProjectDeletionResponse",
"Projects",
"Prompt",
"PromptMeta",
"PromptMetaListResponse",
"Prompt_Chat",
"Prompt_Text",
+ "ResourceMeta",
+ "ResourceType",
+ "ResourceTypesResponse",
+ "SchemaExtension",
+ "SchemaResource",
+ "SchemasResponse",
+ "ScimEmail",
+ "ScimFeatureSupport",
+ "ScimName",
+ "ScimUser",
+ "ScimUsersListResponse",
"Score",
"ScoreBody",
"ScoreConfig",
@@ -296,11 +373,16 @@
"ScoreDataType",
"ScoreEvent",
"ScoreSource",
+ "ScoreV1",
+ "ScoreV1_Boolean",
+ "ScoreV1_Categorical",
+ "ScoreV1_Numeric",
"Score_Boolean",
"Score_Categorical",
"Score_Numeric",
"SdkLogBody",
"SdkLogEvent",
+ "ServiceProviderConfig",
"ServiceUnavailableError",
"Session",
"SessionWithTraces",
@@ -321,8 +403,8 @@
"UpdateSpanBody",
"UpdateSpanEvent",
"Usage",
- "UsageByModel",
"UsageDetails",
+ "UserMeta",
"annotation_queues",
"comments",
"commons",
@@ -335,11 +417,14 @@
"metrics",
"models",
"observations",
+ "organizations",
"projects",
"prompt_version",
"prompts",
+ "scim",
"score",
"score_configs",
+ "score_v_2",
"sessions",
"trace",
"utils",
diff --git a/langfuse/api/resources/commons/__init__.py b/langfuse/api/resources/commons/__init__.py
index e3e919f41..6dfbecafe 100644
--- a/langfuse/api/resources/commons/__init__.py
+++ b/langfuse/api/resources/commons/__init__.py
@@ -2,8 +2,11 @@
from .types import (
BaseScore,
+ BaseScoreV1,
BooleanScore,
+ BooleanScoreV1,
CategoricalScore,
+ CategoricalScoreV1,
Comment,
CommentObjectType,
ConfigCategory,
@@ -16,8 +19,10 @@
DatasetStatus,
MapValue,
Model,
+ ModelPrice,
ModelUsageUnit,
NumericScore,
+ NumericScoreV1,
Observation,
ObservationLevel,
ObservationsView,
@@ -25,6 +30,10 @@
ScoreConfig,
ScoreDataType,
ScoreSource,
+ ScoreV1,
+ ScoreV1_Boolean,
+ ScoreV1_Categorical,
+ ScoreV1_Numeric,
Score_Boolean,
Score_Categorical,
Score_Numeric,
@@ -46,8 +55,11 @@
__all__ = [
"AccessDeniedError",
"BaseScore",
+ "BaseScoreV1",
"BooleanScore",
+ "BooleanScoreV1",
"CategoricalScore",
+ "CategoricalScoreV1",
"Comment",
"CommentObjectType",
"ConfigCategory",
@@ -62,9 +74,11 @@
"MapValue",
"MethodNotAllowedError",
"Model",
+ "ModelPrice",
"ModelUsageUnit",
"NotFoundError",
"NumericScore",
+ "NumericScoreV1",
"Observation",
"ObservationLevel",
"ObservationsView",
@@ -72,6 +86,10 @@
"ScoreConfig",
"ScoreDataType",
"ScoreSource",
+ "ScoreV1",
+ "ScoreV1_Boolean",
+ "ScoreV1_Categorical",
+ "ScoreV1_Numeric",
"Score_Boolean",
"Score_Categorical",
"Score_Numeric",
diff --git a/langfuse/api/resources/commons/types/__init__.py b/langfuse/api/resources/commons/types/__init__.py
index fcec85214..1c0d06a8d 100644
--- a/langfuse/api/resources/commons/types/__init__.py
+++ b/langfuse/api/resources/commons/types/__init__.py
@@ -1,8 +1,11 @@
# This file was auto-generated by Fern from our API Definition.
from .base_score import BaseScore
+from .base_score_v_1 import BaseScoreV1
from .boolean_score import BooleanScore
+from .boolean_score_v_1 import BooleanScoreV1
from .categorical_score import CategoricalScore
+from .categorical_score_v_1 import CategoricalScoreV1
from .comment import Comment
from .comment_object_type import CommentObjectType
from .config_category import ConfigCategory
@@ -15,8 +18,10 @@
from .dataset_status import DatasetStatus
from .map_value import MapValue
from .model import Model
+from .model_price import ModelPrice
from .model_usage_unit import ModelUsageUnit
from .numeric_score import NumericScore
+from .numeric_score_v_1 import NumericScoreV1
from .observation import Observation
from .observation_level import ObservationLevel
from .observations_view import ObservationsView
@@ -24,6 +29,7 @@
from .score_config import ScoreConfig
from .score_data_type import ScoreDataType
from .score_source import ScoreSource
+from .score_v_1 import ScoreV1, ScoreV1_Boolean, ScoreV1_Categorical, ScoreV1_Numeric
from .session import Session
from .session_with_traces import SessionWithTraces
from .trace import Trace
@@ -33,8 +39,11 @@
__all__ = [
"BaseScore",
+ "BaseScoreV1",
"BooleanScore",
+ "BooleanScoreV1",
"CategoricalScore",
+ "CategoricalScoreV1",
"Comment",
"CommentObjectType",
"ConfigCategory",
@@ -47,8 +56,10 @@
"DatasetStatus",
"MapValue",
"Model",
+ "ModelPrice",
"ModelUsageUnit",
"NumericScore",
+ "NumericScoreV1",
"Observation",
"ObservationLevel",
"ObservationsView",
@@ -56,6 +67,10 @@
"ScoreConfig",
"ScoreDataType",
"ScoreSource",
+ "ScoreV1",
+ "ScoreV1_Boolean",
+ "ScoreV1_Categorical",
+ "ScoreV1_Numeric",
"Score_Boolean",
"Score_Categorical",
"Score_Numeric",
diff --git a/langfuse/api/resources/commons/types/base_score.py b/langfuse/api/resources/commons/types/base_score.py
index 89394956b..74e93d0bd 100644
--- a/langfuse/api/resources/commons/types/base_score.py
+++ b/langfuse/api/resources/commons/types/base_score.py
@@ -10,12 +10,18 @@
class BaseScore(pydantic_v1.BaseModel):
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -23,6 +29,7 @@ class BaseScore(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
"""
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
diff --git a/langfuse/api/resources/commons/types/base_score_v_1.py b/langfuse/api/resources/commons/types/base_score_v_1.py
new file mode 100644
index 000000000..a89a4f7bb
--- /dev/null
+++ b/langfuse/api/resources/commons/types/base_score_v_1.py
@@ -0,0 +1,73 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .score_source import ScoreSource
+
+
+class BaseScoreV1(pydantic_v1.BaseModel):
+ id: str
+ trace_id: str = pydantic_v1.Field(alias="traceId")
+ name: str
+ source: ScoreSource
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ timestamp: dt.datetime
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
+ author_user_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="authorUserId", default=None
+ )
+ comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
+ config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
+ """
+ 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
+ """
+
+ queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
+ """
+ Reference an annotation queue on a score. Populated if the score was initially created in an annotation queue.
+ """
+
+ environment: typing.Optional[str] = pydantic_v1.Field(default=None)
+ """
+ The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
+ """
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/metrics/types/usage_by_model.py b/langfuse/api/resources/commons/types/boolean_score_v_1.py
similarity index 61%
rename from langfuse/api/resources/metrics/types/usage_by_model.py
rename to langfuse/api/resources/commons/types/boolean_score_v_1.py
index 3ff6de59c..9f8e8935f 100644
--- a/langfuse/api/resources/metrics/types/usage_by_model.py
+++ b/langfuse/api/resources/commons/types/boolean_score_v_1.py
@@ -5,34 +5,18 @@
from ....core.datetime_utils import serialize_datetime
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .base_score_v_1 import BaseScoreV1
-class UsageByModel(pydantic_v1.BaseModel):
+class BooleanScoreV1(BaseScoreV1):
+ value: float = pydantic_v1.Field()
"""
- Daily usage of a given model. Usage corresponds to the unit set for the specific model (e.g. tokens).
+ The numeric value of the score. Equals 1 for "True" and 0 for "False"
"""
- model: typing.Optional[str] = None
- input_usage: int = pydantic_v1.Field(alias="inputUsage")
+ string_value: str = pydantic_v1.Field(alias="stringValue")
"""
- Total number of generation input units (e.g. tokens)
- """
-
- output_usage: int = pydantic_v1.Field(alias="outputUsage")
- """
- Total number of generation output units (e.g. tokens)
- """
-
- total_usage: int = pydantic_v1.Field(alias="totalUsage")
- """
- Total number of generation total units (e.g. tokens)
- """
-
- count_traces: int = pydantic_v1.Field(alias="countTraces")
- count_observations: int = pydantic_v1.Field(alias="countObservations")
- total_cost: float = pydantic_v1.Field(alias="totalCost")
- """
- Total model cost in USD
+ The string representation of the score value. Is inferred from the numeric value and equals "True" or "False"
"""
def json(self, **kwargs: typing.Any) -> str:
diff --git a/langfuse/api/resources/commons/types/categorical_score_v_1.py b/langfuse/api/resources/commons/types/categorical_score_v_1.py
new file mode 100644
index 000000000..2cc84fc25
--- /dev/null
+++ b/langfuse/api/resources/commons/types/categorical_score_v_1.py
@@ -0,0 +1,53 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .base_score_v_1 import BaseScoreV1
+
+
+class CategoricalScoreV1(BaseScoreV1):
+ value: typing.Optional[float] = pydantic_v1.Field(default=None)
+ """
+ Only defined if a config is linked. Represents the numeric category mapping of the stringValue
+ """
+
+ string_value: str = pydantic_v1.Field(alias="stringValue")
+ """
+ The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category
+ """
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/commons/types/model.py b/langfuse/api/resources/commons/types/model.py
index 54cb26bc8..ea3922ee9 100644
--- a/langfuse/api/resources/commons/types/model.py
+++ b/langfuse/api/resources/commons/types/model.py
@@ -5,6 +5,7 @@
from ....core.datetime_utils import serialize_datetime
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .model_price import ModelPrice
from .model_usage_unit import ModelUsageUnit
@@ -40,21 +41,21 @@ class Model(pydantic_v1.BaseModel):
alias="inputPrice", default=None
)
"""
- Price (USD) per input unit
+ Deprecated. See 'prices' instead. Price (USD) per input unit
"""
output_price: typing.Optional[float] = pydantic_v1.Field(
alias="outputPrice", default=None
)
"""
- Price (USD) per output unit
+ Deprecated. See 'prices' instead. Price (USD) per output unit
"""
total_price: typing.Optional[float] = pydantic_v1.Field(
alias="totalPrice", default=None
)
"""
- Price (USD) per total unit. Cannot be set if input or output price is set.
+ Deprecated. See 'prices' instead. Price (USD) per total unit. Cannot be set if input or output price is set.
"""
tokenizer_id: typing.Optional[str] = pydantic_v1.Field(
@@ -72,6 +73,10 @@ class Model(pydantic_v1.BaseModel):
"""
is_langfuse_managed: bool = pydantic_v1.Field(alias="isLangfuseManaged")
+ prices: typing.Dict[str, ModelPrice] = pydantic_v1.Field()
+ """
+ Price (USD) by usage type
+ """
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/ingestion/types/open_ai_usage_schema.py b/langfuse/api/resources/commons/types/model_price.py
similarity index 81%
rename from langfuse/api/resources/ingestion/types/open_ai_usage_schema.py
rename to langfuse/api/resources/commons/types/model_price.py
index ecf755bb3..8882004e7 100644
--- a/langfuse/api/resources/ingestion/types/open_ai_usage_schema.py
+++ b/langfuse/api/resources/commons/types/model_price.py
@@ -7,12 +7,8 @@
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
-class OpenAiUsageSchema(pydantic_v1.BaseModel):
- prompt_tokens: int
- completion_tokens: int
- total_tokens: int
- prompt_tokens_details: typing.Optional[typing.Dict[str, int]] = None
- completion_tokens_details: typing.Optional[typing.Dict[str, int]] = None
+class ModelPrice(pydantic_v1.BaseModel):
+ price: float
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/commons/types/numeric_score_v_1.py b/langfuse/api/resources/commons/types/numeric_score_v_1.py
new file mode 100644
index 000000000..773d84b46
--- /dev/null
+++ b/langfuse/api/resources/commons/types/numeric_score_v_1.py
@@ -0,0 +1,48 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .base_score_v_1 import BaseScoreV1
+
+
+class NumericScoreV1(BaseScoreV1):
+ value: float = pydantic_v1.Field()
+ """
+ The numeric value of the score
+ """
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/commons/types/score.py b/langfuse/api/resources/commons/types/score.py
index 8eed33b78..789854afc 100644
--- a/langfuse/api/resources/commons/types/score.py
+++ b/langfuse/api/resources/commons/types/score.py
@@ -13,12 +13,18 @@
class Score_Numeric(pydantic_v1.BaseModel):
value: float
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -26,6 +32,7 @@ class Score_Numeric(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
@@ -71,12 +78,18 @@ class Score_Categorical(pydantic_v1.BaseModel):
value: typing.Optional[float] = None
string_value: str = pydantic_v1.Field(alias="stringValue")
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -84,6 +97,7 @@ class Score_Categorical(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
@@ -129,12 +143,18 @@ class Score_Boolean(pydantic_v1.BaseModel):
value: float
string_value: str = pydantic_v1.Field(alias="stringValue")
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -142,6 +162,7 @@ class Score_Boolean(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
diff --git a/langfuse/api/resources/commons/types/score_v_1.py b/langfuse/api/resources/commons/types/score_v_1.py
new file mode 100644
index 000000000..788f6f39c
--- /dev/null
+++ b/langfuse/api/resources/commons/types/score_v_1.py
@@ -0,0 +1,189 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from __future__ import annotations
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .score_source import ScoreSource
+
+
+class ScoreV1_Numeric(pydantic_v1.BaseModel):
+ value: float
+ id: str
+ trace_id: str = pydantic_v1.Field(alias="traceId")
+ name: str
+ source: ScoreSource
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ timestamp: dt.datetime
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
+ author_user_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="authorUserId", default=None
+ )
+ comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
+ config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
+ queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
+ environment: typing.Optional[str] = None
+ data_type: typing.Literal["NUMERIC"] = pydantic_v1.Field(
+ alias="dataType", default="NUMERIC"
+ )
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
+
+
+class ScoreV1_Categorical(pydantic_v1.BaseModel):
+ value: typing.Optional[float] = None
+ string_value: str = pydantic_v1.Field(alias="stringValue")
+ id: str
+ trace_id: str = pydantic_v1.Field(alias="traceId")
+ name: str
+ source: ScoreSource
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ timestamp: dt.datetime
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
+ author_user_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="authorUserId", default=None
+ )
+ comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
+ config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
+ queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
+ environment: typing.Optional[str] = None
+ data_type: typing.Literal["CATEGORICAL"] = pydantic_v1.Field(
+ alias="dataType", default="CATEGORICAL"
+ )
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
+
+
+class ScoreV1_Boolean(pydantic_v1.BaseModel):
+ value: float
+ string_value: str = pydantic_v1.Field(alias="stringValue")
+ id: str
+ trace_id: str = pydantic_v1.Field(alias="traceId")
+ name: str
+ source: ScoreSource
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ timestamp: dt.datetime
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
+ author_user_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="authorUserId", default=None
+ )
+ comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
+ config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
+ queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
+ environment: typing.Optional[str] = None
+ data_type: typing.Literal["BOOLEAN"] = pydantic_v1.Field(
+ alias="dataType", default="BOOLEAN"
+ )
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
+
+
+ScoreV1 = typing.Union[ScoreV1_Numeric, ScoreV1_Categorical, ScoreV1_Boolean]
diff --git a/langfuse/api/resources/commons/types/trace_with_full_details.py b/langfuse/api/resources/commons/types/trace_with_full_details.py
index c96258d73..2c6a99402 100644
--- a/langfuse/api/resources/commons/types/trace_with_full_details.py
+++ b/langfuse/api/resources/commons/types/trace_with_full_details.py
@@ -6,7 +6,7 @@
from ....core.datetime_utils import serialize_datetime
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
from .observations_view import ObservationsView
-from .score import Score
+from .score_v_1 import ScoreV1
from .trace import Trace
@@ -31,7 +31,7 @@ class TraceWithFullDetails(Trace):
List of observations
"""
- scores: typing.List[Score] = pydantic_v1.Field()
+ scores: typing.List[ScoreV1] = pydantic_v1.Field()
"""
List of scores
"""
diff --git a/langfuse/api/resources/dataset_run_items/__init__.py b/langfuse/api/resources/dataset_run_items/__init__.py
index 44a70688e..d522a3129 100644
--- a/langfuse/api/resources/dataset_run_items/__init__.py
+++ b/langfuse/api/resources/dataset_run_items/__init__.py
@@ -1,5 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import CreateDatasetRunItemRequest
+from .types import CreateDatasetRunItemRequest, PaginatedDatasetRunItems
-__all__ = ["CreateDatasetRunItemRequest"]
+__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"]
diff --git a/langfuse/api/resources/dataset_run_items/client.py b/langfuse/api/resources/dataset_run_items/client.py
index 4f5426568..71bd8576d 100644
--- a/langfuse/api/resources/dataset_run_items/client.py
+++ b/langfuse/api/resources/dataset_run_items/client.py
@@ -5,6 +5,7 @@
from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import pydantic_v1
from ...core.request_options import RequestOptions
from ..commons.errors.access_denied_error import AccessDeniedError
@@ -14,6 +15,7 @@
from ..commons.errors.unauthorized_error import UnauthorizedError
from ..commons.types.dataset_run_item import DatasetRunItem
from .types.create_dataset_run_item_request import CreateDatasetRunItemRequest
+from .types.paginated_dataset_run_items import PaginatedDatasetRunItems
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -96,6 +98,135 @@ def create(
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
+ def list(
+ self,
+ *,
+ dataset_id: str,
+ run_name: str,
+ response: PaginatedDatasetRunItems,
+ page: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ List dataset run items
+
+ Parameters
+ ----------
+ dataset_id : str
+
+ run_name : str
+
+ response : PaginatedDatasetRunItems
+
+ page : typing.Optional[int]
+ page number, starts at 1
+
+ limit : typing.Optional[int]
+ limit of items per page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import datetime
+
+ from langfuse import DatasetRunItem, PaginatedDatasetRunItems
+ from langfuse.client import FernLangfuse
+ from langfuse.resources.utils import MetaResponse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.dataset_run_items.list(
+ dataset_id="datasetId",
+ run_name="runName",
+ response=PaginatedDatasetRunItems(
+ data=[
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ ],
+ meta=MetaResponse(
+ page=1,
+ limit=1,
+ total_items=1,
+ total_pages=1,
+ ),
+ ),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/dataset-run-items",
+ method="GET",
+ params={
+ "datasetId": dataset_id,
+ "runName": run_name,
+ "page": page,
+ "limit": limit,
+ "response": jsonable_encoder(response),
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
class AsyncDatasetRunItemsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
@@ -181,3 +312,139 @@ async def main() -> None:
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def list(
+ self,
+ *,
+ dataset_id: str,
+ run_name: str,
+ response: PaginatedDatasetRunItems,
+ page: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ List dataset run items
+
+ Parameters
+ ----------
+ dataset_id : str
+
+ run_name : str
+
+ response : PaginatedDatasetRunItems
+
+ page : typing.Optional[int]
+ page number, starts at 1
+
+ limit : typing.Optional[int]
+ limit of items per page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+ import datetime
+
+ from langfuse import DatasetRunItem, PaginatedDatasetRunItems
+ from langfuse.client import AsyncFernLangfuse
+ from langfuse.resources.utils import MetaResponse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.dataset_run_items.list(
+ dataset_id="datasetId",
+ run_name="runName",
+ response=PaginatedDatasetRunItems(
+ data=[
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ DatasetRunItem(
+ id="id",
+ dataset_run_id="datasetRunId",
+ dataset_run_name="datasetRunName",
+ dataset_item_id="datasetItemId",
+ trace_id="traceId",
+ created_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ updated_at=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ ),
+ ],
+ meta=MetaResponse(
+ page=1,
+ limit=1,
+ total_items=1,
+ total_pages=1,
+ ),
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/dataset-run-items",
+ method="GET",
+ params={
+ "datasetId": dataset_id,
+ "runName": run_name,
+ "page": page,
+ "limit": limit,
+ "response": jsonable_encoder(response),
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/langfuse/api/resources/dataset_run_items/types/__init__.py b/langfuse/api/resources/dataset_run_items/types/__init__.py
index 3944308d6..e48e72c27 100644
--- a/langfuse/api/resources/dataset_run_items/types/__init__.py
+++ b/langfuse/api/resources/dataset_run_items/types/__init__.py
@@ -1,5 +1,6 @@
# This file was auto-generated by Fern from our API Definition.
from .create_dataset_run_item_request import CreateDatasetRunItemRequest
+from .paginated_dataset_run_items import PaginatedDatasetRunItems
-__all__ = ["CreateDatasetRunItemRequest"]
+__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"]
diff --git a/langfuse/api/resources/metrics/types/daily_metrics.py b/langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py
similarity index 83%
rename from langfuse/api/resources/metrics/types/daily_metrics.py
rename to langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py
index 36a12a3d6..c1611bae0 100644
--- a/langfuse/api/resources/metrics/types/daily_metrics.py
+++ b/langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py
@@ -5,16 +5,12 @@
from ....core.datetime_utils import serialize_datetime
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from ...commons.types.dataset_run_item import DatasetRunItem
from ...utils.resources.pagination.types.meta_response import MetaResponse
-from .daily_metrics_details import DailyMetricsDetails
-class DailyMetrics(pydantic_v1.BaseModel):
- data: typing.List[DailyMetricsDetails] = pydantic_v1.Field()
- """
- A list of daily metrics, only days with ingested data are included.
- """
-
+class PaginatedDatasetRunItems(pydantic_v1.BaseModel):
+ data: typing.List[DatasetRunItem]
meta: MetaResponse
def json(self, **kwargs: typing.Any) -> str:
diff --git a/langfuse/api/resources/ingestion/types/score_body.py b/langfuse/api/resources/ingestion/types/score_body.py
index dbe2fbbd9..286c06514 100644
--- a/langfuse/api/resources/ingestion/types/score_body.py
+++ b/langfuse/api/resources/ingestion/types/score_body.py
@@ -23,7 +23,16 @@ class ScoreBody(pydantic_v1.BaseModel):
"""
id: typing.Optional[str] = None
- trace_id: str = pydantic_v1.Field(alias="traceId")
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
name: str
environment: typing.Optional[str] = None
value: CreateScoreValue = pydantic_v1.Field()
@@ -31,10 +40,8 @@ class ScoreBody(pydantic_v1.BaseModel):
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)
"""
- observation_id: typing.Optional[str] = pydantic_v1.Field(
- alias="observationId", default=None
- )
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
data_type: typing.Optional[ScoreDataType] = pydantic_v1.Field(
alias="dataType", default=None
)
diff --git a/langfuse/api/resources/metrics/__init__.py b/langfuse/api/resources/metrics/__init__.py
index cd6745c97..90e510b5f 100644
--- a/langfuse/api/resources/metrics/__init__.py
+++ b/langfuse/api/resources/metrics/__init__.py
@@ -1,5 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import DailyMetrics, DailyMetricsDetails, UsageByModel
+from .types import MetricsResponse
-__all__ = ["DailyMetrics", "DailyMetricsDetails", "UsageByModel"]
+__all__ = ["MetricsResponse"]
diff --git a/langfuse/api/resources/metrics/client.py b/langfuse/api/resources/metrics/client.py
index 9ae8666c9..0eb830717 100644
--- a/langfuse/api/resources/metrics/client.py
+++ b/langfuse/api/resources/metrics/client.py
@@ -1,12 +1,10 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
from json.decoder import JSONDecodeError
from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.datetime_utils import serialize_datetime
from ...core.pydantic_utilities import pydantic_v1
from ...core.request_options import RequestOptions
from ..commons.errors.access_denied_error import AccessDeniedError
@@ -14,61 +12,66 @@
from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
from ..commons.errors.not_found_error import NotFoundError
from ..commons.errors.unauthorized_error import UnauthorizedError
-from .types.daily_metrics import DailyMetrics
+from .types.metrics_response import MetricsResponse
class MetricsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def daily(
- self,
- *,
- page: typing.Optional[int] = None,
- limit: typing.Optional[int] = None,
- trace_name: typing.Optional[str] = None,
- user_id: typing.Optional[str] = None,
- tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- from_timestamp: typing.Optional[dt.datetime] = None,
- to_timestamp: typing.Optional[dt.datetime] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DailyMetrics:
+ def metrics(
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> MetricsResponse:
"""
- Get daily metrics of the Langfuse project
+ Get metrics from the Langfuse project using a query object
Parameters
----------
- page : typing.Optional[int]
- page number, starts at 1
-
- limit : typing.Optional[int]
- limit of items per page
-
- trace_name : typing.Optional[str]
- Optional filter by the name of the trace
-
- user_id : typing.Optional[str]
- Optional filter by the userId associated with the trace
-
- tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for metrics where traces include all of these tags
-
- environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for metrics where events include any of these environments
-
- from_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include traces and observations on or after a certain datetime (ISO 8601)
-
- to_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include traces and observations before a certain datetime (ISO 8601)
+ query : str
+ JSON string containing the query parameters with the following structure:
+ ```json
+ {
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
+ "dimensions": [ // Optional. Default: []
+ {
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
+ }
+ ],
+ "metrics": [ // Required. At least one metric must be provided
+ {
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95"
+ }
+ ],
+ "filters": [ // Optional. Default: []
+ {
+ "column": string, // Column to filter on
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
+ "value": any, // Value to compare against
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
+ "key": string // Required only when filtering on metadata
+ }
+ ],
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
+ },
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
+ "orderBy": [ // Optional. Default: null
+ {
+ "field": string, // Field to order by
+ "direction": string // "asc" or "desc"
+ }
+ ]
+ }
+ ```
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- DailyMetrics
+ MetricsResponse
Examples
--------
@@ -82,30 +85,19 @@ def daily(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
- client.metrics.daily()
+ client.metrics.metrics(
+ query="query",
+ )
"""
_response = self._client_wrapper.httpx_client.request(
- "api/public/metrics/daily",
+ "api/public/metrics",
method="GET",
- params={
- "page": page,
- "limit": limit,
- "traceName": trace_name,
- "userId": user_id,
- "tags": tags,
- "environment": environment,
- "fromTimestamp": serialize_datetime(from_timestamp)
- if from_timestamp is not None
- else None,
- "toTimestamp": serialize_datetime(to_timestamp)
- if to_timestamp is not None
- else None,
- },
+ params={"query": query},
request_options=request_options,
)
try:
if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(DailyMetrics, _response.json()) # type: ignore
+ return pydantic_v1.parse_obj_as(MetricsResponse, _response.json()) # type: ignore
if _response.status_code == 400:
raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
if _response.status_code == 401:
@@ -134,54 +126,59 @@ class AsyncMetricsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
self._client_wrapper = client_wrapper
- async def daily(
- self,
- *,
- page: typing.Optional[int] = None,
- limit: typing.Optional[int] = None,
- trace_name: typing.Optional[str] = None,
- user_id: typing.Optional[str] = None,
- tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- from_timestamp: typing.Optional[dt.datetime] = None,
- to_timestamp: typing.Optional[dt.datetime] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DailyMetrics:
+ async def metrics(
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> MetricsResponse:
"""
- Get daily metrics of the Langfuse project
+ Get metrics from the Langfuse project using a query object
Parameters
----------
- page : typing.Optional[int]
- page number, starts at 1
-
- limit : typing.Optional[int]
- limit of items per page
-
- trace_name : typing.Optional[str]
- Optional filter by the name of the trace
-
- user_id : typing.Optional[str]
- Optional filter by the userId associated with the trace
-
- tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for metrics where traces include all of these tags
-
- environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for metrics where events include any of these environments
-
- from_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include traces and observations on or after a certain datetime (ISO 8601)
-
- to_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include traces and observations before a certain datetime (ISO 8601)
+ query : str
+ JSON string containing the query parameters with the following structure:
+ ```json
+ {
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
+ "dimensions": [ // Optional. Default: []
+ {
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
+ }
+ ],
+ "metrics": [ // Required. At least one metric must be provided
+ {
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95"
+ }
+ ],
+ "filters": [ // Optional. Default: []
+ {
+ "column": string, // Column to filter on
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
+ "value": any, // Value to compare against
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
+ "key": string // Required only when filtering on metadata
+ }
+ ],
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
+ },
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
+ "orderBy": [ // Optional. Default: null
+ {
+ "field": string, // Field to order by
+ "direction": string // "asc" or "desc"
+ }
+ ]
+ }
+ ```
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- DailyMetrics
+ MetricsResponse
Examples
--------
@@ -200,33 +197,22 @@ async def daily(
async def main() -> None:
- await client.metrics.daily()
+ await client.metrics.metrics(
+ query="query",
+ )
asyncio.run(main())
"""
_response = await self._client_wrapper.httpx_client.request(
- "api/public/metrics/daily",
+ "api/public/metrics",
method="GET",
- params={
- "page": page,
- "limit": limit,
- "traceName": trace_name,
- "userId": user_id,
- "tags": tags,
- "environment": environment,
- "fromTimestamp": serialize_datetime(from_timestamp)
- if from_timestamp is not None
- else None,
- "toTimestamp": serialize_datetime(to_timestamp)
- if to_timestamp is not None
- else None,
- },
+ params={"query": query},
request_options=request_options,
)
try:
if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(DailyMetrics, _response.json()) # type: ignore
+ return pydantic_v1.parse_obj_as(MetricsResponse, _response.json()) # type: ignore
if _response.status_code == 400:
raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
if _response.status_code == 401:
diff --git a/langfuse/api/resources/metrics/types/__init__.py b/langfuse/api/resources/metrics/types/__init__.py
index 4b350c4e9..7bf03027d 100644
--- a/langfuse/api/resources/metrics/types/__init__.py
+++ b/langfuse/api/resources/metrics/types/__init__.py
@@ -1,7 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-from .daily_metrics import DailyMetrics
-from .daily_metrics_details import DailyMetricsDetails
-from .usage_by_model import UsageByModel
+from .metrics_response import MetricsResponse
-__all__ = ["DailyMetrics", "DailyMetricsDetails", "UsageByModel"]
+__all__ = ["MetricsResponse"]
diff --git a/langfuse/api/resources/metrics/types/metrics_response.py b/langfuse/api/resources/metrics/types/metrics_response.py
new file mode 100644
index 000000000..ec1ecd97f
--- /dev/null
+++ b/langfuse/api/resources/metrics/types/metrics_response.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class MetricsResponse(pydantic_v1.BaseModel):
+ data: typing.List[typing.Dict[str, typing.Any]] = pydantic_v1.Field()
+ """
+ The metrics data. Each item in the list contains the metric values and dimensions requested in the query.
+ Format varies based on the query parameters.
+ """
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/observations/client.py b/langfuse/api/resources/observations/client.py
index 180a48949..01bf60f78 100644
--- a/langfuse/api/resources/observations/client.py
+++ b/langfuse/api/resources/observations/client.py
@@ -132,7 +132,7 @@ def get_many(
Optional filter for observations where the environment is one of the provided values.
from_start_time : typing.Optional[dt.datetime]
- Retrieve only observations with a start_time or or after this datetime (ISO 8601).
+ Retrieve only observations with a start_time on or after this datetime (ISO 8601).
to_start_time : typing.Optional[dt.datetime]
Retrieve only observations with a start_time before this datetime (ISO 8601).
@@ -331,7 +331,7 @@ async def get_many(
Optional filter for observations where the environment is one of the provided values.
from_start_time : typing.Optional[dt.datetime]
- Retrieve only observations with a start_time or or after this datetime (ISO 8601).
+ Retrieve only observations with a start_time on or after this datetime (ISO 8601).
to_start_time : typing.Optional[dt.datetime]
Retrieve only observations with a start_time before this datetime (ISO 8601).
diff --git a/langfuse/api/resources/organizations/__init__.py b/langfuse/api/resources/organizations/__init__.py
new file mode 100644
index 000000000..48edda3f4
--- /dev/null
+++ b/langfuse/api/resources/organizations/__init__.py
@@ -0,0 +1,19 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .types import (
+ MembershipRequest,
+ MembershipResponse,
+ MembershipRole,
+ MembershipsResponse,
+ OrganizationProject,
+ OrganizationProjectsResponse,
+)
+
+__all__ = [
+ "MembershipRequest",
+ "MembershipResponse",
+ "MembershipRole",
+ "MembershipsResponse",
+ "OrganizationProject",
+ "OrganizationProjectsResponse",
+]
diff --git a/langfuse/api/resources/organizations/client.py b/langfuse/api/resources/organizations/client.py
new file mode 100644
index 000000000..f7f2f5021
--- /dev/null
+++ b/langfuse/api/resources/organizations/client.py
@@ -0,0 +1,750 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.pydantic_utilities import pydantic_v1
+from ...core.request_options import RequestOptions
+from ..commons.errors.access_denied_error import AccessDeniedError
+from ..commons.errors.error import Error
+from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
+from ..commons.errors.not_found_error import NotFoundError
+from ..commons.errors.unauthorized_error import UnauthorizedError
+from .types.membership_request import MembershipRequest
+from .types.membership_response import MembershipResponse
+from .types.memberships_response import MembershipsResponse
+from .types.organization_projects_response import OrganizationProjectsResponse
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class OrganizationsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_organization_memberships(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> MembershipsResponse:
+ """
+ Get all memberships for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipsResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.organizations.get_organization_memberships()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/organizations/memberships",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def update_organization_membership(
+ self,
+ *,
+ request: MembershipRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipResponse:
+ """
+ Create or update a membership for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request : MembershipRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipResponse
+
+ Examples
+ --------
+ from langfuse import MembershipRequest, MembershipRole
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.organizations.update_organization_membership(
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/organizations/memberships",
+ method="PUT",
+ json=request,
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_project_memberships(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipsResponse:
+ """
+ Get all memberships for a specific project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipsResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.organizations.get_project_memberships(
+ project_id="projectId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/memberships",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def update_project_membership(
+ self,
+ project_id: str,
+ *,
+ request: MembershipRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipResponse:
+ """
+ Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization.
+
+ Parameters
+ ----------
+ project_id : str
+
+ request : MembershipRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipResponse
+
+ Examples
+ --------
+ from langfuse import MembershipRequest, MembershipRole
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.organizations.update_project_membership(
+ project_id="projectId",
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/memberships",
+ method="PUT",
+ json=request,
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_organization_projects(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> OrganizationProjectsResponse:
+ """
+ Get all projects for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ OrganizationProjectsResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.organizations.get_organization_projects()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/organizations/projects",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ OrganizationProjectsResponse, _response.json()
+ ) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncOrganizationsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_organization_memberships(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> MembershipsResponse:
+ """
+ Get all memberships for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipsResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.organizations.get_organization_memberships()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/organizations/memberships",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def update_organization_membership(
+ self,
+ *,
+ request: MembershipRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipResponse:
+ """
+ Create or update a membership for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request : MembershipRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse import MembershipRequest, MembershipRole
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.organizations.update_organization_membership(
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/organizations/memberships",
+ method="PUT",
+ json=request,
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_project_memberships(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipsResponse:
+ """
+ Get all memberships for a specific project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipsResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.organizations.get_project_memberships(
+ project_id="projectId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/memberships",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def update_project_membership(
+ self,
+ project_id: str,
+ *,
+ request: MembershipRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> MembershipResponse:
+ """
+ Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization.
+
+ Parameters
+ ----------
+ project_id : str
+
+ request : MembershipRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ MembershipResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse import MembershipRequest, MembershipRole
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.organizations.update_project_membership(
+ project_id="projectId",
+ request=MembershipRequest(
+ user_id="userId",
+ role=MembershipRole.OWNER,
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/memberships",
+ method="PUT",
+ json=request,
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_organization_projects(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> OrganizationProjectsResponse:
+ """
+ Get all projects for the organization associated with the API key (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ OrganizationProjectsResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.organizations.get_organization_projects()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/organizations/projects",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ OrganizationProjectsResponse, _response.json()
+ ) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/langfuse/api/resources/organizations/types/__init__.py b/langfuse/api/resources/organizations/types/__init__.py
new file mode 100644
index 000000000..4a401124d
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/__init__.py
@@ -0,0 +1,17 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .membership_request import MembershipRequest
+from .membership_response import MembershipResponse
+from .membership_role import MembershipRole
+from .memberships_response import MembershipsResponse
+from .organization_project import OrganizationProject
+from .organization_projects_response import OrganizationProjectsResponse
+
+__all__ = [
+ "MembershipRequest",
+ "MembershipResponse",
+ "MembershipRole",
+ "MembershipsResponse",
+ "OrganizationProject",
+ "OrganizationProjectsResponse",
+]
diff --git a/langfuse/api/resources/organizations/types/membership_request.py b/langfuse/api/resources/organizations/types/membership_request.py
new file mode 100644
index 000000000..a7f046f51
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/membership_request.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .membership_role import MembershipRole
+
+
+class MembershipRequest(pydantic_v1.BaseModel):
+ user_id: str = pydantic_v1.Field(alias="userId")
+ role: MembershipRole
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/organizations/types/membership_response.py b/langfuse/api/resources/organizations/types/membership_response.py
new file mode 100644
index 000000000..e9d82f3c7
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/membership_response.py
@@ -0,0 +1,48 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .membership_role import MembershipRole
+
+
+class MembershipResponse(pydantic_v1.BaseModel):
+ user_id: str = pydantic_v1.Field(alias="userId")
+ role: MembershipRole
+ email: str
+ name: str
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/organizations/types/membership_role.py b/langfuse/api/resources/organizations/types/membership_role.py
new file mode 100644
index 000000000..1721cc0ed
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/membership_role.py
@@ -0,0 +1,29 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import enum
+import typing
+
+T_Result = typing.TypeVar("T_Result")
+
+
+class MembershipRole(str, enum.Enum):
+ OWNER = "OWNER"
+ ADMIN = "ADMIN"
+ MEMBER = "MEMBER"
+ VIEWER = "VIEWER"
+
+ def visit(
+ self,
+ owner: typing.Callable[[], T_Result],
+ admin: typing.Callable[[], T_Result],
+ member: typing.Callable[[], T_Result],
+ viewer: typing.Callable[[], T_Result],
+ ) -> T_Result:
+ if self is MembershipRole.OWNER:
+ return owner()
+ if self is MembershipRole.ADMIN:
+ return admin()
+ if self is MembershipRole.MEMBER:
+ return member()
+ if self is MembershipRole.VIEWER:
+ return viewer()
diff --git a/langfuse/api/resources/organizations/types/memberships_response.py b/langfuse/api/resources/organizations/types/memberships_response.py
new file mode 100644
index 000000000..0a8091449
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/memberships_response.py
@@ -0,0 +1,43 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .membership_response import MembershipResponse
+
+
+class MembershipsResponse(pydantic_v1.BaseModel):
+ memberships: typing.List[MembershipResponse]
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/organizations/types/organization_project.py b/langfuse/api/resources/organizations/types/organization_project.py
new file mode 100644
index 000000000..87f245b9a
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/organization_project.py
@@ -0,0 +1,48 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class OrganizationProject(pydantic_v1.BaseModel):
+ id: str
+ name: str
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = None
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/organizations/types/organization_projects_response.py b/langfuse/api/resources/organizations/types/organization_projects_response.py
new file mode 100644
index 000000000..1c939a3e0
--- /dev/null
+++ b/langfuse/api/resources/organizations/types/organization_projects_response.py
@@ -0,0 +1,43 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .organization_project import OrganizationProject
+
+
+class OrganizationProjectsResponse(pydantic_v1.BaseModel):
+ projects: typing.List[OrganizationProject]
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/projects/__init__.py b/langfuse/api/resources/projects/__init__.py
index 8c2147e41..26c74c1c7 100644
--- a/langfuse/api/resources/projects/__init__.py
+++ b/langfuse/api/resources/projects/__init__.py
@@ -1,5 +1,21 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import Project, Projects
+from .types import (
+ ApiKeyDeletionResponse,
+ ApiKeyList,
+ ApiKeyResponse,
+ ApiKeySummary,
+ Project,
+ ProjectDeletionResponse,
+ Projects,
+)
-__all__ = ["Project", "Projects"]
+__all__ = [
+ "ApiKeyDeletionResponse",
+ "ApiKeyList",
+ "ApiKeyResponse",
+ "ApiKeySummary",
+ "Project",
+ "ProjectDeletionResponse",
+ "Projects",
+]
diff --git a/langfuse/api/resources/projects/client.py b/langfuse/api/resources/projects/client.py
index 3f4e38e6e..2c63e3186 100644
--- a/langfuse/api/resources/projects/client.py
+++ b/langfuse/api/resources/projects/client.py
@@ -5,6 +5,7 @@
from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import pydantic_v1
from ...core.request_options import RequestOptions
from ..commons.errors.access_denied_error import AccessDeniedError
@@ -12,8 +13,16 @@
from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
from ..commons.errors.not_found_error import NotFoundError
from ..commons.errors.unauthorized_error import UnauthorizedError
+from .types.api_key_deletion_response import ApiKeyDeletionResponse
+from .types.api_key_list import ApiKeyList
+from .types.api_key_response import ApiKeyResponse
+from .types.project import Project
+from .types.project_deletion_response import ProjectDeletionResponse
from .types.projects import Projects
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
class ProjectsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
@@ -77,33 +86,260 @@ def get(
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
+ def create(
+ self,
+ *,
+ name: str,
+ retention: int,
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Project:
+ """
+ Create a new project (requires organization-scoped API key)
-class AsyncProjectsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ Parameters
+ ----------
+ name : str
- async def get(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> Projects:
+ retention : int
+ Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+ metadata : typing.Optional[typing.Dict[str, typing.Any]]
+ Optional metadata for the project
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Project
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.projects.create(
+ name="name",
+ retention=1,
+ )
"""
- Get Project associated with API key
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/projects",
+ method="POST",
+ json={"name": name, "metadata": metadata, "retention": retention},
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def update(
+ self,
+ project_id: str,
+ *,
+ name: str,
+ retention: int,
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Project:
+ """
+ Update a project by ID (requires organization-scoped API key).
Parameters
----------
+ project_id : str
+
+ name : str
+
+ retention : int
+ Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+ metadata : typing.Optional[typing.Dict[str, typing.Any]]
+ Optional metadata for the project
+
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- Projects
+ Project
Examples
--------
- import asyncio
+ from langfuse.client import FernLangfuse
- from langfuse.client import AsyncFernLangfuse
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.projects.update(
+ project_id="projectId",
+ name="name",
+ retention=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}",
+ method="PUT",
+ json={"name": name, "metadata": metadata, "retention": retention},
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
- client = AsyncFernLangfuse(
+ def delete(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ProjectDeletionResponse:
+ """
+ Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously.
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectDeletionResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.projects.delete(
+ project_id="projectId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ ProjectDeletionResponse, _response.json()
+ ) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_api_keys(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyList:
+ """
+ Get all API keys for a project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyList
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
@@ -111,20 +347,725 @@ async def get(
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
+ client.projects.get_api_keys(
+ project_id="projectId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ApiKeyList, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+ def create_api_key(
+ self,
+ project_id: str,
+ *,
+ note: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyResponse:
+ """
+ Create a new API key for a project (requires organization-scoped API key)
- async def main() -> None:
- await client.projects.get()
+ Parameters
+ ----------
+ project_id : str
+ note : typing.Optional[str]
+ Optional note for the API key
- asyncio.run(main())
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.projects.create_api_key(
+ project_id="projectId",
+ )
"""
- _response = await self._client_wrapper.httpx_client.request(
- "api/public/projects", method="GET", request_options=request_options
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys",
+ method="POST",
+ json={"note": note},
+ request_options=request_options,
+ omit=OMIT,
)
try:
if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(Projects, _response.json()) # type: ignore
+ return pydantic_v1.parse_obj_as(ApiKeyResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def delete_api_key(
+ self,
+ project_id: str,
+ api_key_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyDeletionResponse:
+ """
+ Delete an API key for a project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ api_key_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyDeletionResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.projects.delete_api_key(
+ project_id="projectId",
+ api_key_id="apiKeyId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ ApiKeyDeletionResponse, _response.json()
+ ) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncProjectsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> Projects:
+ """
+ Get Project associated with API key
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Projects
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.get()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/projects", method="GET", request_options=request_options
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Projects, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def create(
+ self,
+ *,
+ name: str,
+ retention: int,
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Project:
+ """
+ Create a new project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ name : str
+
+ retention : int
+ Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+ metadata : typing.Optional[typing.Dict[str, typing.Any]]
+ Optional metadata for the project
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Project
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.create(
+ name="name",
+ retention=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/projects",
+ method="POST",
+ json={"name": name, "metadata": metadata, "retention": retention},
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def update(
+ self,
+ project_id: str,
+ *,
+ name: str,
+ retention: int,
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Project:
+ """
+ Update a project by ID (requires organization-scoped API key).
+
+ Parameters
+ ----------
+ project_id : str
+
+ name : str
+
+ retention : int
+ Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional.
+
+ metadata : typing.Optional[typing.Dict[str, typing.Any]]
+ Optional metadata for the project
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Project
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.update(
+ project_id="projectId",
+ name="name",
+ retention=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}",
+ method="PUT",
+ json={"name": name, "metadata": metadata, "retention": retention},
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def delete(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ProjectDeletionResponse:
+ """
+ Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously.
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectDeletionResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.delete(
+ project_id="projectId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ ProjectDeletionResponse, _response.json()
+ ) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_api_keys(
+ self,
+ project_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyList:
+ """
+ Get all API keys for a project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyList
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.get_api_keys(
+ project_id="projectId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ApiKeyList, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def create_api_key(
+ self,
+ project_id: str,
+ *,
+ note: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyResponse:
+ """
+ Create a new API key for a project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ note : typing.Optional[str]
+ Optional note for the API key
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.create_api_key(
+ project_id="projectId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys",
+ method="POST",
+ json={"note": note},
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ApiKeyResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def delete_api_key(
+ self,
+ project_id: str,
+ api_key_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiKeyDeletionResponse:
+ """
+ Delete an API key for a project (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ project_id : str
+
+ api_key_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiKeyDeletionResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.projects.delete_api_key(
+ project_id="projectId",
+ api_key_id="apiKeyId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(
+ ApiKeyDeletionResponse, _response.json()
+ ) # type: ignore
if _response.status_code == 400:
raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
if _response.status_code == 401:
diff --git a/langfuse/api/resources/projects/types/__init__.py b/langfuse/api/resources/projects/types/__init__.py
index 11822a648..c59b62a62 100644
--- a/langfuse/api/resources/projects/types/__init__.py
+++ b/langfuse/api/resources/projects/types/__init__.py
@@ -1,6 +1,19 @@
# This file was auto-generated by Fern from our API Definition.
+from .api_key_deletion_response import ApiKeyDeletionResponse
+from .api_key_list import ApiKeyList
+from .api_key_response import ApiKeyResponse
+from .api_key_summary import ApiKeySummary
from .project import Project
+from .project_deletion_response import ProjectDeletionResponse
from .projects import Projects
-__all__ = ["Project", "Projects"]
+__all__ = [
+ "ApiKeyDeletionResponse",
+ "ApiKeyList",
+ "ApiKeyResponse",
+ "ApiKeySummary",
+ "Project",
+ "ProjectDeletionResponse",
+ "Projects",
+]
diff --git a/langfuse/api/resources/projects/types/api_key_deletion_response.py b/langfuse/api/resources/projects/types/api_key_deletion_response.py
new file mode 100644
index 000000000..6084400de
--- /dev/null
+++ b/langfuse/api/resources/projects/types/api_key_deletion_response.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ApiKeyDeletionResponse(pydantic_v1.BaseModel):
+ """
+ Response for API key deletion
+ """
+
+ success: bool
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/metrics/types/daily_metrics_details.py b/langfuse/api/resources/projects/types/api_key_list.py
similarity index 77%
rename from langfuse/api/resources/metrics/types/daily_metrics_details.py
rename to langfuse/api/resources/projects/types/api_key_list.py
index e97f65446..0a798ddbf 100644
--- a/langfuse/api/resources/metrics/types/daily_metrics_details.py
+++ b/langfuse/api/resources/projects/types/api_key_list.py
@@ -5,19 +5,15 @@
from ....core.datetime_utils import serialize_datetime
from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
-from .usage_by_model import UsageByModel
+from .api_key_summary import ApiKeySummary
-class DailyMetricsDetails(pydantic_v1.BaseModel):
- date: dt.date
- count_traces: int = pydantic_v1.Field(alias="countTraces")
- count_observations: int = pydantic_v1.Field(alias="countObservations")
- total_cost: float = pydantic_v1.Field(alias="totalCost")
+class ApiKeyList(pydantic_v1.BaseModel):
"""
- Total model cost in USD
+ List of API keys for a project
"""
- usage: typing.List[UsageByModel]
+ api_keys: typing.List[ApiKeySummary] = pydantic_v1.Field(alias="apiKeys")
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/projects/types/api_key_response.py b/langfuse/api/resources/projects/types/api_key_response.py
new file mode 100644
index 000000000..fc9364faf
--- /dev/null
+++ b/langfuse/api/resources/projects/types/api_key_response.py
@@ -0,0 +1,53 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ApiKeyResponse(pydantic_v1.BaseModel):
+ """
+ Response for API key creation
+ """
+
+ id: str
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ public_key: str = pydantic_v1.Field(alias="publicKey")
+ secret_key: str = pydantic_v1.Field(alias="secretKey")
+ display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey")
+ note: typing.Optional[str] = None
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/projects/types/api_key_summary.py b/langfuse/api/resources/projects/types/api_key_summary.py
new file mode 100644
index 000000000..b95633731
--- /dev/null
+++ b/langfuse/api/resources/projects/types/api_key_summary.py
@@ -0,0 +1,58 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ApiKeySummary(pydantic_v1.BaseModel):
+ """
+ Summary of an API key
+ """
+
+ id: str
+ created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
+ expires_at: typing.Optional[dt.datetime] = pydantic_v1.Field(
+ alias="expiresAt", default=None
+ )
+ last_used_at: typing.Optional[dt.datetime] = pydantic_v1.Field(
+ alias="lastUsedAt", default=None
+ )
+ note: typing.Optional[str] = None
+ public_key: str = pydantic_v1.Field(alias="publicKey")
+ display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/projects/types/project.py b/langfuse/api/resources/projects/types/project.py
index ad2b48cd2..2128a258c 100644
--- a/langfuse/api/resources/projects/types/project.py
+++ b/langfuse/api/resources/projects/types/project.py
@@ -10,6 +10,15 @@
class Project(pydantic_v1.BaseModel):
id: str
name: str
+ metadata: typing.Dict[str, typing.Any] = pydantic_v1.Field()
+ """
+ Metadata for the project
+ """
+
+ retention_days: int = pydantic_v1.Field(alias="retentionDays")
+ """
+ Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured.
+ """
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
@@ -39,5 +48,7 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
class Config:
frozen = True
smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
extra = pydantic_v1.Extra.allow
json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/projects/types/project_deletion_response.py b/langfuse/api/resources/projects/types/project_deletion_response.py
new file mode 100644
index 000000000..62c05d3d8
--- /dev/null
+++ b/langfuse/api/resources/projects/types/project_deletion_response.py
@@ -0,0 +1,43 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ProjectDeletionResponse(pydantic_v1.BaseModel):
+ success: bool
+ message: str
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/__init__.py b/langfuse/api/resources/scim/__init__.py
new file mode 100644
index 000000000..29655a8da
--- /dev/null
+++ b/langfuse/api/resources/scim/__init__.py
@@ -0,0 +1,41 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .types import (
+ AuthenticationScheme,
+ BulkConfig,
+ EmptyResponse,
+ FilterConfig,
+ ResourceMeta,
+ ResourceType,
+ ResourceTypesResponse,
+ SchemaExtension,
+ SchemaResource,
+ SchemasResponse,
+ ScimEmail,
+ ScimFeatureSupport,
+ ScimName,
+ ScimUser,
+ ScimUsersListResponse,
+ ServiceProviderConfig,
+ UserMeta,
+)
+
+__all__ = [
+ "AuthenticationScheme",
+ "BulkConfig",
+ "EmptyResponse",
+ "FilterConfig",
+ "ResourceMeta",
+ "ResourceType",
+ "ResourceTypesResponse",
+ "SchemaExtension",
+ "SchemaResource",
+ "SchemasResponse",
+ "ScimEmail",
+ "ScimFeatureSupport",
+ "ScimName",
+ "ScimUser",
+ "ScimUsersListResponse",
+ "ServiceProviderConfig",
+ "UserMeta",
+]
diff --git a/langfuse/api/resources/scim/client.py b/langfuse/api/resources/scim/client.py
new file mode 100644
index 000000000..38523a4f9
--- /dev/null
+++ b/langfuse/api/resources/scim/client.py
@@ -0,0 +1,1042 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.pydantic_utilities import pydantic_v1
+from ...core.request_options import RequestOptions
+from ..commons.errors.access_denied_error import AccessDeniedError
+from ..commons.errors.error import Error
+from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
+from ..commons.errors.not_found_error import NotFoundError
+from ..commons.errors.unauthorized_error import UnauthorizedError
+from .types.empty_response import EmptyResponse
+from .types.resource_types_response import ResourceTypesResponse
+from .types.schemas_response import SchemasResponse
+from .types.scim_email import ScimEmail
+from .types.scim_name import ScimName
+from .types.scim_user import ScimUser
+from .types.scim_users_list_response import ScimUsersListResponse
+from .types.service_provider_config import ServiceProviderConfig
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class ScimClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_service_provider_config(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ServiceProviderConfig:
+ """
+ Get SCIM Service Provider Configuration (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ServiceProviderConfig
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.get_service_provider_config()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/scim/ServiceProviderConfig",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ServiceProviderConfig, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_resource_types(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ResourceTypesResponse:
+ """
+ Get SCIM Resource Types (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ResourceTypesResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.get_resource_types()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/scim/ResourceTypes",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ResourceTypesResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_schemas(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> SchemasResponse:
+ """
+ Get SCIM Schemas (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SchemasResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.get_schemas()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/scim/Schemas", method="GET", request_options=request_options
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(SchemasResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def list_users(
+ self,
+ *,
+ filter: typing.Optional[str] = None,
+ start_index: typing.Optional[int] = None,
+ count: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ScimUsersListResponse:
+ """
+ List users in the organization (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ filter : typing.Optional[str]
+ Filter expression (e.g. userName eq "value")
+
+ start_index : typing.Optional[int]
+ 1-based index of the first result to return (default 1)
+
+ count : typing.Optional[int]
+ Maximum number of results to return (default 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUsersListResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.list_users()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/scim/Users",
+ method="GET",
+ params={"filter": filter, "startIndex": start_index, "count": count},
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUsersListResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def create_user(
+ self,
+ *,
+ user_name: str,
+ name: ScimName,
+ emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT,
+ active: typing.Optional[bool] = OMIT,
+ password: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ScimUser:
+ """
+ Create a new user in the organization (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ user_name : str
+ User's email address (required)
+
+ name : ScimName
+ User's name information
+
+ emails : typing.Optional[typing.Sequence[ScimEmail]]
+ User's email addresses
+
+ active : typing.Optional[bool]
+ Whether the user is active
+
+ password : typing.Optional[str]
+ Initial password for the user
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUser
+
+ Examples
+ --------
+ from langfuse import ScimName
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.create_user(
+ user_name="userName",
+ name=ScimName(),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/scim/Users",
+ method="POST",
+ json={
+ "userName": user_name,
+ "name": name,
+ "emails": emails,
+ "active": active,
+ "password": password,
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_user(
+ self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ScimUser:
+ """
+ Get a specific user by ID (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ user_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUser
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.get_user(
+ user_id="userId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/scim/Users/{jsonable_encoder(user_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def delete_user(
+ self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> EmptyResponse:
+ """
+ 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.
+
+ Parameters
+ ----------
+ user_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EmptyResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.scim.delete_user(
+ user_id="userId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/scim/Users/{jsonable_encoder(user_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(EmptyResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncScimClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_service_provider_config(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ServiceProviderConfig:
+ """
+ Get SCIM Service Provider Configuration (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ServiceProviderConfig
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.get_service_provider_config()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/scim/ServiceProviderConfig",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ServiceProviderConfig, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_resource_types(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ResourceTypesResponse:
+ """
+ Get SCIM Resource Types (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ResourceTypesResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.get_resource_types()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/scim/ResourceTypes",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ResourceTypesResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_schemas(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> SchemasResponse:
+ """
+ Get SCIM Schemas (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SchemasResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.get_schemas()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/scim/Schemas", method="GET", request_options=request_options
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(SchemasResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def list_users(
+ self,
+ *,
+ filter: typing.Optional[str] = None,
+ start_index: typing.Optional[int] = None,
+ count: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ScimUsersListResponse:
+ """
+ List users in the organization (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ filter : typing.Optional[str]
+ Filter expression (e.g. userName eq "value")
+
+ start_index : typing.Optional[int]
+ 1-based index of the first result to return (default 1)
+
+ count : typing.Optional[int]
+ Maximum number of results to return (default 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUsersListResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.list_users()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/scim/Users",
+ method="GET",
+ params={"filter": filter, "startIndex": start_index, "count": count},
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUsersListResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def create_user(
+ self,
+ *,
+ user_name: str,
+ name: ScimName,
+ emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT,
+ active: typing.Optional[bool] = OMIT,
+ password: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ScimUser:
+ """
+ Create a new user in the organization (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ user_name : str
+ User's email address (required)
+
+ name : ScimName
+ User's name information
+
+ emails : typing.Optional[typing.Sequence[ScimEmail]]
+ User's email addresses
+
+ active : typing.Optional[bool]
+ Whether the user is active
+
+ password : typing.Optional[str]
+ Initial password for the user
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUser
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse import ScimName
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.create_user(
+ user_name="userName",
+ name=ScimName(),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/scim/Users",
+ method="POST",
+ json={
+ "userName": user_name,
+ "name": name,
+ "emails": emails,
+ "active": active,
+ "password": password,
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_user(
+ self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ScimUser:
+ """
+ Get a specific user by ID (requires organization-scoped API key)
+
+ Parameters
+ ----------
+ user_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScimUser
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.get_user(
+ user_id="userId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/scim/Users/{jsonable_encoder(user_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def delete_user(
+ self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> EmptyResponse:
+ """
+ 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.
+
+ Parameters
+ ----------
+ user_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EmptyResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.scim.delete_user(
+ user_id="userId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/scim/Users/{jsonable_encoder(user_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(EmptyResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/langfuse/api/resources/scim/types/__init__.py b/langfuse/api/resources/scim/types/__init__.py
new file mode 100644
index 000000000..c0b60e8c2
--- /dev/null
+++ b/langfuse/api/resources/scim/types/__init__.py
@@ -0,0 +1,39 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .authentication_scheme import AuthenticationScheme
+from .bulk_config import BulkConfig
+from .empty_response import EmptyResponse
+from .filter_config import FilterConfig
+from .resource_meta import ResourceMeta
+from .resource_type import ResourceType
+from .resource_types_response import ResourceTypesResponse
+from .schema_extension import SchemaExtension
+from .schema_resource import SchemaResource
+from .schemas_response import SchemasResponse
+from .scim_email import ScimEmail
+from .scim_feature_support import ScimFeatureSupport
+from .scim_name import ScimName
+from .scim_user import ScimUser
+from .scim_users_list_response import ScimUsersListResponse
+from .service_provider_config import ServiceProviderConfig
+from .user_meta import UserMeta
+
+__all__ = [
+ "AuthenticationScheme",
+ "BulkConfig",
+ "EmptyResponse",
+ "FilterConfig",
+ "ResourceMeta",
+ "ResourceType",
+ "ResourceTypesResponse",
+ "SchemaExtension",
+ "SchemaResource",
+ "SchemasResponse",
+ "ScimEmail",
+ "ScimFeatureSupport",
+ "ScimName",
+ "ScimUser",
+ "ScimUsersListResponse",
+ "ServiceProviderConfig",
+ "UserMeta",
+]
diff --git a/langfuse/api/resources/scim/types/authentication_scheme.py b/langfuse/api/resources/scim/types/authentication_scheme.py
new file mode 100644
index 000000000..6d6526901
--- /dev/null
+++ b/langfuse/api/resources/scim/types/authentication_scheme.py
@@ -0,0 +1,48 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class AuthenticationScheme(pydantic_v1.BaseModel):
+ name: str
+ description: str
+ spec_uri: str = pydantic_v1.Field(alias="specUri")
+ type: str
+ primary: bool
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/bulk_config.py b/langfuse/api/resources/scim/types/bulk_config.py
new file mode 100644
index 000000000..0b41af5cf
--- /dev/null
+++ b/langfuse/api/resources/scim/types/bulk_config.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class BulkConfig(pydantic_v1.BaseModel):
+ supported: bool
+ max_operations: int = pydantic_v1.Field(alias="maxOperations")
+ max_payload_size: int = pydantic_v1.Field(alias="maxPayloadSize")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/empty_response.py b/langfuse/api/resources/scim/types/empty_response.py
new file mode 100644
index 000000000..82105e8a3
--- /dev/null
+++ b/langfuse/api/resources/scim/types/empty_response.py
@@ -0,0 +1,44 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class EmptyResponse(pydantic_v1.BaseModel):
+ """
+ Empty response for 204 No Content responses
+ """
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/filter_config.py b/langfuse/api/resources/scim/types/filter_config.py
new file mode 100644
index 000000000..2bd035867
--- /dev/null
+++ b/langfuse/api/resources/scim/types/filter_config.py
@@ -0,0 +1,45 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class FilterConfig(pydantic_v1.BaseModel):
+ supported: bool
+ max_results: int = pydantic_v1.Field(alias="maxResults")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/resource_meta.py b/langfuse/api/resources/scim/types/resource_meta.py
new file mode 100644
index 000000000..a61d14442
--- /dev/null
+++ b/langfuse/api/resources/scim/types/resource_meta.py
@@ -0,0 +1,45 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ResourceMeta(pydantic_v1.BaseModel):
+ resource_type: str = pydantic_v1.Field(alias="resourceType")
+ location: str
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/resource_type.py b/langfuse/api/resources/scim/types/resource_type.py
new file mode 100644
index 000000000..264dc87cf
--- /dev/null
+++ b/langfuse/api/resources/scim/types/resource_type.py
@@ -0,0 +1,55 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .resource_meta import ResourceMeta
+from .schema_extension import SchemaExtension
+
+
+class ResourceType(pydantic_v1.BaseModel):
+ schemas: typing.Optional[typing.List[str]] = None
+ id: str
+ name: str
+ endpoint: str
+ description: str
+ schema_: str = pydantic_v1.Field(alias="schema")
+ schema_extensions: typing.List[SchemaExtension] = pydantic_v1.Field(
+ alias="schemaExtensions"
+ )
+ meta: ResourceMeta
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/resource_types_response.py b/langfuse/api/resources/scim/types/resource_types_response.py
new file mode 100644
index 000000000..cce65b8d1
--- /dev/null
+++ b/langfuse/api/resources/scim/types/resource_types_response.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .resource_type import ResourceType
+
+
+class ResourceTypesResponse(pydantic_v1.BaseModel):
+ schemas: typing.List[str]
+ total_results: int = pydantic_v1.Field(alias="totalResults")
+ resources: typing.List[ResourceType] = pydantic_v1.Field(alias="Resources")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/schema_extension.py b/langfuse/api/resources/scim/types/schema_extension.py
new file mode 100644
index 000000000..c5ede44b9
--- /dev/null
+++ b/langfuse/api/resources/scim/types/schema_extension.py
@@ -0,0 +1,45 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class SchemaExtension(pydantic_v1.BaseModel):
+ schema_: str = pydantic_v1.Field(alias="schema")
+ required: bool
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/schema_resource.py b/langfuse/api/resources/scim/types/schema_resource.py
new file mode 100644
index 000000000..e85cda9a0
--- /dev/null
+++ b/langfuse/api/resources/scim/types/schema_resource.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .resource_meta import ResourceMeta
+
+
+class SchemaResource(pydantic_v1.BaseModel):
+ id: str
+ name: str
+ description: str
+ attributes: typing.List[typing.Any]
+ meta: ResourceMeta
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/schemas_response.py b/langfuse/api/resources/scim/types/schemas_response.py
new file mode 100644
index 000000000..4c7b8199a
--- /dev/null
+++ b/langfuse/api/resources/scim/types/schemas_response.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .schema_resource import SchemaResource
+
+
+class SchemasResponse(pydantic_v1.BaseModel):
+ schemas: typing.List[str]
+ total_results: int = pydantic_v1.Field(alias="totalResults")
+ resources: typing.List[SchemaResource] = pydantic_v1.Field(alias="Resources")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/scim_email.py b/langfuse/api/resources/scim/types/scim_email.py
new file mode 100644
index 000000000..71b817809
--- /dev/null
+++ b/langfuse/api/resources/scim/types/scim_email.py
@@ -0,0 +1,44 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ScimEmail(pydantic_v1.BaseModel):
+ primary: bool
+ value: str
+ type: str
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/scim_feature_support.py b/langfuse/api/resources/scim/types/scim_feature_support.py
new file mode 100644
index 000000000..2aedc07b5
--- /dev/null
+++ b/langfuse/api/resources/scim/types/scim_feature_support.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ScimFeatureSupport(pydantic_v1.BaseModel):
+ supported: bool
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/scim_name.py b/langfuse/api/resources/scim/types/scim_name.py
new file mode 100644
index 000000000..c2812a25a
--- /dev/null
+++ b/langfuse/api/resources/scim/types/scim_name.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class ScimName(pydantic_v1.BaseModel):
+ formatted: typing.Optional[str] = None
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/scim_user.py b/langfuse/api/resources/scim/types/scim_user.py
new file mode 100644
index 000000000..581bab8c1
--- /dev/null
+++ b/langfuse/api/resources/scim/types/scim_user.py
@@ -0,0 +1,52 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .scim_email import ScimEmail
+from .scim_name import ScimName
+from .user_meta import UserMeta
+
+
+class ScimUser(pydantic_v1.BaseModel):
+ schemas: typing.List[str]
+ id: str
+ user_name: str = pydantic_v1.Field(alias="userName")
+ name: ScimName
+ emails: typing.List[ScimEmail]
+ meta: UserMeta
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/scim_users_list_response.py b/langfuse/api/resources/scim/types/scim_users_list_response.py
new file mode 100644
index 000000000..3c41a4d16
--- /dev/null
+++ b/langfuse/api/resources/scim/types/scim_users_list_response.py
@@ -0,0 +1,49 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .scim_user import ScimUser
+
+
+class ScimUsersListResponse(pydantic_v1.BaseModel):
+ schemas: typing.List[str]
+ total_results: int = pydantic_v1.Field(alias="totalResults")
+ start_index: int = pydantic_v1.Field(alias="startIndex")
+ items_per_page: int = pydantic_v1.Field(alias="itemsPerPage")
+ resources: typing.List[ScimUser] = pydantic_v1.Field(alias="Resources")
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/service_provider_config.py b/langfuse/api/resources/scim/types/service_provider_config.py
new file mode 100644
index 000000000..9bf611ae6
--- /dev/null
+++ b/langfuse/api/resources/scim/types/service_provider_config.py
@@ -0,0 +1,60 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+from .authentication_scheme import AuthenticationScheme
+from .bulk_config import BulkConfig
+from .filter_config import FilterConfig
+from .resource_meta import ResourceMeta
+from .scim_feature_support import ScimFeatureSupport
+
+
+class ServiceProviderConfig(pydantic_v1.BaseModel):
+ schemas: typing.List[str]
+ documentation_uri: str = pydantic_v1.Field(alias="documentationUri")
+ patch: ScimFeatureSupport
+ bulk: BulkConfig
+ filter: FilterConfig
+ change_password: ScimFeatureSupport = pydantic_v1.Field(alias="changePassword")
+ sort: ScimFeatureSupport
+ etag: ScimFeatureSupport
+ authentication_schemes: typing.List[AuthenticationScheme] = pydantic_v1.Field(
+ alias="authenticationSchemes"
+ )
+ meta: ResourceMeta
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/scim/types/user_meta.py b/langfuse/api/resources/scim/types/user_meta.py
new file mode 100644
index 000000000..09cb7e6a0
--- /dev/null
+++ b/langfuse/api/resources/scim/types/user_meta.py
@@ -0,0 +1,48 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from ....core.datetime_utils import serialize_datetime
+from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1
+
+
+class UserMeta(pydantic_v1.BaseModel):
+ resource_type: str = pydantic_v1.Field(alias="resourceType")
+ created: typing.Optional[str] = None
+ last_modified: typing.Optional[str] = pydantic_v1.Field(
+ alias="lastModified", default=None
+ )
+
+ def json(self, **kwargs: typing.Any) -> str:
+ kwargs_with_defaults: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ "by_alias": True,
+ "exclude_none": True,
+ **kwargs,
+ }
+
+ return deep_union_pydantic_dicts(
+ super().dict(**kwargs_with_defaults_exclude_unset),
+ super().dict(**kwargs_with_defaults_exclude_none),
+ )
+
+ class Config:
+ frozen = True
+ smart_union = True
+ allow_population_by_field_name = True
+ populate_by_name = True
+ extra = pydantic_v1.Extra.allow
+ json_encoders = {dt.datetime: serialize_datetime}
diff --git a/langfuse/api/resources/score/__init__.py b/langfuse/api/resources/score/__init__.py
index 97fd51ffa..566310af3 100644
--- a/langfuse/api/resources/score/__init__.py
+++ b/langfuse/api/resources/score/__init__.py
@@ -1,29 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import (
- CreateScoreRequest,
- CreateScoreResponse,
- GetScoresResponse,
- GetScoresResponseData,
- GetScoresResponseDataBoolean,
- GetScoresResponseDataCategorical,
- GetScoresResponseDataNumeric,
- GetScoresResponseData_Boolean,
- GetScoresResponseData_Categorical,
- GetScoresResponseData_Numeric,
- GetScoresResponseTraceData,
-)
+from .types import CreateScoreRequest, CreateScoreResponse
-__all__ = [
- "CreateScoreRequest",
- "CreateScoreResponse",
- "GetScoresResponse",
- "GetScoresResponseData",
- "GetScoresResponseDataBoolean",
- "GetScoresResponseDataCategorical",
- "GetScoresResponseDataNumeric",
- "GetScoresResponseData_Boolean",
- "GetScoresResponseData_Categorical",
- "GetScoresResponseData_Numeric",
- "GetScoresResponseTraceData",
-]
+__all__ = ["CreateScoreRequest", "CreateScoreResponse"]
diff --git a/langfuse/api/resources/score/client.py b/langfuse/api/resources/score/client.py
index 774f4f218..0c259929f 100644
--- a/langfuse/api/resources/score/client.py
+++ b/langfuse/api/resources/score/client.py
@@ -1,12 +1,10 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
from json.decoder import JSONDecodeError
from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.datetime_utils import serialize_datetime
from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import pydantic_v1
from ...core.request_options import RequestOptions
@@ -15,12 +13,8 @@
from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
from ..commons.errors.not_found_error import NotFoundError
from ..commons.errors.unauthorized_error import UnauthorizedError
-from ..commons.types.score import Score
-from ..commons.types.score_data_type import ScoreDataType
-from ..commons.types.score_source import ScoreSource
from .types.create_score_request import CreateScoreRequest
from .types.create_score_response import CreateScoreResponse
-from .types.get_scores_response import GetScoresResponse
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -37,7 +31,7 @@ def create(
request_options: typing.Optional[RequestOptions] = None,
) -> CreateScoreResponse:
"""
- Create a score
+ Create a score (supports both trace and session scores)
Parameters
----------
@@ -65,7 +59,6 @@ def create(
)
client.score.create(
request=CreateScoreRequest(
- trace_id="traceId",
name="name",
value=1.1,
),
@@ -104,219 +97,11 @@ def create(
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
- def get(
- self,
- *,
- page: typing.Optional[int] = None,
- limit: typing.Optional[int] = None,
- user_id: typing.Optional[str] = None,
- name: typing.Optional[str] = None,
- from_timestamp: typing.Optional[dt.datetime] = None,
- to_timestamp: typing.Optional[dt.datetime] = None,
- environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- source: typing.Optional[ScoreSource] = None,
- operator: typing.Optional[str] = None,
- value: typing.Optional[float] = None,
- score_ids: typing.Optional[str] = None,
- config_id: typing.Optional[str] = None,
- queue_id: typing.Optional[str] = None,
- data_type: typing.Optional[ScoreDataType] = None,
- trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> GetScoresResponse:
- """
- Get a list of scores
-
- Parameters
- ----------
- page : typing.Optional[int]
- Page number, starts at 1.
-
- limit : typing.Optional[int]
- Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
-
- user_id : typing.Optional[str]
- Retrieve only scores with this userId associated to the trace.
-
- name : typing.Optional[str]
- Retrieve only scores with this name.
-
- from_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include scores created on or after a certain datetime (ISO 8601)
-
- to_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include scores created before a certain datetime (ISO 8601)
-
- environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for scores where the environment is one of the provided values.
-
- source : typing.Optional[ScoreSource]
- Retrieve only scores from a specific source.
-
- operator : typing.Optional[str]
- Retrieve only scores with value.
-
- value : typing.Optional[float]
- Retrieve only scores with value.
-
- score_ids : typing.Optional[str]
- Comma-separated list of score IDs to limit the results to.
-
- config_id : typing.Optional[str]
- Retrieve only scores with a specific configId.
-
- queue_id : typing.Optional[str]
- Retrieve only scores with a specific annotation queueId.
-
- data_type : typing.Optional[ScoreDataType]
- Retrieve only scores with a specific dataType.
-
- trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only scores linked to traces that include all of these tags will be returned.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetScoresResponse
-
- Examples
- --------
- from langfuse.client import FernLangfuse
-
- client = FernLangfuse(
- x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
- x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
- x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
- username="YOUR_USERNAME",
- password="YOUR_PASSWORD",
- base_url="https://yourhost.com/path/to/api",
- )
- client.score.get()
- """
- _response = self._client_wrapper.httpx_client.request(
- "api/public/scores",
- method="GET",
- params={
- "page": page,
- "limit": limit,
- "userId": user_id,
- "name": name,
- "fromTimestamp": serialize_datetime(from_timestamp)
- if from_timestamp is not None
- else None,
- "toTimestamp": serialize_datetime(to_timestamp)
- if to_timestamp is not None
- else None,
- "environment": environment,
- "source": source,
- "operator": operator,
- "value": value,
- "scoreIds": score_ids,
- "configId": config_id,
- "queueId": queue_id,
- "dataType": data_type,
- "traceTags": trace_tags,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 403:
- raise AccessDeniedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 405:
- raise MethodNotAllowedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
- def get_by_id(
- self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> Score:
- """
- Get a score
-
- Parameters
- ----------
- score_id : str
- The unique langfuse identifier of a score
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Score
-
- Examples
- --------
- from langfuse.client import FernLangfuse
-
- client = FernLangfuse(
- x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
- x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
- x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
- username="YOUR_USERNAME",
- password="YOUR_PASSWORD",
- base_url="https://yourhost.com/path/to/api",
- )
- client.score.get_by_id(
- score_id="scoreId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"api/public/scores/{jsonable_encoder(score_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 403:
- raise AccessDeniedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 405:
- raise MethodNotAllowedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
def delete(
self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> None:
"""
- Delete a score
+ Delete a score (supports both trace and session scores)
Parameters
----------
@@ -389,7 +174,7 @@ async def create(
request_options: typing.Optional[RequestOptions] = None,
) -> CreateScoreResponse:
"""
- Create a score
+ Create a score (supports both trace and session scores)
Parameters
----------
@@ -422,7 +207,6 @@ async def create(
async def main() -> None:
await client.score.create(
request=CreateScoreRequest(
- trace_id="traceId",
name="name",
value=1.1,
),
@@ -464,235 +248,11 @@ async def main() -> None:
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
- async def get(
- self,
- *,
- page: typing.Optional[int] = None,
- limit: typing.Optional[int] = None,
- user_id: typing.Optional[str] = None,
- name: typing.Optional[str] = None,
- from_timestamp: typing.Optional[dt.datetime] = None,
- to_timestamp: typing.Optional[dt.datetime] = None,
- environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- source: typing.Optional[ScoreSource] = None,
- operator: typing.Optional[str] = None,
- value: typing.Optional[float] = None,
- score_ids: typing.Optional[str] = None,
- config_id: typing.Optional[str] = None,
- queue_id: typing.Optional[str] = None,
- data_type: typing.Optional[ScoreDataType] = None,
- trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> GetScoresResponse:
- """
- Get a list of scores
-
- Parameters
- ----------
- page : typing.Optional[int]
- Page number, starts at 1.
-
- limit : typing.Optional[int]
- Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
-
- user_id : typing.Optional[str]
- Retrieve only scores with this userId associated to the trace.
-
- name : typing.Optional[str]
- Retrieve only scores with this name.
-
- from_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include scores created on or after a certain datetime (ISO 8601)
-
- to_timestamp : typing.Optional[dt.datetime]
- Optional filter to only include scores created before a certain datetime (ISO 8601)
-
- environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Optional filter for scores where the environment is one of the provided values.
-
- source : typing.Optional[ScoreSource]
- Retrieve only scores from a specific source.
-
- operator : typing.Optional[str]
- Retrieve only scores with value.
-
- value : typing.Optional[float]
- Retrieve only scores with value.
-
- score_ids : typing.Optional[str]
- Comma-separated list of score IDs to limit the results to.
-
- config_id : typing.Optional[str]
- Retrieve only scores with a specific configId.
-
- queue_id : typing.Optional[str]
- Retrieve only scores with a specific annotation queueId.
-
- data_type : typing.Optional[ScoreDataType]
- Retrieve only scores with a specific dataType.
-
- trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only scores linked to traces that include all of these tags will be returned.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetScoresResponse
-
- Examples
- --------
- import asyncio
-
- from langfuse.client import AsyncFernLangfuse
-
- client = AsyncFernLangfuse(
- x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
- x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
- x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
- username="YOUR_USERNAME",
- password="YOUR_PASSWORD",
- base_url="https://yourhost.com/path/to/api",
- )
-
-
- async def main() -> None:
- await client.score.get()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "api/public/scores",
- method="GET",
- params={
- "page": page,
- "limit": limit,
- "userId": user_id,
- "name": name,
- "fromTimestamp": serialize_datetime(from_timestamp)
- if from_timestamp is not None
- else None,
- "toTimestamp": serialize_datetime(to_timestamp)
- if to_timestamp is not None
- else None,
- "environment": environment,
- "source": source,
- "operator": operator,
- "value": value,
- "scoreIds": score_ids,
- "configId": config_id,
- "queueId": queue_id,
- "dataType": data_type,
- "traceTags": trace_tags,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 403:
- raise AccessDeniedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 405:
- raise MethodNotAllowedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
- async def get_by_id(
- self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> Score:
- """
- Get a score
-
- Parameters
- ----------
- score_id : str
- The unique langfuse identifier of a score
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Score
-
- Examples
- --------
- import asyncio
-
- from langfuse.client import AsyncFernLangfuse
-
- client = AsyncFernLangfuse(
- x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
- x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
- x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
- username="YOUR_USERNAME",
- password="YOUR_PASSWORD",
- base_url="https://yourhost.com/path/to/api",
- )
-
-
- async def main() -> None:
- await client.score.get_by_id(
- score_id="scoreId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"api/public/scores/{jsonable_encoder(score_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 403:
- raise AccessDeniedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 405:
- raise MethodNotAllowedError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(
- pydantic_v1.parse_obj_as(typing.Any, _response.json())
- ) # type: ignore
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
async def delete(
self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> None:
"""
- Delete a score
+ Delete a score (supports both trace and session scores)
Parameters
----------
diff --git a/langfuse/api/resources/score/types/__init__.py b/langfuse/api/resources/score/types/__init__.py
index b627bad8f..72d61f6f3 100644
--- a/langfuse/api/resources/score/types/__init__.py
+++ b/langfuse/api/resources/score/types/__init__.py
@@ -2,28 +2,5 @@
from .create_score_request import CreateScoreRequest
from .create_score_response import CreateScoreResponse
-from .get_scores_response import GetScoresResponse
-from .get_scores_response_data import (
- GetScoresResponseData,
- GetScoresResponseData_Boolean,
- GetScoresResponseData_Categorical,
- GetScoresResponseData_Numeric,
-)
-from .get_scores_response_data_boolean import GetScoresResponseDataBoolean
-from .get_scores_response_data_categorical import GetScoresResponseDataCategorical
-from .get_scores_response_data_numeric import GetScoresResponseDataNumeric
-from .get_scores_response_trace_data import GetScoresResponseTraceData
-__all__ = [
- "CreateScoreRequest",
- "CreateScoreResponse",
- "GetScoresResponse",
- "GetScoresResponseData",
- "GetScoresResponseDataBoolean",
- "GetScoresResponseDataCategorical",
- "GetScoresResponseDataNumeric",
- "GetScoresResponseData_Boolean",
- "GetScoresResponseData_Categorical",
- "GetScoresResponseData_Numeric",
- "GetScoresResponseTraceData",
-]
+__all__ = ["CreateScoreRequest", "CreateScoreResponse"]
diff --git a/langfuse/api/resources/score/types/create_score_request.py b/langfuse/api/resources/score/types/create_score_request.py
index c11030f4f..d6ad037a4 100644
--- a/langfuse/api/resources/score/types/create_score_request.py
+++ b/langfuse/api/resources/score/types/create_score_request.py
@@ -23,17 +23,24 @@ class CreateScoreRequest(pydantic_v1.BaseModel):
"""
id: typing.Optional[str] = None
- trace_id: str = pydantic_v1.Field(alias="traceId")
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
+ observation_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="observationId", default=None
+ )
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
name: str
value: CreateScoreValue = pydantic_v1.Field()
"""
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)
"""
- observation_id: typing.Optional[str] = pydantic_v1.Field(
- alias="observationId", default=None
- )
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
environment: typing.Optional[str] = pydantic_v1.Field(default=None)
"""
The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
diff --git a/langfuse/api/resources/score_v_2/__init__.py b/langfuse/api/resources/score_v_2/__init__.py
new file mode 100644
index 000000000..40599eec1
--- /dev/null
+++ b/langfuse/api/resources/score_v_2/__init__.py
@@ -0,0 +1,25 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .types import (
+ GetScoresResponse,
+ GetScoresResponseData,
+ GetScoresResponseDataBoolean,
+ GetScoresResponseDataCategorical,
+ GetScoresResponseDataNumeric,
+ GetScoresResponseData_Boolean,
+ GetScoresResponseData_Categorical,
+ GetScoresResponseData_Numeric,
+ GetScoresResponseTraceData,
+)
+
+__all__ = [
+ "GetScoresResponse",
+ "GetScoresResponseData",
+ "GetScoresResponseDataBoolean",
+ "GetScoresResponseDataCategorical",
+ "GetScoresResponseDataNumeric",
+ "GetScoresResponseData_Boolean",
+ "GetScoresResponseData_Categorical",
+ "GetScoresResponseData_Numeric",
+ "GetScoresResponseTraceData",
+]
diff --git a/langfuse/api/resources/score_v_2/client.py b/langfuse/api/resources/score_v_2/client.py
new file mode 100644
index 000000000..894b44f22
--- /dev/null
+++ b/langfuse/api/resources/score_v_2/client.py
@@ -0,0 +1,463 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.datetime_utils import serialize_datetime
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.pydantic_utilities import pydantic_v1
+from ...core.request_options import RequestOptions
+from ..commons.errors.access_denied_error import AccessDeniedError
+from ..commons.errors.error import Error
+from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
+from ..commons.errors.not_found_error import NotFoundError
+from ..commons.errors.unauthorized_error import UnauthorizedError
+from ..commons.types.score import Score
+from ..commons.types.score_data_type import ScoreDataType
+from ..commons.types.score_source import ScoreSource
+from .types.get_scores_response import GetScoresResponse
+
+
+class ScoreV2Client:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get(
+ self,
+ *,
+ page: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ user_id: typing.Optional[str] = None,
+ name: typing.Optional[str] = None,
+ from_timestamp: typing.Optional[dt.datetime] = None,
+ to_timestamp: typing.Optional[dt.datetime] = None,
+ environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ source: typing.Optional[ScoreSource] = None,
+ operator: typing.Optional[str] = None,
+ value: typing.Optional[float] = None,
+ score_ids: typing.Optional[str] = None,
+ config_id: typing.Optional[str] = None,
+ queue_id: typing.Optional[str] = None,
+ data_type: typing.Optional[ScoreDataType] = None,
+ trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> GetScoresResponse:
+ """
+ Get a list of scores (supports both trace and session scores)
+
+ Parameters
+ ----------
+ page : typing.Optional[int]
+ Page number, starts at 1.
+
+ limit : typing.Optional[int]
+ Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
+
+ user_id : typing.Optional[str]
+ Retrieve only scores with this userId associated to the trace.
+
+ name : typing.Optional[str]
+ Retrieve only scores with this name.
+
+ from_timestamp : typing.Optional[dt.datetime]
+ Optional filter to only include scores created on or after a certain datetime (ISO 8601)
+
+ to_timestamp : typing.Optional[dt.datetime]
+ Optional filter to only include scores created before a certain datetime (ISO 8601)
+
+ environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
+ Optional filter for scores where the environment is one of the provided values.
+
+ source : typing.Optional[ScoreSource]
+ Retrieve only scores from a specific source.
+
+ operator : typing.Optional[str]
+ Retrieve only scores with value.
+
+ value : typing.Optional[float]
+ Retrieve only scores with value.
+
+ score_ids : typing.Optional[str]
+ Comma-separated list of score IDs to limit the results to.
+
+ config_id : typing.Optional[str]
+ Retrieve only scores with a specific configId.
+
+ queue_id : typing.Optional[str]
+ Retrieve only scores with a specific annotation queueId.
+
+ data_type : typing.Optional[ScoreDataType]
+ Retrieve only scores with a specific dataType.
+
+ trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
+ Only scores linked to traces that include all of these tags will be returned.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ GetScoresResponse
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.score_v_2.get()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/public/v2/scores",
+ method="GET",
+ params={
+ "page": page,
+ "limit": limit,
+ "userId": user_id,
+ "name": name,
+ "fromTimestamp": serialize_datetime(from_timestamp)
+ if from_timestamp is not None
+ else None,
+ "toTimestamp": serialize_datetime(to_timestamp)
+ if to_timestamp is not None
+ else None,
+ "environment": environment,
+ "source": source,
+ "operator": operator,
+ "value": value,
+ "scoreIds": score_ids,
+ "configId": config_id,
+ "queueId": queue_id,
+ "dataType": data_type,
+ "traceTags": trace_tags,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_by_id(
+ self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> Score:
+ """
+ Get a score (supports both trace and session scores)
+
+ Parameters
+ ----------
+ score_id : str
+ The unique langfuse identifier of a score
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Score
+
+ Examples
+ --------
+ from langfuse.client import FernLangfuse
+
+ client = FernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+ client.score_v_2.get_by_id(
+ score_id="scoreId",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/public/v2/scores/{jsonable_encoder(score_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncScoreV2Client:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get(
+ self,
+ *,
+ page: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ user_id: typing.Optional[str] = None,
+ name: typing.Optional[str] = None,
+ from_timestamp: typing.Optional[dt.datetime] = None,
+ to_timestamp: typing.Optional[dt.datetime] = None,
+ environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ source: typing.Optional[ScoreSource] = None,
+ operator: typing.Optional[str] = None,
+ value: typing.Optional[float] = None,
+ score_ids: typing.Optional[str] = None,
+ config_id: typing.Optional[str] = None,
+ queue_id: typing.Optional[str] = None,
+ data_type: typing.Optional[ScoreDataType] = None,
+ trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> GetScoresResponse:
+ """
+ Get a list of scores (supports both trace and session scores)
+
+ Parameters
+ ----------
+ page : typing.Optional[int]
+ Page number, starts at 1.
+
+ limit : typing.Optional[int]
+ Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
+
+ user_id : typing.Optional[str]
+ Retrieve only scores with this userId associated to the trace.
+
+ name : typing.Optional[str]
+ Retrieve only scores with this name.
+
+ from_timestamp : typing.Optional[dt.datetime]
+ Optional filter to only include scores created on or after a certain datetime (ISO 8601)
+
+ to_timestamp : typing.Optional[dt.datetime]
+ Optional filter to only include scores created before a certain datetime (ISO 8601)
+
+ environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
+ Optional filter for scores where the environment is one of the provided values.
+
+ source : typing.Optional[ScoreSource]
+ Retrieve only scores from a specific source.
+
+ operator : typing.Optional[str]
+ Retrieve only scores with value.
+
+ value : typing.Optional[float]
+ Retrieve only scores with value.
+
+ score_ids : typing.Optional[str]
+ Comma-separated list of score IDs to limit the results to.
+
+ config_id : typing.Optional[str]
+ Retrieve only scores with a specific configId.
+
+ queue_id : typing.Optional[str]
+ Retrieve only scores with a specific annotation queueId.
+
+ data_type : typing.Optional[ScoreDataType]
+ Retrieve only scores with a specific dataType.
+
+ trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
+ Only scores linked to traces that include all of these tags will be returned.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ GetScoresResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.score_v_2.get()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/public/v2/scores",
+ method="GET",
+ params={
+ "page": page,
+ "limit": limit,
+ "userId": user_id,
+ "name": name,
+ "fromTimestamp": serialize_datetime(from_timestamp)
+ if from_timestamp is not None
+ else None,
+ "toTimestamp": serialize_datetime(to_timestamp)
+ if to_timestamp is not None
+ else None,
+ "environment": environment,
+ "source": source,
+ "operator": operator,
+ "value": value,
+ "scoreIds": score_ids,
+ "configId": config_id,
+ "queueId": queue_id,
+ "dataType": data_type,
+ "traceTags": trace_tags,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_by_id(
+ self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> Score:
+ """
+ Get a score (supports both trace and session scores)
+
+ Parameters
+ ----------
+ score_id : str
+ The unique langfuse identifier of a score
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Score
+
+ Examples
+ --------
+ import asyncio
+
+ from langfuse.client import AsyncFernLangfuse
+
+ client = AsyncFernLangfuse(
+ x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
+ x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
+ x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
+ username="YOUR_USERNAME",
+ password="YOUR_PASSWORD",
+ base_url="https://yourhost.com/path/to/api",
+ )
+
+
+ async def main() -> None:
+ await client.score_v_2.get_by_id(
+ score_id="scoreId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/public/v2/scores/{jsonable_encoder(score_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore
+ if _response.status_code == 400:
+ raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 403:
+ raise AccessDeniedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 405:
+ raise MethodNotAllowedError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ if _response.status_code == 404:
+ raise NotFoundError(
+ pydantic_v1.parse_obj_as(typing.Any, _response.json())
+ ) # type: ignore
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/langfuse/api/resources/score_v_2/types/__init__.py b/langfuse/api/resources/score_v_2/types/__init__.py
new file mode 100644
index 000000000..480ed3406
--- /dev/null
+++ b/langfuse/api/resources/score_v_2/types/__init__.py
@@ -0,0 +1,25 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .get_scores_response import GetScoresResponse
+from .get_scores_response_data import (
+ GetScoresResponseData,
+ GetScoresResponseData_Boolean,
+ GetScoresResponseData_Categorical,
+ GetScoresResponseData_Numeric,
+)
+from .get_scores_response_data_boolean import GetScoresResponseDataBoolean
+from .get_scores_response_data_categorical import GetScoresResponseDataCategorical
+from .get_scores_response_data_numeric import GetScoresResponseDataNumeric
+from .get_scores_response_trace_data import GetScoresResponseTraceData
+
+__all__ = [
+ "GetScoresResponse",
+ "GetScoresResponseData",
+ "GetScoresResponseDataBoolean",
+ "GetScoresResponseDataCategorical",
+ "GetScoresResponseDataNumeric",
+ "GetScoresResponseData_Boolean",
+ "GetScoresResponseData_Categorical",
+ "GetScoresResponseData_Numeric",
+ "GetScoresResponseTraceData",
+]
diff --git a/langfuse/api/resources/score/types/get_scores_response.py b/langfuse/api/resources/score_v_2/types/get_scores_response.py
similarity index 100%
rename from langfuse/api/resources/score/types/get_scores_response.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response.py
diff --git a/langfuse/api/resources/score/types/get_scores_response_data.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data.py
similarity index 84%
rename from langfuse/api/resources/score/types/get_scores_response_data.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response_data.py
index 5642e0f80..63f41f4c4 100644
--- a/langfuse/api/resources/score/types/get_scores_response_data.py
+++ b/langfuse/api/resources/score_v_2/types/get_scores_response_data.py
@@ -12,15 +12,21 @@
class GetScoresResponseData_Numeric(pydantic_v1.BaseModel):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
value: float
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -28,6 +34,7 @@ class GetScoresResponseData_Numeric(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
@@ -70,16 +77,22 @@ class Config:
class GetScoresResponseData_Categorical(pydantic_v1.BaseModel):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
value: typing.Optional[float] = None
string_value: str = pydantic_v1.Field(alias="stringValue")
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -87,6 +100,7 @@ class GetScoresResponseData_Categorical(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
@@ -129,16 +143,22 @@ class Config:
class GetScoresResponseData_Boolean(pydantic_v1.BaseModel):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
value: float
string_value: str = pydantic_v1.Field(alias="stringValue")
id: str
- trace_id: str = pydantic_v1.Field(alias="traceId")
- name: str
- source: ScoreSource
+ trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None)
+ session_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="sessionId", default=None
+ )
observation_id: typing.Optional[str] = pydantic_v1.Field(
alias="observationId", default=None
)
+ dataset_run_id: typing.Optional[str] = pydantic_v1.Field(
+ alias="datasetRunId", default=None
+ )
+ name: str
+ source: ScoreSource
timestamp: dt.datetime
created_at: dt.datetime = pydantic_v1.Field(alias="createdAt")
updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt")
@@ -146,6 +166,7 @@ class GetScoresResponseData_Boolean(pydantic_v1.BaseModel):
alias="authorUserId", default=None
)
comment: typing.Optional[str] = None
+ metadata: typing.Optional[typing.Any] = None
config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None)
queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None)
environment: typing.Optional[str] = None
diff --git a/langfuse/api/resources/score/types/get_scores_response_data_boolean.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py
similarity index 95%
rename from langfuse/api/resources/score/types/get_scores_response_data_boolean.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py
index 4dbf85af2..48012990c 100644
--- a/langfuse/api/resources/score/types/get_scores_response_data_boolean.py
+++ b/langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py
@@ -10,7 +10,7 @@
class GetScoresResponseDataBoolean(BooleanScore):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/score/types/get_scores_response_data_categorical.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py
similarity index 95%
rename from langfuse/api/resources/score/types/get_scores_response_data_categorical.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py
index 3c619779f..6e27f6d64 100644
--- a/langfuse/api/resources/score/types/get_scores_response_data_categorical.py
+++ b/langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py
@@ -10,7 +10,7 @@
class GetScoresResponseDataCategorical(CategoricalScore):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/score/types/get_scores_response_data_numeric.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py
similarity index 95%
rename from langfuse/api/resources/score/types/get_scores_response_data_numeric.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py
index 127d8f028..f7342833f 100644
--- a/langfuse/api/resources/score/types/get_scores_response_data_numeric.py
+++ b/langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py
@@ -10,7 +10,7 @@
class GetScoresResponseDataNumeric(NumericScore):
- trace: GetScoresResponseTraceData
+ trace: typing.Optional[GetScoresResponseTraceData] = None
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
diff --git a/langfuse/api/resources/score/types/get_scores_response_trace_data.py b/langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py
similarity index 100%
rename from langfuse/api/resources/score/types/get_scores_response_trace_data.py
rename to langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py
From e9413e2e240871c7695b2a488c68a748812cba34 Mon Sep 17 00:00:00 2001
From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com>
Date: Wed, 28 May 2025 18:31:57 +0200
Subject: [PATCH 2/4] push
---
langfuse/_client/client.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py
index 97f5ca72b..16d74bfac 100644
--- a/langfuse/_client/client.py
+++ b/langfuse/_client/client.py
@@ -1215,7 +1215,9 @@ def create_score(
*,
name: str,
value: float,
- trace_id: str,
+ session_id: Optional[str] = None,
+ dataset_run_id: Optional[str] = None,
+ trace_id: Optional[str] = None,
observation_id: Optional[str] = None,
score_id: Optional[str] = None,
data_type: Optional[Literal["NUMERIC", "BOOLEAN"]] = None,
@@ -1230,7 +1232,9 @@ def create_score(
*,
name: str,
value: str,
- trace_id: str,
+ trace_id: Optional[str] = None,
+ session_id: Optional[str] = None,
+ dataset_run_id: Optional[str] = None,
score_id: Optional[str] = None,
observation_id: Optional[str] = None,
data_type: Optional[Literal["CATEGORICAL"]] = "CATEGORICAL",
From 807f7db82a38f93d5ebd6405bd23fa26fc0af630 Mon Sep 17 00:00:00 2001
From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com>
Date: Mon, 2 Jun 2025 11:53:53 +0200
Subject: [PATCH 3/4] push
---
langfuse/api/resources/projects/types/project.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/langfuse/api/resources/projects/types/project.py b/langfuse/api/resources/projects/types/project.py
index 2128a258c..cf257d406 100644
--- a/langfuse/api/resources/projects/types/project.py
+++ b/langfuse/api/resources/projects/types/project.py
@@ -15,7 +15,9 @@ class Project(pydantic_v1.BaseModel):
Metadata for the project
"""
- retention_days: int = pydantic_v1.Field(alias="retentionDays")
+ retention_days: typing.Optional[int] = pydantic_v1.Field(
+ alias="retentionDays", default=None
+ )
"""
Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured.
"""
From b356fc01acb2c3c342d55fabe0f1cc0751081c49 Mon Sep 17 00:00:00 2001
From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com>
Date: Mon, 2 Jun 2025 12:02:47 +0200
Subject: [PATCH 4/4] push
---
langfuse/_client/client.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py
index 08b44c4ea..ade8f3c6d 100644
--- a/langfuse/_client/client.py
+++ b/langfuse/_client/client.py
@@ -166,7 +166,9 @@ def __init__(
self._project_id = None
sample_rate = sample_rate or float(os.environ.get(LANGFUSE_SAMPLE_RATE, 1.0))
if not 0.0 <= sample_rate <= 1.0:
- raise ValueError(f"Sample rate must be between 0.0 and 1.0, got {sample_rate}")
+ raise ValueError(
+ f"Sample rate must be between 0.0 and 1.0, got {sample_rate}"
+ )
self._tracing_enabled = (
tracing_enabled
@@ -1231,9 +1233,9 @@ def create_score(
*,
name: str,
value: str,
- trace_id: Optional[str] = None,
session_id: Optional[str] = None,
dataset_run_id: Optional[str] = None,
+ trace_id: Optional[str] = None,
score_id: Optional[str] = None,
observation_id: Optional[str] = None,
data_type: Optional[Literal["CATEGORICAL"]] = "CATEGORICAL",