maestro/docs/tools/webfetch.md
oss-sync 29ccaf1e92
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (dfadcd5f)
2026-06-23 06:38:48 +00:00

7.7 KiB
Raw Blame History

WebFetch

URL を HTTP GET してレスポンス本文を取得するツール。静的ページ向け。

基本

WebFetch({ url: "https://example.com/article", timeout: 30 })
  • HTML は readability 抽出でクリーンな Markdown に変換されて返る(ナビ・広告・ヘッダー・フッターを除去し、見出し・リスト・テーブル・リンクは保持)
  • JSON / XML / プレーンテキストもそのまま取得可能
  • リダイレクトは自動で追従

返却テキストは context 節約のため約 10,000 文字で切り詰められる。スペースタスクでは全文(未切り詰め)が source/ に保存されるので、切り詰めが起きると末尾に ... (truncated; full version saved to source/<file>) という案内が付く。全文を読みたいときは保存された source/ のファイルを Read で開けばよい。

いつ使うか

状況 使うツール
静的 HTML ページ WebFetch
JS で動的レンダリングされる SPA BrowseWeb
ボタン・フォーム操作が必要 BrowseWeb
ファイルダウンロード DownloadFile
検索結果を一覧で取得 WebSearch

WebFetch は軽量で速い。BrowseWeb はブラウザ起動コストがかかるので、できる限り WebFetch を優先する。

クリーン本文抽出readability

取得した生 HTML は、記事本文だけを取り出す readability エンジンで処理してから返す。 内部パイプラインは HTML → linkedom で DOM 化 → @mozilla/readability で記事抽出 → turndown(+gfm) で Markdown 化

  • 除去されるもの: ナビゲーション、広告バナー、ヘッダー、フッター、サイドバー等のボイラープレート
  • 保持されるもの: 見出し(# 記法、箇条書き、番号付きリスト、テーブルGFM 記法)、リンク、コードブロック
  • 相対リンクは取得 URL を基準に絶対 URL へ変換される
  • selector を指定すると、その CSS セレクタにマッチする要素のサブツリーだけをクリーン抽出する(見つからなければページ全体の抽出にフォールバック)

抽出に失敗するページ(記事構造のない LP、JS で本文を生成する SPA、空ページ等では、 従来の素朴なタグ除去にフォールバックするので WebFetch が失敗扱いになることはない。 本文がほぼ空のときは SPA の可能性が高いので BrowseWeb に切り替える。

全文は source へ、切り詰め版は agent へ

  • agent のコンテキストに返るのは約 10,000 文字に切り詰めた版context 膨張を防ぐため)
  • スペースタスクでは、切り詰める前の全文クリーン Markdown が source/ に保存される
  • 切り詰めが起きた場合、返却テキスト末尾に ... (truncated; full version saved to source/<file>) が付く
  • 病的に巨大なページ対策として、source/ 保存も 2MB で打ち切る(その旨ノートを付す)

レスポンス履歴

各 WebFetch 呼び出しは logs/webfetch-history.jsonl に記録される。後から「どの URL を取得したか」を振り返れる。

スクリーンショット添付vlmEnabled 時のみ)

ワーカーが vlm=true(主 LLM が画像入力対応の場合、WebFetch は成功時に Playwright でファーストビュー1280×1600 viewportのスクショを撮り、LLM の文脈に image_url として自動添付する。天気・ダッシュボード・地図など、HTML テキスト抽出では情報が欠落しやすいサイトの理解を補う目的。

  • 保存先: logs/webfetch-screenshots/{timestamp}-{url-hash}.png
  • logs/webfetch-history.jsonl の各レコードに screenshotPath が記録される
  • Playwright 未インストール・CAPTCHA・タイムアウト等で失敗しても WebFetch 本体は成功扱い(テキストだけ返る)
  • 無効化: config.yamltools.webfetch_screenshot: false
  • タイムアウト: tools.webfetch_screenshot_timeout_ms(デフォルト 15,000

SSRF 保護

ローカル/プライベート IP127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, ::1, fc00::/7 等)はデフォルトでブロックされる。社内ホストへアクセスする必要がある場合は Settings UI の「SSRF Allowed Hosts」に追加する。

トラブルシューティング

  • 本文がほぼ空: SPA で JS レンダリングが必要 → BrowseWeb に切り替え
  • タイムアウト: timeout パラメータを増やす(デフォルト 30 秒)
  • 403/404: User-Agent 制限・bot 検出の可能性 → BrowseWeb なら回避できる場合あり
  • SSRF blocked: ローカル/プライベート IP に向いている → 設定追加またはターゲット見直し

エラー時のフォールバック方針

WebFetch がエラーを返した場合、以下の原則で BrowseWeb にリトライする:

エラー BrowseWeb で再試行すべきか
HTTP 403 / 429 する — bot 検出・レート制限。ブラウザ User-Agent で回避できる可能性
HTTP 502 / 503 / 504 する — CDN/upstream の一時的エラー。別の HTTP スタックで成功することがある
ネットワークエラー / タイムアウト する — 動的ページが静的 fetch に応答しないケースが多い
HTTP 404 / 401 / 410 しない — 永続的なエラー。URL を見直すべき
invalid_url しない — URL の記述ミス
ssrf_blocked しない — セキュリティ設定。Settings で allowed hosts を追加
pdf_blocked しない — DownloadFile + ReadPdf の組み合わせを使う
binary_blocked しない — DownloadFile でバイナリ保存する
本文が極端に短い(< 200 chars する — SPA の空シェルを取得した可能性が高い
Just a moment... 等 Cloudflare challenge する — ブラウザで JS challenge を通過できる

リトライ時は同じ URL を BrowseWeb({ url: "..." }) に渡すだけでよい。BrowseWeb はジョブ内で Cookie・セッションを保持するので、複数回呼んでもログイン状態は引き継がれる。

バイナリの扱い

WebFetch は取得 body の先頭 8KB を sniff しmagic byte / NUL / 不正 UTF-8 / 制御文字比率)、 バイナリと判定したらコンテキストに展開せずブロックする。Content-Type が欠落・詐称 (例: .xlstext/plain)していても実バイトで検出する。バイナリを処理したい場合は DownloadFileinput/ に保存し、ReadExcel / ReadPdf 等を使う。テキスト body は 5MB で打ち切られる(末尾に [truncated: body exceeded 5MB])。

ソースライブラリへの蓄積(スペースタスク)

スペースのタスクで WebFetch がページ本文を取得すると、クリーン抽出した全文 Markdownagent への 返却で切り詰める前のもの)が source/ に保存され、出典メタURL・タイトル・取得日時・サイズsource/index.jsonl に追記される。 これにより「そのスペースのソース(資料)」が自動で溜まり、後から追加調査やグラウンディングに使える。 同一 URL は重複保存しない(既に index にあればスキップ)。スペース文脈でないタスク ephemeral / gitea issue 等)では従来どおり蓄積しない。logs/raw/ への生データ保存は従来どおり。 BrowseWebブラウザ閲覧や DownloadFilesection: "source")も同じ source/index.jsonl に合流する。