fleet-memory/hindsight-clients/python/hindsight_client_api/rest.py
Nicolò Boschi c2ac7d0440
feat: support vertex as llm provider (#233)
* feat: support vertex as llm provider

* fix

* fix: add uv index-strategy to resolve dependency conflicts with pytorch index

When using pytorch index for faster torch downloads in CI,
filelock dependency resolution was failing because pytorch index
only has older versions. Adding unsafe-best-match strategy allows
uv to search all configured indexes.

Also fix type checking warnings from ty.

* fix: add index-strategy to root pyproject.toml for workspace-level uv resolution

* chore: regenerate client SDKs after Vertex AI support
2026-01-29 16:13:57 -05:00

235 lines
7.7 KiB
Python

# coding: utf-8
"""
Hindsight HTTP API
HTTP API for Hindsight
The version of the OpenAPI document: 0.4.2
Generated by OpenAPI Generator (https://openapi-generator.tech)
Do not edit the class manually.
""" # noqa: E501
import io
import json
import re
import ssl
from typing import Optional, Union
import aiohttp
import aiohttp_retry
from hindsight_client_api.exceptions import ApiException, ApiValueError
RESTResponseType = aiohttp.ClientResponse
ALLOW_RETRY_METHODS = frozenset({'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE'})
class RESTResponse(io.IOBase):
def __init__(self, resp) -> None:
self.response = resp
self.status = resp.status
self.reason = resp.reason
self.data = None
async def read(self):
if self.data is None:
self.data = await self.response.read()
return self.data
def getheaders(self):
"""Returns a CIMultiDictProxy of the response headers."""
return self.response.headers
def getheader(self, name, default=None):
"""Returns a given response header."""
return self.response.headers.get(name, default)
class RESTClientObject:
def __init__(self, configuration) -> None:
# Store configuration for deferred initialization
# aiohttp.TCPConnector requires a running event loop, so we defer
# creation until the first request (which runs in async context)
self._configuration = configuration
self._pool_manager: Optional[aiohttp.ClientSession] = None
self._retry_client: Optional[aiohttp_retry.RetryClient] = None
self.proxy = configuration.proxy
self.proxy_headers = configuration.proxy_headers
def _ensure_session(self) -> None:
"""Create aiohttp session lazily (must be called from async context)."""
if self._pool_manager is not None:
return
configuration = self._configuration
maxsize = configuration.connection_pool_maxsize
ssl_context = ssl.create_default_context(
cafile=configuration.ssl_ca_cert
)
if configuration.cert_file:
ssl_context.load_cert_chain(
configuration.cert_file, keyfile=configuration.key_file
)
if not configuration.verify_ssl:
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
connector = aiohttp.TCPConnector(
limit=maxsize,
ssl=ssl_context
)
self._pool_manager = aiohttp.ClientSession(
connector=connector,
trust_env=True
)
retries = configuration.retries
if retries is not None:
self._retry_client = aiohttp_retry.RetryClient(
client_session=self._pool_manager,
retry_options=aiohttp_retry.ExponentialRetry(
attempts=retries,
factor=2.0,
start_timeout=0.1,
max_timeout=120.0
)
)
@property
def pool_manager(self) -> aiohttp.ClientSession:
"""Get the pool manager, initializing if needed."""
self._ensure_session()
return self._pool_manager
@property
def retry_client(self) -> Optional[aiohttp_retry.RetryClient]:
"""Get the retry client, initializing if needed."""
self._ensure_session()
return self._retry_client
async def close(self):
if self._pool_manager is not None:
await self._pool_manager.close()
if self._retry_client is not None:
await self._retry_client.close()
async def request(
self,
method,
url,
headers=None,
body=None,
post_params=None,
_request_timeout=None
):
"""Execute request
:param method: http request method
:param url: http request url
:param headers: http request headers
:param body: request json body, for `application/json`
:param post_params: request post parameters,
`application/x-www-form-urlencoded`
and `multipart/form-data`
: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.
"""
method = method.upper()
assert method in [
'GET',
'HEAD',
'DELETE',
'POST',
'PUT',
'PATCH',
'OPTIONS'
]
if post_params and body:
raise ApiValueError(
"body parameter cannot be used with post_params parameter."
)
post_params = post_params or {}
headers = headers or {}
# url already contains the URL query string
timeout = _request_timeout or 5 * 60
if 'Content-Type' not in headers:
headers['Content-Type'] = 'application/json'
args = {
"method": method,
"url": url,
"timeout": timeout,
"headers": headers
}
if self.proxy:
args["proxy"] = self.proxy
if self.proxy_headers:
args["proxy_headers"] = self.proxy_headers
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
if re.search('json', headers['Content-Type'], re.IGNORECASE):
if body is not None:
body = json.dumps(body)
args["data"] = body
elif headers['Content-Type'] == 'application/x-www-form-urlencoded':
args["data"] = aiohttp.FormData(post_params)
elif headers['Content-Type'] == 'multipart/form-data':
# must del headers['Content-Type'], or the correct
# Content-Type which generated by aiohttp
del headers['Content-Type']
data = aiohttp.FormData()
for param in post_params:
k, v = param
if isinstance(v, tuple) and len(v) == 3:
data.add_field(
k,
value=v[1],
filename=v[0],
content_type=v[2]
)
else:
# Ensures that dict objects are serialized
if isinstance(v, dict):
v = json.dumps(v)
elif isinstance(v, int):
v = str(v)
data.add_field(k, v)
args["data"] = data
# Pass a `bytes` or `str` parameter directly in the body to support
# other content types than Json when `body` argument is provided
# in serialized form
elif isinstance(body, str) or isinstance(body, bytes):
args["data"] = body
else:
# Cannot generate the request from given parameters
msg = """Cannot prepare a request message for provided
arguments. Please check that your arguments match
declared content type."""
raise ApiException(status=0, reason=msg)
pool_manager: Union[aiohttp.ClientSession, aiohttp_retry.RetryClient]
if self.retry_client is not None and method in ALLOW_RETRY_METHODS:
pool_manager = self.retry_client
else:
pool_manager = self.pool_manager
r = await pool_manager.request(**args)
return RESTResponse(r)