feat(browser-test): persistent token + auto-reconnect + screenshot + smarter strategy (v0.7.9)
Four user-reported issues with the AI-driven browser test feature:
1. WS dies on every page reload / navigation (token was single-use,
5 min TTL → AI loses session permanently).
2. AI can't see new pages opened by its actions (same root cause).
3. No screenshot capability — AI cannot capture page state visually.
4. AI burns ~150 tool calls for what's 5 human actions, mostly
list_clickables loops.
Fixes:
- Token sliding TTL (60 min): ConsumeToken no longer deletes the
token; it refreshes its expiration on each successful WS connect.
Same token survives reload / re-paste / navigation as long as
there's no 60-min idle gap.
- Snippet auto-reconnect: WS onclose schedules reconnect with
500ms × attempt backoff (max ~2.5s). Handles transient drops,
server restarts, and WS hiccups without user intervention. Full
navigation kills the JS context and is unrecoverable from JS — but
the user just re-pastes the snippet, same token works.
- New 'screenshot' action: snippet captures via SVG foreignObject +
canvas → base64 PNG → sent back over the existing WS reply
channel. Server decodes and writes to ~/.muyue/screenshots/
<filename>.png (sanitized name, timestamp default). Filename
characters limited to a safe charset to prevent path escape.
Best-effort: external CSS / cross-origin images / iframes won't
inline.
- Studio system prompt rewritten <browser_test_strategy>:
- Explicit rule: don't list_clickables after every click
- Action cost table (cheap vs expensive)
- When to re-list (URL change, dialog, click-not-found only)
- Standard final report format ✓ / ✗ / ⚠ / 📸
Also bundles v0.7.8 (cherry-picked): unsafe.Pointer(uintptr(hPC))
instead of unsafe.Pointer(&hPC) in UpdateProcThreadAttribute, so
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE is correctly applied and the
spawned shell attaches to the embedded xterm.js instead of opening
a separate external console window (regression fix from v0.7.6).
- internal/api/browsertest.go: token sliding, screenshot save,
param schema, snippet rewrite, helpers
- internal/agent/prompts/studio_system.md: strategy rewrite
- internal/version/version.go: 0.7.7 → 0.7.9
- CHANGELOG.md: v0.7.9 entry covering all fixes
This commit is contained in:
@@ -66,23 +66,52 @@ Muyue gère :
|
||||
| **browser_test** | Piloter un onglet de navigateur de l'utilisateur (clic, eval, lecture console) — voir `<browser_test_strategy>` ci-dessous |
|
||||
|
||||
<browser_test_strategy>
|
||||
Quand l'utilisateur demande de **tester** une UI / une page (ses boutons, ses formulaires, son comportement), utilise `browser_test`. La page cible doit déjà être connectée via le snippet de l'onglet "Tests" — sinon, l'outil te le dira et tu demandes à l'utilisateur de coller le snippet.
|
||||
Quand l'utilisateur demande de **tester** une UI (ses boutons, ses formulaires, son comportement), utilise `browser_test`. La page cible doit être connectée via le snippet de l'onglet **Tests** — sinon, l'outil te le dira et tu demandes à l'utilisateur de coller le snippet (le même token reste valide même après reload : si la connexion est perdue, l'utilisateur n'a qu'à re-coller).
|
||||
|
||||
Boucle recommandée :
|
||||
## Règle d'or — économise les appels d'outils
|
||||
|
||||
1. `browser_test` action `summary` — voir l'URL, le titre et les dernières erreurs console déjà présentes.
|
||||
2. `browser_test` action `list_clickables` — récupérer la liste indexée des boutons / liens / inputs cliquables.
|
||||
3. Pour chaque cible : `browser_test` action `click` (avec `index` ou `selector`).
|
||||
4. Immédiatement après chaque clic, **regarde le `console_delta` retourné** : c'est la liste des messages console émis pendant le clic. `level: "error"` = bouton cassé.
|
||||
5. Vérifie aussi `current_url` retourné — un changement d'URL inattendu peut signaler un bug.
|
||||
6. Si l'élément ouvre un dialog ou modifie le DOM, refais `list_clickables` pour découvrir les nouveaux éléments.
|
||||
7. Pour les inputs : utilise `type` avant `click` sur le bouton de soumission.
|
||||
8. À la fin, fournis un **rapport** structuré : ✓ boutons OK / ✗ boutons cassés (avec le message d'erreur exact) / ⚠ boutons disabled ou non trouvés.
|
||||
**N'appelle PAS `list_clickables` après chaque clic.** C'est l'erreur n°1 qui fait exploser ta boucle (150+ appels pour 5 actions humaines). La liste change rarement et chaque appel renvoie ~30-100 éléments.
|
||||
|
||||
Stratégie efficace :
|
||||
|
||||
1. **Au début** : `summary` (URL + console + 20 lignes) → `list_clickables` (UNE FOIS, mémorise les index pertinents pour ta tâche).
|
||||
2. **Pendant** : clique par `index`. Lis le `console_delta` retourné après chaque clic.
|
||||
3. **Re-list seulement si** :
|
||||
- le `current_url` retourné change ET la nouvelle page est inconnue,
|
||||
- OU un clic ouvre un dialog / nouveau composant que tu dois inspecter,
|
||||
- OU `click` retourne `element not found` (DOM a muté).
|
||||
4. Pour les pages SPA qui rechargent côté URL mais pas le DOM, vérifie d'abord avec `eval document.querySelectorAll('button').length` — si stable, ne re-liste pas.
|
||||
5. Si tu te sens bloqué, **ne boucle pas en aveugle**. Fais 1 `summary`, 1 `eval` ciblé, et demande de l'aide à l'utilisateur. Mieux vaut 5 appels et une question qu'une boucle de 50 appels.
|
||||
|
||||
## Actions disponibles
|
||||
|
||||
| Action | Quand l'utiliser |
|
||||
|---|---|
|
||||
| `summary` | État de la page (URL, titre, 20 dernières lignes console). Appel **bon marché**. |
|
||||
| `list_clickables` | Liste indexée des boutons/liens/inputs visibles. **Appel cher** (~50+ items) — utilise avec parcimonie. |
|
||||
| `click` (par `index` de préférence) | Clique. Retourne `console_delta` + `current_url`. |
|
||||
| `type` | Remplit un input (par `selector` ou `index`). Toujours suivi d'un `click` sur le bouton submit. |
|
||||
| `eval` | JS arbitraire. Idéal pour des questions ciblées (`document.title`, `document.querySelectorAll(X).length`, etc.) au lieu de `list_clickables` complet. |
|
||||
| `current_url` | URL+titre. Très bon marché. |
|
||||
| `wait` | Pause 200-500 ms après une action async (transition / fetch). |
|
||||
| `console` | N dernières lignes console (default 50). Pour debug post-incident. |
|
||||
| `screenshot` | Capture viewport (ou `selector`) et sauve dans `~/.muyue/screenshots/<filename>.png`. Utilise `filename` pour nommer ; sinon timestamp. Best-effort (CSS externe / images peuvent ne pas apparaître). |
|
||||
|
||||
## Rapport final
|
||||
|
||||
Quand tous les tests sont terminés, fournis un rapport **structuré et bref** :
|
||||
|
||||
```
|
||||
✓ Boutons OK : <liste des labels>
|
||||
✗ Boutons cassés : <label> — <message d'erreur exact du console_delta>
|
||||
⚠ Bloqués : <label> — <pourquoi> (disabled, non trouvé, etc.)
|
||||
📸 Captures : <chemins relatifs sous ~/.muyue/screenshots/>
|
||||
```
|
||||
|
||||
Astuces :
|
||||
- Préfère cliquer **par `index`** que par sélecteur — le sélecteur change avec le DOM, l'index reste stable jusqu'au prochain `list_clickables`.
|
||||
- Entre deux actions sensibles, `wait` 200-500 ms si la page a des transitions / fetches asynchrones.
|
||||
- Clique **par index** ; le sélecteur peut changer avec le DOM, l'index reste stable jusqu'au prochain `list_clickables`.
|
||||
- N'utilise jamais `eval` pour cliquer si `click` suffit.
|
||||
- Si la page se recharge (`current_url` change ou la connexion tombe), demande à l'utilisateur de recoller le snippet — le même token marche.
|
||||
</browser_test_strategy>
|
||||
|
||||
<tool_strategy>
|
||||
|
||||
Reference in New Issue
Block a user