Split out of the bilingual-contract table bloat work (branch claude/contract-table-bloat-v5wikg), where a .docx laid out as one long table extracted at several times its content size.
Problem
POST /text (app/routes/document_routes.py:1114) concatenates every loaded Document into one string and returns it, with no bound on the result:
text_content = extract_text_from_documents(data, file_ext)
return {"text": text_content, ...}
There is no guard anywhere in the path. Whatever the loader produces is held in memory, serialised into the JSON response and handed to the caller. A pathological document — a table-heavy contract, a large spreadsheet, a long OCR'd PDF — can therefore blow up the caller's context window (or its own memory) with no warning and no way for the caller to tell that it happened.
The table-padding fix removes one cause of oversized output, not the class of problem.
Suggested fix
- A configurable cap (e.g.
TEXT_EXTRACTION_MAX_CHARS), applied after extraction.
- On exceeding it, prefer a clear
413-style error naming the size and the limit over silent truncation; silent truncation hands the caller a contract that stops mid-clause with no indication of it.
- Log the extracted size per file either way, so oversized documents are visible in production. (The
.docx path now logs Chars: N -> M after cleanup; the other loaders have nothing equivalent.)
Notes
Worth deciding explicitly whether the cap applies to /embed too, or only to /text — the embedding path chunks its input, so it degrades differently.
Split out of the bilingual-contract table bloat work (branch
claude/contract-table-bloat-v5wikg), where a.docxlaid out as one long table extracted at several times its content size.Problem
POST /text(app/routes/document_routes.py:1114) concatenates every loadedDocumentinto one string and returns it, with no bound on the result:There is no guard anywhere in the path. Whatever the loader produces is held in memory, serialised into the JSON response and handed to the caller. A pathological document — a table-heavy contract, a large spreadsheet, a long OCR'd PDF — can therefore blow up the caller's context window (or its own memory) with no warning and no way for the caller to tell that it happened.
The table-padding fix removes one cause of oversized output, not the class of problem.
Suggested fix
TEXT_EXTRACTION_MAX_CHARS), applied after extraction.413-style error naming the size and the limit over silent truncation; silent truncation hands the caller a contract that stops mid-clause with no indication of it..docxpath now logsChars: N -> M after cleanup; the other loaders have nothing equivalent.)Notes
Worth deciding explicitly whether the cap applies to
/embedtoo, or only to/text— the embedding path chunks its input, so it degrades differently.