# DO NOT EDIT — generated by _gen/ from the OpenAPI spec.
# Regenerate with: ./client_gen.sh
from __future__ import annotations

from typing import Any

import httpx

from goodmem._base import _op_meta, _expand_label_filters
from goodmem._base import _op_meta, _prepare_create_payload
from goodmem.errors import raise_for_status
from goodmem.models.chunking_configuration import ChunkingConfiguration
from goodmem.models.list_spaces_response import ListSpacesResponse
from goodmem.models.sort_order import SortOrder
from goodmem.models.space import Space
from goodmem.models.space_creation_request import SpaceCreationRequest
from goodmem.models.update_space_request import UpdateSpaceRequest
from goodmem.pagination import AsyncPage, Page


class SpacesAPIBase:
    """Spaces API — auto-generated structural base.

    Auto-generated structural base. Do not edit.
    Override in goodmem/api/spaces.py to add domain-specific logic.
    """

    _create_model = SpaceCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/spaces', 'input_shape': 'kwargs_body', 'summary': 'Create a new Space', 'description': 'Creates a new space with the provided name, labels, and embedder configuration. A space is a container for organizing related memories. OWNER DEFAULTS: Owner defaults to authenticated user unless ownerId is provided (requires CREATE_SPACE_ANY if differs). EMBEDDER DEFAULTS: If no embedders are specified, a system-default embedder is attached. DUPLICATE DETECTION: Returns ALREADY_EXISTS if another space exists with identical {ownerId, name} (case-sensitive). Requires CREATE_SPACE_OWN permission (or CREATE_SPACE_ANY for admin users). This operation is NOT idempotent.', 'response': 'Space', 'params': [{'name': 'name', 'type': 'str', 'source': 'body', 'required': True, 'description': "The desired name for the space. Must be unique within the user's scope."}, {'name': 'labels', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.'}, {'name': 'space_embedders', 'type': 'list[SpaceEmbedderConfig]', 'source': 'body', 'required': True, 'alias': 'spaceEmbedders', 'description': 'List of embedder configurations to associate with this space. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided.'}, {'name': 'public_read', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'publicRead', 'description': 'Indicates if the space and its memories can be read by unauthenticated users or users other than the owner. Defaults to false.', 'default': False}, {'name': 'owner_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'ownerId', 'description': 'Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.'}, {'name': 'default_chunking_config', 'type': 'ChunkingConfiguration', 'source': 'body', 'required': True, 'alias': 'defaultChunkingConfig', 'description': 'Default chunking strategy for memories in this space'}, {'name': 'space_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'spaceId', 'description': 'Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.'}], 'body_model': 'SpaceCreationRequest', 'body_expr': 'SpaceCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'get': {'http_method': 'GET', 'path': '/v1/spaces/{id}', 'input_shape': 'path_query', 'summary': 'Get a space by ID', 'description': 'Retrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata. PUBLIC SPACE ACCESS: When public_read=true, any authenticated user can retrieve the space metadata, bypassing ownership checks. Otherwise, requires ownership or DISPLAY_SPACE_ANY permission. Requires DISPLAY_SPACE_OWN permission for owned spaces (or DISPLAY_SPACE_ANY for admin users to view any space). This is a read-only operation safe to retry.', 'response': 'Space', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to retrieve'}]}, 'list': {'http_method': 'GET', 'path': '/v1/spaces', 'input_shape': 'query_only', 'summary': 'List spaces', 'description': 'Retrieves a list of spaces accessible to the caller, with optional filtering by owner, labels, and name. Results are paginated with a maximum number of spaces per response. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.project=AI). PERMISSION-BASED FILTERING: With LIST_SPACE_ANY and ownerId omitted, returns all visible spaces; otherwise returns caller-owned spaces only. DEFAULT SORT: Results ordered by created_at DESCENDING unless specified otherwise. MAX_RESULTS CLAMPING: maxResults defaults to 50 and is clamped to [1, 1000] range. Requires LIST_SPACE_OWN or LIST_SPACE_ANY permission.', 'response': 'ListSpacesResponse', 'query_params': ['owner_id', 'name_filter', 'max_results', 'next_token', 'sort_by', 'sort_order', 'label.*'], 'params': [{'name': 'owner_id', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'ownerId', 'description': 'Filter spaces by owner ID. With LIST_SPACE_ANY permission and ownerId omitted, returns all visible spaces. Otherwise returns caller-owned spaces only. Specifying ownerId without LIST_SPACE_ANY returns PERMISSION_DENIED.'}, {'name': 'name_filter', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nameFilter', 'description': 'Filter spaces by name using glob pattern matching'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results to return in a single page (defaults to 50, clamped to [1, 1000])', 'default': 50}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Pagination token for retrieving the next set of results'}, {'name': 'sort_by', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'sortBy', 'description': "Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.", 'default': 'created_time', 'enum': ['created_time', 'updated_time', 'name']}, {'name': 'sort_order', 'type': 'SortOrder', 'source': 'query', 'required': False, 'alias': 'sortOrder', 'description': 'Sort order (ASCENDING or DESCENDING, default: DESCENDING)', 'default': 'DESCENDING'}, {'name': 'label.*', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Filter by label value. Multiple label filters can be specified (e.g., ?label.project=AI&label.team=NLP)'}], 'auto_next_token': True, 'supports_label_wildcard': True}, 'update': {'http_method': 'PUT', 'path': '/v1/spaces/{id}', 'input_shape': 'typed_request', 'summary': 'Update a space', 'description': 'Updates an existing space with new values for the specified fields. Only name, publicRead, and labels can be updated. Fields not included in the request remain unchanged. IMMUTABLE FIELDS: space_embedders, default_chunking_config, and ownerId cannot be modified after creation. NAME UNIQUENESS: Name must be unique per owner - returns ALREADY_EXISTS if name conflicts with existing space. Requires UPDATE_SPACE_OWN permission for spaces you own (or UPDATE_SPACE_ANY for admin users). This operation is idempotent.', 'response': 'Space', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to update'}, {'name': 'name', 'type': 'str', 'source': 'body', 'required': False, 'description': 'The new name for the space.'}, {'name': 'public_read', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'publicRead', 'description': 'Whether the space is publicly readable by all users.'}, {'name': 'replace_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'replaceLabels', 'description': 'Labels to replace all existing labels. Mutually exclusive with mergeLabels.'}, {'name': 'merge_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'mergeLabels', 'description': 'Labels to merge with existing labels. Mutually exclusive with replaceLabels.'}], 'body_model': 'UpdateSpaceRequest', 'body_expr': 'UpdateSpaceRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'delete': {'http_method': 'DELETE', 'path': '/v1/spaces/{id}', 'input_shape': 'path_query', 'summary': 'Delete a space', 'description': 'Permanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires DELETE_SPACE_OWN permission for spaces you own (or DELETE_SPACE_ANY for admin users). This operation is safe to retry - may return NOT_FOUND if already deleted.', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to delete'}]}}

    def __init__(self, http: httpx.Client, headers: dict[str, str]) -> None:
        self._http = http
        self._headers = headers

    def create(self, *, name: str | None=None, labels: dict | None=None, space_embedders: list | None=None, public_read: bool | None=False, owner_id: str | None=None, default_chunking_config: ChunkingConfiguration | None=None, space_id: str | None=None) -> Space:
        """Create a new Space

        Creates a new space with the provided name, labels, and embedder configuration. A space is a container for organizing related memories. OWNER DEFAULTS: Owner defaults to authenticated user unless owner_id is provided (requires CREATE_SPACE_ANY if differs). EMBEDDER DEFAULTS: If no embedders are specified, a system-default embedder is attached. DUPLICATE DETECTION: Returns ALREADY_EXISTS if another space exists with identical {owner_id, name} (case-sensitive). Requires CREATE_SPACE_OWN permission (or CREATE_SPACE_ANY for admin users). This operation is NOT idempotent.

        Args:
            name (str): The desired name for the space. Must be unique within the user's scope.
            labels (dict, optional): A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.
            space_embedders (list): List of embedder configurations to associate with this space. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided.
            public_read (bool, optional, default=False): Indicates if the space and its memories can be read by unauthenticated users or users other than the owner. Defaults to false.
            owner_id (str, optional): Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.
            default_chunking_config (ChunkingConfiguration): Default chunking strategy for memories in this space
            space_id (str, optional): Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.

        Returns:
            Space
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if name is not None:
            _params['name'] = name
        if labels is not None:
            _params['labels'] = labels
        if space_embedders is not None:
            _params['space_embedders'] = space_embedders
        _params['public_read'] = public_read
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if default_chunking_config is not None:
            _params['default_chunking_config'] = default_chunking_config
        if space_id is not None:
            _params['space_id'] = space_id
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=SpaceCreationRequest, op=op, kwargs=_params,
        )
        resp = self._http.post(
            "/v1/spaces",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    def list(self, *, labels: dict[str, str] | None = None, owner_id: str | None=None, name_filter: str | None=None, max_results: int | None=50, next_token: str | None=None, sort_by: str | None='created_time', sort_order: SortOrder | None='DESCENDING') -> Page[Space]:
        """List spaces

        Retrieves a list of spaces accessible to the caller, with optional filtering by owner, labels, and name. Results are paginated with a maximum number of spaces per response. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.project=AI). PERMISSION-BASED FILTERING: With LIST_SPACE_ANY and owner_id omitted, returns all visible spaces; otherwise returns caller-owned spaces only. DEFAULT SORT: Results ordered by created_at DESCENDING unless specified otherwise. MAX_RESULTS CLAMPING: max_results defaults to 50 and is clamped to [1, 1000] range. Requires LIST_SPACE_OWN or LIST_SPACE_ANY permission.

        Args:
            owner_id (str, optional): Filter spaces by owner ID. With LIST_SPACE_ANY permission and owner_id omitted, returns all visible spaces. Otherwise returns caller-owned spaces only. Specifying owner_id without LIST_SPACE_ANY returns PERMISSION_DENIED.
            name_filter (str, optional): Filter spaces by name using glob pattern matching
            max_results (int, optional, default=50): Maximum number of results to return in a single page (defaults to 50, clamped to [1, 1000])
            next_token (str, optional): Pagination token for retrieving the next set of results
            sort_by (str, optional, default='created_time'): Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.
            sort_order (SortOrder, optional, default='DESCENDING'): Sort order (ASCENDING or DESCENDING, default: DESCENDING)
            label.* (str, optional): Filter by label value. Multiple label filters can be specified (e.g., ?label.project=AI&label.team=NLP)

        Returns:
            Page[Space]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if name_filter is not None:
            _params['name_filter'] = name_filter
        _params['max_results'] = max_results
        if next_token is not None:
            _params['next_token'] = next_token
        _params['sort_by'] = sort_by
        _params['sort_order'] = sort_order
        params = _expand_label_filters(op=op, labels=labels, params=_params)
        _resp = self._http.get(
            "/v1/spaces",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = ListSpacesResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            "/v1/spaces",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return Page(
            data=getattr(_page_obj, 'spaces', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=ListSpacesResponse,
            items_field='spaces',
        )

    def get(self, *, id: str) -> Space:
        """Get a space by ID

        Retrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata. PUBLIC SPACE ACCESS: When public_read=true, any authenticated user can retrieve the space metadata, bypassing ownership checks. Otherwise, requires ownership or DISPLAY_SPACE_ANY permission. Requires DISPLAY_SPACE_OWN permission for owned spaces (or DISPLAY_SPACE_ANY for admin users to view any space). This is a read-only operation safe to retry.

        Args:
            id (str): The unique identifier of the space to retrieve

        Returns:
            Space
        """
        resp = self._http.get(
            f"/v1/spaces/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    def update(self, *, id: str, request: UpdateSpaceRequest | dict) -> Space:
        """Update a space

        Updates an existing space with new values for the specified fields. Only name, public_read, and labels can be updated. Fields not included in the request remain unchanged. IMMUTABLE FIELDS: space_embedders, default_chunking_config, and owner_id cannot be modified after creation. NAME UNIQUENESS: Name must be unique per owner - returns ALREADY_EXISTS if name conflicts with existing space. Requires UPDATE_SPACE_OWN permission for spaces you own (or UPDATE_SPACE_ANY for admin users). This operation is idempotent.

        Args:
            id (str): The unique identifier of the space to update.
            request (UpdateSpaceRequest | dict): The update payload. Accepts a UpdateSpaceRequest instance or a plain dict with the same fields. Only specified fields will be modified.

        Returns:
            Space
        """
        if isinstance(request, dict):
            request = UpdateSpaceRequest.model_validate(request)
        resp = self._http.put(
            f"/v1/spaces/{id}",
            json=request.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    def delete(self, *, id: str) -> None:
        """Delete a space

        Permanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires DELETE_SPACE_OWN permission for spaces you own (or DELETE_SPACE_ANY for admin users). This operation is safe to retry - may return NOT_FOUND if already deleted.

        Args:
            id (str): The unique identifier of the space to delete
        """
        resp = self._http.delete(
            f"/v1/spaces/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)


class AsyncSpacesAPIBase:
    """Async Spaces API — auto-generated structural base.

    Auto-generated structural base. Do not edit.
    Override in goodmem/api/spaces.py to add domain-specific logic.
    """

    _create_model = SpaceCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/spaces', 'input_shape': 'kwargs_body', 'summary': 'Create a new Space', 'description': 'Creates a new space with the provided name, labels, and embedder configuration. A space is a container for organizing related memories. OWNER DEFAULTS: Owner defaults to authenticated user unless ownerId is provided (requires CREATE_SPACE_ANY if differs). EMBEDDER DEFAULTS: If no embedders are specified, a system-default embedder is attached. DUPLICATE DETECTION: Returns ALREADY_EXISTS if another space exists with identical {ownerId, name} (case-sensitive). Requires CREATE_SPACE_OWN permission (or CREATE_SPACE_ANY for admin users). This operation is NOT idempotent.', 'response': 'Space', 'params': [{'name': 'name', 'type': 'str', 'source': 'body', 'required': True, 'description': "The desired name for the space. Must be unique within the user's scope."}, {'name': 'labels', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.'}, {'name': 'space_embedders', 'type': 'list[SpaceEmbedderConfig]', 'source': 'body', 'required': True, 'alias': 'spaceEmbedders', 'description': 'List of embedder configurations to associate with this space. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided.'}, {'name': 'public_read', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'publicRead', 'description': 'Indicates if the space and its memories can be read by unauthenticated users or users other than the owner. Defaults to false.', 'default': False}, {'name': 'owner_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'ownerId', 'description': 'Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.'}, {'name': 'default_chunking_config', 'type': 'ChunkingConfiguration', 'source': 'body', 'required': True, 'alias': 'defaultChunkingConfig', 'description': 'Default chunking strategy for memories in this space'}, {'name': 'space_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'spaceId', 'description': 'Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.'}], 'body_model': 'SpaceCreationRequest', 'body_expr': 'SpaceCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'get': {'http_method': 'GET', 'path': '/v1/spaces/{id}', 'input_shape': 'path_query', 'summary': 'Get a space by ID', 'description': 'Retrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata. PUBLIC SPACE ACCESS: When public_read=true, any authenticated user can retrieve the space metadata, bypassing ownership checks. Otherwise, requires ownership or DISPLAY_SPACE_ANY permission. Requires DISPLAY_SPACE_OWN permission for owned spaces (or DISPLAY_SPACE_ANY for admin users to view any space). This is a read-only operation safe to retry.', 'response': 'Space', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to retrieve'}]}, 'list': {'http_method': 'GET', 'path': '/v1/spaces', 'input_shape': 'query_only', 'summary': 'List spaces', 'description': 'Retrieves a list of spaces accessible to the caller, with optional filtering by owner, labels, and name. Results are paginated with a maximum number of spaces per response. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.project=AI). PERMISSION-BASED FILTERING: With LIST_SPACE_ANY and ownerId omitted, returns all visible spaces; otherwise returns caller-owned spaces only. DEFAULT SORT: Results ordered by created_at DESCENDING unless specified otherwise. MAX_RESULTS CLAMPING: maxResults defaults to 50 and is clamped to [1, 1000] range. Requires LIST_SPACE_OWN or LIST_SPACE_ANY permission.', 'response': 'ListSpacesResponse', 'query_params': ['owner_id', 'name_filter', 'max_results', 'next_token', 'sort_by', 'sort_order', 'label.*'], 'params': [{'name': 'owner_id', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'ownerId', 'description': 'Filter spaces by owner ID. With LIST_SPACE_ANY permission and ownerId omitted, returns all visible spaces. Otherwise returns caller-owned spaces only. Specifying ownerId without LIST_SPACE_ANY returns PERMISSION_DENIED.'}, {'name': 'name_filter', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nameFilter', 'description': 'Filter spaces by name using glob pattern matching'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results to return in a single page (defaults to 50, clamped to [1, 1000])', 'default': 50}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Pagination token for retrieving the next set of results'}, {'name': 'sort_by', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'sortBy', 'description': "Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.", 'default': 'created_time', 'enum': ['created_time', 'updated_time', 'name']}, {'name': 'sort_order', 'type': 'SortOrder', 'source': 'query', 'required': False, 'alias': 'sortOrder', 'description': 'Sort order (ASCENDING or DESCENDING, default: DESCENDING)', 'default': 'DESCENDING'}, {'name': 'label.*', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Filter by label value. Multiple label filters can be specified (e.g., ?label.project=AI&label.team=NLP)'}], 'auto_next_token': True, 'supports_label_wildcard': True}, 'update': {'http_method': 'PUT', 'path': '/v1/spaces/{id}', 'input_shape': 'typed_request', 'summary': 'Update a space', 'description': 'Updates an existing space with new values for the specified fields. Only name, publicRead, and labels can be updated. Fields not included in the request remain unchanged. IMMUTABLE FIELDS: space_embedders, default_chunking_config, and ownerId cannot be modified after creation. NAME UNIQUENESS: Name must be unique per owner - returns ALREADY_EXISTS if name conflicts with existing space. Requires UPDATE_SPACE_OWN permission for spaces you own (or UPDATE_SPACE_ANY for admin users). This operation is idempotent.', 'response': 'Space', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to update'}, {'name': 'name', 'type': 'str', 'source': 'body', 'required': False, 'description': 'The new name for the space.'}, {'name': 'public_read', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'publicRead', 'description': 'Whether the space is publicly readable by all users.'}, {'name': 'replace_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'replaceLabels', 'description': 'Labels to replace all existing labels. Mutually exclusive with mergeLabels.'}, {'name': 'merge_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'mergeLabels', 'description': 'Labels to merge with existing labels. Mutually exclusive with replaceLabels.'}], 'body_model': 'UpdateSpaceRequest', 'body_expr': 'UpdateSpaceRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'delete': {'http_method': 'DELETE', 'path': '/v1/spaces/{id}', 'input_shape': 'path_query', 'summary': 'Delete a space', 'description': 'Permanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires DELETE_SPACE_OWN permission for spaces you own (or DELETE_SPACE_ANY for admin users). This operation is safe to retry - may return NOT_FOUND if already deleted.', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the space to delete'}]}}

    def __init__(self, http: httpx.AsyncClient, headers: dict[str, str]) -> None:
        self._http = http
        self._headers = headers

    async def create(self, *, name: str | None=None, labels: dict | None=None, space_embedders: list | None=None, public_read: bool | None=False, owner_id: str | None=None, default_chunking_config: ChunkingConfiguration | None=None, space_id: str | None=None) -> Space:
        """Create a new Space

        Creates a new space with the provided name, labels, and embedder configuration. A space is a container for organizing related memories. OWNER DEFAULTS: Owner defaults to authenticated user unless owner_id is provided (requires CREATE_SPACE_ANY if differs). EMBEDDER DEFAULTS: If no embedders are specified, a system-default embedder is attached. DUPLICATE DETECTION: Returns ALREADY_EXISTS if another space exists with identical {owner_id, name} (case-sensitive). Requires CREATE_SPACE_OWN permission (or CREATE_SPACE_ANY for admin users). This operation is NOT idempotent.

        Args:
            name (str): The desired name for the space. Must be unique within the user's scope.
            labels (dict, optional): A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.
            space_embedders (list): List of embedder configurations to associate with this space. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided.
            public_read (bool, optional, default=False): Indicates if the space and its memories can be read by unauthenticated users or users other than the owner. Defaults to false.
            owner_id (str, optional): Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.
            default_chunking_config (ChunkingConfiguration): Default chunking strategy for memories in this space
            space_id (str, optional): Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.

        Returns:
            Space
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if name is not None:
            _params['name'] = name
        if labels is not None:
            _params['labels'] = labels
        if space_embedders is not None:
            _params['space_embedders'] = space_embedders
        _params['public_read'] = public_read
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if default_chunking_config is not None:
            _params['default_chunking_config'] = default_chunking_config
        if space_id is not None:
            _params['space_id'] = space_id
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=SpaceCreationRequest, op=op, kwargs=_params,
        )
        resp = await self._http.post(
            "/v1/spaces",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    async def list(self, *, labels: dict[str, str] | None = None, owner_id: str | None=None, name_filter: str | None=None, max_results: int | None=50, next_token: str | None=None, sort_by: str | None='created_time', sort_order: SortOrder | None='DESCENDING') -> AsyncPage[Space]:
        """List spaces

        Retrieves a list of spaces accessible to the caller, with optional filtering by owner, labels, and name. Results are paginated with a maximum number of spaces per response. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.project=AI). PERMISSION-BASED FILTERING: With LIST_SPACE_ANY and owner_id omitted, returns all visible spaces; otherwise returns caller-owned spaces only. DEFAULT SORT: Results ordered by created_at DESCENDING unless specified otherwise. MAX_RESULTS CLAMPING: max_results defaults to 50 and is clamped to [1, 1000] range. Requires LIST_SPACE_OWN or LIST_SPACE_ANY permission.

        Args:
            owner_id (str, optional): Filter spaces by owner ID. With LIST_SPACE_ANY permission and owner_id omitted, returns all visible spaces. Otherwise returns caller-owned spaces only. Specifying owner_id without LIST_SPACE_ANY returns PERMISSION_DENIED.
            name_filter (str, optional): Filter spaces by name using glob pattern matching
            max_results (int, optional, default=50): Maximum number of results to return in a single page (defaults to 50, clamped to [1, 1000])
            next_token (str, optional): Pagination token for retrieving the next set of results
            sort_by (str, optional, default='created_time'): Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.
            sort_order (SortOrder, optional, default='DESCENDING'): Sort order (ASCENDING or DESCENDING, default: DESCENDING)
            label.* (str, optional): Filter by label value. Multiple label filters can be specified (e.g., ?label.project=AI&label.team=NLP)

        Returns:
            Page[Space]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if name_filter is not None:
            _params['name_filter'] = name_filter
        _params['max_results'] = max_results
        if next_token is not None:
            _params['next_token'] = next_token
        _params['sort_by'] = sort_by
        _params['sort_order'] = sort_order
        params = _expand_label_filters(op=op, labels=labels, params=_params)
        _resp = await self._http.get(
            "/v1/spaces",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = ListSpacesResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            "/v1/spaces",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return AsyncPage(
            data=getattr(_page_obj, 'spaces', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=ListSpacesResponse,
            items_field='spaces',
        )

    async def get(self, *, id: str) -> Space:
        """Get a space by ID

        Retrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata. PUBLIC SPACE ACCESS: When public_read=true, any authenticated user can retrieve the space metadata, bypassing ownership checks. Otherwise, requires ownership or DISPLAY_SPACE_ANY permission. Requires DISPLAY_SPACE_OWN permission for owned spaces (or DISPLAY_SPACE_ANY for admin users to view any space). This is a read-only operation safe to retry.

        Args:
            id (str): The unique identifier of the space to retrieve

        Returns:
            Space
        """
        resp = await self._http.get(
            f"/v1/spaces/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    async def update(self, *, id: str, request: UpdateSpaceRequest | dict) -> Space:
        """Update a space

        Updates an existing space with new values for the specified fields. Only name, public_read, and labels can be updated. Fields not included in the request remain unchanged. IMMUTABLE FIELDS: space_embedders, default_chunking_config, and owner_id cannot be modified after creation. NAME UNIQUENESS: Name must be unique per owner - returns ALREADY_EXISTS if name conflicts with existing space. Requires UPDATE_SPACE_OWN permission for spaces you own (or UPDATE_SPACE_ANY for admin users). This operation is idempotent.

        Args:
            id (str): The unique identifier of the space to update.
            request (UpdateSpaceRequest | dict): The update payload. Accepts a UpdateSpaceRequest instance or a plain dict with the same fields. Only specified fields will be modified.

        Returns:
            Space
        """
        if isinstance(request, dict):
            request = UpdateSpaceRequest.model_validate(request)
        resp = await self._http.put(
            f"/v1/spaces/{id}",
            json=request.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return Space.model_validate(resp.json())

    async def delete(self, *, id: str) -> None:
        """Delete a space

        Permanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires DELETE_SPACE_OWN permission for spaces you own (or DELETE_SPACE_ANY for admin users). This operation is safe to retry - may return NOT_FOUND if already deleted.

        Args:
            id (str): The unique identifier of the space to delete
        """
        resp = await self._http.delete(
            f"/v1/spaces/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)

