6.6 KiB
6.6 KiB
| title | state | created_at | updated_at | assignee | readiness | risk_flags | queued_by | queued_at | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| WebFetch: PDF を page-delimited text として取得できるようにする | closed | 2026-06-20T10:46:48Z | 2026-06-20T12:31:33Z | null | implementation_ready |
|
workspace-panel | 2026-06-20T12:06:29Z |
Background
ユーザー要望: WebFetch で PDF URL を取得し、LLM が読める bounded text として返せるようにする。調査は同一会話内で完了済みで、初期実装は semantic な「PDF to Markdown」ではなく、PDF から page-delimited な Markdown-ish text を抽出する方針とする。
現状:
crates/tools/src/web.rsのWebFetchは HTML / text / JSON / XML-ish content のみを許可し、application/pdfは unsupported Content-Type として拒否する。- 既存の
render_content()はreject_binary(bytes)と UTF-8 decode 前提なので、PDF binary を既存 text path に乗せることはできない。 WebFetchの既存 safety behavior は維持する必要がある: private/local host rejection、bounded redirects、max_response_bytes、max_output_bytes、untrusted content warning。
調査結論:
- 初期実装には
pdf-extractcrate が最有力。- MIT license。
- pure Rust。
- native/system dependency なし。
- memory buffer API あり。
- page split API
pdf_extract::extract_text_from_mem_by_pages()あり。
- Poppler /
pdftotextは GPL / system dependency / deployment / Nix packaging の重さから採用しない。 pdfium-renderは Pdfium native library が必要で、初期の text extraction には重すぎるため採用しない。unpdf/pdf_oxide/spectre_pdf等は Markdown-oriented な候補だが、初期採用には成熟度・audit が不足気味。必要なら follow-up で比較する。
Requirements
WebFetchがapplication/pdfresponse を unsupported Content-Type として拒否せず処理できる。- PDF binary bytes は既存の UTF-8 text path /
reject_binary()path と分離して扱う。 pdf_extract::extract_text_from_mem_by_pages()を使い、page ごとに抽出した text を Markdown-ish に整形する。- 出力例:
## Page 1
...
## Page 2
...
transformed_asはpdf_text_by_pagesなど、semantic Markdown 化を約束しない名前にする。- result JSON に PDF 用 metadata を追加する。
- text/html / JSON / XML / text の既存挙動と
html_extractionmetadata を regress させない。 WebFetchの既存 bounds と safety behavior を維持する。
Acceptance criteria
application/pdfresponse が bounded text result を返す。- PDF response では
render_content()の UTF-8 decode 前提 path を通らず、PDF 専用 extraction path が使われる。 pdf_extract::extract_text_from_mem_by_pages()により、page delimiter 付き Markdown-ish text が返る。- result JSON に
pdf_extractionmetadata が含まれる。 max_output_bytesを超える抽出結果は既存 truncation marker で切り詰められ、output_truncatedが正しく立つ。max_response_bytes/ Content-Length check / redirect limit / private host rejection / embedded credential rejection は既存通り維持される。- malformed PDF / encrypted PDF / text のない PDF で panic しない。diagnostic error または readable=false 相当の metadata を返す。
- PDF 以外の unsupported binary content は引き続き拒否される。
- 既存 WebFetch HTML reader tests が通る。
Binding decisions / invariants
WebFetchは fetch/extraction tool のままとし、LLM summarization や multi-page research orchestration は入れない。- 初期実装では semantic な「PDF to Markdown」を約束しない。page-delimited Markdown-ish text extraction として扱う。
- 初期実装で対応する MIME は
application/pdfのみとする。application/x-pdf、application/acrobat、application/octet-streamwith.pdf、extension sniffing は必要なら follow-up。 max_response_bytesdefault は変更しない。大きい PDF が必要な場合は既存 config override を使う。- Poppler / Pdfium / subprocess
pdftotext/ system native dependency は導入しない。 - OCR、scanned PDF 対応、画像抽出、rendering、table reconstruction、2-column layout の完全復元、heading inference、PDF 保存/cache は範囲外。
- PDF 抽出結果も untrusted content として扱い、既存の warning / network safety / bounds を弱めない。
Implementation latitude
- PDF metadata は互換性重視で
pdf_extractionを新設するのが推奨。既存html_extractionは残す。 pdf_extractionmetadata の具体フィールドは実装時に調整してよいが、少なくとも method / pages or pages_included / readable / error diagnostic 相当が分かるようにする。- PDF extraction は CPU-heavy になり得るため、可能なら
spawn_blocking等で async runtime を塞がない設計にする。ただし Rust parser の強制 cancel までは初期実装の必須条件にしない。 - 抽出品質が
pdf-extractで明確に不足する場合は、実装を歪めず、別 Ticket でunpdf/pdf_oxide等を比較する。
Readiness
- readiness: implementation_ready
- risk_flags: [security, dependency, public-api, output-bounds]
Escalation conditions
pdf-extractが実装上致命的に使えない、または license/build/security 上の問題が見つかった場合は実装前に戻す。- Tool result JSON shape に breaking change が必要になりそうな場合は、既存互換を維持する案を先に提示する。
- PDF fixture で parser panic / runaway CPU / excessive memory の懸念が出た場合は、bounds 追加または別方針を提案する。
- Nix packaging / Cargo.lock / cargoHash 影響が大きい場合は実装報告で明示する。
Validation
- focused tests:
- small valid PDF fixture returns expected text。
- multi-page PDF fixture returns
## Page 1/## Page 2。 - output truncation sets
output_truncated。 - unsupported binary non-PDF remains rejected。
- oversized PDF Content-Length remains rejected。
- existing WebFetch HTML reader behavior remains unchanged。
- commands:
cargo fmt --checkcargo test -p tools webcargo check -p toolsgit diff --checkTicketDoctorif Ticket consistency needs checking。
Related work
crates/tools/src/web.rs— current WebSearch/WebFetch implementation。- Closed prior WebFetch HTML work:
00001KSX9W968,00001KSXECDG0。