From 65534bcfa5f42f34108b2928d64da48d5f8270ba Mon Sep 17 00:00:00 2001 From: daavoo <12677733+daavoo@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:06:05 +0000 Subject: [PATCH] feat: regenerate SDK client core from Otari OpenAPI spec --- sdk-endpoints.txt | 6 +- src/otari/_client/__init__.py | 16 +- src/otari/_client/api/hosted_providers_api.py | 353 +++++++----- src/otari/_client/api/oauth_api.py | 6 +- .../_client/api/organization_traces_api.py | 78 +-- src/otari/_client/api/pricing_api.py | 515 ------------------ src/otari/_client/api/traces_api.py | 78 +-- src/otari/_client/models/__init__.py | 8 +- .../models/accepted_snapshot_response.py | 2 +- .../models/federation_token_request.py | 4 +- .../_client/models/gate_summary_public.py | 21 +- .../hosted_catalog_price_change_public.py | 97 ++++ .../hosted_catalog_price_update_public.py | 118 ++++ .../hosted_catalog_update_preview_public.py | 110 ++++ ... hosted_catalog_update_preview_request.py} | 16 +- .../models/hosted_catalog_update_public.py | 94 ++++ .../models/hosted_catalog_update_request.py | 95 ++++ .../pricing_refresh_preview_response.py | 2 +- src/otari/_client/models/pricing_response.py | 9 +- .../_client/models/rate_limit_rule_create.py | 25 +- .../_client/models/rate_limit_rule_public.py | 25 +- .../_client/models/rate_limit_rule_update.py | 30 +- .../_client/models/set_pricing_request.py | 13 +- src/otari/_client/models/span_public.py | 6 +- src/otari/_client/models/tool_charge_line.py | 2 +- src/otari/_client/models/tool_cost_public.py | 111 ++++ .../_client/models/trace_bucket_public.py | 4 +- .../_client/models/trace_detail_public.py | 12 +- .../_client/models/trace_series_public.py | 4 +- 29 files changed, 1079 insertions(+), 781 deletions(-) create mode 100644 src/otari/_client/models/hosted_catalog_price_change_public.py create mode 100644 src/otari/_client/models/hosted_catalog_price_update_public.py create mode 100644 src/otari/_client/models/hosted_catalog_update_preview_public.py rename src/otari/_client/models/{pricing_refresh_confirmation_response.py => hosted_catalog_update_preview_request.py} (77%) create mode 100644 src/otari/_client/models/hosted_catalog_update_public.py create mode 100644 src/otari/_client/models/hosted_catalog_update_request.py create mode 100644 src/otari/_client/models/tool_cost_public.py diff --git a/sdk-endpoints.txt b/sdk-endpoints.txt index 19c749fa..cfa60009 100644 --- a/sdk-endpoints.txt +++ b/sdk-endpoints.txt @@ -131,8 +131,8 @@ DELETE /api/v1/provider-endpoints/{endpoint_id} # not yet wrapped # Hosted providers (the deployment's own upstream credentials, operator-only) GET /api/v1/hosted-providers # dashboard-only POST /api/v1/hosted-providers # dashboard-only -GET /api/v1/hosted-providers/refresh/preview # dashboard-only -POST /api/v1/hosted-providers/refresh # dashboard-only +POST /api/v1/hosted-providers/catalog-update/preview # dashboard-only +POST /api/v1/hosted-providers/catalog-update # dashboard-only POST /api/v1/hosted-providers/test # dashboard-only POST /api/v1/hosted-providers/reencrypt # dashboard-only GET /api/v1/hosted-providers/migration # dashboard-only @@ -285,8 +285,6 @@ POST /api/v1/routing/preferences/rank # not yet wrapped GET /api/v1/routing/status # not yet wrapped POST /api/v1/routing/recommend # not yet wrapped # Pricing refresh workflow -POST /api/v1/pricing/refresh # not yet wrapped -POST /api/v1/pricing/refresh/confirm # not yet wrapped POST /api/v1/pricing/refresh/reject # not yet wrapped GET /api/v1/pricing/refresh/pending # not yet wrapped GET /api/v1/pricing/snapshots # not yet wrapped diff --git a/src/otari/_client/__init__.py b/src/otari/_client/__init__.py index cdaf782a..8d813961 100644 --- a/src/otari/_client/__init__.py +++ b/src/otari/_client/__init__.py @@ -320,8 +320,14 @@ "HealthCheckStatus", "HostedAvailableModelsPublic", "HostedCatalogKeptGroupPublic", + "HostedCatalogPriceChangePublic", + "HostedCatalogPriceUpdatePublic", "HostedCatalogProviderRefreshPublic", "HostedCatalogRefreshPublic", + "HostedCatalogUpdatePreviewPublic", + "HostedCatalogUpdatePreviewRequest", + "HostedCatalogUpdatePublic", + "HostedCatalogUpdateRequest", "HostedModelCreateRequest", "HostedModelPublic", "HostedModelUpdateRequest", @@ -614,7 +620,6 @@ "PoolStatus", "PricingDriftRow", "PricingRefreshChangeResponse", - "PricingRefreshConfirmationResponse", "PricingRefreshPreviewResponse", "PricingResponse", "PricingTier", @@ -706,6 +711,7 @@ "ToolChargeLine", "ToolChoice", "ToolChoice1", + "ToolCostPublic", "ToolMeter", "ToolSettingField", "ToolSettingsResponse", @@ -1098,8 +1104,14 @@ from otari._client.models.health_check_status import HealthCheckStatus as HealthCheckStatus from otari._client.models.hosted_available_models_public import HostedAvailableModelsPublic as HostedAvailableModelsPublic from otari._client.models.hosted_catalog_kept_group_public import HostedCatalogKeptGroupPublic as HostedCatalogKeptGroupPublic +from otari._client.models.hosted_catalog_price_change_public import HostedCatalogPriceChangePublic as HostedCatalogPriceChangePublic +from otari._client.models.hosted_catalog_price_update_public import HostedCatalogPriceUpdatePublic as HostedCatalogPriceUpdatePublic from otari._client.models.hosted_catalog_provider_refresh_public import HostedCatalogProviderRefreshPublic as HostedCatalogProviderRefreshPublic from otari._client.models.hosted_catalog_refresh_public import HostedCatalogRefreshPublic as HostedCatalogRefreshPublic +from otari._client.models.hosted_catalog_update_preview_public import HostedCatalogUpdatePreviewPublic as HostedCatalogUpdatePreviewPublic +from otari._client.models.hosted_catalog_update_preview_request import HostedCatalogUpdatePreviewRequest as HostedCatalogUpdatePreviewRequest +from otari._client.models.hosted_catalog_update_public import HostedCatalogUpdatePublic as HostedCatalogUpdatePublic +from otari._client.models.hosted_catalog_update_request import HostedCatalogUpdateRequest as HostedCatalogUpdateRequest from otari._client.models.hosted_model_create_request import HostedModelCreateRequest as HostedModelCreateRequest from otari._client.models.hosted_model_public import HostedModelPublic as HostedModelPublic from otari._client.models.hosted_model_update_request import HostedModelUpdateRequest as HostedModelUpdateRequest @@ -1392,7 +1404,6 @@ from otari._client.models.pool_status import PoolStatus as PoolStatus from otari._client.models.pricing_drift_row import PricingDriftRow as PricingDriftRow from otari._client.models.pricing_refresh_change_response import PricingRefreshChangeResponse as PricingRefreshChangeResponse -from otari._client.models.pricing_refresh_confirmation_response import PricingRefreshConfirmationResponse as PricingRefreshConfirmationResponse from otari._client.models.pricing_refresh_preview_response import PricingRefreshPreviewResponse as PricingRefreshPreviewResponse from otari._client.models.pricing_response import PricingResponse as PricingResponse from otari._client.models.pricing_tier import PricingTier as PricingTier @@ -1484,6 +1495,7 @@ from otari._client.models.tool_charge_line import ToolChargeLine as ToolChargeLine from otari._client.models.tool_choice import ToolChoice as ToolChoice from otari._client.models.tool_choice1 import ToolChoice1 as ToolChoice1 +from otari._client.models.tool_cost_public import ToolCostPublic as ToolCostPublic from otari._client.models.tool_meter import ToolMeter as ToolMeter from otari._client.models.tool_setting_field import ToolSettingField as ToolSettingField from otari._client.models.tool_settings_response import ToolSettingsResponse as ToolSettingsResponse diff --git a/src/otari/_client/api/hosted_providers_api.py b/src/otari/_client/api/hosted_providers_api.py index 73cc8e2f..6474ef9a 100644 --- a/src/otari/_client/api/hosted_providers_api.py +++ b/src/otari/_client/api/hosted_providers_api.py @@ -22,7 +22,10 @@ from otari._client.models.deployment_provider_migration_public import DeploymentProviderMigrationPublic from otari._client.models.deployment_provider_migration_request import DeploymentProviderMigrationRequest from otari._client.models.hosted_available_models_public import HostedAvailableModelsPublic -from otari._client.models.hosted_catalog_refresh_public import HostedCatalogRefreshPublic +from otari._client.models.hosted_catalog_update_preview_public import HostedCatalogUpdatePreviewPublic +from otari._client.models.hosted_catalog_update_preview_request import HostedCatalogUpdatePreviewRequest +from otari._client.models.hosted_catalog_update_public import HostedCatalogUpdatePublic +from otari._client.models.hosted_catalog_update_request import HostedCatalogUpdateRequest from otari._client.models.hosted_model_create_request import HostedModelCreateRequest from otari._client.models.hosted_model_public import HostedModelPublic from otari._client.models.hosted_model_update_request import HostedModelUpdateRequest @@ -2283,8 +2286,9 @@ def _hosted_providers_list_hosted_providers_serialize( @validate_call - def hosted_providers_preview_catalog_refresh( + def hosted_providers_preview_catalog_update( self, + hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2297,11 +2301,13 @@ def hosted_providers_preview_catalog_refresh( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> HostedCatalogRefreshPublic: - """Preview Catalog Refresh + ) -> HostedCatalogUpdatePreviewPublic: + """Preview Catalog Update - What a catalog sweep would remove, without removing it. A GET, and a truthful one: it writes nothing. It does dial every enabled provider, as ``available-models`` does, because a model the provider still lists would survive the sweep and previewing it as doomed would be a lie. + What updating the catalog would do: the models.dev price changes, then what each provider newly lists. A POST, because it holds the fetched prices as pending for the apply to name by their ``digest``; nothing else is written. It dials every enabled provider. A price fetch that fails is reported in ``price_error`` and the model lists are still previewed. With ``cleanup``, it also previews which prices of models no provider serves would be removed. + :param hosted_catalog_update_preview_request: (required) + :type hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest :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 @@ -2324,7 +2330,8 @@ def hosted_providers_preview_catalog_refresh( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_preview_catalog_refresh_serialize( + _param = self._hosted_providers_preview_catalog_update_serialize( + hosted_catalog_update_preview_request=hosted_catalog_update_preview_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2332,7 +2339,8 @@ def hosted_providers_preview_catalog_refresh( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedCatalogUpdatePreviewPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2346,8 +2354,9 @@ def hosted_providers_preview_catalog_refresh( @validate_call - def hosted_providers_preview_catalog_refresh_with_http_info( + def hosted_providers_preview_catalog_update_with_http_info( self, + hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2360,11 +2369,13 @@ def hosted_providers_preview_catalog_refresh_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[HostedCatalogRefreshPublic]: - """Preview Catalog Refresh + ) -> ApiResponse[HostedCatalogUpdatePreviewPublic]: + """Preview Catalog Update - What a catalog sweep would remove, without removing it. A GET, and a truthful one: it writes nothing. It does dial every enabled provider, as ``available-models`` does, because a model the provider still lists would survive the sweep and previewing it as doomed would be a lie. + What updating the catalog would do: the models.dev price changes, then what each provider newly lists. A POST, because it holds the fetched prices as pending for the apply to name by their ``digest``; nothing else is written. It dials every enabled provider. A price fetch that fails is reported in ``price_error`` and the model lists are still previewed. With ``cleanup``, it also previews which prices of models no provider serves would be removed. + :param hosted_catalog_update_preview_request: (required) + :type hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest :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 @@ -2387,7 +2398,8 @@ def hosted_providers_preview_catalog_refresh_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_preview_catalog_refresh_serialize( + _param = self._hosted_providers_preview_catalog_update_serialize( + hosted_catalog_update_preview_request=hosted_catalog_update_preview_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2395,7 +2407,8 @@ def hosted_providers_preview_catalog_refresh_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedCatalogUpdatePreviewPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2409,8 +2422,9 @@ def hosted_providers_preview_catalog_refresh_with_http_info( @validate_call - def hosted_providers_preview_catalog_refresh_without_preload_content( + def hosted_providers_preview_catalog_update_without_preload_content( self, + hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2424,10 +2438,12 @@ def hosted_providers_preview_catalog_refresh_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Preview Catalog Refresh + """Preview Catalog Update - What a catalog sweep would remove, without removing it. A GET, and a truthful one: it writes nothing. It does dial every enabled provider, as ``available-models`` does, because a model the provider still lists would survive the sweep and previewing it as doomed would be a lie. + What updating the catalog would do: the models.dev price changes, then what each provider newly lists. A POST, because it holds the fetched prices as pending for the apply to name by their ``digest``; nothing else is written. It dials every enabled provider. A price fetch that fails is reported in ``price_error`` and the model lists are still previewed. With ``cleanup``, it also previews which prices of models no provider serves would be removed. + :param hosted_catalog_update_preview_request: (required) + :type hosted_catalog_update_preview_request: HostedCatalogUpdatePreviewRequest :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 @@ -2450,7 +2466,8 @@ def hosted_providers_preview_catalog_refresh_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_preview_catalog_refresh_serialize( + _param = self._hosted_providers_preview_catalog_update_serialize( + hosted_catalog_update_preview_request=hosted_catalog_update_preview_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2458,7 +2475,8 @@ def hosted_providers_preview_catalog_refresh_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedCatalogUpdatePreviewPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -2467,8 +2485,9 @@ def hosted_providers_preview_catalog_refresh_without_preload_content( return response_data.response - def _hosted_providers_preview_catalog_refresh_serialize( + def _hosted_providers_preview_catalog_update_serialize( self, + hosted_catalog_update_preview_request, _request_auth, _content_type, _headers, @@ -2494,6 +2513,8 @@ def _hosted_providers_preview_catalog_refresh_serialize( # process the header parameters # process the form parameters # process the body parameter + if hosted_catalog_update_preview_request is not None: + _body_params = hosted_catalog_update_preview_request # set the HTTP header `Accept` @@ -2504,6 +2525,19 @@ def _hosted_providers_preview_catalog_refresh_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] = [ @@ -2512,8 +2546,8 @@ def _hosted_providers_preview_catalog_refresh_serialize( ] return self.api_client.param_serialize( - method='GET', - resource_path='/api/v1/hosted-providers/refresh/preview', + method='POST', + resource_path='/api/v1/hosted-providers/catalog-update/preview', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -3024,8 +3058,9 @@ def _hosted_providers_reencrypt_hosted_providers_serialize( @validate_call - def hosted_providers_refresh_catalog( + def hosted_providers_refresh_hosted_models( self, + provider: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3038,11 +3073,13 @@ def hosted_providers_refresh_catalog( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> HostedCatalogRefreshPublic: - """Refresh Catalog + ) -> HostedModelsRefreshPublic: + """Refresh Hosted Models - Re-ask every enabled provider what it lists, then take the rest off the catalog. The whole deployment rather than one provider: a stored price is what puts a model on a tenant's Models page, and a price under a provider nothing here serves cannot be reached by a per-provider refresh. A model list whose provider nothing defines any more, such as a removed ``config.yml`` entry, goes too, and is named in ``orphaned_rosters``. Where no provider offers a model, only those lists go and every price stays; with none of them either, the sweep answers 409. Declared before the ``/{provider}`` paths to read in the order the surface is used; no method collides in any case. + Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + :param provider: (required) + :type provider: 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 @@ -3065,7 +3102,8 @@ def hosted_providers_refresh_catalog( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_catalog_serialize( + _param = self._hosted_providers_refresh_hosted_models_serialize( + provider=provider, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3073,7 +3111,8 @@ def hosted_providers_refresh_catalog( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedModelsRefreshPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -3087,8 +3126,9 @@ def hosted_providers_refresh_catalog( @validate_call - def hosted_providers_refresh_catalog_with_http_info( + def hosted_providers_refresh_hosted_models_with_http_info( self, + provider: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3101,11 +3141,13 @@ def hosted_providers_refresh_catalog_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[HostedCatalogRefreshPublic]: - """Refresh Catalog + ) -> ApiResponse[HostedModelsRefreshPublic]: + """Refresh Hosted Models - Re-ask every enabled provider what it lists, then take the rest off the catalog. The whole deployment rather than one provider: a stored price is what puts a model on a tenant's Models page, and a price under a provider nothing here serves cannot be reached by a per-provider refresh. A model list whose provider nothing defines any more, such as a removed ``config.yml`` entry, goes too, and is named in ``orphaned_rosters``. Where no provider offers a model, only those lists go and every price stays; with none of them either, the sweep answers 409. Declared before the ``/{provider}`` paths to read in the order the surface is used; no method collides in any case. + Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + :param provider: (required) + :type provider: 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 @@ -3128,7 +3170,8 @@ def hosted_providers_refresh_catalog_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_catalog_serialize( + _param = self._hosted_providers_refresh_hosted_models_serialize( + provider=provider, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3136,7 +3179,8 @@ def hosted_providers_refresh_catalog_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedModelsRefreshPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -3150,8 +3194,9 @@ def hosted_providers_refresh_catalog_with_http_info( @validate_call - def hosted_providers_refresh_catalog_without_preload_content( + def hosted_providers_refresh_hosted_models_without_preload_content( self, + provider: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3165,10 +3210,12 @@ def hosted_providers_refresh_catalog_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Refresh Catalog + """Refresh Hosted Models - Re-ask every enabled provider what it lists, then take the rest off the catalog. The whole deployment rather than one provider: a stored price is what puts a model on a tenant's Models page, and a price under a provider nothing here serves cannot be reached by a per-provider refresh. A model list whose provider nothing defines any more, such as a removed ``config.yml`` entry, goes too, and is named in ``orphaned_rosters``. Where no provider offers a model, only those lists go and every price stays; with none of them either, the sweep answers 409. Declared before the ``/{provider}`` paths to read in the order the surface is used; no method collides in any case. + Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + :param provider: (required) + :type provider: 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 @@ -3191,7 +3238,8 @@ def hosted_providers_refresh_catalog_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_catalog_serialize( + _param = self._hosted_providers_refresh_hosted_models_serialize( + provider=provider, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3199,7 +3247,8 @@ def hosted_providers_refresh_catalog_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedCatalogRefreshPublic", + '200': "HostedModelsRefreshPublic", + '422': "HTTPValidationError", } response_data = self.api_client.call_api( *_param, @@ -3208,8 +3257,9 @@ def hosted_providers_refresh_catalog_without_preload_content( return response_data.response - def _hosted_providers_refresh_catalog_serialize( + def _hosted_providers_refresh_hosted_models_serialize( self, + provider, _request_auth, _content_type, _headers, @@ -3231,6 +3281,8 @@ def _hosted_providers_refresh_catalog_serialize( _body_params: Optional[bytes] = None # process the path parameters + if provider is not None: + _path_params['provider'] = provider # process the query parameters # process the header parameters # process the form parameters @@ -3254,7 +3306,7 @@ def _hosted_providers_refresh_catalog_serialize( return self.api_client.param_serialize( method='POST', - resource_path='/api/v1/hosted-providers/refresh', + resource_path='/api/v1/hosted-providers/{provider}/models/refresh', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -3271,9 +3323,10 @@ def _hosted_providers_refresh_catalog_serialize( @validate_call - def hosted_providers_refresh_hosted_models( + def hosted_providers_remove_hosted_model( self, provider: StrictStr, + model_id: UUID, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3286,13 +3339,15 @@ def hosted_providers_refresh_hosted_models( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> HostedModelsRefreshPublic: - """Refresh Hosted Models + ) -> Message: + """Remove Hosted Model - Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + Stop offering a model on a provider. Its pricing history stays. :param provider: (required) :type provider: str + :param model_id: (required) + :type model_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -3315,8 +3370,9 @@ def hosted_providers_refresh_hosted_models( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_hosted_models_serialize( + _param = self._hosted_providers_remove_hosted_model_serialize( provider=provider, + model_id=model_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3324,7 +3380,7 @@ def hosted_providers_refresh_hosted_models( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedModelsRefreshPublic", + '200': "Message", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3339,9 +3395,10 @@ def hosted_providers_refresh_hosted_models( @validate_call - def hosted_providers_refresh_hosted_models_with_http_info( + def hosted_providers_remove_hosted_model_with_http_info( self, provider: StrictStr, + model_id: UUID, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3354,13 +3411,15 @@ def hosted_providers_refresh_hosted_models_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[HostedModelsRefreshPublic]: - """Refresh Hosted Models + ) -> ApiResponse[Message]: + """Remove Hosted Model - Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + Stop offering a model on a provider. Its pricing history stays. :param provider: (required) :type provider: str + :param model_id: (required) + :type model_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -3383,8 +3442,9 @@ def hosted_providers_refresh_hosted_models_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_hosted_models_serialize( + _param = self._hosted_providers_remove_hosted_model_serialize( provider=provider, + model_id=model_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3392,7 +3452,7 @@ def hosted_providers_refresh_hosted_models_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedModelsRefreshPublic", + '200': "Message", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3407,9 +3467,10 @@ def hosted_providers_refresh_hosted_models_with_http_info( @validate_call - def hosted_providers_refresh_hosted_models_without_preload_content( + def hosted_providers_remove_hosted_model_without_preload_content( self, provider: StrictStr, + model_id: UUID, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3423,12 +3484,14 @@ def hosted_providers_refresh_hosted_models_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Refresh Hosted Models + """Remove Hosted Model - Ask the provider again and offer whatever is newly listed. Nothing already offered is removed, even when the provider no longer lists it. New models follow the offer rule, seeded with the community default price and off when nothing prices them. A seeded price nobody changed moves with the default. An offered model whose stored price has since been deleted is seeded again, or switched off where the default does not price it, even one an operator switched on: a refresh never switches a model on. + Stop offering a model on a provider. Its pricing history stays. :param provider: (required) :type provider: str + :param model_id: (required) + :type model_id: UUID :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -3451,8 +3514,9 @@ def hosted_providers_refresh_hosted_models_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_refresh_hosted_models_serialize( + _param = self._hosted_providers_remove_hosted_model_serialize( provider=provider, + model_id=model_id, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3460,7 +3524,7 @@ def hosted_providers_refresh_hosted_models_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedModelsRefreshPublic", + '200': "Message", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3470,9 +3534,10 @@ def hosted_providers_refresh_hosted_models_without_preload_content( return response_data.response - def _hosted_providers_refresh_hosted_models_serialize( + def _hosted_providers_remove_hosted_model_serialize( self, provider, + model_id, _request_auth, _content_type, _headers, @@ -3496,6 +3561,8 @@ def _hosted_providers_refresh_hosted_models_serialize( # process the path parameters if provider is not None: _path_params['provider'] = provider + if model_id is not None: + _path_params['model_id'] = model_id # process the query parameters # process the header parameters # process the form parameters @@ -3518,8 +3585,8 @@ def _hosted_providers_refresh_hosted_models_serialize( ] return self.api_client.param_serialize( - method='POST', - resource_path='/api/v1/hosted-providers/{provider}/models/refresh', + method='DELETE', + resource_path='/api/v1/hosted-providers/{provider}/models/{model_id}', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -3536,10 +3603,9 @@ def _hosted_providers_refresh_hosted_models_serialize( @validate_call - def hosted_providers_remove_hosted_model( + def hosted_providers_test_hosted_provider( self, - provider: StrictStr, - model_id: UUID, + hosted_provider_test_request: HostedProviderTestRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3552,15 +3618,13 @@ def hosted_providers_remove_hosted_model( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> Message: - """Remove Hosted Model + ) -> HostedProviderTestPublic: + """Test Hosted Provider - Stop offering a model on a provider. Its pricing history stays. + Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. - :param provider: (required) - :type provider: str - :param model_id: (required) - :type model_id: UUID + :param hosted_provider_test_request: (required) + :type hosted_provider_test_request: HostedProviderTestRequest :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 @@ -3583,9 +3647,8 @@ def hosted_providers_remove_hosted_model( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_remove_hosted_model_serialize( - provider=provider, - model_id=model_id, + _param = self._hosted_providers_test_hosted_provider_serialize( + hosted_provider_test_request=hosted_provider_test_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3593,7 +3656,7 @@ def hosted_providers_remove_hosted_model( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "Message", + '200': "HostedProviderTestPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3608,10 +3671,9 @@ def hosted_providers_remove_hosted_model( @validate_call - def hosted_providers_remove_hosted_model_with_http_info( + def hosted_providers_test_hosted_provider_with_http_info( self, - provider: StrictStr, - model_id: UUID, + hosted_provider_test_request: HostedProviderTestRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3624,15 +3686,13 @@ def hosted_providers_remove_hosted_model_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[Message]: - """Remove Hosted Model + ) -> ApiResponse[HostedProviderTestPublic]: + """Test Hosted Provider - Stop offering a model on a provider. Its pricing history stays. + Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. - :param provider: (required) - :type provider: str - :param model_id: (required) - :type model_id: UUID + :param hosted_provider_test_request: (required) + :type hosted_provider_test_request: HostedProviderTestRequest :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 @@ -3655,9 +3715,8 @@ def hosted_providers_remove_hosted_model_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_remove_hosted_model_serialize( - provider=provider, - model_id=model_id, + _param = self._hosted_providers_test_hosted_provider_serialize( + hosted_provider_test_request=hosted_provider_test_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3665,7 +3724,7 @@ def hosted_providers_remove_hosted_model_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "Message", + '200': "HostedProviderTestPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3680,10 +3739,9 @@ def hosted_providers_remove_hosted_model_with_http_info( @validate_call - def hosted_providers_remove_hosted_model_without_preload_content( + def hosted_providers_test_hosted_provider_without_preload_content( self, - provider: StrictStr, - model_id: UUID, + hosted_provider_test_request: HostedProviderTestRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3697,14 +3755,12 @@ def hosted_providers_remove_hosted_model_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Remove Hosted Model + """Test Hosted Provider - Stop offering a model on a provider. Its pricing history stays. + Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. - :param provider: (required) - :type provider: str - :param model_id: (required) - :type model_id: UUID + :param hosted_provider_test_request: (required) + :type hosted_provider_test_request: HostedProviderTestRequest :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 @@ -3727,9 +3783,8 @@ def hosted_providers_remove_hosted_model_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_remove_hosted_model_serialize( - provider=provider, - model_id=model_id, + _param = self._hosted_providers_test_hosted_provider_serialize( + hosted_provider_test_request=hosted_provider_test_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3737,7 +3792,7 @@ def hosted_providers_remove_hosted_model_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "Message", + '200': "HostedProviderTestPublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3747,10 +3802,9 @@ def hosted_providers_remove_hosted_model_without_preload_content( return response_data.response - def _hosted_providers_remove_hosted_model_serialize( + def _hosted_providers_test_hosted_provider_serialize( self, - provider, - model_id, + hosted_provider_test_request, _request_auth, _content_type, _headers, @@ -3772,14 +3826,12 @@ def _hosted_providers_remove_hosted_model_serialize( _body_params: Optional[bytes] = None # process the path parameters - if provider is not None: - _path_params['provider'] = provider - if model_id is not None: - _path_params['model_id'] = model_id # process the query parameters # process the header parameters # process the form parameters # process the body parameter + if hosted_provider_test_request is not None: + _body_params = hosted_provider_test_request # set the HTTP header `Accept` @@ -3790,6 +3842,19 @@ def _hosted_providers_remove_hosted_model_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] = [ @@ -3798,8 +3863,8 @@ def _hosted_providers_remove_hosted_model_serialize( ] return self.api_client.param_serialize( - method='DELETE', - resource_path='/api/v1/hosted-providers/{provider}/models/{model_id}', + method='POST', + resource_path='/api/v1/hosted-providers/test', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -3816,9 +3881,9 @@ def _hosted_providers_remove_hosted_model_serialize( @validate_call - def hosted_providers_test_hosted_provider( + def hosted_providers_update_catalog( self, - hosted_provider_test_request: HostedProviderTestRequest, + hosted_catalog_update_request: HostedCatalogUpdateRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3831,13 +3896,13 @@ def hosted_providers_test_hosted_provider( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> HostedProviderTestPublic: - """Test Hosted Provider + ) -> HostedCatalogUpdatePublic: + """Update Catalog - Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. + Apply the reviewed prices, then refresh every provider's models, then the cleanup if asked. The price step comes first, so the model step prices new models at the prices it applied, and a model held for want of a price is served once it has one. Without a ``digest`` no price changes. A ``digest`` that no longer names the pending prices answers 409 and changes nothing. ``cleanup`` removes the prices of models no provider serves, with their history. - :param hosted_provider_test_request: (required) - :type hosted_provider_test_request: HostedProviderTestRequest + :param hosted_catalog_update_request: (required) + :type hosted_catalog_update_request: HostedCatalogUpdateRequest :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 @@ -3860,8 +3925,8 @@ def hosted_providers_test_hosted_provider( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_test_hosted_provider_serialize( - hosted_provider_test_request=hosted_provider_test_request, + _param = self._hosted_providers_update_catalog_serialize( + hosted_catalog_update_request=hosted_catalog_update_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3869,7 +3934,7 @@ def hosted_providers_test_hosted_provider( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedProviderTestPublic", + '200': "HostedCatalogUpdatePublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3884,9 +3949,9 @@ def hosted_providers_test_hosted_provider( @validate_call - def hosted_providers_test_hosted_provider_with_http_info( + def hosted_providers_update_catalog_with_http_info( self, - hosted_provider_test_request: HostedProviderTestRequest, + hosted_catalog_update_request: HostedCatalogUpdateRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3899,13 +3964,13 @@ def hosted_providers_test_hosted_provider_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[HostedProviderTestPublic]: - """Test Hosted Provider + ) -> ApiResponse[HostedCatalogUpdatePublic]: + """Update Catalog - Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. + Apply the reviewed prices, then refresh every provider's models, then the cleanup if asked. The price step comes first, so the model step prices new models at the prices it applied, and a model held for want of a price is served once it has one. Without a ``digest`` no price changes. A ``digest`` that no longer names the pending prices answers 409 and changes nothing. ``cleanup`` removes the prices of models no provider serves, with their history. - :param hosted_provider_test_request: (required) - :type hosted_provider_test_request: HostedProviderTestRequest + :param hosted_catalog_update_request: (required) + :type hosted_catalog_update_request: HostedCatalogUpdateRequest :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 @@ -3928,8 +3993,8 @@ def hosted_providers_test_hosted_provider_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_test_hosted_provider_serialize( - hosted_provider_test_request=hosted_provider_test_request, + _param = self._hosted_providers_update_catalog_serialize( + hosted_catalog_update_request=hosted_catalog_update_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3937,7 +4002,7 @@ def hosted_providers_test_hosted_provider_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedProviderTestPublic", + '200': "HostedCatalogUpdatePublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -3952,9 +4017,9 @@ def hosted_providers_test_hosted_provider_with_http_info( @validate_call - def hosted_providers_test_hosted_provider_without_preload_content( + def hosted_providers_update_catalog_without_preload_content( self, - hosted_provider_test_request: HostedProviderTestRequest, + hosted_catalog_update_request: HostedCatalogUpdateRequest, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3968,12 +4033,12 @@ def hosted_providers_test_hosted_provider_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """Test Hosted Provider + """Update Catalog - Ask a provider what it lists on the given credentials, storing nothing. Backs the form's \"Test connection\". With ``name`` naming a stored provider, a field left out is read from it, so an edit can be tested without typing the key again; pointing the stored key at another origin still needs it. Failure comes back in the body. + Apply the reviewed prices, then refresh every provider's models, then the cleanup if asked. The price step comes first, so the model step prices new models at the prices it applied, and a model held for want of a price is served once it has one. Without a ``digest`` no price changes. A ``digest`` that no longer names the pending prices answers 409 and changes nothing. ``cleanup`` removes the prices of models no provider serves, with their history. - :param hosted_provider_test_request: (required) - :type hosted_provider_test_request: HostedProviderTestRequest + :param hosted_catalog_update_request: (required) + :type hosted_catalog_update_request: HostedCatalogUpdateRequest :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 @@ -3996,8 +4061,8 @@ def hosted_providers_test_hosted_provider_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._hosted_providers_test_hosted_provider_serialize( - hosted_provider_test_request=hosted_provider_test_request, + _param = self._hosted_providers_update_catalog_serialize( + hosted_catalog_update_request=hosted_catalog_update_request, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -4005,7 +4070,7 @@ def hosted_providers_test_hosted_provider_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "HostedProviderTestPublic", + '200': "HostedCatalogUpdatePublic", '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -4015,9 +4080,9 @@ def hosted_providers_test_hosted_provider_without_preload_content( return response_data.response - def _hosted_providers_test_hosted_provider_serialize( + def _hosted_providers_update_catalog_serialize( self, - hosted_provider_test_request, + hosted_catalog_update_request, _request_auth, _content_type, _headers, @@ -4043,8 +4108,8 @@ def _hosted_providers_test_hosted_provider_serialize( # process the header parameters # process the form parameters # process the body parameter - if hosted_provider_test_request is not None: - _body_params = hosted_provider_test_request + if hosted_catalog_update_request is not None: + _body_params = hosted_catalog_update_request # set the HTTP header `Accept` @@ -4077,7 +4142,7 @@ def _hosted_providers_test_hosted_provider_serialize( return self.api_client.param_serialize( method='POST', - resource_path='/api/v1/hosted-providers/test', + resource_path='/api/v1/hosted-providers/catalog-update', path_params=_path_params, query_params=_query_params, header_params=_header_params, diff --git a/src/otari/_client/api/oauth_api.py b/src/otari/_client/api/oauth_api.py index a2ff981d..e551d5c5 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 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. + 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``, where set, must be the UUID of the rule's key's organization. ``workspace_id`` and ``service_account_id`` are accepted and ignored, so a client configured for Anthropic needs only its rule and organization changed. 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 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. + 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``, where set, must be the UUID of the rule's key's organization. ``workspace_id`` and ``service_account_id`` are accepted and ignored, so a client configured for Anthropic needs only its rule and organization changed. 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 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. + 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``, where set, must be the UUID of the rule's key's organization. ``workspace_id`` and ``service_account_id`` are accepted and ignored, so a client configured for Anthropic needs only its rule and organization changed. 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_traces_api.py b/src/otari/_client/api/organization_traces_api.py index a850412c..08faa8b2 100644 --- a/src/otari/_client/api/organization_traces_api.py +++ b/src/otari/_client/api/organization_traces_api.py @@ -48,8 +48,8 @@ def __init__(self, api_client=None) -> None: def organization_traces_count_traces( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -75,9 +75,9 @@ def organization_traces_count_traces( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -148,8 +148,8 @@ def organization_traces_count_traces( def organization_traces_count_traces_with_http_info( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -175,9 +175,9 @@ def organization_traces_count_traces_with_http_info( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -248,8 +248,8 @@ def organization_traces_count_traces_with_http_info( def organization_traces_count_traces_without_preload_content( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -275,9 +275,9 @@ def organization_traces_count_traces_without_preload_content( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -759,8 +759,8 @@ def organization_traces_list_traces( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -794,9 +794,9 @@ def organization_traces_list_traces( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -875,8 +875,8 @@ def organization_traces_list_traces_with_http_info( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -910,9 +910,9 @@ def organization_traces_list_traces_with_http_info( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -991,8 +991,8 @@ def organization_traces_list_traces_without_preload_content( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1026,9 +1026,9 @@ def organization_traces_list_traces_without_preload_content( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1514,8 +1514,8 @@ def organization_traces_trace_series( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1537,15 +1537,15 @@ def organization_traces_trace_series( ) -> TraceSeriesPublic: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1618,8 +1618,8 @@ def organization_traces_trace_series_with_http_info( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1641,15 +1641,15 @@ def organization_traces_trace_series_with_http_info( ) -> ApiResponse[TraceSeriesPublic]: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1722,8 +1722,8 @@ def organization_traces_trace_series_without_preload_content( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1745,15 +1745,15 @@ def organization_traces_trace_series_without_preload_content( ) -> RESTResponseType: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] diff --git a/src/otari/_client/api/pricing_api.py b/src/otari/_client/api/pricing_api.py index fa8896af..f6374d31 100644 --- a/src/otari/_client/api/pricing_api.py +++ b/src/otari/_client/api/pricing_api.py @@ -22,7 +22,6 @@ from otari._client.models.accepted_snapshot_response import AcceptedSnapshotResponse from otari._client.models.current_pricing_page import CurrentPricingPage from otari._client.models.pricing_drift_row import PricingDriftRow -from otari._client.models.pricing_refresh_confirmation_response import PricingRefreshConfirmationResponse from otari._client.models.pricing_refresh_preview_response import PricingRefreshPreviewResponse from otari._client.models.pricing_response import PricingResponse from otari._client.models.set_pricing_request import SetPricingRequest @@ -45,273 +44,6 @@ def __init__(self, api_client=None) -> None: self.api_client = api_client - @validate_call - def pricing_confirm_pricing_refresh( - self, - digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - 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, - ) -> PricingRefreshConfirmationResponse: - """Confirm Pricing Refresh - - Activate the latest reviewed default-price snapshot. - - :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. - :type digest: str - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (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._pricing_confirm_pricing_refresh_serialize( - digest=digest, - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshConfirmationResponse", - '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 pricing_confirm_pricing_refresh_with_http_info( - self, - digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - 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[PricingRefreshConfirmationResponse]: - """Confirm Pricing Refresh - - Activate the latest reviewed default-price snapshot. - - :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. - :type digest: str - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (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._pricing_confirm_pricing_refresh_serialize( - digest=digest, - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshConfirmationResponse", - '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 pricing_confirm_pricing_refresh_without_preload_content( - self, - digest: Annotated[Optional[StrictStr], Field(description="The `digest` of the previewed snapshot; 409 when the pending one differs.")] = None, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - 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: - """Confirm Pricing Refresh - - Activate the latest reviewed default-price snapshot. - - :param digest: The `digest` of the previewed snapshot; 409 when the pending one differs. - :type digest: str - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (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._pricing_confirm_pricing_refresh_serialize( - digest=digest, - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshConfirmationResponse", - '422': "HTTPValidationError", - } - response_data = self.api_client.call_api( - *_param, - _request_timeout=_request_timeout - ) - return response_data.response - - - def _pricing_confirm_pricing_refresh_serialize( - self, - digest, - _request_auth, - _content_type, - _headers, - _host_index, - ) -> RequestSerialized: - - _host = None - - _collection_formats: Dict[str, str] = { - } - - _path_params: Dict[str, str] = {} - _query_params: List[Tuple[str, str]] = [] - _header_params: Dict[str, Optional[str]] = _headers or {} - _form_params: List[Tuple[str, str]] = [] - _files: Dict[ - str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] - ] = {} - _body_params: Optional[bytes] = None - - # process the path parameters - # process the query parameters - if digest is not None: - - _query_params.append(('digest', digest)) - - # process the header parameters - # process the form parameters - # process the body parameter - - - # set the HTTP header `Accept` - if 'Accept' not in _header_params: - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) - - - # authentication setting - _auth_settings: List[str] = [ - 'XApiKeyAuth', - 'ApiKeyAuth' - ] - - return self.api_client.param_serialize( - method='POST', - resource_path='/api/v1/pricing/refresh/confirm', - 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 pricing_delete_pricing( self, @@ -2565,253 +2297,6 @@ def _pricing_list_pricing_snapshots_serialize( - @validate_call - def pricing_preview_pricing_refresh( - self, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - Tuple[ - Annotated[StrictFloat, Field(gt=0)], - Annotated[StrictFloat, Field(gt=0)] - ] - ] = None, - _request_auth: Optional[Dict[StrictStr, Any]] = None, - _content_type: Optional[StrictStr] = None, - _headers: Optional[Dict[StrictStr, Any]] = None, - _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> PricingRefreshPreviewResponse: - """Preview Pricing Refresh - - Fetch the latest defaults and hold them for operator review. - - :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._pricing_preview_pricing_refresh_serialize( - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshPreviewResponse", - } - 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 pricing_preview_pricing_refresh_with_http_info( - self, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - Tuple[ - Annotated[StrictFloat, Field(gt=0)], - Annotated[StrictFloat, Field(gt=0)] - ] - ] = None, - _request_auth: Optional[Dict[StrictStr, Any]] = None, - _content_type: Optional[StrictStr] = None, - _headers: Optional[Dict[StrictStr, Any]] = None, - _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[PricingRefreshPreviewResponse]: - """Preview Pricing Refresh - - Fetch the latest defaults and hold them for operator review. - - :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._pricing_preview_pricing_refresh_serialize( - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshPreviewResponse", - } - 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 pricing_preview_pricing_refresh_without_preload_content( - self, - _request_timeout: Union[ - None, - Annotated[StrictFloat, Field(gt=0)], - Tuple[ - Annotated[StrictFloat, Field(gt=0)], - Annotated[StrictFloat, Field(gt=0)] - ] - ] = None, - _request_auth: Optional[Dict[StrictStr, Any]] = None, - _content_type: Optional[StrictStr] = None, - _headers: Optional[Dict[StrictStr, Any]] = None, - _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> RESTResponseType: - """Preview Pricing Refresh - - Fetch the latest defaults and hold them for operator review. - - :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._pricing_preview_pricing_refresh_serialize( - _request_auth=_request_auth, - _content_type=_content_type, - _headers=_headers, - _host_index=_host_index - ) - - _response_types_map: Dict[str, Optional[str]] = { - '200': "PricingRefreshPreviewResponse", - } - response_data = self.api_client.call_api( - *_param, - _request_timeout=_request_timeout - ) - return response_data.response - - - def _pricing_preview_pricing_refresh_serialize( - self, - _request_auth, - _content_type, - _headers, - _host_index, - ) -> RequestSerialized: - - _host = None - - _collection_formats: Dict[str, str] = { - } - - _path_params: Dict[str, str] = {} - _query_params: List[Tuple[str, str]] = [] - _header_params: Dict[str, Optional[str]] = _headers or {} - _form_params: List[Tuple[str, str]] = [] - _files: Dict[ - str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] - ] = {} - _body_params: Optional[bytes] = None - - # process the path parameters - # process the query parameters - # process the header parameters - # process the form parameters - # process the body parameter - - - # set the HTTP header `Accept` - if 'Accept' not in _header_params: - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) - - - # authentication setting - _auth_settings: List[str] = [ - 'XApiKeyAuth', - 'ApiKeyAuth' - ] - - return self.api_client.param_serialize( - method='POST', - resource_path='/api/v1/pricing/refresh', - 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 pricing_reject_pricing_refresh( self, diff --git a/src/otari/_client/api/traces_api.py b/src/otari/_client/api/traces_api.py index ded88859..62b1c3ef 100644 --- a/src/otari/_client/api/traces_api.py +++ b/src/otari/_client/api/traces_api.py @@ -48,8 +48,8 @@ def __init__(self, api_client=None) -> None: def traces_count_traces( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -75,9 +75,9 @@ def traces_count_traces( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -148,8 +148,8 @@ def traces_count_traces( def traces_count_traces_with_http_info( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -175,9 +175,9 @@ def traces_count_traces_with_http_info( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -248,8 +248,8 @@ def traces_count_traces_with_http_info( def traces_count_traces_without_preload_content( self, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -275,9 +275,9 @@ def traces_count_traces_without_preload_content( :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -759,8 +759,8 @@ def traces_list_traces( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -794,9 +794,9 @@ def traces_list_traces( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -875,8 +875,8 @@ def traces_list_traces_with_http_info( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -910,9 +910,9 @@ def traces_list_traces_with_http_info( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -991,8 +991,8 @@ def traces_list_traces_without_preload_content( sort: Annotated[Optional[StrictStr], Field(description="What to order by. Latency runs from a session's start to its last activity.")] = None, order: Annotated[Optional[StrictStr], Field(description="The direction of `sort`.")] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1026,9 +1026,9 @@ def traces_list_traces_without_preload_content( :type order: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1514,8 +1514,8 @@ def traces_trace_series( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1537,15 +1537,15 @@ def traces_trace_series( ) -> TraceSeriesPublic: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1618,8 +1618,8 @@ def traces_trace_series_with_http_info( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1641,15 +1641,15 @@ def traces_trace_series_with_http_info( ) -> ApiResponse[TraceSeriesPublic]: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] @@ -1722,8 +1722,8 @@ def traces_trace_series_without_preload_content( self, bucket: Optional[StrictStr] = None, workspace_id: Annotated[Optional[UUID], Field(description="Only sessions in this workspace. Narrows the caller's scope; never widens it.")] = None, - start: Annotated[Optional[datetime], Field(description="Last activity at or after this instant (ISO 8601).")] = None, - end: Annotated[Optional[datetime], Field(description="Last activity before this instant (ISO 8601).")] = None, + start: Annotated[Optional[datetime], Field(description="Sessions active at or after this instant (ISO 8601).")] = None, + end: Annotated[Optional[datetime], Field(description="Sessions started before this instant (ISO 8601).")] = None, user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Owning users.")] = None, api_key_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="API keys.")] = None, harness: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Agent harnesses.")] = None, @@ -1745,15 +1745,15 @@ def traces_trace_series_without_preload_content( ) -> RESTResponseType: """Trace Series - Count sessions per bucket of their start, split by whether they failed. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. + Count the sessions active in each bucket, split by whether they failed. A session is active from its start to its last activity, so a long one counts in every bucket it ran through. Here ``start`` and ``end`` bound the buckets: a session that began before ``start`` or was still active at ``end`` counts in the buckets between them it overlaps. Buckets are aligned to their size in UTC and only the populated ones are returned. A session failed when it holds an unrecovered error other than a tool's. A tool's error goes back to the model, an MCP tool's included, so a session whose only errors are tools' counts as succeeded. :param bucket: :type bucket: str :param workspace_id: Only sessions in this workspace. Narrows the caller's scope; never widens it. :type workspace_id: UUID - :param start: Last activity at or after this instant (ISO 8601). + :param start: Sessions active at or after this instant (ISO 8601). :type start: datetime - :param end: Last activity before this instant (ISO 8601). + :param end: Sessions started before this instant (ISO 8601). :type end: datetime :param user_id: Owning users. :type user_id: List[str] diff --git a/src/otari/_client/models/__init__.py b/src/otari/_client/models/__init__.py index c7c02d94..50c9d8cb 100644 --- a/src/otari/_client/models/__init__.py +++ b/src/otari/_client/models/__init__.py @@ -244,8 +244,14 @@ from otari._client.models.health_check_status import HealthCheckStatus from otari._client.models.hosted_available_models_public import HostedAvailableModelsPublic from otari._client.models.hosted_catalog_kept_group_public import HostedCatalogKeptGroupPublic +from otari._client.models.hosted_catalog_price_change_public import HostedCatalogPriceChangePublic +from otari._client.models.hosted_catalog_price_update_public import HostedCatalogPriceUpdatePublic from otari._client.models.hosted_catalog_provider_refresh_public import HostedCatalogProviderRefreshPublic from otari._client.models.hosted_catalog_refresh_public import HostedCatalogRefreshPublic +from otari._client.models.hosted_catalog_update_preview_public import HostedCatalogUpdatePreviewPublic +from otari._client.models.hosted_catalog_update_preview_request import HostedCatalogUpdatePreviewRequest +from otari._client.models.hosted_catalog_update_public import HostedCatalogUpdatePublic +from otari._client.models.hosted_catalog_update_request import HostedCatalogUpdateRequest from otari._client.models.hosted_model_create_request import HostedModelCreateRequest from otari._client.models.hosted_model_public import HostedModelPublic from otari._client.models.hosted_model_update_request import HostedModelUpdateRequest @@ -538,7 +544,6 @@ from otari._client.models.pool_status import PoolStatus from otari._client.models.pricing_drift_row import PricingDriftRow from otari._client.models.pricing_refresh_change_response import PricingRefreshChangeResponse -from otari._client.models.pricing_refresh_confirmation_response import PricingRefreshConfirmationResponse from otari._client.models.pricing_refresh_preview_response import PricingRefreshPreviewResponse from otari._client.models.pricing_response import PricingResponse from otari._client.models.pricing_tier import PricingTier @@ -630,6 +635,7 @@ from otari._client.models.tool_charge_line import ToolChargeLine from otari._client.models.tool_choice import ToolChoice from otari._client.models.tool_choice1 import ToolChoice1 +from otari._client.models.tool_cost_public import ToolCostPublic from otari._client.models.tool_meter import ToolMeter from otari._client.models.tool_setting_field import ToolSettingField from otari._client.models.tool_settings_response import ToolSettingsResponse diff --git a/src/otari/_client/models/accepted_snapshot_response.py b/src/otari/_client/models/accepted_snapshot_response.py index fdae7506..0f56c31e 100644 --- a/src/otari/_client/models/accepted_snapshot_response.py +++ b/src/otari/_client/models/accepted_snapshot_response.py @@ -29,7 +29,7 @@ class AcceptedSnapshotResponse(BaseModel): One accepted models.dev snapshot in the history. """ # noqa: E501 accepted_at: datetime - accepted_by: StrictStr = Field(description="`operator` for a dashboard confirm, `schedule` for the auto policy.") + accepted_by: StrictStr = Field(description="`operator` for a catalog update an operator ran, `schedule` for the auto policy.") id: StrictStr model_count: StrictInt __properties: ClassVar[List[str]] = ["accepted_at", "accepted_by", "id", "model_count"] diff --git a/src/otari/_client/models/federation_token_request.py b/src/otari/_client/models/federation_token_request.py index e64d7345..d6b665a5 100644 --- a/src/otari/_client/models/federation_token_request.py +++ b/src/otari/_client/models/federation_token_request.py @@ -31,8 +31,8 @@ class FederationTokenRequest(BaseModel): federation_rule_id: Optional[StrictStr] = Field(default=None, description="The id of the federation rule the identity token must match.") grant_type: Optional[StrictStr] = Field(default=None, description="urn:ietf:params:oauth:grant-type:jwt-bearer") organization_id: Optional[StrictStr] = Field(default=None, description="When set, the UUID of the organization of the rule's key.") - service_account_id: Optional[StrictStr] = Field(default=None, description="When set, the id of the rule's key.") - workspace_id: Optional[StrictStr] = Field(default=None, description="When set, the UUID of the rule's key's workspace.") + service_account_id: Optional[StrictStr] = Field(default=None, description="Ignored. Accepted so that a client configured for Anthropic's service account id is not refused.") + workspace_id: Optional[StrictStr] = Field(default=None, description="Ignored. Accepted so that a client configured for Anthropic's workspace id is not refused.") __properties: ClassVar[List[str]] = ["assertion", "federation_rule_id", "grant_type", "organization_id", "service_account_id", "workspace_id"] model_config = ConfigDict( diff --git a/src/otari/_client/models/gate_summary_public.py b/src/otari/_client/models/gate_summary_public.py index 2e26d57a..14172a68 100644 --- a/src/otari/_client/models/gate_summary_public.py +++ b/src/otari/_client/models/gate_summary_public.py @@ -33,11 +33,13 @@ class GateSummaryPublic(BaseModel): 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.") + origin: Optional[StrictStr] = Field(description="Whether the gate is the repository's (.otari/) or the user's own (~/.otari/).") passed: StrictInt refused: StrictInt = Field(description="Checks where the gate could not decide and held the agent anyway.") + runs: List[StrictStr] = Field(description="The moments the gate runs at (pre_tool_use.edit_target, stop.session, ...).") 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"] + __properties: ClassVar[List[str]] = ["blocked", "enforcement", "flagged", "gate_id", "gate_type", "message", "origin", "passed", "refused", "runs", "span_id", "undecided"] @field_validator('enforcement') def enforcement_validate_enum(cls, value): @@ -49,6 +51,16 @@ def enforcement_validate_enum(cls, value): raise ValueError("must be one of enum values ('required', 'advisory')") return value + @field_validator('origin') + def origin_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(['repo', 'user']): + raise ValueError("must be one of enum values ('repo', 'user')") + return value + model_config = ConfigDict( validate_by_name=True, validate_by_alias=True, @@ -103,6 +115,11 @@ def to_dict(self) -> Dict[str, Any]: if self.message is None and "message" in self.model_fields_set: _dict['message'] = None + # set to None if origin (nullable) is None + # and model_fields_set contains the field + if self.origin is None and "origin" in self.model_fields_set: + _dict['origin'] = 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: @@ -126,8 +143,10 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "gate_id": obj.get("gate_id"), "gate_type": obj.get("gate_type"), "message": obj.get("message"), + "origin": obj.get("origin"), "passed": obj.get("passed"), "refused": obj.get("refused"), + "runs": obj.get("runs"), "span_id": obj.get("span_id"), "undecided": obj.get("undecided") }) diff --git a/src/otari/_client/models/hosted_catalog_price_change_public.py b/src/otari/_client/models/hosted_catalog_price_change_public.py new file mode 100644 index 00000000..ef69a8e6 --- /dev/null +++ b/src/otari/_client/models/hosted_catalog_price_change_public.py @@ -0,0 +1,97 @@ +# 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, field_validator +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 HostedCatalogPriceChangePublic(BaseModel): + """ + One model whose models.dev price a catalog update adds, changes or removes. + """ # noqa: E501 + change: StrictStr + model_key: StrictStr + __properties: ClassVar[List[str]] = ["change", "model_key"] + + @field_validator('change') + def change_validate_enum(cls, value): + """Validates the enum""" + if value not in set(['added', 'changed', 'removed']): + raise ValueError("must be one of enum values ('added', 'changed', 'removed')") + 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 HostedCatalogPriceChangePublic 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 HostedCatalogPriceChangePublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "change": obj.get("change"), + "model_key": obj.get("model_key") + }) + return _obj + + diff --git a/src/otari/_client/models/hosted_catalog_price_update_public.py b/src/otari/_client/models/hosted_catalog_price_update_public.py new file mode 100644 index 00000000..af664c9e --- /dev/null +++ b/src/otari/_client/models/hosted_catalog_price_update_public.py @@ -0,0 +1,118 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, StrictBool, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from otari._client.models.hosted_catalog_price_change_public import HostedCatalogPriceChangePublic +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class HostedCatalogPriceUpdatePublic(BaseModel): + """ + The models.dev price changes a catalog update would apply. ``changes`` is a sample and the counts are the totals. ``digest`` names the fetched prices, so applying them applies what was reviewed. ``needs_review`` is why the scheduled update would hold them for a person under ``auto``. + """ # noqa: E501 + added_count: StrictInt + changed_count: StrictInt + changes: List[HostedCatalogPriceChangePublic] + changes_truncated: StrictBool + digest: StrictStr + fetched_at: datetime + needs_review: StrictBool + removed_count: StrictInt + review_reason: Optional[StrictStr] = None + __properties: ClassVar[List[str]] = ["added_count", "changed_count", "changes", "changes_truncated", "digest", "fetched_at", "needs_review", "removed_count", "review_reason"] + + 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 HostedCatalogPriceUpdatePublic 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 changes (list) + _items = [] + if self.changes: + for _item_changes in self.changes: + if _item_changes: + _items.append(_item_changes.to_dict()) + _dict['changes'] = _items + # set to None if review_reason (nullable) is None + # and model_fields_set contains the field + if self.review_reason is None and "review_reason" in self.model_fields_set: + _dict['review_reason'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of HostedCatalogPriceUpdatePublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "added_count": obj.get("added_count"), + "changed_count": obj.get("changed_count"), + "changes": [HostedCatalogPriceChangePublic.from_dict(_item) for _item in obj["changes"]] if obj.get("changes") is not None else None, + "changes_truncated": obj.get("changes_truncated"), + "digest": obj.get("digest"), + "fetched_at": obj.get("fetched_at"), + "needs_review": obj.get("needs_review"), + "removed_count": obj.get("removed_count"), + "review_reason": obj.get("review_reason") + }) + return _obj + + diff --git a/src/otari/_client/models/hosted_catalog_update_preview_public.py b/src/otari/_client/models/hosted_catalog_update_preview_public.py new file mode 100644 index 00000000..f7827487 --- /dev/null +++ b/src/otari/_client/models/hosted_catalog_update_preview_public.py @@ -0,0 +1,110 @@ +# 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 otari._client.models.hosted_catalog_price_update_public import HostedCatalogPriceUpdatePublic +from otari._client.models.hosted_catalog_refresh_public import HostedCatalogRefreshPublic +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class HostedCatalogUpdatePreviewPublic(BaseModel): + """ + What a catalog update would do: its price changes, then what each provider newly lists. ``prices`` is ``None`` when models.dev changed nothing, or when it could not be fetched, which ``price_error`` then says. ``catalog`` carries the cleanup the preview was asked for, and no removals otherwise. + """ # noqa: E501 + catalog: HostedCatalogRefreshPublic + price_error: Optional[StrictStr] = None + prices: Optional[HostedCatalogPriceUpdatePublic] + __properties: ClassVar[List[str]] = ["catalog", "price_error", "prices"] + + 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 HostedCatalogUpdatePreviewPublic 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 catalog + if self.catalog: + _dict['catalog'] = self.catalog.to_dict() + # override the default output from pydantic by calling `to_dict()` of prices + if self.prices: + _dict['prices'] = self.prices.to_dict() + # set to None if price_error (nullable) is None + # and model_fields_set contains the field + if self.price_error is None and "price_error" in self.model_fields_set: + _dict['price_error'] = None + + # set to None if prices (nullable) is None + # and model_fields_set contains the field + if self.prices is None and "prices" in self.model_fields_set: + _dict['prices'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of HostedCatalogUpdatePreviewPublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "catalog": HostedCatalogRefreshPublic.from_dict(obj["catalog"]) if obj.get("catalog") is not None else None, + "price_error": obj.get("price_error"), + "prices": HostedCatalogPriceUpdatePublic.from_dict(obj["prices"]) if obj.get("prices") is not None else None + }) + return _obj + + diff --git a/src/otari/_client/models/pricing_refresh_confirmation_response.py b/src/otari/_client/models/hosted_catalog_update_preview_request.py similarity index 77% rename from src/otari/_client/models/pricing_refresh_confirmation_response.py rename to src/otari/_client/models/hosted_catalog_update_preview_request.py index b0844974..30b3909a 100644 --- a/src/otari/_client/models/pricing_refresh_confirmation_response.py +++ b/src/otari/_client/models/hosted_catalog_update_preview_request.py @@ -17,18 +17,18 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, StrictBool +from pydantic import BaseModel, ConfigDict, Field, StrictBool 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 PricingRefreshConfirmationResponse(BaseModel): +class HostedCatalogUpdatePreviewRequest(BaseModel): """ - Result of activating a reviewed models.dev refresh. + What to preview: the update alone, or with the cleanup. """ # noqa: E501 - applied: Optional[StrictBool] = True - __properties: ClassVar[List[str]] = ["applied"] + cleanup: Optional[StrictBool] = Field(default=False, description="Also preview removing the prices of models no hosted provider serves.") + __properties: ClassVar[List[str]] = ["cleanup"] model_config = ConfigDict( validate_by_name=True, @@ -48,7 +48,7 @@ def to_json(self) -> str: @classmethod def from_json(cls, json_str: str) -> Optional[Self]: - """Create an instance of PricingRefreshConfirmationResponse from a JSON string""" + """Create an instance of HostedCatalogUpdatePreviewRequest from a JSON string""" return cls.from_dict(json.loads(json_str)) def to_dict(self) -> Dict[str, Any]: @@ -73,7 +73,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: - """Create an instance of PricingRefreshConfirmationResponse from a dict""" + """Create an instance of HostedCatalogUpdatePreviewRequest from a dict""" if obj is None: return None @@ -81,7 +81,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ - "applied": obj.get("applied") if obj.get("applied") is not None else True + "cleanup": obj.get("cleanup") if obj.get("cleanup") is not None else False }) return _obj diff --git a/src/otari/_client/models/hosted_catalog_update_public.py b/src/otari/_client/models/hosted_catalog_update_public.py new file mode 100644 index 00000000..2fe803a9 --- /dev/null +++ b/src/otari/_client/models/hosted_catalog_update_public.py @@ -0,0 +1,94 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictBool +from typing import Any, ClassVar, Dict, List +from otari._client.models.hosted_catalog_refresh_public import HostedCatalogRefreshPublic +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class HostedCatalogUpdatePublic(BaseModel): + """ + What a catalog update did. + """ # noqa: E501 + catalog: HostedCatalogRefreshPublic + prices_applied: StrictBool + __properties: ClassVar[List[str]] = ["catalog", "prices_applied"] + + 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 HostedCatalogUpdatePublic 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 catalog + if self.catalog: + _dict['catalog'] = self.catalog.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of HostedCatalogUpdatePublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "catalog": HostedCatalogRefreshPublic.from_dict(obj["catalog"]) if obj.get("catalog") is not None else None, + "prices_applied": obj.get("prices_applied") + }) + return _obj + + diff --git a/src/otari/_client/models/hosted_catalog_update_request.py b/src/otari/_client/models/hosted_catalog_update_request.py new file mode 100644 index 00000000..90870976 --- /dev/null +++ b/src/otari/_client/models/hosted_catalog_update_request.py @@ -0,0 +1,95 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictBool, 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 HostedCatalogUpdateRequest(BaseModel): + """ + What to apply, as the preview showed it. + """ # noqa: E501 + cleanup: Optional[StrictBool] = Field(default=False, description="Also remove the prices of models no hosted provider serves, with their history.") + digest: Optional[StrictStr] = Field(default=None, description="The `digest` of the previewed prices, to apply them; 409 when the pending prices differ. Without it, no price changes.") + __properties: ClassVar[List[str]] = ["cleanup", "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 HostedCatalogUpdateRequest 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 digest (nullable) is None + # and model_fields_set contains the field + if self.digest is None and "digest" in self.model_fields_set: + _dict['digest'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of HostedCatalogUpdateRequest from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "cleanup": obj.get("cleanup") if obj.get("cleanup") is not None else False, + "digest": obj.get("digest") + }) + return _obj + + diff --git a/src/otari/_client/models/pricing_refresh_preview_response.py b/src/otari/_client/models/pricing_refresh_preview_response.py index 8b25e878..795a649f 100644 --- a/src/otari/_client/models/pricing_refresh_preview_response.py +++ b/src/otari/_client/models/pricing_refresh_preview_response.py @@ -33,7 +33,7 @@ class PricingRefreshPreviewResponse(BaseModel): changed_count: StrictInt changes: List[PricingRefreshChangeResponse] changes_truncated: StrictBool - digest: Optional[StrictStr] = Field(default='', description="Identity of the pending snapshot; send it to confirm or reject to act on exactly this one.") + digest: Optional[StrictStr] = Field(default='', description="Identity of the pending snapshot, to act on exactly this one: send it as `digest` to `POST /hosted-providers/catalog-update` to apply it, or to `POST /pricing/refresh/reject` to discard it.") fetched_at: datetime needs_review: Optional[StrictBool] = Field(default=False, description="True when the update is implausibly large; the scheduled `auto` policy leaves it pending.") protected_model_count: StrictInt diff --git a/src/otari/_client/models/pricing_response.py b/src/otari/_client/models/pricing_response.py index 71cfffe3..ac0ce8aa 100644 --- a/src/otari/_client/models/pricing_response.py +++ b/src/otari/_client/models/pricing_response.py @@ -37,10 +37,11 @@ class PricingResponse(BaseModel): model_key: StrictStr origin: Optional[StrictStr] = Field(description="Which writer set this row: config, api, or migration. Null when recorded before origins were.") output_price_per_million: Union[StrictFloat, StrictInt] + price_per_request: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="USD for each request, for a rate in requests; null for any other unit.") pricing_tiers: List[PricingTier] unit: StrictStr = Field(description="What the rates are per: tokens, requests, or images.") updated_at: StrictStr - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "created_at", "effective_at", "input_price_per_million", "kind", "model_key", "origin", "output_price_per_million", "pricing_tiers", "unit", "updated_at"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "created_at", "effective_at", "input_price_per_million", "kind", "model_key", "origin", "output_price_per_million", "price_per_request", "pricing_tiers", "unit", "updated_at"] model_config = ConfigDict( validate_by_name=True, @@ -103,6 +104,11 @@ def to_dict(self) -> Dict[str, Any]: if self.origin is None and "origin" in self.model_fields_set: _dict['origin'] = None + # set to None if price_per_request (nullable) is None + # and model_fields_set contains the field + if self.price_per_request is None and "price_per_request" in self.model_fields_set: + _dict['price_per_request'] = None + return _dict @classmethod @@ -124,6 +130,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "model_key": obj.get("model_key"), "origin": obj.get("origin"), "output_price_per_million": obj.get("output_price_per_million"), + "price_per_request": obj.get("price_per_request"), "pricing_tiers": [PricingTier.from_dict(_item) for _item in obj["pricing_tiers"]] if obj.get("pricing_tiers") is not None else None, "unit": obj.get("unit"), "updated_at": obj.get("updated_at") diff --git a/src/otari/_client/models/rate_limit_rule_create.py b/src/otari/_client/models/rate_limit_rule_create.py index f835907b..66ebf485 100644 --- a/src/otari/_client/models/rate_limit_rule_create.py +++ b/src/otari/_client/models/rate_limit_rule_create.py @@ -28,15 +28,27 @@ class RateLimitRuleCreate(BaseModel): """ A rule to add. The same fields, limits and validation as a ``rate_limits`` entry in config.yml. """ # noqa: E501 + budgets: Optional[List[StrictStr]] = Field(default=None, description="The budget IDs a `per: budget` rule counts, each on its own; unset counts every budget. Refused on any other rule.") lease_sec: Optional[Union[Annotated[float, Field(strict=True, gt=0.0)], Annotated[int, Field(strict=True, gt=0)]]] = Field(default=900.0, description="How long a max_concurrent slot is held at most. A slot is given back when its response ends; this bounds what a process that dies mid-request keeps.") max_concurrent: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Requests in flight at once.") + mode: Optional[StrictStr] = Field(default='enforce', description="'enforce' (the default) refuses a request over the limit with 429. 'report' counts the same way but serves the request, naming the rule in the Otari-Rate-Limit-Exceeded response header, so a limit can be watched before it is enforced.") models: Optional[List[StrictStr]] = Field(default=None, description="The models a `per: model` rule limits, each as instance:model (the provider instance the model is called through, then the model), each counted on its own. Required there and refused on any other rule.") name: Annotated[str, Field(strict=True)] = Field(description="Names the rule in a 429's detail and in the counter's key. Unique across rate_limits.") per: StrictStr = Field(description="What one count is shared by.") rpm: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Requests per minute.") tpm: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Tokens per minute, counted on what each request used; see tpm_admission for how a request is admitted.") tpm_admission: Optional[StrictStr] = Field(default='used', description="How a tpm limit admits a request. 'used' (the default) admits a request while the minute's tokens are under the limit and counts what it used once it completes, as LiteLLM does. 'estimate' holds the request's estimate (prompt plus max output, or budget_estimate_default_output_tokens) while it runs and refuses it when that does not fit, which is how providers count their own quotas: use it for a limit meant to stay under one.") - __properties: ClassVar[List[str]] = ["lease_sec", "max_concurrent", "models", "name", "per", "rpm", "tpm", "tpm_admission"] + __properties: ClassVar[List[str]] = ["budgets", "lease_sec", "max_concurrent", "mode", "models", "name", "per", "rpm", "tpm", "tpm_admission"] + + @field_validator('mode') + def mode_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(['enforce', 'report']): + raise ValueError("must be one of enum values ('enforce', 'report')") + return value @field_validator('name') def name_validate_regular_expression(cls, value): @@ -51,8 +63,8 @@ def name_validate_regular_expression(cls, value): @field_validator('per') def per_validate_enum(cls, value): """Validates the enum""" - if value not in set(['deployment', 'key', 'user', 'model']): - raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model')") + if value not in set(['deployment', 'key', 'user', 'model', 'budget']): + raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model', 'budget')") return value @field_validator('tpm_admission') @@ -104,6 +116,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if budgets (nullable) is None + # and model_fields_set contains the field + if self.budgets is None and "budgets" in self.model_fields_set: + _dict['budgets'] = None + # set to None if max_concurrent (nullable) is None # and model_fields_set contains the field if self.max_concurrent is None and "max_concurrent" in self.model_fields_set: @@ -136,8 +153,10 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "budgets": obj.get("budgets"), "lease_sec": obj.get("lease_sec") if obj.get("lease_sec") is not None else 900.0, "max_concurrent": obj.get("max_concurrent"), + "mode": obj.get("mode") if obj.get("mode") is not None else 'enforce', "models": obj.get("models"), "name": obj.get("name"), "per": obj.get("per"), diff --git a/src/otari/_client/models/rate_limit_rule_public.py b/src/otari/_client/models/rate_limit_rule_public.py index 4e792026..1b366008 100644 --- a/src/otari/_client/models/rate_limit_rule_public.py +++ b/src/otari/_client/models/rate_limit_rule_public.py @@ -29,8 +29,10 @@ class RateLimitRulePublic(BaseModel): """ One rule in effect, and where it is defined. """ # noqa: E501 + budgets: Optional[List[StrictStr]] = Field(default=None, description="The budget IDs a `per: budget` rule counts, each on its own; unset counts every budget. Refused on any other rule.") lease_sec: Optional[Union[Annotated[float, Field(strict=True, gt=0.0)], Annotated[int, Field(strict=True, gt=0)]]] = Field(default=900.0, description="How long a max_concurrent slot is held at most. A slot is given back when its response ends; this bounds what a process that dies mid-request keeps.") max_concurrent: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Requests in flight at once.") + mode: Optional[StrictStr] = Field(default='enforce', description="'enforce' (the default) refuses a request over the limit with 429. 'report' counts the same way but serves the request, naming the rule in the Otari-Rate-Limit-Exceeded response header, so a limit can be watched before it is enforced.") models: Optional[List[StrictStr]] = Field(default=None, description="The models a `per: model` rule limits, each as instance:model (the provider instance the model is called through, then the model), each counted on its own. Required there and refused on any other rule.") name: Annotated[str, Field(strict=True)] = Field(description="Names the rule in a 429's detail and in the counter's key. Unique across rate_limits.") per: StrictStr = Field(description="What one count is shared by.") @@ -40,7 +42,17 @@ class RateLimitRulePublic(BaseModel): tpm_admission: Optional[StrictStr] = Field(default='used', description="How a tpm limit admits a request. 'used' (the default) admits a request while the minute's tokens are under the limit and counts what it used once it completes, as LiteLLM does. 'estimate' holds the request's estimate (prompt plus max output, or budget_estimate_default_output_tokens) while it runs and refuses it when that does not fit, which is how providers count their own quotas: use it for a limit meant to stay under one.") updated_at: Optional[datetime] = Field(default=None, description="When a stored rule last changed.") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["lease_sec", "max_concurrent", "models", "name", "per", "rpm", "source", "tpm", "tpm_admission", "updated_at"] + __properties: ClassVar[List[str]] = ["budgets", "lease_sec", "max_concurrent", "mode", "models", "name", "per", "rpm", "source", "tpm", "tpm_admission", "updated_at"] + + @field_validator('mode') + def mode_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(['enforce', 'report']): + raise ValueError("must be one of enum values ('enforce', 'report')") + return value @field_validator('name') def name_validate_regular_expression(cls, value): @@ -55,8 +67,8 @@ def name_validate_regular_expression(cls, value): @field_validator('per') def per_validate_enum(cls, value): """Validates the enum""" - if value not in set(['deployment', 'key', 'user', 'model']): - raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model')") + if value not in set(['deployment', 'key', 'user', 'model', 'budget']): + raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model', 'budget')") return value @field_validator('source') @@ -122,6 +134,11 @@ def to_dict(self) -> Dict[str, Any]: for _key, _value in self.additional_properties.items(): _dict[_key] = _value + # set to None if budgets (nullable) is None + # and model_fields_set contains the field + if self.budgets is None and "budgets" in self.model_fields_set: + _dict['budgets'] = None + # set to None if max_concurrent (nullable) is None # and model_fields_set contains the field if self.max_concurrent is None and "max_concurrent" in self.model_fields_set: @@ -159,8 +176,10 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "budgets": obj.get("budgets"), "lease_sec": obj.get("lease_sec") if obj.get("lease_sec") is not None else 900.0, "max_concurrent": obj.get("max_concurrent"), + "mode": obj.get("mode") if obj.get("mode") is not None else 'enforce', "models": obj.get("models"), "name": obj.get("name"), "per": obj.get("per"), diff --git a/src/otari/_client/models/rate_limit_rule_update.py b/src/otari/_client/models/rate_limit_rule_update.py index 36421996..da7084dd 100644 --- a/src/otari/_client/models/rate_limit_rule_update.py +++ b/src/otari/_client/models/rate_limit_rule_update.py @@ -28,14 +28,26 @@ class RateLimitRuleUpdate(BaseModel): """ Fields to change on a stored rule. An omitted field keeps its value; ``null`` clears a limit. The merged rule must still set at least one of rpm, tpm or max_concurrent. """ # noqa: E501 + budgets: Optional[List[StrictStr]] = Field(default=None, description="The budget IDs a per: budget rule counts; null for every budget, and on any other rule.") lease_sec: Optional[Union[Annotated[float, Field(strict=True, gt=0.0)], Annotated[int, Field(strict=True, gt=0)]]] = Field(default=None, description="How long a max_concurrent slot is held at most.") max_concurrent: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Requests in flight at once.") + mode: Optional[StrictStr] = Field(default=None, description="'enforce' refuses a request over the rule; 'report' serves it and names the rule.") models: Optional[List[StrictStr]] = Field(default=None, description="The instance:model names a per: model rule limits; null for any other rule.") per: Optional[StrictStr] = Field(default=None, description="What one count is shared by.") rpm: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Requests per minute.") tpm: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(default=None, description="Tokens per minute.") tpm_admission: Optional[StrictStr] = Field(default=None, description="'used' counts only what a request used; 'estimate' holds its estimate.") - __properties: ClassVar[List[str]] = ["lease_sec", "max_concurrent", "models", "per", "rpm", "tpm", "tpm_admission"] + __properties: ClassVar[List[str]] = ["budgets", "lease_sec", "max_concurrent", "mode", "models", "per", "rpm", "tpm", "tpm_admission"] + + @field_validator('mode') + def mode_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(['enforce', 'report']): + raise ValueError("must be one of enum values ('enforce', 'report')") + return value @field_validator('per') def per_validate_enum(cls, value): @@ -43,8 +55,8 @@ def per_validate_enum(cls, value): if value is None: return value - if value not in set(['deployment', 'key', 'user', 'model']): - raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model')") + if value not in set(['deployment', 'key', 'user', 'model', 'budget']): + raise ValueError("must be one of enum values ('deployment', 'key', 'user', 'model', 'budget')") return value @field_validator('tpm_admission') @@ -96,6 +108,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if budgets (nullable) is None + # and model_fields_set contains the field + if self.budgets is None and "budgets" in self.model_fields_set: + _dict['budgets'] = None + # set to None if lease_sec (nullable) is None # and model_fields_set contains the field if self.lease_sec is None and "lease_sec" in self.model_fields_set: @@ -106,6 +123,11 @@ def to_dict(self) -> Dict[str, Any]: if self.max_concurrent is None and "max_concurrent" in self.model_fields_set: _dict['max_concurrent'] = None + # set to None if mode (nullable) is None + # and model_fields_set contains the field + if self.mode is None and "mode" in self.model_fields_set: + _dict['mode'] = None + # set to None if models (nullable) is None # and model_fields_set contains the field if self.models is None and "models" in self.model_fields_set: @@ -143,8 +165,10 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "budgets": obj.get("budgets"), "lease_sec": obj.get("lease_sec"), "max_concurrent": obj.get("max_concurrent"), + "mode": obj.get("mode"), "models": obj.get("models"), "per": obj.get("per"), "rpm": obj.get("rpm"), diff --git a/src/otari/_client/models/set_pricing_request.py b/src/otari/_client/models/set_pricing_request.py index ef7a775f..d1eeec24 100644 --- a/src/otari/_client/models/set_pricing_request.py +++ b/src/otari/_client/models/set_pricing_request.py @@ -33,13 +33,14 @@ class SetPricingRequest(BaseModel): cache_read_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cached-input tokens") cache_write_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M cache-write (creation) tokens") effective_at: Optional[datetime] = Field(default=None, description="ISO 8601 datetime from which this price applies. Defaults to now if omitted.") - input_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M of the rate's unit: input tokens, requests or images") + input_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M of the rate's unit: input tokens, requests or images") kind: Optional[StrictStr] = Field(default=None, description="What the row prices: 'model' (the default), or 'search' or 'fetch' for a search or fetch instance, keyed by the instance's name and priced per call. Only the deployment operator sets a search or fetch rate.") model_key: StrictStr = Field(description="Model identifier in format 'provider:model', or a search or fetch instance's name for those kinds") - output_price_per_million: Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Price per 1M output tokens; unused by a rate in requests or images") + output_price_per_million: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="Price per 1M output tokens; unused by a rate in requests or images") + price_per_request: Optional[Union[Annotated[float, Field(strict=True, ge=0.0)], Annotated[int, Field(strict=True, ge=0)]]] = Field(default=None, description="USD for each request, whatever it uses: a completion model billed per call, such as Exa's or Liner's answers. Shorthand for unit 'requests' with input_price_per_million at a million times this; not combined with token prices.") pricing_tiers: Optional[List[PricingTier]] = Field(default=None, description="Whole-request context thresholds. Fields omitted by a tier inherit the base rate.") unit: Optional[StrictStr] = Field(default='tokens', description="What the rates are per: 'tokens' for a model, 'requests' for a gateway-run tool, a moderation call, or a completion model billed per call (USD per million requests), 'images' for image generation (USD per million images).") - __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "effective_at", "input_price_per_million", "kind", "model_key", "output_price_per_million", "pricing_tiers", "unit"] + __properties: ClassVar[List[str]] = ["cache_read_price_per_million", "cache_write_price_per_million", "effective_at", "input_price_per_million", "kind", "model_key", "output_price_per_million", "price_per_request", "pricing_tiers", "unit"] @field_validator('kind') def kind_validate_enum(cls, value): @@ -127,6 +128,11 @@ def to_dict(self) -> Dict[str, Any]: if self.kind is None and "kind" in self.model_fields_set: _dict['kind'] = None + # set to None if price_per_request (nullable) is None + # and model_fields_set contains the field + if self.price_per_request is None and "price_per_request" in self.model_fields_set: + _dict['price_per_request'] = None + # set to None if pricing_tiers (nullable) is None # and model_fields_set contains the field if self.pricing_tiers is None and "pricing_tiers" in self.model_fields_set: @@ -151,6 +157,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "kind": obj.get("kind"), "model_key": obj.get("model_key"), "output_price_per_million": obj.get("output_price_per_million"), + "price_per_request": obj.get("price_per_request"), "pricing_tiers": [PricingTier.from_dict(_item) for _item in obj["pricing_tiers"]] if obj.get("pricing_tiers") is not None else None, "unit": obj.get("unit") if obj.get("unit") is not None else 'tokens' }) diff --git a/src/otari/_client/models/span_public.py b/src/otari/_client/models/span_public.py index befa79b7..fe437e74 100644 --- a/src/otari/_client/models/span_public.py +++ b/src/otari/_client/models/span_public.py @@ -27,12 +27,13 @@ class SpanPublic(BaseModel): """ - One span of a session. Content is never part of a span. + One span of a session. Its content is empty unless the deployment keeps content. """ # noqa: E501 approximate: StrictBool = Field(description="True when the start was inferred rather than measured.") attributes: Dict[str, AttributesValue] cache_read_tokens: Optional[StrictInt] = Field(description="Input tokens read from the prompt cache.") cache_write_tokens: Optional[StrictInt] = Field(description="Input tokens written to the prompt cache.") + content: Dict[str, StrictStr] = Field(description="What the span was about (prompt, command, file_path, gate.evidence, gate.detail), only where the deployment keeps content and the agent sent it. Empty otherwise.") cost: Optional[Union[StrictFloat, StrictInt]] duration_ms: Optional[StrictInt] end_time: Optional[datetime] @@ -58,7 +59,7 @@ class SpanPublic(BaseModel): tool_call_id: Optional[StrictStr] tool_name: Optional[StrictStr] tool_type: Optional[StrictStr] - __properties: ClassVar[List[str]] = ["approximate", "attributes", "cache_read_tokens", "cache_write_tokens", "cost", "duration_ms", "end_time", "error_class", "input_tokens", "kind", "model", "name", "opens_turn", "operation", "origin", "otel_span_id", "otel_trace_id", "outcome", "output_tokens", "parent_span_id", "provider", "reasoning_tokens", "recovered", "request_id", "span_id", "start_time", "tool_call_id", "tool_name", "tool_type"] + __properties: ClassVar[List[str]] = ["approximate", "attributes", "cache_read_tokens", "cache_write_tokens", "content", "cost", "duration_ms", "end_time", "error_class", "input_tokens", "kind", "model", "name", "opens_turn", "operation", "origin", "otel_span_id", "otel_trace_id", "outcome", "output_tokens", "parent_span_id", "provider", "reasoning_tokens", "recovered", "request_id", "span_id", "start_time", "tool_call_id", "tool_name", "tool_type"] @field_validator('origin') def origin_validate_enum(cls, value): @@ -241,6 +242,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: else None, "cache_read_tokens": obj.get("cache_read_tokens"), "cache_write_tokens": obj.get("cache_write_tokens"), + "content": obj.get("content"), "cost": obj.get("cost"), "duration_ms": obj.get("duration_ms"), "end_time": obj.get("end_time"), diff --git a/src/otari/_client/models/tool_charge_line.py b/src/otari/_client/models/tool_charge_line.py index 09763791..87b8f7f3 100644 --- a/src/otari/_client/models/tool_charge_line.py +++ b/src/otari/_client/models/tool_charge_line.py @@ -26,7 +26,7 @@ class ToolChargeLine(BaseModel): """ - A gateway-run tool's charge line, one per tool and label. A subclass with ``label`` required, rather than a defaulted field on :class:`UnitChargeLine`, so the per-request, rerank and image lines, and a stored tool line without a label, serialize back without a ``\"label\": null`` they never had. + A gateway-run tool's charge line, one per tool, label and payer. A subclass with ``label`` required, rather than a defaulted field on :class:`UnitChargeLine`, so the per-request, rerank and image lines, and a stored tool line without a label, serialize back without a ``\"label\": null`` they never had. A line written since tools are charged by whose account ran them also carries ``deployment_paid``: true where the deployment's account ran the calls, which charges the organization's funds where the deployment bills them, and false where the organization's own key did. It is kept as an extra key rather than declared, so an older line serializes back without it. """ # noqa: E501 cost: Union[StrictFloat, StrictInt] = Field(description="USD charged for this line.") label: StrictStr = Field(description="What served the calls: ':' for a search or fetch instance, 'builtin:builtin_fetch' for the built-in fetcher, 'org:' for an organization's own key, or 'otari:' for any other gateway-run tool.") diff --git a/src/otari/_client/models/tool_cost_public.py b/src/otari/_client/models/tool_cost_public.py new file mode 100644 index 00000000..0d8627e5 --- /dev/null +++ b/src/otari/_client/models/tool_cost_public.py @@ -0,0 +1,111 @@ +# 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, StrictFloat, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional, Union +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class ToolCostPublic(BaseModel): + """ + An estimate of what one tool call cost, from the model requests either side of it. + """ # noqa: E501 + calling: Union[StrictFloat, StrictInt] = Field(description="Its share of the output of the request that called it.") + calls_sharing_request: StrictInt = Field(description="Tool calls the request that called it made, sharing its output.") + calls_sharing_result: StrictInt = Field(description="Tool calls whose results arrived together, sharing that growth.") + later_requests: StrictInt = Field(description="The later requests that read its result again.") + rereading: Union[StrictFloat, StrictInt] = Field(description="Reading its result again in later requests, until the context was compacted.") + result_tokens: StrictInt = Field(description="About how many tokens its result added to the context.") + span_id: StrictStr + subagent: Optional[Union[StrictFloat, StrictInt]] = Field(description="What a subagent the call ran cost, exactly.") + total: Union[StrictFloat, StrictInt] + writing: Union[StrictFloat, StrictInt] = Field(description="Writing its result into the context, on the next request.") + __properties: ClassVar[List[str]] = ["calling", "calls_sharing_request", "calls_sharing_result", "later_requests", "rereading", "result_tokens", "span_id", "subagent", "total", "writing"] + + 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 ToolCostPublic 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 subagent (nullable) is None + # and model_fields_set contains the field + if self.subagent is None and "subagent" in self.model_fields_set: + _dict['subagent'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ToolCostPublic from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "calling": obj.get("calling"), + "calls_sharing_request": obj.get("calls_sharing_request"), + "calls_sharing_result": obj.get("calls_sharing_result"), + "later_requests": obj.get("later_requests"), + "rereading": obj.get("rereading"), + "result_tokens": obj.get("result_tokens"), + "span_id": obj.get("span_id"), + "subagent": obj.get("subagent"), + "total": obj.get("total"), + "writing": obj.get("writing") + }) + return _obj + + diff --git a/src/otari/_client/models/trace_bucket_public.py b/src/otari/_client/models/trace_bucket_public.py index 9abc15fa..9eca3147 100644 --- a/src/otari/_client/models/trace_bucket_public.py +++ b/src/otari/_client/models/trace_bucket_public.py @@ -28,8 +28,8 @@ class TraceBucketPublic(BaseModel): TraceBucketPublic """ # noqa: E501 bucket: StrictStr = Field(description="Bucket start, ISO 8601 UTC.") - failed: StrictInt = Field(description="Sessions that started in the bucket and hold an unrecovered error other than a tool's. A tool's error, an MCP tool's included, goes back to the model, so it alone does not fail a session.") - succeeded: StrictInt = Field(description="Sessions that started in the bucket and did not fail.") + failed: StrictInt = Field(description="Sessions active in the bucket that hold an unrecovered error other than a tool's. A tool's error, an MCP tool's included, goes back to the model, so it alone does not fail a session.") + succeeded: StrictInt = Field(description="Sessions active in the bucket that did not fail.") __properties: ClassVar[List[str]] = ["bucket", "failed", "succeeded"] model_config = ConfigDict( diff --git a/src/otari/_client/models/trace_detail_public.py b/src/otari/_client/models/trace_detail_public.py index 7075ae1c..4a2ad33d 100644 --- a/src/otari/_client/models/trace_detail_public.py +++ b/src/otari/_client/models/trace_detail_public.py @@ -21,6 +21,7 @@ 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.tool_cost_public import ToolCostPublic from otari._client.models.trace_summary_public import TraceSummaryPublic from otari._client.models.turn_public import TurnPublic from typing import Optional, Set @@ -35,9 +36,10 @@ class TraceDetailPublic(BaseModel): spans: List[SpanPublic] state: StrictStr summary: TraceSummaryPublic + tool_costs: List[ToolCostPublic] = Field(description="An estimate for each tool call between two priced model requests, in the order they were made.") truncated: StrictBool = Field(description="True when the session holds more spans than one read returns.") turns: List[TurnPublic] - __properties: ClassVar[List[str]] = ["gates", "spans", "state", "summary", "truncated", "turns"] + __properties: ClassVar[List[str]] = ["gates", "spans", "state", "summary", "tool_costs", "truncated", "turns"] @field_validator('state') def state_validate_enum(cls, value): @@ -102,6 +104,13 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of summary if self.summary: _dict['summary'] = self.summary.to_dict() + # override the default output from pydantic by calling `to_dict()` of each item in tool_costs (list) + _items = [] + if self.tool_costs: + for _item_tool_costs in self.tool_costs: + if _item_tool_costs: + _items.append(_item_tool_costs.to_dict()) + _dict['tool_costs'] = _items # override the default output from pydantic by calling `to_dict()` of each item in turns (list) _items = [] if self.turns: @@ -125,6 +134,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "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, + "tool_costs": [ToolCostPublic.from_dict(_item) for _item in obj["tool_costs"]] if obj.get("tool_costs") is not None else None, "truncated": obj.get("truncated"), "turns": [TurnPublic.from_dict(_item) for _item in obj["turns"]] if obj.get("turns") is not None else None }) diff --git a/src/otari/_client/models/trace_series_public.py b/src/otari/_client/models/trace_series_public.py index 5a925431..5c42b299 100644 --- a/src/otari/_client/models/trace_series_public.py +++ b/src/otari/_client/models/trace_series_public.py @@ -35,8 +35,8 @@ class TraceSeriesPublic(BaseModel): @field_validator('bucket') def bucket_validate_enum(cls, value): """Validates the enum""" - if value not in set(['hour', 'day']): - raise ValueError("must be one of enum values ('hour', 'day')") + if value not in set(['1m', '5m', '30m', 'hour', '6h', 'day']): + raise ValueError("must be one of enum values ('1m', '5m', '30m', 'hour', '6h', 'day')") return value model_config = ConfigDict(