diff --git a/docs/v2/client_options.rst b/docs/v2/client_options.rst index 22842a12..d77249b2 100644 --- a/docs/v2/client_options.rst +++ b/docs/v2/client_options.rst @@ -1,8 +1,14 @@ V2 Client Options ################# -Base Parameters -=============== -.. autoclass:: mindee.v2.client_options.base_parameters.BaseParameters +Base Product Parameters +======================= +.. autoclass:: mindee.v2.client_options.base_product_parameters.BaseProductParameters + :members: + :inherited-members: + +Base Search Parameters +====================== +.. autoclass:: mindee.v2.client_options.base_search_parameters.BaseSearchParameters :members: :inherited-members: diff --git a/docs/v2/index.rst b/docs/v2/index.rst index 2f3aed59..6530183f 100644 --- a/docs/v2/index.rst +++ b/docs/v2/index.rst @@ -10,6 +10,7 @@ V2 Utilities ./mindee_http ./parsing/index ./product/index + ./search diff --git a/docs/v2/mindee_http.rst b/docs/v2/mindee_http.rst index 5037d5c8..3a77d915 100644 --- a/docs/v2/mindee_http.rst +++ b/docs/v2/mindee_http.rst @@ -6,9 +6,3 @@ Mindee API V2 .. autoclass:: mindee.v2.mindee_http.mindee_api_v2.MindeeAPIV2 :members: :inherited-members: - -Response Validation V2 -====================== -.. automodule:: mindee.v2.mindee_http.response_validation_v2 - :members: - :inherited-members: diff --git a/docs/v2/parsing/search.rst b/docs/v2/parsing/search.rst index f220952e..5f42fec2 100644 --- a/docs/v2/parsing/search.rst +++ b/docs/v2/parsing/search.rst @@ -28,9 +28,20 @@ Search Models :members: :inherited-members: +Search RAG Document +################### +.. autoclass:: mindee.v2.parsing.search.search_rag_document.SearchRagDocument + :members: + :inherited-members: + +Search RAG Documents +#################### +.. autoclass:: mindee.v2.parsing.search.search_rag_documents.SearchRagDocuments + :members: + :inherited-members: + Search Response ############### .. autoclass:: mindee.v2.parsing.search.search_response.SearchResponse :members: :inherited-members: - diff --git a/docs/v2/search.rst b/docs/v2/search.rst new file mode 100644 index 00000000..f5b3a24e --- /dev/null +++ b/docs/v2/search.rst @@ -0,0 +1,26 @@ +V2 Search +######### + +Model Search Parameters +======================= +.. autoclass:: mindee.v2.search.models.model_search_parameters.ModelSearchParameters + :members: + :inherited-members: + +Model Search Response +===================== +.. autoclass:: mindee.v2.search.models.model_search_response.ModelSearchResponse + :members: + :inherited-members: + +RAG Document Search Parameters +============================== +.. autoclass:: mindee.v2.search.rag_documents.rag_document_search_parameters.RagDocumentSearchParameters + :members: + :inherited-members: + +RAG Document Search Response +============================ +.. autoclass:: mindee.v2.search.rag_documents.rag_document_search_response.RagDocumentSearchResponse + :members: + :inherited-members: diff --git a/mindee/cli.py b/mindee/cli.py index 51a29983..73664a6e 100644 --- a/mindee/cli.py +++ b/mindee/cli.py @@ -63,9 +63,9 @@ def main() -> None: """Run the Command Line Interface. The unified ``mindee`` binary exposes V2 inference commands and the - ``search-models`` utility at the root, with all V1 product commands - wrapped under a ``v1`` subcommand — mirroring the canonical - ``mindee-api-dotnet`` CLI. + ``search-models`` and ``search-rag-docs`` utilities at the root, with + all V1 product commands wrapped under a ``v1`` subcommand — mirroring + the canonical ``mindee-api-dotnet`` CLI. Pass ``--verbose`` (or ``-v``) to enable diagnostic logging; repeat the flag (``--verbose --verbose``) for debug-level output. diff --git a/mindee/v2/client_options/base_search_parameters.py b/mindee/v2/client_options/base_search_parameters.py index 2fe06c53..e6007626 100644 --- a/mindee/v2/client_options/base_search_parameters.py +++ b/mindee/v2/client_options/base_search_parameters.py @@ -31,9 +31,9 @@ def get_request_parameters(self) -> dict[str, str | list[str]]: """ data: dict[str, str | list[str]] = {} - if self.page is not None: + if self.page is not None and self.page > 0: data["page"] = str(self.page) - if self.per_page is not None: + if self.per_page is not None and self.per_page > 0: data["per_page"] = str(self.per_page) return data diff --git a/mindee/v2/commands/__init__.py b/mindee/v2/commands/__init__.py index aa51ebe8..5959c3b3 100644 --- a/mindee/v2/commands/__init__.py +++ b/mindee/v2/commands/__init__.py @@ -6,6 +6,7 @@ from mindee.v2.commands.ocr_command import OcrCommand from mindee.v2.commands.output_type import OutputType from mindee.v2.commands.search_models_command import SearchModelsCommand +from mindee.v2.commands.search_rag_documents_command import SearchRagDocumentsCommand from mindee.v2.commands.split_command import SplitCommand __all__ = [ @@ -18,5 +19,6 @@ "OcrCommand", "OutputType", "SearchModelsCommand", + "SearchRagDocumentsCommand", "SplitCommand", ] diff --git a/mindee/v2/commands/cli_parser.py b/mindee/v2/commands/cli_parser.py index bae32429..028fb48b 100644 --- a/mindee/v2/commands/cli_parser.py +++ b/mindee/v2/commands/cli_parser.py @@ -16,6 +16,7 @@ from mindee.v2.commands.extraction_command import ExtractionCommand from mindee.v2.commands.ocr_command import OcrCommand from mindee.v2.commands.search_models_command import SearchModelsCommand +from mindee.v2.commands.search_rag_documents_command import SearchRagDocumentsCommand from mindee.v2.commands.split_command import SplitCommand from mindee.v2.error.mindee_api_v2_error import MindeeAPIV2Error @@ -51,7 +52,7 @@ class MindeeParser: * V2 inference commands are exposed at the root level (``classification``, ``crop``, ``extraction``, ``ocr``, ``split``). - * The ``search-models`` utility is also at the root. + * The ``search-models`` and ``search-rag-docs`` utilities are also at the root. * V1 product commands are wrapped under a ``v1`` subcommand. """ @@ -60,6 +61,7 @@ class MindeeParser: _client_factory: Callable[[str | None], Client] _inference_commands: dict[str, BaseInferenceCommand] _search_models_command: SearchModelsCommand + _search_rag_documents_command: SearchRagDocumentsCommand def __init__( self, @@ -76,6 +78,7 @@ def __init__( cmd.name: cmd for cmd in _build_inference_commands() } self._search_models_command = SearchModelsCommand() + self._search_rag_documents_command = SearchRagDocumentsCommand() if parsed_args is None: self._build_parser() self.parsed_args = self.parser.parse_args() @@ -95,27 +98,33 @@ def call_parse(self) -> int: self.parser.print_help() return 1 try: - if cmd == "v1": - v1_parser = V1MindeeParser(parsed_args=self.parsed_args) - v1_parser.call_parse() - return 0 - if cmd == self._search_models_command.name: - return self._search_models_command.execute( - self.parsed_args, self._client_factory - ) - inference_command = self._inference_commands.get(cmd) - if inference_command is None: - raise ValueError(f"Unknown command: {cmd}") - return inference_command.execute(self.parsed_args, self._client_factory) + return self._execute_command(cmd) except MindeeAPIV2Error as exc: return _report_api_key_error(exc, "V2", "MINDEE_V2_API_KEY") except MindeeAPIError as exc: return _report_api_key_error(exc, "V1", "MINDEE_API_KEY") + def _execute_command(self, cmd: str) -> int: + """Execute a parsed subcommand.""" + if cmd == "v1": + v1_parser = V1MindeeParser(parsed_args=self.parsed_args) + v1_parser.call_parse() + return 0 + if cmd == self._search_models_command.name: + return self._search_models_command.execute( + self.parsed_args, self._client_factory + ) + if cmd == self._search_rag_documents_command.name: + return self._search_rag_documents_command.execute( + self.parsed_args, self._client_factory + ) + + inference_command = self._inference_commands.get(cmd) + if inference_command is None: + raise ValueError(f"Unknown command: {cmd}") + return inference_command.execute(self.parsed_args, self._client_factory) + def _build_parser(self) -> None: - # ``--verbose`` / ``-v`` are pre-consumed in ``mindee.cli.main`` - # (mirroring the .NET ``args.Contains("--verbose")`` pattern); we - # still register them here for ``--help`` discoverability. self.parser.add_argument( "-v", "--verbose", @@ -129,6 +138,7 @@ def _build_parser(self) -> None: cmd.register(subparsers) self._search_models_command.register(subparsers) + self._search_rag_documents_command.register(subparsers) v1_parser = subparsers.add_parser( "v1", diff --git a/mindee/v2/commands/search_models_command.py b/mindee/v2/commands/search_models_command.py index c8bd465e..acd4465e 100644 --- a/mindee/v2/commands/search_models_command.py +++ b/mindee/v2/commands/search_models_command.py @@ -2,6 +2,7 @@ from collections.abc import Callable from mindee.v2.client import Client +from mindee.v2.search.models.model_search_parameters import ModelSearchParameters _AVAILABLE_MODEL_TYPES: list[str] = [ "extraction", @@ -74,9 +75,11 @@ def execute( ) -> int: """Run the search and print the result.""" client = client_factory(getattr(parsed_args, "api_key", None)) - response = client.search_models( - name=getattr(parsed_args, "name", None), - model_type=getattr(parsed_args, "model_type", None), + response = client.search( + ModelSearchParameters( + name=getattr(parsed_args, "name", None), + model_type=getattr(parsed_args, "model_type", None), + ) ) if getattr(parsed_args, "raw_json", False): print(response.raw_http) diff --git a/mindee/v2/commands/search_rag_documents_command.py b/mindee/v2/commands/search_rag_documents_command.py new file mode 100644 index 00000000..82744138 --- /dev/null +++ b/mindee/v2/commands/search_rag_documents_command.py @@ -0,0 +1,76 @@ +from argparse import ArgumentParser, Namespace, _SubParsersAction +from collections.abc import Callable + +from mindee.v2.client import Client +from mindee.v2.search.rag_documents.rag_document_search_parameters import ( + RagDocumentSearchParameters, +) + + +class SearchRagDocumentsCommand: + """Builder + handler for the V2 ``search-rag-docs`` subcommand. + + Mirrors ``Mindee.Cli.Commands.V2.SearchRagDocumentsCommand`` from the + .NET SDK. + """ + + name = "search-rag-docs" + description = "Search available RAG documents for a given model." + + def register(self, subparsers: _SubParsersAction) -> ArgumentParser: + """Register this command on the given subparsers action.""" + parser = subparsers.add_parser( + self.name, + help=self.description, + description=self.description, + ) + parser.add_argument( + "-k", + "--api-key", + dest="api_key", + help="Mindee V2 API key.", + required=False, + default=None, + ) + parser.add_argument( + "-m", + "--model-id", + dest="model_id", + help="Filter by model ID", + required=True, + ) + parser.add_argument( + "-f", + "--filename", + dest="filename", + help="Filter by file name partial match (case insensitive).", + required=False, + default=None, + ) + parser.add_argument( + "-r", + "--raw-json", + dest="raw_json", + action="store_true", + help="Whether to output the raw JSON response.", + ) + return parser + + def execute( + self, + parsed_args: Namespace, + client_factory: Callable[[str | None], Client], + ) -> int: + """Run the search and print the result.""" + client = client_factory(getattr(parsed_args, "api_key", None)) + response = client.search( + RagDocumentSearchParameters( + model_id=parsed_args.model_id, + filename=getattr(parsed_args, "filename", None), + ) + ) + if getattr(parsed_args, "raw_json", False): + print(response.raw_http) + else: + print(response) + return 0 diff --git a/mindee/v2/parsing/inference/inference_active_options.py b/mindee/v2/parsing/inference/inference_active_options.py index 4c894aef..1fd46e9e 100644 --- a/mindee/v2/parsing/inference/inference_active_options.py +++ b/mindee/v2/parsing/inference/inference_active_options.py @@ -17,25 +17,16 @@ class InferenceActiveOptions: """Active options for the inference.""" raw_text: bool - """ - Whether the Raw Text feature was activated. - When this feature is activated, the raw text extracted from the document is returned in the result. - """ + """Extract the full text content from the document as strings, and fill the ``raw_text`` attribute.""" polygon: bool - """ - Whether the polygon feature was activated. - When this feature is activated, the bounding-box polygon(s) for each field is returned in the result. - """ + """Calculate bounding box polygons for all fields, and fill their ``locations`` attribute.""" confidence: bool """ - Whether the confidence feature was activated. - When this feature is activated, a confidence score for each field is returned in the result. + Boost the precision and accuracy of all extractions. + Calculate confidence scores for all fields, and fill their ``confidence`` attribute. """ rag: bool - """ - Whether the Retrieval-Augmented Generation feature was activated. - When this feature is activated, the RAG pipeline is used to increase result accuracy. - """ + """Enhance extraction accuracy with Retrieval-Augmented Generation.""" text_context: bool """ Whether the text context feature was activated. diff --git a/mindee/v2/parsing/inference/rag_metadata.py b/mindee/v2/parsing/inference/rag_metadata.py index c9af29b5..52e0a4f4 100644 --- a/mindee/v2/parsing/inference/rag_metadata.py +++ b/mindee/v2/parsing/inference/rag_metadata.py @@ -5,6 +5,7 @@ class RAGMetadata: """Metadata about the RAG operation.""" retrieved_document_id: str | None + """The UUID of the matched document used during the RAG operation.""" def __init__(self, raw_response: StringDict): self.retrieved_document_id = raw_response["retrieved_document_id"] diff --git a/mindee/v2/parsing/search/base_search_response.py b/mindee/v2/parsing/search/base_search_response.py index 3d0eb1f5..3be4057a 100644 --- a/mindee/v2/parsing/search/base_search_response.py +++ b/mindee/v2/parsing/search/base_search_response.py @@ -9,7 +9,7 @@ class BaseSearchResponse(CommonResponse, ABC): """Base class for search responses.""" pagination: PaginationMetadata - """Pagination metadata for the search results.""" + """Pagination metadata.""" def __init__(self, raw_response: StringDict) -> None: super().__init__(raw_response) @@ -17,7 +17,7 @@ def __init__(self, raw_response: StringDict) -> None: @abstractmethod def body_lines(self) -> list[str]: - """List of strings representing the search response.""" + """Lines composing the response-specific body (header + items).""" def __str__(self) -> str: """ diff --git a/mindee/v2/parsing/search/model_webhook.py b/mindee/v2/parsing/search/model_webhook.py index d4d3bd88..01065a07 100644 --- a/mindee/v2/parsing/search/model_webhook.py +++ b/mindee/v2/parsing/search/model_webhook.py @@ -1,5 +1,5 @@ class ModelWebhook: - """Model webhook information.""" + """Information about a model's webhook.""" id: str """ID of the webhook.""" diff --git a/mindee/v2/parsing/search/pagination_metadata.py b/mindee/v2/parsing/search/pagination_metadata.py index 14e628e3..81292b7c 100644 --- a/mindee/v2/parsing/search/pagination_metadata.py +++ b/mindee/v2/parsing/search/pagination_metadata.py @@ -1,23 +1,20 @@ class PaginationMetadata: - """Pagination metadata.""" + """Pagination metadata associated with searches.""" per_page: int """Number of results per page.""" page: int """1-indexed page number.""" total_items: int - """Total number of items.""" + """Total items.""" total_pages: int """Total number of pages.""" - total_items_unfiltered: int | None - """Total number of items, including unfiltered results.""" def __init__(self, server_response: dict) -> None: self.per_page = server_response["per_page"] self.page = server_response["page"] self.total_items = server_response["total_items"] self.total_pages = server_response["total_pages"] - self.total_items_unfiltered = server_response.get("total_items_unfiltered") def __str__(self) -> str: return ( diff --git a/mindee/v2/parsing/search/search_model.py b/mindee/v2/parsing/search/search_model.py index 97be009c..ed036a8d 100644 --- a/mindee/v2/parsing/search/search_model.py +++ b/mindee/v2/parsing/search/search_model.py @@ -6,13 +6,13 @@ class SearchModel: """Individual model information.""" id: str - """Model ID.""" + """ID of the model.""" name: str - """Model name.""" + """Name of the model.""" model_type: str - """Model type.""" + """Type of the model.""" webhooks: list[ModelWebhook] - """Webhooks associated with the model.""" + """List of webhooks associated with the model.""" def __init__(self, server_response: StringDict) -> None: self.id = server_response["id"] @@ -23,3 +23,15 @@ def __init__(self, server_response: StringDict) -> None: if "webhooks" in server_response else [] ) + + def __str__(self) -> str: + """String representation of the model.""" + return f":Name: {self.name}\n:ID: {self.id}\n:Model Type: {self.model_type}" + + def to_list_string(self) -> list[str]: + """Return a list of display lines for multi-line rendering.""" + return [ + f":Name: {self.name}", + f":ID: {self.id}", + f":Model Type: {self.model_type}", + ] diff --git a/mindee/v2/parsing/search/search_models.py b/mindee/v2/parsing/search/search_models.py index c7c907d6..86c135dc 100644 --- a/mindee/v2/parsing/search/search_models.py +++ b/mindee/v2/parsing/search/search_models.py @@ -2,7 +2,7 @@ class SearchModels(list[SearchModel]): - """List of models.""" + """List of search models.""" def __init__(self, raw_response: list[dict]) -> None: super().__init__([SearchModel(item) for item in raw_response]) @@ -19,6 +19,5 @@ def __str__(self) -> str: lines.append(f"* :Name: {model.name}") lines.append(f" :ID: {model.id}") lines.append(f" :Model Type: {model.model_type}") - lines.append(f" :Webhooks: {len(model.webhooks)}") return "\n".join(lines) + "\n" diff --git a/mindee/v2/parsing/search/search_response.py b/mindee/v2/parsing/search/search_response.py index cba1baec..2f232ab4 100644 --- a/mindee/v2/parsing/search/search_response.py +++ b/mindee/v2/parsing/search/search_response.py @@ -1,5 +1,15 @@ +from mindee.v2.parsing.search.pagination_metadata import PaginationMetadata from mindee.v2.search.models.model_search_response import ModelSearchResponse class SearchResponse(ModelSearchResponse): - """Deprecated: use `ModelSearchResponse` instead.""" + """Models search response.""" + + @property + def pagination_metadata(self) -> PaginationMetadata: + """Pagination metadata (Obsolete).""" + return self.pagination + + @pagination_metadata.setter + def pagination_metadata(self, value: PaginationMetadata) -> None: + self.pagination = value diff --git a/mindee/v2/product/extraction/params/extraction_parameters.py b/mindee/v2/product/extraction/params/extraction_parameters.py index 7940a890..08e378ec 100644 --- a/mindee/v2/product/extraction/params/extraction_parameters.py +++ b/mindee/v2/product/extraction/params/extraction_parameters.py @@ -51,13 +51,13 @@ def get_request_parameters(self) -> dict[str, str | list[str]]: if self.data_schema is not None: data["data_schema"] = str(self.data_schema) if self.rag is not None: - data["rag"] = data["rag"] = str(self.rag).lower() + data["rag"] = str(self.rag).lower() if self.raw_text is not None: - data["raw_text"] = data["raw_text"] = str(self.raw_text).lower() + data["raw_text"] = str(self.raw_text).lower() if self.polygon is not None: - data["polygon"] = data["polygon"] = str(self.polygon).lower() + data["polygon"] = str(self.polygon).lower() if self.confidence is not None: - data["confidence"] = data["confidence"] = str(self.confidence).lower() + data["confidence"] = str(self.confidence).lower() if self.text_context is not None: data["text_context"] = self.text_context return data diff --git a/mindee/v2/search/models/model_search_parameters.py b/mindee/v2/search/models/model_search_parameters.py index 063a6f68..ee89c9e1 100644 --- a/mindee/v2/search/models/model_search_parameters.py +++ b/mindee/v2/search/models/model_search_parameters.py @@ -23,9 +23,9 @@ def get_request_parameters(self) -> dict[str, str | list[str]]: params = super().get_request_parameters() - if self.name is not None: + if self.name: params["name"] = self.name - if self.model_type is not None: + if self.model_type: params["model_type"] = self.model_type return params diff --git a/mindee/v2/search/models/model_search_response.py b/mindee/v2/search/models/model_search_response.py index 549adbf2..bc73000b 100644 --- a/mindee/v2/search/models/model_search_response.py +++ b/mindee/v2/search/models/model_search_response.py @@ -14,5 +14,5 @@ def __init__(self, raw_response: StringDict) -> None: self.models = SearchModels(raw_response["models"]) def body_lines(self) -> list[str]: - """List of strings representing the search response.""" + """Lines composing the response-specific body (header + items).""" return ["Models", "######", str(self.models)] diff --git a/mindee/v2/search/rag_documents/rag_document_search_parameters.py b/mindee/v2/search/rag_documents/rag_document_search_parameters.py index 02ace8a7..351e3ff4 100644 --- a/mindee/v2/search/rag_documents/rag_document_search_parameters.py +++ b/mindee/v2/search/rag_documents/rag_document_search_parameters.py @@ -20,12 +20,16 @@ class RagDocumentSearchParameters(BaseSearchParameters[RagDocumentSearchResponse _slug: ClassVar[str] = "rag-documents" _response_class: type[RagDocumentSearchResponse] = RagDocumentSearchResponse + def __post_init__(self) -> None: + if not self.model_id: + raise ValueError("model_id is required in RagDocumentSearchParameters") + def get_request_parameters(self) -> dict[str, str | list[str]]: params = super().get_request_parameters() params["model_id"] = self.model_id - if self.filename is not None: + if self.filename: params["filename"] = self.filename return params diff --git a/mindee/v2/search/rag_documents/rag_document_search_response.py b/mindee/v2/search/rag_documents/rag_document_search_response.py index 77e48c09..911ea971 100644 --- a/mindee/v2/search/rag_documents/rag_document_search_response.py +++ b/mindee/v2/search/rag_documents/rag_document_search_response.py @@ -4,7 +4,7 @@ class RagDocumentSearchResponse(BaseSearchResponse): - """RAG documents search response.""" + """RAG Documents search response.""" rag_documents: SearchRagDocuments """Paginated list of matching RAG documents.""" @@ -14,5 +14,5 @@ def __init__(self, raw_response: StringDict) -> None: self.rag_documents = SearchRagDocuments(raw_response["rag_documents"]) def body_lines(self) -> list[str]: - """List of strings representing the search response.""" - return ["RAG Documents", "################", str(self.rag_documents)] + """Lines composing the response-specific body (header + items).""" + return ["RAG Documents", "#############", str(self.rag_documents)] diff --git a/tests/v2/test_cli.py b/tests/v2/test_cli.py index 2dc74f31..13ee6693 100644 --- a/tests/v2/test_cli.py +++ b/tests/v2/test_cli.py @@ -26,16 +26,20 @@ def parser() -> MindeeParser: from mindee.v2.commands.search_models_command import ( SearchModelsCommand, ) + from mindee.v2.commands.search_rag_documents_command import ( + SearchRagDocumentsCommand, + ) p._inference_commands = {cmd.name: cmd for cmd in _build_inference_commands()} p._search_models_command = SearchModelsCommand() + p._search_rag_documents_command = SearchRagDocumentsCommand() p._client_factory = _default_client_factory p._build_parser() return p def test_top_level_subcommands_registered(parser: MindeeParser): - """All V2 inference subcommands + search-models + v1 are reachable.""" + """All V2 inference subcommands + search commands + v1 are reachable.""" expected = { "classification", "crop", @@ -43,6 +47,7 @@ def test_top_level_subcommands_registered(parser: MindeeParser): "ocr", "split", "search-models", + "search-rag-docs", "v1", } actions = [a for a in parser.parser._actions if a.dest == "cmd"] @@ -154,6 +159,26 @@ def test_search_models_rejects_invalid_model_type(parser: MindeeParser): parser.parser.parse_args(["search-models", "--model-type", "nope"]) +def test_search_rag_documents_flags(parser: MindeeParser): + ns = parser.parser.parse_args( + [ + "search-rag-docs", + "--api-key", + "dummy", + "--model-id", + "model-1", + "--filename", + "invoice", + "--raw-json", + ] + ) + assert ns.cmd == "search-rag-docs" + assert ns.api_key == "dummy" + assert ns.model_id == "model-1" + assert ns.filename == "invoice" + assert ns.raw_json is True + + def test_v1_group_dispatches_to_v1_product(parser: MindeeParser): """The `v1` group preserves the existing V1 product subcommand shape.""" ns = parser.parser.parse_args( @@ -213,6 +238,24 @@ def fake_execute(args, factory): assert captured == {"name": "inv", "model_type": "extraction"} +def test_search_rag_documents_dispatches_to_search_command( + monkeypatch, parser: MindeeParser +): + captured = {} + + def fake_execute(args, factory): + captured["model_id"] = args.model_id + captured["filename"] = args.filename + return 0 + + monkeypatch.setattr(parser._search_rag_documents_command, "execute", fake_execute) + parser.parsed_args = parser.parser.parse_args( + ["search-rag-docs", "-m", "model-1", "-f", "invoice"] + ) + parser.call_parse() + assert captured == {"model_id": "model-1", "filename": "invoice"} + + def test_v1_group_delegates_to_v1_mindee_parser(monkeypatch, parser: MindeeParser): """`v1` command instantiates the V1 MindeeParser with the parsed args.""" seen = {}