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

from typing import Any
from typing import Literal, overload

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.batch_memory_deletion_request import BatchMemoryDeletionRequest
from goodmem.models.batch_memory_response import BatchMemoryResponse
from goodmem.models.batch_memory_retrieval_request import BatchMemoryRetrievalRequest
from goodmem.models.chunking_configuration import ChunkingConfiguration
from goodmem.models.hnsw_options import HnswOptions
from goodmem.models.json_batch_memory_creation_request import JsonBatchMemoryCreationRequest
from goodmem.models.json_memory_creation_request import JsonMemoryCreationRequest
from goodmem.models.list_memory_page_images_response import ListMemoryPageImagesResponse
from goodmem.models.memory import Memory
from goodmem.models.memory_list_response import MemoryListResponse
from goodmem.models.memory_page_image import MemoryPageImage
from goodmem.models.post_processor import PostProcessor
from goodmem.models.retrieve_memory_event import RetrieveMemoryEvent
from goodmem.models.retrieve_memory_request import RetrieveMemoryRequest
from goodmem.models.sort_order import SortOrder
from goodmem.pagination import AsyncPage, Page
from goodmem.streaming import AsyncStream, Format, Stream, _ACCEPT, _validate_format


class MemoriesAPIBase:
    """Memories API — auto-generated structural base.

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

    _create_model = JsonMemoryCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/memories', 'input_shape': 'kwargs_body', 'summary': 'Create a new memory', 'description': 'Creates a new memory in a specified space and starts asynchronous processing. The memory begins in PENDING status while a background job performs chunking and embedding generation. IDEMPOTENCY: If memoryId is omitted, the server generates a new UUID and retries are not idempotent. If the client supplies a stable memoryId, the operation behaves as create-if-absent: the first request creates the memory and subsequent retries return HTTP 409 Conflict (ALREADY_EXISTS) rather than creating duplicates. Returns INVALID_ARGUMENT if space_id, original_content, or content_type is missing or invalid. Returns NOT_FOUND if the specified space does not exist. Requires CREATE_MEMORY_OWN permission for spaces you own (or CREATE_MEMORY_ANY for admin users to create in any space). Side effects include creating the memory record and enqueuing a background processing job.', 'response': 'Memory', 'params': [{'name': 'memory_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'memoryId', 'description': 'Optional client-provided UUID for the memory. If omitted, the server generates one. Returns ALREADY_EXISTS if the ID is already in use.'}, {'name': 'space_id', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'spaceId', 'description': 'ID of the space where this memory will be stored'}, {'name': 'original_content', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContent', 'description': 'Original content as plain text (use either this or originalContentB64)'}, {'name': 'original_content_b64', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContentB64', 'description': 'Original content as base64-encoded binary data (use either this or originalContent)'}, {'name': 'original_content_ref', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContentRef', 'description': 'Reference to external content location'}, {'name': 'content_type', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'contentType', 'description': 'MIME type of the content'}, {'name': 'metadata', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'Additional metadata for the memory'}, {'name': 'chunking_config', 'type': 'ChunkingConfiguration', 'source': 'body', 'required': False, 'alias': 'chunkingConfig', 'description': 'Chunking strategy for this memory (if not provided, uses space default)'}, {'name': 'extract_page_images', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'extractPageImages', 'description': 'Optional hint to extract page images for eligible document types (for example, PDFs)'}, {'name': 'file_field', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'fileField', 'description': 'Optional multipart file field name to bind binary content; required when multiple files are uploaded in a batch multipart request.'}], 'body_model': 'JsonMemoryCreationRequest', 'body_expr': 'JsonMemoryCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json', 'multipart/form-data'], 'supports_multipart': True, 'multipart_request_field': 'request', 'multipart_file_field': 'file'}, 'get': {'http_method': 'GET', 'path': '/v1/memories/{id}', 'input_shape': 'path_query', 'summary': 'Get a memory by ID', 'description': 'Retrieves a single memory by its ID. PERMISSION CLARIFICATION: With READ_MEMORY_OWN permission, access is granted if you own the parent space OR if the parent space is public (public_read=true). With READ_MEMORY_ANY permission, you can access any memory regardless of ownership. This is a read-only operation with no side effects and is safe to retry. Returns NOT_FOUND if the memory or its parent space does not exist.', 'response': 'Memory', 'query_params': ['id', 'include_content', 'include_processing_history'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to retrieve'}, {'name': 'include_content', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.', 'default': False}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.', 'default': False}]}, 'list': {'http_method': 'GET', 'path': '/v1/spaces/{spaceId}/memories', 'input_shape': 'path_query', 'summary': 'List memories in a space', 'description': 'Lists all memories within a given space. Pagination is supported via maxResults and nextToken (opaque). nextToken is a URL-safe Base64 string without padding; do not parse or construct it. This is a read-only operation with no side effects and is safe to retry. Requires LIST_MEMORY_OWN or LIST_MEMORY_ANY permission. Returns NOT_FOUND if the specified space does not exist.', 'response': 'MemoryListResponse', 'query_params': ['space_id', 'include_content', 'include_processing_history', 'status_filter', 'filter', 'max_results', 'next_token', 'sort_by', 'sort_order'], 'params': [{'name': 'space_id', 'type': 'str', 'source': 'path', 'required': True, 'alias': 'spaceId', 'description': 'The unique identifier of the space containing the memories'}, {'name': 'include_content', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.', 'default': False}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.', 'default': False}, {'name': 'status_filter', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'statusFilter', 'description': 'Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED). The snake_case alias status_filter is also accepted.', 'enum': ['PENDING', 'PROCESSING', 'COMPLETED', 'FAILED']}, {'name': 'filter', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Optional metadata filter expression for list results'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results per page (defaults to 50, clamped to [1, 500]). The snake_case alias max_results is also accepted.', 'default': 50}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it. The snake_case alias next_token is also accepted.'}, {'name': 'sort_by', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'sortBy', 'description': "Field to sort by (e.g., 'created_at'). The snake_case alias sort_by is also accepted."}, {'name': 'sort_order', 'type': 'SortOrder', 'source': 'query', 'required': False, 'alias': 'sortOrder', 'description': 'Sort direction (ASCENDING or DESCENDING). The snake_case alias sort_order is also accepted.'}], 'auto_next_token': True}, 'delete': {'http_method': 'DELETE', 'path': '/v1/memories/{id}', 'input_shape': 'path_query', 'summary': 'Delete a memory', 'description': 'Permanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. Requires DELETE_MEMORY_OWN permission for memories in spaces you own (or DELETE_MEMORY_ANY for admin users to delete any memory). Side effects include permanent removal of the memory record and all associated chunk data.', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to delete'}]}, 'content': {'http_method': 'GET', 'path': '/v1/memories/{id}/content', 'input_shape': 'path_query', 'summary': 'Download memory content', 'description': "Streams the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check originalContentRef from the metadata endpoint to locate external content.", 'response': 'bytes', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to download'}]}, 'pages': {'http_method': 'GET', 'path': '/v1/memories/{id}/pages', 'input_shape': 'path_query', 'summary': 'List memory page images', 'description': 'Lists extracted page-image metadata for a memory with optional filters and pagination.', 'response': 'ListMemoryPageImagesResponse', 'query_params': ['id', 'start_page_index', 'end_page_index', 'dpi', 'content_type', 'max_results', 'next_token'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'Memory UUID'}, {'name': 'start_page_index', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'startPageIndex', 'description': 'Optional lower bound for returned page indices, inclusive. The snake_case alias start_page_index is also accepted.'}, {'name': 'end_page_index', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'endPageIndex', 'description': 'Optional upper bound for returned page indices, inclusive. The snake_case alias end_page_index is also accepted.'}, {'name': 'dpi', 'type': 'int', 'source': 'query', 'required': False, 'description': 'Optional rendition filter for page-image DPI.'}, {'name': 'content_type', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'contentType', 'description': 'Optional rendition filter for page-image MIME type, such as image/png. The snake_case alias content_type is also accepted.'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results per page. The snake_case alias max_results is also accepted.'}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Opaque pagination token for the next page. The snake_case alias next_token is also accepted. Do not parse or construct it.'}]}, 'pages_image': {'http_method': 'GET', 'path': '/v1/memories/{id}/pages/{pageIndex}/image', 'input_shape': 'path_query', 'summary': 'Download memory page image content', 'description': 'Downloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.', 'response': 'bytes', 'query_params': ['id', 'page_index', 'dpi', 'content_type'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'Memory UUID'}, {'name': 'page_index', 'type': 'int', 'source': 'path', 'required': True, 'alias': 'pageIndex', 'description': '0-based page index'}, {'name': 'dpi', 'type': 'int', 'source': 'query', 'required': False, 'description': 'Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or contentType.'}, {'name': 'content_type', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'contentType', 'description': 'Optional rendition filter. MIME type of the desired page image, such as image/png. The snake_case alias content_type is also accepted.'}]}, 'batch_create': {'http_method': 'POST', 'path': '/v1/memories:batchCreate', 'input_shape': 'kwargs_body', 'summary': 'Create multiple memories in a batch', 'description': 'Creates multiple memories in a single operation, with individual success/failure results.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'requests', 'type': 'list[JsonMemoryCreationRequest]', 'source': 'body', 'required': True, 'description': 'Array of memory creation requests.'}], 'body_model': 'JsonBatchMemoryCreationRequest', 'body_expr': 'JsonBatchMemoryCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json', 'multipart/form-data'], 'supports_multipart': True, 'multipart_request_field': 'requests', 'multipart_file_field': 'file'}, 'batch_delete': {'http_method': 'POST', 'path': '/v1/memories:batchDelete', 'input_shape': 'kwargs_body', 'summary': 'Delete memories in batch', 'description': 'Deletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'requests', 'type': 'list[BatchDeleteMemorySelectorRequest]', 'source': 'body', 'required': True, 'description': 'Array of delete selectors'}], 'body_model': 'BatchMemoryDeletionRequest', 'body_expr': 'BatchMemoryDeletionRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'batch_get': {'http_method': 'POST', 'path': '/v1/memories:batchGet', 'input_shape': 'kwargs_body', 'summary': 'Get multiple memories by ID', 'description': 'Retrieves multiple memories in a single operation, with individual success/failure results.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'memory_ids', 'type': 'list[str]', 'source': 'body', 'required': True, 'alias': 'memoryIds', 'description': 'Array of memory IDs to retrieve'}, {'name': 'include_content', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response'}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history for each memory'}], 'body_model': 'BatchMemoryRetrievalRequest', 'body_expr': 'BatchMemoryRetrievalRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'retrieve': {'http_method': 'POST', 'path': '/v1/memories:retrieve', 'input_shape': 'kwargs_body', 'summary': 'Advanced semantic memory retrieval with JSON', 'description': 'Streams semantic retrieval results with full feature support including context items and embedder weight overrides, per-space filters, and request-level HNSW tuning. Supports SSE (text/event-stream) and NDJSON (application/x-ndjson) formats.', 'response': 'RetrieveMemoryStream | list[RetrieveMemoryEvent]', 'query_params': ['accept'], 'params': [{'name': 'accept', 'type': 'str', 'source': 'header', 'required': False, 'alias': 'Accept', 'description': "Response format: 'text/event-stream' for Server-Sent Events or 'application/x-ndjson' for newline-delimited JSON"}, {'name': 'message', 'type': 'str', 'source': 'body', 'required': True, 'description': 'Primary query/message for semantic search.'}, {'name': 'context', 'type': 'list[ContextItem]', 'source': 'body', 'required': False, 'description': 'Optional context items (text or binary) to provide additional context for the search.'}, {'name': 'space_keys', 'type': 'list[SpaceKey]', 'source': 'body', 'required': True, 'alias': 'spaceKeys', 'description': 'List of spaces to search with optional per-embedder weight overrides.'}, {'name': 'requested_size', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'requestedSize', 'description': 'Maximum number of memories to retrieve.'}, {'name': 'fetch_memory', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'fetchMemory', 'description': 'Whether to include full Memory objects in the response.'}, {'name': 'fetch_memory_content', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'fetchMemoryContent', 'description': 'Whether to include memory content in the response. Requires fetchMemory=true.'}, {'name': 'hnsw', 'type': 'HnswOptions', 'source': 'body', 'required': False, 'description': 'Optional request-level HNSW tuning overrides. Advanced usage; available on POST retrieve.'}, {'name': 'post_processor', 'type': 'PostProcessor', 'source': 'body', 'required': False, 'alias': 'postProcessor', 'description': 'Optional post-processor configuration to transform retrieval results.'}], 'body_model': 'RetrieveMemoryRequest', 'body_expr': 'RetrieveMemoryRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json'], 'accept_from': 'format'}}

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

    def create(self, *, memory_id: str | None=None, space_id: str | None=None, original_content: str | None=None, original_content_b64: str | None=None, original_content_ref: str | None=None, content_type: str | None=None, metadata: dict | None=None, chunking_config: ChunkingConfiguration | None=None, extract_page_images: bool | None=None, file_field: str | None=None) -> Memory:
        """Create a new memory

        Creates a new memory in a specified space and starts asynchronous processing. The memory begins in PENDING status while a background job performs chunking and embedding generation. IDEMPOTENCY: If memory_id is omitted, the server generates a new UUID and retries are not idempotent. If the client supplies a stable memory_id, the operation behaves as create-if-absent: the first request creates the memory and subsequent retries return HTTP 409 Conflict (ALREADY_EXISTS) rather than creating duplicates. Returns INVALID_ARGUMENT if space_id, original_content, or content_type is missing or invalid. Returns NOT_FOUND if the specified space does not exist. Requires CREATE_MEMORY_OWN permission for spaces you own (or CREATE_MEMORY_ANY for admin users to create in any space). Side effects include creating the memory record and enqueuing a background processing job.

        Args:
            memory_id (str, optional): Optional client-provided UUID for the memory. If omitted, the server generates one. Returns ALREADY_EXISTS if the ID is already in use.
            space_id (str): ID of the space where this memory will be stored
            original_content (str, optional): Original content as plain text (use either this or original_content_b64)
            original_content_b64 (str, optional): Original content as base64-encoded binary data (use either this or original_content)
            original_content_ref (str, optional): Reference to external content location
            content_type (str): MIME type of the content
            metadata (dict, optional): Additional metadata for the memory
            chunking_config (ChunkingConfiguration, optional): Chunking strategy for this memory (if not provided, uses space default)
            extract_page_images (bool, optional): Optional hint to extract page images for eligible document types (for example, PDFs)
            file_field (str, optional): Optional multipart file field name to bind binary content; required when multiple files are uploaded in a batch multipart request.

        Returns:
            Memory
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if memory_id is not None:
            _params['memory_id'] = memory_id
        if space_id is not None:
            _params['space_id'] = space_id
        if original_content is not None:
            _params['original_content'] = original_content
        if original_content_b64 is not None:
            _params['original_content_b64'] = original_content_b64
        if original_content_ref is not None:
            _params['original_content_ref'] = original_content_ref
        if content_type is not None:
            _params['content_type'] = content_type
        if metadata is not None:
            _params['metadata'] = metadata
        if chunking_config is not None:
            _params['chunking_config'] = chunking_config
        if extract_page_images is not None:
            _params['extract_page_images'] = extract_page_images
        if file_field is not None:
            _params['file_field'] = file_field
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=JsonMemoryCreationRequest, op=op, kwargs=_params,
        )
        resp = self._http.post(
            "/v1/memories",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Memory.model_validate(resp.json())

    def get(self, *, id: str, include_content: bool | None = False, include_processing_history: bool | None = False) -> Memory:
        """Get a memory by ID

        Retrieves a single memory by its ID. PERMISSION CLARIFICATION: With READ_MEMORY_OWN permission, access is granted if you own the parent space OR if the parent space is public (public_read=true). With READ_MEMORY_ANY permission, you can access any memory regardless of ownership. This is a read-only operation with no side effects and is safe to retry. Returns NOT_FOUND if the memory or its parent space does not exist.

        Args:
            id (str): The unique identifier of the memory to retrieve
            include_content (bool, optional, default=False): Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.
            include_processing_history (bool, optional, default=False): Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.

        Returns:
            Memory
        """
        params = {}
        if include_content is not None:
            params["include_content"] = include_content
        if include_processing_history is not None:
            params["include_processing_history"] = include_processing_history
        resp = self._http.get(
            f"/v1/memories/{id}",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Memory.model_validate(resp.json())

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

        Permanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. Requires DELETE_MEMORY_OWN permission for memories in spaces you own (or DELETE_MEMORY_ANY for admin users to delete any memory). Side effects include permanent removal of the memory record and all associated chunk data.

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

    def content(self, *, id: str) -> bytes:
        """Download memory content

        Streams the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check original_content_ref from the metadata endpoint to locate external content.

        Args:
            id (str): The unique identifier of the memory to download
        """
        resp = self._http.get(
            f"/v1/memories/{id}/content",
            headers=self._headers,
        )
        raise_for_status(resp)
        return resp.content

    def pages(self, *, id: str, start_page_index: int | None = None, end_page_index: int | None = None, dpi: int | None = None, content_type: str | None = None, max_results: int | None = None, next_token: str | None = None) -> Page[MemoryPageImage]:
        """List memory page images

        Lists extracted page-image metadata for a memory with optional filters and pagination.

        Args:
            id (str): Memory UUID
            start_page_index (int, optional): Optional lower bound for returned page indices, inclusive. The snake_case alias start_page_index is also accepted.
            end_page_index (int, optional): Optional upper bound for returned page indices, inclusive. The snake_case alias end_page_index is also accepted.
            dpi (int, optional): Optional rendition filter for page-image DPI.
            content_type (str, optional): Optional rendition filter for page-image MIME type, such as image/png. The snake_case alias content_type is also accepted.
            max_results (int, optional): Maximum number of results per page. The snake_case alias max_results is also accepted.
            next_token (str, optional): Opaque pagination token for the next page. The snake_case alias next_token is also accepted. Do not parse or construct it.

        Returns:
            Page[MemoryPageImage]
        """
        params = {}
        if start_page_index is not None:
            params["start_page_index"] = start_page_index
        if end_page_index is not None:
            params["end_page_index"] = end_page_index
        if dpi is not None:
            params["dpi"] = dpi
        if content_type is not None:
            params["content_type"] = content_type
        if max_results is not None:
            params["max_results"] = max_results
        if next_token is not None:
            params["next_token"] = next_token
        _resp = self._http.get(
            f"/v1/memories/{id}/pages",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = ListMemoryPageImagesResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            f"/v1/memories/{id}/pages",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return Page(
            data=getattr(_page_obj, 'page_images', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=ListMemoryPageImagesResponse,
            items_field='page_images',
        )

    def pages_image(self, *, id: str, page_index: int, dpi: int | None = None, content_type: str | None = None) -> bytes:
        """Download memory page image content

        Downloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.

        Args:
            id (str): Memory UUID
            page_index (int): 0-based page index
            dpi (int, optional): Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or content_type.
            content_type (str, optional): Optional rendition filter. MIME type of the desired page image, such as image/png. The snake_case alias content_type is also accepted.
        """
        params = {}
        if dpi is not None:
            params["dpi"] = dpi
        if content_type is not None:
            params["content_type"] = content_type
        resp = self._http.get(
            f"/v1/memories/{id}/pages/{page_index}/image",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        return resp.content

    def batch_create(self, *, requests: list) -> BatchMemoryResponse:
        """Create multiple memories in a batch

        Creates multiple memories in a single operation, with individual success/failure results.

        Args:
            requests (list): Array of memory creation requests.

        Returns:
            BatchMemoryResponse
        """
        _params = {'requests': requests}
        body = JsonBatchMemoryCreationRequest.model_validate(_params)
        resp = self._http.post(
            "/v1/memories:batchCreate",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    def batch_delete(self, *, requests: list) -> BatchMemoryResponse:
        """Delete memories in batch

        Deletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space.

        Args:
            requests (list): Array of delete selectors

        Returns:
            BatchMemoryResponse
        """
        _params = {'requests': requests}
        body = BatchMemoryDeletionRequest.model_validate(_params)
        resp = self._http.post(
            "/v1/memories:batchDelete",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    def batch_get(self, *, memory_ids: list, include_content: bool | None=None, include_processing_history: bool | None=None) -> BatchMemoryResponse:
        """Get multiple memories by ID

        Retrieves multiple memories in a single operation, with individual success/failure results.

        Args:
            memory_ids (list): Array of memory IDs to retrieve
            include_content (bool, optional): Whether to include the original content in the response
            include_processing_history (bool, optional): Whether to include background job processing history for each memory

        Returns:
            BatchMemoryResponse
        """
        _params = {'memory_ids': memory_ids}
        if include_content is not None:
            _params['include_content'] = include_content
        if include_processing_history is not None:
            _params['include_processing_history'] = include_processing_history
        body = BatchMemoryRetrievalRequest.model_validate(_params)
        resp = self._http.post(
            "/v1/memories:batchGet",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    def _retrieve_with_body(
        self,
        body_dict: dict,
        *,
        stream: bool,
        format: Format = "ndjson",
    ) -> Stream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]:
        """Execute a retrieve request with a pre-built body dict.

        Shared by the structural base and any convenience overrides.
        """
        stream_obj = Stream(
            self._http,
            method="POST",
            url="/v1/memories:retrieve",
            model=RetrieveMemoryEvent,
            format=format,
            json=body_dict,
            headers={**self._headers, "Accept": _ACCEPT[format]},
        )
        if stream:
            return stream_obj
        with stream_obj as s:
            return list(s)

    @overload
    def retrieve(
        self,
        *,
        message: str, space_keys: list, context: list | None=None, requested_size: int | None=None, fetch_memory: bool | None=None, fetch_memory_content: bool | None=None, hnsw: HnswOptions | None=None, post_processor: PostProcessor | None=None, stream: Literal[False],
        format: Format = ...,
    ) -> list[RetrieveMemoryEvent]: ...

    @overload
    def retrieve(
        self,
        *,
        message: str, space_keys: list, context: list | None=None, requested_size: int | None=None, fetch_memory: bool | None=None, fetch_memory_content: bool | None=None, hnsw: HnswOptions | None=None, post_processor: PostProcessor | None=None, stream: Literal[True] = ...,
        format: Format = ...,
    ) -> Stream[RetrieveMemoryEvent]: ...

    def retrieve(
        self,
        *,
        message: str, space_keys: list, context: list | None=None, requested_size: int | None=None, fetch_memory: bool | None=None, fetch_memory_content: bool | None=None, hnsw: HnswOptions | None=None, post_processor: PostProcessor | None=None, stream: bool = True,
        format: Format = "ndjson",
    ) -> Stream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]:
        """Advanced semantic memory retrieval with JSON

        Streams semantic retrieval results with full feature support including context items and embedder weight overrides, per-space filters, and request-level HNSW tuning. Supports SSE (text/event-stream) and NDJSON (application/x-ndjson) formats.

        Args:
            message (str): Primary query/message for semantic search.
            context (list, optional): Optional context items (text or binary) to provide additional context for the search.
            space_keys (list): List of spaces to search with optional per-embedder weight overrides.
            requested_size (int, optional): Maximum number of memories to retrieve.
            fetch_memory (bool, optional): Whether to include full Memory objects in the response.
            fetch_memory_content (bool, optional): Whether to include memory content in the response. Requires fetch_memory=true.
            hnsw (HnswOptions, optional): Optional request-level HNSW tuning overrides. Advanced usage; available on POST retrieve.
            post_processor (PostProcessor, optional): Optional post-processor configuration to transform retrieval results.

        Returns:
            Stream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]
        """
        fmt = _validate_format(format)
        _params = {'message': message, 'space_keys': space_keys}
        if context is not None:
            _params['context'] = context
        if requested_size is not None:
            _params['requested_size'] = requested_size
        if fetch_memory is not None:
            _params['fetch_memory'] = fetch_memory
        if fetch_memory_content is not None:
            _params['fetch_memory_content'] = fetch_memory_content
        if hnsw is not None:
            _params['hnsw'] = hnsw
        if post_processor is not None:
            _params['post_processor'] = post_processor
        body = RetrieveMemoryRequest.model_validate(_params)
        body_dict = body.model_dump(by_alias=True, exclude_unset=True)
        return self._retrieve_with_body(body_dict, stream=stream, format=fmt)

    def list(self, *, space_id: str, include_content: bool | None=False, include_processing_history: bool | None=False, status_filter: str | None=None, filter: str | None=None, max_results: int | None=50, next_token: str | None=None, sort_by: str | None=None, sort_order: SortOrder | None=None) -> Page[Memory]:
        """List memories in a space

        Lists all memories within a given space. Pagination is supported via max_results and next_token (opaque). next_token is a URL-safe Base64 string without padding; do not parse or construct it. This is a read-only operation with no side effects and is safe to retry. Requires LIST_MEMORY_OWN or LIST_MEMORY_ANY permission. Returns NOT_FOUND if the specified space does not exist.

        Args:
            space_id (str): The unique identifier of the space containing the memories
            include_content (bool, optional, default=False): Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.
            include_processing_history (bool, optional, default=False): Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.
            status_filter (str, optional): Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED). The snake_case alias status_filter is also accepted.
            filter (str, optional): Optional metadata filter expression for list results
            max_results (int, optional, default=50): Maximum number of results per page (defaults to 50, clamped to [1, 500]). The snake_case alias max_results is also accepted.
            next_token (str, optional): Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it. The snake_case alias next_token is also accepted.
            sort_by (str, optional): Field to sort by (e.g., 'created_at'). The snake_case alias sort_by is also accepted.
            sort_order (SortOrder, optional): Sort direction (ASCENDING or DESCENDING). The snake_case alias sort_order is also accepted.

        Returns:
            Page[Memory]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        _params['include_content'] = include_content
        _params['include_processing_history'] = include_processing_history
        if status_filter is not None:
            _params['status_filter'] = status_filter
        if filter is not None:
            _params['filter'] = filter
        _params['max_results'] = max_results
        if next_token is not None:
            _params['next_token'] = next_token
        if sort_by is not None:
            _params['sort_by'] = sort_by
        if sort_order is not None:
            _params['sort_order'] = sort_order
        params = _params
        _resp = self._http.get(
            f"/v1/spaces/{space_id}/memories",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = MemoryListResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            f"/v1/spaces/{space_id}/memories",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return Page(
            data=getattr(_page_obj, 'memories', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=MemoryListResponse,
            items_field='memories',
        )


class AsyncMemoriesAPIBase:
    """Async Memories API — auto-generated structural base.

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

    _create_model = JsonMemoryCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/memories', 'input_shape': 'kwargs_body', 'summary': 'Create a new memory', 'description': 'Creates a new memory in a specified space and starts asynchronous processing. The memory begins in PENDING status while a background job performs chunking and embedding generation. IDEMPOTENCY: If memoryId is omitted, the server generates a new UUID and retries are not idempotent. If the client supplies a stable memoryId, the operation behaves as create-if-absent: the first request creates the memory and subsequent retries return HTTP 409 Conflict (ALREADY_EXISTS) rather than creating duplicates. Returns INVALID_ARGUMENT if space_id, original_content, or content_type is missing or invalid. Returns NOT_FOUND if the specified space does not exist. Requires CREATE_MEMORY_OWN permission for spaces you own (or CREATE_MEMORY_ANY for admin users to create in any space). Side effects include creating the memory record and enqueuing a background processing job.', 'response': 'Memory', 'params': [{'name': 'memory_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'memoryId', 'description': 'Optional client-provided UUID for the memory. If omitted, the server generates one. Returns ALREADY_EXISTS if the ID is already in use.'}, {'name': 'space_id', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'spaceId', 'description': 'ID of the space where this memory will be stored'}, {'name': 'original_content', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContent', 'description': 'Original content as plain text (use either this or originalContentB64)'}, {'name': 'original_content_b64', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContentB64', 'description': 'Original content as base64-encoded binary data (use either this or originalContent)'}, {'name': 'original_content_ref', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'originalContentRef', 'description': 'Reference to external content location'}, {'name': 'content_type', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'contentType', 'description': 'MIME type of the content'}, {'name': 'metadata', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'Additional metadata for the memory'}, {'name': 'chunking_config', 'type': 'ChunkingConfiguration', 'source': 'body', 'required': False, 'alias': 'chunkingConfig', 'description': 'Chunking strategy for this memory (if not provided, uses space default)'}, {'name': 'extract_page_images', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'extractPageImages', 'description': 'Optional hint to extract page images for eligible document types (for example, PDFs)'}, {'name': 'file_field', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'fileField', 'description': 'Optional multipart file field name to bind binary content; required when multiple files are uploaded in a batch multipart request.'}], 'body_model': 'JsonMemoryCreationRequest', 'body_expr': 'JsonMemoryCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json', 'multipart/form-data'], 'supports_multipart': True, 'multipart_request_field': 'request', 'multipart_file_field': 'file'}, 'get': {'http_method': 'GET', 'path': '/v1/memories/{id}', 'input_shape': 'path_query', 'summary': 'Get a memory by ID', 'description': 'Retrieves a single memory by its ID. PERMISSION CLARIFICATION: With READ_MEMORY_OWN permission, access is granted if you own the parent space OR if the parent space is public (public_read=true). With READ_MEMORY_ANY permission, you can access any memory regardless of ownership. This is a read-only operation with no side effects and is safe to retry. Returns NOT_FOUND if the memory or its parent space does not exist.', 'response': 'Memory', 'query_params': ['id', 'include_content', 'include_processing_history'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to retrieve'}, {'name': 'include_content', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.', 'default': False}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.', 'default': False}]}, 'list': {'http_method': 'GET', 'path': '/v1/spaces/{spaceId}/memories', 'input_shape': 'path_query', 'summary': 'List memories in a space', 'description': 'Lists all memories within a given space. Pagination is supported via maxResults and nextToken (opaque). nextToken is a URL-safe Base64 string without padding; do not parse or construct it. This is a read-only operation with no side effects and is safe to retry. Requires LIST_MEMORY_OWN or LIST_MEMORY_ANY permission. Returns NOT_FOUND if the specified space does not exist.', 'response': 'MemoryListResponse', 'query_params': ['space_id', 'include_content', 'include_processing_history', 'status_filter', 'filter', 'max_results', 'next_token', 'sort_by', 'sort_order'], 'params': [{'name': 'space_id', 'type': 'str', 'source': 'path', 'required': True, 'alias': 'spaceId', 'description': 'The unique identifier of the space containing the memories'}, {'name': 'include_content', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.', 'default': False}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'query', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.', 'default': False}, {'name': 'status_filter', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'statusFilter', 'description': 'Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED). The snake_case alias status_filter is also accepted.', 'enum': ['PENDING', 'PROCESSING', 'COMPLETED', 'FAILED']}, {'name': 'filter', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Optional metadata filter expression for list results'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results per page (defaults to 50, clamped to [1, 500]). The snake_case alias max_results is also accepted.', 'default': 50}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it. The snake_case alias next_token is also accepted.'}, {'name': 'sort_by', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'sortBy', 'description': "Field to sort by (e.g., 'created_at'). The snake_case alias sort_by is also accepted."}, {'name': 'sort_order', 'type': 'SortOrder', 'source': 'query', 'required': False, 'alias': 'sortOrder', 'description': 'Sort direction (ASCENDING or DESCENDING). The snake_case alias sort_order is also accepted.'}], 'auto_next_token': True}, 'delete': {'http_method': 'DELETE', 'path': '/v1/memories/{id}', 'input_shape': 'path_query', 'summary': 'Delete a memory', 'description': 'Permanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. Requires DELETE_MEMORY_OWN permission for memories in spaces you own (or DELETE_MEMORY_ANY for admin users to delete any memory). Side effects include permanent removal of the memory record and all associated chunk data.', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to delete'}]}, 'content': {'http_method': 'GET', 'path': '/v1/memories/{id}/content', 'input_shape': 'path_query', 'summary': 'Download memory content', 'description': "Streams the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check originalContentRef from the metadata endpoint to locate external content.", 'response': 'bytes', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the memory to download'}]}, 'pages': {'http_method': 'GET', 'path': '/v1/memories/{id}/pages', 'input_shape': 'path_query', 'summary': 'List memory page images', 'description': 'Lists extracted page-image metadata for a memory with optional filters and pagination.', 'response': 'ListMemoryPageImagesResponse', 'query_params': ['id', 'start_page_index', 'end_page_index', 'dpi', 'content_type', 'max_results', 'next_token'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'Memory UUID'}, {'name': 'start_page_index', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'startPageIndex', 'description': 'Optional lower bound for returned page indices, inclusive. The snake_case alias start_page_index is also accepted.'}, {'name': 'end_page_index', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'endPageIndex', 'description': 'Optional upper bound for returned page indices, inclusive. The snake_case alias end_page_index is also accepted.'}, {'name': 'dpi', 'type': 'int', 'source': 'query', 'required': False, 'description': 'Optional rendition filter for page-image DPI.'}, {'name': 'content_type', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'contentType', 'description': 'Optional rendition filter for page-image MIME type, such as image/png. The snake_case alias content_type is also accepted.'}, {'name': 'max_results', 'type': 'int', 'source': 'query', 'required': False, 'alias': 'maxResults', 'description': 'Maximum number of results per page. The snake_case alias max_results is also accepted.'}, {'name': 'next_token', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'nextToken', 'description': 'Opaque pagination token for the next page. The snake_case alias next_token is also accepted. Do not parse or construct it.'}]}, 'pages_image': {'http_method': 'GET', 'path': '/v1/memories/{id}/pages/{pageIndex}/image', 'input_shape': 'path_query', 'summary': 'Download memory page image content', 'description': 'Downloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.', 'response': 'bytes', 'query_params': ['id', 'page_index', 'dpi', 'content_type'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'Memory UUID'}, {'name': 'page_index', 'type': 'int', 'source': 'path', 'required': True, 'alias': 'pageIndex', 'description': '0-based page index'}, {'name': 'dpi', 'type': 'int', 'source': 'query', 'required': False, 'description': 'Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or contentType.'}, {'name': 'content_type', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'contentType', 'description': 'Optional rendition filter. MIME type of the desired page image, such as image/png. The snake_case alias content_type is also accepted.'}]}, 'batch_create': {'http_method': 'POST', 'path': '/v1/memories:batchCreate', 'input_shape': 'kwargs_body', 'summary': 'Create multiple memories in a batch', 'description': 'Creates multiple memories in a single operation, with individual success/failure results.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'requests', 'type': 'list[JsonMemoryCreationRequest]', 'source': 'body', 'required': True, 'description': 'Array of memory creation requests.'}], 'body_model': 'JsonBatchMemoryCreationRequest', 'body_expr': 'JsonBatchMemoryCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json', 'multipart/form-data'], 'supports_multipart': True, 'multipart_request_field': 'requests', 'multipart_file_field': 'file'}, 'batch_delete': {'http_method': 'POST', 'path': '/v1/memories:batchDelete', 'input_shape': 'kwargs_body', 'summary': 'Delete memories in batch', 'description': 'Deletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'requests', 'type': 'list[BatchDeleteMemorySelectorRequest]', 'source': 'body', 'required': True, 'description': 'Array of delete selectors'}], 'body_model': 'BatchMemoryDeletionRequest', 'body_expr': 'BatchMemoryDeletionRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'batch_get': {'http_method': 'POST', 'path': '/v1/memories:batchGet', 'input_shape': 'kwargs_body', 'summary': 'Get multiple memories by ID', 'description': 'Retrieves multiple memories in a single operation, with individual success/failure results.', 'response': 'BatchMemoryResponse', 'params': [{'name': 'memory_ids', 'type': 'list[str]', 'source': 'body', 'required': True, 'alias': 'memoryIds', 'description': 'Array of memory IDs to retrieve'}, {'name': 'include_content', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'includeContent', 'description': 'Whether to include the original content in the response'}, {'name': 'include_processing_history', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'includeProcessingHistory', 'description': 'Whether to include background job processing history for each memory'}], 'body_model': 'BatchMemoryRetrievalRequest', 'body_expr': 'BatchMemoryRetrievalRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'retrieve': {'http_method': 'POST', 'path': '/v1/memories:retrieve', 'input_shape': 'kwargs_body', 'summary': 'Advanced semantic memory retrieval with JSON', 'description': 'Streams semantic retrieval results with full feature support including context items and embedder weight overrides, per-space filters, and request-level HNSW tuning. Supports SSE (text/event-stream) and NDJSON (application/x-ndjson) formats.', 'response': 'RetrieveMemoryStream | list[RetrieveMemoryEvent]', 'query_params': ['accept'], 'params': [{'name': 'accept', 'type': 'str', 'source': 'header', 'required': False, 'alias': 'Accept', 'description': "Response format: 'text/event-stream' for Server-Sent Events or 'application/x-ndjson' for newline-delimited JSON"}, {'name': 'message', 'type': 'str', 'source': 'body', 'required': True, 'description': 'Primary query/message for semantic search.'}, {'name': 'context', 'type': 'list[ContextItem]', 'source': 'body', 'required': False, 'description': 'Optional context items (text or binary) to provide additional context for the search.'}, {'name': 'space_keys', 'type': 'list[SpaceKey]', 'source': 'body', 'required': True, 'alias': 'spaceKeys', 'description': 'List of spaces to search with optional per-embedder weight overrides.'}, {'name': 'requested_size', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'requestedSize', 'description': 'Maximum number of memories to retrieve.'}, {'name': 'fetch_memory', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'fetchMemory', 'description': 'Whether to include full Memory objects in the response.'}, {'name': 'fetch_memory_content', 'type': 'bool', 'source': 'body', 'required': False, 'alias': 'fetchMemoryContent', 'description': 'Whether to include memory content in the response. Requires fetchMemory=true.'}, {'name': 'hnsw', 'type': 'HnswOptions', 'source': 'body', 'required': False, 'description': 'Optional request-level HNSW tuning overrides. Advanced usage; available on POST retrieve.'}, {'name': 'post_processor', 'type': 'PostProcessor', 'source': 'body', 'required': False, 'alias': 'postProcessor', 'description': 'Optional post-processor configuration to transform retrieval results.'}], 'body_model': 'RetrieveMemoryRequest', 'body_expr': 'RetrieveMemoryRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json'], 'accept_from': 'format'}}

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

    async def create(self, *, memory_id: str | None=None, space_id: str | None=None, original_content: str | None=None, original_content_b64: str | None=None, original_content_ref: str | None=None, content_type: str | None=None, metadata: dict | None=None, chunking_config: ChunkingConfiguration | None=None, extract_page_images: bool | None=None, file_field: str | None=None) -> Memory:
        """Create a new memory

        Creates a new memory in a specified space and starts asynchronous processing. The memory begins in PENDING status while a background job performs chunking and embedding generation. IDEMPOTENCY: If memory_id is omitted, the server generates a new UUID and retries are not idempotent. If the client supplies a stable memory_id, the operation behaves as create-if-absent: the first request creates the memory and subsequent retries return HTTP 409 Conflict (ALREADY_EXISTS) rather than creating duplicates. Returns INVALID_ARGUMENT if space_id, original_content, or content_type is missing or invalid. Returns NOT_FOUND if the specified space does not exist. Requires CREATE_MEMORY_OWN permission for spaces you own (or CREATE_MEMORY_ANY for admin users to create in any space). Side effects include creating the memory record and enqueuing a background processing job.

        Args:
            memory_id (str, optional): Optional client-provided UUID for the memory. If omitted, the server generates one. Returns ALREADY_EXISTS if the ID is already in use.
            space_id (str): ID of the space where this memory will be stored
            original_content (str, optional): Original content as plain text (use either this or original_content_b64)
            original_content_b64 (str, optional): Original content as base64-encoded binary data (use either this or original_content)
            original_content_ref (str, optional): Reference to external content location
            content_type (str): MIME type of the content
            metadata (dict, optional): Additional metadata for the memory
            chunking_config (ChunkingConfiguration, optional): Chunking strategy for this memory (if not provided, uses space default)
            extract_page_images (bool, optional): Optional hint to extract page images for eligible document types (for example, PDFs)
            file_field (str, optional): Optional multipart file field name to bind binary content; required when multiple files are uploaded in a batch multipart request.

        Returns:
            Memory
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if memory_id is not None:
            _params['memory_id'] = memory_id
        if space_id is not None:
            _params['space_id'] = space_id
        if original_content is not None:
            _params['original_content'] = original_content
        if original_content_b64 is not None:
            _params['original_content_b64'] = original_content_b64
        if original_content_ref is not None:
            _params['original_content_ref'] = original_content_ref
        if content_type is not None:
            _params['content_type'] = content_type
        if metadata is not None:
            _params['metadata'] = metadata
        if chunking_config is not None:
            _params['chunking_config'] = chunking_config
        if extract_page_images is not None:
            _params['extract_page_images'] = extract_page_images
        if file_field is not None:
            _params['file_field'] = file_field
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=JsonMemoryCreationRequest, op=op, kwargs=_params,
        )
        resp = await self._http.post(
            "/v1/memories",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Memory.model_validate(resp.json())

    async def get(self, *, id: str, include_content: bool | None = False, include_processing_history: bool | None = False) -> Memory:
        """Get a memory by ID

        Retrieves a single memory by its ID. PERMISSION CLARIFICATION: With READ_MEMORY_OWN permission, access is granted if you own the parent space OR if the parent space is public (public_read=true). With READ_MEMORY_ANY permission, you can access any memory regardless of ownership. This is a read-only operation with no side effects and is safe to retry. Returns NOT_FOUND if the memory or its parent space does not exist.

        Args:
            id (str): The unique identifier of the memory to retrieve
            include_content (bool, optional, default=False): Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.
            include_processing_history (bool, optional, default=False): Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.

        Returns:
            Memory
        """
        params = {}
        if include_content is not None:
            params["include_content"] = include_content
        if include_processing_history is not None:
            params["include_processing_history"] = include_processing_history
        resp = await self._http.get(
            f"/v1/memories/{id}",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        return Memory.model_validate(resp.json())

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

        Permanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. Requires DELETE_MEMORY_OWN permission for memories in spaces you own (or DELETE_MEMORY_ANY for admin users to delete any memory). Side effects include permanent removal of the memory record and all associated chunk data.

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

    async def content(self, *, id: str) -> bytes:
        """Download memory content

        Streams the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check original_content_ref from the metadata endpoint to locate external content.

        Args:
            id (str): The unique identifier of the memory to download
        """
        resp = await self._http.get(
            f"/v1/memories/{id}/content",
            headers=self._headers,
        )
        raise_for_status(resp)
        return resp.content

    async def pages(self, *, id: str, start_page_index: int | None = None, end_page_index: int | None = None, dpi: int | None = None, content_type: str | None = None, max_results: int | None = None, next_token: str | None = None) -> AsyncPage[MemoryPageImage]:
        """List memory page images

        Lists extracted page-image metadata for a memory with optional filters and pagination.

        Args:
            id (str): Memory UUID
            start_page_index (int, optional): Optional lower bound for returned page indices, inclusive. The snake_case alias start_page_index is also accepted.
            end_page_index (int, optional): Optional upper bound for returned page indices, inclusive. The snake_case alias end_page_index is also accepted.
            dpi (int, optional): Optional rendition filter for page-image DPI.
            content_type (str, optional): Optional rendition filter for page-image MIME type, such as image/png. The snake_case alias content_type is also accepted.
            max_results (int, optional): Maximum number of results per page. The snake_case alias max_results is also accepted.
            next_token (str, optional): Opaque pagination token for the next page. The snake_case alias next_token is also accepted. Do not parse or construct it.

        Returns:
            Page[MemoryPageImage]
        """
        params = {}
        if start_page_index is not None:
            params["start_page_index"] = start_page_index
        if end_page_index is not None:
            params["end_page_index"] = end_page_index
        if dpi is not None:
            params["dpi"] = dpi
        if content_type is not None:
            params["content_type"] = content_type
        if max_results is not None:
            params["max_results"] = max_results
        if next_token is not None:
            params["next_token"] = next_token
        _resp = await self._http.get(
            f"/v1/memories/{id}/pages",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = ListMemoryPageImagesResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            f"/v1/memories/{id}/pages",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return AsyncPage(
            data=getattr(_page_obj, 'page_images', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=ListMemoryPageImagesResponse,
            items_field='page_images',
        )

    async def pages_image(self, *, id: str, page_index: int, dpi: int | None = None, content_type: str | None = None) -> bytes:
        """Download memory page image content

        Downloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.

        Args:
            id (str): Memory UUID
            page_index (int): 0-based page index
            dpi (int, optional): Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or content_type.
            content_type (str, optional): Optional rendition filter. MIME type of the desired page image, such as image/png. The snake_case alias content_type is also accepted.
        """
        params = {}
        if dpi is not None:
            params["dpi"] = dpi
        if content_type is not None:
            params["content_type"] = content_type
        resp = await self._http.get(
            f"/v1/memories/{id}/pages/{page_index}/image",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        return resp.content

    async def batch_create(self, *, requests: list) -> BatchMemoryResponse:
        """Create multiple memories in a batch

        Creates multiple memories in a single operation, with individual success/failure results.

        Args:
            requests (list): Array of memory creation requests.

        Returns:
            BatchMemoryResponse
        """
        _params = {'requests': requests}
        body = JsonBatchMemoryCreationRequest.model_validate(_params)
        resp = await self._http.post(
            "/v1/memories:batchCreate",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    async def batch_delete(self, *, requests: list) -> BatchMemoryResponse:
        """Delete memories in batch

        Deletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space.

        Args:
            requests (list): Array of delete selectors

        Returns:
            BatchMemoryResponse
        """
        _params = {'requests': requests}
        body = BatchMemoryDeletionRequest.model_validate(_params)
        resp = await self._http.post(
            "/v1/memories:batchDelete",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    async def batch_get(self, *, memory_ids: list, include_content: bool | None=None, include_processing_history: bool | None=None) -> BatchMemoryResponse:
        """Get multiple memories by ID

        Retrieves multiple memories in a single operation, with individual success/failure results.

        Args:
            memory_ids (list): Array of memory IDs to retrieve
            include_content (bool, optional): Whether to include the original content in the response
            include_processing_history (bool, optional): Whether to include background job processing history for each memory

        Returns:
            BatchMemoryResponse
        """
        _params = {'memory_ids': memory_ids}
        if include_content is not None:
            _params['include_content'] = include_content
        if include_processing_history is not None:
            _params['include_processing_history'] = include_processing_history
        body = BatchMemoryRetrievalRequest.model_validate(_params)
        resp = await self._http.post(
            "/v1/memories:batchGet",
            json=body.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return BatchMemoryResponse.model_validate(resp.json())

    async def _retrieve_with_body(
        self,
        body_dict: dict,
        *,
        stream: bool,
        format: Format = "ndjson",
    ) -> AsyncStream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]:
        """Execute a retrieve request with a pre-built body dict.
        """
        stream_obj = AsyncStream(
            self._http,
            method="POST",
            url="/v1/memories:retrieve",
            model=RetrieveMemoryEvent,
            format=format,
            json=body_dict,
            headers={**self._headers, "Accept": _ACCEPT[format]},
        )
        if stream:
            return stream_obj
        async with stream_obj as s:
            return [event async for event in s]

    async def retrieve(
        self,
        *,
        message: str, space_keys: list, context: list | None=None, requested_size: int | None=None, fetch_memory: bool | None=None, fetch_memory_content: bool | None=None, hnsw: HnswOptions | None=None, post_processor: PostProcessor | None=None, stream: bool = True,
        format: Format = "ndjson",
    ) -> AsyncStream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]:
        """Advanced semantic memory retrieval with JSON

        Streams semantic retrieval results with full feature support including context items and embedder weight overrides, per-space filters, and request-level HNSW tuning. Supports SSE (text/event-stream) and NDJSON (application/x-ndjson) formats.

        Args:
            message (str): Primary query/message for semantic search.
            context (list, optional): Optional context items (text or binary) to provide additional context for the search.
            space_keys (list): List of spaces to search with optional per-embedder weight overrides.
            requested_size (int, optional): Maximum number of memories to retrieve.
            fetch_memory (bool, optional): Whether to include full Memory objects in the response.
            fetch_memory_content (bool, optional): Whether to include memory content in the response. Requires fetch_memory=true.
            hnsw (HnswOptions, optional): Optional request-level HNSW tuning overrides. Advanced usage; available on POST retrieve.
            post_processor (PostProcessor, optional): Optional post-processor configuration to transform retrieval results.

        Returns:
            Stream[RetrieveMemoryEvent] | list[RetrieveMemoryEvent]
        """
        fmt = _validate_format(format)
        _params = {'message': message, 'space_keys': space_keys}
        if context is not None:
            _params['context'] = context
        if requested_size is not None:
            _params['requested_size'] = requested_size
        if fetch_memory is not None:
            _params['fetch_memory'] = fetch_memory
        if fetch_memory_content is not None:
            _params['fetch_memory_content'] = fetch_memory_content
        if hnsw is not None:
            _params['hnsw'] = hnsw
        if post_processor is not None:
            _params['post_processor'] = post_processor
        body = RetrieveMemoryRequest.model_validate(_params)
        body_dict = body.model_dump(by_alias=True, exclude_unset=True)
        return await self._retrieve_with_body(body_dict, stream=stream, format=fmt)

    async def list(self, *, space_id: str, include_content: bool | None=False, include_processing_history: bool | None=False, status_filter: str | None=None, filter: str | None=None, max_results: int | None=50, next_token: str | None=None, sort_by: str | None=None, sort_order: SortOrder | None=None) -> AsyncPage[Memory]:
        """List memories in a space

        Lists all memories within a given space. Pagination is supported via max_results and next_token (opaque). next_token is a URL-safe Base64 string without padding; do not parse or construct it. This is a read-only operation with no side effects and is safe to retry. Requires LIST_MEMORY_OWN or LIST_MEMORY_ANY permission. Returns NOT_FOUND if the specified space does not exist.

        Args:
            space_id (str): The unique identifier of the space containing the memories
            include_content (bool, optional, default=False): Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.
            include_processing_history (bool, optional, default=False): Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.
            status_filter (str, optional): Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED). The snake_case alias status_filter is also accepted.
            filter (str, optional): Optional metadata filter expression for list results
            max_results (int, optional, default=50): Maximum number of results per page (defaults to 50, clamped to [1, 500]). The snake_case alias max_results is also accepted.
            next_token (str, optional): Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it. The snake_case alias next_token is also accepted.
            sort_by (str, optional): Field to sort by (e.g., 'created_at'). The snake_case alias sort_by is also accepted.
            sort_order (SortOrder, optional): Sort direction (ASCENDING or DESCENDING). The snake_case alias sort_order is also accepted.

        Returns:
            Page[Memory]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        _params['include_content'] = include_content
        _params['include_processing_history'] = include_processing_history
        if status_filter is not None:
            _params['status_filter'] = status_filter
        if filter is not None:
            _params['filter'] = filter
        _params['max_results'] = max_results
        if next_token is not None:
            _params['next_token'] = next_token
        if sort_by is not None:
            _params['sort_by'] = sort_by
        if sort_order is not None:
            _params['sort_order'] = sort_order
        params = _params
        _resp = await self._http.get(
            f"/v1/spaces/{space_id}/memories",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(_resp)
        _page_obj = MemoryListResponse.model_validate(_resp.json())
        params.pop('next_token', None)
        _fetch_fn = lambda token: self._http.get(
            f"/v1/spaces/{space_id}/memories",
            params={**params, 'next_token': token} if token else params or None,
            headers=self._headers,
        )
        return AsyncPage(
            data=getattr(_page_obj, 'memories', []) or [],
            next_token=getattr(_page_obj, 'next_token', None),
            fetch_fn=_fetch_fn,
            response_model=MemoryListResponse,
            items_field='memories',
        )

