diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a835b1b..a1da6ce0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added +- `providers.docling_serve.timeout` (default 300 seconds), forwarded to the docling-serve client's per-request timeout. - `evaluations run --filter/-f CLAUSE`: SQL `WHERE` clause over document columns, applied to the retrieval benchmark's searches and to every capability search during QA. Recorded as `document_filter` in experiment metadata. - `mtrag_clapnq` / `mtrag_clapnq_rewrite` / `mtrag_clapnq_live` / `mtrag_clapnq_live_uncompacted` evaluation datasets: multi-turn QA with gold-prefix and live-session conversation replay, live arms with and without `EvidenceCompactionCapability`, Recall@k/nDCG@k retrieval metrics, eligibility-aware citation scoring, refusal precision/recall, per-turn tool-traffic attributes, and `citation_status` / `turn_citation_status` eval attributes. - Raw chunk metadata is now exposed to search and citation results, through `SearchResult.chunk_meta` and `Citation.chunk_meta`. For context-expanded results, the metadata is that of the anchor chunk. @@ -27,6 +28,9 @@ ### Fixed +- `create_document_from_source` closes the source adapter it builds for the call; adapters passed in through `sources` are left to their owner. +- Directory ingestion skips symlinked files resolving outside the given directory, matching `FSSource.discover`. +- A FULL rebuild no longer deletes a source-backed document before re-ingesting it: it refreshes the document in place, so the document id is preserved and a failed fetch or conversion falls back to rebuilding from stored content instead of losing the document. - `DocumentRepository.delete_all` recreated `document_items` from `DocumentItemRecord` instead of `get_document_items_arrow_schema()`, returning `picture_data` as `binary` rather than `large_binary`. - `server.json` runtime arguments are `mcp --stdio`, was `serve --mcp`. diff --git a/docs/remote-processing.md b/docs/remote-processing.md index 73cefaf9..9c5b9783 100644 --- a/docs/remote-processing.md +++ b/docs/remote-processing.md @@ -64,6 +64,7 @@ providers: docling_serve: base_url: http://localhost:5001 api_key: "" # Optional API key for authentication + timeout: 300 # Per-request timeout in seconds ``` For converter / chunker config options (chunking strategy, tokenizer, diff --git a/haiku_rag_slim/haiku/rag/client/documents.py b/haiku_rag_slim/haiku/rag/client/documents.py index 7257fcbd..e3b23df1 100644 --- a/haiku_rag_slim/haiku/rag/client/documents.py +++ b/haiku_rag_slim/haiku/rag/client/documents.py @@ -677,6 +677,7 @@ async def create_document_from_source( sources: "list[Source] | None" = None, source_id: str | None = None, metadata_provider: "MetadataProvider | None" = None, + force: bool = False, ) -> Document | list[Document]: """Create or update document(s) from a file path, directory, or URL. @@ -685,6 +686,10 @@ async def create_document_from_source( - If MD5 changed, updates the document - If no document exists, creates a new one + ``force`` skips both freshness checks so an unchanged source is re-converted, + re-chunked and re-embedded into the existing document. Internal: rebuild uses + it to refresh a document in place instead of deleting and recreating it. + If ``uri`` is provided, it overrides the URI auto-derived from the source (which is normally ``file://`` for local files or the URL for remote sources). Not supported for directory sources, which produce one document @@ -721,6 +726,14 @@ async def create_document_from_source( documents: list[Document] = [] filter = FileFilter() for child in local_path.rglob("*"): + # rglob does not recurse into symlinked directories, but it does + # yield symlinked files. Skip the ones resolving outside the + # directory the caller named, as FSSource.discover does. + if child.is_symlink(): + resolved = child.resolve(strict=False) + if not resolved.is_relative_to(local_path.resolve()): + continue + child = resolved if child.is_file() and filter.include_file(str(child)): doc = await create_document_from_source( client, @@ -730,6 +743,7 @@ async def create_document_from_source( sources=sources, source_id=source_id, metadata_provider=metadata_provider, + force=force, ) assert isinstance(doc, Document) documents.append(doc) @@ -762,76 +776,91 @@ async def create_document_from_source( source_str, sources=sources, storage_options=storage_options ) - # The stored URI is what we look up + persist by. For an explicit uri - # override, use it as-is. For a file:// input the source string is - # already canonical (URL-encoded); round-tripping via Path.as_uri() - # would double-encode any escapes like %5B. For bare paths, canonicalize. - if uri is not None: - stored_uri = uri - elif parsed_url.scheme == "file": - stored_uri = source_str - elif parsed_url.scheme == "": - stored_uri = Path(source_str).absolute().as_uri() - else: - stored_uri = source_str + # A fetcher built for this call holds its own httpx pool (HTTP, WebDAV) and + # has to be closed here. One handed in through `sources` belongs to the + # caller: the ingester keeps its sources open across jobs. + owns_fetcher = all(fetcher is not configured for configured in sources or ()) - existing_doc = await client.get_document_by_uri(stored_uri) + try: + # The stored URI is what we look up + persist by. For an explicit uri + # override, use it as-is. For a file:// input the source string is + # already canonical (URL-encoded); round-tripping via Path.as_uri() + # would double-encode any escapes like %5B. For bare paths, canonicalize. + if uri is not None: + stored_uri = uri + elif parsed_url.scheme == "file": + stored_uri = source_str + elif parsed_url.scheme == "": + stored_uri = Path(source_str).absolute().as_uri() + else: + stored_uri = source_str - # Cheap revision-based short-circuit: only worth a HEAD when we have a - # stored revision to compare against. All sources persist their native - # revision (mtime_ns for FS, ETag for S3, ETag/Last-Modified for HTTP) - # under the canonical "source_revision" metadata key. - stored_revision = ( - (existing_doc.metadata or {}).get("source_revision") if existing_doc else None - ) - if existing_doc and stored_revision: - current_revision = await fetcher.head(source_str) - if current_revision == stored_revision: + existing_doc = await client.get_document_by_uri(stored_uri) + + # Cheap revision-based short-circuit: only worth a HEAD when we have a + # stored revision to compare against. All sources persist their native + # revision (mtime_ns for FS, ETag for S3, ETag/Last-Modified for HTTP) + # under the canonical "source_revision" metadata key. + stored_revision = ( + (existing_doc.metadata or {}).get("source_revision") + if existing_doc + else None + ) + if existing_doc and stored_revision and not force: + current_revision = await fetcher.head(source_str) + if current_revision == stored_revision: + return await _refresh_doc_metadata( + client, + existing_doc, + title=title, + user_metadata=metadata, + source_metadata=None, + ) + + with logfire.span("document.fetch", uri=source_str) as fetch_span: + result = await fetcher.fetch(source_str) + fetch_span.set_attribute("bytes", len(result.body)) + fetch_span.set_attribute("content_hash", result.content_hash) + + provider_metadata = await _provider_metadata( + metadata_provider, source_id or fetcher.source_id, source_str, result + ) + user_metadata = {**metadata, **provider_metadata} + + # MD5 short-circuit: the bytes are unchanged even if the revision wasn't. + # Refresh the source-derived metadata (revision may have rolled) but skip + # convert/embed/store entirely. + if ( + existing_doc + and not force + and existing_doc.metadata.get("md5") == result.content_hash + ): + source_meta: dict = { + "content_type": result.content_type, + "md5": result.content_hash, + **result.extra_metadata, + } + if result.revision is not None: + source_meta["source_revision"] = result.revision return await _refresh_doc_metadata( client, existing_doc, title=title, - user_metadata=metadata, - source_metadata=None, + user_metadata=user_metadata, + source_metadata=source_meta, ) - with logfire.span("document.fetch", uri=source_str) as fetch_span: - result = await fetcher.fetch(source_str) - fetch_span.set_attribute("bytes", len(result.body)) - fetch_span.set_attribute("content_hash", result.content_hash) - - provider_metadata = await _provider_metadata( - metadata_provider, source_id or fetcher.source_id, source_str, result - ) - user_metadata = {**metadata, **provider_metadata} - - # MD5 short-circuit: the bytes are unchanged even if the revision wasn't. - # Refresh the source-derived metadata (revision may have rolled) but skip - # convert/embed/store entirely. - if existing_doc and existing_doc.metadata.get("md5") == result.content_hash: - source_meta: dict = { - "content_type": result.content_type, - "md5": result.content_hash, - **result.extra_metadata, - } - if result.revision is not None: - source_meta["source_revision"] = result.revision - return await _refresh_doc_metadata( + return await _ingest_fetch_result( client, - existing_doc, + result, title=title, user_metadata=user_metadata, - source_metadata=source_meta, + stored_uri=stored_uri, + existing_doc=existing_doc, ) - - return await _ingest_fetch_result( - client, - result, - title=title, - user_metadata=user_metadata, - stored_uri=stored_uri, - existing_doc=existing_doc, - ) + finally: + if owns_fetcher: + await fetcher.aclose() async def update_document( diff --git a/haiku_rag_slim/haiku/rag/client/rebuild.py b/haiku_rag_slim/haiku/rag/client/rebuild.py index 9374a2f4..9193123e 100644 --- a/haiku_rag_slim/haiku/rag/client/rebuild.py +++ b/haiku_rag_slim/haiku/rag/client/rebuild.py @@ -8,7 +8,10 @@ from typing import TYPE_CHECKING from docling_core.types.doc.document import DescriptionMetaField, PictureMeta from lancedb.pydantic import LanceModel -from haiku.rag.client.documents import check_source_accessible +from haiku.rag.client.documents import ( + check_source_accessible, + create_document_from_source, +) from haiku.rag.converters import get_converter from haiku.rag.store.compression import compress_docling_split from haiku.rag.store.engine import ChunkRecordBase @@ -807,28 +810,38 @@ async def _rebuild_full( # Try to rebuild from source if available — uses the light listing # directly, no need to load the stored content/blobs first. if light_doc.uri and check_source_accessible(light_doc.uri): - try: - # Flush pending batch before source rebuild (creates new doc) - if pending_docs: - await _flush_rebuild_batch(client, pending_docs, pending_chunks) - pending_chunks = [] - pending_docs = [] + # The refresh writes through the client, not the batch buffer, so + # anything pending has to land first. + if pending_docs: + await _flush_rebuild_batch(client, pending_docs, pending_chunks) + pending_chunks = [] + pending_docs = [] - await client.delete_document(light_doc.id) - new_doc = await client.create_document_from_source( - source=light_doc.uri, metadata=light_doc.metadata or {} + try: + # force=True: the source bytes are usually unchanged, and the + # point of a FULL rebuild is to re-convert them anyway. Updates + # in place, so a failure here cannot cost the document. + refreshed = await create_document_from_source( + client, + source=light_doc.uri, + metadata=light_doc.metadata or {}, + force=True, ) - assert isinstance(new_doc, Document) - assert new_doc.id is not None - yield new_doc.id + assert isinstance(refreshed, Document) + assert refreshed.id is not None + yield refreshed.id continue except Exception as e: - logger.error( - "Error recreating document from source %s: %s", + logger.warning( + "Rebuilding %s from source failed (%s), " + "falling back to stored content", light_doc.uri, e, ) - continue + elif light_doc.uri: + logger.warning( + "Source missing for %s, re-embedding from content", light_doc.uri + ) # Fallback: rebuild from stored content. Now we need the full # record (content + docling_pages for the round-trip write). @@ -838,8 +851,6 @@ async def _rebuild_full( if doc is None: continue assert doc.id is not None - if doc.uri: - logger.warning("Source missing for %s, re-embedding from content", doc.uri) docling_document = await converter.convert_text(doc.content, format="md") chunks = await client.chunk(docling_document) diff --git a/haiku_rag_slim/haiku/rag/config/models.py b/haiku_rag_slim/haiku/rag/config/models.py index 2fa58a8e..b122ae8d 100644 --- a/haiku_rag_slim/haiku/rag/config/models.py +++ b/haiku_rag_slim/haiku/rag/config/models.py @@ -295,6 +295,11 @@ class DoclingServeConfig(BaseModel): description="Max attempts per request across the fleet before giving up; " "each retry fails over to another instance.", ) + timeout: float = Field( + default=300, + gt=0, + description="Per-request timeout in seconds for submit, poll and result calls.", + ) circuit_breaker: CircuitBreakerConfig = Field( default_factory=lambda: CircuitBreakerConfig( failure_threshold=3, cooldown_s=30.0 diff --git a/haiku_rag_slim/haiku/rag/providers/docling_serve.py b/haiku_rag_slim/haiku/rag/providers/docling_serve.py index a14cc0fe..23abd5d9 100644 --- a/haiku_rag_slim/haiku/rag/providers/docling_serve.py +++ b/haiku_rag_slim/haiku/rag/providers/docling_serve.py @@ -97,6 +97,7 @@ class DoclingServeClient: return cls( base_urls=config.base_urls, api_key=config.api_key, + timeout=config.timeout, circuit_breaker=config.circuit_breaker, max_attempts=config.max_attempts, ) diff --git a/haiku_rag_slim/haiku/rag/store/repositories/chunk.py b/haiku_rag_slim/haiku/rag/store/repositories/chunk.py index ecfe9f49..d3005128 100644 --- a/haiku_rag_slim/haiku/rag/store/repositories/chunk.py +++ b/haiku_rag_slim/haiku/rag/store/repositories/chunk.py @@ -60,7 +60,8 @@ class ChunkRepository: """Create one or more chunks in the database. Chunks must have embeddings set before calling this method. - Use client._ensure_chunks_embedded() to embed chunks if needed. + Use haiku.rag.client.processing.ensure_chunks_embedded() to embed + chunks if needed. """ self.store._assert_writable() # Handle single chunk diff --git a/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml b/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml new file mode 100644 index 00000000..23b39e99 --- /dev/null +++ b/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '100' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - |- + Counting + Ad-hoc fetched body. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 10 + total_tokens: 10 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml b/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml new file mode 100644 index 00000000..bab50fd1 --- /dev/null +++ b/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '100' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - |- + Configured + Caller-owned body. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: Dsl+uS9hlbutIBY9XQjqvEREjbozziM9lk9WPXb2ObxQKLw7SPhWvOztATsJWbs8DLXGuZyVFrxcXTg63aQ8veLAGD0kpgG64LsQPcF3ODrJsby8c0KkugGUBT1KlZa8iacIvbyrRTzGGL68hm9RvaHzybwwwBE9gh48u0wti708qoq5W2S3vD3fqzq4HLW8TftaPKaDJ7yLmDG9qYymPPvJEj2R1Cc8mJQ3PAHBMztvxc+8Z0uNu9AMFjwTBA266SvrvFqdELwlIqA5IfQ9PMGZ7bvK3My8XoUiPKmqlrpCNwm6sMkdu+A6Jr1G7oq8d+8PPJ799rv+bAu88fkHvdnGA7ybgyC91LwqOskItrm6VXA7HADwvMaOfj3Tn6a8dw4GPPFmqzxEr8G832r6vOEzmbzvcfw8l72dvIrqCTybUYQ8YZirOnxstLvXd5i8yeiFO2YAgrwXFZ+8sA0EPGW5Q71yogG8iHMgPHgrsbwSaia5rs+tO88q0zsbABE7X/WgPMqs2rwtZHe82mucuqlUhrwJuU880qAIvSWLGrsyFpU8aQTOvAnkTLz1+1s8K/EWPL/4Jzw/sC28WtQOu8FyFb3Ezii9i9myvCyT7zqANhe88RA3vAcWEjxAtHQ886KUOhC85TtHKOe6ManzvHJlAzz/OpM8YS3Uumr/abwNT/u7HeX8PNFYmzsGUJa8KLGAPFjhPrtnxjk8On8AOnR/CbzoEzu723QLu9LbGTzLlve5a31/vO/SPDwUDpq8CoLmvMZXQLsvOK67YcOavOVjVLxM2Zs78tSDPA/htLpDJtM7Kuk1PC02MTzG9yU9UC0QO9E0Az0l9Ww7CZcpvFWzWDzvQEA7cYbtu8OtaD1tu9A7gftMPN0dpzxk3Ms72OALvZQ0Azx7QvS7O/wEvCmLmzsVqHu8WZAOve74EztvRJG78vz2vAIzhbx7oFs9ksQKOavnhDttN4C9Q3yGvMc+KbuKI5c837qEvIVuxDwvf6I73hBTPMyptDugkAU4HkQxu5M3LbwKb967EfLOO8SBbLwL+Yq8TMGdOmAzBjw+BSc8lyo9vLCJZzzHbrE7VjWZPMdpXbwSg8W3D7G4u9YyVTzXUIy8kQ8XPCPGpjwmBZW8ab9CvW/iejzA87w7322JvDiaWrzFwdw8ZXpMPQDN7jt8ElM8uKb0vN8DSDzxY5e8zyZ2O9EZYDzOIAu6WcB8PBvSSLz2pyY8Vic9vDnJgTzCTFW8z9GhPOO6BjxTfb288jWRPJW3wrtlTz28+NPAu0uDhLz6SEg7mdxwPGsXtLsBQra8fuo3OqRRabuDQoU8CZauu27PG7xDZCA8Dt7WO8Ms0Tuzzlq8yHKhu95FlLz2A7480ZAtPBBf1zk22oc5h/HpOl21GTtwPYa8GWoUPDGfhrzz0gI7UbvjOyCTwjvP9rS8fEuiPAH01rtE4XU8yk/cO9+Lsjvyx9m8BT2rO+QnWbyg+3I8aL0cvGd5yLwbd9E8wlaKvOq2gzzTPoc8YDk1PFq2ED2qDv+7rb6KvNY/LDsEWAU9+NvZO3lY8TyN1ZK8h7h7PMjQLbvi7ai6chaDPIQ087yFhce71c4uPBo5hbvC6ia8DxGjPF+fBj1dTUA8QbS8uy5ONzxT2zK8v9ObPJibWTzcw6u8B/nsPG/xv7uyvd68J5nNvM3j57rm+Li7D27UvA5MrbwckK26G18avYEjn7y8EFq8gA6ovJbj7Dyx1dY8imWfPA35Kb0MUlI8QEqfvAavtTyHV8S8i0YLvB+RG7wWwho4cE7XO+TAFz2OrIE8VTVhPDOq8Lt1C4Y7rYYdO1c8wDzizIU8VYjfOhIiED36iii7wq3YvPHnLbnJYQ29s1dBu+x8wrwDFRi8wq2VPHc2Gz37RiO9+iWdPIPppzzVkb88z1ajOpYdGTwO8ww8RXGUui6eIjvsBiK8HE6iOyC6qDwnj0e8RHxHvAq7oDteLaO7uCjiPGoSnTulZi08tv1UvHWFMz3kbju6ihfRvHWM0DxEtUM9JYMavXMJTrxxJTk9yZMqPLBSDDxra7a8f2iFOvd1DL0ftL47y70EPLnaQrxQKnG8/aeoPKaWiLoBjb88hig7PACLYDx+wCM9glehu9SxG7xy+N48eIqHvB2GxjxCJrS7ZiADvKlfULyvxz07vGKQPDRa57qY3568dqgDva6iRzt/hFI7Rzq9vOHsKzv0ELc8ngjjvEACILmbnv67X1vwO5pOmLxKXwa763C6uju5u7vfgZi6tC15u38t+jyJjBq8hOGZPLuzBjwy8Us8RMi9vKboaD2E/Qc8gmQnPFj29rwCnbM7DmfLvNutarv25Q68NqyuOvgSq7tMzHw8zAW0vHEm9TvlMYU73m3NPPP5p7vO6oe94IIzvb53HTte3uw8BVBlvOHUTjwUESS7cqV+unyvNb2llQW84/b4vNeEK72MNMA8V9UAPTfSgbzl17K87PuDvCDtCjzn/h088F+RPFwYjjvUZE67AQIvPLvHQTsaUxo9eZiIuuc4SjzeXks8X3MaPPpliLoC5987luICPWC3Uzt2m9c7cY2zuxHkiztM6iY9K5VLPY2ivjw0YH68gzEVvAz7JbyKVXQ8gxSJvNBOt7xTvPa7AGKQOtWfGT2pUj+99f53O5VQ7DzxGs875u+0u+R0Q7wGPDS8dALRvAIS7LtmJo48zlS5OfoYkLuEM+Y7wipNvP1KgLvJdD47RP90vaK6Xbu1HhO9iEKnPAyeRDq01bY6cQrOuyqQxbwBpzE8wDtqPTSVobzQQAE9bNFOO2T0nDxLoms8dCCEPCyW1TsSymi7aH3tusI/ALwWTJM84v3/vMZ4uronf5i72EJsPJoQYrv7Vqc8WonDu1sJTz21+Iw8Y9mCu/KL6bwG0yY78yfXu96OAjyKmiO9GZvcO1CyHrvtjEC889bnPCDrKbzX5vQ7+93dPElV7jucMD08FOuTPCEzqzwOJAG80ZAOvAVxBj196rE7P+IWPeoPWLz4x8M6PNlpPQNADr2UeJw6Rz0wPFfjGLrH25Y8MZYevcmHubpyKoQ8O5uMvJ80K7tqfgG9yFpSvPyoyzuu6gI9G/qnuxq7VTwZdIy8Kra7vO9zoTwpIyy9q/Z9PPcJEDh7lOq8hFF5O5xsTDx3y487yGxyu8UVH72Iqes8EmEavWEkRrsdZmi8zekKPYAMXbxHon273dAjO2alzDmzkgy9nEZGvPZ3CT3zXb+8m9ZjO93CZryDWWi83RnFu3/LWDsGa607I7xRvKO0rLxzUMm8nV6CurmXRbyXNpq8luw5PInTVDzE+7W8TR9vvK6BBL1qnmk8FmZQvJvPeLzwy/y86I6VvJjsCjyatIO87ckAvJhlzTyDcFC9TyOFvfWUB7sPIEw8Yoz3vGn8y7pwzmQ8RBUIPewYhbxxuhg9OKLJuxBFB73aWF28Em6zvGRzuDwURa681eBfPP3xUbx+iDq8Ci4uPKNmabxHujE9d7MxPA3RkTwqZhS5RX1MO8ByWLzBslg8xkUfPER6gL2oZtQ8WBlXvbZpYzulHTK8rhdVvOLiWLzGRPA7o5l7PFgC1jvG5wQ7KokJvMpEsbhqGIA8+tSovIK34TzVs0C9xrACO/v1vDsPJd87LU2jvP1i7DwJmp080RBavCnR4jwgFgU8rJylPHqdG7vnHlE8LuehPOKCIz29F0I72mCHPAuFmzxWPsq8nX4WvQuvt7wlIpA82e4OusxlcTvyDWu7eMtNvDSvUTw2uhE9cWTLPFyqf7kgEdg7jzuWvDCtnzvtVea60HGUvONCLbzOZqi8DRSuPLNEeTnYyhY8EsiEPDFx4jzx+2u85MAXPIuthbzG26G8pK6xvL8OqzrBY7E6NawhPVxPYjwU/LM8IXuHvHqADDyv9EW9Pv5QPIpnVrzsN4U7h9K/O+CvCzzmdN48IwuXvOrSg7dNxXk8O38svOK3zjsvLLq7BnnAOnE9Q7yPZHK8kce9PINZpbzIRjU9Q36VvP9aJL2bQ8s7oe8GvKDf1zwZQog8ViuOusYYqDzxchq8Hc5fvD65qrxG6sK8bciiO8macDsJ3eC8g0/RPJMusDx/E+Q6InxUPJbvFzwLWjE9SWHRPKDh1rzNKKY8yevlvI5RED1MoP08iE3rPJ44OzwnR588CwmIvKVotLyc9gs90DS+u2r9pbxYZcc7t1K+O89iS7yvUHq8UwqyvNB1jbve5Fm7JaqsvJQptjx5Z6Q8AKupvCpi/DuF4D282E68PMSkC72CltU8hlgauyBf4bsEYpk8tFQ6vRKCujtVBS08Mm+kPJBbD70pkyM8oISCPMn0rrzobRa9O6taPAbX1bxVJ+68UuHSu+aaGLy+86E7b9jIPJ6eR7s2pFU8FMOaPD65TD2pNXS61b1CPLiuljxrdkC8rc4KvKevPDx1yFu7GrCpu39OpLw0RYK8nGIovUoYk7gHD548h4upu6bq3zwTYS88BvSgvO1Ikbxa2Eo87bXYuyB9Njvg0uq6pk5ivBBkbLzu5yE9ioAcPce1fzuy66y8PWYUPSqe47v7sNS8TiM9PDNPuzp0RwM9a+bMvIDA8zsqVrI7wedIPB4rdLwa/4y8vC4WvLmGkjyLivK8xCxnPFJxCDo9Fj472HnPPJeNhzzpdZs7AzDevJOvwDv9R3k8KN+VPAdkPTrX/KS84HOIPJA+uDshccS8UuGwPBQEa7t5g7g8HLdEuqqKZTu3poE7FxEYPa0ywjtYm905CtK2PNyf+jsqnHs84holvMUc/Tswgqm88sVQO/wD4zyrjpa88S61PKlHVDuwDCy8a0f2OpIlCrty7kK87yR4PPeRYDpKIIK6CLAovFlI8ztk8PK8t5GbvEgIIL2JVaI8WAl2u9OCj7zWaU498KSjO/Gmi7zbFh28fE10PKqSzLu1FJ+89JQLulfwnruIAqY8VAYoPOlbEbylQ4u8E9kyPLfFV7yCGZw8huqfPHIYzDzETHs8ZZulvOixNb0SImU8sG3gvMI+RT1HZrs7wqnVu39xjDupCRw81UEYPLQfWbvu4MU8RcAWvA33jL3NAII7zdKWOmyNizsaHTg8q7NIvB1O8TvQxRC8Hf3lvAFBWDwR2Sa8kE/yuSVBUrzugAW8vQh8u48djzzqTCi7R4AXuxUvOrwFxDs9M9PruzjuiLxtj7o8A94pPDECnDwpxzo8QwbaPKjOSTzPMRM8AU4FPD9wyTw9Azm9omGYPIZI/bu/D9+7/se0vKbhqLwF6ri86InSPP/Z4bpP/LW87A7lO0gRqrxqeao8AL3BvFWs/ry3t5g8vRJZO/SOr7yZ5Ko8ErWUPMHrJryONFS8+xAVvQEBEzyEy3i8RqHSPH/dBLp2jwu9+lmzvP92FzxGhJq83zmWOJ2EpjzjB3I8xxi2PMp5C7ySKBI8jWTSvMqDkbxZZ588zGMVPIAOELv1yyC80O8/O8V4yDsDSbu8RL4FvdT14zvtl2c8NYA1vEVf77vBOv88s9MtvHrbNrzrKfc8sAyjPJSKJzwWB3y8TT0Eu3NDzToCvwS8LWV+O1MZxjz7Jz88LdfWu0m1C71nFz28sekiPRqbibuXHM48T72Qu9YEcjvRFAA9DKNzOqaJwLtW+Ka7ZiNFPf4JWzy0M0E8UdMgvDOOfbyvDvu802RuPFt1Ijx0HVG8d9gnPGz61TsP3qm7H+wKuxl0/zyPc8e8NYeiuyzfpDv9lY+8FW9EOTJgYLzjGC+9I/mQuizUGDv2Nwa75J0uvQNWQjzXTIi9u1wfu27km7wsQpS817nIPHWtGDw9/EK8HGyPPIqTKLz7TCQ9jT0hPFjl2Te8dnC8XHQ5O6OPxDuTAYI7erWeuq6Ck7xiPQs8OD4su1EUn7zgTwu8cmNgPfjsi7xBJdQ77iNJvSeRtjyZBYa8TC9APFxJpzx5osq6+lpyvL7SabtjcVG9n+4KvQWDCTrx6Au7I2lePIsp8DtAExU7blR/PG3dwzzWh988ZNHwO/hXhDzYJkG8EwqSPDLqojycm8a8Sxw8PG3I3Lt2Sp+88za0O6FVn7rghwg7obmPvHyQoLt2bUw7GrbBvBUZ+TyOIYk94crdvFwYcDwdOw28SOUEPNOQ4DqscJA8pV+Hu9gpTTzxuug7JQsxPYKJrzwe5/Q7+KaDuxJn9ruQiZg7VNeoO/VWcLxKXYG7otIgPFIjPr0aBIU7GnyEvMWJk7y6xgK8fVtCu795ALxykoc782F0vJTj/TwKZrg8Q/DfPJKVAb3nYrM8H+IUuwF807tFx+i7vQLKPA8Ej7yFyd057mHwuy/QPj0nARA9pLHdvFN6hbwDdsY8QFCIPFY/r7xlKL669V2bPOz+nTuYfbQ7Jbw1PI4JAr0f1pa8Q1oYPKbZfrs6PIQ8vWkDvGXqFbzXqlG7ws/qN5LOojycBA08v5grPOHpAb3Lurc7sqAjvU13yzvIdEK7xCOmvE5eXruuIve744EDPMLtRTwlI5U7ityDvJ1mSruWBTO8msJePN6E2btcxJ4807jHPI7Dcjyo9oE8Pl2OPOGaNzxIyHw86g8HPO181LxlqoQ6JZccvEEDgrxPWL476WiWvIGYSDzcFpW8PTQfPLzsSDy7bHw9rVinu+XOyjofcFI8sUA5PA/heLzXIgW9QVsvvDO/xLwOE7S8SNfTOXcuO7zaq8Q8sCOUPFYTRDx/DBE8pXThvBN/3LwLSD68hm8tvCVICj3zUL+8vP43PDB9qjqzQFi8LYasO2C8gbtJuM08G/3FPKRvQTwdekq84xP+OzwaObxoqRu91Us0vZ25dLvwOtq6zp3APMx/KTuV0oE8x98QPPh3BbxSJhq8lMTYPAzqEL0LVhK9gLOWvHWdbrzXeES9DgTtPD9wDrs9KgC8h8s5PE9rHjzge3C8Qu2iu8JTjDy55F08Oj3sPCmqK70mUe87mgtXvZy3rzw8kKc8h50uPJKBdjs3VEq7ke0dvEZHVzypjJA8/tzvPKmnV7wW3+28Aq4CvckATbzZHWW89Q8dO3qOgTzld/26dyo4vVUIxbvrpt+7VQY5PPr16zyeDjg7BeiuuzbKqzr4JHw8DDnEPKw1dzwZipy8JKs2vIx86zwNuZk859NvPTcgrzwFDdG7USoBvWzvrrzNmXW6kzamPAYxAz3mIO04L8YHO35XETzrWco71UHKO4E04zugNJS8Icg4vMKHjDyJjJO8frPUO1YHeTo4mB47WxslPDBEIzuxxBa8FsW0vC5rFLxjCKI8sNUqPbaI3Tx6fri6CHyPPL7pnjw/rIU8BK2RuYujjjwNvz68zf7rPJ6EqjvRD1K8LQEPvP8S97x7riC9t5ypPGELw7w6iWm7AcnQO0DUlzyzd/w8xuUVveMh0DxDtqG8a9fxuocrnbuwQFa8qfgyvXSXwDw43jw75HVCvOMXMTxm4ca8ASMiO6wg2DyukSk8oX4HPbyZJb00Rqm8ylC9u/Fg+bzpMn06sRfPvIVfLbzhOJ+8JDZHvNfg4zsqxrq8niglO0mBfLlrh8O7mgNHu+hDJrwc5+g8z+G6u+g4Aj0+Ek+8940JO8UqmbwuUoA8xdw+vDqNIj0lQoW8CB/mvC5XBz2B4Vw8djwSvScQhLvo6IO8GnrPPCXe/Lw/xXU7Ey/uPBpdZD1YFdU7p05QOdICUjumS4w8XuokPGY0xrwKKeE525+fO4FN6rvxf6I8V1+5OnWw2DtE0T+8keyqu+3D6Ls01km8jG+iPNKqRbykeoS8tRSWPIBD1DqLamm7iSQUPf4QBr3R7uG74yHyPAsY+bwG74a80c4pPEFnbjyONOq8G7wXve86CjyXGxS8DNyhPDebWrsHL4E8sPKDvEcTHjxLOO07ckpivBiijrzMuCc8jbNiOs3GnTu+nRK9B8GIvA2R07tXkPC62rDyPEbAobyHDRC8wnxLO+jzWDy85bs8geWgO0HS97tqjyC8GYAKut+sHDzopNw7YG4wvIDNZjx3kMa8krCiPJkjhTzI4MG8mpTZPG9NjLtoT6Q8Mk+LPNTsYzvmhIK8wLPRPHlzhTwQRzY7gcHaO2XGCTyz76673HKHvMZAqjz69766Tm9oPBckDbxySTs816jkO9F+2ryVlPq7qJDuPIdbFj0Gp2E8vUk4PGut5byus4885fdyPAiLa7zFpgE9/o41PLItWbuP7IC8h6+xPIvQqjtf9+e74rumvORZLTtt9y49qjj2O1y2Y7qvTrM7eazJvJPW9DxrbYc7RCanvKGTbz08UWS8cLSqvAw4orsLd6A8h2u1O/Rav7zdtUO8ka9ePKY6pTx//ky8f17au5lfK7sRnSS8W3I9O/qi3zs1q3y8l4TyPHJXfjywCUA7WqvUPKcbejvFrdU7yz7nO3FBvjscoX48GbWyPEvUgTx8eAi82quFvDbBhDwEvyM6nTsWvP874zvu+HU8Du4WPPnWkzzYVtA7Zk1FvdPyED0X2PW73HoKO5bBojuNW2U8scF2PAlIojxzAfQ69S6/PEdPu7x0eHC6OissO5vfaz1bpjY8VGKgu+z53TwAFJs7R6iAvCgTsrwMWQW8b0snPEeMd7zR2qm8X+ugO5q9Lrz1isy8QummvEZoUTwSJR06tK/FPItHCLyywYO8bEARPHKmEDyW5G08UPiqvE+no7xr9dS8pkmFPIgJcjvVV9i8/2ToO0eR0rwqTYq8GZgnO4bfJrzbBqA8NOIwvEIZ57rbTZi8RXlXvLpzDj3Crxi9gIOgvCSYBr0K9/y8XjvlPGNAv7v3Rsy6tP3tPHd5wbwBS8k7pfNOu9+N9rwdg867lmTSPIXp1Lwphrq7PDGDPOeeJL29DOI7bm65PJV5PDxi+Py8ICBEPD/opTxMNto7CMfevGT23DxUM5g8X7jGvCpNpTwUo706gsxSvFcIQr0OwnG8FQxFPArGkbys3R88AaoavOjp67wlxwQ8T4UXPIosDr0BwnK9Xl78OhKbmjsZlA68n7aCvMJDrLwtpg89AN1fuuM5Bz1gen+85NUSPK4o4zyw3IS8eSBNvB2fKbwMfLi8itAqvMFsjTwtkIA7BX4rPMZR9zyDPjG9jNWau2+5tLzQ8Hi8NBdOPFtJubk2cZS8v4IauL6lXbz5dew7QnEIvUI8fzu0ijC8bPiBvCfIXzziqZY8Fxk9vY29Pb0J4AK8WlnNu7nSorsGZgQ9xMYqOkDDmDwAoze8SSvAPLndnjyp5iW9lROjOScQ2TtXbvS8hTzGudxwSrsShdy8qY85PW0MDzrm35s6ofdrPFCQlTu1OIK8livwu9PRljw8ZoS7Ap2lvFs8FbzgOqG8sUKfu76nnbzxOEu8t+CZPBvJ1zwmSXo8a1BRO+vbGLy0Pf282dmmvFE+NzwdRzQ8mAzTuvpCpjwIkpG8QUgsPBlEH7yxozK6OHaZvL6ilTwnNr08bbkKPZdMZjwSWge8wZtkvCHQEzwCoiU8vjLSvAGTETuHECC8ddqSu97Fs7vpTuI87J9fPC1FrDv/cka8VYc4vHGbjbycrjQ8bberOwNINTysvQW9HmfZPGXwNLw0Reo5+hIXPDuj47oplDi8ziLuvIa/xrwpCee87LTPvPIs/TwVBT89n0rmOzWvM7x0FxY9sMaSvE3bGTy8q5E8XrIwueZhEj3/z2U8buWcPD4v4ju/qdk8H49QPGX/kjyNhr+8inSxvF5WjbsI74A7hOfSvKmeJr3bKx68sIGHPMqrhbxgOWY82jSlPK773DxW/Oq7w5SIvHBxejx53My85LgBvXoooby89+I7EP3cvCqxAzxAaHi882CkOhjGJD3f6QQ8Sac/vO/xjjxTtA27nXa7vPM+2TwIQWI8WrkbvL5hGz0CnSY8TGTAu+UMpjrruFA80mwoOdEWlLwOaci7bp7FvGdWJL3hknc8i82dO3/1Xzt9TYK8luiVvJXFvrzz/Kc8FMyUvD/cu7zzGQO9OpK5PJdZIDonZKY8IfIyPeNvOz0tlDA8uJIBu5+ZkrnXL3W8CSITPeWUobsz/6+7MvyhPKeTDTw/QO+7p9bCPHPANTsXEM27VtwIvJ+ojru9L0w8zeFyPN2lDbwQMRY8tuDHvIen3zy0Tnk8U5ipPN2j9jun0228X3YIu12xhjwG5pw89XHyu/Plwbyk7768ViWOvHeNILzZN8a7gGXXvE5iRDwSKWG7DIgZPErrmjwkfTe40HoNPbXCUrxmVbE8UocCPOm28jyN5WE8AdGzOwqltTzrAFQ8YYr7OwxRQDyWRU88PPA+PLJnNztO3a28iAX3PHipl7zUPik8DdeKO2VNnzzvi1u64hpUPM2Z5ryC6gm8c0ievFIFhzti9Nc8yz5xvO5Tu7ysfZ68EpuQPFh59rvzLJa7fQvqO4GEpjpVu7Y7iwO+PEWxzTwtcZs8enA6vEjpF73xwj48rGeuPA6A+zwMzE68Ms1CvDE3M72BMIG8lmmSvArMAz1FpiW9T1eBPLQoAr3FsiW96JGSO21cJbyblBM8Txy4PD5NLzycXoi8DCwYvGPAprzKv2e9tZecPF+WXDv0ct67sVuKO+ifFj2/8sA6NGJCPMkZnTrHMRy8caoSPVmPirwZ4xY6mFWXvIDoIDykYPG7OqDGPBvJGT2nrmc9RvyKOo2DTTy5Luu8fxeFvJ2CpzxwvpG8W1gvu/uQAL13fpQ8oamYPF0lU7yMNVe8/anMuhJ9C7yVIHA8+Jt7vKBDqLy7eF28IUCiPKcrLzzrwv06z9UgvK9C/bymrqs8tWzrPNHZobx/65c7g+UqvGgIpzz/Bha9I2jjOnBf2rwtL1c8F6TMPNmOPrwHYfs8uanNO9fzjzyYyZ27KDMSvLSoozxSpGk8bwDGO6Id+7t+/Yy8hukVPe2juLurHM28ze/IO/UOErwGk/a8uwiYPLJ22Tttccq6r7fnvLjRdTvghU67T8MtvKiAnzyI5F48zUHFPGpBmryt1OE8IFHWPOzWjTzhcoy78KZ1PLwAJjyqk787fQ2JO9b+YjxeAwm8z590PPglXTsGB3C7X2RdPSmg/LpNKxC845yzvO8b6bxYIAK9H4pVPDvqorrBxAm9VCT0O71Y/jvZmGy8APuUvDWYqLodULW7eQDbvKsIGL22k5i5w7SfPOY2Fz0OHg88L/EiPNN5AT04whK8B+TAPPpAJTtleSc7AUdiPA4MDzwmSgA828R0vMFKkbs9jlA8fAaePEVLFL2Ff6E86CXju2APEr2EqRe8nnLJPGHFNDu7iv07v+zLu7as9Tyud5q7UJjLvFnMJbyMksM8+e4CvQZVFL0PdYk6TsbDPI89hDpP6Cs8w/UvPOY3kLyADWC8pEeDvAOonLyoBgy980l/uuUfCLyGfum8Z9O2PMB1VzwzYRo8SUtRPHOvULxCs2a8YbnDPI0J4LsAa6A8z5c4vMeXujuUVTW8maG+OkjbuLw5spA7+8rnPIkkFDzq0bY8kFpeuqXgKLwZRcg8DlY4PdbKPDy9ztS8dRuGPDr7OrzEUwI8ioRlvGzEiDzqmR69z2APvQPSqLwjKDc7V5gyvGjmojq1APa6HCCrO8usRbxaBEM803/EuwxbDbwTexc9uKLoOkn04TriStS8mt25unvBJL0ROl682oSqOjpT0LtWNRw9v0nwO7hKTD1JSWE76QWVPM8G8TpDOg+7mnmLvIU0xzreKRc8Bxa9PPXKzbx76wC9aojRuybJ4rmXh+I7A9PnvN6syDxY+Pg8DZyYvKqeFb2enQ+98e4wPFPOfzvFXNO6iSdyOzfnkTtNx988jD85PTlUQLxzF867J+/XuyZ4SbxEJOY8mzARvAZnvryzKxc9n1BFu8Lauzu7j428Y9iGOyj9DDzzglk8UWiSvM1/2ryjOaO79QwyPObS9rzYKzU87Cs9O3a4ubwOcCi8Mj6kvPEBkbtmEY28YKxAOrVID71axyG8Bey+O98o1jujjFG8uIgsvRIdqbvVix881/7hu8yNgTuG5a08k0FgPL7L0bsl3+06x4jfumCarTrUGz28KNsivEfO9bpSWZ2864hIO6TKHj05shq88RdZPNI3+jtw5p+8IYQWvYKoCb1deqa8FFfAvOq1VDsyd9M8RgpDPHoNHT2BIF+8hb3HubqRlDwPZYq8btZaPOReczr2Zyu8a0+Hu6vfCb30jse8GZPBvFkAgry4nEC8ovaiuxlFr7yNWFc9KeGDPGoisjsLuEA78WuzuuoQFD3NGam7x3oEPFCxFDxXNg+9QRYmu3FpQj1RKrW8P1R4PGrtOT31ud28GhYyu5spt7w4iLI8aZHIOwKixjyle6A7VtDNO5ENOL1dlKG5cD9Hu9ZPiT3AaRI9RpcWvCiG8Tx5mPm55zeVPMbAgLyZUpq8x/40vVgmGjwM3Lo7DCCXu5vEMLsXM228kXiCPN7JCjw7wo+70c2TOmST7jzQkwY8kosXvepql7tfueE7qxcpvIKl8bw3Dv87fKynO+mJELyfeLO8RB0XPIxPEruftRm84OX9O87n/TzpJJy74qTJvNdv4zyqbv+8sFBCvAoJmjwhceQ8OHkRvCii3zyg5PG75sg8PMgQxTyu55o8XvLXunmEHr3hbUA7xuVyOyqqC71Vo1y8R1mgPB9qIbwsnLW73h6TOmZPv7oSJNO8FFSkO0UsGL3Hz7w8CTQ2O1JOIryQqFe7joYHO8e0Trw6FGG8FpidvL7PIDzUM0y84nubvLGI3Dw7UF49QF64PMfJJLzA+k+65sKIPGVWbDuU/jS46FmQvFV8IbxS5uY8PxCMPGwXTDvIgNI8l8BmPDdJJzpC8dC656CSvNTErbxYZx05UjLIPBm3CD3YHtc8ktOnuosXTby8Kvu7BW5ZvDB01zz3MFq72IaVO4f/l7yINFO7pXjsvBLIuLt7Y5E7KV9hvKQQbjyMTta8ue/iut+Ivbxgt6i8KMvCOq4yqDupK7Q8pPMUvaVBSTzmB6G8BDsmPeqDPby9L6o8QEOROpMveDzvqmg8tFumvHcz5zzCQ9O7xJWMPLd/qrxmXSm7djXDvPbmMzzaOle7NQ4qOlu9A72iHiA7m9q+O0Ldl7p9gKw8P5GHu5AJCT0T+b67XRE5vak+5btaJI48VTAUPFipLzuTrOw83jnEOwm92jzD7Hi73b2LPA9CqzyLNr27Ggpxux/6LTzJ16k7vCGhPNESqDxTKSM8dKIYvDdQD7vhm5e63VPkPBHBNjxteWA99mgrveq6WrzHcVA7BJ9NO400P7xNtV+8NV8WPMyCszyS8aA77mQyO7f9jDzaG9w8pG4WPMESB71qVUK8jZqwPBt0krrWwb+85FZRPI3JcDzAwIg84kwPvMgCgzxP8nQ8ducfPEc24zvVkY484vL7u8aYFLt0lSO8zKsQPDEzkzqeaVo8Z6zxu8OwJryKcVS8cdENPILHrjyqi88623ZHvFaslryluGO8Pe7FvLz/Ar0CAIU76m/zOU8yajoyqg68TWp8vHd+azwoOTC9QROWO7h9jTzIJDK8AC2bvPg6hLwhFfw8CN6uuu6bpTsrSuY5U7iyvLZeorwK/OS7blxCvA4EobtEcny9FaBJvUHjZrx8yTc8DW7lvAR1KLw1poi8WbRau+Ib5bz1ydm8m5zqPA== + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 8 + total_tokens: 8 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml b/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml new file mode 100644 index 00000000..791ad797 --- /dev/null +++ b/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '86' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Inside the tree. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 5 + total_tokens: 5 + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '86' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Inside the tree. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 5 + total_tokens: 5 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_falls_back_to_stored_content.yaml b/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_falls_back_to_stored_content.yaml new file mode 100644 index 00000000..ff7f37ab --- /dev/null +++ b/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_falls_back_to_stored_content.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '111' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Content that will vanish by rebuild time. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 9 + total_tokens: 9 + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '111' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Content that will vanish by rebuild time. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 9 + total_tokens: 9 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_is_logged_and_skipped.yaml b/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_is_logged_and_skipped.yaml deleted file mode 100644 index 6ff93083..00000000 --- a/tests/cassettes/test_rebuild/test_rebuild_full_source_failure_is_logged_and_skipped.yaml +++ /dev/null @@ -1,42 +0,0 @@ -interactions: -- request: - headers: - accept: - - application/json - accept-encoding: - - gzip, deflate, zstd - connection: - - keep-alive - content-length: - - '111' - content-type: - - application/json - host: - - localhost:11434 - method: POST - parsed_body: - encoding_format: base64 - input: - - Content that will vanish by rebuild time. - model: qwen3-embedding:4b - uri: http://localhost:11434/v1/embeddings - response: - headers: - content-type: - - application/json - transfer-encoding: - - chunked - parsed_body: - data: - - embedding: 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 - index: 0 - object: embedding - model: qwen3-embedding:4b - object: list - usage: - prompt_tokens: 9 - total_tokens: 9 - status: - code: 200 - message: OK -version: 1 diff --git a/tests/test_client.py b/tests/test_client.py index e6e379a2..2b29a146 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -19,6 +19,7 @@ from haiku.rag.client.documents import ( ) from haiku.rag.config import Config from haiku.rag.embeddings import EmbedderWrapper +from haiku.rag.ingester.sources.base import FetchResult from haiku.rag.store.compression import decompress_json from haiku.rag.store.models.chunk import Chunk from haiku.rag.store.models.document import Document @@ -444,6 +445,32 @@ async def test_client_create_document_from_directory(temp_db_path): assert not any("unsupported.xyz" in uri for uri in uris) +@pytest.mark.vcr() +async def test_directory_ingest_skips_symlinks_escaping_the_tree(temp_db_path): + """A symlinked file resolving outside the named directory is not ingested; + one resolving inside it is. Matches FSSource.discover.""" + import os + + async with HaikuRAG(temp_db_path, create=True) as client: + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) / "tree" + outside = Path(temp_dir) / "outside" + root.mkdir() + outside.mkdir() + + (root / "real.txt").write_text("Inside the tree.") + (outside / "secret.txt").write_text("Outside the tree.") + os.symlink(outside / "secret.txt", root / "escape.txt") + os.symlink(root / "real.txt", root / "inside_link.txt") + + result = await client.create_document_from_source(root) + + assert isinstance(result, list) + uris = sorted(uri for doc in result if (uri := doc.uri)) + assert not any("secret" in uri or "escape" in uri for uri in uris) + assert any("real.txt" in uri for uri in uris) + + @pytest.mark.vcr() async def test_client_create_document_from_url(temp_db_path): """Test creating a document from a URL.""" @@ -2408,6 +2435,74 @@ def test_check_source_accessible_file_uri(tmp_path): assert check_source_accessible((tmp_path / "gone.txt").as_uri()) is False +class _CountingSource: + """A real Source over one in-memory document that counts its closes.""" + + def __init__(self, uri: str, body: bytes) -> None: + self.source_id = "counting" + self.supported_extensions = None + self.max_file_size = None + self._uri = uri + self._body = body + self.closes = 0 + + def supports(self, uri: str) -> bool: + return uri == self._uri + + async def head(self, uri: str) -> str | None: + return "v1" + + async def aclose(self) -> None: + self.closes += 1 + + async def fetch(self, uri: str) -> "FetchResult": + import hashlib + + return FetchResult( + uri=uri, + body=self._body, + content_type="text/markdown", + content_hash=hashlib.md5(self._body).hexdigest(), + revision="v1", + ) + + def discover(self, since=None, *, known_uris=None): + raise NotImplementedError + + +@pytest.mark.vcr() +async def test_adhoc_source_is_closed_after_ingest(temp_db_path, monkeypatch): + """An ad-hoc fetcher is built for this one call, so this call has to close + it — HTTP and WebDAV adapters hold an httpx connection pool.""" + from haiku.rag.ingester import sources as sources_module + + uri = "https://example.com/counting.md" + fetcher = _CountingSource(uri, b"# Counting\n\nAd-hoc fetched body.") + monkeypatch.setattr( + sources_module, "resolve_adhoc_fetcher", lambda *a, **kw: fetcher + ) + + async with HaikuRAG(temp_db_path, create=True) as client: + doc = await client.create_document_from_source(uri) + assert not isinstance(doc, list) + + assert fetcher.closes == 1 + + +@pytest.mark.vcr() +async def test_configured_source_is_not_closed_after_ingest(temp_db_path): + """A source handed in by the caller (the ingester's long-lived pool) is not + ours to close: closing it would tear down the pool mid-run.""" + uri = "https://example.com/configured.md" + fetcher = _CountingSource(uri, b"# Configured\n\nCaller-owned body.") + + async with HaikuRAG(temp_db_path, create=True) as client: + doc = await client.create_document_from_source(uri, sources=[fetcher]) + assert not isinstance(doc, list) + + assert fetcher.closes == 0 + + def _bbox_doc(*, with_page_image: bool, pages: tuple[int, ...] = (1,)): """DoclingDocument with one paragraph per page, each carrying a bbox. diff --git a/tests/test_config.py b/tests/test_config.py index 3bcdef6d..19383411 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,3 +1,5 @@ +from pathlib import Path + import pytest import yaml @@ -557,3 +559,21 @@ def test_get_config_initialises_lazily_then_reuses(monkeypatch): first = config_module.get_config() assert isinstance(first, AppConfig) assert config_module.get_config() is first + + +# Every YAML config shipped in the repo has to load. These are what users copy. +_EXAMPLE_CONFIGS = sorted( + (Path(__file__).resolve().parent.parent).glob("**/*.yaml.example") +) + + +def test_example_configs_are_present(): + """Guard against the glob silently matching nothing.""" + assert _EXAMPLE_CONFIGS + + +@pytest.mark.parametrize( + "path", _EXAMPLE_CONFIGS, ids=lambda p: p.parent.name + "/" + p.name +) +def test_example_config_validates(path: Path): + AppConfig.model_validate(yaml.safe_load(path.read_text()) or {}) diff --git a/tests/test_docling_serve_client.py b/tests/test_docling_serve_client.py index 175ed53e..655f9f6c 100644 --- a/tests/test_docling_serve_client.py +++ b/tests/test_docling_serve_client.py @@ -474,11 +474,13 @@ def test_from_config_wires_retry_and_breaker(): ds = config.providers.docling_serve ds.base_url = "http://cfg-n:5001" ds.max_attempts = 7 + ds.timeout = 42.0 ds.circuit_breaker = CircuitBreakerConfig(failure_threshold=9, cooldown_s=90.0) for component in (DoclingServeConverter(config), DoclingServeChunker(config)): client = component.client assert client._max_attempts == 7 + assert client.timeout == 42.0 assert client._breaker_config.failure_threshold == 9 assert client._breaker_config.cooldown_s == 90.0 diff --git a/tests/test_rebuild.py b/tests/test_rebuild.py index bcc41f4b..01c29a55 100644 --- a/tests/test_rebuild.py +++ b/tests/test_rebuild.py @@ -523,7 +523,10 @@ async def test_rebuild_full_with_accessible_source(temp_db_path): """FULL rebuild re-ingests from source when the URI is accessible. Covers the main path in _rebuild_full (source-accessible branch): the - document is deleted and re-created from its URI, producing a new ID. + document is refreshed in place, keeping its ID. The source bytes are + unchanged since ingestion, so this also pins that the refresh bypasses the + revision and MD5 short-circuits instead of returning the document + untouched. """ async with HaikuRAG(temp_db_path, create=True) as client: with tempfile.TemporaryDirectory() as temp_dir: @@ -540,15 +543,17 @@ async def test_rebuild_full_with_accessible_source(temp_db_path): async for doc_id in client.rebuild_database(mode=RebuildMode.FULL) ] - # Original doc was deleted and a new one created; the old ID - # must not appear, and exactly one new ID must have been yielded. - assert original_id not in processed_ids - assert len(processed_ids) == 1 + assert processed_ids == [original_id] - new_doc = await client.get_document_by_id(processed_ids[0]) - assert new_doc is not None - assert new_doc.uri == source_path.as_uri() - assert "Fresh content" in new_doc.content + refreshed = await client.get_document_by_id(original_id) + assert refreshed is not None + assert refreshed.uri == source_path.as_uri() + assert "Fresh content" in refreshed.content + + # The chunks table is recreated at the top of FULL, so the refresh + # must have written new chunks for the document to stay searchable. + chunks = await client.chunk_repository.get_by_document_id(original_id) + assert chunks async def test_rebuild_title_only_reads_structural_title(temp_db_path): @@ -622,14 +627,14 @@ async def test_rebuild_title_only_handles_llm_failure(temp_db_path, monkeypatch) @pytest.mark.vcr() -async def test_rebuild_full_source_failure_is_logged_and_skipped( +async def test_rebuild_full_source_failure_falls_back_to_stored_content( temp_db_path, monkeypatch ): - """FULL rebuild logs-and-continues when re-ingesting from source fails. + """A failed source refresh must never cost the document. - Covers _rebuild_full's `except Exception` branch: when - create_document_from_source raises, the doc is skipped (no yield) and - the error is logged. Regression guard against silent failures. + Covers _rebuild_full's `except Exception` branch: when the refresh raises, + the document keeps its stored row and is rebuilt from stored content, so it + is still readable and still searchable afterwards. """ import logging @@ -644,22 +649,31 @@ async def test_rebuild_full_source_failure_is_logged_and_skipped( assert not isinstance(original, list) assert original.id is not None - # Force the source rebuild branch to raise. - async def failing_create(*args, **kwargs): + # Force the source refresh to raise. + async def failing_refresh(*args, **kwargs): raise RuntimeError("simulated ingestion failure") - monkeypatch.setattr(client, "create_document_from_source", failing_create) + monkeypatch.setattr( + rebuild_module, "create_document_from_source", failing_refresh + ) - with capture_logs(rebuild_module.logger, logging.ERROR) as records: + with capture_logs(rebuild_module.logger, logging.WARNING) as records: processed_ids = [ doc_id async for doc_id in client.rebuild_database(mode=RebuildMode.FULL) ] - assert processed_ids == [] + assert processed_ids == [original.id] + + survivor = await client.get_document_by_id(original.id) + assert survivor is not None + assert "Content that will vanish" in survivor.content + + chunks = await client.chunk_repository.get_by_document_id(original.id) + assert chunks + assert any( - "Error recreating document from source" in rec.getMessage() - for rec in records + "falling back to stored content" in rec.getMessage() for rec in records ) @@ -1412,12 +1426,10 @@ async def test_rebuild_full_flushes_pending_before_source_rebuild(temp_db_path): async for doc_id in client.rebuild_database(mode=RebuildMode.FULL) ] - # The content-path document keeps its id and must survive the - # flush that precedes the source re-ingest; the source document - # is replaced by a freshly ingested one with a new id. - assert content_doc.id in processed - assert source_doc.id not in processed - assert len(processed) == 2 + # Both documents keep their ids: the content-path one must survive + # the flush that precedes the source refresh, and the source one is + # refreshed in place. + assert sorted(processed) == sorted([content_doc.id, source_doc.id]) assert await client.store.documents_table.count_rows() == 2