diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index c46278180..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 @@ -1214,12 +1216,15 @@ 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, comment: Optional[str] = None, config_id: Optional[str] = None, + metadata: Optional[Any] = None, ) -> None: ... @overload @@ -1228,12 +1233,15 @@ def create_score( *, name: str, value: str, - trace_id: str, + 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", comment: Optional[str] = None, config_id: Optional[str] = None, + metadata: Optional[Any] = None, ) -> None: ... def create_score( @@ -1241,12 +1249,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. @@ -1256,12 +1267,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 @@ -1292,6 +1306,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, @@ -1300,6 +1316,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/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..cf257d406 100644 --- a/langfuse/api/resources/projects/types/project.py +++ b/langfuse/api/resources/projects/types/project.py @@ -10,6 +10,17 @@ class Project(pydantic_v1.BaseModel): id: str name: str + metadata: typing.Dict[str, typing.Any] = pydantic_v1.Field() + """ + Metadata for the project + """ + + 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. + """ def json(self, **kwargs: typing.Any) -> str: kwargs_with_defaults: typing.Any = { @@ -39,5 +50,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