Lot 42 : outils web de l'agent exécutés par la façade

Les outils web des tours de la façade (web_search, web_images, web_open,
web_read, web_grep) ne passent plus par /tool/exec du Go : src/webtools.rs
porte chat_internet_tools.go, chat_internet.go et chat_web_images.go. Le
cache des pages (10 min, clé MD5 des options comme le Go) est dans la
façade ; client Crawl4AI au corps près, réponses lues comme json.Unmarshal ;
résultats DuckDuckGo tirés du markdown (uddg, entités, extraits) ;
recherche d'images avec le jeton vqd et les cookies gardés par hôte ;
web_grep sur les regex du Go, erreurs au texte de regexp.

Le moteur intégré lit le HTML avec go-readability et html-to-markdown, que
rien en Rust ne reproduit au caractère près : la conversion d'une page et la
lecture des résultats restent au Go, derrière /internal/v1/web/fetch et
/internal/v1/web/search (sans état). web_screenshot reste au Go.

Le traducteur go_regex refuse la répétition d'une répétition et les comptes
au-delà de 1000, et rend littéral un « { » qui n'ouvre pas de répétition,
comme le Go (motifs retry_patterns compris).

Parité : journal de 74 appels tiré du Go (parity_web_tools_test.go →
tests/parity_web/outils.json : résultats, requêtes reçues par les faux
Crawl4AI et DuckDuckGo, pages demandées au moteur intégré), rejoué par
tests/webtools.rs ; un tour de la façade qui ouvre une page (tests/lot6.rs) ;
TestInternalMoteurWebIntegre côté Go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
Claude committed 2026-10-16 05:29:35 +00:00
1 parent bed6d07739
commit f66d1b7621
19 files changed
+4561 -7

No files matched your search

@@ -0,0 +1,121 @@
# Lot 42 — Outils web de l'agent dans la façade
## Contexte
La façade tient la conversation par défaut. Les outils web de ses tours
partaient pourtant au Go (`/internal/v1/tool/exec`) :
- `web_search` ;
- `web_images` ;
- `web_open`, `web_read`, `web_grep`.
Le cache des pages (10 min) était donc au Go : `web_open` puis `web_read`
faisaient chacun un aller-retour.
## Le lot
`src/webtools.rs` porte les outils. Sources Go :
- `chat_internet_tools.go` : les quatre outils de lecture et de recherche ;
- `chat_internet.go` : client Crawl4AI, cache, lecture des résultats
DuckDuckGo ;
- `chat_web_images.go` : recherche d'images.
Ce qui est porté :
- **le cache** :
- clé : l'URL, suivie de l'empreinte MD5 des options qui changent la page
(actions, attente, bandeaux), à l'échappement HTML près du Go ;
- `web_read` et `web_grep` lisent l'ouverture la plus récente d'une URL,
toutes options confondues ;
- 10 minutes ;
- **Crawl4AI** :
- corps envoyé au Go près (clés triées, échappement HTML) ;
- clé d'accès en `Bearer` ;
- réponse `{results:[…]}` ou résultat seul, lue comme `json.Unmarshal`
(types faux, `null`, casse des clés) ;
- markdown en chaîne ou `{raw_markdown, fit_markdown}` ;
- erreurs : HTTP (fin du corps), échec du crawl, réponse vide, serveur
injoignable (texte de l'erreur du client Go) ;
- **les lignes** : `\r\n`, blancs de fin, vides et doublons consécutifs
réduits ; plan des titres ;
- **la recherche par Crawl4AI** : titres, liens `uddg` décodés deux fois
comme le Go, entités HTML, extrait tiré des liens qui suivent, doublons et
liens DuckDuckGo écartés, défi anti-bot ;
- **les images** :
- jeton `vqd` de la page, puis `i.js` ;
- mêmes en-têtes ;
- cookies gardés par hôte, comme le jar du client Go ;
- réponse lue comme `json.Unmarshal` (erreurs de syntaxe et de type au
texte du Go) ;
- **`web_grep`** :
- regex du Go (`(?i)`, classes ASCII) ;
- erreurs au texte de `regexp` pour les fautes courantes ;
- **le plafond** de 8000 caractères ;
- **les arguments** : nombres tronqués comme `int(float64)` du Go.
Le moteur intégré lit le HTML avec go-readability, html-to-markdown et le
parseur HTML5 de x/net : rien en Rust ne les reproduit au caractère près.
Ces deux étapes restent au Go, derrière deux appels sans état :
- `POST /internal/v1/web/fetch` `{url}` → `{markdown}` ou `{error}`
(`goFetchMarkdown`) ;
- `POST /internal/v1/web/search` `{query, limit}` → `{results}` ou `{error}`
(`goSearch`).
`ChatShared.web` porte les outils ; `GoTurnHost::exec_tool` les exécute
avant tout le reste. `web_screenshot` reste au Go (navigateur piloté).
Le traducteur des regex du Go (`go_regex`) refuse désormais :
- la répétition d'une répétition (`a**`, `a*??`, `a{2}*`) ;
- un compte au-delà de 1000 ou inversé.
Un `{` qui n'ouvre pas de répétition y devient littéral, comme au Go. Les
motifs `retry_patterns` en profitent.
Côté Go, pour le journal :
- `webNow` : l'horloge du cache ;
- `ddgImagesBase` et `ddgHTMLBase` : les adresses de DuckDuckGo.
## Écart connu
reqwest pose `Accept: */*` sur une requête qui n'en a pas ; le client Go
n'en pose aucun. Seule la page de recherche d'images est concernée, sans
effet sur DuckDuckGo.
## Parité
`internal/loki/parity_web_tools_test.go` tire du Go un journal de 74
appels (`tests/parity_web/outils.json`). Chaque appel porte :
- le résultat ;
- les requêtes reçues par le faux Crawl4AI (méthode, clé, type, corps) ;
- les requêtes reçues par le faux DuckDuckGo (chemin, en-têtes, cookies) ;
- les pages et recherches demandées au moteur intégré.
Il couvre :
- recherche : limites, anti-bot, aucun résultat, panne ;
- lecture : plages, bornes, au-delà, page jamais ouverte ;
- grep : contexte fusionné, plafond, sans résultat, classes ASCII, sept
regex invalides ;
- cache : réouverture, forcée, options, la plus récente, péremption ;
- GitHub ;
- les réponses de Crawl4AI ;
- serveur injoignable, sans serveur, sans clé ;
- moteur intégré : ouverture, texte brut, page absente, recherche ;
- images : doublons, cookie gardé, jeton absent, pannes, réponses
illisibles ou mal typées, `null`.
`tests/webtools.rs` le rejoue contre le port. Le faux Go sert ce que le
moteur intégré a tiré des pages.
D'autres tests complètent le journal :
- `tests/lot6.rs` (`outil_web_par_la_facade`) : un tour de la façade ouvre
une page sans passer par `/tool/exec` ;
- `TestInternalMoteurWebIntegre` : les deux appels internes du Go ;
- tests unitaires : MD5, clés du cache, URL, entités, nombres, erreurs de
regex, réponses de Crawl4AI.