diff --git a/sdk-endpoints.txt b/sdk-endpoints.txt index fefe20e7..bc140282 100644 --- a/sdk-endpoints.txt +++ b/sdk-endpoints.txt @@ -153,10 +153,12 @@ GET /api/v1/models/metadata # not yet wrapped GET /api/v1/traces # not yet wrapped GET /api/v1/traces/count # not yet wrapped GET /api/v1/traces/series # not yet wrapped +GET /api/v1/traces/requests/{request_id} # not yet wrapped GET /api/v1/traces/{trace_id} # not yet wrapped GET /api/v1/organizations/me/traces # not yet wrapped GET /api/v1/organizations/me/traces/count # not yet wrapped GET /api/v1/organizations/me/traces/series # not yet wrapped +GET /api/v1/organizations/me/traces/requests/{request_id} # not yet wrapped GET /api/v1/organizations/me/traces/{trace_id} # not yet wrapped # Other control-plane extensions of already-covered resources GET /api/v1/usage/count # not yet wrapped @@ -164,9 +166,20 @@ GET /api/v1/usage/requests/{request_id} # not yet wrapped POST /api/v1/keys/{key_id}/rotate # not yet wrapped GET /api/v1/budgets/{budget_id}/reset-logs # not yet wrapped PUT /api/v1/budgets/{budget_id} # not yet wrapped +GET /api/v1/keys/{key_id}/end-users # not yet wrapped +PUT /api/v1/keys/{key_id}/end-users # not yet wrapped +PATCH /api/v1/keys/{key_id}/end-users # not yet wrapped GET /api/v1/keys/{key_id}/end-users/{external_id} # not yet wrapped PUT /api/v1/keys/{key_id}/end-users/{external_id} # not yet wrapped PATCH /api/v1/keys/{key_id}/end-users/{external_id} # not yet wrapped +# A service key managing its own end users, authenticated with that key +GET /api/v1/end-users # not yet wrapped +PUT /api/v1/end-users # not yet wrapped +PATCH /api/v1/end-users # not yet wrapped +GET /api/v1/end-users/{external_id} # not yet wrapped +PUT /api/v1/end-users/{external_id} # not yet wrapped +PATCH /api/v1/end-users/{external_id} # not yet wrapped +GET /api/v1/end-user-budgets # not yet wrapped # --- Second wave of gateway endpoints (added after the initial manifest) --- # Dashboard session auth: browser cookie flow for the admin UI, not an SDK surface. @@ -180,9 +193,10 @@ DELETE /api/v1/auth/session # dashboard-only # flow. An SDK authenticates with the master key or an API key and never holds # a password, so there is nothing here for one to wrap. PUT /api/v1/auth/password # dashboard-only -# The name the signed-in identity goes by: the account page's own write, beside +# Who the signed-in identity is, and the name it goes by: the account page's own read and write, beside # the credential ones. An SDK authenticates as a key rather than as a person and # has no account page to render, so there is nothing here for one to wrap. +GET /api/v1/auth/profile # dashboard-only PATCH /api/v1/auth/profile # dashboard-only # A signed-in person's message to the Otari team, sent from the top bar (the # account menu on a phone). @@ -196,6 +210,8 @@ POST /api/v1/auth/verify-email # dashboard-only POST /api/v1/auth/resend-verification # dashboard-only POST /api/v1/auth/password/reset # dashboard-only POST /api/v1/auth/password/reset/confirm # dashboard-only +POST /api/v1/auth/password/reset/validate # dashboard-only +POST /api/v1/auth/verify-email/validate # dashboard-only # Passkeys (otari#652): both ceremonies need a WebAuthn authenticator, which is # a browser API. An SDK cannot produce an attestation or an assertion, so there # is nothing here for one to wrap, including the credential list: it exists to @@ -292,6 +308,7 @@ DELETE /api/v1/scoped-budgets/{budget_id} # not yet wrappe GET /api/v1/admin/access # dashboard-only GET /api/v1/admin/users # dashboard-only PATCH /api/v1/admin/users/{user_id} # dashboard-only +POST /api/v1/admin/users/{user_id}/password-link # dashboard-only # Tenancy: organizations, workspaces, and their memberships. The dashboard's # tenancy pages are the consumer; an SDK caller acts inside one workspace with a # key that already names it, so none of these is an SDK surface yet. Move to @@ -378,6 +395,7 @@ POST /api/v1/organizations/me/guardrail-definitions/{definition_id}/test # dash POST /api/v1/organizations/me/member-invitations # dashboard-only POST /api/v1/organizations/me/member-invitations/bulk # dashboard-only DELETE /api/v1/organizations/me/member-invitations/{invitation_id} # dashboard-only +POST /api/v1/organizations/me/member-invitations/{invitation_id}/reissue # dashboard-only # The invitee's side of the same flow, and dashboard-only for the same reason # the admin's side above is: it acts as a signed-in person deciding about their # own membership, not as a key-holder calling the gateway. diff --git a/src/otari/_client/__init__.py b/src/otari/_client/__init__.py index 354540a1..375c6af2 100644 --- a/src/otari/_client/__init__.py +++ b/src/otari/_client/__init__.py @@ -30,6 +30,7 @@ "ChatApi", "DecisionsApi", "EmbeddingsApi", + "EndUsersApi", "FeedbackApi", "FilesApi", "HealthApi", @@ -270,6 +271,7 @@ "EmbeddingRequest", "EmbeddingResponse", "EmbeddingUsage", + "EndUserBudgetPublic", "EndUserPublic", "EndUserPut", "EndUserUpdate", @@ -454,6 +456,9 @@ "MSGImageURL", "MSGInputAudio", "MailSettings", + "MailedLinkRequest", + "MailedLinkStatus", + "MailedLinkStatusResponse", "MaintenanceMode", "ManagedTool", "McpErrorBody", @@ -529,6 +534,7 @@ "OrganizationModelPricingUpdate", "OrganizationModelPricingsPublic", "OrganizationPublic", + "OrganizationRefusal", "OrganizationScopedBudgetCreate", "OrganizationScopedBudgetPublic", "OrganizationScopedBudgetUpdate", @@ -536,6 +542,7 @@ "OutputShape", "OverviewSummaryResponse", "PasskeySessionResponse", + "PasswordLinkPublic", "PasswordResponse", "PendingOrganizationInvitationPublic", "PendingOrganizationInvitationsPublic", @@ -753,6 +760,7 @@ from otari._client.api.chat_api import ChatApi as ChatApi from otari._client.api.decisions_api import DecisionsApi as DecisionsApi from otari._client.api.embeddings_api import EmbeddingsApi as EmbeddingsApi +from otari._client.api.end_users_api import EndUsersApi as EndUsersApi from otari._client.api.feedback_api import FeedbackApi as FeedbackApi from otari._client.api.files_api import FilesApi as FilesApi from otari._client.api.health_api import HealthApi as HealthApi @@ -997,6 +1005,7 @@ from otari._client.models.embedding_request import EmbeddingRequest as EmbeddingRequest from otari._client.models.embedding_response import EmbeddingResponse as EmbeddingResponse from otari._client.models.embedding_usage import EmbeddingUsage as EmbeddingUsage +from otari._client.models.end_user_budget_public import EndUserBudgetPublic as EndUserBudgetPublic from otari._client.models.end_user_public import EndUserPublic as EndUserPublic from otari._client.models.end_user_put import EndUserPut as EndUserPut from otari._client.models.end_user_update import EndUserUpdate as EndUserUpdate @@ -1181,6 +1190,9 @@ from otari._client.models.msg_image_url import MSGImageURL as MSGImageURL from otari._client.models.msg_input_audio import MSGInputAudio as MSGInputAudio from otari._client.models.mail_settings import MailSettings as MailSettings +from otari._client.models.mailed_link_request import MailedLinkRequest as MailedLinkRequest +from otari._client.models.mailed_link_status import MailedLinkStatus as MailedLinkStatus +from otari._client.models.mailed_link_status_response import MailedLinkStatusResponse as MailedLinkStatusResponse from otari._client.models.maintenance_mode import MaintenanceMode as MaintenanceMode from otari._client.models.managed_tool import ManagedTool as ManagedTool from otari._client.models.mcp_error_body import McpErrorBody as McpErrorBody @@ -1256,6 +1268,7 @@ from otari._client.models.organization_model_pricing_update import OrganizationModelPricingUpdate as OrganizationModelPricingUpdate from otari._client.models.organization_model_pricings_public import OrganizationModelPricingsPublic as OrganizationModelPricingsPublic from otari._client.models.organization_public import OrganizationPublic as OrganizationPublic +from otari._client.models.organization_refusal import OrganizationRefusal as OrganizationRefusal from otari._client.models.organization_scoped_budget_create import OrganizationScopedBudgetCreate as OrganizationScopedBudgetCreate from otari._client.models.organization_scoped_budget_public import OrganizationScopedBudgetPublic as OrganizationScopedBudgetPublic from otari._client.models.organization_scoped_budget_update import OrganizationScopedBudgetUpdate as OrganizationScopedBudgetUpdate @@ -1263,6 +1276,7 @@ from otari._client.models.output_shape import OutputShape as OutputShape from otari._client.models.overview_summary_response import OverviewSummaryResponse as OverviewSummaryResponse from otari._client.models.passkey_session_response import PasskeySessionResponse as PasskeySessionResponse +from otari._client.models.password_link_public import PasswordLinkPublic as PasswordLinkPublic from otari._client.models.password_response import PasswordResponse as PasswordResponse from otari._client.models.pending_organization_invitation_public import PendingOrganizationInvitationPublic as PendingOrganizationInvitationPublic from otari._client.models.pending_organization_invitations_public import PendingOrganizationInvitationsPublic as PendingOrganizationInvitationsPublic diff --git a/src/otari/_client/api/__init__.py b/src/otari/_client/api/__init__.py index d1195b3a..4514cf4d 100644 --- a/src/otari/_client/api/__init__.py +++ b/src/otari/_client/api/__init__.py @@ -13,6 +13,7 @@ from otari._client.api.chat_api import ChatApi from otari._client.api.decisions_api import DecisionsApi from otari._client.api.embeddings_api import EmbeddingsApi +from otari._client.api.end_users_api import EndUsersApi from otari._client.api.feedback_api import FeedbackApi from otari._client.api.files_api import FilesApi from otari._client.api.health_api import HealthApi diff --git a/src/otari/_client/api/admin_api.py b/src/otari/_client/api/admin_api.py index 6c78fa85..ea0a64b6 100644 --- a/src/otari/_client/api/admin_api.py +++ b/src/otari/_client/api/admin_api.py @@ -23,6 +23,7 @@ from otari._client.models.deployment_user_public import DeploymentUserPublic from otari._client.models.deployment_user_update_request import DeploymentUserUpdateRequest from otari._client.models.deployment_users_public import DeploymentUsersPublic +from otari._client.models.password_link_public import PasswordLinkPublic from otari._client.api_client import ApiClient, RequestSerialized from otari._client.api_response import ApiResponse @@ -289,11 +290,277 @@ def _admin_get_administration_access_serialize( + @validate_call + def admin_issue_password_link( + self, + user_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> PasswordLinkPublic: + """Issue Password Link + + Give an account a single-use link that sets its password, for someone who cannot sign in. Where this deployment can mail links, the link goes to the account's address and is not returned, the same as \"Forgot your password?\". Where it cannot, or the send fails, the response carries the link for you to pass on, which is how a member who forgot their password gets back in on a deployment without mail. A password chosen through a link that was not mailed records the address as vouched for rather than proven. A new link replaces any earlier reset link for the account. Refused with 409 for a deactivated account, one with no address, one that has no password and signs in with a provider or a passkey (its owner adds a password once signed in), and, where open_signup is disabled, an unverified address no organization still has as a member or invitee. + + :param user_id: (required) + :type user_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._admin_issue_password_link_serialize( + user_id=user_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "PasswordLinkPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def admin_issue_password_link_with_http_info( + self, + user_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[PasswordLinkPublic]: + """Issue Password Link + + Give an account a single-use link that sets its password, for someone who cannot sign in. Where this deployment can mail links, the link goes to the account's address and is not returned, the same as \"Forgot your password?\". Where it cannot, or the send fails, the response carries the link for you to pass on, which is how a member who forgot their password gets back in on a deployment without mail. A password chosen through a link that was not mailed records the address as vouched for rather than proven. A new link replaces any earlier reset link for the account. Refused with 409 for a deactivated account, one with no address, one that has no password and signs in with a provider or a passkey (its owner adds a password once signed in), and, where open_signup is disabled, an unverified address no organization still has as a member or invitee. + + :param user_id: (required) + :type user_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._admin_issue_password_link_serialize( + user_id=user_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "PasswordLinkPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def admin_issue_password_link_without_preload_content( + self, + user_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Issue Password Link + + Give an account a single-use link that sets its password, for someone who cannot sign in. Where this deployment can mail links, the link goes to the account's address and is not returned, the same as \"Forgot your password?\". Where it cannot, or the send fails, the response carries the link for you to pass on, which is how a member who forgot their password gets back in on a deployment without mail. A password chosen through a link that was not mailed records the address as vouched for rather than proven. A new link replaces any earlier reset link for the account. Refused with 409 for a deactivated account, one with no address, one that has no password and signs in with a provider or a passkey (its owner adds a password once signed in), and, where open_signup is disabled, an unverified address no organization still has as a member or invitee. + + :param user_id: (required) + :type user_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._admin_issue_password_link_serialize( + user_id=user_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "PasswordLinkPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _admin_issue_password_link_serialize( + self, + user_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if user_id is not None: + _path_params['user_id'] = user_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/api/v1/admin/users/{user_id}/password-link', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def admin_list_deployment_users( self, skip: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Number of records to skip")] = None, limit: Annotated[Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]], Field(description="Maximum number of records to return")] = None, + search: Annotated[Optional[Annotated[str, Field(strict=True, max_length=200)]], Field(description="Narrow to accounts whose name or email contains this text, case-insensitively.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -309,12 +576,14 @@ def admin_list_deployment_users( ) -> DeploymentUsersPublic: """List Deployment Users - List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. + List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. ``search`` narrows the page and the count together. :param skip: Number of records to skip :type skip: int :param limit: Maximum number of records to return :type limit: int + :param search: Narrow to accounts whose name or email contains this text, case-insensitively. + :type search: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -340,6 +609,7 @@ def admin_list_deployment_users( _param = self._admin_list_deployment_users_serialize( skip=skip, limit=limit, + search=search, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -366,6 +636,7 @@ def admin_list_deployment_users_with_http_info( self, skip: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Number of records to skip")] = None, limit: Annotated[Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]], Field(description="Maximum number of records to return")] = None, + search: Annotated[Optional[Annotated[str, Field(strict=True, max_length=200)]], Field(description="Narrow to accounts whose name or email contains this text, case-insensitively.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -381,12 +652,14 @@ def admin_list_deployment_users_with_http_info( ) -> ApiResponse[DeploymentUsersPublic]: """List Deployment Users - List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. + List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. ``search`` narrows the page and the count together. :param skip: Number of records to skip :type skip: int :param limit: Maximum number of records to return :type limit: int + :param search: Narrow to accounts whose name or email contains this text, case-insensitively. + :type search: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -412,6 +685,7 @@ def admin_list_deployment_users_with_http_info( _param = self._admin_list_deployment_users_serialize( skip=skip, limit=limit, + search=search, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -438,6 +712,7 @@ def admin_list_deployment_users_without_preload_content( self, skip: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Number of records to skip")] = None, limit: Annotated[Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]], Field(description="Maximum number of records to return")] = None, + search: Annotated[Optional[Annotated[str, Field(strict=True, max_length=200)]], Field(description="Narrow to accounts whose name or email contains this text, case-insensitively.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -453,12 +728,14 @@ def admin_list_deployment_users_without_preload_content( ) -> RESTResponseType: """List Deployment Users - List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. + List every account on this deployment, with the organizations each belongs to. Deployment-wide, so it is not the same list as ``GET /api/v1/organizations/me/members``: that one is the caller's organization roster and drops a suspended membership, while this one carries every identity at whatever standing, including one whose memberships are all suspended. Each row also reports when the account last signed in to the dashboard, and null there means never. ``search`` narrows the page and the count together. :param skip: Number of records to skip :type skip: int :param limit: Maximum number of records to return :type limit: int + :param search: Narrow to accounts whose name or email contains this text, case-insensitively. + :type search: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -484,6 +761,7 @@ def admin_list_deployment_users_without_preload_content( _param = self._admin_list_deployment_users_serialize( skip=skip, limit=limit, + search=search, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -505,6 +783,7 @@ def _admin_list_deployment_users_serialize( self, skip, limit, + search, _request_auth, _content_type, _headers, @@ -535,6 +814,10 @@ def _admin_list_deployment_users_serialize( _query_params.append(('limit', limit)) + if search is not None: + + _query_params.append(('search', search)) + # process the header parameters # process the form parameters # process the body parameter diff --git a/src/otari/_client/api/aliases_api.py b/src/otari/_client/api/aliases_api.py index 623a1201..9c27bec0 100644 --- a/src/otari/_client/api/aliases_api.py +++ b/src/otari/_client/api/aliases_api.py @@ -624,7 +624,7 @@ def _aliases_delete_organization_alias_serialize( @validate_call def aliases_list_aliases( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -640,9 +640,9 @@ def aliases_list_aliases( ) -> List[AliasResponse]: """List Aliases - List every alias in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every alias in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace. + :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -692,7 +692,7 @@ def aliases_list_aliases( @validate_call def aliases_list_aliases_with_http_info( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -708,9 +708,9 @@ def aliases_list_aliases_with_http_info( ) -> ApiResponse[List[AliasResponse]]: """List Aliases - List every alias in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every alias in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace. + :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -760,7 +760,7 @@ def aliases_list_aliases_with_http_info( @validate_call def aliases_list_aliases_without_preload_content( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -776,9 +776,9 @@ def aliases_list_aliases_without_preload_content( ) -> RESTResponseType: """List Aliases - List every alias in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every alias in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace. + :param workspace_id: Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit to list the stored entries of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request diff --git a/src/otari/_client/api/auth_api.py b/src/otari/_client/api/auth_api.py index a4a93553..efd3bd74 100644 --- a/src/otari/_client/api/auth_api.py +++ b/src/otari/_client/api/auth_api.py @@ -23,6 +23,8 @@ from otari._client.models.authorize_response import AuthorizeResponse from otari._client.models.caller_identity_public import CallerIdentityPublic from otari._client.models.create_session_request import CreateSessionRequest +from otari._client.models.mailed_link_request import MailedLinkRequest +from otari._client.models.mailed_link_status_response import MailedLinkStatusResponse from otari._client.models.o_auth_callback_request import OAuthCallbackRequest from otari._client.models.o_auth_session_response import OAuthSessionResponse from otari._client.models.passkey_session_response import PasskeySessionResponse @@ -866,7 +868,7 @@ def auth_callback( ) -> OAuthSessionResponse: """Callback - Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. + Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. A sign-in that created the account, or is the first way in to one, is reported to ``GrowthSignalPort`` as a signup once it has committed. Where the deployment publishes terms, that sign-in is refused with ``terms_not_accepted`` unless the body carries ``terms_accepted``, and nothing it would have created is kept. :param provider: Which OAuth provider to sign in with. (required) :type provider: str @@ -938,7 +940,7 @@ def auth_callback_with_http_info( ) -> ApiResponse[OAuthSessionResponse]: """Callback - Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. + Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. A sign-in that created the account, or is the first way in to one, is reported to ``GrowthSignalPort`` as a signup once it has committed. Where the deployment publishes terms, that sign-in is refused with ``terms_not_accepted`` unless the body carries ``terms_accepted``, and nothing it would have created is kept. :param provider: Which OAuth provider to sign in with. (required) :type provider: str @@ -1010,7 +1012,7 @@ def auth_callback_without_preload_content( ) -> RESTResponseType: """Callback - Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. + Exchange an authorization code and set the HttpOnly session cookie. The session is bound to the identity the provider's account resolves to, exactly as a password sign-in binds one to the identity that authenticated, so every request it later authenticates resolves the same caller. A refusal is counted like the other sign-in failures (``record_auth_failure``) and rendered by the tenancy error handler. Like the passkey route there is no separate post-failure throttle: this route is throttled unconditionally on the way in, because there is no legitimate caller here whose correct credential must never be blocked. An authorization code is single-use and minted by a redirect, not something a person retries by hand. **Maintenance mode freezes this the way it freezes the other two sign-ins.** The freeze is on starting a session, not on a credential, so an OAuth sign-in has to answer to it or the switch is bypassable by anybody holding a Google account. Refused before the exchange, so a frozen deployment makes no outbound call, spends nobody's authorization code, and counts no auth failure: nobody failed to authenticate, the gateway declined to try. A sign-in that created the account, or is the first way in to one, is reported to ``GrowthSignalPort`` as a signup once it has committed. Where the deployment publishes terms, that sign-in is refused with ``terms_not_accepted`` unless the body carries ``terms_accepted``, and nothing it would have created is kept. :param provider: Which OAuth provider to sign in with. (required) :type provider: str @@ -1156,7 +1158,7 @@ def auth_confirm_reset( ) -> None: """Confirm Reset - Complete a password reset. Single-use: the token stops working after this. + Complete a password reset, or choose a first password. Single-use: the token stops working after this. Not throttled with the address-bearing routes, for the reason the verification route gives: the token is the proof. :param reset_password_request: (required) :type reset_password_request: ResetPasswordRequest @@ -1224,7 +1226,7 @@ def auth_confirm_reset_with_http_info( ) -> ApiResponse[None]: """Confirm Reset - Complete a password reset. Single-use: the token stops working after this. + Complete a password reset, or choose a first password. Single-use: the token stops working after this. Not throttled with the address-bearing routes, for the reason the verification route gives: the token is the proof. :param reset_password_request: (required) :type reset_password_request: ResetPasswordRequest @@ -1292,7 +1294,7 @@ def auth_confirm_reset_without_preload_content( ) -> RESTResponseType: """Confirm Reset - Complete a password reset. Single-use: the token stops working after this. + Complete a password reset, or choose a first password. Single-use: the token stops working after this. Not throttled with the address-bearing routes, for the reason the verification route gives: the token is the proof. :param reset_password_request: (required) :type reset_password_request: ResetPasswordRequest @@ -2192,6 +2194,253 @@ def _auth_delete_session_serialize( + @validate_call + def auth_get_own_profile( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> CallerIdentityPublic: + """Get Own Profile + + Report who the caller is, whether or not they belong to an organization. The same shape ``GET /api/v1/organizations/me`` carries as ``caller``, for an identity that context cannot describe because it has no active membership. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_get_own_profile_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CallerIdentityPublic", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def auth_get_own_profile_with_http_info( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[CallerIdentityPublic]: + """Get Own Profile + + Report who the caller is, whether or not they belong to an organization. The same shape ``GET /api/v1/organizations/me`` carries as ``caller``, for an identity that context cannot describe because it has no active membership. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_get_own_profile_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CallerIdentityPublic", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def auth_get_own_profile_without_preload_content( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get Own Profile + + Report who the caller is, whether or not they belong to an organization. The same shape ``GET /api/v1/organizations/me`` carries as ``caller``, for an identity that context cannot describe because it has no active membership. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_get_own_profile_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CallerIdentityPublic", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _auth_get_own_profile_serialize( + self, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/auth/profile', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def auth_list_passkeys( self, @@ -3828,7 +4077,7 @@ def auth_set_dashboard_password( ) -> PasswordResponse: """Set Dashboard Password - Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. + Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. With the master key the caller is the deployment's operator, so an ``email`` sent then is the operator's own sign-in address: on an unclaimed deployment it claims the deployment with that address. This never sets another account's password; an address another account holds is refused with 409. To help a member who forgot their password, send them a link with ``POST /api/v1/admin/users/{user_id}/password-link``. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. :param set_password_request: (required) :type set_password_request: SetPasswordRequest @@ -3896,7 +4145,7 @@ def auth_set_dashboard_password_with_http_info( ) -> ApiResponse[PasswordResponse]: """Set Dashboard Password - Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. + Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. With the master key the caller is the deployment's operator, so an ``email`` sent then is the operator's own sign-in address: on an unclaimed deployment it claims the deployment with that address. This never sets another account's password; an address another account holds is refused with 409. To help a member who forgot their password, send them a link with ``POST /api/v1/admin/users/{user_id}/password-link``. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. :param set_password_request: (required) :type set_password_request: SetPasswordRequest @@ -3964,7 +4213,7 @@ def auth_set_dashboard_password_without_preload_content( ) -> RESTResponseType: """Set Dashboard Password - Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. + Set or change the password the caller signs in to the dashboard with. Always the caller's own identity. Supply ``email`` when it has no sign-in address yet, which is the state first boot leaves the operator in, and ``current_password`` when it already has a password and the request is authenticated by the session cookie. The master key in a header is what excuses ``current_password``, which is how a forgotten password is recovered; it does not excuse ``email``, because an identity with no address has nothing to sign in with whoever is asking. The operator setting a password for the first time retires master-key sign-in on this deployment. With the master key the caller is the deployment's operator, so an ``email`` sent then is the operator's own sign-in address: on an unclaimed deployment it claims the deployment with that address. This never sets another account's password; an address another account holds is refused with 409. To help a member who forgot their password, send them a link with ``POST /api/v1/admin/users/{user_id}/password-link``. Every other session this identity holds ends, the caller's own excepted, so a cookie stolen before the change does not outlive it. :param set_password_request: (required) :type set_password_request: SetPasswordRequest @@ -4106,7 +4355,7 @@ def auth_signup( ) -> SignupResponse: """Signup - Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. + Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. Refused with a 400 where the deployment publishes terms and ``terms_accepted`` is not set, whatever the address. :param signup_request: (required) :type signup_request: SignupRequest @@ -4174,7 +4423,7 @@ def auth_signup_with_http_info( ) -> ApiResponse[SignupResponse]: """Signup - Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. + Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. Refused with a 400 where the deployment publishes terms and ``terms_accepted`` is not set, whatever the address. :param signup_request: (required) :type signup_request: SignupRequest @@ -4242,7 +4491,7 @@ def auth_signup_without_preload_content( ) -> RESTResponseType: """Signup - Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. + Claim a roster identity, register a new one, or do nothing: the response never says which. Which of the three this deployment will do is ``open_signup``, published in the bootstrap so the page can say so before anyone types an address. No session is minted. A newly claimed or registered identity is hard-blocked from signing in until it verifies, so there is nothing yet to sign it into. Refused with a 400 where the deployment publishes terms and ``terms_accepted`` is not set, whatever the address. :param signup_request: (required) :type signup_request: SignupRequest @@ -4641,6 +4890,562 @@ def _auth_update_own_profile_serialize( + @validate_call + def auth_validate_reset_link( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> MailedLinkStatusResponse: + """Validate Reset Link + + Say whether a password reset link can still be used, without using it. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_reset_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def auth_validate_reset_link_with_http_info( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[MailedLinkStatusResponse]: + """Validate Reset Link + + Say whether a password reset link can still be used, without using it. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_reset_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def auth_validate_reset_link_without_preload_content( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Validate Reset Link + + Say whether a password reset link can still be used, without using it. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_reset_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _auth_validate_reset_link_serialize( + self, + mailed_link_request, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if mailed_link_request is not None: + _body_params = mailed_link_request + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/api/v1/auth/password/reset/validate', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def auth_validate_verification_link( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> MailedLinkStatusResponse: + """Validate Verification Link + + Say whether an email verification link can still be used, without using it. Verifying still needs the password chosen at signup, which this does not check. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_verification_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def auth_validate_verification_link_with_http_info( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[MailedLinkStatusResponse]: + """Validate Verification Link + + Say whether an email verification link can still be used, without using it. Verifying still needs the password chosen at signup, which this does not check. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_verification_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def auth_validate_verification_link_without_preload_content( + self, + mailed_link_request: MailedLinkRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Validate Verification Link + + Say whether an email verification link can still be used, without using it. Verifying still needs the password chosen at signup, which this does not check. + + :param mailed_link_request: (required) + :type mailed_link_request: MailedLinkRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._auth_validate_verification_link_serialize( + mailed_link_request=mailed_link_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "MailedLinkStatusResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _auth_validate_verification_link_serialize( + self, + mailed_link_request, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if mailed_link_request is not None: + _body_params = mailed_link_request + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/api/v1/auth/verify-email/validate', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def auth_verify_email_route( self, @@ -4660,7 +5465,7 @@ def auth_verify_email_route( ) -> VerifyEmailResponse: """Verify Email Route - Confirm an address from its verification link, lifting the sign-in gate. + Confirm an address from its verification link and the password chosen at signup, lifting the sign-in gate. One refusal for a link that is unknown, expired or spent and for a password that does not match, and a refusal consumes nothing. Refusals are counted per client IP and answer 429 once over the limit, so a held link cannot be used to guess its password; a verification that succeeds is never counted. :param verify_email_request: (required) :type verify_email_request: VerifyEmailRequest @@ -4728,7 +5533,7 @@ def auth_verify_email_route_with_http_info( ) -> ApiResponse[VerifyEmailResponse]: """Verify Email Route - Confirm an address from its verification link, lifting the sign-in gate. + Confirm an address from its verification link and the password chosen at signup, lifting the sign-in gate. One refusal for a link that is unknown, expired or spent and for a password that does not match, and a refusal consumes nothing. Refusals are counted per client IP and answer 429 once over the limit, so a held link cannot be used to guess its password; a verification that succeeds is never counted. :param verify_email_request: (required) :type verify_email_request: VerifyEmailRequest @@ -4796,7 +5601,7 @@ def auth_verify_email_route_without_preload_content( ) -> RESTResponseType: """Verify Email Route - Confirm an address from its verification link, lifting the sign-in gate. + Confirm an address from its verification link and the password chosen at signup, lifting the sign-in gate. One refusal for a link that is unknown, expired or spent and for a password that does not match, and a refusal consumes nothing. Refusals are counted per client IP and answer 429 once over the limit, so a held link cannot be used to guess its password; a verification that succeeds is never counted. :param verify_email_request: (required) :type verify_email_request: VerifyEmailRequest diff --git a/src/otari/_client/api/budgets_api.py b/src/otari/_client/api/budgets_api.py index 4dc52f1d..5edf7742 100644 --- a/src/otari/_client/api/budgets_api.py +++ b/src/otari/_client/api/budgets_api.py @@ -1168,7 +1168,7 @@ def budgets_list_budgets( ) -> List[BudgetResponse]: """List Budgets - List all budgets with pagination. + List the deployment's budgets and the caller's organization's, with pagination. :param skip: :type skip: int @@ -1240,7 +1240,7 @@ def budgets_list_budgets_with_http_info( ) -> ApiResponse[List[BudgetResponse]]: """List Budgets - List all budgets with pagination. + List the deployment's budgets and the caller's organization's, with pagination. :param skip: :type skip: int @@ -1312,7 +1312,7 @@ def budgets_list_budgets_without_preload_content( ) -> RESTResponseType: """List Budgets - List all budgets with pagination. + List the deployment's budgets and the caller's organization's, with pagination. :param skip: :type skip: int diff --git a/src/otari/_client/api/catalog_api.py b/src/otari/_client/api/catalog_api.py index 489b3c70..c68ae931 100644 --- a/src/otari/_client/api/catalog_api.py +++ b/src/otari/_client/api/catalog_api.py @@ -341,7 +341,7 @@ def catalog_list_catalog( ) -> CatalogResponse: """List Catalog - The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the genai-prices default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. + The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the models.dev default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. :param at_context: Compare prices for a request of this many input tokens: each model's minimum is taken from the pricing tier that request would settle at. Omitted, the base rates compare. :type at_context: int @@ -473,7 +473,7 @@ def catalog_list_catalog_with_http_info( ) -> ApiResponse[CatalogResponse]: """List Catalog - The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the genai-prices default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. + The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the models.dev default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. :param at_context: Compare prices for a request of this many input tokens: each model's minimum is taken from the pricing tier that request would settle at. Omitted, the base rates compare. :type at_context: int @@ -605,7 +605,7 @@ def catalog_list_catalog_without_preload_content( ) -> RESTResponseType: """List Catalog - The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the genai-prices default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. + The models this caller may use, one entry each however many providers serve it. Prices are the caller's: an organization's override where one applies, else the deployment's row, else the models.dev default. Aliases and routing policies are not models and are not listed; see Routing. A visitor, where the catalog is public, sees the configured instances and the hosted models at the deployment's rates, and nothing that belongs to a tenant. :param at_context: Compare prices for a request of this many input tokens: each model's minimum is taken from the pricing tier that request would settle at. Omitted, the base rates compare. :type at_context: int diff --git a/src/otari/_client/api/end_users_api.py b/src/otari/_client/api/end_users_api.py new file mode 100644 index 00000000..9b7a4d66 --- /dev/null +++ b/src/otari/_client/api/end_users_api.py @@ -0,0 +1,2087 @@ +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import warnings +from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt +from typing import Any, Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated + +from pydantic import Field, StrictBool, StrictStr +from typing import List, Optional +from typing_extensions import Annotated +from otari._client.models.end_user_budget_public import EndUserBudgetPublic +from otari._client.models.end_user_public import EndUserPublic +from otari._client.models.end_user_put import EndUserPut +from otari._client.models.end_user_update import EndUserUpdate + +from otari._client.api_client import ApiClient, RequestSerialized +from otari._client.api_response import ApiResponse +from otari._client.rest import RESTResponseType + + +class EndUsersApi: + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, api_client=None) -> None: + if api_client is None: + api_client = ApiClient.get_default() + self.api_client = api_client + + + @validate_call + def end_users_get_end_user( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Get End User + + Get an end user of the calling service key by the id the service names it by. Requires a service key. An id no end user of the key's user goes by answers 404. An id with a '.' or '..' segment is refused with 400; ``GET /end-users?external_id=`` reads any end user. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_get_end_user_serialize( + external_id=external_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_get_end_user_with_http_info( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Get End User + + Get an end user of the calling service key by the id the service names it by. Requires a service key. An id no end user of the key's user goes by answers 404. An id with a '.' or '..' segment is refused with 400; ``GET /end-users?external_id=`` reads any end user. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_get_end_user_serialize( + external_id=external_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_get_end_user_without_preload_content( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get End User + + Get an end user of the calling service key by the id the service names it by. Requires a service key. An id no end user of the key's user goes by answers 404. An id with a '.' or '..' segment is refused with 400; ``GET /end-users?external_id=`` reads any end user. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_get_end_user_serialize( + external_id=external_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_get_end_user_serialize( + self, + external_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if external_id is not None: + _path_params['external_id'] = external_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/end-users/{external_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_list_end_user_budgets( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> List[EndUserBudgetPublic]: + """List End User Budgets + + List the budgets the calling service key may put its end users on, with how many end users each holds. Requires a service key. The counts cover the end users of the key's user, blocked ones included and deleted ones not. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_user_budgets_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserBudgetPublic]", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_list_end_user_budgets_with_http_info( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[List[EndUserBudgetPublic]]: + """List End User Budgets + + List the budgets the calling service key may put its end users on, with how many end users each holds. Requires a service key. The counts cover the end users of the key's user, blocked ones included and deleted ones not. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_user_budgets_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserBudgetPublic]", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_list_end_user_budgets_without_preload_content( + self, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List End User Budgets + + List the budgets the calling service key may put its end users on, with how many end users each holds. Requires a service key. The counts cover the end users of the key's user, blocked ones included and deleted ones not. + + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_user_budgets_serialize( + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserBudgetPublic]", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_list_end_user_budgets_serialize( + self, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/end-user-budgets', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_list_end_users( + self, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[Annotated[str, Field(min_length=1, strict=True)]], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> List[EndUserPublic]: + """List End Users + + List the end users of the calling service key, oldest first. Requires a service key. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + + :param skip: + :type skip: int + :param limit: + :type limit: int + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_users_serialize( + skip=skip, + limit=limit, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserPublic]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_list_end_users_with_http_info( + self, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[Annotated[str, Field(min_length=1, strict=True)]], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[List[EndUserPublic]]: + """List End Users + + List the end users of the calling service key, oldest first. Requires a service key. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + + :param skip: + :type skip: int + :param limit: + :type limit: int + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_users_serialize( + skip=skip, + limit=limit, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserPublic]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_list_end_users_without_preload_content( + self, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[Annotated[str, Field(min_length=1, strict=True)]], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List End Users + + List the end users of the calling service key, oldest first. Requires a service key. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + + :param skip: + :type skip: int + :param limit: + :type limit: int + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_list_end_users_serialize( + skip=skip, + limit=limit, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserPublic]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_list_end_users_serialize( + self, + skip, + limit, + budget_id, + blocked, + external_id, + include_total, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if skip is not None: + + _query_params.append(('skip', skip)) + + if limit is not None: + + _query_params.append(('limit', limit)) + + if budget_id is not None: + + _query_params.append(('budget_id', budget_id)) + + if blocked is not None: + + _query_params.append(('blocked', blocked)) + + if external_id is not None: + + _query_params.append(('external_id', external_id)) + + if include_total is not None: + + _query_params.append(('include_total', include_total)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/end-users', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_put_end_user( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Put End User + + Put an end user of the calling service key on a budget from the key's list, creating it if needed. Requires a service key. Answers 201 when the end user was created. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_put_end_user_with_http_info( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Put End User + + Put an end user of the calling service key on a budget from the key's list, creating it if needed. Requires a service key. Answers 201 when the end user was created. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_put_end_user_without_preload_content( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Put End User + + Put an end user of the calling service key on a budget from the key's list, creating it if needed. Requires a service key. Answers 201 when the end user was created. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_put_end_user_serialize( + self, + external_id, + end_user_put, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if external_id is not None: + _path_params['external_id'] = external_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if end_user_put is not None: + _body_params = end_user_put + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='PUT', + resource_path='/api/v1/end-users/{external_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_put_end_user_by_query( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Put End User By Query + + Put the end user named by ``external_id`` on a budget from the key's list, creating it if needed. The same as ``PUT /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_by_query_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_put_end_user_by_query_with_http_info( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Put End User By Query + + Put the end user named by ``external_id`` on a budget from the key's list, creating it if needed. The same as ``PUT /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_by_query_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_put_end_user_by_query_without_preload_content( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Put End User By Query + + Put the end user named by ``external_id`` on a budget from the key's list, creating it if needed. The same as ``PUT /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_put_end_user_by_query_serialize( + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_put_end_user_by_query_serialize( + self, + external_id, + end_user_put, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if external_id is not None: + + _query_params.append(('external_id', external_id)) + + # process the header parameters + # process the form parameters + # process the body parameter + if end_user_put is not None: + _body_params = end_user_put + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='PUT', + resource_path='/api/v1/end-users', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_update_end_user( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Update End User + + Block, unblock or move an end user of the calling service key. Requires a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far. The budget must be on the key's ``end_user_budget_ids``, or the move is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PATCH /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_update_end_user_with_http_info( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Update End User + + Block, unblock or move an end user of the calling service key. Requires a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far. The budget must be on the key's ``end_user_budget_ids``, or the move is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PATCH /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_update_end_user_without_preload_content( + self, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Update End User + + Block, unblock or move an end user of the calling service key. Requires a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far. The budget must be on the key's ``end_user_budget_ids``, or the move is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PATCH /end-users?external_id=`` takes any id. + + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_update_end_user_serialize( + self, + external_id, + end_user_update, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if external_id is not None: + _path_params['external_id'] = external_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if end_user_update is not None: + _body_params = end_user_update + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='PATCH', + resource_path='/api/v1/end-users/{external_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def end_users_update_end_user_by_query( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Update End User By Query + + Block, unblock or move the end user named by ``external_id``. The same as ``PATCH /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_by_query_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def end_users_update_end_user_by_query_with_http_info( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Update End User By Query + + Block, unblock or move the end user named by ``external_id``. The same as ``PATCH /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_by_query_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def end_users_update_end_user_by_query_without_preload_content( + self, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_update: EndUserUpdate, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Update End User By Query + + Block, unblock or move the end user named by ``external_id``. The same as ``PATCH /end-users/{external_id}``, for any id, one containing '/' included. + + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._end_users_update_end_user_by_query_serialize( + external_id=external_id, + end_user_update=end_user_update, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _end_users_update_end_user_by_query_serialize( + self, + external_id, + end_user_update, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if external_id is not None: + + _query_params.append(('external_id', external_id)) + + # process the header parameters + # process the form parameters + # process the body parameter + if end_user_update is not None: + _body_params = end_user_update + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='PATCH', + resource_path='/api/v1/end-users', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + diff --git a/src/otari/_client/api/invitations_api.py b/src/otari/_client/api/invitations_api.py index 89083ed7..ea62ef3d 100644 --- a/src/otari/_client/api/invitations_api.py +++ b/src/otari/_client/api/invitations_api.py @@ -57,7 +57,7 @@ def invitations_accept_invitation( ) -> AcceptInvitationResultPublic: """Accept Invitation - Accept a pending invitation, resolving it to an active membership and optionally setting a first password. + Accept a pending invitation, resolving it to an active membership and optionally setting a first password. Setting a first password makes the account usable for the first time, so it is reported to ``GrowthSignalPort`` as a signup. :param accept_invitation_request: (required) :type accept_invitation_request: AcceptInvitationRequest @@ -125,7 +125,7 @@ def invitations_accept_invitation_with_http_info( ) -> ApiResponse[AcceptInvitationResultPublic]: """Accept Invitation - Accept a pending invitation, resolving it to an active membership and optionally setting a first password. + Accept a pending invitation, resolving it to an active membership and optionally setting a first password. Setting a first password makes the account usable for the first time, so it is reported to ``GrowthSignalPort`` as a signup. :param accept_invitation_request: (required) :type accept_invitation_request: AcceptInvitationRequest @@ -193,7 +193,7 @@ def invitations_accept_invitation_without_preload_content( ) -> RESTResponseType: """Accept Invitation - Accept a pending invitation, resolving it to an active membership and optionally setting a first password. + Accept a pending invitation, resolving it to an active membership and optionally setting a first password. Setting a first password makes the account usable for the first time, so it is reported to ``GrowthSignalPort`` as a signup. :param accept_invitation_request: (required) :type accept_invitation_request: AcceptInvitationRequest diff --git a/src/otari/_client/api/keys_api.py b/src/otari/_client/api/keys_api.py index ae90f041..8332e024 100644 --- a/src/otari/_client/api/keys_api.py +++ b/src/otari/_client/api/keys_api.py @@ -15,7 +15,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import Field, StrictStr +from pydantic import Field, StrictBool, StrictStr from typing import List, Optional from typing_extensions import Annotated from uuid import UUID @@ -608,7 +608,7 @@ def keys_get_end_user( ) -> EndUserPublic: """Get End User - Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. + Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. An id with a '.' or '..' segment is refused with 400; ``GET /keys/{key_id}/end-users?external_id=`` reads any end user. :param key_id: (required) :type key_id: str @@ -680,7 +680,7 @@ def keys_get_end_user_with_http_info( ) -> ApiResponse[EndUserPublic]: """Get End User - Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. + Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. An id with a '.' or '..' segment is refused with 400; ``GET /keys/{key_id}/end-users?external_id=`` reads any end user. :param key_id: (required) :type key_id: str @@ -752,7 +752,7 @@ def keys_get_end_user_without_preload_content( ) -> RESTResponseType: """Get End User - Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. + Get an end user of a service key by the id the service names it by. End users belong to the key's user, so every service key of one user reaches the same end users. An id with a '.' or '..' segment is refused with 400; ``GET /keys/{key_id}/end-users?external_id=`` reads any end user. :param key_id: (required) :type key_id: str @@ -1134,11 +1134,15 @@ def _keys_get_key_serialize( @validate_call - def keys_list_keys( + def keys_list_end_users( self, + key_id: StrictStr, skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, - workspace_id: Annotated[Optional[UUID], Field(description="Only keys in this workspace.")] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1151,17 +1155,25 @@ def keys_list_keys( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> List[KeyInfo]: - """List Keys + ) -> List[EndUserPublic]: + """List End Users - List the API keys in the caller's organization. Requires master key authentication. An unset ``workspace_id`` lists every key in that organization; naming a workspace in another one lists nothing rather than refusing, so the filter reports no more than the unfiltered read does. + List the end users of a service key, oldest first. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + :param key_id: (required) + :type key_id: str :param skip: :type skip: int :param limit: :type limit: int - :param workspace_id: Only keys in this workspace. - :type workspace_id: UUID + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1184,10 +1196,14 @@ def keys_list_keys( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_list_keys_serialize( + _param = self._keys_list_end_users_serialize( + key_id=key_id, skip=skip, limit=limit, - workspace_id=workspace_id, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1195,7 +1211,7 @@ def keys_list_keys( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[KeyInfo]", + '200': "List[EndUserPublic]", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1210,7 +1226,282 @@ def keys_list_keys( @validate_call - def keys_list_keys_with_http_info( + def keys_list_end_users_with_http_info( + self, + key_id: StrictStr, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[List[EndUserPublic]]: + """List End Users + + List the end users of a service key, oldest first. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + + :param key_id: (required) + :type key_id: str + :param skip: + :type skip: int + :param limit: + :type limit: int + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_list_end_users_serialize( + key_id=key_id, + skip=skip, + limit=limit, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserPublic]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def keys_list_end_users_without_preload_content( + self, + key_id: StrictStr, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + budget_id: Annotated[Optional[StrictStr], Field(description="Only end users on this budget.")] = None, + blocked: Annotated[Optional[StrictBool], Field(description="Only end users that are, or are not, blocked.")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Only the end user the service names with this `user` value: zero or one.")] = None, + include_total: Annotated[Optional[StrictBool], Field(description="Also count every matching end user, in the Otari-Total-Count response header.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List End Users + + List the end users of a service key, oldest first. End users belong to the key's user, so every service key of one user lists the same end users. A deleted end user is not listed. ``external_id`` reads one end user by any id, one containing '/' included, as a list of zero or one. + + :param key_id: (required) + :type key_id: str + :param skip: + :type skip: int + :param limit: + :type limit: int + :param budget_id: Only end users on this budget. + :type budget_id: str + :param blocked: Only end users that are, or are not, blocked. + :type blocked: bool + :param external_id: Only the end user the service names with this `user` value: zero or one. + :type external_id: str + :param include_total: Also count every matching end user, in the Otari-Total-Count response header. + :type include_total: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_list_end_users_serialize( + key_id=key_id, + skip=skip, + limit=limit, + budget_id=budget_id, + blocked=blocked, + external_id=external_id, + include_total=include_total, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[EndUserPublic]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _keys_list_end_users_serialize( + self, + key_id, + skip, + limit, + budget_id, + blocked, + external_id, + include_total, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if key_id is not None: + _path_params['key_id'] = key_id + # process the query parameters + if skip is not None: + + _query_params.append(('skip', skip)) + + if limit is not None: + + _query_params.append(('limit', limit)) + + if budget_id is not None: + + _query_params.append(('budget_id', budget_id)) + + if blocked is not None: + + _query_params.append(('blocked', blocked)) + + if external_id is not None: + + _query_params.append(('external_id', external_id)) + + if include_total is not None: + + _query_params.append(('include_total', include_total)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/keys/{key_id}/end-users', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def keys_list_keys( self, skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, @@ -1227,7 +1518,7 @@ def keys_list_keys_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[List[KeyInfo]]: + ) -> List[KeyInfo]: """List Keys List the API keys in the caller's organization. Requires master key authentication. An unset ``workspace_id`` lists every key in that organization; naming a workspace in another one lists nothing rather than refusing, so the filter reports no more than the unfiltered read does. @@ -1271,7 +1562,697 @@ def keys_list_keys_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[KeyInfo]", + '200': "List[KeyInfo]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def keys_list_keys_with_http_info( + self, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only keys in this workspace.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[List[KeyInfo]]: + """List Keys + + List the API keys in the caller's organization. Requires master key authentication. An unset ``workspace_id`` lists every key in that organization; naming a workspace in another one lists nothing rather than refusing, so the filter reports no more than the unfiltered read does. + + :param skip: + :type skip: int + :param limit: + :type limit: int + :param workspace_id: Only keys in this workspace. + :type workspace_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_list_keys_serialize( + skip=skip, + limit=limit, + workspace_id=workspace_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[KeyInfo]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def keys_list_keys_without_preload_content( + self, + skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, + limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only keys in this workspace.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List Keys + + List the API keys in the caller's organization. Requires master key authentication. An unset ``workspace_id`` lists every key in that organization; naming a workspace in another one lists nothing rather than refusing, so the filter reports no more than the unfiltered read does. + + :param skip: + :type skip: int + :param limit: + :type limit: int + :param workspace_id: Only keys in this workspace. + :type workspace_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_list_keys_serialize( + skip=skip, + limit=limit, + workspace_id=workspace_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[KeyInfo]", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _keys_list_keys_serialize( + self, + skip, + limit, + workspace_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if skip is not None: + + _query_params.append(('skip', skip)) + + if limit is not None: + + _query_params.append(('limit', limit)) + + if workspace_id is not None: + + _query_params.append(('workspace_id', workspace_id)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/keys', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def keys_put_end_user( + self, + key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Put End User + + Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /keys/{key_id}/end-users?external_id=`` takes any id. + + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_put_end_user_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def keys_put_end_user_with_http_info( + self, + key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Put End User + + Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /keys/{key_id}/end-users?external_id=`` takes any id. + + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_put_end_user_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def keys_put_end_user_without_preload_content( + self, + key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Put End User + + Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. An id with a '.' or '..' segment is refused with 400; ``PUT /keys/{key_id}/end-users?external_id=`` takes any id. + + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_put_end_user_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _keys_put_end_user_serialize( + self, + key_id, + external_id, + end_user_put, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if key_id is not None: + _path_params['key_id'] = key_id + if external_id is not None: + _path_params['external_id'] = external_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if end_user_put is not None: + _body_params = end_user_put + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='PUT', + resource_path='/api/v1/keys/{key_id}/end-users/{external_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def keys_put_end_user_by_query( + self, + key_id: StrictStr, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> EndUserPublic: + """Put End User By Query + + Put the end user named by ``external_id`` on a budget from the key's list, creating it if it does not exist yet. The same as ``PUT /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. + + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_put_end_user_by_query_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def keys_put_end_user_by_query_with_http_info( + self, + key_id: StrictStr, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[EndUserPublic]: + """Put End User By Query + + Put the end user named by ``external_id`` on a budget from the key's list, creating it if it does not exist yet. The same as ``PUT /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. + + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._keys_put_end_user_by_query_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "EndUserPublic", + '201': "EndUserPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1286,11 +2267,11 @@ def keys_list_keys_with_http_info( @validate_call - def keys_list_keys_without_preload_content( + def keys_put_end_user_by_query_without_preload_content( self, - skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, - limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, - workspace_id: Annotated[Optional[UUID], Field(description="Only keys in this workspace.")] = None, + key_id: StrictStr, + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], + end_user_put: EndUserPut, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1304,16 +2285,16 @@ def keys_list_keys_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """List Keys + """Put End User By Query - List the API keys in the caller's organization. Requires master key authentication. An unset ``workspace_id`` lists every key in that organization; naming a workspace in another one lists nothing rather than refusing, so the filter reports no more than the unfiltered read does. + Put the end user named by ``external_id`` on a budget from the key's list, creating it if it does not exist yet. The same as ``PUT /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. - :param skip: - :type skip: int - :param limit: - :type limit: int - :param workspace_id: Only keys in this workspace. - :type workspace_id: UUID + :param key_id: (required) + :type key_id: str + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) + :type external_id: str + :param end_user_put: (required) + :type end_user_put: EndUserPut :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1336,10 +2317,10 @@ def keys_list_keys_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_list_keys_serialize( - skip=skip, - limit=limit, - workspace_id=workspace_id, + _param = self._keys_put_end_user_by_query_serialize( + key_id=key_id, + external_id=external_id, + end_user_put=end_user_put, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1347,7 +2328,8 @@ def keys_list_keys_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[KeyInfo]", + '200': "EndUserPublic", + '201': "EndUserPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1357,11 +2339,11 @@ def keys_list_keys_without_preload_content( return response_data.response - def _keys_list_keys_serialize( + def _keys_put_end_user_by_query_serialize( self, - skip, - limit, - workspace_id, + key_id, + external_id, + end_user_put, _request_auth, _content_type, _headers, @@ -1383,22 +2365,18 @@ def _keys_list_keys_serialize( _body_params: Optional[bytes] = None # process the path parameters + if key_id is not None: + _path_params['key_id'] = key_id # process the query parameters - if skip is not None: - - _query_params.append(('skip', skip)) - - if limit is not None: - - _query_params.append(('limit', limit)) - - if workspace_id is not None: + if external_id is not None: - _query_params.append(('workspace_id', workspace_id)) + _query_params.append(('external_id', external_id)) # process the header parameters # process the form parameters # process the body parameter + if end_user_put is not None: + _body_params = end_user_put # set the HTTP header `Accept` @@ -1409,6 +2387,19 @@ def _keys_list_keys_serialize( ] ) + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type # authentication setting _auth_settings: List[str] = [ @@ -1417,8 +2408,8 @@ def _keys_list_keys_serialize( ] return self.api_client.param_serialize( - method='GET', - resource_path='/api/v1/keys', + method='PUT', + resource_path='/api/v1/keys/{key_id}/end-users', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -1435,11 +2426,9 @@ def _keys_list_keys_serialize( @validate_call - def keys_put_end_user( + def keys_rotate_key( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], - end_user_put: EndUserPut, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1452,17 +2441,13 @@ def keys_put_end_user( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> EndUserPublic: - """Put End User + ) -> CreateKeyResponse: + """Rotate Key - Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. + Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) - :type external_id: str - :param end_user_put: (required) - :type end_user_put: EndUserPut :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1485,10 +2470,8 @@ def keys_put_end_user( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_put_end_user_serialize( + _param = self._keys_rotate_key_serialize( key_id=key_id, - external_id=external_id, - end_user_put=end_user_put, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1496,8 +2479,7 @@ def keys_put_end_user( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "EndUserPublic", - '201': "EndUserPublic", + '200': "CreateKeyResponse", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1512,11 +2494,9 @@ def keys_put_end_user( @validate_call - def keys_put_end_user_with_http_info( + def keys_rotate_key_with_http_info( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], - end_user_put: EndUserPut, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1529,17 +2509,13 @@ def keys_put_end_user_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[EndUserPublic]: - """Put End User + ) -> ApiResponse[CreateKeyResponse]: + """Rotate Key - Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. + Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) - :type external_id: str - :param end_user_put: (required) - :type end_user_put: EndUserPut :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1562,10 +2538,8 @@ def keys_put_end_user_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_put_end_user_serialize( + _param = self._keys_rotate_key_serialize( key_id=key_id, - external_id=external_id, - end_user_put=end_user_put, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1573,8 +2547,7 @@ def keys_put_end_user_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "EndUserPublic", - '201': "EndUserPublic", + '200': "CreateKeyResponse", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1589,11 +2562,9 @@ def keys_put_end_user_with_http_info( @validate_call - def keys_put_end_user_without_preload_content( + def keys_rotate_key_without_preload_content( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], - end_user_put: EndUserPut, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1607,16 +2578,12 @@ def keys_put_end_user_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Put End User + """Rotate Key - Put an end user of a service key on a budget from the key's list, creating it if it does not exist yet. Answers 201 when the end user was created, so one can be placed on a budget before its first request. An end user already on the budget keeps its current period, so repeating the call changes nothing. A budget that is not on the key's ``end_user_budget_ids`` is refused with 403 and ``end_user_budget_not_allowed``. + Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) - :type external_id: str - :param end_user_put: (required) - :type end_user_put: EndUserPut :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1639,10 +2606,8 @@ def keys_put_end_user_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_put_end_user_serialize( + _param = self._keys_rotate_key_serialize( key_id=key_id, - external_id=external_id, - end_user_put=end_user_put, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1650,8 +2615,7 @@ def keys_put_end_user_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "EndUserPublic", - '201': "EndUserPublic", + '200': "CreateKeyResponse", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1661,11 +2625,9 @@ def keys_put_end_user_without_preload_content( return response_data.response - def _keys_put_end_user_serialize( + def _keys_rotate_key_serialize( self, key_id, - external_id, - end_user_put, _request_auth, _content_type, _headers, @@ -1689,14 +2651,10 @@ def _keys_put_end_user_serialize( # process the path parameters if key_id is not None: _path_params['key_id'] = key_id - if external_id is not None: - _path_params['external_id'] = external_id # process the query parameters # process the header parameters # process the form parameters # process the body parameter - if end_user_put is not None: - _body_params = end_user_put # set the HTTP header `Accept` @@ -1707,19 +2665,6 @@ def _keys_put_end_user_serialize( ] ) - # set the HTTP header `Content-Type` - if _content_type: - _header_params['Content-Type'] = _content_type - else: - _default_content_type = ( - self.api_client.select_header_content_type( - [ - 'application/json' - ] - ) - ) - if _default_content_type is not None: - _header_params['Content-Type'] = _default_content_type # authentication setting _auth_settings: List[str] = [ @@ -1728,8 +2673,8 @@ def _keys_put_end_user_serialize( ] return self.api_client.param_serialize( - method='PUT', - resource_path='/api/v1/keys/{key_id}/end-users/{external_id}', + method='POST', + resource_path='/api/v1/keys/{key_id}/rotate', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -1746,9 +2691,11 @@ def _keys_put_end_user_serialize( @validate_call - def keys_rotate_key( + def keys_update_end_user( self, key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1761,13 +2708,17 @@ def keys_rotate_key( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> CreateKeyResponse: - """Rotate Key + ) -> EndUserPublic: + """Update End User - Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. + Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. An id with a '.' or '..' segment is refused with 400; ``PATCH /keys/{key_id}/end-users?external_id=`` takes any id. :param key_id: (required) :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1790,8 +2741,10 @@ def keys_rotate_key( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_rotate_key_serialize( + _param = self._keys_update_end_user_serialize( key_id=key_id, + external_id=external_id, + end_user_update=end_user_update, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1799,7 +2752,7 @@ def keys_rotate_key( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '200': "EndUserPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1814,9 +2767,11 @@ def keys_rotate_key( @validate_call - def keys_rotate_key_with_http_info( + def keys_update_end_user_with_http_info( self, key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1829,13 +2784,17 @@ def keys_rotate_key_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[CreateKeyResponse]: - """Rotate Key + ) -> ApiResponse[EndUserPublic]: + """Update End User - Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. + Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. An id with a '.' or '..' segment is refused with 400; ``PATCH /keys/{key_id}/end-users?external_id=`` takes any id. :param key_id: (required) :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1858,8 +2817,10 @@ def keys_rotate_key_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_rotate_key_serialize( + _param = self._keys_update_end_user_serialize( key_id=key_id, + external_id=external_id, + end_user_update=end_user_update, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1867,7 +2828,7 @@ def keys_rotate_key_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '200': "EndUserPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1882,9 +2843,11 @@ def keys_rotate_key_with_http_info( @validate_call - def keys_rotate_key_without_preload_content( + def keys_update_end_user_without_preload_content( self, key_id: StrictStr, + external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + end_user_update: EndUserUpdate, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1898,12 +2861,16 @@ def keys_rotate_key_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Rotate Key + """Update End User - Rotate an API key's secret in place, within the caller's organization. Requires master key authentication. Generates a new secret for the same key row (id, user, name, expiry, and metadata are preserved) and returns the new raw key once, using the same response shape as key creation. The previous secret stops authenticating immediately; there is no grace window. + Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. An id with a '.' or '..' segment is refused with 400; ``PATCH /keys/{key_id}/end-users?external_id=`` takes any id. :param key_id: (required) :type key_id: str + :param external_id: The id the service names the end user by in a request's user field (required) + :type external_id: str + :param end_user_update: (required) + :type end_user_update: EndUserUpdate :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -1926,8 +2893,10 @@ def keys_rotate_key_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_rotate_key_serialize( + _param = self._keys_update_end_user_serialize( key_id=key_id, + external_id=external_id, + end_user_update=end_user_update, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -1935,7 +2904,7 @@ def keys_rotate_key_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '200': "EndUserPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1945,9 +2914,11 @@ def keys_rotate_key_without_preload_content( return response_data.response - def _keys_rotate_key_serialize( + def _keys_update_end_user_serialize( self, key_id, + external_id, + end_user_update, _request_auth, _content_type, _headers, @@ -1971,10 +2942,14 @@ def _keys_rotate_key_serialize( # process the path parameters if key_id is not None: _path_params['key_id'] = key_id + if external_id is not None: + _path_params['external_id'] = external_id # process the query parameters # process the header parameters # process the form parameters # process the body parameter + if end_user_update is not None: + _body_params = end_user_update # set the HTTP header `Accept` @@ -1985,6 +2960,19 @@ def _keys_rotate_key_serialize( ] ) + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type # authentication setting _auth_settings: List[str] = [ @@ -1993,8 +2981,8 @@ def _keys_rotate_key_serialize( ] return self.api_client.param_serialize( - method='POST', - resource_path='/api/v1/keys/{key_id}/rotate', + method='PATCH', + resource_path='/api/v1/keys/{key_id}/end-users/{external_id}', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -2011,10 +2999,10 @@ def _keys_rotate_key_serialize( @validate_call - def keys_update_end_user( + def keys_update_end_user_by_query( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], end_user_update: EndUserUpdate, _request_timeout: Union[ None, @@ -2029,13 +3017,13 @@ def keys_update_end_user( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> EndUserPublic: - """Update End User + """Update End User By Query - Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. + Block, unblock or move the end user of a service key named by ``external_id``. The same as ``PATCH /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) :type external_id: str :param end_user_update: (required) :type end_user_update: EndUserUpdate @@ -2061,7 +3049,7 @@ def keys_update_end_user( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_update_end_user_serialize( + _param = self._keys_update_end_user_by_query_serialize( key_id=key_id, external_id=external_id, end_user_update=end_user_update, @@ -2087,10 +3075,10 @@ def keys_update_end_user( @validate_call - def keys_update_end_user_with_http_info( + def keys_update_end_user_by_query_with_http_info( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], end_user_update: EndUserUpdate, _request_timeout: Union[ None, @@ -2105,13 +3093,13 @@ def keys_update_end_user_with_http_info( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> ApiResponse[EndUserPublic]: - """Update End User + """Update End User By Query - Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. + Block, unblock or move the end user of a service key named by ``external_id``. The same as ``PATCH /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) :type external_id: str :param end_user_update: (required) :type end_user_update: EndUserUpdate @@ -2137,7 +3125,7 @@ def keys_update_end_user_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_update_end_user_serialize( + _param = self._keys_update_end_user_by_query_serialize( key_id=key_id, external_id=external_id, end_user_update=end_user_update, @@ -2163,10 +3151,10 @@ def keys_update_end_user_with_http_info( @validate_call - def keys_update_end_user_without_preload_content( + def keys_update_end_user_by_query_without_preload_content( self, key_id: StrictStr, - external_id: Annotated[StrictStr, Field(description="The id the service names the end user by in a request's user field")], + external_id: Annotated[str, Field(min_length=1, strict=True, description="The id the service names the end user by in a request's user field, any id, '/' included")], end_user_update: EndUserUpdate, _request_timeout: Union[ None, @@ -2181,13 +3169,13 @@ def keys_update_end_user_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Update End User + """Update End User By Query - Block, unblock or move an end user of a service key. A move restarts the end user's period on the new budget but keeps what it has spent and used so far, as the users API does. The budget must be on the key's ``end_user_budget_ids``. + Block, unblock or move the end user of a service key named by ``external_id``. The same as ``PATCH /keys/{key_id}/end-users/{external_id}``, for any id, one containing '/' included. :param key_id: (required) :type key_id: str - :param external_id: The id the service names the end user by in a request's user field (required) + :param external_id: The id the service names the end user by in a request's user field, any id, '/' included (required) :type external_id: str :param end_user_update: (required) :type end_user_update: EndUserUpdate @@ -2213,7 +3201,7 @@ def keys_update_end_user_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._keys_update_end_user_serialize( + _param = self._keys_update_end_user_by_query_serialize( key_id=key_id, external_id=external_id, end_user_update=end_user_update, @@ -2234,7 +3222,7 @@ def keys_update_end_user_without_preload_content( return response_data.response - def _keys_update_end_user_serialize( + def _keys_update_end_user_by_query_serialize( self, key_id, external_id, @@ -2262,9 +3250,11 @@ def _keys_update_end_user_serialize( # process the path parameters if key_id is not None: _path_params['key_id'] = key_id - if external_id is not None: - _path_params['external_id'] = external_id # process the query parameters + if external_id is not None: + + _query_params.append(('external_id', external_id)) + # process the header parameters # process the form parameters # process the body parameter @@ -2302,7 +3292,7 @@ def _keys_update_end_user_serialize( return self.api_client.param_serialize( method='PATCH', - resource_path='/api/v1/keys/{key_id}/end-users/{external_id}', + resource_path='/api/v1/keys/{key_id}/end-users', path_params=_path_params, query_params=_query_params, header_params=_header_params, diff --git a/src/otari/_client/api/models_api.py b/src/otari/_client/api/models_api.py index 20eeae54..6cf1e53d 100644 --- a/src/otari/_client/api/models_api.py +++ b/src/otari/_client/api/models_api.py @@ -839,7 +839,7 @@ def models_list_models( ) -> ModelListResponse: """List Models - List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from models.dev, or from genai-prices where models.dev has none, and the output limit from models.dev alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. + List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from the live models.dev catalog, or from the pricing snapshot where it has none, and the output limit from the live catalog alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. :param provider: Filter models by provider name :type provider: str @@ -907,7 +907,7 @@ def models_list_models_with_http_info( ) -> ApiResponse[ModelListResponse]: """List Models - List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from models.dev, or from genai-prices where models.dev has none, and the output limit from models.dev alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. + List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from the live models.dev catalog, or from the pricing snapshot where it has none, and the output limit from the live catalog alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. :param provider: Filter models by provider name :type provider: str @@ -975,7 +975,7 @@ def models_list_models_without_preload_content( ) -> RESTResponseType: """List Models - List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from models.dev, or from genai-prices where models.dev has none, and the output limit from models.dev alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. + List all available models. Returns models auto-discovered from configured providers, enriched with pricing data from the model_pricing table when available, and with each model's token limits: the context window from the live models.dev catalog, or from the pricing snapshot where it has none, and the output limit from the live catalog alone. A limit neither knows is null. Models that only exist in the pricing table are also included for backward compatibility. :param provider: Filter models by provider name :type provider: str diff --git a/src/otari/_client/api/organization_traces_api.py b/src/otari/_client/api/organization_traces_api.py index 183a9967..b1cb9543 100644 --- a/src/otari/_client/api/organization_traces_api.py +++ b/src/otari/_client/api/organization_traces_api.py @@ -24,6 +24,7 @@ from otari._client.models.trace_detail_public import TraceDetailPublic from otari._client.models.trace_list_public import TraceListPublic from otari._client.models.trace_series_public import TraceSeriesPublic +from otari._client.models.trace_summary_public import TraceSummaryPublic from otari._client.api_client import ApiClient, RequestSerialized from otari._client.api_response import ApiResponse @@ -1209,6 +1210,271 @@ def _organization_traces_list_traces_serialize( + @validate_call + def organization_traces_trace_of_request( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> TraceSummaryPublic: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organization_traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def organization_traces_trace_of_request_with_http_info( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[TraceSummaryPublic]: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organization_traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def organization_traces_trace_of_request_without_preload_content( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organization_traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _organization_traces_trace_of_request_serialize( + self, + request_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if request_id is not None: + _path_params['request_id'] = request_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/organizations/me/traces/requests/{request_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def organization_traces_trace_series( self, diff --git a/src/otari/_client/api/organization_usage_api.py b/src/otari/_client/api/organization_usage_api.py index 73cdb368..ddb8b9ab 100644 --- a/src/otari/_client/api/organization_usage_api.py +++ b/src/otari/_client/api/organization_usage_api.py @@ -78,7 +78,7 @@ def organization_usage_count_organization_usage( ) -> UsageCount: """Count Organization Usage - Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the deployment-wide ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. + Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the operator's ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. :param start_date: Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds) :type start_date: datetime @@ -210,7 +210,7 @@ def organization_usage_count_organization_usage_with_http_info( ) -> ApiResponse[UsageCount]: """Count Organization Usage - Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the deployment-wide ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. + Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the operator's ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. :param start_date: Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds) :type start_date: datetime @@ -342,7 +342,7 @@ def organization_usage_count_organization_usage_without_preload_content( ) -> RESTResponseType: """Count Organization Usage - Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the deployment-wide ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. + Total rows matching these filters, within the caller's scope. Serves the paginator's \"N of M\" beside the list above, and is scoped the same way, so the total can never describe more rows than the list will show. Unlike the operator's ``GET /api/v1/usage/count``, ``counts_toward_budget=false`` is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and this surface has none. So this total keeps matching the list beside it. :param start_date: Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds) :type start_date: datetime diff --git a/src/otari/_client/api/organizations_api.py b/src/otari/_client/api/organizations_api.py index 45530478..2e59f2f3 100644 --- a/src/otari/_client/api/organizations_api.py +++ b/src/otari/_client/api/organizations_api.py @@ -344,7 +344,7 @@ def organizations_bulk_invite_active_organization_members( ) -> BulkInviteOrganizationMembersResultPublic: """Bulk Invite Active Organization Members - Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent`` and accept link. + Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent``, and its accept link when that is false. :param bulk_invite_organization_members_request: (required) :type bulk_invite_organization_members_request: BulkInviteOrganizationMembersRequest @@ -412,7 +412,7 @@ def organizations_bulk_invite_active_organization_members_with_http_info( ) -> ApiResponse[BulkInviteOrganizationMembersResultPublic]: """Bulk Invite Active Organization Members - Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent`` and accept link. + Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent``, and its accept link when that is false. :param bulk_invite_organization_members_request: (required) :type bulk_invite_organization_members_request: BulkInviteOrganizationMembersRequest @@ -480,7 +480,7 @@ def organizations_bulk_invite_active_organization_members_without_preload_conten ) -> RESTResponseType: """Bulk Invite Active Organization Members - Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent`` and accept link. + Invite several addresses to the caller's active organization at once. Organization owners and admins only. Every address gets the same role and workspace assignments. Each one is checked as ``POST /me/member-invitations`` would check it, and an address that is refused lands in ``failed`` with the reason rather than failing the request, so the answer is 200 even when some or all were refused. Each invited entry carries its own ``mail_sent``, and its accept link when that is false. :param bulk_invite_organization_members_request: (required) :type bulk_invite_organization_members_request: BulkInviteOrganizationMembersRequest @@ -900,7 +900,7 @@ def organizations_create_active_organization_member( ) -> ActiveOrganizationMemberCreateResultPublic: """Create Active Organization Member - Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately and the response says so: this edition has no invitation to send and no way to accept one, so it answers on the ``active`` arm of the result rather than the ``invited`` one the platform uses. An address that belongs to no identity yet creates one, which carries the address as the handle a future sign-in flow will claim it by, and can do nothing until then. + Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately, with no invitation to accept and no email sent, so the person has to be told some other way. An address that belongs to no identity yet creates one, which gets in by signing up, by \"Forgot your password?\" or by a Google or GitHub sign-in; on a deployment with no mail and no provider it waits for an operator's password link, so invite it instead (``POST /me/member-invitations``), whose link can set its first password. :param active_organization_member_create_request: (required) :type active_organization_member_create_request: ActiveOrganizationMemberCreateRequest @@ -968,7 +968,7 @@ def organizations_create_active_organization_member_with_http_info( ) -> ApiResponse[ActiveOrganizationMemberCreateResultPublic]: """Create Active Organization Member - Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately and the response says so: this edition has no invitation to send and no way to accept one, so it answers on the ``active`` arm of the result rather than the ``invited`` one the platform uses. An address that belongs to no identity yet creates one, which carries the address as the handle a future sign-in flow will claim it by, and can do nothing until then. + Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately, with no invitation to accept and no email sent, so the person has to be told some other way. An address that belongs to no identity yet creates one, which gets in by signing up, by \"Forgot your password?\" or by a Google or GitHub sign-in; on a deployment with no mail and no provider it waits for an operator's password link, so invite it instead (``POST /me/member-invitations``), whose link can set its first password. :param active_organization_member_create_request: (required) :type active_organization_member_create_request: ActiveOrganizationMemberCreateRequest @@ -1036,7 +1036,7 @@ def organizations_create_active_organization_member_without_preload_content( ) -> RESTResponseType: """Create Active Organization Member - Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately and the response says so: this edition has no invitation to send and no way to accept one, so it answers on the ``active`` arm of the result rather than the ``invited`` one the platform uses. An address that belongs to no identity yet creates one, which carries the address as the handle a future sign-in flow will claim it by, and can do nothing until then. + Add a member to the caller's active organization, by email address. Organization owners and admins only. The member is active immediately, with no invitation to accept and no email sent, so the person has to be told some other way. An address that belongs to no identity yet creates one, which gets in by signing up, by \"Forgot your password?\" or by a Google or GitHub sign-in; on a deployment with no mail and no provider it waits for an operator's password link, so invite it instead (``POST /me/member-invitations``), whose link can set its first password. :param active_organization_member_create_request: (required) :type active_organization_member_create_request: ActiveOrganizationMemberCreateRequest @@ -1178,7 +1178,7 @@ def organizations_create_organization( ) -> OrganizationPublic: """Create Organization - Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. + Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. Where signup is closed, the caller must already be an active member of an organization; a caller with none is refused with a 403. :param organization_create_request: (required) :type organization_create_request: OrganizationCreateRequest @@ -1214,6 +1214,7 @@ def organizations_create_organization( _response_types_map: Dict[str, Optional[str]] = { '201': "OrganizationPublic", + '403': "OrganizationRefusal", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1246,7 +1247,7 @@ def organizations_create_organization_with_http_info( ) -> ApiResponse[OrganizationPublic]: """Create Organization - Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. + Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. Where signup is closed, the caller must already be an active member of an organization; a caller with none is refused with a 403. :param organization_create_request: (required) :type organization_create_request: OrganizationCreateRequest @@ -1282,6 +1283,7 @@ def organizations_create_organization_with_http_info( _response_types_map: Dict[str, Optional[str]] = { '201': "OrganizationPublic", + '403': "OrganizationRefusal", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -1314,7 +1316,7 @@ def organizations_create_organization_without_preload_content( ) -> RESTResponseType: """Create Organization - Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. + Create an organization with the caller as its owner. Takes a name; the slug is derived from it with a random suffix, so two organizations may share a name and a later rename does not move the slug. A default workspace is provisioned alongside, because an organization without one has nowhere to hold a key, a budget or a usage row. The caller is **not** moved into it. Switching is a separate call (``POST /me/switch``), so creating an organization does not change what the rest of the caller's session is looking at. Where signup is closed, the caller must already be an active member of an organization; a caller with none is refused with a 403. :param organization_create_request: (required) :type organization_create_request: OrganizationCreateRequest @@ -1350,6 +1352,7 @@ def organizations_create_organization_without_preload_content( _response_types_map: Dict[str, Optional[str]] = { '201': "OrganizationPublic", + '403': "OrganizationRefusal", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -2018,6 +2021,7 @@ def organizations_get_active_organization_context( _response_types_map: Dict[str, Optional[str]] = { '200': "OrganizationMembershipContextPublic", + '404': "OrganizationRefusal", } response_data = self.api_client.call_api( *_param, @@ -2081,6 +2085,7 @@ def organizations_get_active_organization_context_with_http_info( _response_types_map: Dict[str, Optional[str]] = { '200': "OrganizationMembershipContextPublic", + '404': "OrganizationRefusal", } response_data = self.api_client.call_api( *_param, @@ -2144,6 +2149,7 @@ def organizations_get_active_organization_context_without_preload_content( _response_types_map: Dict[str, Optional[str]] = { '200': "OrganizationMembershipContextPublic", + '404': "OrganizationRefusal", } response_data = self.api_client.call_api( *_param, @@ -2233,7 +2239,7 @@ def organizations_invite_active_organization_member( ) -> InviteOrganizationMemberResultPublic: """Invite Active Organization Member - Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). The response always carries the accept link, whether or not it was actually emailed (``mail_sent``), so an operator can share it themselves when mail is not configured or the send fails. + Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). When the email did not go out (``mail_sent`` is false: mail is not configured, the send failed, or the invitation mail limit was reached), the response carries the accept link so the caller can share it themselves. An address whose invitation is still pending is refused; reissue that invitation to send a new link. :param invite_organization_member_request: (required) :type invite_organization_member_request: InviteOrganizationMemberRequest @@ -2301,7 +2307,7 @@ def organizations_invite_active_organization_member_with_http_info( ) -> ApiResponse[InviteOrganizationMemberResultPublic]: """Invite Active Organization Member - Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). The response always carries the accept link, whether or not it was actually emailed (``mail_sent``), so an operator can share it themselves when mail is not configured or the send fails. + Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). When the email did not go out (``mail_sent`` is false: mail is not configured, the send failed, or the invitation mail limit was reached), the response carries the accept link so the caller can share it themselves. An address whose invitation is still pending is refused; reissue that invitation to send a new link. :param invite_organization_member_request: (required) :type invite_organization_member_request: InviteOrganizationMemberRequest @@ -2369,7 +2375,7 @@ def organizations_invite_active_organization_member_without_preload_content( ) -> RESTResponseType: """Invite Active Organization Member - Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). The response always carries the accept link, whether or not it was actually emailed (``mail_sent``), so an operator can share it themselves when mail is not configured or the send fails. + Invite an address to the caller's active organization by email. Organization owners and admins only. Unlike ``POST /me/members``, the membership lands ``invited`` rather than ``active``: it becomes active once the recipient accepts (``POST /api/v1/invitations/accept``). When the email did not go out (``mail_sent`` is false: mail is not configured, the send failed, or the invitation mail limit was reached), the response carries the accept link so the caller can share it themselves. An address whose invitation is still pending is refused; reissue that invitation to send a new link. :param invite_organization_member_request: (required) :type invite_organization_member_request: InviteOrganizationMemberRequest @@ -3608,6 +3614,271 @@ def _organizations_list_caller_pending_memberships_serialize( + @validate_call + def organizations_reissue_active_organization_member_invitation( + self, + invitation_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> InviteOrganizationMemberResultPublic: + """Reissue Active Organization Member Invitation + + Give a pending or expired invitation a new accept link. Organization owners and admins only. The old link stops working. The new one is emailed as an invitation is, and returned in ``accept_link`` when it was not, so a lost link can be recovered whether or not the deployment sends mail. + + :param invitation_id: (required) + :type invitation_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organizations_reissue_active_organization_member_invitation_serialize( + invitation_id=invitation_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "InviteOrganizationMemberResultPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def organizations_reissue_active_organization_member_invitation_with_http_info( + self, + invitation_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[InviteOrganizationMemberResultPublic]: + """Reissue Active Organization Member Invitation + + Give a pending or expired invitation a new accept link. Organization owners and admins only. The old link stops working. The new one is emailed as an invitation is, and returned in ``accept_link`` when it was not, so a lost link can be recovered whether or not the deployment sends mail. + + :param invitation_id: (required) + :type invitation_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organizations_reissue_active_organization_member_invitation_serialize( + invitation_id=invitation_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "InviteOrganizationMemberResultPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def organizations_reissue_active_organization_member_invitation_without_preload_content( + self, + invitation_id: UUID, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Reissue Active Organization Member Invitation + + Give a pending or expired invitation a new accept link. Organization owners and admins only. The old link stops working. The new one is emailed as an invitation is, and returned in ``accept_link`` when it was not, so a lost link can be recovered whether or not the deployment sends mail. + + :param invitation_id: (required) + :type invitation_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._organizations_reissue_active_organization_member_invitation_serialize( + invitation_id=invitation_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "InviteOrganizationMemberResultPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _organizations_reissue_active_organization_member_invitation_serialize( + self, + invitation_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if invitation_id is not None: + _path_params['invitation_id'] = invitation_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/api/v1/organizations/me/member-invitations/{invitation_id}/reissue', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def organizations_remove_active_organization_member( self, @@ -3892,7 +4163,7 @@ def organizations_revoke_active_organization_member_invitation( ) -> Message: """Revoke Active Organization Member Invitation - Revoke an unaccepted invitation. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. + Revoke an unaccepted invitation, pending or expired. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. :param invitation_id: (required) :type invitation_id: UUID @@ -3960,7 +4231,7 @@ def organizations_revoke_active_organization_member_invitation_with_http_info( ) -> ApiResponse[Message]: """Revoke Active Organization Member Invitation - Revoke an unaccepted invitation. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. + Revoke an unaccepted invitation, pending or expired. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. :param invitation_id: (required) :type invitation_id: UUID @@ -4028,7 +4299,7 @@ def organizations_revoke_active_organization_member_invitation_without_preload_c ) -> RESTResponseType: """Revoke Active Organization Member Invitation - Revoke an unaccepted invitation. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. + Revoke an unaccepted invitation, pending or expired. Organization owners and admins only. Suspends the paired membership rather than deleting it, the same as removing an active member: re-inviting the same address later revives it. :param invitation_id: (required) :type invitation_id: UUID diff --git a/src/otari/_client/api/pricing_api.py b/src/otari/_client/api/pricing_api.py index d478109b..8ec6c2ce 100644 --- a/src/otari/_client/api/pricing_api.py +++ b/src/otari/_client/api/pricing_api.py @@ -48,6 +48,7 @@ def __init__(self, api_client=None) -> None: @validate_call def pricing_confirm_pricing_refresh( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -65,6 +66,8 @@ def pricing_confirm_pricing_refresh( Activate the latest reviewed default-price snapshot. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -88,6 +91,7 @@ def pricing_confirm_pricing_refresh( """ # noqa: E501 _param = self._pricing_confirm_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -96,6 +100,7 @@ def pricing_confirm_pricing_refresh( _response_types_map: Dict[str, Optional[str]] = { '200': "PricingRefreshConfirmationResponse", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -111,6 +116,7 @@ def pricing_confirm_pricing_refresh( @validate_call def pricing_confirm_pricing_refresh_with_http_info( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -128,6 +134,8 @@ def pricing_confirm_pricing_refresh_with_http_info( Activate the latest reviewed default-price snapshot. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -151,6 +159,7 @@ def pricing_confirm_pricing_refresh_with_http_info( """ # noqa: E501 _param = self._pricing_confirm_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -159,6 +168,7 @@ def pricing_confirm_pricing_refresh_with_http_info( _response_types_map: Dict[str, Optional[str]] = { '200': "PricingRefreshConfirmationResponse", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -174,6 +184,7 @@ def pricing_confirm_pricing_refresh_with_http_info( @validate_call def pricing_confirm_pricing_refresh_without_preload_content( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -191,6 +202,8 @@ def pricing_confirm_pricing_refresh_without_preload_content( Activate the latest reviewed default-price snapshot. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -214,6 +227,7 @@ def pricing_confirm_pricing_refresh_without_preload_content( """ # noqa: E501 _param = self._pricing_confirm_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -222,6 +236,7 @@ def pricing_confirm_pricing_refresh_without_preload_content( _response_types_map: Dict[str, Optional[str]] = { '200': "PricingRefreshConfirmationResponse", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -232,6 +247,7 @@ def pricing_confirm_pricing_refresh_without_preload_content( def _pricing_confirm_pricing_refresh_serialize( self, + digest, _request_auth, _content_type, _headers, @@ -254,6 +270,10 @@ def _pricing_confirm_pricing_refresh_serialize( # process the path parameters # process the query parameters + if digest is not None: + + _query_params.append(('digest', digest)) + # process the header parameters # process the form parameters # process the body parameter @@ -1973,7 +1993,7 @@ def pricing_list_pricing_drift( ) -> List[PricingDriftRow]: """List Pricing Drift - Every stored deployment rate in force today, beside today's default for it. A stored row shadows the genai-prices default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. + Every stored deployment rate in force today, beside today's default for it. A stored row shadows the models.dev default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. :param limit: :type limit: int @@ -2041,7 +2061,7 @@ def pricing_list_pricing_drift_with_http_info( ) -> ApiResponse[List[PricingDriftRow]]: """List Pricing Drift - Every stored deployment rate in force today, beside today's default for it. A stored row shadows the genai-prices default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. + Every stored deployment rate in force today, beside today's default for it. A stored row shadows the models.dev default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. :param limit: :type limit: int @@ -2109,7 +2129,7 @@ def pricing_list_pricing_drift_without_preload_content( ) -> RESTResponseType: """List Pricing Drift - Every stored deployment rate in force today, beside today's default for it. A stored row shadows the genai-prices default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. + Every stored deployment rate in force today, beside today's default for it. A stored row shadows the models.dev default silently and forever, whether it was a deliberate override or a copy of a then-current default. This is what makes the difference visible: a row that matches the default is a row that could be deleted, and a row far from it is one worth a second look. Tool rows (``otari:``) are per request and have no default to drift from, so they are left out. :param limit: :type limit: int @@ -2738,6 +2758,7 @@ def _pricing_preview_pricing_refresh_serialize( @validate_call def pricing_reject_pricing_refresh( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2755,6 +2776,8 @@ def pricing_reject_pricing_refresh( Discard a reviewed default-price snapshot without applying it. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -2778,6 +2801,7 @@ def pricing_reject_pricing_refresh( """ # noqa: E501 _param = self._pricing_reject_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2786,6 +2810,7 @@ def pricing_reject_pricing_refresh( _response_types_map: Dict[str, Optional[str]] = { '204': None, + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2801,6 +2826,7 @@ def pricing_reject_pricing_refresh( @validate_call def pricing_reject_pricing_refresh_with_http_info( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2818,6 +2844,8 @@ def pricing_reject_pricing_refresh_with_http_info( Discard a reviewed default-price snapshot without applying it. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -2841,6 +2869,7 @@ def pricing_reject_pricing_refresh_with_http_info( """ # noqa: E501 _param = self._pricing_reject_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2849,6 +2878,7 @@ def pricing_reject_pricing_refresh_with_http_info( _response_types_map: Dict[str, Optional[str]] = { '204': None, + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2864,6 +2894,7 @@ def pricing_reject_pricing_refresh_with_http_info( @validate_call def pricing_reject_pricing_refresh_without_preload_content( self, + digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2881,6 +2912,8 @@ def pricing_reject_pricing_refresh_without_preload_content( Discard a reviewed default-price snapshot without applying it. + :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. + :type digest: str :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -2904,6 +2937,7 @@ def pricing_reject_pricing_refresh_without_preload_content( """ # noqa: E501 _param = self._pricing_reject_pricing_refresh_serialize( + digest=digest, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2912,6 +2946,7 @@ def pricing_reject_pricing_refresh_without_preload_content( _response_types_map: Dict[str, Optional[str]] = { '204': None, + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2922,6 +2957,7 @@ def pricing_reject_pricing_refresh_without_preload_content( def _pricing_reject_pricing_refresh_serialize( self, + digest, _request_auth, _content_type, _headers, @@ -2944,11 +2980,22 @@ def _pricing_reject_pricing_refresh_serialize( # process the path parameters # process the query parameters + if digest is not None: + + _query_params.append(('digest', digest)) + # process the header parameters # process the form parameters # process the body parameter + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting diff --git a/src/otari/_client/api/providers_api.py b/src/otari/_client/api/providers_api.py index 36801555..cf6232c9 100644 --- a/src/otari/_client/api/providers_api.py +++ b/src/otari/_client/api/providers_api.py @@ -607,7 +607,7 @@ def providers_list_providers( ) -> ProvidersResponse: """List Providers - List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and genai-prices datasets. No provider is contacted, so this is cheap and always available. + List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and models.dev datasets. No provider is contacted, so this is cheap and always available. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -670,7 +670,7 @@ def providers_list_providers_with_http_info( ) -> ApiResponse[ProvidersResponse]: """List Providers - List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and genai-prices datasets. No provider is contacted, so this is cheap and always available. + List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and models.dev datasets. No provider is contacted, so this is cheap and always available. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -733,7 +733,7 @@ def providers_list_providers_without_preload_content( ) -> RESTResponseType: """List Providers - List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and genai-prices datasets. No provider is contacted, so this is cheap and always available. + List static metadata for every configured provider. Operator-facing: reports each provider's capabilities, documentation and pricing links, and display name from the bundled any-llm and models.dev datasets. No provider is contacted, so this is cheap and always available. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -1101,7 +1101,7 @@ def providers_provider_catalog( ) -> List[KnownProviderSummarySchema]: """Provider Catalog - List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the bundled genai-prices dataset, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. + List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the models.dev catalog, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -1164,7 +1164,7 @@ def providers_provider_catalog_with_http_info( ) -> ApiResponse[List[KnownProviderSummarySchema]]: """Provider Catalog - List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the bundled genai-prices dataset, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. + List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the models.dev catalog, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -1227,7 +1227,7 @@ def providers_provider_catalog_without_preload_content( ) -> RESTResponseType: """Provider Catalog - List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the bundled genai-prices dataset, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. + List every known provider for the add-provider picker: id and name only. Lightweight by design so the picker never lags: provider ids come from the any-llm registry and names from the models.dev catalog, so no provider SDK is imported. The autofill hints for a chosen provider come from GET /api/v1/providers/catalog/{provider_id}, which imports only that one SDK. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request diff --git a/src/otari/_client/api/routing_api.py b/src/otari/_client/api/routing_api.py index 2da731b7..9d998da2 100644 --- a/src/otari/_client/api/routing_api.py +++ b/src/otari/_client/api/routing_api.py @@ -909,7 +909,7 @@ def _routing_explain_policy_serialize( @validate_call def routing_list_policies( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -925,9 +925,9 @@ def routing_list_policies( ) -> List[PolicyResponse]: """List Policies - List every routing policy in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every routing policy in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace. + :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -977,7 +977,7 @@ def routing_list_policies( @validate_call def routing_list_policies_with_http_info( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -993,9 +993,9 @@ def routing_list_policies_with_http_info( ) -> ApiResponse[List[PolicyResponse]]: """List Policies - List every routing policy in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every routing policy in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace. + :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -1045,7 +1045,7 @@ def routing_list_policies_with_http_info( @validate_call def routing_list_policies_without_preload_content( self, - workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace.")] = None, + workspace_id: Annotated[Optional[UUID], Field(description="Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -1061,9 +1061,9 @@ def routing_list_policies_without_preload_content( ) -> RESTResponseType: """List Policies - List every routing policy in force, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. + List every routing policy in force in your organization, from config.yml and from storage. Every scope at once, workspace-wide and user-scoped alike: this is the master-key management view, not what any one caller resolves. - :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace. + :param workspace_id: Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization. :type workspace_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request diff --git a/src/otari/_client/api/scoped_budgets_api.py b/src/otari/_client/api/scoped_budgets_api.py index 96dbbdaa..0e6fb777 100644 --- a/src/otari/_client/api/scoped_budgets_api.py +++ b/src/otari/_client/api/scoped_budgets_api.py @@ -870,7 +870,7 @@ def scoped_budgets_list_scoped_budgets( ) -> List[ScopedBudgetResponse]: """List Scoped Budgets - List scoped budgets, optionally filtered to one scope. + List the scoped budgets in the caller's organization, optionally filtered to one scope. :param scope_type: :type scope_type: str @@ -950,7 +950,7 @@ def scoped_budgets_list_scoped_budgets_with_http_info( ) -> ApiResponse[List[ScopedBudgetResponse]]: """List Scoped Budgets - List scoped budgets, optionally filtered to one scope. + List the scoped budgets in the caller's organization, optionally filtered to one scope. :param scope_type: :type scope_type: str @@ -1030,7 +1030,7 @@ def scoped_budgets_list_scoped_budgets_without_preload_content( ) -> RESTResponseType: """List Scoped Budgets - List scoped budgets, optionally filtered to one scope. + List the scoped budgets in the caller's organization, optionally filtered to one scope. :param scope_type: :type scope_type: str diff --git a/src/otari/_client/api/search_api.py b/src/otari/_client/api/search_api.py index f21138f6..64bdd565 100644 --- a/src/otari/_client/api/search_api.py +++ b/src/otari/_client/api/search_api.py @@ -57,7 +57,7 @@ def search_create_search( ) -> SearchResponse: """Create Search - Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when exactly one tool is configured. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. + Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when the deployment's ``web_search_default_tool`` names one, or when exactly one tool is configured. Such a call runs on the workspace's organization search key when it has one. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. :param search_request: (required) :type search_request: SearchRequest @@ -125,7 +125,7 @@ def search_create_search_with_http_info( ) -> ApiResponse[SearchResponse]: """Create Search - Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when exactly one tool is configured. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. + Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when the deployment's ``web_search_default_tool`` names one, or when exactly one tool is configured. Such a call runs on the workspace's organization search key when it has one. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. :param search_request: (required) :type search_request: SearchRequest @@ -193,7 +193,7 @@ def search_create_search_without_preload_content( ) -> RESTResponseType: """Create Search - Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when exactly one tool is configured. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. + Run a search against a configured search tool. The tool is taken from ``search_tool_name``, which may be omitted when the deployment's ``web_search_default_tool`` names one, or when exactly one tool is configured. Such a call runs on the workspace's organization search key when it has one. Authentication modes: - Master key: the ``user`` field is required and may name any existing user. - API key: usage and spend bind to the key's own user. A ``user`` field naming a different user is rejected with 403 (or ignored, when the key's own ``reject_user_mismatch`` is false, or the deployment-wide setting is disabled and the key does not override it); it is never billed to that user. - Service key: a ``user`` field names one of the key owner's end users, created on first use on the budget ``Otari-End-User-Budget`` names (or the key's default), and is billed and rate limited as that end user, as on chat completions. :param search_request: (required) :type search_request: SearchRequest diff --git a/src/otari/_client/api/traces_api.py b/src/otari/_client/api/traces_api.py index d964ccbb..bc1a8514 100644 --- a/src/otari/_client/api/traces_api.py +++ b/src/otari/_client/api/traces_api.py @@ -24,6 +24,7 @@ from otari._client.models.trace_detail_public import TraceDetailPublic from otari._client.models.trace_list_public import TraceListPublic from otari._client.models.trace_series_public import TraceSeriesPublic +from otari._client.models.trace_summary_public import TraceSummaryPublic from otari._client.api_client import ApiClient, RequestSerialized from otari._client.api_response import ApiResponse @@ -1209,6 +1210,271 @@ def _traces_list_traces_serialize( + @validate_call + def traces_trace_of_request( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> TraceSummaryPublic: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def traces_trace_of_request_with_http_info( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[TraceSummaryPublic]: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def traces_trace_of_request_without_preload_content( + self, + request_id: StrictStr, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Trace Of Request + + The session a gateway request was traced into, by the ``Otari-Request-ID`` it was sent. The usage log's ``request_group_id`` is that id, so a request log row opens its session here. A request outside the scope, or with no trace stored, is a 404. + + :param request_id: (required) + :type request_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._traces_trace_of_request_serialize( + request_id=request_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "TraceSummaryPublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _traces_trace_of_request_serialize( + self, + request_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if request_id is not None: + _path_params['request_id'] = request_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/traces/requests/{request_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def traces_trace_series( self, diff --git a/src/otari/_client/models/__init__.py b/src/otari/_client/models/__init__.py index 6ff7c45a..3b8620fe 100644 --- a/src/otari/_client/models/__init__.py +++ b/src/otari/_client/models/__init__.py @@ -197,6 +197,7 @@ from otari._client.models.embedding_request import EmbeddingRequest from otari._client.models.embedding_response import EmbeddingResponse from otari._client.models.embedding_usage import EmbeddingUsage +from otari._client.models.end_user_budget_public import EndUserBudgetPublic from otari._client.models.end_user_public import EndUserPublic from otari._client.models.end_user_put import EndUserPut from otari._client.models.end_user_update import EndUserUpdate @@ -381,6 +382,9 @@ from otari._client.models.msg_image_url import MSGImageURL from otari._client.models.msg_input_audio import MSGInputAudio from otari._client.models.mail_settings import MailSettings +from otari._client.models.mailed_link_request import MailedLinkRequest +from otari._client.models.mailed_link_status import MailedLinkStatus +from otari._client.models.mailed_link_status_response import MailedLinkStatusResponse from otari._client.models.maintenance_mode import MaintenanceMode from otari._client.models.managed_tool import ManagedTool from otari._client.models.mcp_error_body import McpErrorBody @@ -456,6 +460,7 @@ from otari._client.models.organization_model_pricing_update import OrganizationModelPricingUpdate from otari._client.models.organization_model_pricings_public import OrganizationModelPricingsPublic from otari._client.models.organization_public import OrganizationPublic +from otari._client.models.organization_refusal import OrganizationRefusal from otari._client.models.organization_scoped_budget_create import OrganizationScopedBudgetCreate from otari._client.models.organization_scoped_budget_public import OrganizationScopedBudgetPublic from otari._client.models.organization_scoped_budget_update import OrganizationScopedBudgetUpdate @@ -463,6 +468,7 @@ from otari._client.models.output_shape import OutputShape from otari._client.models.overview_summary_response import OverviewSummaryResponse from otari._client.models.passkey_session_response import PasskeySessionResponse +from otari._client.models.password_link_public import PasswordLinkPublic from otari._client.models.password_response import PasswordResponse from otari._client.models.pending_organization_invitation_public import PendingOrganizationInvitationPublic from otari._client.models.pending_organization_invitations_public import PendingOrganizationInvitationsPublic diff --git a/src/otari/_client/models/accept_invitation_result_public.py b/src/otari/_client/models/accept_invitation_result_public.py index 601369fb..e1eefdfd 100644 --- a/src/otari/_client/models/accept_invitation_result_public.py +++ b/src/otari/_client/models/accept_invitation_result_public.py @@ -17,7 +17,7 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional from typing import Optional, Set from typing_extensions import Self @@ -27,10 +27,24 @@ class AcceptInvitationResultPublic(BaseModel): """ What accepting produces: enough for the accept page to say where the visitor landed. No session and no token. When the request carried a password, the identity can sign in straight away; otherwise it stays password-less until claimed by signup or a provider sign-in. """ # noqa: E501 + can_sign_in: Optional[StrictBool] = Field(default=True, description="Whether the invited address can sign in now, with a password (this accept's included) or through a provider. False when it accepted without one and has never signed in.") organization_name: StrictStr password_set: Optional[StrictBool] = Field(default=False, description="Whether this accept set the identity's password.") role: StrictStr - __properties: ClassVar[List[str]] = ["organization_name", "password_set", "role"] + verification_pending: Optional[StrictBool] = Field(default=False, description="Whether the invited address chose a password through signup and has not verified it yet, so it has to open its verification link before it can sign in.") + ways_in: Optional[List[StrictStr]] = Field(default=None, description="When can_sign_in is false, what this deployment offers instead, as the preview's ways_in says.") + __properties: ClassVar[List[str]] = ["can_sign_in", "organization_name", "password_set", "role", "verification_pending", "ways_in"] + + @field_validator('ways_in') + def ways_in_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + for i in value: + if i not in set(['provider', 'password_reset']): + raise ValueError("each list item must be one of ('provider', 'password_reset')") + return value model_config = ConfigDict( validate_by_name=True, @@ -83,9 +97,12 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "can_sign_in": obj.get("can_sign_in") if obj.get("can_sign_in") is not None else True, "organization_name": obj.get("organization_name"), "password_set": obj.get("password_set") if obj.get("password_set") is not None else False, - "role": obj.get("role") + "role": obj.get("role"), + "verification_pending": obj.get("verification_pending") if obj.get("verification_pending") is not None else False, + "ways_in": obj.get("ways_in") }) return _obj diff --git a/src/otari/_client/models/accepted_snapshot_response.py b/src/otari/_client/models/accepted_snapshot_response.py index badd980a..fdae7506 100644 --- a/src/otari/_client/models/accepted_snapshot_response.py +++ b/src/otari/_client/models/accepted_snapshot_response.py @@ -26,7 +26,7 @@ class AcceptedSnapshotResponse(BaseModel): """ - One accepted genai-prices snapshot in the history. + One accepted models.dev snapshot in the history. """ # noqa: E501 accepted_at: datetime accepted_by: StrictStr = Field(description="`operator` for a dashboard confirm, `schedule` for the auto policy.") diff --git a/src/otari/_client/models/active_organization_member_create_result_public.py b/src/otari/_client/models/active_organization_member_create_result_public.py index f288e335..bf7c07c8 100644 --- a/src/otari/_client/models/active_organization_member_create_result_public.py +++ b/src/otari/_client/models/active_organization_member_create_result_public.py @@ -27,7 +27,7 @@ class ActiveOrganizationMemberCreateResultPublic(BaseModel): """ - The outcome of adding a member. The platform answers ``invited`` on both its branches, because being added there always needs acceptance: a known address gets an ``invited`` membership, an unknown one an emailed invitation. This edition has neither an invitation to send nor a way to accept one, so it answers on the other arm of the same union, ``active``, and the invitation fields stay null until that flow rehomes. + The outcome of adding a member directly. The platform answers ``invited`` on both its branches, because being added there always needs acceptance. A direct add here needs none, so it answers on the other arm of the same union, ``active``, and the invitation fields stay null; inviting answers ``InviteOrganizationMemberResultPublic``. """ # noqa: E501 attribution_user_id: Optional[StrictStr] = None created_at: Optional[datetime] = None diff --git a/src/otari/_client/models/active_organization_member_public.py b/src/otari/_client/models/active_organization_member_public.py index e6cbf329..1d303cf1 100644 --- a/src/otari/_client/models/active_organization_member_public.py +++ b/src/otari/_client/models/active_organization_member_public.py @@ -18,7 +18,7 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional from uuid import UUID from otari._client.models.member_attribution_public import MemberAttributionPublic @@ -29,13 +29,14 @@ class ActiveOrganizationMemberPublic(BaseModel): """ - A member row joined to the identity behind it, as the roster shows it. Field-for-field the platform's shape, so the ported roster page is not rewritten around a new contract, with two consequences of the OSS line: ``email`` is nullable here (a local operator identity has no sign-in address), and ``invitation_id`` is always null until the invitation flow rehomes, which is what fills it. ``attribution_user_id`` is the addition the platform has no counterpart for. Keys, budgets, and usage attach to the gateway's string-keyed ``users`` row, not to this UUID identity, so this carries the ``user_id`` a caller passes to when minting a key for this member. It is null when no usable row exists (nobody minted one, or it was soft-deleted through soft-deleted), which is the signal not to offer this member as a key owner: key creation would refuse. How the two ids converge is the open question in otari-ai#1727; this field is the join until it is answered, and is what lets either answer land without the dashboard changing. + A member row joined to the identity behind it, as the roster shows it. Field-for-field the platform's shape, so the ported roster page is not rewritten around a new contract, except that ``email`` is nullable here (a local operator identity has no sign-in address). ``invitation_id`` and ``invitation_expires_at`` name an ``invited`` row's current invitation, which may have expired, so the roster can offer to revoke or reissue it. ``attribution_user_id`` is the addition the platform has no counterpart for. Keys, budgets, and usage attach to the gateway's string-keyed ``users`` row, not to this UUID identity, so this carries the ``user_id`` a caller passes to when minting a key for this member. It is null when no usable row exists (nobody minted one, or it was soft-deleted through soft-deleted), which is the signal not to offer this member as a key owner: key creation would refuse. How the two ids converge is the open question in otari-ai#1727; this field is the join until it is answered, and is what lets either answer land without the dashboard changing. """ # noqa: E501 attribution: Optional[MemberAttributionPublic] = None attribution_user_id: Optional[StrictStr] = None created_at: datetime email: Optional[StrictStr] = None full_name: Optional[StrictStr] = None + invitation_expires_at: Optional[datetime] = Field(default=None, description="When the invitation in invitation_id expires, or expired. Null when there is none.") invitation_id: Optional[UUID] = None organization_member_id: Optional[UUID] = None role: StrictStr @@ -43,7 +44,7 @@ class ActiveOrganizationMemberPublic(BaseModel): updated_at: Optional[datetime] = None user_id: Optional[UUID] = None workspaces: Optional[List[MemberWorkspacePlacementPublic]] = None - __properties: ClassVar[List[str]] = ["attribution", "attribution_user_id", "created_at", "email", "full_name", "invitation_id", "organization_member_id", "role", "status", "updated_at", "user_id", "workspaces"] + __properties: ClassVar[List[str]] = ["attribution", "attribution_user_id", "created_at", "email", "full_name", "invitation_expires_at", "invitation_id", "organization_member_id", "role", "status", "updated_at", "user_id", "workspaces"] model_config = ConfigDict( validate_by_name=True, @@ -114,6 +115,11 @@ def to_dict(self) -> Dict[str, Any]: if self.full_name is None and "full_name" in self.model_fields_set: _dict['full_name'] = None + # set to None if invitation_expires_at (nullable) is None + # and model_fields_set contains the field + if self.invitation_expires_at is None and "invitation_expires_at" in self.model_fields_set: + _dict['invitation_expires_at'] = None + # set to None if invitation_id (nullable) is None # and model_fields_set contains the field if self.invitation_id is None and "invitation_id" in self.model_fields_set: @@ -151,6 +157,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "created_at": obj.get("created_at"), "email": obj.get("email"), "full_name": obj.get("full_name"), + "invitation_expires_at": obj.get("invitation_expires_at"), "invitation_id": obj.get("invitation_id"), "organization_member_id": obj.get("organization_member_id"), "role": obj.get("role"), diff --git a/src/otari/_client/models/catalog_model_detail.py b/src/otari/_client/models/catalog_model_detail.py index ba1b16ea..c3e9c633 100644 --- a/src/otari/_client/models/catalog_model_detail.py +++ b/src/otari/_client/models/catalog_model_detail.py @@ -33,7 +33,7 @@ class CatalogModelDetail(BaseModel): also_available_from: List[CatalogElsewhere] capabilities: CatalogCapabilities context_window: Optional[StrictInt] = Field(default=None, description="The largest any offering serves.") - default_pricing: StrictBool = Field(description="Whether an unpriced model is metered at the genai-prices default.") + default_pricing: StrictBool = Field(description="Whether an unpriced model is metered at the models.dev default.") deprecated: Optional[StrictBool] = Field(default=False, description="True only when every offering with metadata says so.") description: Optional[StrictStr] = Field(default=None, description="models.dev's, from the offering that named the model.") discovered: StrictBool = Field(description="Whether any offering was discovered from its provider.") diff --git a/src/otari/_client/models/catalog_offering.py b/src/otari/_client/models/catalog_offering.py index fe9f9392..5ecaad05 100644 --- a/src/otari/_client/models/catalog_offering.py +++ b/src/otari/_client/models/catalog_offering.py @@ -34,10 +34,10 @@ class CatalogOffering(BaseModel): credential: CatalogCredential = Field(description="Whose key serves it: `deployment` for a `providers:` instance the operator configured, `hosted` for a provider the deployment pays for in any workspace of the viewer's organization, `organization` for one on the organization's own key, which it may set its own rate for. A workspace can still call a `hosted` provider with the organization's own key.") discovered: StrictBool = Field(description="Whether the provider itself reported this model.") max_output_tokens: Optional[StrictInt] = None - metadata_input_price_per_million: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="What models.dev lists this provider charging, for a cross-check. Not billed from: two independent datasets disagreeing is the cheapest stale-price detector there is.") + metadata_input_price_per_million: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="What the live models.dev catalog lists this provider charging. The default is billed from the accepted models.dev snapshot, which can lag the live catalog, so a difference means a price update is waiting for review.") metadata_output_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None - price_reference: Optional[StrictStr] = Field(default=None, description="For a default, the genai-prices `provider:model` entry that matched; the selector otherwise.") - price_source: Optional[StrictStr] = Field(default=None, description="Which price list `pricing` came from, for this viewer: the organization's own override, the deployment's stored row, or the genai-prices defaults. Null when nothing prices it.") + price_reference: Optional[StrictStr] = Field(default=None, description="For a default, the `models.dev:/` entry that matched; the selector otherwise.") + price_source: Optional[StrictStr] = Field(default=None, description="Which price list `pricing` came from, for this viewer: the organization's own override, the deployment's stored row, or the models.dev defaults. Null when nothing prices it.") pricing: Optional[ModelPricingInfo] = None provider: StrictStr = Field(description="The provider instance the selector names.") provider_type: StrictStr = Field(description="The any-llm implementation behind the instance.") diff --git a/src/otari/_client/models/catalog_response.py b/src/otari/_client/models/catalog_response.py index f173b885..9a78cc15 100644 --- a/src/otari/_client/models/catalog_response.py +++ b/src/otari/_client/models/catalog_response.py @@ -31,8 +31,8 @@ class CatalogResponse(BaseModel): The grouped catalog, and the facts a reader needs to interpret its prices. """ # noqa: E501 count: StrictInt = Field(description="Models matching all filters before paging.") - default_pricing: StrictBool = Field(description="Whether an unpriced model is metered at the genai-prices default.") - defaults_as_of: Optional[datetime] = Field(description="When the accepted genai-prices snapshot was taken. Null while the bundled dataset serves.") + default_pricing: StrictBool = Field(description="Whether an unpriced model is metered at the models.dev default.") + defaults_as_of: Optional[datetime] = Field(description="When the accepted models.dev snapshot, which the defaults are billed from, was taken. Null while the bundled snapshot serves.") facets: Optional[CatalogFacets] = Field(default=None, description="Present when include_facets is requested.") metadata_available: StrictBool = Field(description="False when models.dev could not be read; descriptions are then absent.") models: List[CatalogModelSummary] diff --git a/src/otari/_client/models/end_user_budget_public.py b/src/otari/_client/models/end_user_budget_public.py new file mode 100644 index 00000000..680ba16c --- /dev/null +++ b/src/otari/_client/models/end_user_budget_public.py @@ -0,0 +1,94 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class EndUserBudgetPublic(BaseModel): + """ + A budget a service key may put its end users on, and how many of them are on it. + """ # noqa: E501 + blocked_end_user_count: StrictInt + budget_id: StrictStr + end_user_count: StrictInt = Field(description="End users of the key's user on this budget, blocked ones included") + is_default: StrictBool = Field(description="Whether a new end user starts here when its request names no budget") + __properties: ClassVar[List[str]] = ["blocked_end_user_count", "budget_id", "end_user_count", "is_default"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of EndUserBudgetPublic from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of EndUserBudgetPublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "blocked_end_user_count": obj.get("blocked_end_user_count"), + "budget_id": obj.get("budget_id"), + "end_user_count": obj.get("end_user_count"), + "is_default": obj.get("is_default") + }) + return _obj + + diff --git a/src/otari/_client/models/invitation_preview_public.py b/src/otari/_client/models/invitation_preview_public.py index d7dda53e..464bf292 100644 --- a/src/otari/_client/models/invitation_preview_public.py +++ b/src/otari/_client/models/invitation_preview_public.py @@ -18,7 +18,7 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List from typing import Optional, Set from typing_extensions import Self @@ -28,12 +28,22 @@ class InvitationPreviewPublic(BaseModel): """ What an unauthenticated visitor sees before committing to accept. Deliberately narrow: the address it was sent to, the organization's name, and the role on offer. The token is the caller's only credential here, not a session, so this carries nothing that identifies who sent it or any other member. """ # noqa: E501 + can_sign_in: StrictBool = Field(description="Whether the invited address can already sign in, with a password or through a provider.") email: StrictStr expires_at: datetime - needs_password: StrictBool = Field(description="Whether the invited address has never signed in here, so accepting should also set its password. False when the address already has a way in, and then accept refuses one.") + needs_password: StrictBool = Field(description="Whether accepting should also set the invited address's first password. False when the address already has a way in, and also when another organization has it as a member or invitee, since this link may not choose a password for it then; can_sign_in tells the two apart. Accept refuses a password whenever this is false.") organization_name: StrictStr role: StrictStr - __properties: ClassVar[List[str]] = ["email", "expires_at", "needs_password", "organization_name", "role"] + ways_in: List[StrictStr] = Field(description="When the address cannot sign in yet and this link will not set its password, what this deployment offers instead once it has accepted: 'provider' (sign in with Google or GitHub) and 'password_reset' (choose a password with \"Forgot your password?\"). Empty otherwise, and empty when the deployment offers neither, in which case whoever administers it has to help.") + __properties: ClassVar[List[str]] = ["can_sign_in", "email", "expires_at", "needs_password", "organization_name", "role", "ways_in"] + + @field_validator('ways_in') + def ways_in_validate_enum(cls, value): + """Validates the enum""" + for i in value: + if i not in set(['provider', 'password_reset']): + raise ValueError("each list item must be one of ('provider', 'password_reset')") + return value model_config = ConfigDict( validate_by_name=True, @@ -86,11 +96,13 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "can_sign_in": obj.get("can_sign_in"), "email": obj.get("email"), "expires_at": obj.get("expires_at"), "needs_password": obj.get("needs_password"), "organization_name": obj.get("organization_name"), - "role": obj.get("role") + "role": obj.get("role"), + "ways_in": obj.get("ways_in") }) return _obj diff --git a/src/otari/_client/models/invite_organization_member_result_public.py b/src/otari/_client/models/invite_organization_member_result_public.py index fb010c99..d12477fa 100644 --- a/src/otari/_client/models/invite_organization_member_result_public.py +++ b/src/otari/_client/models/invite_organization_member_result_public.py @@ -34,11 +34,12 @@ class InviteOrganizationMemberResultPublic(BaseModel): email: StrictStr expires_at: datetime invitation_id: UUID - mail_sent: StrictBool = Field(description="Whether the invitation email was actually dispatched. False when mail is not configured, or the send itself failed.") + mail_limited: Optional[StrictBool] = Field(default=False, description="Whether the email was held back because the organization or the address reached its invitation mail limit for the day. Share the link yourself, or reissue the invitation later to email a new one.") + mail_sent: StrictBool = Field(description="Whether the invitation email was actually dispatched. False when mail is not configured, the send itself failed, or mail_limited.") organization_member_id: UUID role: StrictStr status: Optional[StrictStr] = 'invited' - __properties: ClassVar[List[str]] = ["accept_link", "created_at", "email", "expires_at", "invitation_id", "mail_sent", "organization_member_id", "role", "status"] + __properties: ClassVar[List[str]] = ["accept_link", "created_at", "email", "expires_at", "invitation_id", "mail_limited", "mail_sent", "organization_member_id", "role", "status"] @field_validator('status') def status_validate_enum(cls, value): @@ -111,6 +112,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "email": obj.get("email"), "expires_at": obj.get("expires_at"), "invitation_id": obj.get("invitation_id"), + "mail_limited": obj.get("mail_limited") if obj.get("mail_limited") is not None else False, "mail_sent": obj.get("mail_sent"), "organization_member_id": obj.get("organization_member_id"), "role": obj.get("role"), diff --git a/src/otari/_client/models/mailed_link_request.py b/src/otari/_client/models/mailed_link_request.py new file mode 100644 index 00000000..4542644d --- /dev/null +++ b/src/otari/_client/models/mailed_link_request.py @@ -0,0 +1,89 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field +from typing import Any, ClassVar, Dict, List +from typing_extensions import Annotated +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class MailedLinkRequest(BaseModel): + """ + A token from a verification or password reset link. + """ # noqa: E501 + token: Annotated[str, Field(strict=True, max_length=512)] = Field(description="The token from the link.") + __properties: ClassVar[List[str]] = ["token"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of MailedLinkRequest from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of MailedLinkRequest from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "token": obj.get("token") + }) + return _obj + + diff --git a/src/otari/_client/models/mailed_link_status.py b/src/otari/_client/models/mailed_link_status.py new file mode 100644 index 00000000..78852f97 --- /dev/null +++ b/src/otari/_client/models/mailed_link_status.py @@ -0,0 +1,38 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import json +from enum import Enum +from typing_extensions import Self + + +class MailedLinkStatus(str, Enum): + """ + Whether a mailed verification or password reset link can still be used. NOTE: ``INVALID`` covers a link that was never issued and one already used, because a used link's hash is gone. + """ + + """ + allowed enum values + """ + VALID = 'valid' + EXPIRED = 'expired' + INVALID = 'invalid' + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of MailedLinkStatus from a JSON string""" + return cls(json.loads(json_str)) + + diff --git a/src/otari/_client/models/mailed_link_status_response.py b/src/otari/_client/models/mailed_link_status_response.py new file mode 100644 index 00000000..13ec4da9 --- /dev/null +++ b/src/otari/_client/models/mailed_link_status_response.py @@ -0,0 +1,89 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field +from typing import Any, ClassVar, Dict, List +from otari._client.models.mailed_link_status import MailedLinkStatus +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class MailedLinkStatusResponse(BaseModel): + """ + Whether the link can still be used. Checking it does not use it. + """ # noqa: E501 + status: MailedLinkStatus = Field(description="valid, expired, or invalid. invalid covers a link that was never issued, one already used, and one whose account was deactivated.") + __properties: ClassVar[List[str]] = ["status"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of MailedLinkStatusResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of MailedLinkStatusResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "status": obj.get("status") + }) + return _obj + + diff --git a/src/otari/_client/models/model_pricing_info.py b/src/otari/_client/models/model_pricing_info.py index 7ad70159..57b211d9 100644 --- a/src/otari/_client/models/model_pricing_info.py +++ b/src/otari/_client/models/model_pricing_info.py @@ -29,13 +29,12 @@ class ModelPricingInfo(BaseModel): Pricing information for a model. """ # noqa: E501 cache_read_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None - cache_write_1h_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None cache_write_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None input_price_per_million: Union[StrictFloat, StrictInt] output_price_per_million: Union[StrictFloat, StrictInt] pricing_tiers: Optional[List[PricingTiersInner]] = None unit: Optional[StrictStr] = 'tokens' - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "input_price_per_million", "output_price_per_million", "pricing_tiers", "unit"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "input_price_per_million", "output_price_per_million", "pricing_tiers", "unit"] model_config = ConfigDict( validate_by_name=True, @@ -88,11 +87,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -111,7 +105,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "input_price_per_million": obj.get("input_price_per_million"), "output_price_per_million": obj.get("output_price_per_million"), diff --git a/src/otari/_client/models/o_auth_callback_request.py b/src/otari/_client/models/o_auth_callback_request.py index 566011ea..d1160017 100644 --- a/src/otari/_client/models/o_auth_callback_request.py +++ b/src/otari/_client/models/o_auth_callback_request.py @@ -17,8 +17,8 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field -from typing import Any, ClassVar, Dict, List +from pydantic import BaseModel, ConfigDict, Field, StrictBool +from typing import Any, ClassVar, Dict, List, Optional from typing_extensions import Annotated from typing import Optional, Set from typing_extensions import Self @@ -30,7 +30,8 @@ class OAuthCallbackRequest(BaseModel): """ # noqa: E501 code: Annotated[str, Field(strict=True, max_length=2048)] = Field(description="The authorization code from the provider's redirect.") state: Annotated[str, Field(strict=True, max_length=512)] = Field(description="The 'state' from the provider's redirect, as issued by /authorize.") - __properties: ClassVar[List[str]] = ["code", "state"] + terms_accepted: Optional[StrictBool] = Field(default=False, description="Whether the person accepted this deployment's terms before going to the provider. Required where the bootstrap reports a terms_url and the sign-in creates the account, or is the first way in to one nobody has claimed yet; ignored otherwise.") + __properties: ClassVar[List[str]] = ["code", "state", "terms_accepted"] model_config = ConfigDict( validate_by_name=True, @@ -84,7 +85,8 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "code": obj.get("code"), - "state": obj.get("state") + "state": obj.get("state"), + "terms_accepted": obj.get("terms_accepted") if obj.get("terms_accepted") is not None else False }) return _obj diff --git a/src/otari/_client/models/o_auth_session_response.py b/src/otari/_client/models/o_auth_session_response.py index b27d8e8b..bc966517 100644 --- a/src/otari/_client/models/o_auth_session_response.py +++ b/src/otari/_client/models/o_auth_session_response.py @@ -18,8 +18,8 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, Field -from typing import Any, ClassVar, Dict, List +from pydantic import BaseModel, ConfigDict, Field, StrictBool +from typing import Any, ClassVar, Dict, List, Optional from uuid import UUID from typing import Optional, Set from typing_extensions import Self @@ -29,10 +29,11 @@ class OAuthSessionResponse(BaseModel): """ A dashboard session minted by an OAuth sign-in (the token travels only in the cookie). The same three fields ``POST /api/v1/auth/session`` answers, deliberately: the dashboard's sign-in path does not care which credential got it here. """ # noqa: E501 - active_organization_id: UUID = Field(description="The organization that identity is acting in, which scopes every tenancy surface.") + active_organization_id: Optional[UUID] = Field(description="The organization that identity is acting in, which scopes every tenancy surface. Null when it is an active member of none, as an invitee who has not accepted yet is not.") expires_at: datetime = Field(description="When the session cookie stops being accepted.") + password_removed: Optional[StrictBool] = Field(default=False, description="Whether this sign-in removed a password the account held: the first provider sign-in on an address nobody had proven removes the password set before then. The person can set a new one from Account settings.") user_id: UUID = Field(description="The identity this session speaks for.") - __properties: ClassVar[List[str]] = ["active_organization_id", "expires_at", "user_id"] + __properties: ClassVar[List[str]] = ["active_organization_id", "expires_at", "password_removed", "user_id"] model_config = ConfigDict( validate_by_name=True, @@ -73,6 +74,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if active_organization_id (nullable) is None + # and model_fields_set contains the field + if self.active_organization_id is None and "active_organization_id" in self.model_fields_set: + _dict['active_organization_id'] = None + return _dict @classmethod @@ -87,6 +93,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "active_organization_id": obj.get("active_organization_id"), "expires_at": obj.get("expires_at"), + "password_removed": obj.get("password_removed") if obj.get("password_removed") is not None else False, "user_id": obj.get("user_id") }) return _obj diff --git a/src/otari/_client/models/org_provider_key_model_public.py b/src/otari/_client/models/org_provider_key_model_public.py index b2451414..99ecafb7 100644 --- a/src/otari/_client/models/org_provider_key_model_public.py +++ b/src/otari/_client/models/org_provider_key_model_public.py @@ -27,10 +27,9 @@ class OrgProviderKeyModelPublic(BaseModel): """ - One offered model, with the rate the caller's organization is charged for it. ``price_source`` says which rung of ``services.pricing_service`` answered: ``organization`` for a rate an admin set, ``defaults`` for the community-maintained rate this surface seeded or the genai-prices fallback, ``deployment`` for the deployment's own price list, and None when nothing prices the model yet. ``pricing_id`` names the organization's own row where there is one, so a client can edit that rate without re-deriving the key. ``unit`` says what the rates are per, as on a pricing row: tokens, requests or images, so a per-request rate is not read as a per-token one. + One offered model, with the rate the caller's organization is charged for it. ``price_source`` says which rung of ``services.pricing_service`` answered: ``organization`` for a rate an admin set, ``defaults`` for the community-maintained rate this surface seeded or the models.dev fallback, ``deployment`` for the deployment's own price list, and None when nothing prices the model yet. ``pricing_id`` names the organization's own row where there is one, so a client can edit that rate without re-deriving the key. ``unit`` says what the rates are per, as on a pricing row: tokens, requests or images, so a per-request rate is not read as a per-token one. """ # noqa: E501 cache_read_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None - cache_write_1h_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None cache_write_price_per_million: Optional[Union[StrictFloat, StrictInt]] = None created_at: datetime enabled: StrictBool @@ -43,7 +42,7 @@ class OrgProviderKeyModelPublic(BaseModel): pricing_id: Optional[UUID] = None unit: Optional[StrictStr] = 'tokens' updated_at: Optional[datetime] = None - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "created_at", "enabled", "id", "input_price_per_million", "model", "org_provider_key_id", "output_price_per_million", "price_source", "pricing_id", "unit", "updated_at"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "created_at", "enabled", "id", "input_price_per_million", "model", "org_provider_key_id", "output_price_per_million", "price_source", "pricing_id", "unit", "updated_at"] @field_validator('price_source') def price_source_validate_enum(cls, value): @@ -99,11 +98,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -147,7 +141,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "created_at": obj.get("created_at"), "enabled": obj.get("enabled"), diff --git a/src/otari/_client/models/organization_model_pricing_create.py b/src/otari/_client/models/organization_model_pricing_create.py index e86dc283..4f7be98a 100644 --- a/src/otari/_client/models/organization_model_pricing_create.py +++ b/src/otari/_client/models/organization_model_pricing_create.py @@ -31,7 +31,6 @@ class OrganizationModelPricingCreate(BaseModel): Create one rate override for a model, for a period. """ # noqa: E501 cache_read_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cached-input tokens") - cache_write_1h_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M Anthropic 1-hour cache-write tokens") cache_write_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cache-write (creation) tokens") effective_from: Optional[datetime] = Field(default=None, description="ISO 8601 datetime from which this rate applies, inclusive. Defaults to now.") effective_to: Optional[datetime] = Field(default=None, description="ISO 8601 datetime at which this rate stops applying, exclusive. Null leaves it open ended. Because the end is exclusive, the next period may begin at exactly this instant without overlapping.") @@ -40,7 +39,7 @@ class OrganizationModelPricingCreate(BaseModel): output_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M output tokens; unused by a rate in requests or images") pricing_tiers: Optional[List[PricingTier]] = Field(default=None, description="Whole-request context thresholds. Fields omitted by a tier inherit the base rate.") unit: Optional[StrictStr] = Field(default='tokens', description="What the rates are per: tokens for a model, requests or images for a non-token endpoint, each priced per million. A completion model priced per requests is charged one request per successful call.") - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "effective_from", "effective_to", "input_price_per_million", "model_key", "output_price_per_million", "pricing_tiers", "unit"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "effective_from", "effective_to", "input_price_per_million", "model_key", "output_price_per_million", "pricing_tiers", "unit"] @field_validator('model_key') def model_key_validate_regular_expression(cls, value): @@ -113,11 +112,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -151,7 +145,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "effective_from": obj.get("effective_from"), "effective_to": obj.get("effective_to"), diff --git a/src/otari/_client/models/organization_model_pricing_public.py b/src/otari/_client/models/organization_model_pricing_public.py index 91290d21..f3866f1f 100644 --- a/src/otari/_client/models/organization_model_pricing_public.py +++ b/src/otari/_client/models/organization_model_pricing_public.py @@ -31,7 +31,6 @@ class OrganizationModelPricingPublic(BaseModel): One stored rate override. """ # noqa: E501 cache_read_price_per_million: Optional[Union[StrictFloat, StrictInt]] - cache_write_1h_price_per_million: Optional[Union[StrictFloat, StrictInt]] cache_write_price_per_million: Optional[Union[StrictFloat, StrictInt]] created_at: datetime effective_from: datetime @@ -44,7 +43,7 @@ class OrganizationModelPricingPublic(BaseModel): pricing_tiers: List[PricingTier] unit: StrictStr updated_at: datetime - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "created_at", "effective_from", "effective_to", "id", "input_price_per_million", "model_key", "organization_id", "output_price_per_million", "pricing_tiers", "unit", "updated_at"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "created_at", "effective_from", "effective_to", "id", "input_price_per_million", "model_key", "organization_id", "output_price_per_million", "pricing_tiers", "unit", "updated_at"] model_config = ConfigDict( validate_by_name=True, @@ -97,11 +96,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -125,7 +119,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "created_at": obj.get("created_at"), "effective_from": obj.get("effective_from"), diff --git a/src/otari/_client/models/organization_model_pricing_update.py b/src/otari/_client/models/organization_model_pricing_update.py index e2fa883a..acd59975 100644 --- a/src/otari/_client/models/organization_model_pricing_update.py +++ b/src/otari/_client/models/organization_model_pricing_update.py @@ -31,7 +31,6 @@ class OrganizationModelPricingUpdate(BaseModel): Replace an override's rates and period. ``effective_from`` is required here, where a create defaults it to now. A replacement states the whole row, so defaulting an omitted start would move a stored period to the present: an operator editing next quarter's rate through a client that does not send the field would silently bring it into effect today, or collide with the period that currently applies. Stating it is the only reading that cannot surprise. A full replacement rather than a patch: every rate field is present in the body and an omitted optional rate is cleared, so the stored row is exactly what was sent. That is the opposite of ``POST /api/v1/pricing``, which inherits an omitted cache rate from the model's previous version, and deliberately so: that surface versions a catalog where each write adds a row, while this one edits a single row in place and an inheriting patch would make the result depend on what happened to be stored before. ``model_key`` is absent because it is immutable. Repointing an override at another model is retiring one and creating another, which is two requests. """ # noqa: E501 cache_read_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cached-input tokens") - cache_write_1h_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M Anthropic 1-hour cache-write tokens") cache_write_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cache-write (creation) tokens") effective_from: datetime = Field(description="ISO 8601 datetime from which this rate applies, inclusive. Required on a replacement, so an omitted value cannot silently move a stored period to the present.") effective_to: Optional[datetime] = Field(default=None, description="ISO 8601 datetime at which this rate stops applying, exclusive. Null leaves it open ended. Because the end is exclusive, the next period may begin at exactly this instant without overlapping.") @@ -39,7 +38,7 @@ class OrganizationModelPricingUpdate(BaseModel): output_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M output tokens; unused by a rate in requests or images") pricing_tiers: Optional[List[PricingTier]] = Field(default=None, description="Whole-request context thresholds. Fields omitted by a tier inherit the base rate.") unit: Optional[StrictStr] = Field(default='tokens', description="What the rates are per: tokens for a model, requests or images for a non-token endpoint, each priced per million. A completion model priced per requests is charged one request per successful call.") - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "effective_from", "effective_to", "input_price_per_million", "output_price_per_million", "pricing_tiers", "unit"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "effective_from", "effective_to", "input_price_per_million", "output_price_per_million", "pricing_tiers", "unit"] @field_validator('unit') def unit_validate_enum(cls, value): @@ -102,11 +101,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -135,7 +129,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "effective_from": obj.get("effective_from"), "effective_to": obj.get("effective_to"), diff --git a/src/otari/_client/models/organization_refusal.py b/src/otari/_client/models/organization_refusal.py new file mode 100644 index 00000000..a8c9f6cd --- /dev/null +++ b/src/otari/_client/models/organization_refusal.py @@ -0,0 +1,88 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class OrganizationRefusal(BaseModel): + """ + The body of a request the organizations domain refuses. + """ # noqa: E501 + detail: StrictStr = Field(description="Why the request was refused.") + __properties: ClassVar[List[str]] = ["detail"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of OrganizationRefusal from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of OrganizationRefusal from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "detail": obj.get("detail") + }) + return _obj + + diff --git a/src/otari/_client/models/passkey_session_response.py b/src/otari/_client/models/passkey_session_response.py index 3d0306b5..5748d88a 100644 --- a/src/otari/_client/models/passkey_session_response.py +++ b/src/otari/_client/models/passkey_session_response.py @@ -19,7 +19,7 @@ from datetime import datetime from pydantic import BaseModel, ConfigDict, Field -from typing import Any, ClassVar, Dict, List +from typing import Any, ClassVar, Dict, List, Optional from uuid import UUID from typing import Optional, Set from typing_extensions import Self @@ -29,7 +29,7 @@ class PasskeySessionResponse(BaseModel): """ A dashboard session minted by a passkey (the token travels only in the cookie). The same three fields ``POST /api/v1/auth/session`` answers, deliberately: the dashboard's sign-in path does not care which credential got it here. """ # noqa: E501 - active_organization_id: UUID = Field(description="The organization that identity is acting in, which scopes every tenancy surface.") + active_organization_id: Optional[UUID] = Field(description="The organization that identity is acting in, which scopes every tenancy surface. Null when it is an active member of none, as an invitee who has not accepted yet is not.") expires_at: datetime = Field(description="When the session cookie stops being accepted.") user_id: UUID = Field(description="The identity this session speaks for.") __properties: ClassVar[List[str]] = ["active_organization_id", "expires_at", "user_id"] @@ -73,6 +73,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if active_organization_id (nullable) is None + # and model_fields_set contains the field + if self.active_organization_id is None and "active_organization_id" in self.model_fields_set: + _dict['active_organization_id'] = None + return _dict @classmethod diff --git a/src/otari/_client/models/password_link_public.py b/src/otari/_client/models/password_link_public.py new file mode 100644 index 00000000..a8e0c449 --- /dev/null +++ b/src/otari/_client/models/password_link_public.py @@ -0,0 +1,98 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class PasswordLinkPublic(BaseModel): + """ + A single-use link that sets an account's password, and whether it was mailed. + """ # noqa: E501 + expires_at: datetime = Field(description="When the link stops working.") + link: Optional[StrictStr] = Field(default=None, description="The link to pass on to the account's owner yourself, set only when mail_sent is false. Choosing a password through it records the address as vouched for rather than proven, since the mailbox never saw the link.") + mail_sent: StrictBool = Field(description="Whether the link was mailed to the account's address. False when this deployment cannot mail links, or the send failed.") + __properties: ClassVar[List[str]] = ["expires_at", "link", "mail_sent"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of PasswordLinkPublic from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if link (nullable) is None + # and model_fields_set contains the field + if self.link is None and "link" in self.model_fields_set: + _dict['link'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of PasswordLinkPublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "expires_at": obj.get("expires_at"), + "link": obj.get("link"), + "mail_sent": obj.get("mail_sent") + }) + return _obj + + diff --git a/src/otari/_client/models/pricing_drift_row.py b/src/otari/_client/models/pricing_drift_row.py index 54402ffc..1c110416 100644 --- a/src/otari/_client/models/pricing_drift_row.py +++ b/src/otari/_client/models/pricing_drift_row.py @@ -27,9 +27,9 @@ class PricingDriftRow(BaseModel): """ A stored deployment rate beside the default it shadows. """ # noqa: E501 - default_input_price_per_million: Optional[Union[StrictFloat, StrictInt]] = Field(description="What genai-prices would meter this key at today. Null when the dataset does not know it.") + default_input_price_per_million: Optional[Union[StrictFloat, StrictInt]] = Field(description="What models.dev would meter this key at today. Null when the dataset does not know it.") default_output_price_per_million: Optional[Union[StrictFloat, StrictInt]] - default_reference: Optional[StrictStr] = Field(description="The genai-prices entry the default came from.") + default_reference: Optional[StrictStr] = Field(description="The models.dev entry the default came from.") effective_at: StrictStr input_delta_percent: Optional[Union[StrictFloat, StrictInt]] = Field(description="(stored - default) / default, as a percentage.") input_price_per_million: Union[StrictFloat, StrictInt] diff --git a/src/otari/_client/models/pricing_refresh_confirmation_response.py b/src/otari/_client/models/pricing_refresh_confirmation_response.py index ef4329a2..b0844974 100644 --- a/src/otari/_client/models/pricing_refresh_confirmation_response.py +++ b/src/otari/_client/models/pricing_refresh_confirmation_response.py @@ -25,7 +25,7 @@ class PricingRefreshConfirmationResponse(BaseModel): """ - Result of activating a reviewed genai-prices refresh. + Result of activating a reviewed models.dev refresh. """ # noqa: E501 applied: Optional[StrictBool] = True __properties: ClassVar[List[str]] = ["applied"] diff --git a/src/otari/_client/models/pricing_refresh_preview_response.py b/src/otari/_client/models/pricing_refresh_preview_response.py index 54c08875..8b25e878 100644 --- a/src/otari/_client/models/pricing_refresh_preview_response.py +++ b/src/otari/_client/models/pricing_refresh_preview_response.py @@ -18,8 +18,8 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, StrictBool, StrictInt -from typing import Any, ClassVar, Dict, List +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional from otari._client.models.pricing_refresh_change_response import PricingRefreshChangeResponse from typing import Optional, Set from typing_extensions import Self @@ -27,16 +27,19 @@ class PricingRefreshPreviewResponse(BaseModel): """ - Reviewable summary of a pending genai-prices refresh. + Reviewable summary of a pending models.dev refresh. """ # noqa: E501 added_count: StrictInt changed_count: StrictInt changes: List[PricingRefreshChangeResponse] changes_truncated: StrictBool + digest: Optional[StrictStr] = Field(default='', description="Identity of the pending snapshot; send it to confirm or reject to act on exactly this one.") fetched_at: datetime + needs_review: Optional[StrictBool] = Field(default=False, description="True when the update is implausibly large; the scheduled `auto` policy leaves it pending.") protected_model_count: StrictInt removed_count: StrictInt - __properties: ClassVar[List[str]] = ["added_count", "changed_count", "changes", "changes_truncated", "fetched_at", "protected_model_count", "removed_count"] + review_reason: Optional[StrictStr] = Field(default=None, description="Why the update needs review.") + __properties: ClassVar[List[str]] = ["added_count", "changed_count", "changes", "changes_truncated", "digest", "fetched_at", "needs_review", "protected_model_count", "removed_count", "review_reason"] model_config = ConfigDict( validate_by_name=True, @@ -84,6 +87,11 @@ def to_dict(self) -> Dict[str, Any]: if _item_changes: _items.append(_item_changes.to_dict()) _dict['changes'] = _items + # set to None if review_reason (nullable) is None + # and model_fields_set contains the field + if self.review_reason is None and "review_reason" in self.model_fields_set: + _dict['review_reason'] = None + return _dict @classmethod @@ -100,9 +108,12 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "changed_count": obj.get("changed_count"), "changes": [PricingRefreshChangeResponse.from_dict(_item) for _item in obj["changes"]] if obj.get("changes") is not None else None, "changes_truncated": obj.get("changes_truncated"), + "digest": obj.get("digest") if obj.get("digest") is not None else '', "fetched_at": obj.get("fetched_at"), + "needs_review": obj.get("needs_review") if obj.get("needs_review") is not None else False, "protected_model_count": obj.get("protected_model_count"), - "removed_count": obj.get("removed_count") + "removed_count": obj.get("removed_count"), + "review_reason": obj.get("review_reason") }) return _obj diff --git a/src/otari/_client/models/pricing_response.py b/src/otari/_client/models/pricing_response.py index 364978b2..e69a7e24 100644 --- a/src/otari/_client/models/pricing_response.py +++ b/src/otari/_client/models/pricing_response.py @@ -29,7 +29,6 @@ class PricingResponse(BaseModel): Response model for model pricing. """ # noqa: E501 cache_read_price_per_million: Optional[Union[StrictFloat, StrictInt]] - cache_write_1h_price_per_million: Optional[Union[StrictFloat, StrictInt]] cache_write_price_per_million: Optional[Union[StrictFloat, StrictInt]] created_at: StrictStr effective_at: StrictStr @@ -40,7 +39,7 @@ class PricingResponse(BaseModel): pricing_tiers: List[PricingTier] unit: StrictStr = Field(description="What the rates are per: tokens, requests, or images.") updated_at: StrictStr - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "created_at", "effective_at", "input_price_per_million", "model_key", "origin", "output_price_per_million", "pricing_tiers", "unit", "updated_at"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "created_at", "effective_at", "input_price_per_million", "model_key", "origin", "output_price_per_million", "pricing_tiers", "unit", "updated_at"] model_config = ConfigDict( validate_by_name=True, @@ -93,11 +92,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -121,7 +115,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "created_at": obj.get("created_at"), "effective_at": obj.get("effective_at"), diff --git a/src/otari/_client/models/pricing_tier.py b/src/otari/_client/models/pricing_tier.py index 2ff1dc49..2a9f9ec5 100644 --- a/src/otari/_client/models/pricing_tier.py +++ b/src/otari/_client/models/pricing_tier.py @@ -29,12 +29,11 @@ class PricingTier(BaseModel): Whole-request price cliff selected by total billable input tokens. """ # noqa: E501 cache_read_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = None - cache_write_1h_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = None cache_write_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = None input_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = None min_input_tokens: Annotated[int, Field(strict=True, gt=0)] output_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = None - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "input_price_per_million", "min_input_tokens", "output_price_per_million"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "input_price_per_million", "min_input_tokens", "output_price_per_million"] model_config = ConfigDict( validate_by_name=True, @@ -80,11 +79,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -113,7 +107,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "input_price_per_million": obj.get("input_price_per_million"), "min_input_tokens": obj.get("min_input_tokens"), diff --git a/src/otari/_client/models/request_password_reset_response.py b/src/otari/_client/models/request_password_reset_response.py index 920bd64d..4848fd30 100644 --- a/src/otari/_client/models/request_password_reset_response.py +++ b/src/otari/_client/models/request_password_reset_response.py @@ -27,7 +27,7 @@ class RequestPasswordResetResponse(BaseModel): """ RequestPasswordResetResponse """ # noqa: E501 - message: StrictStr = Field(description="The same message whether or not the address has a password to reset.") + message: StrictStr = Field(description="The same message whether or not a link was sent.") __properties: ClassVar[List[str]] = ["message"] model_config = ConfigDict( diff --git a/src/otari/_client/models/reset_password_request.py b/src/otari/_client/models/reset_password_request.py index c7c39647..cb1b47e6 100644 --- a/src/otari/_client/models/reset_password_request.py +++ b/src/otari/_client/models/reset_password_request.py @@ -17,8 +17,8 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field -from typing import Any, ClassVar, Dict, List +from pydantic import BaseModel, ConfigDict, Field, StrictBool +from typing import Any, ClassVar, Dict, List, Optional from typing_extensions import Annotated from typing import Optional, Set from typing_extensions import Self @@ -29,8 +29,9 @@ class ResetPasswordRequest(BaseModel): ResetPasswordRequest """ # noqa: E501 new_password: Annotated[str, Field(min_length=8, strict=True, max_length=1024)] = Field(description="The password to sign in with from now on. At least 8 characters, at most 72 bytes.") + terms_accepted: Optional[StrictBool] = Field(default=False, description="Whether the caller accepted this deployment's terms. Required where the bootstrap reports a terms_url and the account has not accepted them yet.") token: Annotated[str, Field(strict=True, max_length=512)] = Field(description="The token from the reset link.") - __properties: ClassVar[List[str]] = ["new_password", "token"] + __properties: ClassVar[List[str]] = ["new_password", "terms_accepted", "token"] model_config = ConfigDict( validate_by_name=True, @@ -84,6 +85,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "new_password": obj.get("new_password"), + "terms_accepted": obj.get("terms_accepted") if obj.get("terms_accepted") is not None else False, "token": obj.get("token") }) return _obj diff --git a/src/otari/_client/models/search_request.py b/src/otari/_client/models/search_request.py index 798d3c6b..b28b0b46 100644 --- a/src/otari/_client/models/search_request.py +++ b/src/otari/_client/models/search_request.py @@ -17,7 +17,7 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional from typing_extensions import Annotated from typing import Optional, Set @@ -26,16 +26,18 @@ class SearchRequest(BaseModel): """ - A search request, following LiteLLM's ``/v1/search`` body. + A direct search request: LiteLLM's ``/v1/search`` body, plus ``include_raw`` and ``provider_options``. """ # noqa: E501 country: Optional[Annotated[str, Field(min_length=2, strict=True, max_length=2)]] = Field(default=None, description="Two-letter ISO country code to localize results to") - max_results: Optional[Annotated[int, Field(le=20, strict=True, ge=1)]] = Field(default=None, description="Maximum number of results to return") + include_raw: Optional[StrictBool] = Field(default=False, description="Also return the provider's whole response, as raw.") + max_results: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Maximum number of results to return; 10 when unset. Lowered to the workspace's ceiling when it sets one, and to the provider's own maximum.") max_tokens_per_page: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Approximate cap on the page content returned per result") + provider_options: Optional[Dict[str, Any]] = Field(default=None, description="Tags for cost attribution, recorded on the request's usage rows and filterable in the usage API: up to 16 string pairs, keys up to 64 characters and values up to 512. A null value is ignored. LiteLLM's nested `spend_logs_metadata` object is also read, and wins over a flat key of the same name; it is never forwarded to the provider.") query: Annotated[str, Field(min_length=1, strict=True)] = Field(description="The search query") search_domain_filter: Optional[Annotated[List[StrictStr], Field(max_length=20)]] = Field(default=None, description="Restrict results to these domains; prefix a domain with '-' to exclude it instead") - search_tool_name: Optional[StrictStr] = Field(default=None, description="Configured search tool to run against. Optional when exactly one tool is configured, and ignored on POST /api/v1/search/{search_tool_name}.") + search_tool_name: Optional[StrictStr] = Field(default=None, description="Configured search tool to run against. Optional when the deployment names a default (web_search_default_tool) or has exactly one tool, and ignored on POST /api/v1/search/{search_tool_name}.") user: Optional[StrictStr] = Field(default=None, description="User ID for usage attribution") - __properties: ClassVar[List[str]] = ["country", "max_results", "max_tokens_per_page", "query", "search_domain_filter", "search_tool_name", "user"] + __properties: ClassVar[List[str]] = ["country", "include_raw", "max_results", "max_tokens_per_page", "provider_options", "query", "search_domain_filter", "search_tool_name", "user"] model_config = ConfigDict( validate_by_name=True, @@ -91,6 +93,11 @@ def to_dict(self) -> Dict[str, Any]: if self.max_tokens_per_page is None and "max_tokens_per_page" in self.model_fields_set: _dict['max_tokens_per_page'] = None + # set to None if provider_options (nullable) is None + # and model_fields_set contains the field + if self.provider_options is None and "provider_options" in self.model_fields_set: + _dict['provider_options'] = None + # set to None if search_domain_filter (nullable) is None # and model_fields_set contains the field if self.search_domain_filter is None and "search_domain_filter" in self.model_fields_set: @@ -119,8 +126,10 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "country": obj.get("country"), + "include_raw": obj.get("include_raw") if obj.get("include_raw") is not None else False, "max_results": obj.get("max_results"), "max_tokens_per_page": obj.get("max_tokens_per_page"), + "provider_options": obj.get("provider_options"), "query": obj.get("query"), "search_domain_filter": obj.get("search_domain_filter"), "search_tool_name": obj.get("search_tool_name"), diff --git a/src/otari/_client/models/search_response.py b/src/otari/_client/models/search_response.py index ca2518c8..36a839c0 100644 --- a/src/otari/_client/models/search_response.py +++ b/src/otari/_client/models/search_response.py @@ -26,12 +26,13 @@ class SearchResponse(BaseModel): """ - A completed search. + A completed direct search. """ # noqa: E501 object: Optional[StrictStr] = 'search' + raw: Optional[Dict[str, Any]] = Field(default=None, description="Tags for cost attribution, recorded on the request's usage rows and filterable in the usage API: up to 16 string pairs, keys up to 64 characters and values up to 512. A null value is ignored. LiteLLM's nested `spend_logs_metadata` object is also read, and wins over a flat key of the same name; it is never forwarded to the provider.") results: List[SearchResultItem] search_tool: StrictStr = Field(description="The configured search tool that served the request") - __properties: ClassVar[List[str]] = ["object", "results", "search_tool"] + __properties: ClassVar[List[str]] = ["object", "raw", "results", "search_tool"] @field_validator('object') def object_validate_enum(cls, value): @@ -89,6 +90,11 @@ def to_dict(self) -> Dict[str, Any]: if _item_results: _items.append(_item_results.to_dict()) _dict['results'] = _items + # set to None if raw (nullable) is None + # and model_fields_set contains the field + if self.raw is None and "raw" in self.model_fields_set: + _dict['raw'] = None + return _dict @classmethod @@ -102,6 +108,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "object": obj.get("object") if obj.get("object") is not None else 'search', + "raw": obj.get("raw"), "results": [SearchResultItem.from_dict(_item) for _item in obj["results"]] if obj.get("results") is not None else None, "search_tool": obj.get("search_tool") }) diff --git a/src/otari/_client/models/search_result_item.py b/src/otari/_client/models/search_result_item.py index 53b25950..648c96cc 100644 --- a/src/otari/_client/models/search_result_item.py +++ b/src/otari/_client/models/search_result_item.py @@ -25,13 +25,14 @@ class SearchResultItem(BaseModel): """ - One search result. + One search result, shaped as LiteLLM's ``SearchResult``. """ # noqa: E501 - var_date: Optional[StrictStr] = Field(default=None, alias="date") - snippet: Optional[StrictStr] = None - title: Optional[StrictStr] = None + var_date: Optional[StrictStr] = Field(default=None, description="The page's date, as the provider gave it.", alias="date") + last_updated: Optional[StrictStr] = Field(default=None, description="Always null: no provider reports it.") + snippet: StrictStr = Field(description="The page text the provider returned, else its excerpt, cut to the page budget.") + title: StrictStr = Field(description="The page's title; empty when the provider gave none.") url: StrictStr - __properties: ClassVar[List[str]] = ["date", "snippet", "title", "url"] + __properties: ClassVar[List[str]] = ["date", "last_updated", "snippet", "title", "url"] model_config = ConfigDict( validate_by_name=True, @@ -77,15 +78,10 @@ def to_dict(self) -> Dict[str, Any]: if self.var_date is None and "var_date" in self.model_fields_set: _dict['date'] = None - # set to None if snippet (nullable) is None + # set to None if last_updated (nullable) is None # and model_fields_set contains the field - if self.snippet is None and "snippet" in self.model_fields_set: - _dict['snippet'] = None - - # set to None if title (nullable) is None - # and model_fields_set contains the field - if self.title is None and "title" in self.model_fields_set: - _dict['title'] = None + if self.last_updated is None and "last_updated" in self.model_fields_set: + _dict['last_updated'] = None return _dict @@ -100,6 +96,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "date": obj.get("date"), + "last_updated": obj.get("last_updated"), "snippet": obj.get("snippet"), "title": obj.get("title"), "url": obj.get("url") diff --git a/src/otari/_client/models/search_tool_test_response.py b/src/otari/_client/models/search_tool_test_response.py index 4ac84ca3..df60e5ef 100644 --- a/src/otari/_client/models/search_tool_test_response.py +++ b/src/otari/_client/models/search_tool_test_response.py @@ -28,7 +28,7 @@ class SearchToolTestResponse(BaseModel): How one search or one fetch went. Never the results or the page. """ # noqa: E501 characters: Optional[StrictInt] = Field(default=None, description="For a fetch that worked: how many characters of page text came back.") - error: Optional[StrictStr] = Field(default=None, description="When not ok, the error's tag: timeout, network, http_error, invalid_response, or the provider's own.") + error: Optional[StrictStr] = Field(default=None, description="When not ok, the error's tag: timeout, network, http_error, invalid_response, unexpected_response (an answer whose shape the provider changed), or the provider's own.") hits: Optional[StrictInt] = Field(default=None, description="For a search that worked: how many hits came back.") ok: StrictBool = Field(description="Whether the provider answered the call without an error.") __properties: ClassVar[List[str]] = ["characters", "error", "hits", "ok"] diff --git a/src/otari/_client/models/session_response.py b/src/otari/_client/models/session_response.py index 6a6730d9..bb648cf9 100644 --- a/src/otari/_client/models/session_response.py +++ b/src/otari/_client/models/session_response.py @@ -19,7 +19,7 @@ from datetime import datetime from pydantic import BaseModel, ConfigDict, Field -from typing import Any, ClassVar, Dict, List +from typing import Any, ClassVar, Dict, List, Optional from uuid import UUID from typing import Optional, Set from typing_extensions import Self @@ -29,7 +29,7 @@ class SessionResponse(BaseModel): """ A freshly minted dashboard session (the token travels only in the cookie). """ # noqa: E501 - active_organization_id: UUID = Field(description="The organization that identity is acting in, which scopes every tenancy surface.") + active_organization_id: Optional[UUID] = Field(description="The organization that identity is acting in, which scopes every tenancy surface. Null when it is an active member of none, as an invitee who has not accepted yet is not.") expires_at: datetime = Field(description="When the session cookie stops being accepted.") user_id: UUID = Field(description="The identity this session speaks for.") __properties: ClassVar[List[str]] = ["active_organization_id", "expires_at", "user_id"] @@ -73,6 +73,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if active_organization_id (nullable) is None + # and model_fields_set contains the field + if self.active_organization_id is None and "active_organization_id" in self.model_fields_set: + _dict['active_organization_id'] = None + return _dict @classmethod diff --git a/src/otari/_client/models/set_password_request.py b/src/otari/_client/models/set_password_request.py index f4376a12..631d77e6 100644 --- a/src/otari/_client/models/set_password_request.py +++ b/src/otari/_client/models/set_password_request.py @@ -29,7 +29,7 @@ class SetPasswordRequest(BaseModel): Set or change the signed-in identity's password. The example is the first-boot claim, because that is the call an operator makes first and the one whose required fields are not obvious from the schema: ``email`` is optional here in general and *required* when the identity has no address yet. Without it the generated Postman body carries only ``new_password``, which is the one shape that cannot complete the flow the docs walk through. """ # noqa: E501 current_password: Optional[Annotated[str, Field(strict=True, max_length=1024)]] = Field(default=None, description="The password being replaced. Required when the identity already has one and the request is authenticated by the session cookie; ignored when the master key is sent in a header, which needs no proof of the old password (it still needs `email` when the identity has no sign-in address yet).") - email: Optional[Annotated[str, Field(strict=True, max_length=255)]] = Field(default=None, description="The address to sign in with. Required when the identity has none, which is the state first boot leaves the operator in, including when the master key is what authenticates the call. Resubmitting the address the identity already holds is accepted and ignored; only a *different* address is refused, because changing one is not supported yet.") + email: Optional[Annotated[str, Field(strict=True, max_length=255)]] = Field(default=None, description="The address to sign in with. Required when the identity has none, which is the state first boot leaves the operator in, including when the master key is what authenticates the call. Resubmitting the address the identity already holds is accepted and ignored; only a *different* address is refused, because changing one is not supported yet. It is always the caller's own address, the operator's when the master key authenticates the call, and never names another account.") new_password: Annotated[str, Field(min_length=8, strict=True, max_length=1024)] = Field(description="The password to sign in with from now on. At least 8 characters, and at most 72 bytes, which is bcrypt's ceiling.") __properties: ClassVar[List[str]] = ["current_password", "email", "new_password"] diff --git a/src/otari/_client/models/set_pricing_request.py b/src/otari/_client/models/set_pricing_request.py index ec2bf055..262ffaf1 100644 --- a/src/otari/_client/models/set_pricing_request.py +++ b/src/otari/_client/models/set_pricing_request.py @@ -31,7 +31,6 @@ class SetPricingRequest(BaseModel): Create a versioned per-model price, with optional cache and context tiers. """ # noqa: E501 cache_read_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cached-input tokens") - cache_write_1h_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M Anthropic 1-hour cache-write tokens") cache_write_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cache-write (creation) tokens") effective_at: Optional[datetime] = Field(default=None, description="ISO 8601 datetime from which this price applies. Defaults to now if omitted.") input_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M of the rate's unit: input tokens, requests or images") @@ -39,7 +38,7 @@ class SetPricingRequest(BaseModel): output_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M output tokens; unused by a rate in requests or images") pricing_tiers: Optional[List[PricingTier]] = Field(default=None, description="Whole-request context thresholds. Fields omitted by a tier inherit the base rate.") unit: Optional[StrictStr] = Field(default='tokens', description="What the rates are per: 'tokens' for a model, 'requests' for a gateway-run tool, a moderation call, or a completion model billed per call (USD per million requests), 'images' for image generation (USD per million images).") - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_1h_price_per_million", "cache_write_price_per_million", "effective_at", "input_price_per_million", "model_key", "output_price_per_million", "pricing_tiers", "unit"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "effective_at", "input_price_per_million", "model_key", "output_price_per_million", "pricing_tiers", "unit"] @field_validator('unit') def unit_validate_enum(cls, value): @@ -102,11 +101,6 @@ def to_dict(self) -> Dict[str, Any]: if self.cache_read_price_per_million is None and "cache_read_price_per_million" in self.model_fields_set: _dict['cache_read_price_per_million'] = None - # set to None if cache_write_1h_price_per_million (nullable) is None - # and model_fields_set contains the field - if self.cache_write_1h_price_per_million is None and "cache_write_1h_price_per_million" in self.model_fields_set: - _dict['cache_write_1h_price_per_million'] = None - # set to None if cache_write_price_per_million (nullable) is None # and model_fields_set contains the field if self.cache_write_price_per_million is None and "cache_write_price_per_million" in self.model_fields_set: @@ -135,7 +129,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "cache_read_price_per_million": obj.get("cache_read_price_per_million"), - "cache_write_1h_price_per_million": obj.get("cache_write_1h_price_per_million"), "cache_write_price_per_million": obj.get("cache_write_price_per_million"), "effective_at": obj.get("effective_at"), "input_price_per_million": obj.get("input_price_per_million"), diff --git a/src/otari/_client/models/signup_request.py b/src/otari/_client/models/signup_request.py index aae8c1f3..f6e278c0 100644 --- a/src/otari/_client/models/signup_request.py +++ b/src/otari/_client/models/signup_request.py @@ -31,7 +31,7 @@ class SignupRequest(BaseModel): email: Annotated[str, Field(strict=True, max_length=255)] = Field(description="The address to sign in with. An address an admin added or invited where this deployment keeps signup closed; any address where the bootstrap reports open_signup.") full_name: Optional[Annotated[str, Field(strict=True, max_length=255)]] = Field(default=None, description="Filled in only if not already set.") password: Annotated[str, Field(min_length=8, strict=True, max_length=1024)] = Field(description="The password to sign in with once verified. At least 8 characters, at most 72 bytes.") - terms_accepted: Optional[StrictBool] = Field(default=False, description="Whether the caller accepted this deployment's terms.") + terms_accepted: Optional[StrictBool] = Field(default=False, description="Whether the caller accepted this deployment's terms. Required where the bootstrap reports a terms_url.") __properties: ClassVar[List[str]] = ["email", "full_name", "password", "terms_accepted"] model_config = ConfigDict( diff --git a/src/otari/_client/models/verify_email_request.py b/src/otari/_client/models/verify_email_request.py index 22f7b3fc..2fd20e7b 100644 --- a/src/otari/_client/models/verify_email_request.py +++ b/src/otari/_client/models/verify_email_request.py @@ -28,8 +28,9 @@ class VerifyEmailRequest(BaseModel): """ VerifyEmailRequest """ # noqa: E501 + password: Annotated[str, Field(strict=True, max_length=1024)] = Field(description="The password chosen at signup. The link verifies the address only together with it, so a link that reaches someone who did not sign up verifies nothing.") token: Annotated[str, Field(strict=True, max_length=512)] = Field(description="The token from the verification link.") - __properties: ClassVar[List[str]] = ["token"] + __properties: ClassVar[List[str]] = ["password", "token"] model_config = ConfigDict( validate_by_name=True, @@ -82,6 +83,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "password": obj.get("password"), "token": obj.get("token") }) return _obj diff --git a/src/otari/_client/models/workspace_code_execution_policy_public.py b/src/otari/_client/models/workspace_code_execution_policy_public.py index c2d5b316..3debab6f 100644 --- a/src/otari/_client/models/workspace_code_execution_policy_public.py +++ b/src/otari/_client/models/workspace_code_execution_policy_public.py @@ -33,6 +33,7 @@ class WorkspaceCodeExecutionPolicyPublic(BaseModel): available_tools: List[StrictStr] configured: StrictBool created_at: Optional[StrictStr] + default_enabled: StrictBool default_purpose_hint: Optional[StrictStr] enabled: StrictBool exec_timeout_s: Optional[StrictInt] @@ -43,7 +44,7 @@ class WorkspaceCodeExecutionPolicyPublic(BaseModel): tools: Optional[List[StrictStr]] updated_at: Optional[StrictStr] workspace_id: UUID - __properties: ClassVar[List[str]] = ["allowed_images", "available_tools", "configured", "created_at", "default_purpose_hint", "enabled", "exec_timeout_s", "executor", "image", "max_iterations", "sandbox_configured", "tools", "updated_at", "workspace_id"] + __properties: ClassVar[List[str]] = ["allowed_images", "available_tools", "configured", "created_at", "default_enabled", "default_purpose_hint", "enabled", "exec_timeout_s", "executor", "image", "max_iterations", "sandbox_configured", "tools", "updated_at", "workspace_id"] model_config = ConfigDict( validate_by_name=True, @@ -140,6 +141,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "available_tools": obj.get("available_tools"), "configured": obj.get("configured"), "created_at": obj.get("created_at"), + "default_enabled": obj.get("default_enabled"), "default_purpose_hint": obj.get("default_purpose_hint"), "enabled": obj.get("enabled"), "exec_timeout_s": obj.get("exec_timeout_s"), diff --git a/src/otari/_client/models/workspace_web_search_config_public.py b/src/otari/_client/models/workspace_web_search_config_public.py index 3bd8db3b..1b5999f0 100644 --- a/src/otari/_client/models/workspace_web_search_config_public.py +++ b/src/otari/_client/models/workspace_web_search_config_public.py @@ -32,6 +32,7 @@ class WorkspaceWebSearchConfigPublic(BaseModel): blocked_domains: Optional[List[StrictStr]] configured: StrictBool created_at: Optional[StrictStr] + default_enabled: StrictBool enabled: StrictBool max_results: Optional[StrictInt] provider_options: Optional[Dict[str, Any]] = Field(description="Tags for cost attribution, recorded on the request's usage rows and filterable in the usage API: up to 16 string pairs, keys up to 64 characters and values up to 512. A null value is ignored. LiteLLM's nested `spend_logs_metadata` object is also read, and wins over a flat key of the same name; it is never forwarded to the provider.") @@ -39,7 +40,7 @@ class WorkspaceWebSearchConfigPublic(BaseModel): updated_at: Optional[StrictStr] web_search_configured: StrictBool workspace_id: UUID - __properties: ClassVar[List[str]] = ["allowed_domains", "blocked_domains", "configured", "created_at", "enabled", "max_results", "provider_options", "purpose_hint", "updated_at", "web_search_configured", "workspace_id"] + __properties: ClassVar[List[str]] = ["allowed_domains", "blocked_domains", "configured", "created_at", "default_enabled", "enabled", "max_results", "provider_options", "purpose_hint", "updated_at", "web_search_configured", "workspace_id"] model_config = ConfigDict( validate_by_name=True, @@ -131,6 +132,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "blocked_domains": obj.get("blocked_domains"), "configured": obj.get("configured"), "created_at": obj.get("created_at"), + "default_enabled": obj.get("default_enabled"), "enabled": obj.get("enabled"), "max_results": obj.get("max_results"), "provider_options": obj.get("provider_options"), diff --git a/src/otari/_client/models/workspace_web_search_config_update.py b/src/otari/_client/models/workspace_web_search_config_update.py index 4419f856..5f03c191 100644 --- a/src/otari/_client/models/workspace_web_search_config_update.py +++ b/src/otari/_client/models/workspace_web_search_config_update.py @@ -31,7 +31,7 @@ class WorkspaceWebSearchConfigUpdate(BaseModel): allowed_domains: Optional[List[StrictStr]] = Field(default=None, description="Filters Search results and constrains initial and redirected Fetch destinations; intersected with any list the request sends") blocked_domains: Optional[List[StrictStr]] = Field(default=None, description="Filters Search results and blocks initial and redirected Fetch destinations; added to any list the request sends") enabled: StrictBool = Field(description="False refuses web access for this workspace through otari_web_search, otari_web_fetch, and POST /api/v1/search.") - max_results: Optional[Annotated[int, Field(le=20, strict=True, gt=0)]] = Field(default=None, description="Search only: ceiling on results one search returns; only ever lowers the effective limit, so at most 20") + max_results: Optional[Annotated[int, Field(le=2147483647, strict=True, gt=0)]] = Field(default=None, description="Search only: ceiling on results one search returns, through otari_web_search and POST /api/v1/search; it only ever lowers the count a request asks for. Unset, the provider's own maximum is the only limit.") provider_options: Optional[Dict[str, Any]] = Field(default=None, description="Tags for cost attribution, recorded on the request's usage rows and filterable in the usage API: up to 16 string pairs, keys up to 64 characters and values up to 512. A null value is ignored. LiteLLM's nested `spend_logs_metadata` object is also read, and wins over a flat key of the same name; it is never forwarded to the provider.") purpose_hint: Optional[Annotated[str, Field(strict=True, max_length=2048)]] = Field(default=None, description="Search only: hint used when a request declares otari_web_search without one of its own") __properties: ClassVar[List[str]] = ["allowed_domains", "blocked_domains", "enabled", "max_results", "provider_options", "purpose_hint"]