From 6423d6a0a563755142bbe13648d9a16ca7f91a73 Mon Sep 17 00:00:00 2001 From: daavoo <12677733+daavoo@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:46:37 +0000 Subject: [PATCH] feat: regenerate SDK client core from Otari OpenAPI spec --- sdk-endpoints.txt | 4 + src/otari/_client/__init__.py | 10 + src/otari/_client/api/hooks_api.py | 280 +++++ src/otari/_client/api/oauth_api.py | 6 +- .../_client/api/organization_keys_api.py | 974 ++++++++++++++++-- src/otari/_client/models/__init__.py | 5 + .../_client/models/deployment_bootstrap.py | 4 +- .../_client/models/federation_rule_create.py | 2 +- .../_client/models/federation_rule_public.py | 6 +- .../_client/models/gate_definition_request.py | 128 +++ .../_client/models/gate_summary_public.py | 136 +++ .../models/guardrail_definition_request.py | 109 ++ .../models/guardrail_definition_response.py | 88 ++ .../_client/models/model_architecture.py | 90 ++ src/otari/_client/models/model_object.py | 29 +- .../_client/models/trace_detail_public.py | 12 +- 16 files changed, 1806 insertions(+), 77 deletions(-) create mode 100644 src/otari/_client/models/gate_definition_request.py create mode 100644 src/otari/_client/models/gate_summary_public.py create mode 100644 src/otari/_client/models/guardrail_definition_request.py create mode 100644 src/otari/_client/models/guardrail_definition_response.py create mode 100644 src/otari/_client/models/model_architecture.py diff --git a/sdk-endpoints.txt b/sdk-endpoints.txt index 3f8f51ddf..1db4c6c45 100644 --- a/sdk-endpoints.txt +++ b/sdk-endpoints.txt @@ -275,6 +275,7 @@ GET /api/v1/agent-telemetry/series # not yet wrapped DELETE /api/v1/agent-telemetry # not yet wrapped # Agent Gates' Hook Server: a hook-protocol endpoint for agent tooling, not an SDK surface POST /api/v1/hooks/check # not yet wrapped +POST /api/v1/hooks/guardrails # not yet wrapped # Routing policies GET /api/v1/routing/policies # not yet wrapped POST /api/v1/routing/policies # not yet wrapped @@ -389,6 +390,9 @@ POST /api/v1/organizations/me/keys # dashboard-only PATCH /api/v1/organizations/me/keys/{key_id} # dashboard-only DELETE /api/v1/organizations/me/keys/{key_id} # dashboard-only POST /api/v1/organizations/me/keys/{key_id}/rotate # dashboard-only +POST /api/v1/organizations/me/keys/{key_id}/federation-rules # dashboard-only +GET /api/v1/organizations/me/keys/{key_id}/federation-rules # dashboard-only +DELETE /api/v1/organizations/me/keys/{key_id}/federation-rules/{rule_id} # dashboard-only # The organization's own budgets and the ceilings enforcing them # (otari-ai#1943), excluded for the same reason as the keys above: the # organization is resolved from the caller's dashboard session rather than named diff --git a/src/otari/_client/__init__.py b/src/otari/_client/__init__.py index 74e0aecdd..929f35c66 100644 --- a/src/otari/_client/__init__.py +++ b/src/otari/_client/__init__.py @@ -299,11 +299,15 @@ "FederationTokenRequest", "FederationTokenResponse", "FeedbackSubmission", + "GateDefinitionRequest", "GateResultResponse", + "GateSummaryPublic", "GatewaySettings", "GuardrailCatalog", "GuardrailCategory", "GuardrailConfig", + "GuardrailDefinitionRequest", + "GuardrailDefinitionResponse", "GuardrailParameterSpec", "GuardrailProfileSpec", "GuardrailStage", @@ -513,6 +517,7 @@ "MessagesRequest", "Model", "Model1", + "ModelArchitecture", "ModelFalse", "ModelListResponse", "ModelMetadata", @@ -1070,11 +1075,15 @@ from otari._client.models.federation_token_request import FederationTokenRequest as FederationTokenRequest from otari._client.models.federation_token_response import FederationTokenResponse as FederationTokenResponse from otari._client.models.feedback_submission import FeedbackSubmission as FeedbackSubmission +from otari._client.models.gate_definition_request import GateDefinitionRequest as GateDefinitionRequest from otari._client.models.gate_result_response import GateResultResponse as GateResultResponse +from otari._client.models.gate_summary_public import GateSummaryPublic as GateSummaryPublic from otari._client.models.gateway_settings import GatewaySettings as GatewaySettings from otari._client.models.guardrail_catalog import GuardrailCatalog as GuardrailCatalog from otari._client.models.guardrail_category import GuardrailCategory as GuardrailCategory from otari._client.models.guardrail_config import GuardrailConfig as GuardrailConfig +from otari._client.models.guardrail_definition_request import GuardrailDefinitionRequest as GuardrailDefinitionRequest +from otari._client.models.guardrail_definition_response import GuardrailDefinitionResponse as GuardrailDefinitionResponse from otari._client.models.guardrail_parameter_spec import GuardrailParameterSpec as GuardrailParameterSpec from otari._client.models.guardrail_profile_spec import GuardrailProfileSpec as GuardrailProfileSpec from otari._client.models.guardrail_stage import GuardrailStage as GuardrailStage @@ -1284,6 +1293,7 @@ from otari._client.models.messages_request import MessagesRequest as MessagesRequest from otari._client.models.model import Model as Model from otari._client.models.model1 import Model1 as Model1 +from otari._client.models.model_architecture import ModelArchitecture as ModelArchitecture from otari._client.models.model_false import ModelFalse as ModelFalse from otari._client.models.model_list_response import ModelListResponse as ModelListResponse from otari._client.models.model_metadata import ModelMetadata as ModelMetadata diff --git a/src/otari/_client/api/hooks_api.py b/src/otari/_client/api/hooks_api.py index 2800e7688..eaaab18eb 100644 --- a/src/otari/_client/api/hooks_api.py +++ b/src/otari/_client/api/hooks_api.py @@ -15,6 +15,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated +from otari._client.models.guardrail_definition_request import GuardrailDefinitionRequest +from otari._client.models.guardrail_definition_response import GuardrailDefinitionResponse from otari._client.models.policy_check_request import PolicyCheckRequest from otari._client.models.policy_check_response import PolicyCheckResponse @@ -312,3 +314,281 @@ def _hooks_check_policy_serialize( ) + + + @validate_call + def hooks_record_guardrail_definition( + self, + guardrail_definition_request: GuardrailDefinitionRequest, + _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, + ) -> GuardrailDefinitionResponse: + """Record Guardrail Definition + + Keep one version of an agent guardrail, so the gate spans that name it can say what each gate is for. `otari hook` sends this once per version, the first time it reports a check against it. The fingerprint is recomputed from the gates, and one that does not match the one sent is refused, so a version cannot be stored under another's name. Sending a version again changes nothing. It is stored in the API key's workspace, beside that key's traces, and takes the same key a trace export does: a budget-exempt API key, never the master key. + + :param guardrail_definition_request: (required) + :type guardrail_definition_request: GuardrailDefinitionRequest + :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._hooks_record_guardrail_definition_serialize( + guardrail_definition_request=guardrail_definition_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "GuardrailDefinitionResponse", + '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 hooks_record_guardrail_definition_with_http_info( + self, + guardrail_definition_request: GuardrailDefinitionRequest, + _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[GuardrailDefinitionResponse]: + """Record Guardrail Definition + + Keep one version of an agent guardrail, so the gate spans that name it can say what each gate is for. `otari hook` sends this once per version, the first time it reports a check against it. The fingerprint is recomputed from the gates, and one that does not match the one sent is refused, so a version cannot be stored under another's name. Sending a version again changes nothing. It is stored in the API key's workspace, beside that key's traces, and takes the same key a trace export does: a budget-exempt API key, never the master key. + + :param guardrail_definition_request: (required) + :type guardrail_definition_request: GuardrailDefinitionRequest + :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._hooks_record_guardrail_definition_serialize( + guardrail_definition_request=guardrail_definition_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "GuardrailDefinitionResponse", + '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 hooks_record_guardrail_definition_without_preload_content( + self, + guardrail_definition_request: GuardrailDefinitionRequest, + _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: + """Record Guardrail Definition + + Keep one version of an agent guardrail, so the gate spans that name it can say what each gate is for. `otari hook` sends this once per version, the first time it reports a check against it. The fingerprint is recomputed from the gates, and one that does not match the one sent is refused, so a version cannot be stored under another's name. Sending a version again changes nothing. It is stored in the API key's workspace, beside that key's traces, and takes the same key a trace export does: a budget-exempt API key, never the master key. + + :param guardrail_definition_request: (required) + :type guardrail_definition_request: GuardrailDefinitionRequest + :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._hooks_record_guardrail_definition_serialize( + guardrail_definition_request=guardrail_definition_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "GuardrailDefinitionResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _hooks_record_guardrail_definition_serialize( + self, + guardrail_definition_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 guardrail_definition_request is not None: + _body_params = guardrail_definition_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/hooks/guardrails', + 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/oauth_api.py b/src/otari/_client/api/oauth_api.py index 645c3abe5..a2ff981d2 100644 --- a/src/otari/_client/api/oauth_api.py +++ b/src/otari/_client/api/oauth_api.py @@ -55,7 +55,7 @@ def oauth_exchange_token( ) -> FederationTokenResponse: """Exchange Token - Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must verify against an issuer on ``federation_issuers`` and match the federation rule ``federation_rule_id`` names. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. + Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must match the federation rule ``federation_rule_id`` names and verify against its issuer: one on ``federation_issuers`` for an operator's rule, the one the rule names for a member's. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. :param federation_token_request: (required) :type federation_token_request: FederationTokenRequest @@ -126,7 +126,7 @@ def oauth_exchange_token_with_http_info( ) -> ApiResponse[FederationTokenResponse]: """Exchange Token - Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must verify against an issuer on ``federation_issuers`` and match the federation rule ``federation_rule_id`` names. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. + Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must match the federation rule ``federation_rule_id`` names and verify against its issuer: one on ``federation_issuers`` for an operator's rule, the one the rule names for a member's. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. :param federation_token_request: (required) :type federation_token_request: FederationTokenRequest @@ -197,7 +197,7 @@ def oauth_exchange_token_without_preload_content( ) -> RESTResponseType: """Exchange Token - Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must verify against an issuer on ``federation_issuers`` and match the federation rule ``federation_rule_id`` names. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. + Exchange an identity token for an access token (the RFC 7523 ``jwt-bearer`` grant). The identity token must match the federation rule ``federation_rule_id`` names and verify against its issuer: one on ``federation_issuers`` for an operator's rule, the one the rule names for a member's. ``organization_id``, ``workspace_id`` and ``service_account_id``, where set, must be the UUIDs of the rule's key's organization and workspace and the key's id. The access token authenticates as that key until ``expires_in`` runs out, the rule is deleted or the key stops passing its checks. Every refusal of the identity token answers 401 ``invalid_grant`` with the same description. :param federation_token_request: (required) :type federation_token_request: FederationTokenRequest diff --git a/src/otari/_client/api/organization_keys_api.py b/src/otari/_client/api/organization_keys_api.py index e48efccbe..7a09a51e1 100644 --- a/src/otari/_client/api/organization_keys_api.py +++ b/src/otari/_client/api/organization_keys_api.py @@ -21,6 +21,8 @@ from uuid import UUID from otari._client.models.create_key_response import CreateKeyResponse from otari._client.models.create_own_key_request import CreateOwnKeyRequest +from otari._client.models.federation_rule_create import FederationRuleCreate +from otari._client.models.federation_rule_public import FederationRulePublic from otari._client.models.key_info import KeyInfo from otari._client.models.update_own_key_request import UpdateOwnKeyRequest @@ -42,10 +44,726 @@ def __init__(self, api_client=None) -> None: self.api_client = api_client + @validate_call + def organization_keys_create_own_federation_rule( + self, + key_id: StrictStr, + federation_rule_create: FederationRuleCreate, + _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, + ) -> FederationRulePublic: + """Create Own Federation Rule + + Let an OpenID Connect identity token stand in for a key, through the token exchange. Needs ``federation_member_rules``, else 403, and an organization owner or admin acting on their own key, or the deployment operator on any key in their active organization, else 403. The issuer may be any https URL; its signing keys are fetched only from a public host. The rule matches only in ``POST /api/v1/oauth/token`` naming its id, never as a bare identity token, so it lets a workload act as this key and no other: a rule naming another tenant's workload gives that workload nothing it did not ask for. A rule this key already holds answers 409. + + :param key_id: (required) + :type key_id: str + :param federation_rule_create: (required) + :type federation_rule_create: FederationRuleCreate + :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_keys_create_own_federation_rule_serialize( + key_id=key_id, + federation_rule_create=federation_rule_create, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "FederationRulePublic", + '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_keys_create_own_federation_rule_with_http_info( + self, + key_id: StrictStr, + federation_rule_create: FederationRuleCreate, + _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[FederationRulePublic]: + """Create Own Federation Rule + + Let an OpenID Connect identity token stand in for a key, through the token exchange. Needs ``federation_member_rules``, else 403, and an organization owner or admin acting on their own key, or the deployment operator on any key in their active organization, else 403. The issuer may be any https URL; its signing keys are fetched only from a public host. The rule matches only in ``POST /api/v1/oauth/token`` naming its id, never as a bare identity token, so it lets a workload act as this key and no other: a rule naming another tenant's workload gives that workload nothing it did not ask for. A rule this key already holds answers 409. + + :param key_id: (required) + :type key_id: str + :param federation_rule_create: (required) + :type federation_rule_create: FederationRuleCreate + :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_keys_create_own_federation_rule_serialize( + key_id=key_id, + federation_rule_create=federation_rule_create, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "FederationRulePublic", + '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_keys_create_own_federation_rule_without_preload_content( + self, + key_id: StrictStr, + federation_rule_create: FederationRuleCreate, + _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: + """Create Own Federation Rule + + Let an OpenID Connect identity token stand in for a key, through the token exchange. Needs ``federation_member_rules``, else 403, and an organization owner or admin acting on their own key, or the deployment operator on any key in their active organization, else 403. The issuer may be any https URL; its signing keys are fetched only from a public host. The rule matches only in ``POST /api/v1/oauth/token`` naming its id, never as a bare identity token, so it lets a workload act as this key and no other: a rule naming another tenant's workload gives that workload nothing it did not ask for. A rule this key already holds answers 409. + + :param key_id: (required) + :type key_id: str + :param federation_rule_create: (required) + :type federation_rule_create: FederationRuleCreate + :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_keys_create_own_federation_rule_serialize( + key_id=key_id, + federation_rule_create=federation_rule_create, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '201': "FederationRulePublic", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _organization_keys_create_own_federation_rule_serialize( + self, + key_id, + federation_rule_create, + _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 + # process the header parameters + # process the form parameters + # process the body parameter + if federation_rule_create is not None: + _body_params = federation_rule_create + + + # 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/organizations/me/keys/{key_id}/federation-rules', + 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_keys_create_own_key( self, - create_own_key_request: CreateOwnKeyRequest, + create_own_key_request: CreateOwnKeyRequest, + _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, + ) -> CreateKeyResponse: + """Create Own Key + + Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + + :param create_own_key_request: (required) + :type create_own_key_request: CreateOwnKeyRequest + :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_keys_create_own_key_serialize( + create_own_key_request=create_own_key_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CreateKeyResponse", + '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_keys_create_own_key_with_http_info( + self, + create_own_key_request: CreateOwnKeyRequest, + _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[CreateKeyResponse]: + """Create Own Key + + Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + + :param create_own_key_request: (required) + :type create_own_key_request: CreateOwnKeyRequest + :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_keys_create_own_key_serialize( + create_own_key_request=create_own_key_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CreateKeyResponse", + '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_keys_create_own_key_without_preload_content( + self, + create_own_key_request: CreateOwnKeyRequest, + _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: + """Create Own Key + + Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + + :param create_own_key_request: (required) + :type create_own_key_request: CreateOwnKeyRequest + :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_keys_create_own_key_serialize( + create_own_key_request=create_own_key_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "CreateKeyResponse", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _organization_keys_create_own_key_serialize( + self, + create_own_key_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 create_own_key_request is not None: + _body_params = create_own_key_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/organizations/me/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 organization_keys_delete_own_federation_rule( + self, + key_id: StrictStr, + rule_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, + ) -> None: + """Delete Own Federation Rule + + Remove a federation rule from a key. Tokens it matched stop with the next request. The caller's own key whatever their role, or for the deployment operator any key in their active organization. Works whether or not ``federation_member_rules`` is on, so a rule can always be taken back. + + :param key_id: (required) + :type key_id: str + :param rule_id: (required) + :type rule_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_keys_delete_own_federation_rule_serialize( + key_id=key_id, + rule_id=rule_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '204': None, + '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_keys_delete_own_federation_rule_with_http_info( + self, + key_id: StrictStr, + rule_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[None]: + """Delete Own Federation Rule + + Remove a federation rule from a key. Tokens it matched stop with the next request. The caller's own key whatever their role, or for the deployment operator any key in their active organization. Works whether or not ``federation_member_rules`` is on, so a rule can always be taken back. + + :param key_id: (required) + :type key_id: str + :param rule_id: (required) + :type rule_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_keys_delete_own_federation_rule_serialize( + key_id=key_id, + rule_id=rule_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '204': None, + '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_keys_delete_own_federation_rule_without_preload_content( + self, + key_id: StrictStr, + rule_id: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -58,13 +776,15 @@ def organization_keys_create_own_key( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> CreateKeyResponse: - """Create Own Key + ) -> RESTResponseType: + """Delete Own Federation Rule - Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + Remove a federation rule from a key. Tokens it matched stop with the next request. The caller's own key whatever their role, or for the deployment operator any key in their active organization. Works whether or not ``federation_member_rules`` is on, so a rule can always be taken back. - :param create_own_key_request: (required) - :type create_own_key_request: CreateOwnKeyRequest + :param key_id: (required) + :type key_id: str + :param rule_id: (required) + :type rule_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 @@ -87,8 +807,9 @@ def organization_keys_create_own_key( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_create_own_key_serialize( - create_own_key_request=create_own_key_request, + _param = self._organization_keys_delete_own_federation_rule_serialize( + key_id=key_id, + rule_id=rule_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -96,7 +817,139 @@ def organization_keys_create_own_key( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '204': None, + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _organization_keys_delete_own_federation_rule_serialize( + self, + key_id, + rule_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 key_id is not None: + _path_params['key_id'] = key_id + if rule_id is not None: + _path_params['rule_id'] = rule_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='DELETE', + resource_path='/api/v1/organizations/me/keys/{key_id}/federation-rules/{rule_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_keys_delete_own_key( + self, + key_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, + ) -> None: + """Delete Own Key + + Delete (revoke) one of the caller's own API keys. + + :param key_id: (required) + :type key_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_keys_delete_own_key_serialize( + key_id=key_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '204': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -111,9 +964,9 @@ def organization_keys_create_own_key( @validate_call - def organization_keys_create_own_key_with_http_info( + def organization_keys_delete_own_key_with_http_info( self, - create_own_key_request: CreateOwnKeyRequest, + key_id: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -126,13 +979,13 @@ def organization_keys_create_own_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]: - """Create Own Key + ) -> ApiResponse[None]: + """Delete Own Key - Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + Delete (revoke) one of the caller's own API keys. - :param create_own_key_request: (required) - :type create_own_key_request: CreateOwnKeyRequest + :param key_id: (required) + :type key_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 @@ -155,8 +1008,8 @@ def organization_keys_create_own_key_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_create_own_key_serialize( - create_own_key_request=create_own_key_request, + _param = self._organization_keys_delete_own_key_serialize( + key_id=key_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -164,7 +1017,7 @@ def organization_keys_create_own_key_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '204': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -179,9 +1032,9 @@ def organization_keys_create_own_key_with_http_info( @validate_call - def organization_keys_create_own_key_without_preload_content( + def organization_keys_delete_own_key_without_preload_content( self, - create_own_key_request: CreateOwnKeyRequest, + key_id: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -195,12 +1048,12 @@ def organization_keys_create_own_key_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Create Own Key + """Delete Own Key - Create an API key owned by the caller, in a workspace they may see. The member-scoped counterpart of ``POST /api/v1/keys``: the owner is always the caller's own attribution user, the key is always budget-enforced, and the workspace must be visible to the caller (a member of it, or an organization owner/admin, who see every workspace). The secret is returned once. + Delete (revoke) one of the caller's own API keys. - :param create_own_key_request: (required) - :type create_own_key_request: CreateOwnKeyRequest + :param key_id: (required) + :type key_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 @@ -223,8 +1076,8 @@ def organization_keys_create_own_key_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_create_own_key_serialize( - create_own_key_request=create_own_key_request, + _param = self._organization_keys_delete_own_key_serialize( + key_id=key_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -232,7 +1085,7 @@ def organization_keys_create_own_key_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "CreateKeyResponse", + '204': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -242,9 +1095,9 @@ def organization_keys_create_own_key_without_preload_content( return response_data.response - def _organization_keys_create_own_key_serialize( + def _organization_keys_delete_own_key_serialize( self, - create_own_key_request, + key_id, _request_auth, _content_type, _headers, @@ -266,12 +1119,12 @@ def _organization_keys_create_own_key_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 # process the header parameters # process the form parameters # process the body parameter - if create_own_key_request is not None: - _body_params = create_own_key_request # set the HTTP header `Accept` @@ -282,19 +1135,6 @@ def _organization_keys_create_own_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] = [ @@ -303,8 +1143,8 @@ def _organization_keys_create_own_key_serialize( ] return self.api_client.param_serialize( - method='POST', - resource_path='/api/v1/organizations/me/keys', + method='DELETE', + resource_path='/api/v1/organizations/me/keys/{key_id}', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -321,7 +1161,7 @@ def _organization_keys_create_own_key_serialize( @validate_call - def organization_keys_delete_own_key( + def organization_keys_list_own_federation_rules( self, key_id: StrictStr, _request_timeout: Union[ @@ -336,10 +1176,10 @@ def organization_keys_delete_own_key( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> None: - """Delete Own Key + ) -> List[FederationRulePublic]: + """List Own Federation Rules - Delete (revoke) one of the caller's own API keys. + List the identities that may authenticate as a key, oldest first. The caller's own key, or for the deployment operator any key in their active organization. Includes any rule the operator gave the key on ``/api/v1/keys``, which ``member_managed`` tells apart. :param key_id: (required) :type key_id: str @@ -365,7 +1205,7 @@ def organization_keys_delete_own_key( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_delete_own_key_serialize( + _param = self._organization_keys_list_own_federation_rules_serialize( key_id=key_id, _request_auth=_request_auth, _content_type=_content_type, @@ -374,7 +1214,7 @@ def organization_keys_delete_own_key( ) _response_types_map: Dict[str, Optional[str]] = { - '204': None, + '200': "List[FederationRulePublic]", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -389,7 +1229,7 @@ def organization_keys_delete_own_key( @validate_call - def organization_keys_delete_own_key_with_http_info( + def organization_keys_list_own_federation_rules_with_http_info( self, key_id: StrictStr, _request_timeout: Union[ @@ -404,10 +1244,10 @@ def organization_keys_delete_own_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[None]: - """Delete Own Key + ) -> ApiResponse[List[FederationRulePublic]]: + """List Own Federation Rules - Delete (revoke) one of the caller's own API keys. + List the identities that may authenticate as a key, oldest first. The caller's own key, or for the deployment operator any key in their active organization. Includes any rule the operator gave the key on ``/api/v1/keys``, which ``member_managed`` tells apart. :param key_id: (required) :type key_id: str @@ -433,7 +1273,7 @@ def organization_keys_delete_own_key_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_delete_own_key_serialize( + _param = self._organization_keys_list_own_federation_rules_serialize( key_id=key_id, _request_auth=_request_auth, _content_type=_content_type, @@ -442,7 +1282,7 @@ def organization_keys_delete_own_key_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '204': None, + '200': "List[FederationRulePublic]", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -457,7 +1297,7 @@ def organization_keys_delete_own_key_with_http_info( @validate_call - def organization_keys_delete_own_key_without_preload_content( + def organization_keys_list_own_federation_rules_without_preload_content( self, key_id: StrictStr, _request_timeout: Union[ @@ -473,9 +1313,9 @@ def organization_keys_delete_own_key_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Delete Own Key + """List Own Federation Rules - Delete (revoke) one of the caller's own API keys. + List the identities that may authenticate as a key, oldest first. The caller's own key, or for the deployment operator any key in their active organization. Includes any rule the operator gave the key on ``/api/v1/keys``, which ``member_managed`` tells apart. :param key_id: (required) :type key_id: str @@ -501,7 +1341,7 @@ def organization_keys_delete_own_key_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._organization_keys_delete_own_key_serialize( + _param = self._organization_keys_list_own_federation_rules_serialize( key_id=key_id, _request_auth=_request_auth, _content_type=_content_type, @@ -510,7 +1350,7 @@ def organization_keys_delete_own_key_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '204': None, + '200': "List[FederationRulePublic]", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -520,7 +1360,7 @@ def organization_keys_delete_own_key_without_preload_content( return response_data.response - def _organization_keys_delete_own_key_serialize( + def _organization_keys_list_own_federation_rules_serialize( self, key_id, _request_auth, @@ -568,8 +1408,8 @@ def _organization_keys_delete_own_key_serialize( ] return self.api_client.param_serialize( - method='DELETE', - resource_path='/api/v1/organizations/me/keys/{key_id}', + method='GET', + resource_path='/api/v1/organizations/me/keys/{key_id}/federation-rules', path_params=_path_params, query_params=_query_params, header_params=_header_params, diff --git a/src/otari/_client/models/__init__.py b/src/otari/_client/models/__init__.py index eedef042e..ee52916f5 100644 --- a/src/otari/_client/models/__init__.py +++ b/src/otari/_client/models/__init__.py @@ -223,11 +223,15 @@ from otari._client.models.federation_token_request import FederationTokenRequest from otari._client.models.federation_token_response import FederationTokenResponse from otari._client.models.feedback_submission import FeedbackSubmission +from otari._client.models.gate_definition_request import GateDefinitionRequest from otari._client.models.gate_result_response import GateResultResponse +from otari._client.models.gate_summary_public import GateSummaryPublic from otari._client.models.gateway_settings import GatewaySettings from otari._client.models.guardrail_catalog import GuardrailCatalog from otari._client.models.guardrail_category import GuardrailCategory from otari._client.models.guardrail_config import GuardrailConfig +from otari._client.models.guardrail_definition_request import GuardrailDefinitionRequest +from otari._client.models.guardrail_definition_response import GuardrailDefinitionResponse from otari._client.models.guardrail_parameter_spec import GuardrailParameterSpec from otari._client.models.guardrail_profile_spec import GuardrailProfileSpec from otari._client.models.guardrail_stage import GuardrailStage @@ -437,6 +441,7 @@ from otari._client.models.messages_request import MessagesRequest from otari._client.models.model import Model from otari._client.models.model1 import Model1 +from otari._client.models.model_architecture import ModelArchitecture from otari._client.models.model_false import ModelFalse from otari._client.models.model_list_response import ModelListResponse from otari._client.models.model_metadata import ModelMetadata diff --git a/src/otari/_client/models/deployment_bootstrap.py b/src/otari/_client/models/deployment_bootstrap.py index 9d4a18b6b..b46d33ba7 100644 --- a/src/otari/_client/models/deployment_bootstrap.py +++ b/src/otari/_client/models/deployment_bootstrap.py @@ -28,6 +28,7 @@ class DeploymentBootstrap(BaseModel): What the dashboard shell needs before it can render anything. """ # noqa: E501 docs_url: Optional[StrictStr] = Field(description="Where this deployment's documentation lives, when it is not docs.otari.ai. Set, the dashboard's Documentation links open it in a new tab; null, they open https://docs.otari.ai/. A link target an operator configured, validated at startup as an absolute http(s) URL carrying no credential, since this response is unauthenticated.") + federation_member_rules: StrictBool = Field(description="Whether an organization's owners and admins may give their own API keys federation rules (the federation_member_rules setting), so the dashboard offers workload identity on their keys.") feedback_enabled: StrictBool = Field(description="Whether this deployment accepts deliberate feedback submissions.") mail_ready: StrictBool = Field(description="Whether this deployment can deliver a message carrying a link back to itself (an invitation's accept link, and the verification and reset links to come), not merely whether a transport is configured: it also needs to know its own public URL to put in one. Lets the dashboard disable or hide a mail-dependent affordance instead of offering one that would fail at send time. Every message this deployment sends carries such a link, which is why this is one flag and not one per feature.") maintenance_mode: StrictBool = Field(description="Whether this deployment is refusing new dashboard sign-ins while an operator redeploys it. The sign-in screen says so rather than presenting a form whose only outcome is a 503. Sessions already issued keep working, and the API is unaffected.") @@ -41,7 +42,7 @@ class DeploymentBootstrap(BaseModel): site_url: Optional[StrictStr] = Field(description="Where this deployment's public website lives. Set, the logo on the pages a visitor reaches without an account links to it; null, it links to the public catalog where public_catalog is true, and is not a link otherwise. A link target an operator configured, validated at startup as an absolute http(s) URL carrying no credential, since this response is unauthenticated.") surfaces: List[StrictStr] = Field(description="Management API groups this deployment serves, sorted, which is what its dashboard pages gate on: a fixed set plus one for each enabled feature. Named surfaces, not capabilities: capability is otari.ai's word for the entitlement (licensing) axis.") terms_url: Optional[StrictStr] = Field(description="Where this deployment's terms of service live. Set, the account menu carries a Terms of service row pointing at them; null, no address is configured and the menu carries no such row. A link target an operator configured, validated at startup as an absolute http(s) URL carrying no credential, since this response is unauthenticated.") - __properties: ClassVar[List[str]] = ["docs_url", "feedback_enabled", "mail_ready", "maintenance_mode", "oauth_providers", "open_signup", "passkeys_enabled", "passkeys_ready", "privacy_url", "public_catalog", "sign_in_methods", "site_url", "surfaces", "terms_url"] + __properties: ClassVar[List[str]] = ["docs_url", "federation_member_rules", "feedback_enabled", "mail_ready", "maintenance_mode", "oauth_providers", "open_signup", "passkeys_enabled", "passkeys_ready", "privacy_url", "public_catalog", "sign_in_methods", "site_url", "surfaces", "terms_url"] @field_validator('sign_in_methods') def sign_in_methods_validate_enum(cls, value): @@ -123,6 +124,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "docs_url": obj.get("docs_url"), + "federation_member_rules": obj.get("federation_member_rules"), "feedback_enabled": obj.get("feedback_enabled"), "mail_ready": obj.get("mail_ready"), "maintenance_mode": obj.get("maintenance_mode"), diff --git a/src/otari/_client/models/federation_rule_create.py b/src/otari/_client/models/federation_rule_create.py index 281388f0e..900ff5052 100644 --- a/src/otari/_client/models/federation_rule_create.py +++ b/src/otari/_client/models/federation_rule_create.py @@ -30,7 +30,7 @@ class FederationRuleCreate(BaseModel): """ # noqa: E501 audience: Annotated[str, Field(min_length=1, strict=True, max_length=512)] = Field(description="A value the token's 'aud' must contain.") email: Optional[Annotated[str, Field(min_length=3, strict=True, max_length=320)]] = Field(default=None, description="The token's verified 'email', when the rule names one. Compared without regard to case.") - issuer: Annotated[str, Field(min_length=1, strict=True, max_length=512)] = Field(description="The token's 'iss', one of the deployment's federation_issuers.") + issuer: Annotated[str, Field(min_length=1, strict=True, max_length=512)] = Field(description="The token's 'iss'. On an operator's rule, one of the deployment's federation_issuers; on a member's own key, any https issuer, whose discovery document and signing keys are fetched only from a public host.") subject: Optional[Annotated[str, Field(min_length=1, strict=True, max_length=255)]] = Field(default=None, description="The token's 'sub', when the rule names one.") __properties: ClassVar[List[str]] = ["audience", "email", "issuer", "subject"] diff --git a/src/otari/_client/models/federation_rule_public.py b/src/otari/_client/models/federation_rule_public.py index bbe208970..e0d2410e3 100644 --- a/src/otari/_client/models/federation_rule_public.py +++ b/src/otari/_client/models/federation_rule_public.py @@ -18,7 +18,7 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, StrictStr +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 @@ -34,8 +34,9 @@ class FederationRulePublic(BaseModel): email: Optional[StrictStr] id: StrictStr issuer: StrictStr + member_managed: StrictBool = Field(description="Whether a member gave the rule to their own key: it then matches only in the token exchange.") subject: Optional[StrictStr] - __properties: ClassVar[List[str]] = ["api_key_id", "audience", "created_at", "email", "id", "issuer", "subject"] + __properties: ClassVar[List[str]] = ["api_key_id", "audience", "created_at", "email", "id", "issuer", "member_managed", "subject"] model_config = ConfigDict( validate_by_name=True, @@ -104,6 +105,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "email": obj.get("email"), "id": obj.get("id"), "issuer": obj.get("issuer"), + "member_managed": obj.get("member_managed"), "subject": obj.get("subject") }) return _obj diff --git a/src/otari/_client/models/gate_definition_request.py b/src/otari/_client/models/gate_definition_request.py new file mode 100644 index 000000000..6e2c2ae48 --- /dev/null +++ b/src/otari/_client/models/gate_definition_request.py @@ -0,0 +1,128 @@ +# 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, field_validator +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 GateDefinitionRequest(BaseModel): + """ + One gate of a guardrail version: what it is, when it runs, and what it says when it fails. + """ # noqa: E501 + enforcement: StrictStr + gate_id: Annotated[str, Field(min_length=1, strict=True, max_length=200)] + gate_type: StrictStr + message: Annotated[str, Field(strict=True, max_length=4096)] + origin: StrictStr + runs: Annotated[List[StrictStr], Field(max_length=16)] + __properties: ClassVar[List[str]] = ["enforcement", "gate_id", "gate_type", "message", "origin", "runs"] + + @field_validator('enforcement') + def enforcement_validate_enum(cls, value): + """Validates the enum""" + if value not in set(['required', 'advisory']): + raise ValueError("must be one of enum values ('required', 'advisory')") + return value + + @field_validator('gate_type') + def gate_type_validate_enum(cls, value): + """Validates the enum""" + if value not in set(['command', 'command_if_changed', 'judge', 'path', 'verifier']): + raise ValueError("must be one of enum values ('command', 'command_if_changed', 'judge', 'path', 'verifier')") + return value + + @field_validator('origin') + def origin_validate_enum(cls, value): + """Validates the enum""" + if value not in set(['repo', 'user']): + raise ValueError("must be one of enum values ('repo', 'user')") + return value + + @field_validator('runs') + def runs_validate_enum(cls, value): + """Validates the enum""" + for i in value: + if i not in set(['pre_tool_use.edit_target', 'pre_tool_use.read_target', 'pre_tool_use.command', 'stop.working_tree', 'stop.session', 'stop.verifier']): + raise ValueError("each list item must be one of ('pre_tool_use.edit_target', 'pre_tool_use.read_target', 'pre_tool_use.command', 'stop.working_tree', 'stop.session', 'stop.verifier')") + return value + + 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 GateDefinitionRequest 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 GateDefinitionRequest from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "enforcement": obj.get("enforcement"), + "gate_id": obj.get("gate_id"), + "gate_type": obj.get("gate_type"), + "message": obj.get("message"), + "origin": obj.get("origin"), + "runs": obj.get("runs") + }) + return _obj + + diff --git a/src/otari/_client/models/gate_summary_public.py b/src/otari/_client/models/gate_summary_public.py new file mode 100644 index 000000000..2e26d57a2 --- /dev/null +++ b/src/otari/_client/models/gate_summary_public.py @@ -0,0 +1,136 @@ +# 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, StrictInt, StrictStr, field_validator +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 GateSummaryPublic(BaseModel): + """ + How often one agent guardrail gate ran in a session, by what it decided. + """ # noqa: E501 + blocked: StrictInt = Field(description="Checks where the gate stopped the agent.") + enforcement: Optional[StrictStr] + flagged: StrictInt = Field(description="Checks an advisory gate failed; the agent went ahead.") + gate_id: StrictStr + gate_type: Optional[StrictStr] = Field(description="From the guardrail's definition, when it was sent.") + message: Optional[StrictStr] = Field(description="What the gate says when it fails, from the guardrail's definition.") + passed: StrictInt + refused: StrictInt = Field(description="Checks where the gate could not decide and held the agent anyway.") + span_id: Optional[StrictStr] = Field(description="The check to open first: the earliest that did anything but pass. Null for a gate that never ran.") + undecided: StrictInt = Field(description="Checks where the gate could not decide; the agent went ahead unchecked.") + __properties: ClassVar[List[str]] = ["blocked", "enforcement", "flagged", "gate_id", "gate_type", "message", "passed", "refused", "span_id", "undecided"] + + @field_validator('enforcement') + def enforcement_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(['required', 'advisory']): + raise ValueError("must be one of enum values ('required', 'advisory')") + return value + + 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 GateSummaryPublic 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 enforcement (nullable) is None + # and model_fields_set contains the field + if self.enforcement is None and "enforcement" in self.model_fields_set: + _dict['enforcement'] = None + + # set to None if gate_type (nullable) is None + # and model_fields_set contains the field + if self.gate_type is None and "gate_type" in self.model_fields_set: + _dict['gate_type'] = None + + # set to None if message (nullable) is None + # and model_fields_set contains the field + if self.message is None and "message" in self.model_fields_set: + _dict['message'] = None + + # set to None if span_id (nullable) is None + # and model_fields_set contains the field + if self.span_id is None and "span_id" in self.model_fields_set: + _dict['span_id'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of GateSummaryPublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "blocked": obj.get("blocked"), + "enforcement": obj.get("enforcement"), + "flagged": obj.get("flagged"), + "gate_id": obj.get("gate_id"), + "gate_type": obj.get("gate_type"), + "message": obj.get("message"), + "passed": obj.get("passed"), + "refused": obj.get("refused"), + "span_id": obj.get("span_id"), + "undecided": obj.get("undecided") + }) + return _obj + + diff --git a/src/otari/_client/models/guardrail_definition_request.py b/src/otari/_client/models/guardrail_definition_request.py new file mode 100644 index 000000000..bfbcea0af --- /dev/null +++ b/src/otari/_client/models/guardrail_definition_request.py @@ -0,0 +1,109 @@ +# 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, field_validator +from typing import Any, ClassVar, Dict, List +from typing_extensions import Annotated +from otari._client.models.gate_definition_request import GateDefinitionRequest +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class GuardrailDefinitionRequest(BaseModel): + """ + GuardrailDefinitionRequest + """ # noqa: E501 + digest: Annotated[str, Field(strict=True)] + gates: Annotated[List[GateDefinitionRequest], Field(min_length=1, max_length=500)] + __properties: ClassVar[List[str]] = ["digest", "gates"] + + @field_validator('digest') + def digest_validate_regular_expression(cls, value): + """Validates the regular expression""" + if not isinstance(value, str): + value = str(value) + + if not re.match(r"^[0-9a-f]{64}$", value): + raise ValueError(r"must validate the regular expression /^[0-9a-f]{64}$/") + return value + + 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 GuardrailDefinitionRequest 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, + ) + # override the default output from pydantic by calling `to_dict()` of each item in gates (list) + _items = [] + if self.gates: + for _item_gates in self.gates: + if _item_gates: + _items.append(_item_gates.to_dict()) + _dict['gates'] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of GuardrailDefinitionRequest from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "digest": obj.get("digest"), + "gates": [GateDefinitionRequest.from_dict(_item) for _item in obj["gates"]] if obj.get("gates") is not None else None + }) + return _obj + + diff --git a/src/otari/_client/models/guardrail_definition_response.py b/src/otari/_client/models/guardrail_definition_response.py new file mode 100644 index 000000000..75b16f33a --- /dev/null +++ b/src/otari/_client/models/guardrail_definition_response.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, 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 GuardrailDefinitionResponse(BaseModel): + """ + GuardrailDefinitionResponse + """ # noqa: E501 + digest: StrictStr + __properties: ClassVar[List[str]] = ["digest"] + + 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 GuardrailDefinitionResponse 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 GuardrailDefinitionResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "digest": obj.get("digest") + }) + return _obj + + diff --git a/src/otari/_client/models/model_architecture.py b/src/otari/_client/models/model_architecture.py new file mode 100644 index 000000000..8f046f696 --- /dev/null +++ b/src/otari/_client/models/model_architecture.py @@ -0,0 +1,90 @@ +# 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, 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 ModelArchitecture(BaseModel): + """ + What a model reads and writes, in OpenRouter's ``architecture`` shape. + """ # noqa: E501 + input_modalities: Optional[List[StrictStr]] = None + output_modalities: Optional[List[StrictStr]] = None + __properties: ClassVar[List[str]] = ["input_modalities", "output_modalities"] + + 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 ModelArchitecture 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 ModelArchitecture from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "input_modalities": obj.get("input_modalities"), + "output_modalities": obj.get("output_modalities") + }) + return _obj + + diff --git a/src/otari/_client/models/model_object.py b/src/otari/_client/models/model_object.py index d62810e63..1ab62698c 100644 --- a/src/otari/_client/models/model_object.py +++ b/src/otari/_client/models/model_object.py @@ -19,6 +19,7 @@ from pydantic import BaseModel, ConfigDict, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional +from otari._client.models.model_architecture import ModelArchitecture from otari._client.models.model_pricing_info import ModelPricingInfo from typing import Optional, Set from typing_extensions import Self @@ -28,16 +29,19 @@ class ModelObject(BaseModel): """ OpenAI-compatible model object. """ # noqa: E501 + architecture: Optional[ModelArchitecture] = None context_window: Optional[StrictInt] = None created: StrictInt deployment_managed: Optional[StrictBool] = False id: StrictStr max_output_tokens: Optional[StrictInt] = None + name: Optional[StrictStr] = None object: Optional[StrictStr] = 'model' owned_by: StrictStr pricing: Optional[ModelPricingInfo] = None pricing_source: Optional[StrictStr] = 'none' - __properties: ClassVar[List[str]] = ["context_window", "created", "deployment_managed", "id", "max_output_tokens", "object", "owned_by", "pricing", "pricing_source"] + supported_parameters: Optional[List[StrictStr]] = None + __properties: ClassVar[List[str]] = ["architecture", "context_window", "created", "deployment_managed", "id", "max_output_tokens", "name", "object", "owned_by", "pricing", "pricing_source", "supported_parameters"] model_config = ConfigDict( validate_by_name=True, @@ -78,9 +82,17 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # override the default output from pydantic by calling `to_dict()` of architecture + if self.architecture: + _dict['architecture'] = self.architecture.to_dict() # override the default output from pydantic by calling `to_dict()` of pricing if self.pricing: _dict['pricing'] = self.pricing.to_dict() + # set to None if architecture (nullable) is None + # and model_fields_set contains the field + if self.architecture is None and "architecture" in self.model_fields_set: + _dict['architecture'] = None + # set to None if context_window (nullable) is None # and model_fields_set contains the field if self.context_window is None and "context_window" in self.model_fields_set: @@ -91,11 +103,21 @@ def to_dict(self) -> Dict[str, Any]: if self.max_output_tokens is None and "max_output_tokens" in self.model_fields_set: _dict['max_output_tokens'] = None + # set to None if name (nullable) is None + # and model_fields_set contains the field + if self.name is None and "name" in self.model_fields_set: + _dict['name'] = None + # set to None if pricing (nullable) is None # and model_fields_set contains the field if self.pricing is None and "pricing" in self.model_fields_set: _dict['pricing'] = None + # set to None if supported_parameters (nullable) is None + # and model_fields_set contains the field + if self.supported_parameters is None and "supported_parameters" in self.model_fields_set: + _dict['supported_parameters'] = None + return _dict @classmethod @@ -108,15 +130,18 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "architecture": ModelArchitecture.from_dict(obj["architecture"]) if obj.get("architecture") is not None else None, "context_window": obj.get("context_window"), "created": obj.get("created"), "deployment_managed": obj.get("deployment_managed") if obj.get("deployment_managed") is not None else False, "id": obj.get("id"), "max_output_tokens": obj.get("max_output_tokens"), + "name": obj.get("name"), "object": obj.get("object") if obj.get("object") is not None else 'model', "owned_by": obj.get("owned_by"), "pricing": ModelPricingInfo.from_dict(obj["pricing"]) if obj.get("pricing") is not None else None, - "pricing_source": obj.get("pricing_source") if obj.get("pricing_source") is not None else 'none' + "pricing_source": obj.get("pricing_source") if obj.get("pricing_source") is not None else 'none', + "supported_parameters": obj.get("supported_parameters") }) return _obj diff --git a/src/otari/_client/models/trace_detail_public.py b/src/otari/_client/models/trace_detail_public.py index 97087a8b9..7075ae1c0 100644 --- a/src/otari/_client/models/trace_detail_public.py +++ b/src/otari/_client/models/trace_detail_public.py @@ -19,6 +19,7 @@ from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List +from otari._client.models.gate_summary_public import GateSummaryPublic from otari._client.models.span_public import SpanPublic from otari._client.models.trace_summary_public import TraceSummaryPublic from otari._client.models.turn_public import TurnPublic @@ -30,12 +31,13 @@ class TraceDetailPublic(BaseModel): """ TraceDetailPublic """ # noqa: E501 + gates: List[GateSummaryPublic] = Field(description="Each agent guardrail gate a coding agent's hook reported, the ones that did something first.") spans: List[SpanPublic] state: StrictStr summary: TraceSummaryPublic truncated: StrictBool = Field(description="True when the session holds more spans than one read returns.") turns: List[TurnPublic] - __properties: ClassVar[List[str]] = ["spans", "state", "summary", "truncated", "turns"] + __properties: ClassVar[List[str]] = ["gates", "spans", "state", "summary", "truncated", "turns"] @field_validator('state') def state_validate_enum(cls, value): @@ -83,6 +85,13 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # override the default output from pydantic by calling `to_dict()` of each item in gates (list) + _items = [] + if self.gates: + for _item_gates in self.gates: + if _item_gates: + _items.append(_item_gates.to_dict()) + _dict['gates'] = _items # override the default output from pydantic by calling `to_dict()` of each item in spans (list) _items = [] if self.spans: @@ -112,6 +121,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "gates": [GateSummaryPublic.from_dict(_item) for _item in obj["gates"]] if obj.get("gates") is not None else None, "spans": [SpanPublic.from_dict(_item) for _item in obj["spans"]] if obj.get("spans") is not None else None, "state": obj.get("state"), "summary": TraceSummaryPublic.from_dict(obj["summary"]) if obj.get("summary") is not None else None,