When `TokenChunker` starts a fresh chunk with an overlap prefix (Go `computeOverlapPrefix` / Python visible-text cut), the previous chunk's **tail PDF coordinates were dropped**. As a result, the overlap head of a PDF chunk is displayed but **not highlighted** — the highlight box is shifted/truncated relative to the displayed span (infiniflow/ragflow#18148).
This PR fixes **#18193** — the Python `rag/app/book.py` naive-branch `split("@")` bug that destroys PDF coordinate (`@@`) tags, so chunks lose their clickable page highlight.
Second ragflow PR (#17639 merged 2026-07-31). Docstrings only, no
behavior change.
---
🤖 Written with [Claude Code](https://claude.com/claude-code). Each site
was opened and read, and
each description was checked against the line that consumes the value.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
### Summary
Fixes#18107.
`editdistance==0.8.1` (the only recent release on PyPI) has no cp313
wheels for any platform. Since this project requires exactly Python
3.13, `uv`/`pip`/`poetry` fall back to building it from source (Cython),
which fails on Windows for anyone without a working C build toolchain —
that's the PEP 517 build error in the issue.
Swapped `editdistance` for `rapidfuzz`, which ships full cp313 wheels
(win32/win_amd64/win_arm64 included) and has no build-from-source step
on any of our target platforms. The only call site was
`EntityResolution.is_similarity` in `rag/graphrag/entity_resolution.py`,
using `editdistance.eval(a, b)` to get the unweighted Levenshtein
distance between two entity names.
`rapidfuzz.distance.Levenshtein.distance(a, b)` computes the same thing
(verified identical output on several string pairs) and is used as a
direct replacement.
### Summary
Refs #17885.
Mistral figure enrichment now receives the dataset language through the
production parsing path. `by_mistral_ocr` forwards `lang` to
`MistralParser.parse_pdf`; the parser stores the normalized language and
passes it to the figure-description prompt. Empty or missing values
still fall back to English.
### What problem does this PR solve?
Incremental Wiki compilation could lose provenance for claim-light
entities, produce unstable page groups across embedding models, route
entities to unrelated pages, and assign topics without sufficient
page-level context. Document removals and page membership changes could
also leave stale Wiki state.
This PR:
- preserves source document and chunk provenance throughout entity
matching, reduction, page generation, and deletion;
- uses embeddings to retrieve candidates and the LLM to make final page
grouping and incremental routing decisions;
- batches embedding and LLM operations with bounded concurrency and
deterministic fallbacks;
- selects source-scoped topic candidates with embeddings before the page
LLM chooses the final topic;
- rebuilds Wiki state when the compilation mode or embedding model
changes;
- normalizes Wiki array fields returned by the API and retains entities
without relations in graph responses.
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
## What
This pull request adds **MWS GPT Model Hub** as a built-in model
provider in RAGFlow.
The integration allows users to configure an MWS project endpoint and
token, discover the models available to that project, and use supported
MWS models for chat completion, embeddings, and reranking.
Co-authored-by: ilarionov_n <ilarionov_n@promis.ru>
## Summary
This PR improves the RAGFlow agentic-search path in three areas: it
stops the outer agent from re-looping over the same rag call, lets the
medium thinking mode discover and follow new sub-claims mid-loop, and
strengthens retrieval by having the LLM emit synonym-rich queries with
time/date/number terms boosted.
1. Avoid the outer re-loop — keep all multi-hop cycles inside agentic
RAG
2. Dynamic claims in medium mode — keep querying newly discovered
sub-questions
medium now enables allows_dynamic_claims. During orchestration, when
claim analysis discovers a new required sub-question
(discovered_claims), the loop spawns it as a new ClaimTarget and
continues searching it in subsequent cycles (bounded by the
dynamic-claim budget) instead of stopping. Also added:
3. Stronger query strategy — synonym-rich queries + time/date/number
weighting
LLM-generated synonyms: the claim-analysis prompt now instructs the
model to write each next_queries entry as a retrieval-boosted query that
actively folds in entity aliases, DATE/TIME synonyms (e.g. 1994 → 1994,
66th Academy Awards), and number/unit variants (e.g. 1.95 m → 6 ft 5
in).
Time/date/number boosting: query.py boosts numeric/date tokens to a high
weight (_NUM_DATE_TOKEN_RE).
## What problem does this PR solve?
`TenantLLMService.model_instance` constructs vision providers with
`lang` as the third positional argument and `base_url` as a keyword
argument.
`LocalAICV` declared `base_url` as its third parameter, causing:
```text
TypeError: LocalAICV.__init__() got multiple values for argument 'base_url'
```
This prevents LocalAI vision models from being used during document
parsing.
Co-authored-by: Jin Hai <haijin.chn@gmail.com>
chore(rag/app): remove stray debug print() calls
Two hot-path debug print() calls were leaking content/error text to
stdout in production code paths.
* rag/app/naive.py: TxtParser branch in chunk() was printing the entire
parsed sections list (formatted via repr()) wrapped in 150-char banner
lines. For large text documents (e.g. a 1000+-page book ingest) this
dumped tens of thousands of lines per ingest into the docker logs.
Replaced with a structured
`logging.info("TxtParser produced %d sections for %s", len(sections),
filename)` so the parse count is still observable without the content
leak.
* rag/app/presentation.py: Pdf.position parsing had a debug
`print(f"Error parsing position: {e}")` inside an except clause in the
ingest hot path. Replaced with
`logging.warning(f"Error parsing position in {filename}: {e}")` to
match the file's existing logging pattern and add filename context.
Both call sites already had logging imported; no new imports added.
logging was used throughout the surrounding code in the same
logging.{info,warning,error}(...) style.
Unifies the Go TokenChunker merge path on a single `mergeUnits` core and
fixes coordinate-tag drift in the Python JSON merge at `overlap > 0`.
Rebased on top of #17979 (delimiter_mode convergence).
Re-materialize wiki page graph from merged wiki_page rows after each
batch merge. Adds ProjectWikiGraph/DropWikiGraph, full page_type/slug
identity, delete-then-insert, tests.
### What problem does this PR solve?
`NvidiaRerank.__init__` only assigned `self.base_url` inside two
model-specific
`if` branches:
```python
if self.model_name == "nvidia/nv-rerankqa-mistral-4b-v3":
self.base_url = urljoin(base_url, "nv-rerankqa-mistral-4b-v3/reranking")
if self.model_name == "nvidia/rerank-qa-mistral-4b":
self.base_url = urljoin(base_url, "reranking")
```
Any other NVIDIA rerank model therefore left the attribute unset, and
the first
`_compute_rank()` call died with `AttributeError: 'NvidiaRerank' object
has no
attribute 'base_url'`.
This is reachable in normal use: `conf/llm_factories.json` ships no
NVIDIA
rerank entries at all, so every NVIDIA rerank model has to be added by
hand,
and any name other than those two hardcoded strings crashes.
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
Co-authored-by: Alex Ma <alex_makang@hotmail.com>
Converge `TokenChunker.delimiter_mode` from three values (`token_size`,
`delimiter`, `one`) to two (`delimiter`, `one`). The unified `delimiter`
mode now carries the old `token_size` semantics: when no active
(backtick) delimiter is present, text/JSON chunks are merged up to
`chunk_token_size`; when a backtick delimiter is present, the text is
split by it and not merged. `one` continues to be handled by the
separate `OneChunker`.
Ports dataset knowledge compilation (wiki/graph/tree/mindmap) to the Go
scheduler with a status contract, aligns wiki storage/retrieval with
Python, sizes prompts by content_length, and resolves embedding batch
size from provider capability.
Ports the dataset knowledge compilation (wiki/graph/tree/mindmap) to the
Go scheduler with a status contract, aligns wiki storage/retrieval with
Python, and sizes prompts by content_length.