From 57b0c287ff4abdd09711d594acc81d0d8be8ae14 Mon Sep 17 00:00:00 2001 From: njbrake <33383515+njbrake@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:13:28 +0000 Subject: [PATCH] chore: regenerate SDK client core from Otari OpenAPI spec --- sdk-endpoints.txt | 2 + src/otari/_client/__init__.py | 6 + src/otari/_client/api/__init__.py | 1 + src/otari/_client/api/agent_telemetry_api.py | 314 ++++++++++++++++++ src/otari/_client/api/usage_api.py | 24 +- src/otari/_client/models/__init__.py | 2 + .../models/agent_telemetry_delete_request.py | 140 ++++++++ .../models/agent_telemetry_delete_result.py | 88 +++++ .../_client/models/create_key_request.py | 9 +- .../_client/models/create_key_response.py | 9 +- src/otari/_client/models/key_info.py | 9 +- .../_client/models/update_key_request.py | 9 +- 12 files changed, 597 insertions(+), 16 deletions(-) create mode 100644 src/otari/_client/api/agent_telemetry_api.py create mode 100644 src/otari/_client/models/agent_telemetry_delete_request.py create mode 100644 src/otari/_client/models/agent_telemetry_delete_result.py diff --git a/sdk-endpoints.txt b/sdk-endpoints.txt index 02917ef..49cd485 100644 --- a/sdk-endpoints.txt +++ b/sdk-endpoints.txt @@ -120,6 +120,8 @@ DELETE /v1/usage # not yet wrapped POST /v1/usage/external-events # not yet wrapped POST /v1/usage/set-price # not yet wrapped GET /v1/usage/in-flight # dashboard-only, per-worker live view +# Agent telemetry purge +DELETE /v1/agent-telemetry # not yet wrapped # Routing policies GET /v1/routing/policies # not yet wrapped POST /v1/routing/policies # not yet wrapped diff --git a/src/otari/_client/__init__.py b/src/otari/_client/__init__.py index 0f51d5d..d48a466 100644 --- a/src/otari/_client/__init__.py +++ b/src/otari/_client/__init__.py @@ -18,6 +18,7 @@ # Define package exports __all__ = [ + "AgentTelemetryApi", "AliasesApi", "AudioApi", "AuthApi", @@ -53,6 +54,8 @@ "ApiKeyError", "ApiAttributeError", "ApiException", + "AgentTelemetryDeleteRequest", + "AgentTelemetryDeleteResult", "AliasRequest", "AliasResponse", "ApiKeyId", @@ -373,6 +376,7 @@ ] # import apis into sdk package +from otari._client.api.agent_telemetry_api import AgentTelemetryApi as AgentTelemetryApi from otari._client.api.aliases_api import AliasesApi as AliasesApi from otari._client.api.audio_api import AudioApi as AudioApi from otari._client.api.auth_api import AuthApi as AuthApi @@ -412,6 +416,8 @@ from otari._client.exceptions import ApiException as ApiException # import models into sdk package +from otari._client.models.agent_telemetry_delete_request import AgentTelemetryDeleteRequest as AgentTelemetryDeleteRequest +from otari._client.models.agent_telemetry_delete_result import AgentTelemetryDeleteResult as AgentTelemetryDeleteResult from otari._client.models.alias_request import AliasRequest as AliasRequest from otari._client.models.alias_response import AliasResponse as AliasResponse from otari._client.models.api_key_id import ApiKeyId as ApiKeyId diff --git a/src/otari/_client/api/__init__.py b/src/otari/_client/api/__init__.py index ffd452e..91dc5b6 100644 --- a/src/otari/_client/api/__init__.py +++ b/src/otari/_client/api/__init__.py @@ -1,6 +1,7 @@ # flake8: noqa # import apis into api package +from otari._client.api.agent_telemetry_api import AgentTelemetryApi from otari._client.api.aliases_api import AliasesApi from otari._client.api.audio_api import AudioApi from otari._client.api.auth_api import AuthApi diff --git a/src/otari/_client/api/agent_telemetry_api.py b/src/otari/_client/api/agent_telemetry_api.py new file mode 100644 index 0000000..653c053 --- /dev/null +++ b/src/otari/_client/api/agent_telemetry_api.py @@ -0,0 +1,314 @@ +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import warnings +from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt +from typing import Any, Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated + +from otari._client.models.agent_telemetry_delete_request import AgentTelemetryDeleteRequest +from otari._client.models.agent_telemetry_delete_result import AgentTelemetryDeleteResult + +from otari._client.api_client import ApiClient, RequestSerialized +from otari._client.api_response import ApiResponse +from otari._client.rest import RESTResponseType + + +class AgentTelemetryApi: + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, api_client=None) -> None: + if api_client is None: + api_client = ApiClient.get_default() + self.api_client = api_client + + + @validate_call + def delete_agent_telemetry_rows_v1_agent_telemetry_delete( + self, + agent_telemetry_delete_request: AgentTelemetryDeleteRequest, + _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, + ) -> AgentTelemetryDeleteResult: + """Delete Agent Telemetry Rows + + Delete agent_telemetry rows by explicit ids or by filter (standalone). Target either an explicit selection (`ids`) or everything matching a filter (`by_filter: true` plus optional `user_id` / `api_key_id` / `name` / date range). A selection matching zero rows succeeds with `deleted: 0`. Master-key only. + + :param agent_telemetry_delete_request: (required) + :type agent_telemetry_delete_request: AgentTelemetryDeleteRequest + :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._delete_agent_telemetry_rows_v1_agent_telemetry_delete_serialize( + agent_telemetry_delete_request=agent_telemetry_delete_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AgentTelemetryDeleteResult", + '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 delete_agent_telemetry_rows_v1_agent_telemetry_delete_with_http_info( + self, + agent_telemetry_delete_request: AgentTelemetryDeleteRequest, + _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[AgentTelemetryDeleteResult]: + """Delete Agent Telemetry Rows + + Delete agent_telemetry rows by explicit ids or by filter (standalone). Target either an explicit selection (`ids`) or everything matching a filter (`by_filter: true` plus optional `user_id` / `api_key_id` / `name` / date range). A selection matching zero rows succeeds with `deleted: 0`. Master-key only. + + :param agent_telemetry_delete_request: (required) + :type agent_telemetry_delete_request: AgentTelemetryDeleteRequest + :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._delete_agent_telemetry_rows_v1_agent_telemetry_delete_serialize( + agent_telemetry_delete_request=agent_telemetry_delete_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AgentTelemetryDeleteResult", + '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 delete_agent_telemetry_rows_v1_agent_telemetry_delete_without_preload_content( + self, + agent_telemetry_delete_request: AgentTelemetryDeleteRequest, + _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: + """Delete Agent Telemetry Rows + + Delete agent_telemetry rows by explicit ids or by filter (standalone). Target either an explicit selection (`ids`) or everything matching a filter (`by_filter: true` plus optional `user_id` / `api_key_id` / `name` / date range). A selection matching zero rows succeeds with `deleted: 0`. Master-key only. + + :param agent_telemetry_delete_request: (required) + :type agent_telemetry_delete_request: AgentTelemetryDeleteRequest + :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._delete_agent_telemetry_rows_v1_agent_telemetry_delete_serialize( + agent_telemetry_delete_request=agent_telemetry_delete_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AgentTelemetryDeleteResult", + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _delete_agent_telemetry_rows_v1_agent_telemetry_delete_serialize( + self, + agent_telemetry_delete_request, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if agent_telemetry_delete_request is not None: + _body_params = agent_telemetry_delete_request + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'XApiKeyAuth', + 'ApiKeyAuth' + ] + + return self.api_client.param_serialize( + method='DELETE', + resource_path='/v1/agent-telemetry', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + diff --git a/src/otari/_client/api/usage_api.py b/src/otari/_client/api/usage_api.py index 13baf3b..d4f0041 100644 --- a/src/otari/_client/api/usage_api.py +++ b/src/otari/_client/api/usage_api.py @@ -1384,7 +1384,7 @@ def list_usage_v1_usage_get( self, start_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)")] = None, end_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)")] = None, - user_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, + user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, status: Annotated[Optional[StrictStr], Field(description="Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)")] = None, status_code: Annotated[Optional[StrictInt], Field(description="Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly")] = None, model: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.")] = None, @@ -1396,7 +1396,7 @@ def list_usage_v1_usage_get( priced: Annotated[Optional[StrictBool], Field(description="Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.")] = None, tool: Annotated[Optional[StrictStr], Field(description="Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, code_execution) matches that tool specifically.")] = None, counts_toward_budget: Annotated[Optional[StrictBool], Field(description="Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget")] = None, - request_group_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, + request_group_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, _request_timeout: Union[ @@ -1421,7 +1421,7 @@ def list_usage_v1_usage_get( :param end_date: Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds) :type end_date: datetime :param user_id: Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call. - :type user_id: List[Optional[str]] + :type user_id: List[str] :param status: Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count) :type status: str :param status_code: Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly @@ -1445,7 +1445,7 @@ def list_usage_v1_usage_get( :param counts_toward_budget: Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget :type counts_toward_budget: bool :param request_group_id: Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call. - :type request_group_id: List[Optional[str]] + :type request_group_id: List[str] :param skip: :type skip: int :param limit: @@ -1516,7 +1516,7 @@ def list_usage_v1_usage_get_with_http_info( self, start_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)")] = None, end_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)")] = None, - user_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, + user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, status: Annotated[Optional[StrictStr], Field(description="Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)")] = None, status_code: Annotated[Optional[StrictInt], Field(description="Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly")] = None, model: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.")] = None, @@ -1528,7 +1528,7 @@ def list_usage_v1_usage_get_with_http_info( priced: Annotated[Optional[StrictBool], Field(description="Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.")] = None, tool: Annotated[Optional[StrictStr], Field(description="Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, code_execution) matches that tool specifically.")] = None, counts_toward_budget: Annotated[Optional[StrictBool], Field(description="Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget")] = None, - request_group_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, + request_group_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, _request_timeout: Union[ @@ -1553,7 +1553,7 @@ def list_usage_v1_usage_get_with_http_info( :param end_date: Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds) :type end_date: datetime :param user_id: Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call. - :type user_id: List[Optional[str]] + :type user_id: List[str] :param status: Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count) :type status: str :param status_code: Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly @@ -1577,7 +1577,7 @@ def list_usage_v1_usage_get_with_http_info( :param counts_toward_budget: Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget :type counts_toward_budget: bool :param request_group_id: Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call. - :type request_group_id: List[Optional[str]] + :type request_group_id: List[str] :param skip: :type skip: int :param limit: @@ -1648,7 +1648,7 @@ def list_usage_v1_usage_get_without_preload_content( self, start_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)")] = None, end_date: Annotated[Optional[datetime], Field(description="Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)")] = None, - user_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, + user_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.")] = None, status: Annotated[Optional[StrictStr], Field(description="Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)")] = None, status_code: Annotated[Optional[StrictInt], Field(description="Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly")] = None, model: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=50)]], Field(description="Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.")] = None, @@ -1660,7 +1660,7 @@ def list_usage_v1_usage_get_without_preload_content( priced: Annotated[Optional[StrictBool], Field(description="Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.")] = None, tool: Annotated[Optional[StrictStr], Field(description="Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, code_execution) matches that tool specifically.")] = None, counts_toward_budget: Annotated[Optional[StrictBool], Field(description="Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget")] = None, - request_group_id: Annotated[Optional[Annotated[List[Optional[StrictStr]], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, + request_group_id: Annotated[Optional[Annotated[List[StrictStr], Field(max_length=1000)]], Field(description="Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.")] = None, skip: Optional[Annotated[int, Field(strict=True, ge=0)]] = None, limit: Optional[Annotated[int, Field(le=1000, strict=True, ge=1)]] = None, _request_timeout: Union[ @@ -1685,7 +1685,7 @@ def list_usage_v1_usage_get_without_preload_content( :param end_date: Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds) :type end_date: datetime :param user_id: Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call. - :type user_id: List[Optional[str]] + :type user_id: List[str] :param status: Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count) :type status: str :param status_code: Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly @@ -1709,7 +1709,7 @@ def list_usage_v1_usage_get_without_preload_content( :param counts_toward_budget: Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget :type counts_toward_budget: bool :param request_group_id: Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call. - :type request_group_id: List[Optional[str]] + :type request_group_id: List[str] :param skip: :type skip: int :param limit: diff --git a/src/otari/_client/models/__init__.py b/src/otari/_client/models/__init__.py index 27e4e29..6fc6f33 100644 --- a/src/otari/_client/models/__init__.py +++ b/src/otari/_client/models/__init__.py @@ -13,6 +13,8 @@ """ # noqa: E501 # import models into model package +from otari._client.models.agent_telemetry_delete_request import AgentTelemetryDeleteRequest +from otari._client.models.agent_telemetry_delete_result import AgentTelemetryDeleteResult from otari._client.models.alias_request import AliasRequest from otari._client.models.alias_response import AliasResponse from otari._client.models.api_key_id import ApiKeyId diff --git a/src/otari/_client/models/agent_telemetry_delete_request.py b/src/otari/_client/models/agent_telemetry_delete_request.py new file mode 100644 index 0000000..23ba0bf --- /dev/null +++ b/src/otari/_client/models/agent_telemetry_delete_request.py @@ -0,0 +1,140 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing_extensions import Annotated +from otari._client.models.api_key_id import ApiKeyId +from otari._client.models.user_id import UserId +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class AgentTelemetryDeleteRequest(BaseModel): + """ + Selection of agent_telemetry rows to delete. + """ # noqa: E501 + api_key_id: Optional[ApiKeyId] = None + by_filter: Optional[StrictBool] = False + end_date: Optional[datetime] = None + ids: Optional[Annotated[List[StrictStr], Field(max_length=1000)]] = None + name: Optional[StrictStr] = None + start_date: Optional[datetime] = None + user_id: Optional[UserId] = None + __properties: ClassVar[List[str]] = ["api_key_id", "by_filter", "end_date", "ids", "name", "start_date", "user_id"] + + 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 AgentTelemetryDeleteRequest 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 api_key_id + if self.api_key_id: + _dict['api_key_id'] = self.api_key_id.to_dict() + # override the default output from pydantic by calling `to_dict()` of user_id + if self.user_id: + _dict['user_id'] = self.user_id.to_dict() + # set to None if api_key_id (nullable) is None + # and model_fields_set contains the field + if self.api_key_id is None and "api_key_id" in self.model_fields_set: + _dict['api_key_id'] = None + + # set to None if end_date (nullable) is None + # and model_fields_set contains the field + if self.end_date is None and "end_date" in self.model_fields_set: + _dict['end_date'] = None + + # set to None if ids (nullable) is None + # and model_fields_set contains the field + if self.ids is None and "ids" in self.model_fields_set: + _dict['ids'] = None + + # set to None if name (nullable) is None + # and model_fields_set contains the field + if self.name is None and "name" in self.model_fields_set: + _dict['name'] = None + + # set to None if start_date (nullable) is None + # and model_fields_set contains the field + if self.start_date is None and "start_date" in self.model_fields_set: + _dict['start_date'] = None + + # set to None if user_id (nullable) is None + # and model_fields_set contains the field + if self.user_id is None and "user_id" in self.model_fields_set: + _dict['user_id'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AgentTelemetryDeleteRequest from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "api_key_id": ApiKeyId.from_dict(obj["api_key_id"]) if obj.get("api_key_id") is not None else None, + "by_filter": obj.get("by_filter") if obj.get("by_filter") is not None else False, + "end_date": obj.get("end_date"), + "ids": obj.get("ids"), + "name": obj.get("name"), + "start_date": obj.get("start_date"), + "user_id": UserId.from_dict(obj["user_id"]) if obj.get("user_id") is not None else None + }) + return _obj + + diff --git a/src/otari/_client/models/agent_telemetry_delete_result.py b/src/otari/_client/models/agent_telemetry_delete_result.py new file mode 100644 index 0000000..08178d7 --- /dev/null +++ b/src/otari/_client/models/agent_telemetry_delete_result.py @@ -0,0 +1,88 @@ +# coding: utf-8 + +""" + otari + + Otari, an OpenAI-compatible LLM gateway with API key management + + The version of the OpenAPI document: 0.0.0-dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictInt +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 AgentTelemetryDeleteResult(BaseModel): + """ + How many rows the delete removed. + """ # noqa: E501 + deleted: Optional[StrictInt] = 0 + __properties: ClassVar[List[str]] = ["deleted"] + + 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 AgentTelemetryDeleteResult 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 AgentTelemetryDeleteResult from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "deleted": obj.get("deleted") if obj.get("deleted") is not None else 0 + }) + return _obj + + diff --git a/src/otari/_client/models/create_key_request.py b/src/otari/_client/models/create_key_request.py index 062fe2c..9d80c46 100644 --- a/src/otari/_client/models/create_key_request.py +++ b/src/otari/_client/models/create_key_request.py @@ -29,13 +29,14 @@ class CreateKeyRequest(BaseModel): Request model for creating a new API key. """ # noqa: E501 allowed_models: Optional[List[StrictStr]] = Field(default=None, description="Model allow-list: null = any model, [] = deny all, or canonical instance:model entries (with instance:* / instance:prefix* wildcards).") + capture_agent_telemetry: Optional[StrictBool] = Field(default=None, description="Per-key override of the deployment-wide capture_agent_telemetry setting: null (default) inherits it, true always stores behavioral events (tool_result, tool_decision, user_prompt, api_error) from POST /v1/logs, false always discards them. Usage capture and billing are unaffected either way.") exclude_from_budget: Optional[StrictBool] = Field(default=False, description="When true, requests on this key are logged with cost but never reserved, reconciled into the user's spend, or gated by budget.") expires_at: Optional[datetime] = Field(default=None, description="Optional expiration timestamp") key_name: Optional[StrictStr] = Field(default=None, description="Optional name for the key") metadata: Optional[Dict[str, Any]] = Field(default=None, description="Optional metadata") reject_user_mismatch: Optional[StrictBool] = Field(default=None, description="Per-key override of the deployment-wide reject_user_mismatch setting: null (default) inherits it, true always rejects a request naming a different 'user', false always accepts it. Spend binds to this key's own user either way.") user_id: Optional[StrictStr] = Field(default=None, description="Optional user ID to associate with this key") - __properties: ClassVar[List[str]] = ["allowed_models", "exclude_from_budget", "expires_at", "key_name", "metadata", "reject_user_mismatch", "user_id"] + __properties: ClassVar[List[str]] = ["allowed_models", "capture_agent_telemetry", "exclude_from_budget", "expires_at", "key_name", "metadata", "reject_user_mismatch", "user_id"] model_config = ConfigDict( validate_by_name=True, @@ -81,6 +82,11 @@ def to_dict(self) -> Dict[str, Any]: if self.allowed_models is None and "allowed_models" in self.model_fields_set: _dict['allowed_models'] = None + # set to None if capture_agent_telemetry (nullable) is None + # and model_fields_set contains the field + if self.capture_agent_telemetry is None and "capture_agent_telemetry" in self.model_fields_set: + _dict['capture_agent_telemetry'] = None + # set to None if expires_at (nullable) is None # and model_fields_set contains the field if self.expires_at is None and "expires_at" in self.model_fields_set: @@ -114,6 +120,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "allowed_models": obj.get("allowed_models"), + "capture_agent_telemetry": obj.get("capture_agent_telemetry"), "exclude_from_budget": obj.get("exclude_from_budget") if obj.get("exclude_from_budget") is not None else False, "expires_at": obj.get("expires_at"), "key_name": obj.get("key_name"), diff --git a/src/otari/_client/models/create_key_response.py b/src/otari/_client/models/create_key_response.py index 16990bf..36b03dd 100644 --- a/src/otari/_client/models/create_key_response.py +++ b/src/otari/_client/models/create_key_response.py @@ -28,6 +28,7 @@ class CreateKeyResponse(BaseModel): Response model for creating a new API key. """ # noqa: E501 allowed_models: Optional[List[StrictStr]] + capture_agent_telemetry: Optional[StrictBool] created_at: StrictStr exclude_from_budget: StrictBool expires_at: Optional[StrictStr] @@ -39,7 +40,7 @@ class CreateKeyResponse(BaseModel): metadata: Dict[str, Any] reject_user_mismatch: Optional[StrictBool] user_id: Optional[StrictStr] - __properties: ClassVar[List[str]] = ["allowed_models", "created_at", "exclude_from_budget", "expires_at", "id", "is_active", "key", "key_name", "key_prefix", "metadata", "reject_user_mismatch", "user_id"] + __properties: ClassVar[List[str]] = ["allowed_models", "capture_agent_telemetry", "created_at", "exclude_from_budget", "expires_at", "id", "is_active", "key", "key_name", "key_prefix", "metadata", "reject_user_mismatch", "user_id"] model_config = ConfigDict( validate_by_name=True, @@ -85,6 +86,11 @@ def to_dict(self) -> Dict[str, Any]: if self.allowed_models is None and "allowed_models" in self.model_fields_set: _dict['allowed_models'] = None + # set to None if capture_agent_telemetry (nullable) is None + # and model_fields_set contains the field + if self.capture_agent_telemetry is None and "capture_agent_telemetry" in self.model_fields_set: + _dict['capture_agent_telemetry'] = None + # set to None if expires_at (nullable) is None # and model_fields_set contains the field if self.expires_at is None and "expires_at" in self.model_fields_set: @@ -123,6 +129,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "allowed_models": obj.get("allowed_models"), + "capture_agent_telemetry": obj.get("capture_agent_telemetry"), "created_at": obj.get("created_at"), "exclude_from_budget": obj.get("exclude_from_budget"), "expires_at": obj.get("expires_at"), diff --git a/src/otari/_client/models/key_info.py b/src/otari/_client/models/key_info.py index dda3fe5..a69b8f2 100644 --- a/src/otari/_client/models/key_info.py +++ b/src/otari/_client/models/key_info.py @@ -28,6 +28,7 @@ class KeyInfo(BaseModel): Response model for key information. """ # noqa: E501 allowed_models: Optional[List[StrictStr]] + capture_agent_telemetry: Optional[StrictBool] created_at: StrictStr exclude_from_budget: StrictBool expires_at: Optional[StrictStr] @@ -39,7 +40,7 @@ class KeyInfo(BaseModel): metadata: Dict[str, Any] reject_user_mismatch: Optional[StrictBool] user_id: Optional[StrictStr] - __properties: ClassVar[List[str]] = ["allowed_models", "created_at", "exclude_from_budget", "expires_at", "id", "is_active", "key_name", "key_prefix", "last_used_at", "metadata", "reject_user_mismatch", "user_id"] + __properties: ClassVar[List[str]] = ["allowed_models", "capture_agent_telemetry", "created_at", "exclude_from_budget", "expires_at", "id", "is_active", "key_name", "key_prefix", "last_used_at", "metadata", "reject_user_mismatch", "user_id"] model_config = ConfigDict( validate_by_name=True, @@ -85,6 +86,11 @@ def to_dict(self) -> Dict[str, Any]: if self.allowed_models is None and "allowed_models" in self.model_fields_set: _dict['allowed_models'] = None + # set to None if capture_agent_telemetry (nullable) is None + # and model_fields_set contains the field + if self.capture_agent_telemetry is None and "capture_agent_telemetry" in self.model_fields_set: + _dict['capture_agent_telemetry'] = None + # set to None if expires_at (nullable) is None # and model_fields_set contains the field if self.expires_at is None and "expires_at" in self.model_fields_set: @@ -128,6 +134,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "allowed_models": obj.get("allowed_models"), + "capture_agent_telemetry": obj.get("capture_agent_telemetry"), "created_at": obj.get("created_at"), "exclude_from_budget": obj.get("exclude_from_budget"), "expires_at": obj.get("expires_at"), diff --git a/src/otari/_client/models/update_key_request.py b/src/otari/_client/models/update_key_request.py index 644605a..32015de 100644 --- a/src/otari/_client/models/update_key_request.py +++ b/src/otari/_client/models/update_key_request.py @@ -29,13 +29,14 @@ class UpdateKeyRequest(BaseModel): Request model for updating a key. """ # noqa: E501 allowed_models: Optional[List[StrictStr]] = None + capture_agent_telemetry: Optional[StrictBool] = None exclude_from_budget: Optional[StrictBool] = None expires_at: Optional[datetime] = None is_active: Optional[StrictBool] = None key_name: Optional[StrictStr] = None metadata: Optional[Dict[str, Any]] = None reject_user_mismatch: Optional[StrictBool] = None - __properties: ClassVar[List[str]] = ["allowed_models", "exclude_from_budget", "expires_at", "is_active", "key_name", "metadata", "reject_user_mismatch"] + __properties: ClassVar[List[str]] = ["allowed_models", "capture_agent_telemetry", "exclude_from_budget", "expires_at", "is_active", "key_name", "metadata", "reject_user_mismatch"] model_config = ConfigDict( validate_by_name=True, @@ -81,6 +82,11 @@ def to_dict(self) -> Dict[str, Any]: if self.allowed_models is None and "allowed_models" in self.model_fields_set: _dict['allowed_models'] = None + # set to None if capture_agent_telemetry (nullable) is None + # and model_fields_set contains the field + if self.capture_agent_telemetry is None and "capture_agent_telemetry" in self.model_fields_set: + _dict['capture_agent_telemetry'] = None + # set to None if exclude_from_budget (nullable) is None # and model_fields_set contains the field if self.exclude_from_budget is None and "exclude_from_budget" in self.model_fields_set: @@ -124,6 +130,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "allowed_models": obj.get("allowed_models"), + "capture_agent_telemetry": obj.get("capture_agent_telemetry"), "exclude_from_budget": obj.get("exclude_from_budget"), "expires_at": obj.get("expires_at"), "is_active": obj.get("is_active"),