From 2a1c6eb51785e3fb76c7e7d5bffe3cffd3b4f810 Mon Sep 17 00:00:00 2001 From: langfuse-bot Date: Wed, 21 Oct 2026 15:30:54 +0000 Subject: [PATCH] feat(api): update API spec from langfuse/langfuse 46d50a3 --- langfuse/api/__init__.py | 47 ++ .../api/blob_storage_integrations/client.py | 4 +- .../blob_storage_integrations/raw_client.py | 4 +- .../types/blob_storage_export_field_group.py | 12 +- .../blob_storage_integration_response.py | 2 +- ...create_blob_storage_integration_request.py | 2 +- langfuse/api/client.py | 19 + langfuse/api/commons/types/score_config.py | 6 +- langfuse/api/llm_connections/client.py | 350 +++++++++ langfuse/api/llm_connections/raw_client.py | 734 +++++++++++++++++- langfuse/api/score_configs/client.py | 8 +- langfuse/api/score_configs/raw_client.py | 8 +- .../types/create_score_config_request.py | 2 +- .../types/update_score_config_request.py | 2 +- .../api/{unstable => }/skills/__init__.py | 0 langfuse/api/{unstable => }/skills/client.py | 60 +- .../api/{unstable => }/skills/raw_client.py | 68 +- .../{unstable => }/skills/types/__init__.py | 0 .../types/create_skill_version_request.py | 4 +- .../types/delete_skill_version_response.py | 2 +- .../{unstable => }/skills/types/skill_file.py | 8 +- .../skills/types/skill_file_content.py | 4 +- .../types/skill_file_contents_response.py | 2 +- .../skills/types/skill_list_pagination.py | 4 +- .../{unstable => }/skills/types/skill_meta.py | 4 +- .../skills/types/skill_meta_list_response.py | 2 +- .../skills/types/skill_version.py | 4 +- .../types/skill_version_file_create_input.py | 0 .../skills/types/skill_version_file_input.py | 2 +- .../types/skill_version_file_reference.py | 4 +- .../types/update_skill_labels_request.py | 2 +- .../skills/types/update_skill_request.py | 2 +- langfuse/api/unstable/__init__.py | 48 +- langfuse/api/unstable/client.py | 19 - 34 files changed, 1272 insertions(+), 167 deletions(-) rename langfuse/api/{unstable => }/skills/__init__.py (100%) rename langfuse/api/{unstable => }/skills/client.py (92%) rename langfuse/api/{unstable => }/skills/raw_client.py (96%) rename langfuse/api/{unstable => }/skills/types/__init__.py (100%) rename langfuse/api/{unstable => }/skills/types/create_skill_version_request.py (83%) rename langfuse/api/{unstable => }/skills/types/delete_skill_version_response.py (83%) rename langfuse/api/{unstable => }/skills/types/skill_file.py (70%) rename langfuse/api/{unstable => }/skills/types/skill_file_content.py (78%) rename langfuse/api/{unstable => }/skills/types/skill_file_contents_response.py (85%) rename langfuse/api/{unstable => }/skills/types/skill_list_pagination.py (76%) rename langfuse/api/{unstable => }/skills/types/skill_meta.py (90%) rename langfuse/api/{unstable => }/skills/types/skill_meta_list_response.py (87%) rename langfuse/api/{unstable => }/skills/types/skill_version.py (90%) rename langfuse/api/{unstable => }/skills/types/skill_version_file_create_input.py (100%) rename langfuse/api/{unstable => }/skills/types/skill_version_file_input.py (87%) rename langfuse/api/{unstable => }/skills/types/skill_version_file_reference.py (83%) rename langfuse/api/{unstable => }/skills/types/update_skill_labels_request.py (83%) rename langfuse/api/{unstable => }/skills/types/update_skill_request.py (88%) diff --git a/langfuse/api/__init__.py b/langfuse/api/__init__.py index e4763032e..64f5a67be 100644 --- a/langfuse/api/__init__.py +++ b/langfuse/api/__init__.py @@ -33,6 +33,7 @@ scim, score_configs, scores, + skills, trace, unstable, utils, @@ -384,6 +385,22 @@ ScoreV3_Text, TextScoreV3, ) + from .skills import ( + CreateSkillVersionRequest, + DeleteSkillVersionResponse, + SkillFile, + SkillFileContent, + SkillFileContentsResponse, + SkillListPagination, + SkillMeta, + SkillMetaListResponse, + SkillVersion, + SkillVersionFileCreateInput, + SkillVersionFileInput, + SkillVersionFileReference, + UpdateSkillLabelsRequest, + UpdateSkillRequest, + ) from .trace import DeleteTraceResponse _dynamic_imports: typing.Dict[str, str] = { "AccessDeniedError": ".commons", @@ -462,6 +479,7 @@ "CreateScoreValue": ".commons", "CreateScoresRequest": ".scores", "CreateScoresResponse": ".scores", + "CreateSkillVersionRequest": ".skills", "CreateTextPromptRequest": ".prompts", "CreateTextPromptType": ".prompts", "Creator": ".evaluators", @@ -478,6 +496,7 @@ "DeleteDatasetItemResponse": ".dataset_items", "DeleteLlmConnectionResponse": ".llm_connections", "DeleteMembershipRequest": ".organizations", + "DeleteSkillVersionResponse": ".skills", "DeleteTraceResponse": ".trace", "DeletedEvaluationRule": ".evaluation_rules", "DeletedEvaluator": ".evaluators", @@ -680,6 +699,16 @@ "Score_Text": ".commons", "ServiceProviderConfig": ".scim", "ServiceUnavailableError": ".health", + "SkillFile": ".skills", + "SkillFileContent": ".skills", + "SkillFileContentsResponse": ".skills", + "SkillListPagination": ".skills", + "SkillMeta": ".skills", + "SkillMetaListResponse": ".skills", + "SkillVersion": ".skills", + "SkillVersionFileCreateInput": ".skills", + "SkillVersionFileInput": ".skills", + "SkillVersionFileReference": ".skills", "StringEvaluationRuleFilter": ".evaluation_commons", "StringObjectEvaluationRuleFilter": ".evaluation_commons", "StringOptionsEvaluationRuleFilter": ".evaluation_commons", @@ -697,6 +726,8 @@ "UpdateEvaluatorRequest": ".evaluators", "UpdateLlmAsJudgeEvaluatorRequest": ".evaluators", "UpdateScoreConfigRequest": ".score_configs", + "UpdateSkillLabelsRequest": ".skills", + "UpdateSkillRequest": ".skills", "UpsertLlmConnectionRequest": ".llm_connections", "Usage": ".commons", "UserMeta": ".scim", @@ -726,6 +757,7 @@ "scim": ".scim", "score_configs": ".score_configs", "scores": ".scores", + "skills": ".skills", "trace": ".trace", "unstable": ".unstable", "utils": ".utils", @@ -836,6 +868,7 @@ def __dir__(): "CreateScoreValue", "CreateScoresRequest", "CreateScoresResponse", + "CreateSkillVersionRequest", "CreateTextPromptRequest", "CreateTextPromptType", "Creator", @@ -852,6 +885,7 @@ def __dir__(): "DeleteDatasetItemResponse", "DeleteLlmConnectionResponse", "DeleteMembershipRequest", + "DeleteSkillVersionResponse", "DeleteTraceResponse", "DeletedEvaluationRule", "DeletedEvaluator", @@ -1054,6 +1088,16 @@ def __dir__(): "Score_Text", "ServiceProviderConfig", "ServiceUnavailableError", + "SkillFile", + "SkillFileContent", + "SkillFileContentsResponse", + "SkillListPagination", + "SkillMeta", + "SkillMetaListResponse", + "SkillVersion", + "SkillVersionFileCreateInput", + "SkillVersionFileInput", + "SkillVersionFileReference", "StringEvaluationRuleFilter", "StringObjectEvaluationRuleFilter", "StringOptionsEvaluationRuleFilter", @@ -1071,6 +1115,8 @@ def __dir__(): "UpdateEvaluatorRequest", "UpdateLlmAsJudgeEvaluatorRequest", "UpdateScoreConfigRequest", + "UpdateSkillLabelsRequest", + "UpdateSkillRequest", "UpsertLlmConnectionRequest", "Usage", "UserMeta", @@ -1100,6 +1146,7 @@ def __dir__(): "scim", "score_configs", "scores", + "skills", "trace", "unstable", "utils", diff --git a/langfuse/api/blob_storage_integrations/client.py b/langfuse/api/blob_storage_integrations/client.py index 0e609769d..242eeb2e8 100644 --- a/langfuse/api/blob_storage_integrations/client.py +++ b/langfuse/api/blob_storage_integrations/client.py @@ -159,7 +159,7 @@ def upsert_blob_storage_integration( **Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected. export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]] - Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved. + Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved. `exportFieldGroups` requires `exportSource` to be provided in the same request. @@ -438,7 +438,7 @@ async def upsert_blob_storage_integration( **Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected. export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]] - Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved. + Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved. `exportFieldGroups` requires `exportSource` to be provided in the same request. diff --git a/langfuse/api/blob_storage_integrations/raw_client.py b/langfuse/api/blob_storage_integrations/raw_client.py index 827ab1a4b..5e7fcd6f9 100644 --- a/langfuse/api/blob_storage_integrations/raw_client.py +++ b/langfuse/api/blob_storage_integrations/raw_client.py @@ -216,7 +216,7 @@ def upsert_blob_storage_integration( **Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected. export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]] - Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved. + Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved. `exportFieldGroups` requires `exportSource` to be provided in the same request. @@ -713,7 +713,7 @@ async def upsert_blob_storage_integration( **Cloud-only integration deprecation gate (effective 2026-06-22):** On Langfuse Cloud, legacy export sources are only accepted for blob storage integrations created before 2026-06-22, regardless of project age. Requests that would create a new integration with `LEGACY_TRACES_OBSERVATIONS` or `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` are rejected with HTTP 400. Use `OBSERVATIONS_V2` instead. Self-hosted deployments are unaffected. export_field_groups : typing.Optional[typing.Sequence[BlobStorageExportFieldGroup]] - Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved. + Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved. `exportFieldGroups` requires `exportSource` to be provided in the same request. diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_field_group.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_field_group.py index 32bdbf89d..a38aeaf75 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_export_field_group.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_field_group.py @@ -9,7 +9,9 @@ class BlobStorageExportFieldGroup(enum.StrEnum): """ - Field group selecting which observation columns are included in the export. Applies to all export sources; groups without a counterpart in the legacy data model (e.g. `trace_context`) are omitted from the legacy observations export. + Field group selecting which columns are included in the export. Applies to all export sources. + - Observation groups (`core` through `trace_context`) select observation columns; groups without a counterpart in the legacy data model (e.g. `trace_context`) are omitted from the legacy observations export. + - Score groups (`score_` prefix) add optional columns to the scores export. The core score columns (`id`, `timestamp`, `trace_id`, `name`, `value`, …) are always exported and are not a selectable group; score groups add columns on top of them. `score_metadata` adds the score `metadata` column. `score_provenance` adds the references to where a score came from: `author_user_id`, `config_id`, `queue_id`, `evaluator_id`, `evaluation_rule_id`, `execution_trace_id`. Score groups are never selected by default. """ CORE = "core" @@ -23,6 +25,8 @@ class BlobStorageExportFieldGroup(enum.StrEnum): METRICS = "metrics" TOOLS = "tools" TRACE_CONTEXT = "trace_context" + SCORE_METADATA = "score_metadata" + SCORE_PROVENANCE = "score_provenance" def visit( self, @@ -37,6 +41,8 @@ def visit( metrics: typing.Callable[[], T_Result], tools: typing.Callable[[], T_Result], trace_context: typing.Callable[[], T_Result], + score_metadata: typing.Callable[[], T_Result], + score_provenance: typing.Callable[[], T_Result], ) -> T_Result: if self is BlobStorageExportFieldGroup.CORE: return core() @@ -60,3 +66,7 @@ def visit( return tools() if self is BlobStorageExportFieldGroup.TRACE_CONTEXT: return trace_context() + if self is BlobStorageExportFieldGroup.SCORE_METADATA: + return score_metadata() + if self is BlobStorageExportFieldGroup.SCORE_PROVENANCE: + return score_provenance() diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py index 3cbaba167..343a03d58 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py @@ -53,7 +53,7 @@ class BlobStorageIntegrationResponse(UniversalBaseModel): FieldMetadata(alias="exportFieldGroups"), ] = pydantic.Field(default=None) """ - Field groups included in each exported observation row. An empty list is treated as all groups during export. + Field groups included in each exported observation and score row. An empty list is treated as all observation groups and no score groups during export. Core score columns are always exported. """ next_sync_at: typing_extensions.Annotated[ 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 600a8be84..65fc84e5c 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 @@ -111,7 +111,7 @@ class CreateBlobStorageIntegrationRequest(UniversalBaseModel): FieldMetadata(alias="exportFieldGroups"), ] = pydantic.Field(default=None) """ - Field groups to include in each exported observation row. Applies to all export sources; must include `core` if provided. When omitted on create, the column default (all groups) applies. When omitted on update, the existing value is preserved. + Field groups to include in each exported observation and score row. Applies to all export sources; must include the observation `core` group if provided. Core score columns are always exported; score groups add columns on top. When omitted on create, all observation groups are selected and no score groups. When omitted on update, the existing value is preserved. `exportFieldGroups` requires `exportSource` to be provided in the same request. """ diff --git a/langfuse/api/client.py b/langfuse/api/client.py index a6d960093..ded3d69f0 100644 --- a/langfuse/api/client.py +++ b/langfuse/api/client.py @@ -40,6 +40,7 @@ from .scim.client import AsyncScimClient, ScimClient from .score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient from .scores.client import AsyncScoresClient, ScoresClient + from .skills.client import AsyncSkillsClient, SkillsClient from .trace.client import AsyncTraceClient, TraceClient from .unstable.client import AsyncUnstableClient, UnstableClient @@ -147,6 +148,7 @@ def __init__( self._scim: typing.Optional[ScimClient] = None self._score_configs: typing.Optional[ScoreConfigsClient] = None self._scores: typing.Optional[ScoresClient] = None + self._skills: typing.Optional[SkillsClient] = None self._trace: typing.Optional[TraceClient] = None self._unstable: typing.Optional[UnstableClient] = None @@ -352,6 +354,14 @@ def scores(self): self._scores = ScoresClient(client_wrapper=self._client_wrapper) return self._scores + @property + def skills(self): + if self._skills is None: + from .skills.client import SkillsClient # noqa: E402 + + self._skills = SkillsClient(client_wrapper=self._client_wrapper) + return self._skills + @property def trace(self): if self._trace is None: @@ -472,6 +482,7 @@ def __init__( self._scim: typing.Optional[AsyncScimClient] = None self._score_configs: typing.Optional[AsyncScoreConfigsClient] = None self._scores: typing.Optional[AsyncScoresClient] = None + self._skills: typing.Optional[AsyncSkillsClient] = None self._trace: typing.Optional[AsyncTraceClient] = None self._unstable: typing.Optional[AsyncUnstableClient] = None @@ -685,6 +696,14 @@ def scores(self): self._scores = AsyncScoresClient(client_wrapper=self._client_wrapper) return self._scores + @property + def skills(self): + if self._skills is None: + from .skills.client import AsyncSkillsClient # noqa: E402 + + self._skills = AsyncSkillsClient(client_wrapper=self._client_wrapper) + return self._skills + @property def trace(self): if self._trace is None: diff --git a/langfuse/api/commons/types/score_config.py b/langfuse/api/commons/types/score_config.py index 36e45e168..008ac6df0 100644 --- a/langfuse/api/commons/types/score_config.py +++ b/langfuse/api/commons/types/score_config.py @@ -17,7 +17,11 @@ class ScoreConfig(UniversalBaseModel): """ id: str - name: str + name: str = pydantic.Field() + """ + Score config name. Maximum 80 characters. + """ + created_at: typing_extensions.Annotated[ dt.datetime, FieldMetadata(alias="createdAt") ] diff --git a/langfuse/api/llm_connections/client.py b/langfuse/api/llm_connections/client.py index 3d4e60d00..5590147e2 100644 --- a/langfuse/api/llm_connections/client.py +++ b/langfuse/api/llm_connections/client.py @@ -190,6 +190,169 @@ def delete( _response = self._raw_client.delete(id, request_options=request_options) return _response.data + def list_organization( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedLlmConnections: + """ + Get all organization-level LLM connections. Requires an organization-scoped API key. + + Parameters + ---------- + 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 + ------- + PaginatedLlmConnections + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + 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.llm_connections.list_organization() + """ + _response = self._raw_client.list_organization( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def upsert_organization( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> LlmConnection: + """ + Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": }` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LlmConnection + + Examples + -------- + from langfuse import LangfuseAPI + from langfuse.llm_connections import LlmAdapter + + client = LangfuseAPI( + 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.llm_connections.upsert_organization( + provider="provider", + adapter=LlmAdapter.ANTHROPIC, + secret_key="secretKey", + ) + """ + _response = self._raw_client.upsert_organization( + provider=provider, + adapter=adapter, + secret_key=secret_key, + base_url=base_url, + custom_models=custom_models, + with_default_models=with_default_models, + extra_headers=extra_headers, + config=config, + request_options=request_options, + ) + return _response.data + + def delete_organization( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteLlmConnectionResponse: + """ + Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteLlmConnectionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + 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.llm_connections.delete_organization( + id="id", + ) + """ + _response = self._raw_client.delete_organization( + id, request_options=request_options + ) + return _response.data + class AsyncLlmConnectionsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -390,3 +553,190 @@ async def main() -> None: """ _response = await self._raw_client.delete(id, request_options=request_options) return _response.data + + async def list_organization( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedLlmConnections: + """ + Get all organization-level LLM connections. Requires an organization-scoped API key. + + Parameters + ---------- + 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 + ------- + PaginatedLlmConnections + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + 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.llm_connections.list_organization() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_organization( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def upsert_organization( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> LlmConnection: + """ + Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": }` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LlmConnection + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + from langfuse.llm_connections import LlmAdapter + + client = AsyncLangfuseAPI( + 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.llm_connections.upsert_organization( + provider="provider", + adapter=LlmAdapter.ANTHROPIC, + secret_key="secretKey", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.upsert_organization( + provider=provider, + adapter=adapter, + secret_key=secret_key, + base_url=base_url, + custom_models=custom_models, + with_default_models=with_default_models, + extra_headers=extra_headers, + config=config, + request_options=request_options, + ) + return _response.data + + async def delete_organization( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteLlmConnectionResponse: + """ + Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteLlmConnectionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + 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.llm_connections.delete_organization( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_organization( + id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/llm_connections/raw_client.py b/langfuse/api/llm_connections/raw_client.py index 9a6388658..128c57a4c 100644 --- a/langfuse/api/llm_connections/raw_client.py +++ b/langfuse/api/llm_connections/raw_client.py @@ -382,12 +382,722 @@ def delete( body=_response_json, ) + def list_organization( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedLlmConnections]: + """ + Get all organization-level LLM connections. Requires an organization-scoped API key. + + Parameters + ---------- + 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 + ------- + HttpResponse[PaginatedLlmConnections] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/llm-connections", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedLlmConnections, + parse_obj_as( + type_=PaginatedLlmConnections, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def upsert_organization( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[LlmConnection]: + """ + Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": }` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[LlmConnection] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/llm-connections", + method="PUT", + json={ + "provider": provider, + "adapter": adapter, + "secretKey": secret_key, + "baseURL": base_url, + "customModels": custom_models, + "withDefaultModels": with_default_models, + "extraHeaders": extra_headers, + "config": config, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LlmConnection, + parse_obj_as( + type_=LlmConnection, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_organization( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DeleteLlmConnectionResponse]: + """ + Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteLlmConnectionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/organizations/llm-connections/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteLlmConnectionResponse, + parse_obj_as( + type_=DeleteLlmConnectionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawLlmConnectionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedLlmConnections]: + """ + Get all LLM connections in a project + + Parameters + ---------- + 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 + ------- + AsyncHttpResponse[PaginatedLlmConnections] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedLlmConnections, + parse_obj_as( + type_=PaginatedLlmConnections, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) -class AsyncRawLlmConnectionsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + async def upsert( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[LlmConnection]: + """ + Create or update an LLM connection. The connection is upserted on provider. - async def list( + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": }` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[LlmConnection] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="PUT", + json={ + "provider": provider, + "adapter": adapter, + "secretKey": secret_key, + "baseURL": base_url, + "customModels": custom_models, + "withDefaultModels": with_default_models, + "extraHeaders": extra_headers, + "config": config, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LlmConnection, + parse_obj_as( + type_=LlmConnection, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteLlmConnectionResponse]: + """ + Delete an LLM connection by id. Evaluators that depend on the deleted connection are automatically paused. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteLlmConnectionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/llm-connections/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteLlmConnectionResponse, + parse_obj_as( + type_=DeleteLlmConnectionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list_organization( self, *, page: typing.Optional[int] = None, @@ -395,7 +1105,7 @@ async def list( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[PaginatedLlmConnections]: """ - Get all LLM connections in a project + Get all organization-level LLM connections. Requires an organization-scoped API key. Parameters ---------- @@ -413,7 +1123,7 @@ async def list( AsyncHttpResponse[PaginatedLlmConnections] """ _response = await self._client_wrapper.httpx_client.request( - "api/public/llm-connections", + "api/public/organizations/llm-connections", method="GET", params={ "page": page, @@ -499,7 +1209,7 @@ async def list( body=_response_json, ) - async def upsert( + async def upsert_organization( self, *, provider: str, @@ -513,7 +1223,7 @@ async def upsert( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[LlmConnection]: """ - Create or update an LLM connection. The connection is upserted on provider. + Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key. Parameters ---------- @@ -549,7 +1259,7 @@ async def upsert( AsyncHttpResponse[LlmConnection] """ _response = await self._client_wrapper.httpx_client.request( - "api/public/llm-connections", + "api/public/organizations/llm-connections", method="PUT", json={ "provider": provider, @@ -642,11 +1352,11 @@ async def upsert( body=_response_json, ) - async def delete( + async def delete_organization( self, id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[DeleteLlmConnectionResponse]: """ - Delete an LLM connection by id. Evaluators that depend on the deleted connection are automatically paused. + Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key. Parameters ---------- @@ -660,7 +1370,7 @@ async def delete( AsyncHttpResponse[DeleteLlmConnectionResponse] """ _response = await self._client_wrapper.httpx_client.request( - f"api/public/llm-connections/{jsonable_encoder(id)}", + f"api/public/organizations/llm-connections/{jsonable_encoder(id)}", method="DELETE", request_options=request_options, ) diff --git a/langfuse/api/score_configs/client.py b/langfuse/api/score_configs/client.py index b900e3f5d..9db9cfe61 100644 --- a/langfuse/api/score_configs/client.py +++ b/langfuse/api/score_configs/client.py @@ -46,7 +46,7 @@ def create( Parameters ---------- name : str - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. data_type : ScoreConfigDataType @@ -205,7 +205,7 @@ def update( The status of the score config showing if it is archived or not name : typing.Optional[str] - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. categories : typing.Optional[typing.Sequence[ConfigCategory]] Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed @@ -287,7 +287,7 @@ async def create( Parameters ---------- name : str - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. data_type : ScoreConfigDataType @@ -470,7 +470,7 @@ async def update( The status of the score config showing if it is archived or not name : typing.Optional[str] - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. categories : typing.Optional[typing.Sequence[ConfigCategory]] Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed diff --git a/langfuse/api/score_configs/raw_client.py b/langfuse/api/score_configs/raw_client.py index 11de026c6..1f13905f7 100644 --- a/langfuse/api/score_configs/raw_client.py +++ b/langfuse/api/score_configs/raw_client.py @@ -45,7 +45,7 @@ def create( Parameters ---------- name : str - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. data_type : ScoreConfigDataType @@ -401,7 +401,7 @@ def update( The status of the score config showing if it is archived or not name : typing.Optional[str] - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. categories : typing.Optional[typing.Sequence[ConfigCategory]] Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed @@ -540,7 +540,7 @@ async def create( Parameters ---------- name : str - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. data_type : ScoreConfigDataType @@ -896,7 +896,7 @@ async def update( The status of the score config showing if it is archived or not name : typing.Optional[str] - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. categories : typing.Optional[typing.Sequence[ConfigCategory]] Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed diff --git a/langfuse/api/score_configs/types/create_score_config_request.py b/langfuse/api/score_configs/types/create_score_config_request.py index 0edb01407..175e86e46 100644 --- a/langfuse/api/score_configs/types/create_score_config_request.py +++ b/langfuse/api/score_configs/types/create_score_config_request.py @@ -13,7 +13,7 @@ class CreateScoreConfigRequest(UniversalBaseModel): name: str = pydantic.Field() """ - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. """ data_type: typing_extensions.Annotated[ diff --git a/langfuse/api/score_configs/types/update_score_config_request.py b/langfuse/api/score_configs/types/update_score_config_request.py index 28c4248e9..134920fb1 100644 --- a/langfuse/api/score_configs/types/update_score_config_request.py +++ b/langfuse/api/score_configs/types/update_score_config_request.py @@ -19,7 +19,7 @@ class UpdateScoreConfigRequest(UniversalBaseModel): name: typing.Optional[str] = pydantic.Field(default=None) """ - Name of the score config. Max 35 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. + Name of the score config. Max 80 characters. Only letters, numbers, underscores, spaces, periods, parentheses, and hyphens are allowed. """ categories: typing.Optional[typing.List[ConfigCategory]] = pydantic.Field( diff --git a/langfuse/api/unstable/skills/__init__.py b/langfuse/api/skills/__init__.py similarity index 100% rename from langfuse/api/unstable/skills/__init__.py rename to langfuse/api/skills/__init__.py diff --git a/langfuse/api/unstable/skills/client.py b/langfuse/api/skills/client.py similarity index 92% rename from langfuse/api/unstable/skills/client.py rename to langfuse/api/skills/client.py index ffbd4899e..6d0ba9739 100644 --- a/langfuse/api/unstable/skills/client.py +++ b/langfuse/api/skills/client.py @@ -3,8 +3,8 @@ import datetime as dt import typing -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.request_options import RequestOptions +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions from .raw_client import AsyncRawSkillsClient, RawSkillsClient from .types.delete_skill_version_response import DeleteSkillVersionResponse from .types.skill_file_contents_response import SkillFileContentsResponse @@ -86,7 +86,7 @@ def list( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.list() + client.skills.list() """ _response = self._raw_client.list( name=name, @@ -126,7 +126,7 @@ def create_version( Examples -------- from langfuse import LangfuseAPI - from langfuse.unstable.skills import SkillVersionFileInput + from langfuse.skills import SkillVersionFileInput client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -136,7 +136,7 @@ def create_version( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.create_version( + client.skills.create_version( files=[ SkillVersionFileInput( path="path", @@ -160,10 +160,11 @@ def get( *, version: typing.Optional[int] = None, label: typing.Optional[str] = None, + include_content: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> SkillVersion: """ - Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Use each file's sha256Hash with getFileContents, individually or in batches across manifests. + Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Set includeContent to return file contents inline, or use each file's sha256Hash with getFileContents. Parameters ---------- @@ -173,6 +174,9 @@ def get( label : typing.Optional[str] + include_content : typing.Optional[bool] + Include UTF-8 text content in each file. Defaults to false. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -192,12 +196,16 @@ def get( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.get( + client.skills.get( skill_name="skillName", ) """ _response = self._raw_client.get( - skill_name, version=version, label=label, request_options=request_options + skill_name, + version=version, + label=label, + include_content=include_content, + request_options=request_options, ) return _response.data @@ -237,7 +245,7 @@ def update( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.update( + client.skills.update( skill_name="skillName", tags=["tags", "tags"], ) @@ -280,7 +288,7 @@ def get_file_contents( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.get_file_contents( + client.skills.get_file_contents( sha256hashes="sha256Hashes", ) """ @@ -327,7 +335,7 @@ def set_labels( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.set_labels( + client.skills.set_labels( skill_name="skillName", skill_version=1, labels=["labels", "labels"], @@ -373,7 +381,7 @@ def delete_version( password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) - client.unstable.skills.delete_version( + client.skills.delete_version( skill_name="skillName", skill_version=1, ) @@ -459,7 +467,7 @@ async def list( async def main() -> None: - await client.unstable.skills.list() + await client.skills.list() asyncio.run(main()) @@ -504,7 +512,7 @@ async def create_version( import asyncio from langfuse import AsyncLangfuseAPI - from langfuse.unstable.skills import SkillVersionFileInput + from langfuse.skills import SkillVersionFileInput client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -517,7 +525,7 @@ async def create_version( async def main() -> None: - await client.unstable.skills.create_version( + await client.skills.create_version( files=[ SkillVersionFileInput( path="path", @@ -544,10 +552,11 @@ async def get( *, version: typing.Optional[int] = None, label: typing.Optional[str] = None, + include_content: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> SkillVersion: """ - Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Use each file's sha256Hash with getFileContents, individually or in batches across manifests. + Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Set includeContent to return file contents inline, or use each file's sha256Hash with getFileContents. Parameters ---------- @@ -557,6 +566,9 @@ async def get( label : typing.Optional[str] + include_content : typing.Optional[bool] + Include UTF-8 text content in each file. Defaults to false. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -581,7 +593,7 @@ async def get( async def main() -> None: - await client.unstable.skills.get( + await client.skills.get( skill_name="skillName", ) @@ -589,7 +601,11 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.get( - skill_name, version=version, label=label, request_options=request_options + skill_name, + version=version, + label=label, + include_content=include_content, + request_options=request_options, ) return _response.data @@ -634,7 +650,7 @@ async def update( async def main() -> None: - await client.unstable.skills.update( + await client.skills.update( skill_name="skillName", tags=["tags", "tags"], ) @@ -685,7 +701,7 @@ async def get_file_contents( async def main() -> None: - await client.unstable.skills.get_file_contents( + await client.skills.get_file_contents( sha256hashes="sha256Hashes", ) @@ -740,7 +756,7 @@ async def set_labels( async def main() -> None: - await client.unstable.skills.set_labels( + await client.skills.set_labels( skill_name="skillName", skill_version=1, labels=["labels", "labels"], @@ -794,7 +810,7 @@ async def delete_version( async def main() -> None: - await client.unstable.skills.delete_version( + await client.skills.delete_version( skill_name="skillName", skill_version=1, ) diff --git a/langfuse/api/unstable/skills/raw_client.py b/langfuse/api/skills/raw_client.py similarity index 96% rename from langfuse/api/unstable/skills/raw_client.py rename to langfuse/api/skills/raw_client.py index 152cc2781..bf7efa0cd 100644 --- a/langfuse/api/unstable/skills/raw_client.py +++ b/langfuse/api/skills/raw_client.py @@ -4,19 +4,19 @@ import typing from json.decoder import JSONDecodeError -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 ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.http_response import AsyncHttpResponse, HttpResponse -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import parse_obj_as -from ...core.request_options import RequestOptions -from ...core.serialization import convert_and_respect_annotation_metadata +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 ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata from .types.delete_skill_version_response import DeleteSkillVersionResponse from .types.skill_file_contents_response import SkillFileContentsResponse from .types.skill_meta_list_response import SkillMetaListResponse @@ -75,7 +75,7 @@ def list( HttpResponse[SkillMetaListResponse] """ _response = self._client_wrapper.httpx_client.request( - "api/public/unstable/skills", + "api/public/skills", method="GET", params={ "name": name, @@ -194,7 +194,7 @@ def create_version( HttpResponse[SkillVersion] """ _response = self._client_wrapper.httpx_client.request( - "api/public/unstable/skills", + "api/public/skills", method="POST", json={ "files": convert_and_respect_annotation_metadata( @@ -291,10 +291,11 @@ def get( *, version: typing.Optional[int] = None, label: typing.Optional[str] = None, + include_content: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[SkillVersion]: """ - Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Use each file's sha256Hash with getFileContents, individually or in batches across manifests. + Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Set includeContent to return file contents inline, or use each file's sha256Hash with getFileContents. Parameters ---------- @@ -304,6 +305,9 @@ def get( label : typing.Optional[str] + include_content : typing.Optional[bool] + Include UTF-8 text content in each file. Defaults to false. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -312,11 +316,12 @@ def get( HttpResponse[SkillVersion] """ _response = self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}", + f"api/public/skills/{jsonable_encoder(skill_name)}", method="GET", params={ "version": version, "label": label, + "includeContent": include_content, }, request_options=request_options, ) @@ -423,7 +428,7 @@ def update( HttpResponse[SkillVersion] """ _response = self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}", + f"api/public/skills/{jsonable_encoder(skill_name)}", method="PATCH", json={ "tags": tags, @@ -531,7 +536,7 @@ def get_file_contents( HttpResponse[SkillFileContentsResponse] """ _response = self._client_wrapper.httpx_client.request( - "api/public/unstable/skills/files/content", + "api/public/skills/files/content", method="GET", params={ "sha256Hashes": sha256hashes, @@ -643,7 +648,7 @@ def set_labels( HttpResponse[SkillVersion] """ _response = self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", + f"api/public/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", method="PATCH", json={ "labels": labels, @@ -753,7 +758,7 @@ def delete_version( HttpResponse[DeleteSkillVersionResponse] """ _response = self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", + f"api/public/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", method="DELETE", request_options=request_options, ) @@ -884,7 +889,7 @@ async def list( AsyncHttpResponse[SkillMetaListResponse] """ _response = await self._client_wrapper.httpx_client.request( - "api/public/unstable/skills", + "api/public/skills", method="GET", params={ "name": name, @@ -1003,7 +1008,7 @@ async def create_version( AsyncHttpResponse[SkillVersion] """ _response = await self._client_wrapper.httpx_client.request( - "api/public/unstable/skills", + "api/public/skills", method="POST", json={ "files": convert_and_respect_annotation_metadata( @@ -1100,10 +1105,11 @@ async def get( *, version: typing.Optional[int] = None, label: typing.Optional[str] = None, + include_content: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[SkillVersion]: """ - Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Use each file's sha256Hash with getFileContents, individually or in batches across manifests. + Resolve a skill's metadata and file manifest by version or label. Defaults to the production label. Set includeContent to return file contents inline, or use each file's sha256Hash with getFileContents. Parameters ---------- @@ -1113,6 +1119,9 @@ async def get( label : typing.Optional[str] + include_content : typing.Optional[bool] + Include UTF-8 text content in each file. Defaults to false. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1121,11 +1130,12 @@ async def get( AsyncHttpResponse[SkillVersion] """ _response = await self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}", + f"api/public/skills/{jsonable_encoder(skill_name)}", method="GET", params={ "version": version, "label": label, + "includeContent": include_content, }, request_options=request_options, ) @@ -1232,7 +1242,7 @@ async def update( AsyncHttpResponse[SkillVersion] """ _response = await self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}", + f"api/public/skills/{jsonable_encoder(skill_name)}", method="PATCH", json={ "tags": tags, @@ -1340,7 +1350,7 @@ async def get_file_contents( AsyncHttpResponse[SkillFileContentsResponse] """ _response = await self._client_wrapper.httpx_client.request( - "api/public/unstable/skills/files/content", + "api/public/skills/files/content", method="GET", params={ "sha256Hashes": sha256hashes, @@ -1452,7 +1462,7 @@ async def set_labels( AsyncHttpResponse[SkillVersion] """ _response = await self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", + f"api/public/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", method="PATCH", json={ "labels": labels, @@ -1562,7 +1572,7 @@ async def delete_version( AsyncHttpResponse[DeleteSkillVersionResponse] """ _response = await self._client_wrapper.httpx_client.request( - f"api/public/unstable/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", + f"api/public/skills/{jsonable_encoder(skill_name)}/versions/{jsonable_encoder(skill_version)}", method="DELETE", request_options=request_options, ) diff --git a/langfuse/api/unstable/skills/types/__init__.py b/langfuse/api/skills/types/__init__.py similarity index 100% rename from langfuse/api/unstable/skills/types/__init__.py rename to langfuse/api/skills/types/__init__.py diff --git a/langfuse/api/unstable/skills/types/create_skill_version_request.py b/langfuse/api/skills/types/create_skill_version_request.py similarity index 83% rename from langfuse/api/unstable/skills/types/create_skill_version_request.py rename to langfuse/api/skills/types/create_skill_version_request.py index cf7c073ca..5f2997b69 100644 --- a/langfuse/api/unstable/skills/types/create_skill_version_request.py +++ b/langfuse/api/skills/types/create_skill_version_request.py @@ -4,8 +4,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata from .skill_version_file_create_input import SkillVersionFileCreateInput diff --git a/langfuse/api/unstable/skills/types/delete_skill_version_response.py b/langfuse/api/skills/types/delete_skill_version_response.py similarity index 83% rename from langfuse/api/unstable/skills/types/delete_skill_version_response.py rename to langfuse/api/skills/types/delete_skill_version_response.py index cf92c2867..77551f981 100644 --- a/langfuse/api/unstable/skills/types/delete_skill_version_response.py +++ b/langfuse/api/skills/types/delete_skill_version_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteSkillVersionResponse(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/skill_file.py b/langfuse/api/skills/types/skill_file.py similarity index 70% rename from langfuse/api/unstable/skills/types/skill_file.py rename to langfuse/api/skills/types/skill_file.py index 683b13679..3c3e71252 100644 --- a/langfuse/api/unstable/skills/types/skill_file.py +++ b/langfuse/api/skills/types/skill_file.py @@ -4,8 +4,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata class SkillFile(UniversalBaseModel): @@ -17,6 +17,10 @@ class SkillFile(UniversalBaseModel): content_length: typing_extensions.Annotated[ int, FieldMetadata(alias="contentLength") ] + content: typing.Optional[str] = pydantic.Field(default=None) + """ + UTF-8 text content, included when fetching a skill with includeContent enabled. + """ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( extra="allow", frozen=True diff --git a/langfuse/api/unstable/skills/types/skill_file_content.py b/langfuse/api/skills/types/skill_file_content.py similarity index 78% rename from langfuse/api/unstable/skills/types/skill_file_content.py rename to langfuse/api/skills/types/skill_file_content.py index ce324848d..6ad17badc 100644 --- a/langfuse/api/unstable/skills/types/skill_file_content.py +++ b/langfuse/api/skills/types/skill_file_content.py @@ -4,8 +4,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata class SkillFileContent(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/skill_file_contents_response.py b/langfuse/api/skills/types/skill_file_contents_response.py similarity index 85% rename from langfuse/api/unstable/skills/types/skill_file_contents_response.py rename to langfuse/api/skills/types/skill_file_contents_response.py index 85bb7e2fa..51c8fa90b 100644 --- a/langfuse/api/unstable/skills/types/skill_file_contents_response.py +++ b/langfuse/api/skills/types/skill_file_contents_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .skill_file_content import SkillFileContent diff --git a/langfuse/api/unstable/skills/types/skill_list_pagination.py b/langfuse/api/skills/types/skill_list_pagination.py similarity index 76% rename from langfuse/api/unstable/skills/types/skill_list_pagination.py rename to langfuse/api/skills/types/skill_list_pagination.py index f7ae797de..e671ebb87 100644 --- a/langfuse/api/unstable/skills/types/skill_list_pagination.py +++ b/langfuse/api/skills/types/skill_list_pagination.py @@ -4,8 +4,8 @@ import pydantic import typing_extensions -from ....core.serialization import FieldMetadata -from ....utils.pagination.types.meta_response import MetaResponse +from ...core.serialization import FieldMetadata +from ...utils.pagination.types.meta_response import MetaResponse class SkillListPagination(MetaResponse): diff --git a/langfuse/api/unstable/skills/types/skill_meta.py b/langfuse/api/skills/types/skill_meta.py similarity index 90% rename from langfuse/api/unstable/skills/types/skill_meta.py rename to langfuse/api/skills/types/skill_meta.py index a391972df..1fa1361f6 100644 --- a/langfuse/api/unstable/skills/types/skill_meta.py +++ b/langfuse/api/skills/types/skill_meta.py @@ -5,8 +5,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata class SkillMeta(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/skill_meta_list_response.py b/langfuse/api/skills/types/skill_meta_list_response.py similarity index 87% rename from langfuse/api/unstable/skills/types/skill_meta_list_response.py rename to langfuse/api/skills/types/skill_meta_list_response.py index a097e1bc0..f2b5da4ab 100644 --- a/langfuse/api/unstable/skills/types/skill_meta_list_response.py +++ b/langfuse/api/skills/types/skill_meta_list_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .skill_list_pagination import SkillListPagination from .skill_meta import SkillMeta diff --git a/langfuse/api/unstable/skills/types/skill_version.py b/langfuse/api/skills/types/skill_version.py similarity index 90% rename from langfuse/api/unstable/skills/types/skill_version.py rename to langfuse/api/skills/types/skill_version.py index c3486c23d..ff40643e4 100644 --- a/langfuse/api/unstable/skills/types/skill_version.py +++ b/langfuse/api/skills/types/skill_version.py @@ -5,8 +5,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata from .skill_file import SkillFile diff --git a/langfuse/api/unstable/skills/types/skill_version_file_create_input.py b/langfuse/api/skills/types/skill_version_file_create_input.py similarity index 100% rename from langfuse/api/unstable/skills/types/skill_version_file_create_input.py rename to langfuse/api/skills/types/skill_version_file_create_input.py diff --git a/langfuse/api/unstable/skills/types/skill_version_file_input.py b/langfuse/api/skills/types/skill_version_file_input.py similarity index 87% rename from langfuse/api/unstable/skills/types/skill_version_file_input.py rename to langfuse/api/skills/types/skill_version_file_input.py index c6f20d51e..8b4fade29 100644 --- a/langfuse/api/unstable/skills/types/skill_version_file_input.py +++ b/langfuse/api/skills/types/skill_version_file_input.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class SkillVersionFileInput(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/skill_version_file_reference.py b/langfuse/api/skills/types/skill_version_file_reference.py similarity index 83% rename from langfuse/api/unstable/skills/types/skill_version_file_reference.py rename to langfuse/api/skills/types/skill_version_file_reference.py index 4960d9e90..5d2cd7a7b 100644 --- a/langfuse/api/unstable/skills/types/skill_version_file_reference.py +++ b/langfuse/api/skills/types/skill_version_file_reference.py @@ -4,8 +4,8 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import UniversalBaseModel -from ....core.serialization import FieldMetadata +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.serialization import FieldMetadata class SkillVersionFileReference(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/update_skill_labels_request.py b/langfuse/api/skills/types/update_skill_labels_request.py similarity index 83% rename from langfuse/api/unstable/skills/types/update_skill_labels_request.py rename to langfuse/api/skills/types/update_skill_labels_request.py index c1931a1e4..2b6dc9286 100644 --- a/langfuse/api/unstable/skills/types/update_skill_labels_request.py +++ b/langfuse/api/skills/types/update_skill_labels_request.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class UpdateSkillLabelsRequest(UniversalBaseModel): diff --git a/langfuse/api/unstable/skills/types/update_skill_request.py b/langfuse/api/skills/types/update_skill_request.py similarity index 88% rename from langfuse/api/unstable/skills/types/update_skill_request.py rename to langfuse/api/skills/types/update_skill_request.py index 3c211b921..9d5cce65a 100644 --- a/langfuse/api/unstable/skills/types/update_skill_request.py +++ b/langfuse/api/skills/types/update_skill_request.py @@ -3,7 +3,7 @@ import typing import pydantic -from ....core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class UpdateSkillRequest(UniversalBaseModel): diff --git a/langfuse/api/unstable/__init__.py b/langfuse/api/unstable/__init__.py index 331154d29..2a249200a 100644 --- a/langfuse/api/unstable/__init__.py +++ b/langfuse/api/unstable/__init__.py @@ -20,7 +20,7 @@ TooManyRequestsError, UnauthorizedError, ) - from . import dashboard_widgets, dashboards, errors, skills + from . import dashboard_widgets, dashboards, errors from .dashboard_widgets import ( CreateDashboardWidgetRequest, DashboardWidget, @@ -59,22 +59,6 @@ UpdateDashboardRequest, WidgetPlacement, ) - from .skills import ( - CreateSkillVersionRequest, - DeleteSkillVersionResponse, - SkillFile, - SkillFileContent, - SkillFileContentsResponse, - SkillListPagination, - SkillMeta, - SkillMetaListResponse, - SkillVersion, - SkillVersionFileCreateInput, - SkillVersionFileInput, - SkillVersionFileReference, - UpdateSkillLabelsRequest, - UpdateSkillRequest, - ) _dynamic_imports: typing.Dict[str, str] = { "AccessDeniedError": ".errors", "BadRequestError": ".errors", @@ -85,7 +69,6 @@ "CreateDashboardRequest": ".dashboards", "CreateDashboardWidgetRequest": ".dashboard_widgets", "CreatePresetPlacement": ".dashboards", - "CreateSkillVersionRequest": ".skills", "CreateWidgetPlacement": ".dashboards", "Dashboard": ".dashboards", "DashboardDefinition": ".dashboards", @@ -109,7 +92,6 @@ "DeleteDashboardPlacementResponse": ".dashboards", "DeleteDashboardResponse": ".dashboards", "DeleteDashboardWidgetResponse": ".dashboard_widgets", - "DeleteSkillVersionResponse": ".skills", "InternalServerError": ".errors", "MethodNotAllowedError": ".errors", "NotFoundError": ".errors", @@ -118,28 +100,15 @@ "PublicApiErrorCode": ".errors", "PublicApiErrorDetails": ".errors", "PublicApiValidationIssue": ".errors", - "SkillFile": ".skills", - "SkillFileContent": ".skills", - "SkillFileContentsResponse": ".skills", - "SkillListPagination": ".skills", - "SkillMeta": ".skills", - "SkillMetaListResponse": ".skills", - "SkillVersion": ".skills", - "SkillVersionFileCreateInput": ".skills", - "SkillVersionFileInput": ".skills", - "SkillVersionFileReference": ".skills", "TooManyRequestsError": ".errors", "UnauthorizedError": ".errors", "UpdateDashboardPlacementRequest": ".dashboards", "UpdateDashboardRequest": ".dashboards", "UpdateDashboardWidgetRequest": ".dashboard_widgets", - "UpdateSkillLabelsRequest": ".skills", - "UpdateSkillRequest": ".skills", "WidgetPlacement": ".dashboards", "dashboard_widgets": ".dashboard_widgets", "dashboards": ".dashboards", "errors": ".errors", - "skills": ".skills", } @@ -180,7 +149,6 @@ def __dir__(): "CreateDashboardRequest", "CreateDashboardWidgetRequest", "CreatePresetPlacement", - "CreateSkillVersionRequest", "CreateWidgetPlacement", "Dashboard", "DashboardDefinition", @@ -204,7 +172,6 @@ def __dir__(): "DeleteDashboardPlacementResponse", "DeleteDashboardResponse", "DeleteDashboardWidgetResponse", - "DeleteSkillVersionResponse", "InternalServerError", "MethodNotAllowedError", "NotFoundError", @@ -213,26 +180,13 @@ def __dir__(): "PublicApiErrorCode", "PublicApiErrorDetails", "PublicApiValidationIssue", - "SkillFile", - "SkillFileContent", - "SkillFileContentsResponse", - "SkillListPagination", - "SkillMeta", - "SkillMetaListResponse", - "SkillVersion", - "SkillVersionFileCreateInput", - "SkillVersionFileInput", - "SkillVersionFileReference", "TooManyRequestsError", "UnauthorizedError", "UpdateDashboardPlacementRequest", "UpdateDashboardRequest", "UpdateDashboardWidgetRequest", - "UpdateSkillLabelsRequest", - "UpdateSkillRequest", "WidgetPlacement", "dashboard_widgets", "dashboards", "errors", - "skills", ] diff --git a/langfuse/api/unstable/client.py b/langfuse/api/unstable/client.py index 3cc2a9298..23050bc80 100644 --- a/langfuse/api/unstable/client.py +++ b/langfuse/api/unstable/client.py @@ -13,7 +13,6 @@ DashboardWidgetsClient, ) from .dashboards.client import AsyncDashboardsClient, DashboardsClient - from .skills.client import AsyncSkillsClient, SkillsClient class UnstableClient: @@ -22,7 +21,6 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper self._dashboard_widgets: typing.Optional[DashboardWidgetsClient] = None self._dashboards: typing.Optional[DashboardsClient] = None - self._skills: typing.Optional[SkillsClient] = None @property def with_raw_response(self) -> RawUnstableClient: @@ -53,14 +51,6 @@ def dashboards(self): self._dashboards = DashboardsClient(client_wrapper=self._client_wrapper) return self._dashboards - @property - def skills(self): - if self._skills is None: - from .skills.client import SkillsClient # noqa: E402 - - self._skills = SkillsClient(client_wrapper=self._client_wrapper) - return self._skills - class AsyncUnstableClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -68,7 +58,6 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper self._dashboard_widgets: typing.Optional[AsyncDashboardWidgetsClient] = None self._dashboards: typing.Optional[AsyncDashboardsClient] = None - self._skills: typing.Optional[AsyncSkillsClient] = None @property def with_raw_response(self) -> AsyncRawUnstableClient: @@ -100,11 +89,3 @@ def dashboards(self): client_wrapper=self._client_wrapper ) return self._dashboards - - @property - def skills(self): - if self._skills is None: - from .skills.client import AsyncSkillsClient # noqa: E402 - - self._skills = AsyncSkillsClient(client_wrapper=self._client_wrapper) - return self._skills