diff --git a/bin/generate-sdk.sh b/bin/generate-sdk.sh index 73dfc58..a036519 100755 --- a/bin/generate-sdk.sh +++ b/bin/generate-sdk.sh @@ -23,14 +23,14 @@ def run_command(cmd: str, description: str) -> bool: def patch_ndjson_handling() -> bool: - """Add NDJSON handling to execute_cypher_query._parse_response.""" + """Add NDJSON handling to execute_cypher._parse_response.""" file_path = ( Path(__file__).parent.parent / "robosystems_client" / "api" / "query" - / "execute_cypher_query.py" + / "execute_cypher.py" ) if not file_path.exists(): @@ -55,7 +55,7 @@ def patch_ndjson_handling() -> bool: """ # Find the location to insert the patch (raw generated code uses 4 spaces). - # The /v1/graphs/{graph_id}/query endpoint declares `response_model=None` + # The /v1/graphs/{graph_id}/query/cypher endpoint declares `response_model=None` # (it returns JSONResponse | StreamingResponse | EventSourceResponse depending # on mode), so the generator emits `response.json()` directly with no typed # Response200 model. diff --git a/robosystems_client/api/content_operations/__init__.py b/robosystems_client/api/content_operations/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/robosystems_client/api/content_operations/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/robosystems_client/api/content_operations/op_create_file_upload.py b/robosystems_client/api/content_operations/op_create_file_upload.py new file mode 100644 index 0000000..2a5fca7 --- /dev/null +++ b/robosystems_client/api/content_operations/op_create_file_upload.py @@ -0,0 +1,260 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.file_upload_request import FileUploadRequest +from ...models.operation_envelope import OperationEnvelope +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: FileUploadRequest, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/create-file-upload".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Create File Upload (presign an S3 upload) + + Presign an S3 URL for direct upload and register the file. After uploading to the returned URL, call + `POST /operations/ingest-file` to stage it into DuckDB. The staging table is auto-created if + missing. Not allowed on entity graphs or shared repositories. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Create File Upload (presign an S3 upload) + + Presign an S3 URL for direct upload and register the file. After uploading to the returned URL, call + `POST /operations/ingest-file` to stage it into DuckDB. The staging table is auto-created if + missing. Not allowed on entity graphs or shared repositories. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Create File Upload (presign an S3 upload) + + Presign an S3 URL for direct upload and register the file. After uploading to the returned URL, call + `POST /operations/ingest-file` to stage it into DuckDB. The staging table is auto-created if + missing. Not allowed on entity graphs or shared repositories. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Create File Upload (presign an S3 upload) + + Presign an S3 URL for direct upload and register the file. After uploading to the returned URL, call + `POST /operations/ingest-file` to stage it into DuckDB. The staging table is auto-created if + missing. Not allowed on entity graphs or shared repositories. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/content_operations/op_delete_document.py b/robosystems_client/api/content_operations/op_delete_document.py new file mode 100644 index 0000000..cf038cc --- /dev/null +++ b/robosystems_client/api/content_operations/op_delete_document.py @@ -0,0 +1,252 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_document_op import DeleteDocumentOp +from ...models.error_response import ErrorResponse +from ...models.operation_envelope import OperationEnvelope +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: DeleteDocumentOp, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/delete-document".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteDocumentOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Delete Document (remove from the corpus) + + Delete a document from PostgreSQL and OpenSearch by id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteDocumentOp): Body for delete-document (corpus content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteDocumentOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Delete Document (remove from the corpus) + + Delete a document from PostgreSQL and OpenSearch by id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteDocumentOp): Body for delete-document (corpus content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteDocumentOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Delete Document (remove from the corpus) + + Delete a document from PostgreSQL and OpenSearch by id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteDocumentOp): Body for delete-document (corpus content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteDocumentOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Delete Document (remove from the corpus) + + Delete a document from PostgreSQL and OpenSearch by id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteDocumentOp): Body for delete-document (corpus content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/content_operations/op_delete_file.py b/robosystems_client/api/content_operations/op_delete_file.py new file mode 100644 index 0000000..f7b4580 --- /dev/null +++ b/robosystems_client/api/content_operations/op_delete_file.py @@ -0,0 +1,256 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_file_op import DeleteFileOp +from ...models.error_response import ErrorResponse +from ...models.operation_envelope import OperationEnvelope +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: DeleteFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/delete-file".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Delete File + + Delete a file from S3 and PostgreSQL. `cascade=true` also removes its rows from DuckDB staging + tables and marks the graph stale. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteFileOp): Body for delete-file (raw content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Delete File + + Delete a file from S3 and PostgreSQL. `cascade=true` also removes its rows from DuckDB staging + tables and marks the graph stale. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteFileOp): Body for delete-file (raw content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Delete File + + Delete a file from S3 and PostgreSQL. `cascade=true` also removes its rows from DuckDB staging + tables and marks the graph stale. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteFileOp): Body for delete-file (raw content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: DeleteFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Delete File + + Delete a file from S3 and PostgreSQL. `cascade=true` also removes its rows from DuckDB staging + tables and marks the graph stale. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (DeleteFileOp): Body for delete-file (raw content-op). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/files/create_file_upload.py b/robosystems_client/api/content_operations/op_forget.py similarity index 55% rename from robosystems_client/api/files/create_file_upload.py rename to robosystems_client/api/content_operations/op_forget.py index bf6a5ad..bf0bdb4 100644 --- a/robosystems_client/api/files/create_file_upload.py +++ b/robosystems_client/api/content_operations/op_forget.py @@ -7,22 +7,24 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.error_response import ErrorResponse -from ...models.file_upload_request import FileUploadRequest -from ...models.file_upload_response import FileUploadResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import Response +from ...models.forget_op import ForgetOp +from ...models.operation_envelope import OperationEnvelope +from ...types import UNSET, Response, Unset def _get_kwargs( graph_id: str, *, - body: FileUploadRequest, + body: ForgetOp, + idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/graphs/{graph_id}/files".format( + "url": "/v1/graphs/{graph_id}/operations/forget".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -37,9 +39,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorResponse | FileUploadResponse | HTTPValidationError | None: +) -> ErrorResponse | OperationEnvelope | None: if response.status_code == 200: - response_200 = FileUploadResponse.from_dict(response.json()) + response_200 = OperationEnvelope.from_dict(response.json()) return response_200 @@ -63,8 +65,13 @@ def _parse_response( return response_404 + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) + response_422 = ErrorResponse.from_dict(response.json()) return response_422 @@ -86,7 +93,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorResponse | FileUploadResponse | HTTPValidationError]: +) -> Response[ErrorResponse | OperationEnvelope]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -99,29 +106,33 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: FileUploadRequest, -) -> Response[ErrorResponse | FileUploadResponse | HTTPValidationError]: - """Create File Upload + body: ForgetOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Forget (delete a semantic memory) + + Delete a semantic memory by its server-generated id. - Returns a presigned S3 URL for direct upload. After uploading, call `PATCH /files/{file_id}` with - `status=uploaded` to trigger DuckDB staging. Tables are auto-created if missing. Not allowed on - entity graphs or shared repositories. + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. Args: graph_id (str): - body (FileUploadRequest): + idempotency_key (None | str | Unset): + body (ForgetOp): Body for the forget operation (delete a semantic memory by id). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorResponse | FileUploadResponse | HTTPValidationError] + Response[ErrorResponse | OperationEnvelope] """ kwargs = _get_kwargs( graph_id=graph_id, body=body, + idempotency_key=idempotency_key, ) response = client.get_httpx_client().request( @@ -135,30 +146,34 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: FileUploadRequest, -) -> ErrorResponse | FileUploadResponse | HTTPValidationError | None: - """Create File Upload + body: ForgetOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Forget (delete a semantic memory) - Returns a presigned S3 URL for direct upload. After uploading, call `PATCH /files/{file_id}` with - `status=uploaded` to trigger DuckDB staging. Tables are auto-created if missing. Not allowed on - entity graphs or shared repositories. + Delete a semantic memory by its server-generated id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. Args: graph_id (str): - body (FileUploadRequest): + idempotency_key (None | str | Unset): + body (ForgetOp): Body for the forget operation (delete a semantic memory by id). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorResponse | FileUploadResponse | HTTPValidationError + ErrorResponse | OperationEnvelope """ return sync_detailed( graph_id=graph_id, client=client, body=body, + idempotency_key=idempotency_key, ).parsed @@ -166,29 +181,33 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: FileUploadRequest, -) -> Response[ErrorResponse | FileUploadResponse | HTTPValidationError]: - """Create File Upload + body: ForgetOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Forget (delete a semantic memory) + + Delete a semantic memory by its server-generated id. - Returns a presigned S3 URL for direct upload. After uploading, call `PATCH /files/{file_id}` with - `status=uploaded` to trigger DuckDB staging. Tables are auto-created if missing. Not allowed on - entity graphs or shared repositories. + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. Args: graph_id (str): - body (FileUploadRequest): + idempotency_key (None | str | Unset): + body (ForgetOp): Body for the forget operation (delete a semantic memory by id). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorResponse | FileUploadResponse | HTTPValidationError] + Response[ErrorResponse | OperationEnvelope] """ kwargs = _get_kwargs( graph_id=graph_id, body=body, + idempotency_key=idempotency_key, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -200,24 +219,27 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: FileUploadRequest, -) -> ErrorResponse | FileUploadResponse | HTTPValidationError | None: - """Create File Upload + body: ForgetOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Forget (delete a semantic memory) + + Delete a semantic memory by its server-generated id. - Returns a presigned S3 URL for direct upload. After uploading, call `PATCH /files/{file_id}` with - `status=uploaded` to trigger DuckDB staging. Tables are auto-created if missing. Not allowed on - entity graphs or shared repositories. + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. Args: graph_id (str): - body (FileUploadRequest): + idempotency_key (None | str | Unset): + body (ForgetOp): Body for the forget operation (delete a semantic memory by id). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorResponse | FileUploadResponse | HTTPValidationError + ErrorResponse | OperationEnvelope """ return ( @@ -225,5 +247,6 @@ async def asyncio( graph_id=graph_id, client=client, body=body, + idempotency_key=idempotency_key, ) ).parsed diff --git a/robosystems_client/api/graph_operations/op_change_reporting_style.py b/robosystems_client/api/content_operations/op_index_document.py similarity index 61% rename from robosystems_client/api/graph_operations/op_change_reporting_style.py rename to robosystems_client/api/content_operations/op_index_document.py index 712609b..ba602e8 100644 --- a/robosystems_client/api/graph_operations/op_change_reporting_style.py +++ b/robosystems_client/api/content_operations/op_index_document.py @@ -6,8 +6,8 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.change_reporting_style_op import ChangeReportingStyleOp from ...models.error_response import ErrorResponse +from ...models.index_document_op import IndexDocumentOp from ...models.operation_envelope import OperationEnvelope from ...types import UNSET, Response, Unset @@ -15,7 +15,7 @@ def _get_kwargs( graph_id: str, *, - body: ChangeReportingStyleOp, + body: IndexDocumentOp, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -24,7 +24,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/graphs/{graph_id}/operations/change-reporting-style".format( + "url": "/v1/graphs/{graph_id}/operations/index-document".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -106,14 +106,13 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: ChangeReportingStyleOp, + body: IndexDocumentOp, idempotency_key: None | str | Unset = UNSET, ) -> Response[ErrorResponse | OperationEnvelope]: - """Change Reporting Style + """Index Document (write to the corpus) - Switches the graph's Reporting Style. Synchronous: validates the target Style has a complete - composition in the tenant schema, then updates `graphs.reporting_style_id`. Filed Reports are - unaffected; new reports use the new Style. Idempotent on the same id. + Create a document (omit `document_id`) or update one (provide it). Stored in PostgreSQL, synced to + OpenSearch for search. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -121,15 +120,10 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ChangeReportingStyleOp): Body for the change-reporting-style operation. + body (IndexDocumentOp): Body for index-document (corpus content-op). - Switches the graph to a different Reporting Style. The target Style - must be a library- or customer-authored Structure with - ``block_type='reporting_style'`` and a complete composition - (one Network per required statement type — BS / IS / CF / SE). Filed - Reports are unaffected because each ``Report`` already pins its own - ``structure_id`` per FactSet at create-time; new reports use the new - Style. Idempotent on the same target id. + Create a new document when ``document_id`` is absent; update the named + document (partial — only supplied fields) when present. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -156,14 +150,13 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: ChangeReportingStyleOp, + body: IndexDocumentOp, idempotency_key: None | str | Unset = UNSET, ) -> ErrorResponse | OperationEnvelope | None: - """Change Reporting Style + """Index Document (write to the corpus) - Switches the graph's Reporting Style. Synchronous: validates the target Style has a complete - composition in the tenant schema, then updates `graphs.reporting_style_id`. Filed Reports are - unaffected; new reports use the new Style. Idempotent on the same id. + Create a document (omit `document_id`) or update one (provide it). Stored in PostgreSQL, synced to + OpenSearch for search. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -171,15 +164,10 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ChangeReportingStyleOp): Body for the change-reporting-style operation. + body (IndexDocumentOp): Body for index-document (corpus content-op). - Switches the graph to a different Reporting Style. The target Style - must be a library- or customer-authored Structure with - ``block_type='reporting_style'`` and a complete composition - (one Network per required statement type — BS / IS / CF / SE). Filed - Reports are unaffected because each ``Report`` already pins its own - ``structure_id`` per FactSet at create-time; new reports use the new - Style. Idempotent on the same target id. + Create a new document when ``document_id`` is absent; update the named + document (partial — only supplied fields) when present. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -201,14 +189,13 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: ChangeReportingStyleOp, + body: IndexDocumentOp, idempotency_key: None | str | Unset = UNSET, ) -> Response[ErrorResponse | OperationEnvelope]: - """Change Reporting Style + """Index Document (write to the corpus) - Switches the graph's Reporting Style. Synchronous: validates the target Style has a complete - composition in the tenant schema, then updates `graphs.reporting_style_id`. Filed Reports are - unaffected; new reports use the new Style. Idempotent on the same id. + Create a document (omit `document_id`) or update one (provide it). Stored in PostgreSQL, synced to + OpenSearch for search. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -216,15 +203,10 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ChangeReportingStyleOp): Body for the change-reporting-style operation. + body (IndexDocumentOp): Body for index-document (corpus content-op). - Switches the graph to a different Reporting Style. The target Style - must be a library- or customer-authored Structure with - ``block_type='reporting_style'`` and a complete composition - (one Network per required statement type — BS / IS / CF / SE). Filed - Reports are unaffected because each ``Report`` already pins its own - ``structure_id`` per FactSet at create-time; new reports use the new - Style. Idempotent on the same target id. + Create a new document when ``document_id`` is absent; update the named + document (partial — only supplied fields) when present. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -249,14 +231,13 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: ChangeReportingStyleOp, + body: IndexDocumentOp, idempotency_key: None | str | Unset = UNSET, ) -> ErrorResponse | OperationEnvelope | None: - """Change Reporting Style + """Index Document (write to the corpus) - Switches the graph's Reporting Style. Synchronous: validates the target Style has a complete - composition in the tenant schema, then updates `graphs.reporting_style_id`. Filed Reports are - unaffected; new reports use the new Style. Idempotent on the same id. + Create a document (omit `document_id`) or update one (provide it). Stored in PostgreSQL, synced to + OpenSearch for search. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -264,15 +245,10 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ChangeReportingStyleOp): Body for the change-reporting-style operation. - - Switches the graph to a different Reporting Style. The target Style - must be a library- or customer-authored Structure with - ``block_type='reporting_style'`` and a complete composition - (one Network per required statement type — BS / IS / CF / SE). Filed - Reports are unaffected because each ``Report`` already pins its own - ``structure_id`` per FactSet at create-time; new reports use the new - Style. Idempotent on the same target id. + body (IndexDocumentOp): Body for index-document (corpus content-op). + + Create a new document when ``document_id`` is absent; update the named + document (partial — only supplied fields) when present. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/content_operations/op_ingest_file.py b/robosystems_client/api/content_operations/op_ingest_file.py new file mode 100644 index 0000000..05b364e --- /dev/null +++ b/robosystems_client/api/content_operations/op_ingest_file.py @@ -0,0 +1,272 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.ingest_file_op import IngestFileOp +from ...models.operation_envelope import OperationEnvelope +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: IngestFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/ingest-file".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: IngestFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Ingest File (stage an uploaded file) + + Mark an uploaded file ready and stage it into DuckDB. Small files stage directly (sync); large files + stage via a background job (returns a pending envelope with an `operation_id` to monitor). Set + `ingest_to_graph` to auto-materialize into the graph after staging. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (IngestFileOp): Body for ingest-file (raw→staging content flow). + + Marks an uploaded file ready and triggers DuckDB staging. Set + ``ingest_to_graph`` to auto-chain graph materialization after staging. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: IngestFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Ingest File (stage an uploaded file) + + Mark an uploaded file ready and stage it into DuckDB. Small files stage directly (sync); large files + stage via a background job (returns a pending envelope with an `operation_id` to monitor). Set + `ingest_to_graph` to auto-materialize into the graph after staging. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (IngestFileOp): Body for ingest-file (raw→staging content flow). + + Marks an uploaded file ready and triggers DuckDB staging. Set + ``ingest_to_graph`` to auto-chain graph materialization after staging. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: IngestFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Ingest File (stage an uploaded file) + + Mark an uploaded file ready and stage it into DuckDB. Small files stage directly (sync); large files + stage via a background job (returns a pending envelope with an `operation_id` to monitor). Set + `ingest_to_graph` to auto-materialize into the graph after staging. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (IngestFileOp): Body for ingest-file (raw→staging content flow). + + Marks an uploaded file ready and triggers DuckDB staging. Set + ``ingest_to_graph`` to auto-chain graph materialization after staging. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: IngestFileOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Ingest File (stage an uploaded file) + + Mark an uploaded file ready and stage it into DuckDB. Small files stage directly (sync); large files + stage via a background job (returns a pending envelope with an `operation_id` to monitor). Set + `ingest_to_graph` to auto-materialize into the graph after staging. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (IngestFileOp): Body for ingest-file (raw→staging content flow). + + Marks an uploaded file ready and triggers DuckDB staging. Set + ``ingest_to_graph`` to auto-chain graph materialization after staging. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/content_operations/op_remember.py b/robosystems_client/api/content_operations/op_remember.py new file mode 100644 index 0000000..8657838 --- /dev/null +++ b/robosystems_client/api/content_operations/op_remember.py @@ -0,0 +1,256 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.operation_envelope import OperationEnvelope +from ...models.remember_op import RememberOp +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: RememberOp, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/remember".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: RememberOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Remember (write semantic memory) + + Store a semantic memory in the graph's per-graph memory store. The text is embedded locally; recall + it later via `POST /memory/recall`. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (RememberOp): Body for the remember operation (write a semantic memory). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: RememberOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Remember (write semantic memory) + + Store a semantic memory in the graph's per-graph memory store. The text is embedded locally; recall + it later via `POST /memory/recall`. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (RememberOp): Body for the remember operation (write a semantic memory). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: RememberOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Remember (write semantic memory) + + Store a semantic memory in the graph's per-graph memory store. The text is embedded locally; recall + it later via `POST /memory/recall`. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (RememberOp): Body for the remember operation (write a semantic memory). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: RememberOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Remember (write semantic memory) + + Store a semantic memory in the graph's per-graph memory store. The text is embedded locally; recall + it later via `POST /memory/recall`. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (RememberOp): Body for the remember operation (write a semantic memory). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/content_operations/op_update_memory.py b/robosystems_client/api/content_operations/op_update_memory.py new file mode 100644 index 0000000..36d8ce8 --- /dev/null +++ b/robosystems_client/api/content_operations/op_update_memory.py @@ -0,0 +1,272 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.operation_envelope import OperationEnvelope +from ...models.update_memory_op import UpdateMemoryOp +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: UpdateMemoryOp, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/operations/update-memory".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelope | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelope]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateMemoryOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Update Memory (edit a semantic memory) + + Partially update a stored memory by its server-generated id. Only supplied fields change; the memory + is re-embedded when `text` changes. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateMemoryOp): Body for the update-memory operation (partial update of a stored + memory). + + Only supplied fields are changed; the memory is re-embedded when ``text`` + changes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateMemoryOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Update Memory (edit a semantic memory) + + Partially update a stored memory by its server-generated id. Only supplied fields change; the memory + is re-embedded when `text` changes. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateMemoryOp): Body for the update-memory operation (partial update of a stored + memory). + + Only supplied fields are changed; the memory is re-embedded when ``text`` + changes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateMemoryOp, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelope]: + """Update Memory (edit a semantic memory) + + Partially update a stored memory by its server-generated id. Only supplied fields change; the memory + is re-embedded when `text` changes. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateMemoryOp): Body for the update-memory operation (partial update of a stored + memory). + + Only supplied fields are changed; the memory is re-embedded when ``text`` + changes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelope] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateMemoryOp, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelope | None: + """Update Memory (edit a semantic memory) + + Partially update a stored memory by its server-generated id. Only supplied fields change; the memory + is re-embedded when `text` changes. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateMemoryOp): Body for the update-memory operation (partial update of a stored + memory). + + Only supplied fields are changed; the memory is re-embedded when ``text`` + changes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelope + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/documents/update_document.py b/robosystems_client/api/documents/update_document.py deleted file mode 100644 index cc238db..0000000 --- a/robosystems_client/api/documents/update_document.py +++ /dev/null @@ -1,235 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.document_update_request import DocumentUpdateRequest -from ...models.document_upload_response import DocumentUploadResponse -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import Response - - -def _get_kwargs( - graph_id: str, - document_id: str, - *, - body: DocumentUpdateRequest, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "put", - "url": "/v1/graphs/{graph_id}/documents/{document_id}".format( - graph_id=quote(str(graph_id), safe=""), - document_id=quote(str(document_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: - if response.status_code == 200: - response_200 = DocumentUploadResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = ErrorResponse.from_dict(response.json()) - - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = ErrorResponse.from_dict(response.json()) - - return response_429 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - document_id: str, - *, - client: AuthenticatedClient, - body: DocumentUpdateRequest, -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: - """Update Document - - Updates content and/or metadata. Re-syncs to OpenSearch. - - Args: - graph_id (str): - document_id (str): - body (DocumentUpdateRequest): Update a document's metadata and/or content. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - document_id=document_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - document_id: str, - *, - client: AuthenticatedClient, - body: DocumentUpdateRequest, -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: - """Update Document - - Updates content and/or metadata. Re-syncs to OpenSearch. - - Args: - graph_id (str): - document_id (str): - body (DocumentUpdateRequest): Update a document's metadata and/or content. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DocumentUploadResponse | ErrorResponse | HTTPValidationError - """ - - return sync_detailed( - graph_id=graph_id, - document_id=document_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - document_id: str, - *, - client: AuthenticatedClient, - body: DocumentUpdateRequest, -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: - """Update Document - - Updates content and/or metadata. Re-syncs to OpenSearch. - - Args: - graph_id (str): - document_id (str): - body (DocumentUpdateRequest): Update a document's metadata and/or content. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - document_id=document_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - document_id: str, - *, - client: AuthenticatedClient, - body: DocumentUpdateRequest, -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: - """Update Document - - Updates content and/or metadata. Re-syncs to OpenSearch. - - Args: - graph_id (str): - document_id (str): - body (DocumentUpdateRequest): Update a document's metadata and/or content. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DocumentUploadResponse | ErrorResponse | HTTPValidationError - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - document_id=document_id, - client=client, - body=body, - ) - ).parsed diff --git a/robosystems_client/api/extensions_robo_ledger/op_change_reporting_style.py b/robosystems_client/api/extensions_robo_ledger/op_change_reporting_style.py new file mode 100644 index 0000000..f0b3644 --- /dev/null +++ b/robosystems_client/api/extensions_robo_ledger/op_change_reporting_style.py @@ -0,0 +1,292 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.change_reporting_style_request import ChangeReportingStyleRequest +from ...models.error_response import ErrorResponse +from ...models.operation_envelope_change_reporting_style_response import ( + OperationEnvelopeChangeReportingStyleResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: ChangeReportingStyleRequest, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/extensions/roboledger/{graph_id}/operations/change-reporting-style".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | OperationEnvelopeChangeReportingStyleResponse | None: + if response.status_code == 200: + response_200 = OperationEnvelopeChangeReportingStyleResponse.from_dict( + response.json() + ) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | OperationEnvelopeChangeReportingStyleResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: ChangeReportingStyleRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelopeChangeReportingStyleResponse]: + """Change Reporting Style + + Switch the reporting entity's Reporting Style — how its statements are laid out (equity-form, close- + target concept, per-statement Networks). Validates that the target Style has a complete composition + in the tenant schema, then flips `entities.reporting_style_id`. Omit `entity_id` to target the + graph's primary entity. Filed Reports are unaffected (their FactSet rows pin their structures at + create-time); new reports use the new Style. Idempotent on the same id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (ChangeReportingStyleRequest): Switch a reporting entity's Reporting Style. + + The Reporting Style governs how the entity's statements are laid out + (equity-form, close-target concept, per-statement Networks). It's + validated against the tenant schema — the target must be a renderable + Style with a complete composition — before the switch is applied. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelopeChangeReportingStyleResponse] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: ChangeReportingStyleRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelopeChangeReportingStyleResponse | None: + """Change Reporting Style + + Switch the reporting entity's Reporting Style — how its statements are laid out (equity-form, close- + target concept, per-statement Networks). Validates that the target Style has a complete composition + in the tenant schema, then flips `entities.reporting_style_id`. Omit `entity_id` to target the + graph's primary entity. Filed Reports are unaffected (their FactSet rows pin their structures at + create-time); new reports use the new Style. Idempotent on the same id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (ChangeReportingStyleRequest): Switch a reporting entity's Reporting Style. + + The Reporting Style governs how the entity's statements are laid out + (equity-form, close-target concept, per-statement Networks). It's + validated against the tenant schema — the target must be a renderable + Style with a complete composition — before the switch is applied. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelopeChangeReportingStyleResponse + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: ChangeReportingStyleRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelopeChangeReportingStyleResponse]: + """Change Reporting Style + + Switch the reporting entity's Reporting Style — how its statements are laid out (equity-form, close- + target concept, per-statement Networks). Validates that the target Style has a complete composition + in the tenant schema, then flips `entities.reporting_style_id`. Omit `entity_id` to target the + graph's primary entity. Filed Reports are unaffected (their FactSet rows pin their structures at + create-time); new reports use the new Style. Idempotent on the same id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (ChangeReportingStyleRequest): Switch a reporting entity's Reporting Style. + + The Reporting Style governs how the entity's statements are laid out + (equity-form, close-target concept, per-statement Networks). It's + validated against the tenant schema — the target must be a renderable + Style with a complete composition — before the switch is applied. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | OperationEnvelopeChangeReportingStyleResponse] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: ChangeReportingStyleRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelopeChangeReportingStyleResponse | None: + """Change Reporting Style + + Switch the reporting entity's Reporting Style — how its statements are laid out (equity-form, close- + target concept, per-statement Networks). Validates that the target Style has a complete composition + in the tenant schema, then flips `entities.reporting_style_id`. Omit `entity_id` to target the + graph's primary entity. Filed Reports are unaffected (their FactSet rows pin their structures at + create-time); new reports use the new Style. Idempotent on the same id. + + **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours + return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (ChangeReportingStyleRequest): Switch a reporting entity's Reporting Style. + + The Reporting Style governs how the entity's statements are laid out + (equity-form, close-target concept, per-statement Networks). It's + validated against the tenant schema — the target must be a renderable + Style with a complete composition — before the switch is applied. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | OperationEnvelopeChangeReportingStyleResponse + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/files/update_file.py b/robosystems_client/api/files/update_file.py deleted file mode 100644 index 88087d1..0000000 --- a/robosystems_client/api/files/update_file.py +++ /dev/null @@ -1,243 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.file_status_update import FileStatusUpdate -from ...models.http_validation_error import HTTPValidationError -from ...models.update_file_response_updatefile import UpdateFileResponseUpdatefile -from ...types import Response - - -def _get_kwargs( - graph_id: str, - file_id: str, - *, - body: FileStatusUpdate, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "patch", - "url": "/v1/graphs/{graph_id}/files/{file_id}".format( - graph_id=quote(str(graph_id), safe=""), - file_id=quote(str(file_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile | None: - if response.status_code == 200: - response_200 = UpdateFileResponseUpdatefile.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = ErrorResponse.from_dict(response.json()) - - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = ErrorResponse.from_dict(response.json()) - - return response_429 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileStatusUpdate, -) -> Response[ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile]: - """Update File Status - - Setting `status=uploaded` validates the file in S3, calculates row count, and triggers DuckDB - staging. Small files use direct staging; large files use a background Dagster job with an - `operation_id` for SSE monitoring. Set `ingest_to_graph=true` to auto-chain graph materialization. - - Args: - graph_id (str): - file_id (str): File ID - body (FileStatusUpdate): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileStatusUpdate, -) -> ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile | None: - """Update File Status - - Setting `status=uploaded` validates the file in S3, calculates row count, and triggers DuckDB - staging. Small files use direct staging; large files use a background Dagster job with an - `operation_id` for SSE monitoring. Set `ingest_to_graph=true` to auto-chain graph materialization. - - Args: - graph_id (str): - file_id (str): File ID - body (FileStatusUpdate): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile - """ - - return sync_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileStatusUpdate, -) -> Response[ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile]: - """Update File Status - - Setting `status=uploaded` validates the file in S3, calculates row count, and triggers DuckDB - staging. Small files use direct staging; large files use a background Dagster job with an - `operation_id` for SSE monitoring. Set `ingest_to_graph=true` to auto-chain graph materialization. - - Args: - graph_id (str): - file_id (str): File ID - body (FileStatusUpdate): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileStatusUpdate, -) -> ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile | None: - """Update File Status - - Setting `status=uploaded` validates the file in S3, calculates row count, and triggers DuckDB - staging. Small files use direct staging; large files use a background Dagster job with an - `operation_id` for SSE monitoring. Set `ingest_to_graph=true` to auto-chain graph materialization. - - Args: - graph_id (str): - file_id (str): File ID - body (FileStatusUpdate): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | UpdateFileResponseUpdatefile - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - body=body, - ) - ).parsed diff --git a/robosystems_client/api/memory/__init__.py b/robosystems_client/api/memory/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/robosystems_client/api/memory/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/robosystems_client/api/documents/delete_document.py b/robosystems_client/api/memory/get_memory.py similarity index 73% rename from robosystems_client/api/documents/delete_document.py rename to robosystems_client/api/memory/get_memory.py index de9ea99..dc6e5a9 100644 --- a/robosystems_client/api/documents/delete_document.py +++ b/robosystems_client/api/memory/get_memory.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, cast +from typing import Any from urllib.parse import quote import httpx @@ -8,19 +8,20 @@ from ...client import AuthenticatedClient, Client from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError +from ...models.memory_record import MemoryRecord from ...types import Response def _get_kwargs( graph_id: str, - document_id: str, + memory_id: str, ) -> dict[str, Any]: _kwargs: dict[str, Any] = { - "method": "delete", - "url": "/v1/graphs/{graph_id}/documents/{document_id}".format( + "method": "get", + "url": "/v1/graphs/{graph_id}/memory/{memory_id}".format( graph_id=quote(str(graph_id), safe=""), - document_id=quote(str(document_id), safe=""), + memory_id=quote(str(memory_id), safe=""), ), } @@ -29,10 +30,11 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | ErrorResponse | HTTPValidationError | None: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 +) -> ErrorResponse | HTTPValidationError | MemoryRecord | None: + if response.status_code == 200: + response_200 = MemoryRecord.from_dict(response.json()) + + return response_200 if response.status_code == 400: response_400 = ErrorResponse.from_dict(response.json()) @@ -77,7 +79,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | ErrorResponse | HTTPValidationError]: +) -> Response[ErrorResponse | HTTPValidationError | MemoryRecord]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -88,27 +90,27 @@ def _build_response( def sync_detailed( graph_id: str, - document_id: str, + memory_id: str, *, client: AuthenticatedClient, -) -> Response[Any | ErrorResponse | HTTPValidationError]: - """Delete Document +) -> Response[ErrorResponse | HTTPValidationError | MemoryRecord]: + """Get Memory Args: graph_id (str): - document_id (str): + memory_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | ErrorResponse | HTTPValidationError] + Response[ErrorResponse | HTTPValidationError | MemoryRecord] """ kwargs = _get_kwargs( graph_id=graph_id, - document_id=document_id, + memory_id=memory_id, ) response = client.get_httpx_client().request( @@ -120,54 +122,54 @@ def sync_detailed( def sync( graph_id: str, - document_id: str, + memory_id: str, *, client: AuthenticatedClient, -) -> Any | ErrorResponse | HTTPValidationError | None: - """Delete Document +) -> ErrorResponse | HTTPValidationError | MemoryRecord | None: + """Get Memory Args: graph_id (str): - document_id (str): + memory_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | ErrorResponse | HTTPValidationError + ErrorResponse | HTTPValidationError | MemoryRecord """ return sync_detailed( graph_id=graph_id, - document_id=document_id, + memory_id=memory_id, client=client, ).parsed async def asyncio_detailed( graph_id: str, - document_id: str, + memory_id: str, *, client: AuthenticatedClient, -) -> Response[Any | ErrorResponse | HTTPValidationError]: - """Delete Document +) -> Response[ErrorResponse | HTTPValidationError | MemoryRecord]: + """Get Memory Args: graph_id (str): - document_id (str): + memory_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | ErrorResponse | HTTPValidationError] + Response[ErrorResponse | HTTPValidationError | MemoryRecord] """ kwargs = _get_kwargs( graph_id=graph_id, - document_id=document_id, + memory_id=memory_id, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -177,28 +179,28 @@ async def asyncio_detailed( async def asyncio( graph_id: str, - document_id: str, + memory_id: str, *, client: AuthenticatedClient, -) -> Any | ErrorResponse | HTTPValidationError | None: - """Delete Document +) -> ErrorResponse | HTTPValidationError | MemoryRecord | None: + """Get Memory Args: graph_id (str): - document_id (str): + memory_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | ErrorResponse | HTTPValidationError + ErrorResponse | HTTPValidationError | MemoryRecord """ return ( await asyncio_detailed( graph_id=graph_id, - document_id=document_id, + memory_id=memory_id, client=client, ) ).parsed diff --git a/robosystems_client/api/files/delete_file.py b/robosystems_client/api/memory/list_memories.py similarity index 55% rename from robosystems_client/api/files/delete_file.py rename to robosystems_client/api/memory/list_memories.py index 2fb6b95..2c85856 100644 --- a/robosystems_client/api/files/delete_file.py +++ b/robosystems_client/api/memory/list_memories.py @@ -6,30 +6,47 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.delete_file_response import DeleteFileResponse from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError +from ...models.memory_list_response import MemoryListResponse from ...types import UNSET, Response, Unset def _get_kwargs( graph_id: str, - file_id: str, *, - cascade: bool | Unset = False, + memory_type: None | str | Unset = UNSET, + source: None | str | Unset = UNSET, + limit: int | Unset = 100, + offset: int | Unset = 0, ) -> dict[str, Any]: params: dict[str, Any] = {} - params["cascade"] = cascade + json_memory_type: None | str | Unset + if isinstance(memory_type, Unset): + json_memory_type = UNSET + else: + json_memory_type = memory_type + params["memory_type"] = json_memory_type + + json_source: None | str | Unset + if isinstance(source, Unset): + json_source = UNSET + else: + json_source = source + params["source"] = json_source + + params["limit"] = limit + + params["offset"] = offset params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { - "method": "delete", - "url": "/v1/graphs/{graph_id}/files/{file_id}".format( + "method": "get", + "url": "/v1/graphs/{graph_id}/memory".format( graph_id=quote(str(graph_id), safe=""), - file_id=quote(str(file_id), safe=""), ), "params": params, } @@ -39,9 +56,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> DeleteFileResponse | ErrorResponse | HTTPValidationError | None: +) -> ErrorResponse | HTTPValidationError | MemoryListResponse | None: if response.status_code == 200: - response_200 = DeleteFileResponse.from_dict(response.json()) + response_200 = MemoryListResponse.from_dict(response.json()) return response_200 @@ -88,7 +105,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[DeleteFileResponse | ErrorResponse | HTTPValidationError]: +) -> Response[ErrorResponse | HTTPValidationError | MemoryListResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -99,34 +116,36 @@ def _build_response( def sync_detailed( graph_id: str, - file_id: str, *, client: AuthenticatedClient, - cascade: bool | Unset = False, -) -> Response[DeleteFileResponse | ErrorResponse | HTTPValidationError]: - """Delete File - - Removes from S3 and database. `cascade=true` also deletes data from DuckDB tables and marks the - graph stale (rebuild recommended). Not allowed on shared repositories. + memory_type: None | str | Unset = UNSET, + source: None | str | Unset = UNSET, + limit: int | Unset = 100, + offset: int | Unset = 0, +) -> Response[ErrorResponse | HTTPValidationError | MemoryListResponse]: + """List Memories Args: graph_id (str): - file_id (str): File ID - cascade (bool | Unset): If true, delete from all layers including DuckDB and mark graph - stale Default: False. + memory_type (None | str | Unset): Filter by memory type + source (None | str | Unset): Filter by source + limit (int | Unset): Default: 100. + offset (int | Unset): Default: 0. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[DeleteFileResponse | ErrorResponse | HTTPValidationError] + Response[ErrorResponse | HTTPValidationError | MemoryListResponse] """ kwargs = _get_kwargs( graph_id=graph_id, - file_id=file_id, - cascade=cascade, + memory_type=memory_type, + source=source, + limit=limit, + offset=offset, ) response = client.get_httpx_client().request( @@ -138,68 +157,72 @@ def sync_detailed( def sync( graph_id: str, - file_id: str, *, client: AuthenticatedClient, - cascade: bool | Unset = False, -) -> DeleteFileResponse | ErrorResponse | HTTPValidationError | None: - """Delete File - - Removes from S3 and database. `cascade=true` also deletes data from DuckDB tables and marks the - graph stale (rebuild recommended). Not allowed on shared repositories. + memory_type: None | str | Unset = UNSET, + source: None | str | Unset = UNSET, + limit: int | Unset = 100, + offset: int | Unset = 0, +) -> ErrorResponse | HTTPValidationError | MemoryListResponse | None: + """List Memories Args: graph_id (str): - file_id (str): File ID - cascade (bool | Unset): If true, delete from all layers including DuckDB and mark graph - stale Default: False. + memory_type (None | str | Unset): Filter by memory type + source (None | str | Unset): Filter by source + limit (int | Unset): Default: 100. + offset (int | Unset): Default: 0. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - DeleteFileResponse | ErrorResponse | HTTPValidationError + ErrorResponse | HTTPValidationError | MemoryListResponse """ return sync_detailed( graph_id=graph_id, - file_id=file_id, client=client, - cascade=cascade, + memory_type=memory_type, + source=source, + limit=limit, + offset=offset, ).parsed async def asyncio_detailed( graph_id: str, - file_id: str, *, client: AuthenticatedClient, - cascade: bool | Unset = False, -) -> Response[DeleteFileResponse | ErrorResponse | HTTPValidationError]: - """Delete File - - Removes from S3 and database. `cascade=true` also deletes data from DuckDB tables and marks the - graph stale (rebuild recommended). Not allowed on shared repositories. + memory_type: None | str | Unset = UNSET, + source: None | str | Unset = UNSET, + limit: int | Unset = 100, + offset: int | Unset = 0, +) -> Response[ErrorResponse | HTTPValidationError | MemoryListResponse]: + """List Memories Args: graph_id (str): - file_id (str): File ID - cascade (bool | Unset): If true, delete from all layers including DuckDB and mark graph - stale Default: False. + memory_type (None | str | Unset): Filter by memory type + source (None | str | Unset): Filter by source + limit (int | Unset): Default: 100. + offset (int | Unset): Default: 0. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[DeleteFileResponse | ErrorResponse | HTTPValidationError] + Response[ErrorResponse | HTTPValidationError | MemoryListResponse] """ kwargs = _get_kwargs( graph_id=graph_id, - file_id=file_id, - cascade=cascade, + memory_type=memory_type, + source=source, + limit=limit, + offset=offset, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -209,35 +232,37 @@ async def asyncio_detailed( async def asyncio( graph_id: str, - file_id: str, *, client: AuthenticatedClient, - cascade: bool | Unset = False, -) -> DeleteFileResponse | ErrorResponse | HTTPValidationError | None: - """Delete File - - Removes from S3 and database. `cascade=true` also deletes data from DuckDB tables and marks the - graph stale (rebuild recommended). Not allowed on shared repositories. + memory_type: None | str | Unset = UNSET, + source: None | str | Unset = UNSET, + limit: int | Unset = 100, + offset: int | Unset = 0, +) -> ErrorResponse | HTTPValidationError | MemoryListResponse | None: + """List Memories Args: graph_id (str): - file_id (str): File ID - cascade (bool | Unset): If true, delete from all layers including DuckDB and mark graph - stale Default: False. + memory_type (None | str | Unset): Filter by memory type + source (None | str | Unset): Filter by source + limit (int | Unset): Default: 100. + offset (int | Unset): Default: 0. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - DeleteFileResponse | ErrorResponse | HTTPValidationError + ErrorResponse | HTTPValidationError | MemoryListResponse """ return ( await asyncio_detailed( graph_id=graph_id, - file_id=file_id, client=client, - cascade=cascade, + memory_type=memory_type, + source=source, + limit=limit, + offset=offset, ) ).parsed diff --git a/robosystems_client/api/documents/upload_document.py b/robosystems_client/api/memory/recall_memory.py similarity index 64% rename from robosystems_client/api/documents/upload_document.py rename to robosystems_client/api/memory/recall_memory.py index 6fc5782..c5105e9 100644 --- a/robosystems_client/api/documents/upload_document.py +++ b/robosystems_client/api/memory/recall_memory.py @@ -1,28 +1,28 @@ from http import HTTPStatus -from typing import Any +from typing import Any, cast from urllib.parse import quote import httpx from ... import errors from ...client import AuthenticatedClient, Client -from ...models.document_upload_request import DocumentUploadRequest -from ...models.document_upload_response import DocumentUploadResponse from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError +from ...models.memory_recall_request import MemoryRecallRequest +from ...models.search_response import SearchResponse from ...types import Response def _get_kwargs( graph_id: str, *, - body: DocumentUploadRequest, + body: MemoryRecallRequest, ) -> dict[str, Any]: headers: dict[str, Any] = {} _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/graphs/{graph_id}/documents".format( + "url": "/v1/graphs/{graph_id}/memory/recall".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -37,9 +37,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: +) -> Any | ErrorResponse | HTTPValidationError | SearchResponse | None: if response.status_code == 200: - response_200 = DocumentUploadResponse.from_dict(response.json()) + response_200 = SearchResponse.from_dict(response.json()) return response_200 @@ -78,6 +78,10 @@ def _parse_response( return response_500 + if response.status_code == 503: + response_503 = cast(Any, None) + return response_503 + if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: @@ -86,7 +90,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: +) -> Response[Any | ErrorResponse | HTTPValidationError | SearchResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -99,22 +103,23 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: DocumentUploadRequest, -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: - """Upload Document + body: MemoryRecallRequest, +) -> Response[Any | ErrorResponse | HTTPValidationError | SearchResponse]: + """Recall Semantic Memory - Stored in PostgreSQL, synced to OpenSearch for search. Not allowed on shared repositories. + Ranked semantic recall over the graph's per-graph memory store. Returns scored hits in the same + shape as document search. Args: graph_id (str): - body (DocumentUploadRequest): Upload a markdown document for text indexing. + body (MemoryRecallRequest): Body for recall (ranked semantic search over memory). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError] + Response[Any | ErrorResponse | HTTPValidationError | SearchResponse] """ kwargs = _get_kwargs( @@ -133,22 +138,23 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: DocumentUploadRequest, -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: - """Upload Document + body: MemoryRecallRequest, +) -> Any | ErrorResponse | HTTPValidationError | SearchResponse | None: + """Recall Semantic Memory - Stored in PostgreSQL, synced to OpenSearch for search. Not allowed on shared repositories. + Ranked semantic recall over the graph's per-graph memory store. Returns scored hits in the same + shape as document search. Args: graph_id (str): - body (DocumentUploadRequest): Upload a markdown document for text indexing. + body (MemoryRecallRequest): Body for recall (ranked semantic search over memory). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - DocumentUploadResponse | ErrorResponse | HTTPValidationError + Any | ErrorResponse | HTTPValidationError | SearchResponse """ return sync_detailed( @@ -162,22 +168,23 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: DocumentUploadRequest, -) -> Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError]: - """Upload Document + body: MemoryRecallRequest, +) -> Response[Any | ErrorResponse | HTTPValidationError | SearchResponse]: + """Recall Semantic Memory - Stored in PostgreSQL, synced to OpenSearch for search. Not allowed on shared repositories. + Ranked semantic recall over the graph's per-graph memory store. Returns scored hits in the same + shape as document search. Args: graph_id (str): - body (DocumentUploadRequest): Upload a markdown document for text indexing. + body (MemoryRecallRequest): Body for recall (ranked semantic search over memory). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[DocumentUploadResponse | ErrorResponse | HTTPValidationError] + Response[Any | ErrorResponse | HTTPValidationError | SearchResponse] """ kwargs = _get_kwargs( @@ -194,22 +201,23 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: DocumentUploadRequest, -) -> DocumentUploadResponse | ErrorResponse | HTTPValidationError | None: - """Upload Document + body: MemoryRecallRequest, +) -> Any | ErrorResponse | HTTPValidationError | SearchResponse | None: + """Recall Semantic Memory - Stored in PostgreSQL, synced to OpenSearch for search. Not allowed on shared repositories. + Ranked semantic recall over the graph's per-graph memory store. Returns scored hits in the same + shape as document search. Args: graph_id (str): - body (DocumentUploadRequest): Upload a markdown document for text indexing. + body (MemoryRecallRequest): Body for recall (ranked semantic search over memory). Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - DocumentUploadResponse | ErrorResponse | HTTPValidationError + Any | ErrorResponse | HTTPValidationError | SearchResponse """ return ( diff --git a/robosystems_client/api/query/execute_cypher_query.py b/robosystems_client/api/query/execute_cypher.py similarity index 75% rename from robosystems_client/api/query/execute_cypher_query.py rename to robosystems_client/api/query/execute_cypher.py index f535f42..5b1c89a 100644 --- a/robosystems_client/api/query/execute_cypher_query.py +++ b/robosystems_client/api/query/execute_cypher.py @@ -6,7 +6,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.cypher_query_request import CypherQueryRequest +from ...models.cypher_statement_request import CypherStatementRequest from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError from ...models.response_mode import ResponseMode @@ -16,7 +16,7 @@ def _get_kwargs( graph_id: str, *, - body: CypherQueryRequest, + body: CypherStatementRequest, mode: None | ResponseMode | Unset = UNSET, chunk_size: int | None | Unset = UNSET, test_mode: bool | Unset = False, @@ -47,7 +47,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/graphs/{graph_id}/query".format( + "url": "/v1/graphs/{graph_id}/query/cypher".format( graph_id=quote(str(graph_id), safe=""), ), "params": params, @@ -142,24 +142,25 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CypherQueryRequest, + body: CypherStatementRequest, mode: None | ResponseMode | Unset = UNSET, chunk_size: int | None | Unset = UNSET, test_mode: bool | Unset = False, ) -> Response[Any | ErrorResponse | HTTPValidationError]: - r"""Execute Cypher Query + r"""Execute Cypher Statement - Main graphs are **read-only** — use the staging pipeline to ingest data. Subgraphs support full - writes. Always use parameterized queries (`parameters: {\"key\": \"val\"}`) to prevent injection. - Response modes: `auto` (default), `sync`, `async`, `stream`. Under load, queries are queued and emit - an `operation_id` for SSE monitoring at `/v1/operations/{id}/stream`. + Cypher over the graph (LadybugDB). Main graphs are **read-only** — use the staging pipeline to + ingest data. Subgraphs support full writes. Always use parameterized queries (`parameters: {\"key\": + \"val\"}`) to prevent injection. Response modes: `auto` (default), `sync`, `async`, `stream`. Under + load, queries are queued and emit an `operation_id` for SSE monitoring at + `/v1/operations/{id}/stream`. Args: graph_id (str): mode (None | ResponseMode | Unset): Response mode override chunk_size (int | None | Unset): Rows per chunk for streaming test_mode (bool | Unset): Enable test mode for better debugging Default: False. - body (CypherQueryRequest): Request model for Cypher query execution. + body (CypherStatementRequest): Request model for Cypher query execution. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -188,24 +189,25 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: CypherQueryRequest, + body: CypherStatementRequest, mode: None | ResponseMode | Unset = UNSET, chunk_size: int | None | Unset = UNSET, test_mode: bool | Unset = False, ) -> Any | ErrorResponse | HTTPValidationError | None: - r"""Execute Cypher Query + r"""Execute Cypher Statement - Main graphs are **read-only** — use the staging pipeline to ingest data. Subgraphs support full - writes. Always use parameterized queries (`parameters: {\"key\": \"val\"}`) to prevent injection. - Response modes: `auto` (default), `sync`, `async`, `stream`. Under load, queries are queued and emit - an `operation_id` for SSE monitoring at `/v1/operations/{id}/stream`. + Cypher over the graph (LadybugDB). Main graphs are **read-only** — use the staging pipeline to + ingest data. Subgraphs support full writes. Always use parameterized queries (`parameters: {\"key\": + \"val\"}`) to prevent injection. Response modes: `auto` (default), `sync`, `async`, `stream`. Under + load, queries are queued and emit an `operation_id` for SSE monitoring at + `/v1/operations/{id}/stream`. Args: graph_id (str): mode (None | ResponseMode | Unset): Response mode override chunk_size (int | None | Unset): Rows per chunk for streaming test_mode (bool | Unset): Enable test mode for better debugging Default: False. - body (CypherQueryRequest): Request model for Cypher query execution. + body (CypherStatementRequest): Request model for Cypher query execution. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -229,24 +231,25 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CypherQueryRequest, + body: CypherStatementRequest, mode: None | ResponseMode | Unset = UNSET, chunk_size: int | None | Unset = UNSET, test_mode: bool | Unset = False, ) -> Response[Any | ErrorResponse | HTTPValidationError]: - r"""Execute Cypher Query + r"""Execute Cypher Statement - Main graphs are **read-only** — use the staging pipeline to ingest data. Subgraphs support full - writes. Always use parameterized queries (`parameters: {\"key\": \"val\"}`) to prevent injection. - Response modes: `auto` (default), `sync`, `async`, `stream`. Under load, queries are queued and emit - an `operation_id` for SSE monitoring at `/v1/operations/{id}/stream`. + Cypher over the graph (LadybugDB). Main graphs are **read-only** — use the staging pipeline to + ingest data. Subgraphs support full writes. Always use parameterized queries (`parameters: {\"key\": + \"val\"}`) to prevent injection. Response modes: `auto` (default), `sync`, `async`, `stream`. Under + load, queries are queued and emit an `operation_id` for SSE monitoring at + `/v1/operations/{id}/stream`. Args: graph_id (str): mode (None | ResponseMode | Unset): Response mode override chunk_size (int | None | Unset): Rows per chunk for streaming test_mode (bool | Unset): Enable test mode for better debugging Default: False. - body (CypherQueryRequest): Request model for Cypher query execution. + body (CypherStatementRequest): Request model for Cypher query execution. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -273,24 +276,25 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: CypherQueryRequest, + body: CypherStatementRequest, mode: None | ResponseMode | Unset = UNSET, chunk_size: int | None | Unset = UNSET, test_mode: bool | Unset = False, ) -> Any | ErrorResponse | HTTPValidationError | None: - r"""Execute Cypher Query + r"""Execute Cypher Statement - Main graphs are **read-only** — use the staging pipeline to ingest data. Subgraphs support full - writes. Always use parameterized queries (`parameters: {\"key\": \"val\"}`) to prevent injection. - Response modes: `auto` (default), `sync`, `async`, `stream`. Under load, queries are queued and emit - an `operation_id` for SSE monitoring at `/v1/operations/{id}/stream`. + Cypher over the graph (LadybugDB). Main graphs are **read-only** — use the staging pipeline to + ingest data. Subgraphs support full writes. Always use parameterized queries (`parameters: {\"key\": + \"val\"}`) to prevent injection. Response modes: `auto` (default), `sync`, `async`, `stream`. Under + load, queries are queued and emit an `operation_id` for SSE monitoring at + `/v1/operations/{id}/stream`. Args: graph_id (str): mode (None | ResponseMode | Unset): Response mode override chunk_size (int | None | Unset): Rows per chunk for streaming test_mode (bool | Unset): Enable test mode for better debugging Default: False. - body (CypherQueryRequest): Request model for Cypher query execution. + body (CypherStatementRequest): Request model for Cypher query execution. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/tables/query_tables.py b/robosystems_client/api/query/execute_sql.py similarity index 60% rename from robosystems_client/api/tables/query_tables.py rename to robosystems_client/api/query/execute_sql.py index ec63503..72b7486 100644 --- a/robosystems_client/api/tables/query_tables.py +++ b/robosystems_client/api/query/execute_sql.py @@ -8,21 +8,21 @@ from ...client import AuthenticatedClient, Client from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError -from ...models.table_query_request import TableQueryRequest -from ...models.table_query_response import TableQueryResponse +from ...models.sql_statement_request import SqlStatementRequest +from ...models.sql_statement_response import SqlStatementResponse from ...types import Response def _get_kwargs( graph_id: str, *, - body: TableQueryRequest, + body: SqlStatementRequest, ) -> dict[str, Any]: headers: dict[str, Any] = {} _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/graphs/{graph_id}/tables/query".format( + "url": "/v1/graphs/{graph_id}/query/sql".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -37,9 +37,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | ErrorResponse | HTTPValidationError | TableQueryResponse | None: +) -> Any | ErrorResponse | HTTPValidationError | SqlStatementResponse | None: if response.status_code == 200: - response_200 = TableQueryResponse.from_dict(response.json()) + response_200 = SqlStatementResponse.from_dict(response.json()) return response_200 @@ -90,7 +90,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | ErrorResponse | HTTPValidationError | TableQueryResponse]: +) -> Response[Any | ErrorResponse | HTTPValidationError | SqlStatementResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -103,24 +103,25 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: TableQueryRequest, -) -> Response[Any | ErrorResponse | HTTPValidationError | TableQueryResponse]: - """Query Staging Tables with SQL + body: SqlStatementRequest, +) -> Response[Any | ErrorResponse | HTTPValidationError | SqlStatementResponse]: + """Execute SQL Statement - Execute SQL against DuckDB staging tables for pre-ingestion validation. Use `?` placeholders with - the `parameters` array to prevent injection. Read-only (SELECT only), 30s timeout, 10K row limit. - Not allowed on shared repositories. + SQL over the graph's columnar tables (DuckDB) — a relational lens on the same graph-centric data, + often ahead of the materialized graph. Use `?` placeholders with the `parameters` array to prevent + injection. Read-only (SELECT only), 30s timeout, 10K row limit. Not available on shared + repositories. Args: graph_id (str): - body (TableQueryRequest): + body (SqlStatementRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | ErrorResponse | HTTPValidationError | TableQueryResponse] + Response[Any | ErrorResponse | HTTPValidationError | SqlStatementResponse] """ kwargs = _get_kwargs( @@ -139,24 +140,25 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: TableQueryRequest, -) -> Any | ErrorResponse | HTTPValidationError | TableQueryResponse | None: - """Query Staging Tables with SQL + body: SqlStatementRequest, +) -> Any | ErrorResponse | HTTPValidationError | SqlStatementResponse | None: + """Execute SQL Statement - Execute SQL against DuckDB staging tables for pre-ingestion validation. Use `?` placeholders with - the `parameters` array to prevent injection. Read-only (SELECT only), 30s timeout, 10K row limit. - Not allowed on shared repositories. + SQL over the graph's columnar tables (DuckDB) — a relational lens on the same graph-centric data, + often ahead of the materialized graph. Use `?` placeholders with the `parameters` array to prevent + injection. Read-only (SELECT only), 30s timeout, 10K row limit. Not available on shared + repositories. Args: graph_id (str): - body (TableQueryRequest): + body (SqlStatementRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | ErrorResponse | HTTPValidationError | TableQueryResponse + Any | ErrorResponse | HTTPValidationError | SqlStatementResponse """ return sync_detailed( @@ -170,24 +172,25 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: TableQueryRequest, -) -> Response[Any | ErrorResponse | HTTPValidationError | TableQueryResponse]: - """Query Staging Tables with SQL + body: SqlStatementRequest, +) -> Response[Any | ErrorResponse | HTTPValidationError | SqlStatementResponse]: + """Execute SQL Statement - Execute SQL against DuckDB staging tables for pre-ingestion validation. Use `?` placeholders with - the `parameters` array to prevent injection. Read-only (SELECT only), 30s timeout, 10K row limit. - Not allowed on shared repositories. + SQL over the graph's columnar tables (DuckDB) — a relational lens on the same graph-centric data, + often ahead of the materialized graph. Use `?` placeholders with the `parameters` array to prevent + injection. Read-only (SELECT only), 30s timeout, 10K row limit. Not available on shared + repositories. Args: graph_id (str): - body (TableQueryRequest): + body (SqlStatementRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | ErrorResponse | HTTPValidationError | TableQueryResponse] + Response[Any | ErrorResponse | HTTPValidationError | SqlStatementResponse] """ kwargs = _get_kwargs( @@ -204,24 +207,25 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: TableQueryRequest, -) -> Any | ErrorResponse | HTTPValidationError | TableQueryResponse | None: - """Query Staging Tables with SQL + body: SqlStatementRequest, +) -> Any | ErrorResponse | HTTPValidationError | SqlStatementResponse | None: + """Execute SQL Statement - Execute SQL against DuckDB staging tables for pre-ingestion validation. Use `?` placeholders with - the `parameters` array to prevent injection. Read-only (SELECT only), 30s timeout, 10K row limit. - Not allowed on shared repositories. + SQL over the graph's columnar tables (DuckDB) — a relational lens on the same graph-centric data, + often ahead of the materialized graph. Use `?` placeholders with the `parameters` array to prevent + injection. Read-only (SELECT only), 30s timeout, 10K row limit. Not available on shared + repositories. Args: graph_id (str): - body (TableQueryRequest): + body (SqlStatementRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | ErrorResponse | HTTPValidationError | TableQueryResponse + Any | ErrorResponse | HTTPValidationError | SqlStatementResponse """ return ( diff --git a/robosystems_client/clients/auth_integration.py b/robosystems_client/clients/auth_integration.py index e0a9acb..144ec5d 100644 --- a/robosystems_client/clients/auth_integration.py +++ b/robosystems_client/clients/auth_integration.py @@ -55,10 +55,10 @@ def execute_cypher_query( self, graph_id: str, query: str, parameters: Dict[str, Any] = None ): """Execute Cypher query using authenticated SDK client""" - from ..api.query.execute_cypher_query import sync_detailed - from ..models.cypher_query_request import CypherQueryRequest + from ..api.query.execute_cypher import sync_detailed + from ..models.cypher_statement_request import CypherStatementRequest - request = CypherQueryRequest(query=query, parameters=parameters or {}) + request = CypherStatementRequest(query=query, parameters=parameters or {}) # Execute the query response = sync_detailed( diff --git a/robosystems_client/clients/document_client.py b/robosystems_client/clients/document_client.py index 7bd9093..9371aa3 100644 --- a/robosystems_client/clients/document_client.py +++ b/robosystems_client/clients/document_client.py @@ -9,20 +9,23 @@ from pathlib import Path from typing import Any, Dict, List, Optional -from ..api.documents.delete_document import sync_detailed as delete_document +from ..api.content_operations.op_delete_document import ( + sync_detailed as delete_document, +) +from ..api.content_operations.op_index_document import ( + sync_detailed as index_document, +) from ..api.documents.get_document import sync_detailed as get_document from ..api.documents.list_documents import sync_detailed as list_documents -from ..api.documents.update_document import sync_detailed as update_document -from ..api.documents.upload_document import sync_detailed as upload_document from ..api.search.get_document_section import sync_detailed as get_document_section from ..api.search.search_documents import sync_detailed as search_documents from ..client import AuthenticatedClient +from ..models.delete_document_op import DeleteDocumentOp from ..models.document_detail_response import DocumentDetailResponse from ..models.document_list_response import DocumentListResponse from ..models.document_section import DocumentSection -from ..models.document_update_request import DocumentUpdateRequest -from ..models.document_upload_request import DocumentUploadRequest -from ..models.document_upload_response import DocumentUploadResponse +from ..models.index_document_op import IndexDocumentOp +from ..models.operation_envelope import OperationEnvelope from ..models.search_request import SearchRequest from ..models.search_response import SearchResponse from ..types import UNSET @@ -57,7 +60,7 @@ def upload( tags: Optional[List[str]] = None, folder: Optional[str] = None, external_id: Optional[str] = None, - ) -> DocumentUploadResponse: + ) -> OperationEnvelope: """Upload a markdown document for text indexing. The document is sectioned on headings, embedded, and indexed @@ -72,9 +75,9 @@ def upload( external_id: Optional external ID for upsert behavior. Returns: - DocumentUploadResponse with section IDs and counts. + OperationEnvelope; `result` carries the document ID and section counts. """ - body = DocumentUploadRequest( + body = IndexDocumentOp( title=title, content=content, tags=tags if tags is not None else UNSET, @@ -83,8 +86,8 @@ def upload( ) client = self._get_client() - response = upload_document(graph_id=graph_id, client=client, body=body) - if response.status_code != HTTPStatus.OK: + response = index_document(graph_id=graph_id, client=client, body=body) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.ACCEPTED): raise Exception( f"Document upload failed ({response.status_code}): {response.content.decode()}" ) @@ -124,11 +127,11 @@ def update( content: Optional[str] = None, tags: Optional[List[str]] = UNSET, folder: Optional[str] = UNSET, - ) -> DocumentUploadResponse: + ) -> OperationEnvelope: """Update a document's content and/or metadata. - Only provided fields are updated. Content is re-sectioned, - re-embedded, and re-indexed in OpenSearch. + Re-indexing an existing ``document_id`` upserts it: content is + re-sectioned, re-embedded, and re-indexed in OpenSearch. Args: graph_id: Target graph ID. @@ -139,9 +142,10 @@ def update( folder: Updated folder (None to clear, UNSET to leave unchanged). Returns: - DocumentUploadResponse with updated section counts. + OperationEnvelope; `result` carries the updated section counts. """ - body = DocumentUpdateRequest( + body = IndexDocumentOp( + document_id=document_id, title=title if title is not None else UNSET, content=content if content is not None else UNSET, tags=tags, @@ -149,10 +153,8 @@ def update( ) client = self._get_client() - response = update_document( - graph_id=graph_id, document_id=document_id, client=client, body=body - ) - if response.status_code != HTTPStatus.OK: + response = index_document(graph_id=graph_id, client=client, body=body) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.ACCEPTED): raise Exception( f"Update document failed ({response.status_code}): {response.content.decode()}" ) @@ -166,7 +168,7 @@ def upload_file( tags: Optional[List[str]] = None, folder: Optional[str] = None, external_id: Optional[str] = None, - ) -> DocumentUploadResponse: + ) -> OperationEnvelope: """Upload a markdown file by path. Reads the file, optionally extracts title from filename, @@ -201,7 +203,7 @@ def upload_directory( directory: str | Path, pattern: str = "*.md", folder: Optional[str] = None, - ) -> List[DocumentUploadResponse]: + ) -> List[OperationEnvelope]: """Upload all markdown files from a directory. Args: @@ -338,9 +340,13 @@ def delete(self, graph_id: str, document_id: str) -> bool: """ client = self._get_client() response = delete_document( - graph_id=graph_id, document_id=document_id, client=client + graph_id=graph_id, client=client, body=DeleteDocumentOp(document_id=document_id) ) - if response.status_code == HTTPStatus.NO_CONTENT: + if response.status_code in ( + HTTPStatus.OK, + HTTPStatus.ACCEPTED, + HTTPStatus.NO_CONTENT, + ): return True if response.status_code == HTTPStatus.NOT_FOUND: return False diff --git a/robosystems_client/clients/file_client.py b/robosystems_client/clients/file_client.py index ace3706..b077775 100644 --- a/robosystems_client/clients/file_client.py +++ b/robosystems_client/clients/file_client.py @@ -11,11 +11,11 @@ import logging import httpx -from ..api.files.create_file_upload import ( +from ..api.content_operations.op_create_file_upload import ( sync_detailed as create_file_upload, ) -from ..api.files.update_file import ( - sync_detailed as update_file, +from ..api.content_operations.op_ingest_file import ( + sync_detailed as ingest_file, ) from ..api.files.list_files import ( sync_detailed as list_files, @@ -23,11 +23,12 @@ from ..api.files.get_file import ( sync_detailed as get_file, ) -from ..api.files.delete_file import ( +from ..api.content_operations.op_delete_file import ( sync_detailed as delete_file, ) from ..models.file_upload_request import FileUploadRequest -from ..models.file_status_update import FileStatusUpdate +from ..models.ingest_file_op import IngestFileOp +from ..models.delete_file_op import DeleteFileOp logger = logging.getLogger(__name__) @@ -157,7 +158,10 @@ def upload( response = create_file_upload(**kwargs) - if response.status_code != 200 or not response.parsed: + # create-file-upload is a content operation: the presign payload + # (upload_url, file_id) is carried in the OperationEnvelope's result. + upload_data = getattr(response.parsed, "result", None) or {} + if response.status_code != 200 or not upload_data: error_msg = f"Failed to get upload URL: {response.status_code}" return FileUploadResult( file_id="", @@ -169,9 +173,8 @@ def upload( error=error_msg, ) - upload_data = response.parsed - upload_url = upload_data.upload_url - file_id = upload_data.file_id + upload_url = upload_data.get("upload_url") + file_id = upload_data.get("file_id") # Override S3 endpoint if configured (e.g., for LocalStack) if self.s3_endpoint_url: @@ -212,25 +215,24 @@ def upload( error=f"S3 upload failed: {s3_response.status_code}", ) - # Step 3: Mark file as uploaded + # Step 3: Ingest the uploaded file (stage into DuckDB) if options.on_progress: - options.on_progress(f"Marking {file_name} as uploaded...") + options.on_progress(f"Ingesting {file_name}...") - status_update = FileStatusUpdate( - status="uploaded", + ingest_op = IngestFileOp( + file_id=file_id, ingest_to_graph=options.ingest_to_graph, ) update_kwargs = { "graph_id": graph_id, - "file_id": file_id, "client": client, - "body": status_update, + "body": ingest_op, } - update_response = update_file(**update_kwargs) + update_response = ingest_file(**update_kwargs) - if update_response.status_code != 200 or not update_response.parsed: + if update_response.status_code not in (200, 202) or not update_response.parsed: return FileUploadResult( file_id=file_id, file_size=len(file_content), @@ -241,10 +243,12 @@ def upload( error="Failed to complete file upload", ) - # Extract metadata from response - response_data = update_response.parsed - actual_file_size = getattr(response_data, "file_size_bytes", len(file_content)) - actual_row_count = getattr(response_data, "row_count", 0) + # Extract staging metadata from the operation envelope result. Large files + # stage asynchronously (pending envelope, no result yet) — fall back to the + # uploaded byte count and a zero row count in that case. + ingest_data = getattr(update_response.parsed, "result", None) or {} + actual_file_size = ingest_data.get("file_size_bytes", len(file_content)) + actual_row_count = ingest_data.get("row_count", 0) or 0 if options.on_progress: options.on_progress( @@ -423,16 +427,17 @@ def delete(self, graph_id: str, file_id: str, cascade: bool = False) -> bool: headers=self.headers, ) + delete_op = DeleteFileOp(file_id=file_id, cascade=cascade) + kwargs = { "graph_id": graph_id, - "file_id": file_id, "client": client, - "cascade": cascade, + "body": delete_op, } response = delete_file(**kwargs) - if response.status_code not in [200, 204]: + if response.status_code not in [200, 202, 204]: logger.error(f"Failed to delete file {file_id}: {response.status_code}") return False diff --git a/robosystems_client/clients/query_client.py b/robosystems_client/clients/query_client.py index 83e46e3..4cc5b38 100644 --- a/robosystems_client/clients/query_client.py +++ b/robosystems_client/clients/query_client.py @@ -17,8 +17,8 @@ ) from datetime import datetime -from ..api.query.execute_cypher_query import sync_detailed as execute_cypher_query -from ..models.cypher_query_request import CypherQueryRequest +from ..api.query.execute_cypher import sync_detailed as execute_cypher_query +from ..models.cypher_statement_request import CypherStatementRequest from .sse_client import SSEClient, AsyncSSEClient, SSEConfig, EventType @@ -93,7 +93,7 @@ def execute_query( options = QueryOptions() # Build request data - query_request = CypherQueryRequest( + query_request = CypherStatementRequest( query=request.query, parameters=request.parameters or {} ) diff --git a/robosystems_client/clients/table_client.py b/robosystems_client/clients/table_client.py index ccaec73..b5ca60a 100644 --- a/robosystems_client/clients/table_client.py +++ b/robosystems_client/clients/table_client.py @@ -11,10 +11,10 @@ from ..api.tables.list_tables import ( sync_detailed as list_tables, ) -from ..api.tables.query_tables import ( +from ..api.query.execute_sql import ( sync_detailed as query_tables, ) -from ..models.table_query_request import TableQueryRequest +from ..models.sql_statement_request import SqlStatementRequest logger = logging.getLogger(__name__) @@ -131,7 +131,7 @@ def query( if limit is not None: final_query = f"{sql_query.rstrip(';')} LIMIT {limit}" - request = TableQueryRequest(sql=final_query) + request = SqlStatementRequest(sql=final_query) from ..client import AuthenticatedClient diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 062171d..2ecb3e5 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -29,7 +29,8 @@ CancelOperationResponseCanceloperation, ) from .cancel_subscription_request import CancelSubscriptionRequest -from .change_reporting_style_op import ChangeReportingStyleOp +from .change_reporting_style_request import ChangeReportingStyleRequest +from .change_reporting_style_response import ChangeReportingStyleResponse from .change_tier_op import ChangeTierOp from .change_tier_op_new_tier import ChangeTierOpNewTier from .checkout_response import CheckoutResponse @@ -115,12 +116,15 @@ from .custom_schema_definition_relationships_item import ( CustomSchemaDefinitionRelationshipsItem, ) -from .cypher_query_request import CypherQueryRequest -from .cypher_query_request_parameters_type_0 import CypherQueryRequestParametersType0 +from .cypher_statement_request import CypherStatementRequest +from .cypher_statement_request_parameters_type_0 import ( + CypherStatementRequestParametersType0, +) from .database_health_response import DatabaseHealthResponse from .database_info_response import DatabaseInfoResponse from .database_storage_entry import DatabaseStorageEntry -from .delete_file_response import DeleteFileResponse +from .delete_document_op import DeleteDocumentOp +from .delete_file_op import DeleteFileOp from .delete_graph_op import DeleteGraphOp from .delete_information_block_response import DeleteInformationBlockResponse from .delete_journal_entry_request import DeleteJournalEntryRequest @@ -150,9 +154,6 @@ from .document_list_item import DocumentListItem from .document_list_response import DocumentListResponse from .document_section import DocumentSection -from .document_update_request import DocumentUpdateRequest -from .document_upload_request import DocumentUploadRequest -from .document_upload_response import DocumentUploadResponse from .download_quota import DownloadQuota from .element_lite import ElementLite from .element_update_patch import ElementUpdatePatch @@ -192,12 +193,11 @@ from .file_info import FileInfo from .file_layer_status import FileLayerStatus from .file_report_request import FileReportRequest -from .file_status_update import FileStatusUpdate from .file_upload_request import FileUploadRequest -from .file_upload_response import FileUploadResponse from .financial_statement_analysis_request import FinancialStatementAnalysisRequest from .fiscal_calendar_response import FiscalCalendarResponse from .fiscal_period_summary import FiscalPeriodSummary +from .forget_op import ForgetOp from .forgot_password_request import ForgotPasswordRequest from .forgot_password_response_forgotpassword import ( ForgotPasswordResponseForgotpassword, @@ -233,11 +233,13 @@ from .health_status import HealthStatus from .health_status_details_type_0 import HealthStatusDetailsType0 from .http_validation_error import HTTPValidationError +from .index_document_op import IndexDocumentOp from .information_block_envelope import InformationBlockEnvelope from .information_block_envelope_dimensions_item import ( InformationBlockEnvelopeDimensionsItem, ) from .information_model_response import InformationModelResponse +from .ingest_file_op import IngestFileOp from .initial_entity_data import InitialEntityData from .initialize_ledger_request import InitializeLedgerRequest from .initialize_ledger_response import InitializeLedgerResponse @@ -270,6 +272,10 @@ from .mcp_tool_call_arguments import MCPToolCallArguments from .mcp_tools_response import MCPToolsResponse from .mcp_tools_response_tools_item import MCPToolsResponseToolsItem +from .memory_list_response import MemoryListResponse +from .memory_recall_request import MemoryRecallRequest +from .memory_record import MemoryRecord +from .memory_record_provenance_type_0 import MemoryRecordProvenanceType0 from .metric_mechanics import MetricMechanics from .o_auth_callback_request import OAuthCallbackRequest from .o_auth_init_request import OAuthInitRequest @@ -291,6 +297,12 @@ from .operation_envelope_association_response_status import ( OperationEnvelopeAssociationResponseStatus, ) +from .operation_envelope_change_reporting_style_response import ( + OperationEnvelopeChangeReportingStyleResponse, +) +from .operation_envelope_change_reporting_style_response_status import ( + OperationEnvelopeChangeReportingStyleResponseStatus, +) from .operation_envelope_close_period_response import ( OperationEnvelopeClosePeriodResponse, ) @@ -513,6 +525,8 @@ from .rebuild_schedule_request import RebuildScheduleRequest from .regenerate_report_operation import RegenerateReportOperation from .register_request import RegisterRequest +from .remember_op import RememberOp +from .remember_op_provenance_type_0 import RememberOpProvenanceType0 from .remove_publish_list_member_operation import RemovePublishListMemberOperation from .rendering_lite import RenderingLite from .rendering_period_lite import RenderingPeriodLite @@ -572,6 +586,8 @@ from .share_report_operation import ShareReportOperation from .share_report_response import ShareReportResponse from .share_result_item import ShareResultItem +from .sql_statement_request import SqlStatementRequest +from .sql_statement_response import SqlStatementResponse from .sso_complete_request import SSOCompleteRequest from .sso_exchange_request import SSOExchangeRequest from .sso_exchange_response import SSOExchangeResponse @@ -595,8 +611,6 @@ ) from .table_info import TableInfo from .table_list_response import TableListResponse -from .table_query_request import TableQueryRequest -from .table_query_response import TableQueryResponse from .taxonomy_block_association import TaxonomyBlockAssociation from .taxonomy_block_association_request import TaxonomyBlockAssociationRequest from .taxonomy_block_association_request_association_type import ( @@ -666,13 +680,14 @@ from .update_event_handler_request_metadata_patch import ( UpdateEventHandlerRequestMetadataPatch, ) -from .update_file_response_updatefile import UpdateFileResponseUpdatefile from .update_journal_entry_request import UpdateJournalEntryRequest from .update_journal_entry_request_type_type_0 import UpdateJournalEntryRequestTypeType0 from .update_legacy_arm import UpdateLegacyArm from .update_legacy_arm_block_type import UpdateLegacyArmBlockType from .update_legacy_arm_payload import UpdateLegacyArmPayload from .update_member_role_request import UpdateMemberRoleRequest +from .update_memory_op import UpdateMemoryOp +from .update_memory_op_provenance_type_0 import UpdateMemoryOpProvenanceType0 from .update_org_request import UpdateOrgRequest from .update_password_request import UpdatePasswordRequest from .update_portfolio_block_operation import UpdatePortfolioBlockOperation @@ -731,7 +746,8 @@ "BillingCustomer", "CancelOperationResponseCanceloperation", "CancelSubscriptionRequest", - "ChangeReportingStyleOp", + "ChangeReportingStyleRequest", + "ChangeReportingStyleResponse", "ChangeTierOp", "ChangeTierOpNewTier", "CheckoutResponse", @@ -799,12 +815,13 @@ "CustomSchemaDefinitionMetadata", "CustomSchemaDefinitionNodesItem", "CustomSchemaDefinitionRelationshipsItem", - "CypherQueryRequest", - "CypherQueryRequestParametersType0", + "CypherStatementRequest", + "CypherStatementRequestParametersType0", "DatabaseHealthResponse", "DatabaseInfoResponse", "DatabaseStorageEntry", - "DeleteFileResponse", + "DeleteDocumentOp", + "DeleteFileOp", "DeleteGraphOp", "DeleteInformationBlockResponse", "DeleteJournalEntryRequest", @@ -832,9 +849,6 @@ "DocumentListItem", "DocumentListResponse", "DocumentSection", - "DocumentUpdateRequest", - "DocumentUploadRequest", - "DocumentUploadResponse", "DownloadQuota", "ElementLite", "ElementUpdatePatch", @@ -866,12 +880,11 @@ "FileInfo", "FileLayerStatus", "FileReportRequest", - "FileStatusUpdate", "FileUploadRequest", - "FileUploadResponse", "FinancialStatementAnalysisRequest", "FiscalCalendarResponse", "FiscalPeriodSummary", + "ForgetOp", "ForgotPasswordRequest", "ForgotPasswordResponseForgotpassword", "GetCurrentAuthUserResponseGetcurrentauthuser", @@ -899,9 +912,11 @@ "HealthStatus", "HealthStatusDetailsType0", "HTTPValidationError", + "IndexDocumentOp", "InformationBlockEnvelope", "InformationBlockEnvelopeDimensionsItem", "InformationModelResponse", + "IngestFileOp", "InitialEntityData", "InitializeLedgerRequest", "InitializeLedgerResponse", @@ -932,6 +947,10 @@ "MCPToolCallArguments", "MCPToolsResponse", "MCPToolsResponseToolsItem", + "MemoryListResponse", + "MemoryRecallRequest", + "MemoryRecord", + "MemoryRecordProvenanceType0", "MetricMechanics", "OAuthCallbackRequest", "OAuthInitRequest", @@ -945,6 +964,8 @@ "OperationEnvelope", "OperationEnvelopeAssociationResponse", "OperationEnvelopeAssociationResponseStatus", + "OperationEnvelopeChangeReportingStyleResponse", + "OperationEnvelopeChangeReportingStyleResponseStatus", "OperationEnvelopeClosePeriodResponse", "OperationEnvelopeClosePeriodResponseStatus", "OperationEnvelopeDeleteInformationBlockResponse", @@ -1065,6 +1086,8 @@ "RebuildScheduleRequest", "RegenerateReportOperation", "RegisterRequest", + "RememberOp", + "RememberOpProvenanceType0", "RemovePublishListMemberOperation", "RenderingLite", "RenderingPeriodLite", @@ -1114,6 +1137,8 @@ "ShareReportOperation", "ShareReportResponse", "ShareResultItem", + "SqlStatementRequest", + "SqlStatementResponse", "SSOCompleteRequest", "SSOExchangeRequest", "SSOExchangeResponse", @@ -1135,8 +1160,6 @@ "SyncConnectionRequestSyncOptionsType0", "TableInfo", "TableListResponse", - "TableQueryRequest", - "TableQueryResponse", "TaxonomyBlockAssociation", "TaxonomyBlockAssociationRequest", "TaxonomyBlockAssociationRequestAssociationType", @@ -1180,13 +1203,14 @@ "UpdateEventHandlerRequest", "UpdateEventHandlerRequestMatchMetadataExpressionType0", "UpdateEventHandlerRequestMetadataPatch", - "UpdateFileResponseUpdatefile", "UpdateJournalEntryRequest", "UpdateJournalEntryRequestTypeType0", "UpdateLegacyArm", "UpdateLegacyArmBlockType", "UpdateLegacyArmPayload", "UpdateMemberRoleRequest", + "UpdateMemoryOp", + "UpdateMemoryOpProvenanceType0", "UpdateOrgRequest", "UpdatePasswordRequest", "UpdatePortfolioBlockOperation", diff --git a/robosystems_client/models/change_reporting_style_op.py b/robosystems_client/models/change_reporting_style_op.py deleted file mode 100644 index 0f9c927..0000000 --- a/robosystems_client/models/change_reporting_style_op.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ChangeReportingStyleOp") - - -@_attrs_define -class ChangeReportingStyleOp: - """Body for the change-reporting-style operation. - - Switches the graph to a different Reporting Style. The target Style - must be a library- or customer-authored Structure with - ``block_type='reporting_style'`` and a complete composition - (one Network per required statement type — BS / IS / CF / SE). Filed - Reports are unaffected because each ``Report`` already pins its own - ``structure_id`` per FactSet at create-time; new reports use the new - Style. Idempotent on the same target id. - - Attributes: - reporting_style_id (str): Structure id of the target Reporting Style (e.g., - `025f5d48-12ce-5d65-b9eb-4f137a10ef06` for the library-seeded Default Style). Must resolve to a Structure with - block_type='reporting_style' that has a complete composition in the graph's tenant schema. - """ - - reporting_style_id: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - reporting_style_id = self.reporting_style_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "reporting_style_id": reporting_style_id, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - reporting_style_id = d.pop("reporting_style_id") - - change_reporting_style_op = cls( - reporting_style_id=reporting_style_id, - ) - - change_reporting_style_op.additional_properties = d - return change_reporting_style_op - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/change_reporting_style_request.py b/robosystems_client/models/change_reporting_style_request.py new file mode 100644 index 0000000..c35f72c --- /dev/null +++ b/robosystems_client/models/change_reporting_style_request.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ChangeReportingStyleRequest") + + +@_attrs_define +class ChangeReportingStyleRequest: + """Switch a reporting entity's Reporting Style. + + The Reporting Style governs how the entity's statements are laid out + (equity-form, close-target concept, per-statement Networks). It's + validated against the tenant schema — the target must be a renderable + Style with a complete composition — before the switch is applied. + + Attributes: + reporting_style_id (str): Structure id of the target Reporting Style. Must exist in the tenant schema with a + complete Network composition. + entity_id (None | str | Unset): Target entity. Omit to target the graph's primary (earliest-created) entity — + the single-entity default. + """ + + reporting_style_id: str + entity_id: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + reporting_style_id = self.reporting_style_id + + entity_id: None | str | Unset + if isinstance(self.entity_id, Unset): + entity_id = UNSET + else: + entity_id = self.entity_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "reporting_style_id": reporting_style_id, + } + ) + if entity_id is not UNSET: + field_dict["entity_id"] = entity_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + reporting_style_id = d.pop("reporting_style_id") + + def _parse_entity_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + entity_id = _parse_entity_id(d.pop("entity_id", UNSET)) + + change_reporting_style_request = cls( + reporting_style_id=reporting_style_id, + entity_id=entity_id, + ) + + change_reporting_style_request.additional_properties = d + return change_reporting_style_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/change_reporting_style_response.py b/robosystems_client/models/change_reporting_style_response.py new file mode 100644 index 0000000..5b3f447 --- /dev/null +++ b/robosystems_client/models/change_reporting_style_response.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ChangeReportingStyleResponse") + + +@_attrs_define +class ChangeReportingStyleResponse: + """Result of a change-reporting-style operation. + + Attributes: + entity_id (str): Entity whose Style was targeted. + reporting_style_id (str): Active Style id after the call. + changed (bool): False when the target equals the current Style (no-op). + previous_reporting_style_id (None | str | Unset): Style id before the change (null for legacy/unset). + reporting_style_code (None | str | Unset): 4-segment Style code (e.g. BSC-CORP-IS02-CF1), when stamped. + """ + + entity_id: str + reporting_style_id: str + changed: bool + previous_reporting_style_id: None | str | Unset = UNSET + reporting_style_code: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + reporting_style_id = self.reporting_style_id + + changed = self.changed + + previous_reporting_style_id: None | str | Unset + if isinstance(self.previous_reporting_style_id, Unset): + previous_reporting_style_id = UNSET + else: + previous_reporting_style_id = self.previous_reporting_style_id + + reporting_style_code: None | str | Unset + if isinstance(self.reporting_style_code, Unset): + reporting_style_code = UNSET + else: + reporting_style_code = self.reporting_style_code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "reporting_style_id": reporting_style_id, + "changed": changed, + } + ) + if previous_reporting_style_id is not UNSET: + field_dict["previous_reporting_style_id"] = previous_reporting_style_id + if reporting_style_code is not UNSET: + field_dict["reporting_style_code"] = reporting_style_code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + entity_id = d.pop("entity_id") + + reporting_style_id = d.pop("reporting_style_id") + + changed = d.pop("changed") + + def _parse_previous_reporting_style_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + previous_reporting_style_id = _parse_previous_reporting_style_id( + d.pop("previous_reporting_style_id", UNSET) + ) + + def _parse_reporting_style_code(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + reporting_style_code = _parse_reporting_style_code( + d.pop("reporting_style_code", UNSET) + ) + + change_reporting_style_response = cls( + entity_id=entity_id, + reporting_style_id=reporting_style_id, + changed=changed, + previous_reporting_style_id=previous_reporting_style_id, + reporting_style_code=reporting_style_code, + ) + + change_reporting_style_response.additional_properties = d + return change_reporting_style_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/cypher_query_request.py b/robosystems_client/models/cypher_statement_request.py similarity index 69% rename from robosystems_client/models/cypher_query_request.py rename to robosystems_client/models/cypher_statement_request.py index ee8a739..fb9aa44 100644 --- a/robosystems_client/models/cypher_query_request.py +++ b/robosystems_client/models/cypher_statement_request.py @@ -8,33 +8,33 @@ from ..types import UNSET, Unset if TYPE_CHECKING: - from ..models.cypher_query_request_parameters_type_0 import ( - CypherQueryRequestParametersType0, + from ..models.cypher_statement_request_parameters_type_0 import ( + CypherStatementRequestParametersType0, ) -T = TypeVar("T", bound="CypherQueryRequest") +T = TypeVar("T", bound="CypherStatementRequest") @_attrs_define -class CypherQueryRequest: +class CypherStatementRequest: """Request model for Cypher query execution. Attributes: query (str): The Cypher query to execute. Use parameters ($param_name) for all dynamic values to prevent injection attacks. - parameters (CypherQueryRequestParametersType0 | None | Unset): Query parameters for safe value substitution. + parameters (CypherStatementRequestParametersType0 | None | Unset): Query parameters for safe value substitution. ALWAYS use parameters instead of string interpolation. timeout (int | None | Unset): Query timeout in seconds (1-300) Default: 60. """ query: str - parameters: CypherQueryRequestParametersType0 | None | Unset = UNSET + parameters: CypherStatementRequestParametersType0 | None | Unset = UNSET timeout: int | None | Unset = 60 def to_dict(self) -> dict[str, Any]: - from ..models.cypher_query_request_parameters_type_0 import ( - CypherQueryRequestParametersType0, + from ..models.cypher_statement_request_parameters_type_0 import ( + CypherStatementRequestParametersType0, ) query = self.query @@ -42,7 +42,7 @@ def to_dict(self) -> dict[str, Any]: parameters: dict[str, Any] | None | Unset if isinstance(self.parameters, Unset): parameters = UNSET - elif isinstance(self.parameters, CypherQueryRequestParametersType0): + elif isinstance(self.parameters, CypherStatementRequestParametersType0): parameters = self.parameters.to_dict() else: parameters = self.parameters @@ -69,8 +69,8 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.cypher_query_request_parameters_type_0 import ( - CypherQueryRequestParametersType0, + from ..models.cypher_statement_request_parameters_type_0 import ( + CypherStatementRequestParametersType0, ) d = dict(src_dict) @@ -78,7 +78,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: def _parse_parameters( data: object, - ) -> CypherQueryRequestParametersType0 | None | Unset: + ) -> CypherStatementRequestParametersType0 | None | Unset: if data is None: return data if isinstance(data, Unset): @@ -86,12 +86,12 @@ def _parse_parameters( try: if not isinstance(data, dict): raise TypeError() - parameters_type_0 = CypherQueryRequestParametersType0.from_dict(data) + parameters_type_0 = CypherStatementRequestParametersType0.from_dict(data) return parameters_type_0 except (TypeError, ValueError, AttributeError, KeyError): pass - return cast(CypherQueryRequestParametersType0 | None | Unset, data) + return cast(CypherStatementRequestParametersType0 | None | Unset, data) parameters = _parse_parameters(d.pop("parameters", UNSET)) @@ -104,10 +104,10 @@ def _parse_timeout(data: object) -> int | None | Unset: timeout = _parse_timeout(d.pop("timeout", UNSET)) - cypher_query_request = cls( + cypher_statement_request = cls( query=query, parameters=parameters, timeout=timeout, ) - return cypher_query_request + return cypher_statement_request diff --git a/robosystems_client/models/cypher_statement_request_parameters_type_0.py b/robosystems_client/models/cypher_statement_request_parameters_type_0.py new file mode 100644 index 0000000..6bb24e3 --- /dev/null +++ b/robosystems_client/models/cypher_statement_request_parameters_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CypherStatementRequestParametersType0") + + +@_attrs_define +class CypherStatementRequestParametersType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + cypher_statement_request_parameters_type_0 = cls() + + cypher_statement_request_parameters_type_0.additional_properties = d + return cypher_statement_request_parameters_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/document_upload_response.py b/robosystems_client/models/delete_document_op.py similarity index 51% rename from robosystems_client/models/document_upload_response.py rename to robosystems_client/models/delete_document_op.py index 89cb565..99bff90 100644 --- a/robosystems_client/models/document_upload_response.py +++ b/robosystems_client/models/delete_document_op.py @@ -1,53 +1,33 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar, cast +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="DocumentUploadResponse") +T = TypeVar("T", bound="DeleteDocumentOp") @_attrs_define -class DocumentUploadResponse: - """Response from document upload. +class DeleteDocumentOp: + """Body for delete-document (corpus content-op). Attributes: - id (str): - document_id (str): - sections_indexed (int): - total_content_length (int): - section_ids (list[str]): + document_id (str): Document id to delete """ - id: str document_id: str - sections_indexed: int - total_content_length: int - section_ids: list[str] additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - id = self.id - document_id = self.document_id - sections_indexed = self.sections_indexed - - total_content_length = self.total_content_length - - section_ids = self.section_ids - field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "id": id, "document_id": document_id, - "sections_indexed": sections_indexed, - "total_content_length": total_content_length, - "section_ids": section_ids, } ) @@ -56,26 +36,14 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - id = d.pop("id") - document_id = d.pop("document_id") - sections_indexed = d.pop("sections_indexed") - - total_content_length = d.pop("total_content_length") - - section_ids = cast(list[str], d.pop("section_ids")) - - document_upload_response = cls( - id=id, + delete_document_op = cls( document_id=document_id, - sections_indexed=sections_indexed, - total_content_length=total_content_length, - section_ids=section_ids, ) - document_upload_response.additional_properties = d - return document_upload_response + delete_document_op.additional_properties = d + return delete_document_op @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/file_upload_response.py b/robosystems_client/models/delete_file_op.py similarity index 60% rename from robosystems_client/models/file_upload_response.py rename to robosystems_client/models/delete_file_op.py index 0d11c44..0dab9ac 100644 --- a/robosystems_client/models/file_upload_response.py +++ b/robosystems_client/models/delete_file_op.py @@ -6,67 +6,55 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="FileUploadResponse") +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DeleteFileOp") @_attrs_define -class FileUploadResponse: - """ +class DeleteFileOp: + """Body for delete-file (raw content-op). + Attributes: - upload_url (str): Presigned S3 upload URL - expires_in (int): URL expiration time in seconds - file_id (str): File tracking ID - s3_key (str): S3 object key + file_id (str): File id to delete + cascade (bool | Unset): Also delete the file's rows from DuckDB tables and mark the graph stale Default: False. """ - upload_url: str - expires_in: int file_id: str - s3_key: str + cascade: bool | Unset = False additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - upload_url = self.upload_url - - expires_in = self.expires_in - file_id = self.file_id - s3_key = self.s3_key + cascade = self.cascade field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "upload_url": upload_url, - "expires_in": expires_in, "file_id": file_id, - "s3_key": s3_key, } ) + if cascade is not UNSET: + field_dict["cascade"] = cascade return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - upload_url = d.pop("upload_url") - - expires_in = d.pop("expires_in") - file_id = d.pop("file_id") - s3_key = d.pop("s3_key") + cascade = d.pop("cascade", UNSET) - file_upload_response = cls( - upload_url=upload_url, - expires_in=expires_in, + delete_file_op = cls( file_id=file_id, - s3_key=s3_key, + cascade=cascade, ) - file_upload_response.additional_properties = d - return file_upload_response + delete_file_op.additional_properties = d + return delete_file_op @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/delete_file_response.py b/robosystems_client/models/delete_file_response.py deleted file mode 100644 index 85574ba..0000000 --- a/robosystems_client/models/delete_file_response.py +++ /dev/null @@ -1,136 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DeleteFileResponse") - - -@_attrs_define -class DeleteFileResponse: - """ - Attributes: - status (str): Deletion status - file_id (str): Deleted file ID - file_name (str): Deleted file name - message (str): Operation message - cascade_deleted (bool | Unset): Whether cascade deletion was performed Default: False. - tables_affected (list[str] | None | Unset): Tables from which file data was deleted (if cascade=true) - graph_marked_stale (bool | Unset): Whether graph was marked as stale Default: False. - """ - - status: str - file_id: str - file_name: str - message: str - cascade_deleted: bool | Unset = False - tables_affected: list[str] | None | Unset = UNSET - graph_marked_stale: bool | Unset = False - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - status = self.status - - file_id = self.file_id - - file_name = self.file_name - - message = self.message - - cascade_deleted = self.cascade_deleted - - tables_affected: list[str] | None | Unset - if isinstance(self.tables_affected, Unset): - tables_affected = UNSET - elif isinstance(self.tables_affected, list): - tables_affected = self.tables_affected - - else: - tables_affected = self.tables_affected - - graph_marked_stale = self.graph_marked_stale - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "status": status, - "file_id": file_id, - "file_name": file_name, - "message": message, - } - ) - if cascade_deleted is not UNSET: - field_dict["cascade_deleted"] = cascade_deleted - if tables_affected is not UNSET: - field_dict["tables_affected"] = tables_affected - if graph_marked_stale is not UNSET: - field_dict["graph_marked_stale"] = graph_marked_stale - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - status = d.pop("status") - - file_id = d.pop("file_id") - - file_name = d.pop("file_name") - - message = d.pop("message") - - cascade_deleted = d.pop("cascade_deleted", UNSET) - - def _parse_tables_affected(data: object) -> list[str] | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, list): - raise TypeError() - tables_affected_type_0 = cast(list[str], data) - - return tables_affected_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(list[str] | None | Unset, data) - - tables_affected = _parse_tables_affected(d.pop("tables_affected", UNSET)) - - graph_marked_stale = d.pop("graph_marked_stale", UNSET) - - delete_file_response = cls( - status=status, - file_id=file_id, - file_name=file_name, - message=message, - cascade_deleted=cascade_deleted, - tables_affected=tables_affected, - graph_marked_stale=graph_marked_stale, - ) - - delete_file_response.additional_properties = d - return delete_file_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/document_upload_request.py b/robosystems_client/models/document_upload_request.py deleted file mode 100644 index 265e500..0000000 --- a/robosystems_client/models/document_upload_request.py +++ /dev/null @@ -1,143 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DocumentUploadRequest") - - -@_attrs_define -class DocumentUploadRequest: - """Upload a markdown document for text indexing. - - Attributes: - title (str): Document title - content (str): Markdown content - tags (list[str] | None | Unset): Optional tags for filtering - folder (None | str | Unset): Optional folder/category - external_id (None | str | Unset): Optional external identifier for upsert (e.g., Google Drive file ID) - """ - - title: str - content: str - tags: list[str] | None | Unset = UNSET - folder: None | str | Unset = UNSET - external_id: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - title = self.title - - content = self.content - - tags: list[str] | None | Unset - if isinstance(self.tags, Unset): - tags = UNSET - elif isinstance(self.tags, list): - tags = self.tags - - else: - tags = self.tags - - folder: None | str | Unset - if isinstance(self.folder, Unset): - folder = UNSET - else: - folder = self.folder - - external_id: None | str | Unset - if isinstance(self.external_id, Unset): - external_id = UNSET - else: - external_id = self.external_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "title": title, - "content": content, - } - ) - if tags is not UNSET: - field_dict["tags"] = tags - if folder is not UNSET: - field_dict["folder"] = folder - if external_id is not UNSET: - field_dict["external_id"] = external_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - title = d.pop("title") - - content = d.pop("content") - - def _parse_tags(data: object) -> list[str] | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, list): - raise TypeError() - tags_type_0 = cast(list[str], data) - - return tags_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(list[str] | None | Unset, data) - - tags = _parse_tags(d.pop("tags", UNSET)) - - def _parse_folder(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - folder = _parse_folder(d.pop("folder", UNSET)) - - def _parse_external_id(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - external_id = _parse_external_id(d.pop("external_id", UNSET)) - - document_upload_request = cls( - title=title, - content=content, - tags=tags, - folder=folder, - external_id=external_id, - ) - - document_upload_request.additional_properties = d - return document_upload_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/file_status_update.py b/robosystems_client/models/file_status_update.py deleted file mode 100644 index 6927ee2..0000000 --- a/robosystems_client/models/file_status_update.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="FileStatusUpdate") - - -@_attrs_define -class FileStatusUpdate: - """ - Attributes: - status (str): File status: 'uploaded' (ready for ingest), 'disabled' (exclude from ingest), 'archived' (soft - deleted) - ingest_to_graph (bool | Unset): Auto-ingest to graph after DuckDB staging. Default=false (batch mode). Set to - true for real-time incremental updates. Default: False. - """ - - status: str - ingest_to_graph: bool | Unset = False - - def to_dict(self) -> dict[str, Any]: - status = self.status - - ingest_to_graph = self.ingest_to_graph - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "status": status, - } - ) - if ingest_to_graph is not UNSET: - field_dict["ingest_to_graph"] = ingest_to_graph - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - status = d.pop("status") - - ingest_to_graph = d.pop("ingest_to_graph", UNSET) - - file_status_update = cls( - status=status, - ingest_to_graph=ingest_to_graph, - ) - - return file_status_update diff --git a/robosystems_client/models/forget_op.py b/robosystems_client/models/forget_op.py new file mode 100644 index 0000000..d4a326c --- /dev/null +++ b/robosystems_client/models/forget_op.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ForgetOp") + + +@_attrs_define +class ForgetOp: + """Body for the forget operation (delete a semantic memory by id). + + Attributes: + memory_id (str): Server-generated memory id to forget + """ + + memory_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + memory_id = self.memory_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "memory_id": memory_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + memory_id = d.pop("memory_id") + + forget_op = cls( + memory_id=memory_id, + ) + + forget_op.additional_properties = d + return forget_op + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/document_update_request.py b/robosystems_client/models/index_document_op.py similarity index 63% rename from robosystems_client/models/document_update_request.py rename to robosystems_client/models/index_document_op.py index abf42f2..e667f36 100644 --- a/robosystems_client/models/document_update_request.py +++ b/robosystems_client/models/index_document_op.py @@ -8,27 +8,40 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="DocumentUpdateRequest") +T = TypeVar("T", bound="IndexDocumentOp") @_attrs_define -class DocumentUpdateRequest: - """Update a document's metadata and/or content. - - Attributes: - title (None | str | Unset): - content (None | str | Unset): - tags (list[str] | None | Unset): - folder (None | str | Unset): +class IndexDocumentOp: + """Body for index-document (corpus content-op). + + Create a new document when ``document_id`` is absent; update the named + document (partial — only supplied fields) when present. + + Attributes: + document_id (None | str | Unset): Present → update that document; absent → create a new one + title (None | str | Unset): Required when creating + content (None | str | Unset): Required when creating + tags (list[str] | None | Unset): Optional labels + folder (None | str | Unset): Optional folder + external_id (None | str | Unset): Upsert key (create): re-indexing the same id replaces """ + document_id: None | str | Unset = UNSET title: None | str | Unset = UNSET content: None | str | Unset = UNSET tags: list[str] | None | Unset = UNSET folder: None | str | Unset = UNSET + external_id: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + document_id: None | str | Unset + if isinstance(self.document_id, Unset): + document_id = UNSET + else: + document_id = self.document_id + title: None | str | Unset if isinstance(self.title, Unset): title = UNSET @@ -56,9 +69,17 @@ def to_dict(self) -> dict[str, Any]: else: folder = self.folder + external_id: None | str | Unset + if isinstance(self.external_id, Unset): + external_id = UNSET + else: + external_id = self.external_id + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) + if document_id is not UNSET: + field_dict["document_id"] = document_id if title is not UNSET: field_dict["title"] = title if content is not UNSET: @@ -67,6 +88,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["tags"] = tags if folder is not UNSET: field_dict["folder"] = folder + if external_id is not UNSET: + field_dict["external_id"] = external_id return field_dict @@ -74,6 +97,15 @@ def to_dict(self) -> dict[str, Any]: def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) + def _parse_document_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + document_id = _parse_document_id(d.pop("document_id", UNSET)) + def _parse_title(data: object) -> None | str | Unset: if data is None: return data @@ -118,15 +150,26 @@ def _parse_folder(data: object) -> None | str | Unset: folder = _parse_folder(d.pop("folder", UNSET)) - document_update_request = cls( + def _parse_external_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + external_id = _parse_external_id(d.pop("external_id", UNSET)) + + index_document_op = cls( + document_id=document_id, title=title, content=content, tags=tags, folder=folder, + external_id=external_id, ) - document_update_request.additional_properties = d - return document_update_request + index_document_op.additional_properties = d + return index_document_op @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/ingest_file_op.py b/robosystems_client/models/ingest_file_op.py new file mode 100644 index 0000000..135528b --- /dev/null +++ b/robosystems_client/models/ingest_file_op.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="IngestFileOp") + + +@_attrs_define +class IngestFileOp: + """Body for ingest-file (raw→staging content flow). + + Marks an uploaded file ready and triggers DuckDB staging. Set + ``ingest_to_graph`` to auto-chain graph materialization after staging. + + Attributes: + file_id (str): Uploaded file id to ingest + ingest_to_graph (bool | Unset): Auto-materialize into the graph after DuckDB staging Default: False. + """ + + file_id: str + ingest_to_graph: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file_id = self.file_id + + ingest_to_graph = self.ingest_to_graph + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file_id": file_id, + } + ) + if ingest_to_graph is not UNSET: + field_dict["ingest_to_graph"] = ingest_to_graph + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file_id = d.pop("file_id") + + ingest_to_graph = d.pop("ingest_to_graph", UNSET) + + ingest_file_op = cls( + file_id=file_id, + ingest_to_graph=ingest_to_graph, + ) + + ingest_file_op.additional_properties = d + return ingest_file_op + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/initial_entity_data.py b/robosystems_client/models/initial_entity_data.py index 66a9494..ba1aecb 100644 --- a/robosystems_client/models/initial_entity_data.py +++ b/robosystems_client/models/initial_entity_data.py @@ -34,7 +34,7 @@ class InitialEntityData: 'partnership', 'sole_proprietorship', 'non_profit'). Drives the graph's default Reporting Style at creation — partnership and llc get dedicated equity-form Styles; everything else defaults to corporate. Blank falls back to corporate. - reporting_style_id (None | str | Unset): Optional explicit Reporting Style Structure id to pin on the graph, + reporting_style_id (None | str | Unset): Optional explicit Reporting Style Structure id to pin on the entity, overriding the entity_type-derived default. Leave blank to derive from entity_type. Change later via the change- reporting-style operation. """ diff --git a/robosystems_client/models/ledger_entity_response.py b/robosystems_client/models/ledger_entity_response.py index 3c2e4db..f184325 100644 --- a/robosystems_client/models/ledger_entity_response.py +++ b/robosystems_client/models/ledger_entity_response.py @@ -38,6 +38,8 @@ class LedgerEntityResponse: lei (None | str | Unset): Legal Entity Identifier (ISO 17442). industry (None | str | Unset): Free-form industry label. entity_type (None | str | Unset): Legal form (e.g. 'corporation', 'llc', 'lp'). + reporting_style_id (None | str | Unset): Active Reporting Style (Structure id) governing this entity's statement + layout. Change it via the change-reporting-style operation. phone (None | str | Unset): website (None | str | Unset): status (str | Unset): Operational status: 'active' | 'inactive' | 'dissolved'. Default: 'active'. @@ -73,6 +75,7 @@ class LedgerEntityResponse: lei: None | str | Unset = UNSET industry: None | str | Unset = UNSET entity_type: None | str | Unset = UNSET + reporting_style_id: None | str | Unset = UNSET phone: None | str | Unset = UNSET website: None | str | Unset = UNSET status: str | Unset = "active" @@ -180,6 +183,12 @@ def to_dict(self) -> dict[str, Any]: else: entity_type = self.entity_type + reporting_style_id: None | str | Unset + if isinstance(self.reporting_style_id, Unset): + reporting_style_id = UNSET + else: + reporting_style_id = self.reporting_style_id + phone: None | str | Unset if isinstance(self.phone, Unset): phone = UNSET @@ -300,6 +309,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["industry"] = industry if entity_type is not UNSET: field_dict["entity_type"] = entity_type + if reporting_style_id is not UNSET: + field_dict["reporting_style_id"] = reporting_style_id if phone is not UNSET: field_dict["phone"] = phone if website is not UNSET: @@ -470,6 +481,15 @@ def _parse_entity_type(data: object) -> None | str | Unset: entity_type = _parse_entity_type(d.pop("entity_type", UNSET)) + def _parse_reporting_style_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + reporting_style_id = _parse_reporting_style_id(d.pop("reporting_style_id", UNSET)) + def _parse_phone(data: object) -> None | str | Unset: if data is None: return data @@ -612,6 +632,7 @@ def _parse_updated_at(data: object) -> None | str | Unset: lei=lei, industry=industry, entity_type=entity_type, + reporting_style_id=reporting_style_id, phone=phone, website=website, status=status, diff --git a/robosystems_client/models/memory_list_response.py b/robosystems_client/models/memory_list_response.py new file mode 100644 index 0000000..557c13b --- /dev/null +++ b/robosystems_client/models/memory_list_response.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.memory_record import MemoryRecord + + +T = TypeVar("T", bound="MemoryListResponse") + + +@_attrs_define +class MemoryListResponse: + """Governance list of memories for a graph. + + Attributes: + total (int): + memories (list[MemoryRecord]): + graph_id (str): + """ + + total: int + memories: list[MemoryRecord] + graph_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + total = self.total + + memories = [] + for memories_item_data in self.memories: + memories_item = memories_item_data.to_dict() + memories.append(memories_item) + + graph_id = self.graph_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "total": total, + "memories": memories, + "graph_id": graph_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.memory_record import MemoryRecord + + d = dict(src_dict) + total = d.pop("total") + + memories = [] + _memories = d.pop("memories") + for memories_item_data in _memories: + memories_item = MemoryRecord.from_dict(memories_item_data) + + memories.append(memories_item) + + graph_id = d.pop("graph_id") + + memory_list_response = cls( + total=total, + memories=memories, + graph_id=graph_id, + ) + + memory_list_response.additional_properties = d + return memory_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/memory_recall_request.py b/robosystems_client/models/memory_recall_request.py new file mode 100644 index 0000000..c84ff9c --- /dev/null +++ b/robosystems_client/models/memory_recall_request.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MemoryRecallRequest") + + +@_attrs_define +class MemoryRecallRequest: + """Body for recall (ranked semantic search over memory). + + Attributes: + query (str): Recall query + k (int | Unset): Max results to return Default: 10. + memory_type (None | str | Unset): Filter by memory type + source (None | str | Unset): Filter by source + """ + + query: str + k: int | Unset = 10 + memory_type: None | str | Unset = UNSET + source: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + query = self.query + + k = self.k + + memory_type: None | str | Unset + if isinstance(self.memory_type, Unset): + memory_type = UNSET + else: + memory_type = self.memory_type + + source: None | str | Unset + if isinstance(self.source, Unset): + source = UNSET + else: + source = self.source + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "query": query, + } + ) + if k is not UNSET: + field_dict["k"] = k + if memory_type is not UNSET: + field_dict["memory_type"] = memory_type + if source is not UNSET: + field_dict["source"] = source + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query = d.pop("query") + + k = d.pop("k", UNSET) + + def _parse_memory_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + memory_type = _parse_memory_type(d.pop("memory_type", UNSET)) + + def _parse_source(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + source = _parse_source(d.pop("source", UNSET)) + + memory_recall_request = cls( + query=query, + k=k, + memory_type=memory_type, + source=source, + ) + + memory_recall_request.additional_properties = d + return memory_recall_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/memory_record.py b/robosystems_client/models/memory_record.py new file mode 100644 index 0000000..df84bc7 --- /dev/null +++ b/robosystems_client/models/memory_record.py @@ -0,0 +1,283 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.memory_record_provenance_type_0 import MemoryRecordProvenanceType0 + + +T = TypeVar("T", bound="MemoryRecord") + + +@_attrs_define +class MemoryRecord: + """A stored memory (never includes the raw embedding vector). + + Attributes: + id (str): + text (str): + source (None | str | Unset): + memory_type (None | str | Unset): + tags (list[str] | None | Unset): + source_ref (None | str | Unset): + provenance (MemoryRecordProvenanceType0 | None | Unset): + created_by (None | str | Unset): + created_at (datetime.datetime | None | Unset): + updated_at (datetime.datetime | None | Unset): + """ + + id: str + text: str + source: None | str | Unset = UNSET + memory_type: None | str | Unset = UNSET + tags: list[str] | None | Unset = UNSET + source_ref: None | str | Unset = UNSET + provenance: MemoryRecordProvenanceType0 | None | Unset = UNSET + created_by: None | str | Unset = UNSET + created_at: datetime.datetime | None | Unset = UNSET + updated_at: datetime.datetime | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.memory_record_provenance_type_0 import MemoryRecordProvenanceType0 + + id = self.id + + text = self.text + + source: None | str | Unset + if isinstance(self.source, Unset): + source = UNSET + else: + source = self.source + + memory_type: None | str | Unset + if isinstance(self.memory_type, Unset): + memory_type = UNSET + else: + memory_type = self.memory_type + + tags: list[str] | None | Unset + if isinstance(self.tags, Unset): + tags = UNSET + elif isinstance(self.tags, list): + tags = self.tags + + else: + tags = self.tags + + source_ref: None | str | Unset + if isinstance(self.source_ref, Unset): + source_ref = UNSET + else: + source_ref = self.source_ref + + provenance: dict[str, Any] | None | Unset + if isinstance(self.provenance, Unset): + provenance = UNSET + elif isinstance(self.provenance, MemoryRecordProvenanceType0): + provenance = self.provenance.to_dict() + else: + provenance = self.provenance + + created_by: None | str | Unset + if isinstance(self.created_by, Unset): + created_by = UNSET + else: + created_by = self.created_by + + created_at: None | str | Unset + if isinstance(self.created_at, Unset): + created_at = UNSET + elif isinstance(self.created_at, datetime.datetime): + created_at = self.created_at.isoformat() + else: + created_at = self.created_at + + updated_at: None | str | Unset + if isinstance(self.updated_at, Unset): + updated_at = UNSET + elif isinstance(self.updated_at, datetime.datetime): + updated_at = self.updated_at.isoformat() + else: + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "text": text, + } + ) + if source is not UNSET: + field_dict["source"] = source + if memory_type is not UNSET: + field_dict["memory_type"] = memory_type + if tags is not UNSET: + field_dict["tags"] = tags + if source_ref is not UNSET: + field_dict["source_ref"] = source_ref + if provenance is not UNSET: + field_dict["provenance"] = provenance + if created_by is not UNSET: + field_dict["created_by"] = created_by + if created_at is not UNSET: + field_dict["created_at"] = created_at + if updated_at is not UNSET: + field_dict["updated_at"] = updated_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.memory_record_provenance_type_0 import MemoryRecordProvenanceType0 + + d = dict(src_dict) + id = d.pop("id") + + text = d.pop("text") + + def _parse_source(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + source = _parse_source(d.pop("source", UNSET)) + + def _parse_memory_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + memory_type = _parse_memory_type(d.pop("memory_type", UNSET)) + + def _parse_tags(data: object) -> list[str] | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + tags_type_0 = cast(list[str], data) + + return tags_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None | Unset, data) + + tags = _parse_tags(d.pop("tags", UNSET)) + + def _parse_source_ref(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + source_ref = _parse_source_ref(d.pop("source_ref", UNSET)) + + def _parse_provenance(data: object) -> MemoryRecordProvenanceType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + provenance_type_0 = MemoryRecordProvenanceType0.from_dict(data) + + return provenance_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(MemoryRecordProvenanceType0 | None | Unset, data) + + provenance = _parse_provenance(d.pop("provenance", UNSET)) + + def _parse_created_by(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + created_by = _parse_created_by(d.pop("created_by", UNSET)) + + def _parse_created_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + created_at_type_0 = isoparse(data) + + return created_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + created_at = _parse_created_at(d.pop("created_at", UNSET)) + + def _parse_updated_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + updated_at_type_0 = isoparse(data) + + return updated_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + updated_at = _parse_updated_at(d.pop("updated_at", UNSET)) + + memory_record = cls( + id=id, + text=text, + source=source, + memory_type=memory_type, + tags=tags, + source_ref=source_ref, + provenance=provenance, + created_by=created_by, + created_at=created_at, + updated_at=updated_at, + ) + + memory_record.additional_properties = d + return memory_record + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_file_response_updatefile.py b/robosystems_client/models/memory_record_provenance_type_0.py similarity index 80% rename from robosystems_client/models/update_file_response_updatefile.py rename to robosystems_client/models/memory_record_provenance_type_0.py index 21be3c2..ace1efb 100644 --- a/robosystems_client/models/update_file_response_updatefile.py +++ b/robosystems_client/models/memory_record_provenance_type_0.py @@ -6,11 +6,11 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="UpdateFileResponseUpdatefile") +T = TypeVar("T", bound="MemoryRecordProvenanceType0") @_attrs_define -class UpdateFileResponseUpdatefile: +class MemoryRecordProvenanceType0: """ """ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -25,10 +25,10 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - update_file_response_updatefile = cls() + memory_record_provenance_type_0 = cls() - update_file_response_updatefile.additional_properties = d - return update_file_response_updatefile + memory_record_provenance_type_0.additional_properties = d + return memory_record_provenance_type_0 @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/operation_envelope_change_reporting_style_response.py b/robosystems_client/models/operation_envelope_change_reporting_style_response.py new file mode 100644 index 0000000..40b83a8 --- /dev/null +++ b/robosystems_client/models/operation_envelope_change_reporting_style_response.py @@ -0,0 +1,158 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.operation_envelope_change_reporting_style_response_status import ( + OperationEnvelopeChangeReportingStyleResponseStatus, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.change_reporting_style_response import ChangeReportingStyleResponse + + +T = TypeVar("T", bound="OperationEnvelopeChangeReportingStyleResponse") + + +@_attrs_define +class OperationEnvelopeChangeReportingStyleResponse: + """ + Attributes: + operation (str): Kebab-case operation name + operation_id (str): op_-prefixed ULID for audit and SSE correlation + status (OperationEnvelopeChangeReportingStyleResponseStatus): Operation lifecycle state + at (str): ISO-8601 UTC timestamp + result (ChangeReportingStyleResponse | None | Unset): Command-specific result payload + created_by (None | str | Unset): User ID that initiated the operation (null for legacy callers) + idempotent_replay (bool | Unset): True when this envelope came from the idempotency cache — the underlying + command did not execute again. False on fresh executions. Default: False. + """ + + operation: str + operation_id: str + status: OperationEnvelopeChangeReportingStyleResponseStatus + at: str + result: ChangeReportingStyleResponse | None | Unset = UNSET + created_by: None | str | Unset = UNSET + idempotent_replay: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.change_reporting_style_response import ChangeReportingStyleResponse + + operation = self.operation + + operation_id = self.operation_id + + status = self.status.value + + at = self.at + + result: dict[str, Any] | None | Unset + if isinstance(self.result, Unset): + result = UNSET + elif isinstance(self.result, ChangeReportingStyleResponse): + result = self.result.to_dict() + else: + result = self.result + + created_by: None | str | Unset + if isinstance(self.created_by, Unset): + created_by = UNSET + else: + created_by = self.created_by + + idempotent_replay = self.idempotent_replay + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "operation": operation, + "operationId": operation_id, + "status": status, + "at": at, + } + ) + if result is not UNSET: + field_dict["result"] = result + if created_by is not UNSET: + field_dict["createdBy"] = created_by + if idempotent_replay is not UNSET: + field_dict["idempotentReplay"] = idempotent_replay + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.change_reporting_style_response import ChangeReportingStyleResponse + + d = dict(src_dict) + operation = d.pop("operation") + + operation_id = d.pop("operationId") + + status = OperationEnvelopeChangeReportingStyleResponseStatus(d.pop("status")) + + at = d.pop("at") + + def _parse_result(data: object) -> ChangeReportingStyleResponse | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + result_type_0 = ChangeReportingStyleResponse.from_dict(data) + + return result_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(ChangeReportingStyleResponse | None | Unset, data) + + result = _parse_result(d.pop("result", UNSET)) + + def _parse_created_by(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + created_by = _parse_created_by(d.pop("createdBy", UNSET)) + + idempotent_replay = d.pop("idempotentReplay", UNSET) + + operation_envelope_change_reporting_style_response = cls( + operation=operation, + operation_id=operation_id, + status=status, + at=at, + result=result, + created_by=created_by, + idempotent_replay=idempotent_replay, + ) + + operation_envelope_change_reporting_style_response.additional_properties = d + return operation_envelope_change_reporting_style_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/operation_envelope_change_reporting_style_response_status.py b/robosystems_client/models/operation_envelope_change_reporting_style_response_status.py new file mode 100644 index 0000000..b2ca0cd --- /dev/null +++ b/robosystems_client/models/operation_envelope_change_reporting_style_response_status.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class OperationEnvelopeChangeReportingStyleResponseStatus(str, Enum): + COMPLETED = "completed" + FAILED = "failed" + PENDING = "pending" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/remember_op.py b/robosystems_client/models/remember_op.py new file mode 100644 index 0000000..17403bb --- /dev/null +++ b/robosystems_client/models/remember_op.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.remember_op_provenance_type_0 import RememberOpProvenanceType0 + + +T = TypeVar("T", bound="RememberOp") + + +@_attrs_define +class RememberOp: + """Body for the remember operation (write a semantic memory). + + Attributes: + text (str): Memory content + source (str | Unset): Origin of the memory Default: 'api'. + memory_type (str | Unset): Freeform classifier Default: 'note'. + tags (list[str] | None | Unset): Optional labels + source_ref (None | str | Unset): Optional external reference/URI + provenance (None | RememberOpProvenanceType0 | Unset): Opaque provenance metadata + """ + + text: str + source: str | Unset = "api" + memory_type: str | Unset = "note" + tags: list[str] | None | Unset = UNSET + source_ref: None | str | Unset = UNSET + provenance: None | RememberOpProvenanceType0 | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.remember_op_provenance_type_0 import RememberOpProvenanceType0 + + text = self.text + + source = self.source + + memory_type = self.memory_type + + tags: list[str] | None | Unset + if isinstance(self.tags, Unset): + tags = UNSET + elif isinstance(self.tags, list): + tags = self.tags + + else: + tags = self.tags + + source_ref: None | str | Unset + if isinstance(self.source_ref, Unset): + source_ref = UNSET + else: + source_ref = self.source_ref + + provenance: dict[str, Any] | None | Unset + if isinstance(self.provenance, Unset): + provenance = UNSET + elif isinstance(self.provenance, RememberOpProvenanceType0): + provenance = self.provenance.to_dict() + else: + provenance = self.provenance + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + } + ) + if source is not UNSET: + field_dict["source"] = source + if memory_type is not UNSET: + field_dict["memory_type"] = memory_type + if tags is not UNSET: + field_dict["tags"] = tags + if source_ref is not UNSET: + field_dict["source_ref"] = source_ref + if provenance is not UNSET: + field_dict["provenance"] = provenance + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.remember_op_provenance_type_0 import RememberOpProvenanceType0 + + d = dict(src_dict) + text = d.pop("text") + + source = d.pop("source", UNSET) + + memory_type = d.pop("memory_type", UNSET) + + def _parse_tags(data: object) -> list[str] | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + tags_type_0 = cast(list[str], data) + + return tags_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None | Unset, data) + + tags = _parse_tags(d.pop("tags", UNSET)) + + def _parse_source_ref(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + source_ref = _parse_source_ref(d.pop("source_ref", UNSET)) + + def _parse_provenance(data: object) -> None | RememberOpProvenanceType0 | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + provenance_type_0 = RememberOpProvenanceType0.from_dict(data) + + return provenance_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | RememberOpProvenanceType0 | Unset, data) + + provenance = _parse_provenance(d.pop("provenance", UNSET)) + + remember_op = cls( + text=text, + source=source, + memory_type=memory_type, + tags=tags, + source_ref=source_ref, + provenance=provenance, + ) + + remember_op.additional_properties = d + return remember_op + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/cypher_query_request_parameters_type_0.py b/robosystems_client/models/remember_op_provenance_type_0.py similarity index 78% rename from robosystems_client/models/cypher_query_request_parameters_type_0.py rename to robosystems_client/models/remember_op_provenance_type_0.py index b913e7f..6c3712b 100644 --- a/robosystems_client/models/cypher_query_request_parameters_type_0.py +++ b/robosystems_client/models/remember_op_provenance_type_0.py @@ -6,11 +6,11 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="CypherQueryRequestParametersType0") +T = TypeVar("T", bound="RememberOpProvenanceType0") @_attrs_define -class CypherQueryRequestParametersType0: +class RememberOpProvenanceType0: """ """ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -25,10 +25,10 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - cypher_query_request_parameters_type_0 = cls() + remember_op_provenance_type_0 = cls() - cypher_query_request_parameters_type_0.additional_properties = d - return cypher_query_request_parameters_type_0 + remember_op_provenance_type_0.additional_properties = d + return remember_op_provenance_type_0 @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/table_query_request.py b/robosystems_client/models/sql_statement_request.py similarity index 80% rename from robosystems_client/models/table_query_request.py rename to robosystems_client/models/sql_statement_request.py index bc87a1c..54ff066 100644 --- a/robosystems_client/models/table_query_request.py +++ b/robosystems_client/models/sql_statement_request.py @@ -7,15 +7,16 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="TableQueryRequest") +T = TypeVar("T", bound="SqlStatementRequest") @_attrs_define -class TableQueryRequest: +class SqlStatementRequest: """ Attributes: - sql (str): SQL query to execute on staging tables. Use ? placeholders or $param_name for dynamic values to - prevent SQL injection. + sql (str): SQL query over the graph's columnar tables (DuckDB) — a relational lens on the same graph-centric + data, often ahead of the materialized graph. Use ? placeholders or $param_name for dynamic values to prevent SQL + injection. parameters (list[Any] | None | Unset): Query parameters for safe value substitution. ALWAYS use parameters instead of string concatenation. """ @@ -69,9 +70,9 @@ def _parse_parameters(data: object) -> list[Any] | None | Unset: parameters = _parse_parameters(d.pop("parameters", UNSET)) - table_query_request = cls( + sql_statement_request = cls( sql=sql, parameters=parameters, ) - return table_query_request + return sql_statement_request diff --git a/robosystems_client/models/table_query_response.py b/robosystems_client/models/sql_statement_response.py similarity index 91% rename from robosystems_client/models/table_query_response.py rename to robosystems_client/models/sql_statement_response.py index 6ae9f31..89e22b9 100644 --- a/robosystems_client/models/table_query_response.py +++ b/robosystems_client/models/sql_statement_response.py @@ -6,11 +6,11 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="TableQueryResponse") +T = TypeVar("T", bound="SqlStatementResponse") @_attrs_define -class TableQueryResponse: +class SqlStatementResponse: """ Attributes: columns (list[str]): Column names @@ -67,15 +67,15 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: execution_time_ms = d.pop("execution_time_ms") - table_query_response = cls( + sql_statement_response = cls( columns=columns, rows=rows, row_count=row_count, execution_time_ms=execution_time_ms, ) - table_query_response.additional_properties = d - return table_query_response + sql_statement_response.additional_properties = d + return sql_statement_response @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/update_memory_op.py b/robosystems_client/models/update_memory_op.py new file mode 100644 index 0000000..1681040 --- /dev/null +++ b/robosystems_client/models/update_memory_op.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.update_memory_op_provenance_type_0 import UpdateMemoryOpProvenanceType0 + + +T = TypeVar("T", bound="UpdateMemoryOp") + + +@_attrs_define +class UpdateMemoryOp: + """Body for the update-memory operation (partial update of a stored memory). + + Only supplied fields are changed; the memory is re-embedded when ``text`` + changes. + + Attributes: + memory_id (str): Server-generated memory id to update + text (None | str | Unset): New memory content + memory_type (None | str | Unset): Freeform classifier + tags (list[str] | None | Unset): Optional labels + source_ref (None | str | Unset): Optional external reference/URI + provenance (None | Unset | UpdateMemoryOpProvenanceType0): Opaque provenance metadata + """ + + memory_id: str + text: None | str | Unset = UNSET + memory_type: None | str | Unset = UNSET + tags: list[str] | None | Unset = UNSET + source_ref: None | str | Unset = UNSET + provenance: None | Unset | UpdateMemoryOpProvenanceType0 = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.update_memory_op_provenance_type_0 import ( + UpdateMemoryOpProvenanceType0, + ) + + memory_id = self.memory_id + + text: None | str | Unset + if isinstance(self.text, Unset): + text = UNSET + else: + text = self.text + + memory_type: None | str | Unset + if isinstance(self.memory_type, Unset): + memory_type = UNSET + else: + memory_type = self.memory_type + + tags: list[str] | None | Unset + if isinstance(self.tags, Unset): + tags = UNSET + elif isinstance(self.tags, list): + tags = self.tags + + else: + tags = self.tags + + source_ref: None | str | Unset + if isinstance(self.source_ref, Unset): + source_ref = UNSET + else: + source_ref = self.source_ref + + provenance: dict[str, Any] | None | Unset + if isinstance(self.provenance, Unset): + provenance = UNSET + elif isinstance(self.provenance, UpdateMemoryOpProvenanceType0): + provenance = self.provenance.to_dict() + else: + provenance = self.provenance + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "memory_id": memory_id, + } + ) + if text is not UNSET: + field_dict["text"] = text + if memory_type is not UNSET: + field_dict["memory_type"] = memory_type + if tags is not UNSET: + field_dict["tags"] = tags + if source_ref is not UNSET: + field_dict["source_ref"] = source_ref + if provenance is not UNSET: + field_dict["provenance"] = provenance + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.update_memory_op_provenance_type_0 import ( + UpdateMemoryOpProvenanceType0, + ) + + d = dict(src_dict) + memory_id = d.pop("memory_id") + + def _parse_text(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + text = _parse_text(d.pop("text", UNSET)) + + def _parse_memory_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + memory_type = _parse_memory_type(d.pop("memory_type", UNSET)) + + def _parse_tags(data: object) -> list[str] | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + tags_type_0 = cast(list[str], data) + + return tags_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None | Unset, data) + + tags = _parse_tags(d.pop("tags", UNSET)) + + def _parse_source_ref(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + source_ref = _parse_source_ref(d.pop("source_ref", UNSET)) + + def _parse_provenance(data: object) -> None | Unset | UpdateMemoryOpProvenanceType0: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + provenance_type_0 = UpdateMemoryOpProvenanceType0.from_dict(data) + + return provenance_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | Unset | UpdateMemoryOpProvenanceType0, data) + + provenance = _parse_provenance(d.pop("provenance", UNSET)) + + update_memory_op = cls( + memory_id=memory_id, + text=text, + memory_type=memory_type, + tags=tags, + source_ref=source_ref, + provenance=provenance, + ) + + update_memory_op.additional_properties = d + return update_memory_op + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_memory_op_provenance_type_0.py b/robosystems_client/models/update_memory_op_provenance_type_0.py new file mode 100644 index 0000000..c97e47c --- /dev/null +++ b/robosystems_client/models/update_memory_op_provenance_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateMemoryOpProvenanceType0") + + +@_attrs_define +class UpdateMemoryOpProvenanceType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_memory_op_provenance_type_0 = cls() + + update_memory_op_provenance_type_0.additional_properties = d + return update_memory_op_provenance_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/tests/test_document_client.py b/tests/test_document_client.py index 3530bee..88f3088 100644 --- a/tests/test_document_client.py +++ b/tests/test_document_client.py @@ -44,12 +44,12 @@ def test_close_is_noop(self, mock_config): class TestDocumentUpload: """Test suite for DocumentClient.upload method.""" - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_document(self, mock_upload, mock_config, graph_id): """Test uploading a markdown document.""" mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-123", section_count=3) + mock_resp.parsed = Mock(result={"document_id": "doc-123", "section_count": 3}) mock_upload.return_value = mock_resp client = DocumentClient(mock_config) @@ -61,11 +61,11 @@ def test_upload_document(self, mock_upload, mock_config, graph_id): folder="reports", ) - assert result.document_id == "doc-123" - assert result.section_count == 3 + assert result.result["document_id"] == "doc-123" + assert result.result["section_count"] == 3 mock_upload.assert_called_once() - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_document_failure(self, mock_upload, mock_config, graph_id): """Test upload failure raises exception.""" mock_resp = Mock() @@ -78,18 +78,18 @@ def test_upload_document_failure(self, mock_upload, mock_config, graph_id): with pytest.raises(Exception, match="Document upload failed"): client.upload(graph_id=graph_id, title="Bad", content="content") - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_minimal(self, mock_upload, mock_config, graph_id): """Test upload with only required fields.""" mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-min", section_count=1) + mock_resp.parsed = Mock(result={"document_id": "doc-min", "section_count": 1}) mock_upload.return_value = mock_resp client = DocumentClient(mock_config) result = client.upload(graph_id=graph_id, title="Minimal", content="Just text.") - assert result.document_id == "doc-min" + assert result.result["document_id"] == "doc-min" @pytest.mark.unit @@ -142,12 +142,12 @@ def test_get_document_server_error(self, mock_get, mock_config, graph_id): class TestDocumentUpdate: """Test suite for DocumentClient.update method.""" - @patch("robosystems_client.clients.document_client.update_document") + @patch("robosystems_client.clients.document_client.index_document") def test_update_document(self, mock_update, mock_config, graph_id): """Test updating a document.""" mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-upd", section_count=5) + mock_resp.parsed = Mock(result={"document_id": "doc-upd", "section_count": 5}) mock_update.return_value = mock_resp client = DocumentClient(mock_config) @@ -158,9 +158,9 @@ def test_update_document(self, mock_update, mock_config, graph_id): content="# Updated\n\nNew content.", ) - assert result.section_count == 5 + assert result.result["section_count"] == 5 - @patch("robosystems_client.clients.document_client.update_document") + @patch("robosystems_client.clients.document_client.index_document") def test_update_document_failure(self, mock_update, mock_config, graph_id): """Test update failure raises exception.""" mock_resp = Mock() @@ -338,7 +338,7 @@ def test_get_section_not_found(self, mock_get_section, mock_config, graph_id): class TestDocumentUploadFile: """Test suite for DocumentClient.upload_file method.""" - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_file(self, mock_upload, mock_config, graph_id, tmp_path): """Test uploading a file from disk.""" md_file = tmp_path / "test-doc.md" @@ -346,15 +346,15 @@ def test_upload_file(self, mock_upload, mock_config, graph_id, tmp_path): mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-file", section_count=2) + mock_resp.parsed = Mock(result={"document_id": "doc-file", "section_count": 2}) mock_upload.return_value = mock_resp client = DocumentClient(mock_config) result = client.upload_file(graph_id=graph_id, file_path=md_file) - assert result.document_id == "doc-file" + assert result.result["document_id"] == "doc-file" - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_file_title_from_filename( self, mock_upload, mock_config, graph_id, tmp_path ): @@ -364,7 +364,7 @@ def test_upload_file_title_from_filename( mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-title", section_count=1) + mock_resp.parsed = Mock(result={"document_id": "doc-title", "section_count": 1}) mock_upload.return_value = mock_resp client = DocumentClient(mock_config) @@ -379,7 +379,7 @@ def test_upload_file_title_from_filename( class TestDocumentUploadDirectory: """Test suite for DocumentClient.upload_directory method.""" - @patch("robosystems_client.clients.document_client.upload_document") + @patch("robosystems_client.clients.document_client.index_document") def test_upload_directory(self, mock_upload, mock_config, graph_id, tmp_path): """Test uploading all markdown files from a directory.""" (tmp_path / "doc1.md").write_text("# Doc 1") @@ -388,7 +388,7 @@ def test_upload_directory(self, mock_upload, mock_config, graph_id, tmp_path): mock_resp = Mock() mock_resp.status_code = HTTPStatus.OK - mock_resp.parsed = Mock(document_id="doc-dir", section_count=1) + mock_resp.parsed = Mock(result={"document_id": "doc-dir", "section_count": 1}) mock_upload.return_value = mock_resp client = DocumentClient(mock_config) diff --git a/tests/test_extensions_integration.py b/tests/test_extensions_integration.py index 56fe8dc..742225b 100644 --- a/tests/test_extensions_integration.py +++ b/tests/test_extensions_integration.py @@ -71,7 +71,7 @@ def test_create_clients_factory(self, mock_api_key): ) assert ext.config["headers"]["Authorization"] == "Bearer jwt_token_here" - @patch("robosystems_client.api.query.execute_cypher_query.sync_detailed") + @patch("robosystems_client.api.query.execute_cypher.sync_detailed") def test_cypher_query_execution(self, mock_sync_detailed, extensions): """Test executing Cypher queries through authenticated client""" # Mock the response diff --git a/tests/test_file_client.py b/tests/test_file_client.py index cee6d09..6aa4cf6 100644 --- a/tests/test_file_client.py +++ b/tests/test_file_client.py @@ -137,24 +137,25 @@ def test_file_info_with_layers(self): class TestFileUpload: """Test suite for FileClient.upload method.""" - @patch("robosystems_client.clients.file_client.update_file") + @patch("robosystems_client.clients.file_client.ingest_file") @patch("robosystems_client.clients.file_client.create_file_upload") def test_upload_bytesio(self, mock_create, mock_update, mock_config, graph_id): """Test uploading a BytesIO buffer.""" # Mock presigned URL response mock_create_resp = Mock() mock_create_resp.status_code = 200 - mock_create_resp.parsed = Mock() - mock_create_resp.parsed.upload_url = "http://s3.localhost/bucket/file.parquet" - mock_create_resp.parsed.file_id = "file-new-123" + mock_create_resp.parsed = Mock( + result={ + "upload_url": "http://s3.localhost/bucket/file.parquet", + "file_id": "file-new-123", + } + ) mock_create.return_value = mock_create_resp # Mock update response mock_update_resp = Mock() mock_update_resp.status_code = 200 - mock_update_resp.parsed = Mock() - mock_update_resp.parsed.file_size_bytes = 1234 - mock_update_resp.parsed.row_count = 10 + mock_update_resp.parsed = Mock(result={"file_size_bytes": 1234, "row_count": 10}) mock_update.return_value = mock_update_resp client = FileClient(mock_config) @@ -190,9 +191,12 @@ def test_upload_s3_failure(self, mock_create, mock_config, graph_id): """Test upload failure when S3 PUT fails.""" mock_create_resp = Mock() mock_create_resp.status_code = 200 - mock_create_resp.parsed = Mock() - mock_create_resp.parsed.upload_url = "http://s3.localhost/bucket/file.parquet" - mock_create_resp.parsed.file_id = "file-s3-fail" + mock_create_resp.parsed = Mock( + result={ + "upload_url": "http://s3.localhost/bucket/file.parquet", + "file_id": "file-s3-fail", + } + ) mock_create.return_value = mock_create_resp client = FileClient(mock_config) @@ -204,7 +208,7 @@ def test_upload_s3_failure(self, mock_create, mock_config, graph_id): assert result.success is False assert "S3 upload failed" in result.error - @patch("robosystems_client.clients.file_client.update_file") + @patch("robosystems_client.clients.file_client.ingest_file") @patch("robosystems_client.clients.file_client.create_file_upload") def test_upload_status_update_failure( self, mock_create, mock_update, mock_config, graph_id @@ -212,9 +216,12 @@ def test_upload_status_update_failure( """Test upload failure when status update fails.""" mock_create_resp = Mock() mock_create_resp.status_code = 200 - mock_create_resp.parsed = Mock() - mock_create_resp.parsed.upload_url = "http://s3.localhost/bucket/file.parquet" - mock_create_resp.parsed.file_id = "file-update-fail" + mock_create_resp.parsed = Mock( + result={ + "upload_url": "http://s3.localhost/bucket/file.parquet", + "file_id": "file-update-fail", + } + ) mock_create.return_value = mock_create_resp mock_update_resp = Mock() @@ -250,7 +257,7 @@ def test_upload_unsupported_type(self, mock_config, graph_id): assert result.success is False assert "Unsupported file type" in result.error - @patch("robosystems_client.clients.file_client.update_file") + @patch("robosystems_client.clients.file_client.ingest_file") @patch("robosystems_client.clients.file_client.create_file_upload") def test_upload_with_progress_callback( self, mock_create, mock_update, mock_config, graph_id @@ -258,16 +265,17 @@ def test_upload_with_progress_callback( """Test upload calls progress callback at each step.""" mock_create_resp = Mock() mock_create_resp.status_code = 200 - mock_create_resp.parsed = Mock() - mock_create_resp.parsed.upload_url = "http://s3.localhost/bucket/file.parquet" - mock_create_resp.parsed.file_id = "file-progress" + mock_create_resp.parsed = Mock( + result={ + "upload_url": "http://s3.localhost/bucket/file.parquet", + "file_id": "file-progress", + } + ) mock_create.return_value = mock_create_resp mock_update_resp = Mock() mock_update_resp.status_code = 200 - mock_update_resp.parsed = Mock() - mock_update_resp.parsed.file_size_bytes = 100 - mock_update_resp.parsed.row_count = 5 + mock_update_resp.parsed = Mock(result={"file_size_bytes": 100, "row_count": 5}) mock_update.return_value = mock_update_resp client = FileClient(mock_config) @@ -281,7 +289,7 @@ def test_upload_with_progress_callback( assert len(progress_messages) >= 3 # URL, upload, mark uploaded - @patch("robosystems_client.clients.file_client.update_file") + @patch("robosystems_client.clients.file_client.ingest_file") @patch("robosystems_client.clients.file_client.create_file_upload") def test_upload_with_s3_endpoint_override( self, mock_create, mock_update, mock_config, graph_id @@ -291,18 +299,17 @@ def test_upload_with_s3_endpoint_override( mock_create_resp = Mock() mock_create_resp.status_code = 200 - mock_create_resp.parsed = Mock() - mock_create_resp.parsed.upload_url = ( - "https://s3.amazonaws.com/bucket/file.parquet?sig=abc" + mock_create_resp.parsed = Mock( + result={ + "upload_url": "https://s3.amazonaws.com/bucket/file.parquet?sig=abc", + "file_id": "file-s3-override", + } ) - mock_create_resp.parsed.file_id = "file-s3-override" mock_create.return_value = mock_create_resp mock_update_resp = Mock() mock_update_resp.status_code = 200 - mock_update_resp.parsed = Mock() - mock_update_resp.parsed.file_size_bytes = 100 - mock_update_resp.parsed.row_count = 5 + mock_update_resp.parsed = Mock(result={"file_size_bytes": 100, "row_count": 5}) mock_update.return_value = mock_update_resp client = FileClient(mock_config) @@ -455,4 +462,4 @@ def test_delete_file_with_cascade(self, mock_delete, mock_config, graph_id): assert result is True call_kwargs = mock_delete.call_args[1] - assert call_kwargs["cascade"] is True + assert call_kwargs["body"].cascade is True