WebFetchTool / WebSearchTool:Cline アカウントのネットワークツール
役割
この二つの handler は Cline のネットワーク出口ツールで、どちらも IFullyManagedTool を実装し、実行前に provider が cline で、ユーザーが clineWebToolsEnabled 設定を有効にし、対応する feature flag が有効であることを要求する(WebFetch class:20-21,WebSearch class:21-22)。BrowserToolHandler との本質的な違いは:ブラウザツールはローカルまたはリモート Chrome で直接ページを抓むのに対し、この二つのツールは HTTP リクエストを Cline 公式 API に送り、Cline サーバー側に抓取や検索を行わせ、結果をモデルに返す点である。
- WebFetchToolHandler(
ClineDefaultTool.WEB_FETCH):モデルが URL と prompt を与えると、ツールはこの二つを${apiBaseUrl}/api/v1/search/webfetchに POST し、サーバー側が prompt を使って URL の内容を抽出しテキスト結果を返す(webfetch axios:150). - WebSearchToolHandler(
ClineDefaultTool.WEB_SEARCH):モデルが query とオプションのallowed_domains/blocked_domains白黒リスト(互いに排他)を与えると、ツールは/api/v1/search/websearchに POST し、{title, url} の結果セットを返す(websearch axios:174).
この二つのツールの出力はユーザーに直接表示されず、tool result として userMessageContent に詰め込まれ、次のラウンドの LLM に渡るだけである。ローカルリソース(ファイルシステム、terminal、ブラウザ)を必要とせず、純粋なネットワーク出口なので operationIsLocatedInWorkspace: false である。
設計動機
- ローカル抓取ではなくサーバー代理:多くの場面で Cline は制限された環境で走り、外網への直結が通じない。サーバー代理で認証・レート制限・抓取ロジック(JavaScript レンダリング、アンチクロール回避)を統一し、クライアントはリクエストを送るだけにする(
webfetch request:150-166)。 - 三重ゲート:provider が cline であること、ユーザー設定の clineWebToolsEnabled、feature flag が有効であること。いずれかを満たさなければ
toolError("Cline web tools are currently disabled.")を返し、モデルを先に進めない(feature flag gate:55-59)。 - 15 秒タイムアウト:両ツールとも 15 秒の axios タイムアウトを使い、長いテールのリクエストがラウンド全体を引きずり込まないようにする(
timeout:163)。 - ドメイン白黒リストの排他:web_search は
allowed_domainsとblocked_domainsを同時に指定できないことを検証し、違反時はmistake+++ toolError とする(mutual exclusivity:75-78)。 - ストリーミング部分配列解析:
parsePartialArrayStringはストリーミングで["a", "b"のような不完全な JSON が来ても既に完成している要素を抽出でき、partial block 段階でドメインリストを表示できる(parsePartialArrayString:71-72). - 認証エラーの明確化:auth token が取れない時は
CLINE_ACCOUNT_AUTH_ERROR_MESSAGEを投げ、ユーザーに Cline アカウントへログインするよう促し、401 をモデルに返さない(auth check:146-148).
主要ファイル
WebFetch class:20—name = ClineDefaultTool.WEB_FETCH。handlePartialBlock:27— ストリーミング中は「Fetching URL: ...」プレースホルダーを一回 say するだけで、ブロックしない。execute:44— 主流程:gate → パラメータ検証 → 承認 → hook → axios POST → result 返却。feature flag gate:55-59— provider !== "cline" または設定/flag のいずれかが false なら直接 toolError。approval flow:81-128—shouldAutoApproveToolが say か ask かを決める。axios POST webfetch:143-166— baseUrl + authToken を取得し、POST/api/v1/search/webfetch、body は{Url, Prompt}、header にX-Task-IDを付ける。WebSearch class:21—name = ClineDefaultTool.WEB_SEARCH。domain parse + mutex:70-78—parsePartialArrayStringでドメイン配列を解析 + 排他検証。axios POST websearch:150-183— POST/api/v1/search/websearch。body は配列が空でない場合のみ対応フィールドを付ける。format results:188-200—{title, url}[]を1. title\n url\n\nのテキスト形式に組み立てる。CLINE_ACCOUNT_AUTH_ERROR_MESSAGE— 認証エラーの統一プロンプトテキスト。AuthService—getInstance().getAuthToken()で現在のアカウントトークンを取得。
データフロー
二つの handler の流れはほぼ同じ。WebFetchToolHandler を例にすると、核心は承認後に Cline API に POST すること:
// apps/vscode/src/core/task/tools/handlers/WebFetchToolHandler.ts
const baseUrl = ClineEnv.config().apiBaseUrl
const authToken = await AuthService.getInstance().getAuthToken()
if (!authToken) {
throw new Error(CLINE_ACCOUNT_AUTH_ERROR_MESSAGE)
}
const response = await axios.post(
`${baseUrl}/api/v1/search/webfetch`,
{ Url: url, Prompt: prompt },
{
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
"X-Task-ID": config.ulid || "",
...(await buildClineExtraHeaders()),
},
timeout: 15000,
...getAxiosSettings(),
},
)
const result = response.data.data.result
return formatResponse.toolResult(result)buildClineExtraHeaders() は追加の追跡ヘッダーを付与し、getAxiosSettings() は axios にプロキシ/CA などのユーザー設定を注入する。レスポンス構造は { data: { result: "..." } }(axios が data のラップを自動で一段追加している点に注意)。直接取り出して formatResponse.toolResult で tool result に包んで LLM に返す。
WebSearchToolHandler は結果のフォーマットが一つ増える:
// apps/vscode/src/core/task/tools/handlers/WebSearchToolHandler.ts
const data = response.data.data
const results = data.results || []
let resultText = `Search completed (${resultCount} results found)`
if (results.length > 0) {
resultText += ":\n\n"
results.forEach((result, index) => {
resultText += `${index + 1}. ${result.title}\n ${result.url}\n\n`
})
}
return formatResponse.toolResult(resultText)allowed_domains / blocked_domains はリクエストボディでは非空の時のみ付ける。排他検証は mistake++ 後に直接 toolError で拒否し、リクエストは送らない。
境界と失敗
- 三重ゲート未達成:provider が cline でない、ユーザーが web tools 設定をオフにしている、feature flag が閉じている場合、いずれか一つでも false なら直接 disabled toolError を返す。
mistakeは増えない(feature flag gate:55-59)。 - 未ログイン:
AuthService.getInstance().getAuthToken()が空を返す時、CLINE_ACCOUNT_AUTH_ERROR_MESSAGEを投げ、catch でError fetching web content: ...に変換される(auth check:146-148)。 - ドメイン白黒リスト同時指定:web_search で
allowed_domainsとblocked_domainsを同時に与えた時、mistake+++ toolError で直接遮断する(mutual exclusivity:75-78)。 - PreToolUse hook のキャンセル:hook が
PreToolUseHookCancellationErrorを投げた時、toolDenied を返しリクエストは送らない(PreToolUse hook:131-140)。 - リクエスト失敗のフォールバック:axios がエラーを投げる、またはサーバー側が 200 以外を返す時、catch で
Error fetching web content: .../Error performing web search: ...に包み、Task に投げずモデルにエラーを見せる(error catch:173-175)。 - タイムアウト:15 秒の axios タイムアウト。長いテールのリクエストは切断され error catch に進む(
timeout:163)。 - 結果が空:web_search が 0 件を返す時は
Search completed (0 results found)を返し、後続の行を付けない(empty results:193-199)。
まとめ
WebFetch と WebSearch は Cline が自前のサーバー代理でネットワーク抓取/検索を行う二つの handler で、同じ gate(provider=cline + setting + flag)、同じ承認/hook フロー、同じ 15 秒タイムアウトを共有する。WebFetch はサーバー側が prompt で抽出したテキストを返し、WebSearch は構造化された {title, url} リストを 1./2./3. の形式のテキストに組み立てて返す。両ツールともディスクに書かず、ブラウザを開かず、完全に純粋なネットワーク出口である。
さらに掘り下げるなら次へ:
- ブラウザツール(ローカル抓取):
/cap-tools/browser - ファイルとコマンドツール:
/cap-tools/file-ops - ツール调度の経路:
/agent-loop/task-class