WebFetchTool / WebSearchTool: herramientas web de la cuenta Cline
Responsabilidades
Estos dos handler son las herramientas de salida a red de Cline; ambos implementan IFullyManagedTool y, antes de ejecutarse, exigen que el provider sea cline, que el usuario tenga activada la opción clineWebToolsEnabled y que el feature flag correspondiente esté activo (WebFetch class:20-21, WebSearch class:21-22). La diferencia esencial con BrowserToolHandler es: el de navegador usa Chrome local o remoto para capturar la página directamente, mientras que estos dos envían una petición HTTP a la API oficial de Cline, dejando que el servidor de Cline haga el fetch o la búsqueda, y devuelven el resultado al modelo.
- WebFetchToolHandler (
ClineDefaultTool.WEB_FETCH): el modelo pasa una URL y un prompt; la herramienta hace POST de ambos a${apiBaseUrl}/api/v1/search/webfetch, el servidor extrae el contenido de la URL según el prompt y devuelve un resultado de texto (webfetch axios:150). - WebSearchToolHandler (
ClineDefaultTool.WEB_SEARCH): el modelo pasa un query y opcionalmente listas blanca/negraallowed_domains/blocked_domains(mutuamente excluyentes); la herramienta hace POST a/api/v1/search/websearchy devuelve un arreglo de resultados {title, url} (websearch axios:174).
La salida de ambas herramientas no se presenta al usuario; se inserta como tool result en userMessageContent para la siguiente ronda del LLM. No requieren recursos locales (filesystem, terminal, navegador); son puramente salida a red, por eso operationIsLocatedInWorkspace: false.
Motivación de diseño
- Proxy en servidor en vez de fetch local: en muchos escenarios Cline corre en entornos restringidos sin salida directa a Internet; el proxy unifica autenticación, rate-limit y lógica de fetching (renderizado JavaScript, evasión de anti-bot); el cliente solo envía la petición (
webfetch request:150-166). - Triple puerta: el provider debe ser cline, el setting clineWebToolsEnabled activado, y el feature flag encendido; si alguno falla, se devuelve
toolError("Cline web tools are currently disabled.")sin dejar avanzar al modelo (feature flag gate:55-59). - Timeout de 15 segundos: ambos usan 15 s de timeout en axios, evitando que peticiones de cola larga maten toda la ronda (
timeout:163). - Listas blanca/negra mutuamente excluyentes: web_search valida que
allowed_domainsyblocked_domainsno se pasen juntos; en caso contrario,mistake+++ toolError (mutual exclusivity:75-78). - Parseo de arreglo parcial en streaming:
parsePartialArrayStringextrae elementos ya completos incluso cuando llega JSON incompleto tipo["a", "b", de modo que la lista de dominios se muestre ya en la fase partial block (parsePartialArrayString:71-72). - Errores de autenticación claros: si no se obtiene el auth token, se lanza
CLINE_ACCOUNT_AUTH_ERROR_MESSAGEpidiendo al usuario que inicie sesión en Cline, en lugar de devolver 401 al modelo (auth check:146-148).
Archivos clave
WebFetch class:20—name = ClineDefaultTool.WEB_FETCH.handlePartialBlock:27— durante el streaming solo hace say de un placeholder «Fetching URL: ...», sin bloquear.execute:44— flujo principal: gate → validación de parámetros → aprobación → hook → axios POST → devolver result.feature flag gate:55-59— si provider !== "cline" o si setting/flag es falso, devuelve toolError directo.approval flow:81-128—shouldAutoApproveTooldecide ir por say o por ask.axios POST webfetch:143-166— obtiene baseUrl + authToken, POST a/api/v1/search/webfetch, body{Url, Prompt}, header conX-Task-ID.WebSearch class:21—name = ClineDefaultTool.WEB_SEARCH.domain parse + mutex:70-78—parsePartialArrayStringpara arreglos de dominios + validación de exclusión mutua.axios POST websearch:150-183— POST a/api/v1/search/websearch; el body solo incluye los campos de arreglo cuando no están vacíos.format results:188-200— convierte{title, url}[]en texto con formato1. title\n url\n\n.CLINE_ACCOUNT_AUTH_ERROR_MESSAGE— texto unificado para errores de autenticación.AuthService—getInstance().getAuthToken()obtiene el token de la cuenta actual.
Flujo de datos
Ambos handler son casi idénticos. Tomando WebFetchToolHandler como ejemplo, el núcleo es el POST a la API de Cline tras la aprobación:
// 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() añade headers de trazado; getAxiosSettings() inyecta en axios proxy/CA y demás configuraciones del usuario. La respuesta tiene estructura { data: { result: "..." } } (ojo: axios añade una capa data automáticamente); se extrae y se envuelve con formatResponse.toolResult para devolver como tool result al LLM.
WebSearchToolHandler añade un paso de formateo de resultados:
// 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 se incluyen en el cuerpo solo si no están vacíos; la validación de exclusión mutua, tras mistake++, devuelve toolError sin enviar la petición.
Límites y fallos
- Triple puerta no satisfecha: provider no cline, setting de web tools apagado, o feature flag desactivado; cualquiera de los tres devuelve toolError de disabled sin incrementar
mistake(feature flag gate:55-59). - No logueado: si
AuthService.getInstance().getAuthToken()devuelve vacío, se lanzaCLINE_ACCOUNT_AUTH_ERROR_MESSAGE; el catch lo convierte enError fetching web content: ...(auth check:146-148). - Listas blanca/negra simultáneas: si web_search recibe a la vez
allowed_domainsyblocked_domains,mistake+++ toolError, interceptando directo (mutual exclusivity:75-78). - Cancelación por PreToolUse hook: si el hook lanza
PreToolUseHookCancellationError, devuelve toolDenied sin enviar la petición (PreToolUse hook:131-140). - Fallback ante fallo de petición: si axios lanza o el servidor responde non-200, el catch lo envuelve en
Error fetching web content: .../Error performing web search: ..., sin propagar a Task, para que el modelo vea el error (error catch:173-175). - Timeout: 15 s en axios; las peticiones de cola larga se cortan y caen en error catch (
timeout:163). - Resultado vacío: cuando web_search devuelve 0 resultados, retorna
Search completed (0 results found)sin líneas adicionales (empty results:193-199).
Resumen
WebFetch y WebSearch son los dos handler con los que Cline hace fetching/búsqueda web a través de su propio servidor proxy; comparten la misma gate (provider=cline + setting + flag), el mismo flujo de aprobación/hook y el mismo timeout de 15 s. WebFetch devuelve el texto extraído por el servidor usando el prompt; WebSearch devuelve una lista estructurada {title, url} y la formatea como 1./2./3. Ninguna escribe a disco ni abre navegador; son puramente salida a red.
Para profundizar:
- Herramienta de navegador (fetch local):
/cap-tools/browser - Herramientas de archivos y comandos:
/cap-tools/file-ops - Cadena de despacho de herramientas:
/agent-loop/task-class