From 60dfed8d8ce9b4dc4650a4e0798cde5211502373 Mon Sep 17 00:00:00 2001 From: langfuse-bot Date: Tue, 18 Aug 2026 12:05:47 +0000 Subject: [PATCH] feat(api): update API spec from langfuse/langfuse 9a83721 --- langfuse/api/__init__.py | 9 +++ .../api/blob_storage_integrations/client.py | 4 +- .../blob_storage_integrations/raw_client.py | 4 +- .../types/blob_storage_export_source.py | 2 +- ...create_blob_storage_integration_request.py | 2 +- langfuse/api/comments/client.py | 4 +- langfuse/api/comments/raw_client.py | 4 +- .../comments/types/create_comment_request.py | 2 +- langfuse/api/commons/__init__.py | 9 +++ langfuse/api/commons/types/__init__.py | 9 +++ langfuse/api/commons/types/model.py | 6 +- langfuse/api/commons/types/pricing_tier.py | 6 +- .../types/pricing_tier_attribute_condition.py | 37 ++++++++++ .../types/pricing_tier_attribute_source.py | 22 ++++++ .../commons/types/pricing_tier_condition.py | 68 ++----------------- .../api/commons/types/pricing_tier_input.py | 2 +- .../types/pricing_tier_usage_condition.py | 39 +++++++++++ langfuse/api/metrics/client.py | 26 +++++++ langfuse/api/metrics/raw_client.py | 26 +++++++ langfuse/api/observations/client.py | 10 +++ langfuse/api/observations/raw_client.py | 10 +++ langfuse/api/scim/client.py | 4 +- langfuse/api/scim/raw_client.py | 4 +- langfuse/api/scores/client.py | 12 ---- langfuse/api/scores/raw_client.py | 12 ---- .../commons/types/evaluation_rule_filter.py | 20 ++++++ 26 files changed, 244 insertions(+), 109 deletions(-) create mode 100644 langfuse/api/commons/types/pricing_tier_attribute_condition.py create mode 100644 langfuse/api/commons/types/pricing_tier_attribute_source.py create mode 100644 langfuse/api/commons/types/pricing_tier_usage_condition.py diff --git a/langfuse/api/__init__.py b/langfuse/api/__init__.py index 67198e273..3a98b0646 100644 --- a/langfuse/api/__init__.py +++ b/langfuse/api/__init__.py @@ -112,9 +112,12 @@ ObservationsView, ObservationsViewSingle, PricingTier, + PricingTierAttributeCondition, + PricingTierAttributeSource, PricingTierCondition, PricingTierInput, PricingTierOperator, + PricingTierUsageCondition, Score, ScoreConfig, ScoreConfigDataType, @@ -542,9 +545,12 @@ "PlaceholderMessage": ".prompts", "PlaceholderMessageType": ".prompts", "PricingTier": ".commons", + "PricingTierAttributeCondition": ".commons", + "PricingTierAttributeSource": ".commons", "PricingTierCondition": ".commons", "PricingTierInput": ".commons", "PricingTierOperator": ".commons", + "PricingTierUsageCondition": ".commons", "Project": ".projects", "ProjectDeletionResponse": ".projects", "Projects": ".projects", @@ -883,9 +889,12 @@ def __dir__(): "PlaceholderMessage", "PlaceholderMessageType", "PricingTier", + "PricingTierAttributeCondition", + "PricingTierAttributeSource", "PricingTierCondition", "PricingTierInput", "PricingTierOperator", + "PricingTierUsageCondition", "Project", "ProjectDeletionResponse", "Projects", diff --git a/langfuse/api/blob_storage_integrations/client.py b/langfuse/api/blob_storage_integrations/client.py index 9e8051d8c..9723e4008 100644 --- a/langfuse/api/blob_storage_integrations/client.py +++ b/langfuse/api/blob_storage_integrations/client.py @@ -150,7 +150,7 @@ def upsert_blob_storage_integration( Enable gzip compression for exported files (.csv.gz, .json.gz, .jsonl.gz). Defaults to true. export_source : typing.Optional[BlobStorageExportSource] - Data to export. When omitted on update, the existing value is preserved. When omitted on create: integrations on Langfuse Cloud default to `OBSERVATIONS_V2`; self-hosted deployments fall back to `LEGACY_TRACES_OBSERVATIONS`. Required when `exportFieldGroups` is provided. + Data to export. When omitted on update, the existing value is preserved. When omitted on create, the default is `OBSERVATIONS_V2` on Langfuse Cloud, and on self-hosted deployments `LEGACY_TRACES_OBSERVATIONS` — or `OBSERVATIONS_V2` where the deployment no longer populates the legacy tables. The default is never a source the deployment cannot serve. Required when `exportFieldGroups` is provided. **Cloud-only project deprecation gate (effective 2026-05-20):** For projects created on or after 2026-05-20 on Langfuse Cloud, `LEGACY_TRACES_OBSERVATIONS` and `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` for all new integrations. Self-hosted deployments are unaffected. @@ -427,7 +427,7 @@ async def upsert_blob_storage_integration( Enable gzip compression for exported files (.csv.gz, .json.gz, .jsonl.gz). Defaults to true. export_source : typing.Optional[BlobStorageExportSource] - Data to export. When omitted on update, the existing value is preserved. When omitted on create: integrations on Langfuse Cloud default to `OBSERVATIONS_V2`; self-hosted deployments fall back to `LEGACY_TRACES_OBSERVATIONS`. Required when `exportFieldGroups` is provided. + Data to export. When omitted on update, the existing value is preserved. When omitted on create, the default is `OBSERVATIONS_V2` on Langfuse Cloud, and on self-hosted deployments `LEGACY_TRACES_OBSERVATIONS` — or `OBSERVATIONS_V2` where the deployment no longer populates the legacy tables. The default is never a source the deployment cannot serve. Required when `exportFieldGroups` is provided. **Cloud-only project deprecation gate (effective 2026-05-20):** For projects created on or after 2026-05-20 on Langfuse Cloud, `LEGACY_TRACES_OBSERVATIONS` and `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` for all new integrations. Self-hosted deployments are unaffected. diff --git a/langfuse/api/blob_storage_integrations/raw_client.py b/langfuse/api/blob_storage_integrations/raw_client.py index 9eeb8c2f1..ec544503a 100644 --- a/langfuse/api/blob_storage_integrations/raw_client.py +++ b/langfuse/api/blob_storage_integrations/raw_client.py @@ -207,7 +207,7 @@ def upsert_blob_storage_integration( Enable gzip compression for exported files (.csv.gz, .json.gz, .jsonl.gz). Defaults to true. export_source : typing.Optional[BlobStorageExportSource] - Data to export. When omitted on update, the existing value is preserved. When omitted on create: integrations on Langfuse Cloud default to `OBSERVATIONS_V2`; self-hosted deployments fall back to `LEGACY_TRACES_OBSERVATIONS`. Required when `exportFieldGroups` is provided. + Data to export. When omitted on update, the existing value is preserved. When omitted on create, the default is `OBSERVATIONS_V2` on Langfuse Cloud, and on self-hosted deployments `LEGACY_TRACES_OBSERVATIONS` — or `OBSERVATIONS_V2` where the deployment no longer populates the legacy tables. The default is never a source the deployment cannot serve. Required when `exportFieldGroups` is provided. **Cloud-only project deprecation gate (effective 2026-05-20):** For projects created on or after 2026-05-20 on Langfuse Cloud, `LEGACY_TRACES_OBSERVATIONS` and `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` for all new integrations. Self-hosted deployments are unaffected. @@ -702,7 +702,7 @@ async def upsert_blob_storage_integration( Enable gzip compression for exported files (.csv.gz, .json.gz, .jsonl.gz). Defaults to true. export_source : typing.Optional[BlobStorageExportSource] - Data to export. When omitted on update, the existing value is preserved. When omitted on create: integrations on Langfuse Cloud default to `OBSERVATIONS_V2`; self-hosted deployments fall back to `LEGACY_TRACES_OBSERVATIONS`. Required when `exportFieldGroups` is provided. + Data to export. When omitted on update, the existing value is preserved. When omitted on create, the default is `OBSERVATIONS_V2` on Langfuse Cloud, and on self-hosted deployments `LEGACY_TRACES_OBSERVATIONS` — or `OBSERVATIONS_V2` where the deployment no longer populates the legacy tables. The default is never a source the deployment cannot serve. Required when `exportFieldGroups` is provided. **Cloud-only project deprecation gate (effective 2026-05-20):** For projects created on or after 2026-05-20 on Langfuse Cloud, `LEGACY_TRACES_OBSERVATIONS` and `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` for all new integrations. Self-hosted deployments are unaffected. diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_source.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_source.py index 629397a29..41ec3709e 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_export_source.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_source.py @@ -14,7 +14,7 @@ class BlobStorageExportSource(enum.StrEnum): - `OBSERVATIONS_V2`: same data model as the `/api/public/v2/observations` endpoint, plus scores. Columns are controlled by `exportFieldGroups`. - `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS`: both sets. Observation columns of both portions are controlled by `exportFieldGroups`. - **Note:** `OBSERVATIONS_V2` and the enriched-observations portion of `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` rely on the enriched observations table (Langfuse Fast Preview / v4), which is currently available on Langfuse Cloud only. See https://langfuse.com/docs/v4. + **Note:** which sources a deployment accepts depends on how far it has moved to the v4 data model. `OBSERVATIONS_V2` and the enriched-observations portion of `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` read the enriched observations table, so they require a deployment that already populates it. `LEGACY_TRACES_OBSERVATIONS` and the legacy portion of `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` read the legacy traces and observations tables, so they require a deployment that still populates those. A deployment part-way through the migration populates both and accepts every source. Selecting a source the deployment cannot serve is rejected with `400`, rather than exporting an empty result. See https://langfuse.com/docs/v4. """ LEGACY_TRACES_OBSERVATIONS = "LEGACY_TRACES_OBSERVATIONS" diff --git a/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py index 44d2d2dda..4d3a1e06f 100644 --- a/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +++ b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py @@ -97,7 +97,7 @@ class CreateBlobStorageIntegrationRequest(UniversalBaseModel): typing.Optional[BlobStorageExportSource], FieldMetadata(alias="exportSource") ] = pydantic.Field(default=None) """ - Data to export. When omitted on update, the existing value is preserved. When omitted on create: integrations on Langfuse Cloud default to `OBSERVATIONS_V2`; self-hosted deployments fall back to `LEGACY_TRACES_OBSERVATIONS`. Required when `exportFieldGroups` is provided. + Data to export. When omitted on update, the existing value is preserved. When omitted on create, the default is `OBSERVATIONS_V2` on Langfuse Cloud, and on self-hosted deployments `LEGACY_TRACES_OBSERVATIONS` — or `OBSERVATIONS_V2` where the deployment no longer populates the legacy tables. The default is never a source the deployment cannot serve. Required when `exportFieldGroups` is provided. **Cloud-only project deprecation gate (effective 2026-05-20):** For projects created on or after 2026-05-20 on Langfuse Cloud, `LEGACY_TRACES_OBSERVATIONS` and `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` for all new integrations. Self-hosted deployments are unaffected. diff --git a/langfuse/api/comments/client.py b/langfuse/api/comments/client.py index f5e92ff36..138c58b8f 100644 --- a/langfuse/api/comments/client.py +++ b/langfuse/api/comments/client.py @@ -56,7 +56,7 @@ def create( The content of the comment. May include markdown. Currently limited to 5000 characters. author_user_id : typing.Optional[str] - The id of the user who created the comment. + The id of the user who created the comment. Must be a member of the organization that owns the project, otherwise an error will be thrown. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -241,7 +241,7 @@ async def create( The content of the comment. May include markdown. Currently limited to 5000 characters. author_user_id : typing.Optional[str] - The id of the user who created the comment. + The id of the user who created the comment. Must be a member of the organization that owns the project, otherwise an error will be thrown. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/comments/raw_client.py b/langfuse/api/comments/raw_client.py index 0bb39539a..811a7335c 100644 --- a/langfuse/api/comments/raw_client.py +++ b/langfuse/api/comments/raw_client.py @@ -54,7 +54,7 @@ def create( The content of the comment. May include markdown. Currently limited to 5000 characters. author_user_id : typing.Optional[str] - The id of the user who created the comment. + The id of the user who created the comment. Must be a member of the organization that owns the project, otherwise an error will be thrown. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -418,7 +418,7 @@ async def create( The content of the comment. May include markdown. Currently limited to 5000 characters. author_user_id : typing.Optional[str] - The id of the user who created the comment. + The id of the user who created the comment. Must be a member of the organization that owns the project, otherwise an error will be thrown. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/comments/types/create_comment_request.py b/langfuse/api/comments/types/create_comment_request.py index 56ef2794d..53a756ca9 100644 --- a/langfuse/api/comments/types/create_comment_request.py +++ b/langfuse/api/comments/types/create_comment_request.py @@ -39,7 +39,7 @@ class CreateCommentRequest(UniversalBaseModel): typing.Optional[str], FieldMetadata(alias="authorUserId") ] = pydantic.Field(default=None) """ - The id of the user who created the comment. + The id of the user who created the comment. Must be a member of the organization that owns the project, otherwise an error will be thrown. """ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( diff --git a/langfuse/api/commons/__init__.py b/langfuse/api/commons/__init__.py index 5d5f56bcd..89204bfad 100644 --- a/langfuse/api/commons/__init__.py +++ b/langfuse/api/commons/__init__.py @@ -40,9 +40,12 @@ ObservationsView, ObservationsViewSingle, PricingTier, + PricingTierAttributeCondition, + PricingTierAttributeSource, PricingTierCondition, PricingTierInput, PricingTierOperator, + PricingTierUsageCondition, Score, ScoreConfig, ScoreConfigDataType, @@ -112,9 +115,12 @@ "ObservationsView": ".types", "ObservationsViewSingle": ".types", "PricingTier": ".types", + "PricingTierAttributeCondition": ".types", + "PricingTierAttributeSource": ".types", "PricingTierCondition": ".types", "PricingTierInput": ".types", "PricingTierOperator": ".types", + "PricingTierUsageCondition": ".types", "Score": ".types", "ScoreConfig": ".types", "ScoreConfigDataType": ".types", @@ -207,9 +213,12 @@ def __dir__(): "ObservationsView", "ObservationsViewSingle", "PricingTier", + "PricingTierAttributeCondition", + "PricingTierAttributeSource", "PricingTierCondition", "PricingTierInput", "PricingTierOperator", + "PricingTierUsageCondition", "Score", "ScoreConfig", "ScoreConfigDataType", diff --git a/langfuse/api/commons/types/__init__.py b/langfuse/api/commons/types/__init__.py index 7932fec73..1bf73059d 100644 --- a/langfuse/api/commons/types/__init__.py +++ b/langfuse/api/commons/types/__init__.py @@ -39,9 +39,12 @@ from .observations_view import ObservationsView from .observations_view_single import ObservationsViewSingle from .pricing_tier import PricingTier + from .pricing_tier_attribute_condition import PricingTierAttributeCondition + from .pricing_tier_attribute_source import PricingTierAttributeSource from .pricing_tier_condition import PricingTierCondition from .pricing_tier_input import PricingTierInput from .pricing_tier_operator import PricingTierOperator + from .pricing_tier_usage_condition import PricingTierUsageCondition from .score import ( Score, Score_Boolean, @@ -103,9 +106,12 @@ "ObservationsView": ".observations_view", "ObservationsViewSingle": ".observations_view_single", "PricingTier": ".pricing_tier", + "PricingTierAttributeCondition": ".pricing_tier_attribute_condition", + "PricingTierAttributeSource": ".pricing_tier_attribute_source", "PricingTierCondition": ".pricing_tier_condition", "PricingTierInput": ".pricing_tier_input", "PricingTierOperator": ".pricing_tier_operator", + "PricingTierUsageCondition": ".pricing_tier_usage_condition", "Score": ".score", "ScoreConfig": ".score_config", "ScoreConfigDataType": ".score_config_data_type", @@ -193,9 +199,12 @@ def __dir__(): "ObservationsView", "ObservationsViewSingle", "PricingTier", + "PricingTierAttributeCondition", + "PricingTierAttributeSource", "PricingTierCondition", "PricingTierInput", "PricingTierOperator", + "PricingTierUsageCondition", "Score", "ScoreConfig", "ScoreConfigDataType", diff --git a/langfuse/api/commons/types/model.py b/langfuse/api/commons/types/model.py index e09313e8a..3c7b7a182 100644 --- a/langfuse/api/commons/types/model.py +++ b/langfuse/api/commons/types/model.py @@ -18,7 +18,7 @@ class Model(UniversalBaseModel): Models can have either simple flat pricing or tiered pricing: - Flat pricing: Single price per usage type (legacy, but still supported) - - Tiered pricing: Multiple pricing tiers with conditional matching based on usage patterns + - Tiered pricing: Multiple pricing tiers with conditional matching based on usage patterns or observation attributes The pricing tiers approach is recommended for models with usage-based pricing variations. When using tiered pricing, the flat price fields (inputPrice, outputPrice, prices) are populated @@ -109,10 +109,10 @@ class Model(UniversalBaseModel): typing.List[PricingTier], FieldMetadata(alias="pricingTiers") ] = pydantic.Field() """ - Array of pricing tiers with conditional pricing based on usage thresholds. + Array of pricing tiers with conditional pricing based on usage thresholds or observation attributes. Pricing tiers enable accurate cost tracking for models that charge different rates based on usage patterns - (e.g., different rates for high-volume usage, large context windows, or cached tokens). + or request attributes (e.g., high-volume usage, large context windows, cached tokens, or service tiers). Each model must have exactly one default tier (isDefault=true, priority=0) that serves as a fallback. Additional conditional tiers can be defined with specific matching criteria. diff --git a/langfuse/api/commons/types/pricing_tier.py b/langfuse/api/commons/types/pricing_tier.py index 49b99096b..ee48759aa 100644 --- a/langfuse/api/commons/types/pricing_tier.py +++ b/langfuse/api/commons/types/pricing_tier.py @@ -11,10 +11,10 @@ class PricingTier(UniversalBaseModel): """ - Pricing tier definition with conditional pricing based on usage thresholds. + Pricing tier definition with conditional pricing based on usage thresholds or observation attributes. - Pricing tiers enable accurate cost tracking for LLM providers that charge different rates based on usage patterns. - For example, some providers charge higher rates when context size exceeds certain thresholds. + Pricing tiers enable accurate cost tracking for LLM providers that charge different rates based on usage patterns or request attributes. + For example, some providers charge higher rates when context size exceeds certain thresholds or when an accelerated service tier is selected. How tier matching works: 1. Tiers are evaluated in ascending priority order (priority 1 before priority 2, etc.) diff --git a/langfuse/api/commons/types/pricing_tier_attribute_condition.py b/langfuse/api/commons/types/pricing_tier_attribute_condition.py new file mode 100644 index 000000000..5d5c09234 --- /dev/null +++ b/langfuse/api/commons/types/pricing_tier_attribute_condition.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import UniversalBaseModel +from .pricing_tier_attribute_source import PricingTierAttributeSource + + +class PricingTierAttributeCondition(UniversalBaseModel): + """ + Condition that matches any configured value for a top-level observation attribute. + """ + + source: PricingTierAttributeSource = pydantic.Field() + """ + Observation attribute object evaluated by this condition. + """ + + key: str = pydantic.Field() + """ + Exact top-level attribute key. + """ + + operator: typing.Literal["in"] = pydantic.Field(default="in") + """ + Membership operator. + """ + + values: typing.List[str] = pydantic.Field() + """ + Accepted string attribute values. At least one value is required. + """ + + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/pricing_tier_attribute_source.py b/langfuse/api/commons/types/pricing_tier_attribute_source.py new file mode 100644 index 000000000..2ec1e41b3 --- /dev/null +++ b/langfuse/api/commons/types/pricing_tier_attribute_source.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class PricingTierAttributeSource(enum.StrEnum): + MODEL_PARAMETERS = "model_parameters" + METADATA = "metadata" + + def visit( + self, + model_parameters: typing.Callable[[], T_Result], + metadata: typing.Callable[[], T_Result], + ) -> T_Result: + if self is PricingTierAttributeSource.MODEL_PARAMETERS: + return model_parameters() + if self is PricingTierAttributeSource.METADATA: + return metadata() diff --git a/langfuse/api/commons/types/pricing_tier_condition.py b/langfuse/api/commons/types/pricing_tier_condition.py index 9ebbba0af..9d68f16b5 100644 --- a/langfuse/api/commons/types/pricing_tier_condition.py +++ b/langfuse/api/commons/types/pricing_tier_condition.py @@ -2,67 +2,9 @@ import typing -import pydantic -import typing_extensions -from ...core.pydantic_utilities import UniversalBaseModel -from ...core.serialization import FieldMetadata -from .pricing_tier_operator import PricingTierOperator +from .pricing_tier_attribute_condition import PricingTierAttributeCondition +from .pricing_tier_usage_condition import PricingTierUsageCondition - -class PricingTierCondition(UniversalBaseModel): - """ - Condition for matching a pricing tier based on usage details. Used to implement tiered pricing models where costs vary based on usage thresholds. - - How it works: - 1. The regex pattern matches against usage detail keys (e.g., "input_tokens", "input_cached") - 2. Values of all matching keys are summed together - 3. The sum is compared against the threshold value using the specified operator - 4. All conditions in a tier must be met (AND logic) for the tier to match - - Common use cases: - - Threshold-based pricing: Match when accumulated usage exceeds a certain amount - - Usage-type-specific pricing: Different rates for cached vs non-cached tokens, or input vs output - - Volume-based pricing: Different rates based on total request or token count - """ - - usage_detail_pattern: typing_extensions.Annotated[ - str, FieldMetadata(alias="usageDetailPattern") - ] = pydantic.Field() - """ - Regex pattern to match against usage detail keys. All matching keys' values are summed for threshold comparison. - - Examples: - - "^input" matches "input", "input_tokens", "input_cached", etc. - - "^(input|prompt)" matches both "input_tokens" and "prompt_tokens" - - "_cache$" matches "input_cache", "output_cache", etc. - - The pattern is case-insensitive by default. If no keys match, the sum is treated as zero. - """ - - operator: PricingTierOperator = pydantic.Field() - """ - Comparison operator to apply between the summed value and the threshold. - - - gt: greater than (sum > threshold) - - gte: greater than or equal (sum >= threshold) - - lt: less than (sum < threshold) - - lte: less than or equal (sum <= threshold) - - eq: equal (sum == threshold) - - neq: not equal (sum != threshold) - """ - - value: float = pydantic.Field() - """ - Threshold value for comparison. For token-based pricing, this is typically the token count threshold (e.g., 200000 for a 200K token threshold). - """ - - case_sensitive: typing_extensions.Annotated[ - bool, FieldMetadata(alias="caseSensitive") - ] = pydantic.Field() - """ - Whether the regex pattern matching is case-sensitive. Default is false (case-insensitive matching). - """ - - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) +PricingTierCondition = typing.Union[ + PricingTierUsageCondition, PricingTierAttributeCondition +] diff --git a/langfuse/api/commons/types/pricing_tier_input.py b/langfuse/api/commons/types/pricing_tier_input.py index c25d7f716..40d253ece 100644 --- a/langfuse/api/commons/types/pricing_tier_input.py +++ b/langfuse/api/commons/types/pricing_tier_input.py @@ -58,7 +58,7 @@ class PricingTierInput(UniversalBaseModel): The default tier must have an empty array (conditions=[]). Conditional tiers should define one or more conditions that specify when this tier's pricing applies. - Each condition specifies a regex pattern, operator, and threshold value for matching against usage details. + Conditions can compare summed matching usage details to a numeric threshold, or exactly match a top-level model parameter or metadata value. """ prices: typing.Dict[str, float] = pydantic.Field() diff --git a/langfuse/api/commons/types/pricing_tier_usage_condition.py b/langfuse/api/commons/types/pricing_tier_usage_condition.py new file mode 100644 index 000000000..bfd91ad0a --- /dev/null +++ b/langfuse/api/commons/types/pricing_tier_usage_condition.py @@ -0,0 +1,39 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata +from .pricing_tier_operator import PricingTierOperator + + +class PricingTierUsageCondition(UniversalBaseModel): + """ + Condition that sums usage details whose keys match a regex. + """ + + usage_detail_pattern: typing_extensions.Annotated[ + str, FieldMetadata(alias="usageDetailPattern") + ] = pydantic.Field() + """ + Regex pattern matched against usage detail keys. + """ + + operator: PricingTierOperator + value: float = pydantic.Field() + """ + Numeric threshold for the summed matching usage values. + """ + + case_sensitive: typing_extensions.Annotated[ + bool, FieldMetadata(alias="caseSensitive") + ] = pydantic.Field() + """ + Whether the usage-detail regex is case-sensitive. + """ + + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/metrics/client.py b/langfuse/api/metrics/client.py index 260624ce0..f2272409b 100644 --- a/langfuse/api/metrics/client.py +++ b/langfuse/api/metrics/client.py @@ -32,6 +32,7 @@ def metrics( ## V2 Differences - Supports `observations`, `scores-numeric`, `scores-boolean`, and `scores-categorical` views only (traces view not supported) - Direct access to tags and release fields on observations + - Semantic-root filtering and grouping through the v2-only `isRootObservation` dimension - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view - High cardinality dimensions are not supported and will return a 400 error (see below) @@ -56,6 +57,7 @@ def metrics( - `providedModelName` - Name of the model used - `promptName` - Name of the prompt used - `promptVersion` - Version of the prompt used + - `isRootObservation` - Boolean semantic-root status. `true` includes physical roots and app roots whose SDK parent is external (so `parentObservationId` may be non-null). - `startTimeMonth` - Month of start_time in YYYY-MM format **Measures:** @@ -192,6 +194,17 @@ def metrics( } ``` + For example, to count semantic roots (including app roots with a non-null external parent), use a boolean filter: + ```json + { + "view": "observations", + "metrics": [{"measure": "count", "aggregation": "count"}], + "filters": [{"column": "isRootObservation", "operator": "=", "value": true, "type": "boolean"}], + "fromTimestamp": "2025-01-01T00:00:00.000Z", + "toTimestamp": "2025-02-01T00:00:00.000Z" + } + ``` + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -245,6 +258,7 @@ async def metrics( ## V2 Differences - Supports `observations`, `scores-numeric`, `scores-boolean`, and `scores-categorical` views only (traces view not supported) - Direct access to tags and release fields on observations + - Semantic-root filtering and grouping through the v2-only `isRootObservation` dimension - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view - High cardinality dimensions are not supported and will return a 400 error (see below) @@ -269,6 +283,7 @@ async def metrics( - `providedModelName` - Name of the model used - `promptName` - Name of the prompt used - `promptVersion` - Version of the prompt used + - `isRootObservation` - Boolean semantic-root status. `true` includes physical roots and app roots whose SDK parent is external (so `parentObservationId` may be non-null). - `startTimeMonth` - Month of start_time in YYYY-MM format **Measures:** @@ -405,6 +420,17 @@ async def metrics( } ``` + For example, to count semantic roots (including app roots with a non-null external parent), use a boolean filter: + ```json + { + "view": "observations", + "metrics": [{"measure": "count", "aggregation": "count"}], + "filters": [{"column": "isRootObservation", "operator": "=", "value": true, "type": "boolean"}], + "fromTimestamp": "2025-01-01T00:00:00.000Z", + "toTimestamp": "2025-02-01T00:00:00.000Z" + } + ``` + request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/metrics/raw_client.py b/langfuse/api/metrics/raw_client.py index 9dfaeed4d..ce52e03c2 100644 --- a/langfuse/api/metrics/raw_client.py +++ b/langfuse/api/metrics/raw_client.py @@ -29,6 +29,7 @@ def metrics( ## V2 Differences - Supports `observations`, `scores-numeric`, `scores-boolean`, and `scores-categorical` views only (traces view not supported) - Direct access to tags and release fields on observations + - Semantic-root filtering and grouping through the v2-only `isRootObservation` dimension - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view - High cardinality dimensions are not supported and will return a 400 error (see below) @@ -53,6 +54,7 @@ def metrics( - `providedModelName` - Name of the model used - `promptName` - Name of the prompt used - `promptVersion` - Version of the prompt used + - `isRootObservation` - Boolean semantic-root status. `true` includes physical roots and app roots whose SDK parent is external (so `parentObservationId` may be non-null). - `startTimeMonth` - Month of start_time in YYYY-MM format **Measures:** @@ -189,6 +191,17 @@ def metrics( } ``` + For example, to count semantic roots (including app roots with a non-null external parent), use a boolean filter: + ```json + { + "view": "observations", + "metrics": [{"measure": "count", "aggregation": "count"}], + "filters": [{"column": "isRootObservation", "operator": "=", "value": true, "type": "boolean"}], + "fromTimestamp": "2025-01-01T00:00:00.000Z", + "toTimestamp": "2025-02-01T00:00:00.000Z" + } + ``` + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -296,6 +309,7 @@ async def metrics( ## V2 Differences - Supports `observations`, `scores-numeric`, `scores-boolean`, and `scores-categorical` views only (traces view not supported) - Direct access to tags and release fields on observations + - Semantic-root filtering and grouping through the v2-only `isRootObservation` dimension - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view - High cardinality dimensions are not supported and will return a 400 error (see below) @@ -320,6 +334,7 @@ async def metrics( - `providedModelName` - Name of the model used - `promptName` - Name of the prompt used - `promptVersion` - Version of the prompt used + - `isRootObservation` - Boolean semantic-root status. `true` includes physical roots and app roots whose SDK parent is external (so `parentObservationId` may be non-null). - `startTimeMonth` - Month of start_time in YYYY-MM format **Measures:** @@ -456,6 +471,17 @@ async def metrics( } ``` + For example, to count semantic roots (including app roots with a non-null external parent), use a boolean filter: + ```json + { + "view": "observations", + "metrics": [{"measure": "count", "aggregation": "count"}], + "filters": [{"column": "isRootObservation", "operator": "=", "value": true, "type": "boolean"}], + "fromTimestamp": "2025-01-01T00:00:00.000Z", + "toTimestamp": "2025-02-01T00:00:00.000Z" + } + ``` + request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/observations/client.py b/langfuse/api/observations/client.py index 088b918b9..c57a0b5f0 100644 --- a/langfuse/api/observations/client.py +++ b/langfuse/api/observations/client.py @@ -35,6 +35,7 @@ def get_many( parse_io_as_json: typing.Optional[bool] = None, name: typing.Optional[str] = None, user_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, type: typing.Optional[str] = None, trace_id: typing.Optional[str] = None, level: typing.Optional[ObservationLevel] = None, @@ -103,6 +104,9 @@ def get_many( user_id : typing.Optional[str] + session_id : typing.Optional[str] + Filter by session ID. + type : typing.Optional[str] Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") @@ -274,6 +278,7 @@ def get_many( parse_io_as_json=parse_io_as_json, name=name, user_id=user_id, + session_id=session_id, type=type, trace_id=trace_id, level=level, @@ -314,6 +319,7 @@ async def get_many( parse_io_as_json: typing.Optional[bool] = None, name: typing.Optional[str] = None, user_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, type: typing.Optional[str] = None, trace_id: typing.Optional[str] = None, level: typing.Optional[ObservationLevel] = None, @@ -382,6 +388,9 @@ async def get_many( user_id : typing.Optional[str] + session_id : typing.Optional[str] + Filter by session ID. + type : typing.Optional[str] Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") @@ -561,6 +570,7 @@ async def main() -> None: parse_io_as_json=parse_io_as_json, name=name, user_id=user_id, + session_id=session_id, type=type, trace_id=trace_id, level=level, diff --git a/langfuse/api/observations/raw_client.py b/langfuse/api/observations/raw_client.py index fd828c936..49c98dd63 100644 --- a/langfuse/api/observations/raw_client.py +++ b/langfuse/api/observations/raw_client.py @@ -33,6 +33,7 @@ def get_many( parse_io_as_json: typing.Optional[bool] = None, name: typing.Optional[str] = None, user_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, type: typing.Optional[str] = None, trace_id: typing.Optional[str] = None, level: typing.Optional[ObservationLevel] = None, @@ -101,6 +102,9 @@ def get_many( user_id : typing.Optional[str] + session_id : typing.Optional[str] + Filter by session ID. + type : typing.Optional[str] Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") @@ -261,6 +265,7 @@ def get_many( "parseIoAsJson": parse_io_as_json, "name": name, "userId": user_id, + "sessionId": session_id, "type": type, "traceId": trace_id, "level": level, @@ -371,6 +376,7 @@ async def get_many( parse_io_as_json: typing.Optional[bool] = None, name: typing.Optional[str] = None, user_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, type: typing.Optional[str] = None, trace_id: typing.Optional[str] = None, level: typing.Optional[ObservationLevel] = None, @@ -439,6 +445,9 @@ async def get_many( user_id : typing.Optional[str] + session_id : typing.Optional[str] + Filter by session ID. + type : typing.Optional[str] Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") @@ -599,6 +608,7 @@ async def get_many( "parseIoAsJson": parse_io_as_json, "name": name, "userId": user_id, + "sessionId": session_id, "type": type, "traceId": trace_id, "level": level, diff --git a/langfuse/api/scim/client.py b/langfuse/api/scim/client.py index 30d0815bf..9729276dc 100644 --- a/langfuse/api/scim/client.py +++ b/langfuse/api/scim/client.py @@ -210,7 +210,7 @@ def create_user( Whether the user is active password : typing.Optional[str] - Initial password for the user + Ignored. Accepted only for compatibility with identity providers that always send a password on user creation (Okta sends a placeholder value even when password sync is disabled). No credential is created for the user; provisioned users authenticate via SSO or set a password themselves through the password reset flow. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -548,7 +548,7 @@ async def create_user( Whether the user is active password : typing.Optional[str] - Initial password for the user + Ignored. Accepted only for compatibility with identity providers that always send a password on user creation (Okta sends a placeholder value even when password sync is disabled). No credential is created for the user; provisioned users authenticate via SSO or set a password themselves through the password reset flow. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/scim/raw_client.py b/langfuse/api/scim/raw_client.py index e65f46592..887c69b92 100644 --- a/langfuse/api/scim/raw_client.py +++ b/langfuse/api/scim/raw_client.py @@ -471,7 +471,7 @@ def create_user( Whether the user is active password : typing.Optional[str] - Initial password for the user + Ignored. Accepted only for compatibility with identity providers that always send a password on user creation (Okta sends a placeholder value even when password sync is disabled). No credential is created for the user; provisioned users authenticate via SSO or set a password themselves through the password reset flow. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1221,7 +1221,7 @@ async def create_user( Whether the user is active password : typing.Optional[str] - Initial password for the user + Ignored. Accepted only for compatibility with identity providers that always send a password on user creation (Okta sends a placeholder value even when password sync is disabled). No credential is created for the user; provisioned users authenticate via SSO or set a password themselves through the password reset flow. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/langfuse/api/scores/client.py b/langfuse/api/scores/client.py index e7e1d91c7..155611244 100644 --- a/langfuse/api/scores/client.py +++ b/langfuse/api/scores/client.py @@ -161,9 +161,6 @@ def get_many( request_options: typing.Optional[RequestOptions] = None, ) -> GetScoresResponse: """ - **Deprecated.** Use `GET /api/public/v3/scores` instead. This endpoint - is no longer available on Langfuse v4 and later. - Get a list of scores (supports both trace and session scores) Parameters @@ -282,9 +279,6 @@ def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> Score: """ - **Deprecated.** Use `GET /api/public/v3/scores` with the `id` filter - instead. This endpoint is no longer available on Langfuse v4 and later. - Get a score (supports both trace and session scores) Parameters @@ -472,9 +466,6 @@ async def get_many( request_options: typing.Optional[RequestOptions] = None, ) -> GetScoresResponse: """ - **Deprecated.** Use `GET /api/public/v3/scores` instead. This endpoint - is no longer available on Langfuse v4 and later. - Get a list of scores (supports both trace and session scores) Parameters @@ -601,9 +592,6 @@ async def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> Score: """ - **Deprecated.** Use `GET /api/public/v3/scores` with the `id` filter - instead. This endpoint is no longer available on Langfuse v4 and later. - Get a score (supports both trace and session scores) Parameters diff --git a/langfuse/api/scores/raw_client.py b/langfuse/api/scores/raw_client.py index 09b7ba5b8..c6b09bc11 100644 --- a/langfuse/api/scores/raw_client.py +++ b/langfuse/api/scores/raw_client.py @@ -227,9 +227,6 @@ def get_many( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[GetScoresResponse]: """ - **Deprecated.** Use `GET /api/public/v3/scores` instead. This endpoint - is no longer available on Langfuse v4 and later. - Get a list of scores (supports both trace and session scores) Parameters @@ -418,9 +415,6 @@ def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[Score]: """ - **Deprecated.** Use `GET /api/public/v3/scores` with the `id` filter - instead. This endpoint is no longer available on Langfuse v4 and later. - Get a score (supports both trace and session scores) Parameters @@ -717,9 +711,6 @@ async def get_many( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[GetScoresResponse]: """ - **Deprecated.** Use `GET /api/public/v3/scores` instead. This endpoint - is no longer available on Langfuse v4 and later. - Get a list of scores (supports both trace and session scores) Parameters @@ -908,9 +899,6 @@ async def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[Score]: """ - **Deprecated.** Use `GET /api/public/v3/scores` with the `id` filter - instead. This endpoint is no longer available on Langfuse v4 and later. - Get a score (supports both trace and session scores) Parameters diff --git a/langfuse/api/unstable/commons/types/evaluation_rule_filter.py b/langfuse/api/unstable/commons/types/evaluation_rule_filter.py index ea5e0420b..9d70f822b 100644 --- a/langfuse/api/unstable/commons/types/evaluation_rule_filter.py +++ b/langfuse/api/unstable/commons/types/evaluation_rule_filter.py @@ -37,6 +37,7 @@ class EvaluationRuleFilter_Datetime(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -51,6 +52,7 @@ class EvaluationRuleFilter_Datetime(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -106,6 +108,7 @@ class EvaluationRuleFilter_String(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -120,6 +123,7 @@ class EvaluationRuleFilter_String(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -175,6 +179,7 @@ class EvaluationRuleFilter_Number(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -189,6 +194,7 @@ class EvaluationRuleFilter_Number(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -244,6 +250,7 @@ class EvaluationRuleFilter_StringOptions(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -258,6 +265,7 @@ class EvaluationRuleFilter_StringOptions(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -313,6 +321,7 @@ class EvaluationRuleFilter_CategoryOptions(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -327,6 +336,7 @@ class EvaluationRuleFilter_CategoryOptions(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -383,6 +393,7 @@ class EvaluationRuleFilter_ArrayOptions(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -397,6 +408,7 @@ class EvaluationRuleFilter_ArrayOptions(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -452,6 +464,7 @@ class EvaluationRuleFilter_StringObject(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -466,6 +479,7 @@ class EvaluationRuleFilter_StringObject(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -522,6 +536,7 @@ class EvaluationRuleFilter_NumberObject(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -536,6 +551,7 @@ class EvaluationRuleFilter_NumberObject(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -592,6 +608,7 @@ class EvaluationRuleFilter_Boolean(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -606,6 +623,7 @@ class EvaluationRuleFilter_Boolean(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number` @@ -661,6 +679,7 @@ class EvaluationRuleFilter_Null(UniversalBaseModel): - `stringOptions`: `any of`, `none of` - `arrayOptions`: `any of`, `none of`, `all of` - `stringObject`: same operators as `string` + - `boolean`: `"="`, `"<>"` - `null`: `is null`, `is not null` Supported columns by target: @@ -675,6 +694,7 @@ class EvaluationRuleFilter_Null(UniversalBaseModel): - `sessionId`: `string` - `tags`: `arrayOptions`, operators `any of` / `none of` / `all of` - `metadata`: `stringObject` with `key` + - `isRootObservation`: `boolean`, operators `=` / `<>`; true when the observation has no parent or is explicitly marked as an application root - `parentObservationId`: `null`, operators `is null` / `is not null` - `calledToolNames`: `arrayOptions`, operators `any of` / `none of` / `all of` - `toolCalls`: `number`