WebFetchTool / WebSearchTool : outils réseau du compte Cline
Responsabilités
Ces deux handlers sont les outils réseau de sortie de Cline ; tous deux implémentent IFullyManagedTool et exigent, avant exécution, que le provider soit cline, que l'utilisateur ait activé clineWebToolsEnabled et que le feature flag correspondant soit levé (WebFetch class:20-21, WebSearch class:21-22). La différence essentielle avec BrowserToolHandler est la suivante : l'outil navigateur saisit la page directement via Chrome local ou distant, alors que ces deux outils envoient une requête HTTP à l'API officielle de Cline ; le serveur Cline effectue l'extraction ou la recherche, puis renvoie le résultat au modèle.
- WebFetchToolHandler (
ClineDefaultTool.WEB_FETCH) : le modèle fournit une URL et un prompt ; l'outil POST les deux à${apiBaseUrl}/api/v1/search/webfetch, le serveur extrait le contenu de l'URL selon le prompt et renvoie un texte (webfetch axios:150). - WebSearchToolHandler (
ClineDefaultTool.WEB_SEARCH) : le modèle fournit une requête et, optionnellement, une liste blancheallowed_domainsou une liste noireblocked_domains(mutuellement exclusives) ; l'outil POST vers/api/v1/search/websearchet récupère un ensemble de résultats {title, url} (websearch axios:174).
Les sorties de ces deux outils ne sont pas présentées directement à l'utilisateur : elles ne sont qu'un tool result injecté dans userMessageContent pour le prochain tour LLM. Ils ne consomment aucune ressource locale (système de fichiers, terminal, navigateur), c'est une sortie purement réseau, donc operationIsLocatedInWorkspace: false.
Motivation de conception
- Proxy serveur plutôt que fetch local : dans beaucoup de scénarios, Cline tourne en environnement restreint sans accès direct à Internet ; le proxy serveur unifie authentification, rate limiting et logique d'extraction (rendu JavaScript, contournement d'anti-scraping), le client ne fait qu'envoyer la requête (
webfetch request:150-166). - Trois portes de contrôle : provider doit être cline, paramètre utilisateur clineWebToolsEnabled activé, feature flag levé — si l'un manque, on renvoie
toolError("Cline web tools are currently disabled.")sans laisser le modèle continuer (feature flag gate:55-59). - Timeout de 15 s : les deux outils appliquent un timeout axios de 15 s pour éviter qu'une requête à longue traîne ne tue la manche (
timeout:163). - Listes blanche/noire de domaines mutuellement exclusives : web_search valide que
allowed_domainsetblocked_domainsne sont pas fournis ensemble ; en cas de violation,mistake+++ toolError (mutual exclusivity:75-78). - Parsing de tableau partiel en streaming :
parsePartialArrayStringsait extraire les éléments déjà complets d'un flux["a", "b"incomplet, de sorte que la liste de domaines peut s'afficher dès la phase partial block (parsePartialArrayString:71-72). - Erreur d'auth explicite : si le token d'auth ne peut être récupéré, on lève
CLINE_ACCOUNT_AUTH_ERROR_MESSAGEinvitant l'utilisateur à se connecter à son compte Cline, plutôt que de renvoyer un 401 au modèle (auth check:146-148).
Fichiers clés
WebFetch class:20—name = ClineDefaultTool.WEB_FETCH.handlePartialBlock:27— pendant le streaming, ne fait que say un placeholder « Fetching URL: ... » sans bloquer.execute:44— flux principal : gate → validation des paramètres → approbation → hook → axios POST → renvoyer le result.feature flag gate:55-59— provider !== "cline" ou setting/flag à false → toolError immédiat.approval flow:81-128—shouldAutoApproveTooldécide say vs ask.axios POST webfetch:143-166— récupère baseUrl + authToken, POST/api/v1/search/webfetch, body{Url, Prompt}, headerX-Task-ID.WebSearch class:21—name = ClineDefaultTool.WEB_SEARCH.domain parse + mutex:70-78—parsePartialArrayStringpour les tableaux de domaines + validation de mutex.axios POST websearch:150-183— POST/api/v1/search/websearch, le body n'inclut les champs de tableau que s'ils sont non vides.format results:188-200— concatène{title, url}[]en1. title\n url\n\n.CLINE_ACCOUNT_AUTH_ERROR_MESSAGE— texte unifié d'erreur d'authentification.AuthService—getInstance().getAuthToken()récupère le token du compte courant.
Flux de données
Les deux handlers ont un flux quasi identique ; prenons WebFetchToolHandler en exemple. Le cœur est le POST vers l'API Cline après approbation :
// 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() ajoute des headers de traçabilité ; getAxiosSettings() injecte la configuration utilisateur (proxy/CA, etc.) dans axios. La structure de réponse est { data: { result: "..." } } (notez qu'axios a automatiquement ajouté une couche data), qu'on extrait et qu'on emballe via formatResponse.toolResult pour le renvoyer au LLM.
WebSearchToolHandler ajoute une étape de formatage des résultats :
// 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 ne sont inclus dans le body que s'ils sont non vides ; la validation de mutex déclenche mistake++ puis toolError, sans envoyer la requête.
Limites et échecs
- portes non satisfaites : provider non cline, web tools désactivé par l'utilisateur, feature flag coupé — n'importe lequel manquant renvoie un toolError disabled sans incrémenter
mistake(feature flag gate:55-59). - non connecté : si
AuthService.getInstance().getAuthToken()renvoie vide, on lèveCLINE_ACCOUNT_AUTH_ERROR_MESSAGE, transformé dans le catch enError fetching web content: ...(auth check:146-148). - listes blanche et noire fournies ensemble : si web_search reçoit à la fois
allowed_domainsetblocked_domains,mistake+++ toolError, on bloque (mutual exclusivity:75-78). - hook PreToolUse annule : s'il lève
PreToolUseHookCancellationError, on renvoie toolDenied sans envoyer de requête (PreToolUse hook:131-140). - repli sur erreur de requête : si axios lève ou si le serveur n'est pas 200, le catch emballe en
Error fetching web content: .../Error performing web search: ...sans remonter à Task, pour que le modèle voie l'erreur (error catch:173-175). - timeout : 15 s axios ; les requêtes à longue traîne sont coupées et passent dans le catch d'erreur (
timeout:163). - résultat vide : si web_search renvoie 0 résultat, on retourne
Search completed (0 results found)sans ligne de suite (empty results:193-199).
Résumé
WebFetch et WebSearch sont les deux handlers par lesquels Cline fait du fetch/recherche réseau via son proxy serveur. Ils partagent la même gate (provider=cline + setting + flag), le même flux approbation/hook et le même timeout de 15 s. WebFetch renvoie le texte extrait par le serveur selon le prompt ; WebSearch renvoie une liste structurée {title, url} mise en forme en 1./2./3.. Aucun des deux n'écrit sur disque ni n'ouvre de navigateur : pure sortie réseau.
Pour aller plus loin :
- Outil navigateur (fetch local) :
/cap-tools/browser - Outils fichier et commande :
/cap-tools/file-ops - Chaîne de distribution des outils :
/agent-loop/task-class
Voir la documentation officielle : documentation Cline · README.