| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| README.md | 2026-10-21 | 19.5 kB | |
| v1.4.3 source code.tar.gz | 2026-10-21 | 3.1 MB | |
| v1.4.3 source code.zip | 2026-10-21 | 3.2 MB | |
| Totals: 3 Items | 6.3 MB | 0 | |
Security
HTML is no longer converted to PDF with LibreOffice (#418)
Since 1.2.4, parse_document() and process_document_complete() sent .html, .htm and .xhtml files to the Office path when the parser was MinerU (and PaddleOCR, from its addition in 1.2.10). That path converts them to PDF with LibreOffice. The conversion fetches the remote URLs the page references, such as images and stylesheets. It also embeds local images the page references, such as file:// <img> sources, into the PDF that is then parsed. Ingesting an untrusted HTML file therefore made outbound requests and put referenced local images into the parsed PDF. BatchParser, the batch CLI, process_documents_batch() and process_documents_with_rag_batch() never picked up HTML. process_folder_complete() did so only when HTML extensions were added to file_extensions or SUPPORTED_FILE_EXTENSIONS.
- HTML is now accepted only by parsers with a native
parse_htmlentry point. Among the built-in parsers, that is Docling. MinerU, PaddleOCR and custom parsers withoutparse_htmlraise aValueErrorbefore any conversion. The error tells you how to select Docling:RAGAnythingConfig(parser="docling"), thePARSER=doclingenvironment variable, or--parser doclingon the CLI (#418, [#420]). Parser.convert_office_to_pdf()(and therefore the MinerU and PaddleOCRparse_office_doc()) andMineruParser.parse_document()(which used to try HTML as a PDF) reject HTML as well.PaddleOCRParser.parse_document()already refused HTML as an unsupported format and now raises the same Docling error.- Docling's HTML backend does not fetch the page's images. Their caption or alt text is indexed as text (#417).
- HTML is recognised by file extension. HTML content saved under an Office extension, such as
.docor.xls, still goes to LibreOffice, which makes the same remote requests and embeds the same local images.
Upgrade note: to keep parsing HTML, install Docling (pip install docling; it is not part of raganything[all]) and set RAGAnythingConfig(parser="docling") or PARSER=docling. If you ingested untrusted HTML with MinerU or PaddleOCR, LibreOffice requested the URLs that HTML referenced, and the local images it referenced were embedded in the converted PDF and parsed with it.
What's new
HTML documents with Docling (#405, [#417], [#418])
With parser="docling", HTML files now go through RAG-Anything end to end. BatchParser, the batch CLI, process_documents_batch() and process_documents_with_rag_batch() now find .html, .htm and .xhtml files. parse_document() and process_document_complete() send these files to DoclingParser.parse_html. In 1.4.2, batches skipped HTML, and process_document_complete() with Docling failed with Unsupported office format: .html (#405, @er-s-an).
process_folder_complete()still filters onSUPPORTED_FILE_EXTENSIONS, which does not list HTML. Passfile_extensions=[".html", ".htm", ".xhtml"].- Pictures without image data, which includes every
<img>from Docling's HTML backend, are now skipped. Previously they were indexed as the literal text[Image processing failed: ]. Docling emits the caption, or the alt text when there is no caption, as a separate text item (#417).
Streaming answers from VLM-enhanced image queries (#400)
With a vision model configured, aquery() and aquery_vlm_enhanced() with stream=True used to ignore the flag whenever retrieved images were sent to the vision model, and returned a complete string. They now call vision_model_func(..., stream=True) and return its async iterator unchanged. Non-streaming calls do not pass stream and behave as before. Queries that retrieve no images keep falling back to LightRAG, which streams (@IlyaKhalafi).
Incremental RAG batches finish incomplete ingestion (#393)
process_documents_with_rag_batch(..., incremental=True) only ingested the files it had just parsed. If a file parsed successfully but then failed to index, every later run skipped it as unchanged, so it was never indexed. Files that parsing skips are now checked against the current workspace's doc_status (@dafyy321-pixel).
- Missing, failed, pending or otherwise incomplete documents go through
process_document_complete()again. Their document ID comes from the parse cache. If the workspace has no cached result, the file is parsed once to find the ID. - A document is skipped only when both its text and its multimodal processing are complete, and
force_multimodal_reprocessis not set. Skipped documents get therag_resultsentry{"status": "skipped", "processed": False}and are counted in the newskipped_rag_files.on_batch_completealso receives askippedcount.failed_rag_filesnow counts only entries whosestatusis"failed". - When the text retry succeeds and the multimodal work had already finished, that work is skipped only if its completion flag survived. A
handlingdocument keeps the flag. Afailed,pendingorprocessingdocument loses it when LightRAG rewrites itsdoc_status(on the default JSON doc-status storage), so its multimodal processing runs again (documented in [#417]). - Six ingestion-only options are no longer passed to the parser or included in the incremental parse signature:
display_stats,split_by_character,split_by_character_only,doc_id,file_nameandforce_multimodal_reprocess. If a 1.4.2 incremental RAG batch passed any of them with a value other thanNone, its files are reparsed once.
Concurrent ingestion keeps each document's multimodal context (#391)
A RAGAnything instance shares its modal processors across calls. Several documents can be ingested at once through one instance, for example by process_folder_complete() with more than one worker, or by concurrent process_document_complete() / insert_content_list() calls. A document's table, image or equation prompts could then contain surrounding text from another document, and both calls still succeeded. Now process_document_complete(), insert_content_list() and process_document_complete_lightrag_api() each keep their own content source, which their child tasks inherit. A modal processor used directly via set_content_source() behaves as before. During ingestion the processor's content_source attribute is no longer overwritten, so it no longer holds the last ingested document afterwards (@dafyy321-pixel).
Behaviour changes
- HTML requires Docling (#418). MinerU, PaddleOCR and custom parsers without
parse_htmlraiseValueErrorfor.html,.htmand.xhtmlfiles inparse_document()andprocess_document_complete()instead of converting them with LibreOffice. As in 1.4.2,BatchParserand the batch CLI skip HTML with these parsers, and a file passed explicitly is logged as "Unsupported file type". See Security. - Streaming image queries need a vision function that takes
stream(#400). Withstream=True,vision_model_funcis now called withstream=True. A function that accepts neitherstreamnor**kwargsraisesTypeError; previously the call returned a string. The README examples already take**kwargs. Non-streaming calls are unaffected. - Empty Docling documents fail (#417). An empty DOCX (or an empty HTML body or list) used to become a single empty
tableblock, and an empty text item, such as an empty<title>, became an empty text block. An empty DOCX was therefore ingested with one empty table. Empty bodies, groups and text items now yield no content, so such a document makesparse_document()andprocess_document_complete()raiseValueError: Parsing failed: No content was extracted.BatchParserstill reports the parse as successful (0 blocks), and the RAG phase ofprocess_documents_with_rag_batch()counts the file as failed. An empty list inside a non-empty document no longer adds an empty table. max_workersbelow 1 is rejected (#409, [#417]).process_folder_complete()resolvesmax_workersfrom its argument or fromconfig.max_concurrent_files(MAX_CONCURRENT_FILES). If the value is below 1, it raisesValueError("max_workers must be greater than zero")before initialising LightRAG. Previously0hung and a negative value failed later (#409, @IlyaKhalafi).BatchParser(max_workers=...)raises the same error. Previously it loggedBatch processing failedand returned with every file in neithersuccessful_filesnorfailed_files, and the batch CLI with--workers 0exited 0. This also applies toprocess_documents_batch()andprocess_documents_with_rag_batch(), which build aBatchParser, and to the CLI's--workersoption (#417).
Fixes
Query & VLM
- VLM-enhanced queries label each retrieved image with its real media type (
image/png,image/gif,image/webp,image/bmporimage/tiff), detected from the image bytes. Previously every image was sent asimage/jpeg, and strict providers reject a PNG labelled as JPEG. The new helperraganything.image_signature.image_mime_type()accepts exactly the files thatlooks_like_image()(#387) accepts (#389, @er-s-an). - With a vision model configured,
mode="bypass"queries now go straight to LightRAG, once, asonly_need_contextandonly_need_promptalready did. Previously a bypass query made two model calls, the first without the caller's system prompt, and a streaming bypass raisedTypeError(#402, @IlyaKhalafi). aquery_with_multimodal()now reads query content with the same helpers that ingestion uses (#398, @IlyaKhalafi):- string image captions and footnotes, used when the image file is missing, are no longer joined one character at a time;
- tables given as
table_body(MinerU),table_dataortextreach the table prompt, where previously onlytable_datawas read, and a list of rows is rendered as a Markdown table instead of a Python list; - list captions of tables and equations are joined into text instead of shown as a Python list;
- equations given as
textorequationinstead oflatexare no longer empty.
Batch
- A non-incremental
BatchParserrun now removes the incremental manifest entries of the files it is about to reparse, before any worker starts. Previously, a later incremental run could reuse output that had been overwritten. This happened after a non-incremental run with different options (for examplelang), or after a reparse that failed partway. Entries for other files are kept, dry runs leave the manifest unchanged, and no manifest is created when none exists (#388, @er-s-an). process_documents_with_rag_batch()now runs the batch parse in an executor thread throughprocess_documents_batch_async(). Previously it blocked the event loop (#411, @IlyaKhalafi).- An incremental manifest that is not valid UTF-8 is now treated like malformed JSON: a warning and a full reparse. Previously the batch crashed with
UnicodeDecodeError(#414, @IlyaKhalafi). process_documents_with_rag_batch(..., dry_run=True)returns the parse plan without initialising LightRAG or ingesting anything.rag_resultsis empty and all RAG counters are zero. Previously a "dry run" initialised LightRAG and passed every selected file, together withdry_run, toprocess_document_complete(), which parsed and indexed it (#415, @IlyaKhalafi).
Parsing
- A Markdown image whose title is in single quotes or parentheses, such as
or), now becomes an image block with the alt text and the title as its captions, as a double-quoted title already did. Previously the reference stayed literal text. Only real image files qualify, as in [#387] (#407, @IlyaKhalafi). .txtand.mdfiles that start with a UTF-16 byte-order mark (Notepad's "Unicode", Excel's "Unicode Text") are decoded as UTF-16. Previously they were read one byte per character, with NUL bytes in every chunk. The legacy fallback, which still tries GBK first, now tries Windows-1252 before Latin-1, so curly quotes, dashes and€decode correctly unless the file also happens to be valid GBK. UTF-8 (with or without BOM) and GBK files decode as before.EnhancedMarkdownConverter.convert_file_to_pdf()gets the same Windows-1252-before-Latin-1 order but no UTF-16 detection (#403, @L4XB).raganything.omml_extractor(the standalone OMML-to-LaTeX utility; the built-in parsers do not call it): an equation array (m:eqArr, used for systems of equations and cases) becomes\begin{aligned} … \\ … \end{aligned}. Previously its rows were run together. An empty delimiter is now dropped. Previously it became a literal.(#404, @L4XB).- Docling: picture captions and footnotes are now read from Docling's
captionsandfootnotesreferences, as lists like MinerU's. The old code read acaptionkey that Docling never sets. Pictures whose image data cannot be decoded are skipped, and empty text items, such as an empty<title>, are dropped (#417). - Docling:
.txtand.mdfiles are now read with the shared text parser, as MinerU and PaddleOCR already did.BatchParseralready selected these files for Docling batches, butDoclingParser.parse_document()raisedUnsupported file format(#417).
Multimodal & media
- Models often return single-backslash LaTeX such as
\fracor\betainside their JSON.json.loadsread\fand\bas form-feed and backspace characters, which then went into entity summaries and the vector store. A form feed or backspace followed by a letter is now restored to\for\b.\t,\nand\r(as in\theta,\nabla,\rho) are left as they are, because they cannot be told apart from real whitespace (#396, @porkedchop). - Video: speech outside the scenes kept for visual analysis is now kept as audio-only timeline rows. This covers speech before the first retained scene, between retained scenes and after the last one, including speech in scenes dropped by the minimum scene duration (5 seconds by default). Both
generate_description_only()andgenerate_chunk_sections()keep it, and neither makes extra vision calls. Previouslygenerate_description_only()lost all of this speech, andgenerate_chunk_sections()kept only speech after the last retained scene, without an error. A video with speech but no retained scene now yields audio-only sections instead of the fallback section. The duration in thegenerate_description_only()summary now includes speech after the last retained scene (#395, @dafyy321-pixel).
Install
- The
audio,videoandallextras now requireav<19. A fresh install resolved faster-whisper 1.2.1 (its latest release) with PyAV 19, which removed anav.open()argument faster-whisper uses, so every transcription failed: the audio processor raisedTypeError, and videos were ingested without a transcript, with only a warning. The runtime install hints saypip install faster-whisper "av<19"too (#420).
Docs
- The
vision_model_funcexamples in the README (EN/ZH),examples/andreproduce/now label a single image with its real media type viaraganything.image_signature.image_mime_type(). They used to hard-codedata:image/jpeg. If you copied one of these examples, update your copy (#417). docs/batch_processing.mdnow documents:- how incremental and non-incremental runs interact (#388);
- incremental RAG retries,
skipped_rag_files, and when multimodal work is repeated (#393, [#417]); dry_run=True(#415);- HTML support and how each entry point treats HTML (#405, [#417], [#418]);
- that
BatchParsermax_workersmust be at least 1 (#417). - The README (EN/ZH) says that HTML requires Docling and explains why. The
register_parserdocstring documents the optionalparse_htmlandHTML_FORMATShooks for custom parsers (#418). - The README (EN/ZH) now:
- gives the Docling install command (
pip install docling, not included inraganything[all]); - shows how a parser is actually selected (
RAGAnythingConfig(parser=...),PARSER,--parser). The examples used to passparser="mineru"per call, which never selected a parser and with MinerU raisedTypeError; - documents streaming VLM queries and the
**kwargsrequirement forvision_model_func(#400); - no longer shows the LiteWrite banner (#420).
env.exampleanddocs/batch_processing.mdsayMAX_CONCURRENT_FILES/max_workersmust be at least 1 (#420).
Build & tests
- Dependencies: the
audio,videoandallextras addav<19(#420). Otherwise Requires-Dist, the extras and Requires-Python>=3.10are the same as in 1.4.2, andlightrag-hku<1.5stays. - The wheel adds one module,
raganything/document_context.py(#391). - Each fix comes with regression tests. The suite grows from 684 to 898 tests, all passing on Python 3.10 (LightRAG 1.4.15) and Python 3.12 (LightRAG 1.4.16).
- Version set to 1.4.3 (#419).
Validation
Beyond the unit suites (898 tests, run from source and against the installed wheel on Python 3.10 with LightRAG 1.4.15 and Python 3.12 with LightRAG 1.4.16, plus CI on Linux 3.10–3.12), this release was checked as follows.
Packaging
twine check --strictpasses.- Compared with 1.4.2, the wheel adds only
raganything/document_context.py. The metadata changes only the version andav<19in theaudio/video/allextras. - Fresh installs on Python 3.10 and 3.12 resolve
lightrag-hku1.4.16, andpip checkis clean. [video]now resolves PyAV 18 and a generated speech clip transcribes. Without the pin it resolved PyAV 19 and transcription failed.
Clean Linux end-to-end (python:3.12-slim, wheel only; live gpt-4o-mini for LLM and VLM, text-embedding-3-small via OpenRouter):
- A 4-page content list with text, table, equation and image answers from all three modalities, and its text chunks keep their
page_idx. - Query/VLM:
- a retrieved PNG reaches the vision model labelled
image/png; - a streaming image query returns an async iterator;
bypassmakes one LLM call;- the
aquery_with_multimodalprompt contains the table rows and the whole caption. - 4 concurrent inserts: each image's vision context holds only its own document's text. 1.4.2 leaked another document's text into 3 of 4.
- Batch:
- after an LLM outage, the next incremental run retries the failed documents to
processed, and a rerun makes 0 model calls; dry_run=Truemakes 0 model calls and does not initialise LightRAG;max_workers=0raises;- an invalid-UTF-8 manifest triggers a full reparse;
- the event loop stays responsive during batch parsing.
\frac/\betain model JSON are stored intact. 1.4.2 stored control characters and produced an unparseable graph file.
Real parsers on macOS:
- Docling 2.140:
.html/.htm/.xhtmlingest end to end with no placeholder text;- an empty HTML fails cleanly;
.txt/.mdingest in Docling batches.- MinerU and PaddleOCR reject HTML before LibreOffice runs. A canary server referenced by the page got 0 requests; LibreOffice run directly on the same page hit it 4 times.
- UTF-16 and Windows-1252 text files decode correctly, and UTF-8/GBK are unchanged.
- Titled Markdown images become VLM-described image blocks, while a text file named
.pngstays text. - OMML equation arrays become
alignedrows. - Video speech outside the retained scenes is kept.
Full history: https://github.com/HKUDS/RAG-Anything/compare/v1.4.2...v1.4.3