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/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