Lot 45 : outils d'image (see_image, web_screenshot) tenus par la façade

La façade exécute les deux outils qui montrent une image au modèle
(src/imagetools.rs, port de chat_vision_tool.go, chat_screenshot.go et
prepareImageForModel) : préparation de l'image comme les pièces jointes
(orientation EXIF, grand côté sous 1568 px, mêmes pixels), sonde du moteur
(/props authentifié, gardée 10 s ; preset externe : sa case), see_image aux
textes du Go, web_screenshot par Playwright (adresses locales quand internet
est coupé, mêmes arguments, erreur résumée, capture rangée dans le dossier
de la discussion, ménage à 20 captures et 40 Mo, relayée au modèle s'il
voit les images). Le Go garde les siens pour ses sous-agents et tâches IA.

Parité : journal tiré du Go avec ses fichiers, un faux moteur et un faux
Playwright (tests/parity_images/images.json), rejoué par
tests/imagetools.rs ; un tour de la façade sans passer par le Go
(tests/lot6.rs) ; tests unitaires.

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 06:36:08 +00:00
1 parent fe51bdeee9
commit db1f20c0a4
11 files changed
+2090

No files matched your search

+286
View File
@@ -0,0 +1,286 @@
//! Lot 45 : outils d'image de l'agent (`see_image`, `web_screenshot`)
//! tenus par la façade, rejoués sur le journal du Go
//! (`internal/loki/parity_image_tools_test.go` →
//! `tests/parity_images/images.json`) : mêmes fichiers, même faux moteur
//! (`/props`), même faux Playwright. Une image laissée telle quelle se
//! compare à l'octet ; une image réencodée par ses dimensions et son type,
//! et une PNG réduite par ses pixels.
#![cfg(target_os = "linux")]
mod common;
use std::convert::Infallible;
use std::sync::{Arc, Mutex};
use base64::Engine as _;
use bytes::Bytes;
use common::fakego;
use http_body_util::Full;
use hyper::service::service_fn;
use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use loki_rs::imagetools::{self, VisionProbe};
use loki_rs::store::Store;
use regex::Regex;
use serde_json::{Map, Value, json};
use tokio::net::TcpListener;
const FAKE_PLAYWRIGHT: &str = r#"#!/bin/sh
d=$(dirname "$0")
printf '%s\n' "$@" > "$d/args"
for a in "$@"; do out="$a"; done
mode=$(cat "$d/mode" 2>/dev/null)
case "$mode" in
echec) echo "Launching chromium" ; echo "" ; echo "page.goto: net::ERR_NAME_NOT_RESOLVED at https://x" >&2 ; echo "Call log:" >&2 ; echo " - navigating" >&2 ; exit 1 ;;
vide) : > "$out" ;;
rien) ;;
*) cat "$d/image" > "$out" ;;
esac
"#;
/// Le faux moteur : `/props` authentifié, la vision réglée par le test.
async fn fake_engine(sees: Arc<Mutex<(bool, u32)>>) -> u16 {
let l = TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = l.local_addr().unwrap().port();
tokio::spawn(async move {
while let Ok((st, _)) = l.accept().await {
let sees = sees.clone();
tokio::spawn(async move {
let svc = service_fn(move |req: Request<hyper::body::Incoming>| {
let sees = sees.clone();
async move {
let ok = req.uri().path() == "/props"
&& req
.headers()
.get("authorization")
.and_then(|h| h.to_str().ok())
== Some("Bearer cle-moteur");
let mut r = Response::new(Full::new(Bytes::new()));
if ok {
let mut s = sees.lock().unwrap();
s.1 += 1;
r = Response::new(Full::new(Bytes::from(
json!({ "modalities": { "vision": s.0 } }).to_string(),
)));
} else {
*r.status_mut() = hyper::StatusCode::UNAUTHORIZED;
}
Ok::<_, Infallible>(r)
}
});
let _ = hyper::server::conn::http1::Builder::new()
.serve_connection(TokioIo::new(st), svc)
.await;
});
}
});
port
}
/// `parityPartFacts`.
fn part_facts(part: &Value, raw: &Map<String, Value>) -> Value {
let u = part["image_url"]["url"].as_str().unwrap();
let i = u.find(";base64,").unwrap();
let mime = u[..i].trim_start_matches("data:");
let b = base64::engine::general_purpose::STANDARD
.decode(&u[i + 8..])
.unwrap();
let mut out = Map::new();
out.insert("mime".into(), json!(mime));
for (name, r) in raw {
let rb = base64::engine::general_purpose::STANDARD
.decode(r.as_str().unwrap_or(""))
.unwrap();
if rb == b {
out.insert("same_as".into(), json!(name));
return Value::Object(out);
}
}
let Ok(img) = image::load_from_memory(&b) else {
panic!("image relayée illisible");
};
let img = img.to_rgba8();
let (w, h) = img.dimensions();
out.insert("w".into(), json!(w));
out.insert("h".into(), json!(h));
if mime == "image/png" {
let mut px = Map::new();
for (x, y) in [(0, 0), (1, 1), (100, 50), (w - 1, h - 1), (w / 2, h / 3)] {
let p = img.get_pixel(x, y).0;
px.insert(
format!("{x},{y}"),
json!(format!("{},{},{},{}", p[0], p[1], p[2], p[3])),
);
}
out.insert("px".into(), Value::Object(px));
}
Value::Object(out)
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn outils_image_comme_le_go() {
let fx: Value =
serde_json::from_str(include_str!("parity_images/images.json")).expect("journal");
let tmp = tempfile::tempdir().unwrap();
let files = tmp.path().join("fichiers");
let raw = fx["files"].as_object().unwrap();
for (name, b) in raw {
let p = files.join(name);
std::fs::create_dir_all(p.parent().unwrap()).unwrap();
std::fs::write(
&p,
base64::engine::general_purpose::STANDARD
.decode(b.as_str().unwrap_or(""))
.unwrap(),
)
.unwrap();
}
std::fs::create_dir_all(files.join("dossier.png")).unwrap();
std::fs::File::create(files.join("lourd.png"))
.unwrap()
.set_len(13 << 20)
.unwrap();
let files_s = files.to_string_lossy().into_owned();
let sees = Arc::new(Mutex::new((false, 0u32)));
let port = fake_engine(sees.clone()).await;
let (_, go, _stop) = fakego::start(tmp.path().join("home")).await;
let backend = go.backend.lock().unwrap().unwrap();
let store = Store::new(backend, fakego::JETON.into());
go.set("state", "api_key", "cle-moteur");
let mut cfg = std::collections::HashMap::new();
cfg.insert("PORT".to_string(), port.to_string());
let probe = VisionProbe::default();
let pw_dir = tmp.path().join("pw");
std::fs::create_dir_all(&pw_dir).unwrap();
let pw = pw_dir.join("playwright");
std::fs::write(&pw, FAKE_PLAYWRIGHT).unwrap();
use std::os::unix::fs::PermissionsExt as _;
std::fs::set_permissions(&pw, std::fs::Permissions::from_mode(0o755)).unwrap();
let conv_dir = tmp.path().join("conv");
let cap_dir = conv_dir.join("captures");
let stamp_re = Regex::new(r"[0-9]{8}-[0-9]{6}").unwrap();
for (n, st) in fx["steps"].as_array().unwrap().iter().enumerate() {
let name = st["name"].as_str().unwrap();
*sees.lock().unwrap() = (st["sees"] == true, 0);
probe.reset().await;
std::fs::write(pw_dir.join("mode"), st["mode"].as_str().unwrap_or("")).unwrap();
if let Some(img) = st["image"].as_str() {
let b = base64::engine::general_purpose::STANDARD
.decode(raw[img].as_str().unwrap())
.unwrap();
std::fs::write(pw_dir.join("image"), b).unwrap();
}
let _ = std::fs::remove_file(pw_dir.join("args"));
if name == "ménage des captures" {
let old = std::time::SystemTime::now() - std::time::Duration::from_secs(3600);
for i in 0..22 {
let p = cap_dir.join(format!("vieille-{i:02}.jpg"));
std::fs::write(&p, "x").unwrap();
let f = std::fs::File::options().write(true).open(&p).unwrap();
f.set_modified(old + std::time::Duration::from_secs(i))
.unwrap();
}
}
let args: Map<String, Value> =
serde_json::from_str(&st["args"].to_string().replace("{{FICHIERS}}", &files_s))
.unwrap();
let label = st["label"]
.as_str()
.unwrap()
.replace("{{FICHIERS}}", &files_s);
let vision = st["vision"] == true;
let (mut result, part, shown) = match st["tool"].as_str().unwrap() {
"see_image" => {
let (r, img) =
imagetools::see_image(&label, &files, "", vision, probe.sees(&store, &cfg))
.await;
let relay = img.map(|i| loki_rs::chat::host::see_image_message(&label, i));
(r, relay, String::new())
}
_ => {
let stamp = format!("20260101-1200{:02}", n % 60);
let shot = imagetools::web_screenshot(
&args,
&pw.to_string_lossy(),
&conv_dir,
st["internet"] == true,
&stamp,
)
.await;
let relay = if !shot.rel.is_empty() && vision && probe.sees(&store, &cfg).await {
imagetools::screenshot_message(&shot.abs)
.and_then(|m| serde_json::from_value(m).ok())
} else {
None
};
(shot.result, relay, shot.rel)
}
};
let mut facts = None;
if let Some(m) = &relay_parts(&part) {
for p in m {
if p["type"] == "image_url" {
facts = Some(part_facts(p, raw));
}
if p["type"] == "text" {
result += &format!("\n[relais] {}", p["text"].as_str().unwrap());
}
}
}
let mask = |s: &str| {
stamp_re
.replace_all(&s.replace(&files_s, "{{FICHIERS}}"), "{{T}}")
.into_owned()
};
assert_eq!(mask(&result), st["result"].as_str().unwrap(), "{name}");
assert_eq!(facts, st.get("part").cloned(), "{name} : image relayée");
assert_eq!(
mask(&shown),
st["shown"].as_str().unwrap_or(""),
"{name} : capture montrée"
);
assert_eq!(
sees.lock().unwrap().1 as u64,
st["probes"].as_u64().unwrap(),
"{name} : sondes du moteur"
);
let pw_args: Vec<String> = std::fs::read_to_string(pw_dir.join("args"))
.map(|b| {
b.trim_end_matches('\n')
.split('\n')
.map(|l| {
mask(&l.replace(&cap_dir.to_string_lossy().into_owned(), "{{CAPTURES}}"))
})
.collect()
})
.unwrap_or_default();
assert_eq!(
json!(pw_args),
st.get("pw_args").cloned().unwrap_or(json!([])),
"{name} : Playwright"
);
if st["tool"] == "web_screenshot" {
let mut caps: Vec<String> = std::fs::read_dir(&cap_dir)
.into_iter()
.flatten()
.flatten()
.map(|e| mask(&e.file_name().to_string_lossy()))
.collect();
caps.sort();
assert_eq!(
json!(caps),
st.get("captures").cloned().unwrap_or(json!([])),
"{name} : dossier des captures"
);
}
}
}
/// Les parties d'un message relayé.
fn relay_parts(m: &Option<loki_rs::chat::types::Message>) -> Option<Vec<Value>> {
let m = m.as_ref()?;
m.content.as_ref()?.as_array().cloned()
}
+41
View File
@@ -674,6 +674,7 @@ async fn tour_complet_par_le_go() {
web: Default::default(),
jobs: Default::default(),
browser: Default::default(),
vision: Default::default(),
go_version: Default::default(),
});
let cfg = std::collections::HashMap::new();
@@ -2842,6 +2843,46 @@ async fn job_arriere_plan_par_la_facade() {
assert_eq!(jobs.running(), 0);
}
/// Lot 45 : `see_image` et `web_screenshot` sont exécutés par la façade
/// (rien par le Go) : sans projecteur, l'image n'est pas lue ; une capture
/// sans url est refusée avant Playwright.
#[tokio::test]
async fn outils_image_par_la_facade() {
let calls = sse(&[
serde_json::json!({"choices":[{"delta":{"tool_calls":[
{"index":0,"id":"v1","type":"function","function":{"name":"see_image","arguments":"{\"path\":\"photo.png\"}"}},
{"index":1,"id":"v2","type":"function","function":{"name":"web_screenshot","arguments":"{}"}}
]}}]}),
serde_json::json!({"choices":[{"delta":{},"finish_reason":"tool_calls"}]}),
]);
let (url, seen) = fake_engine(vec![calls, answer("vu")]).await;
let ws = tempfile::tempdir().unwrap();
std::fs::write(ws.path().join("photo.png"), b"x").unwrap();
let (svc, go, _stop, _t) = service_with(Some(&url), |_| {}).await;
*go.tool_ctx.lock().unwrap() = Some(serde_json::json!({
"cwd": ws.path(), "memory_dir": ws.path().join("mem"), "target": ""
}));
svc.send(serde_json::json!({"message": "regarde", "cid": "v"}))
.await
.unwrap();
until_done(&svc, 1).await;
assert!(go.tool_log.lock().unwrap().is_empty(), "{:?}", go.tool_log);
let seen = seen.lock().unwrap().clone();
let tools: Vec<String> = seen[1].1["messages"]
.as_array()
.unwrap()
.iter()
.filter(|m| m["role"] == "tool")
.map(|m| m["content"].as_str().unwrap().to_string())
.collect();
assert_eq!(tools.len(), 2, "{tools:?}");
assert!(tools[0].contains("la vision n'est pas active"), "{tools:?}");
assert!(
tools[1] == "[erreur] url manquante" || tools[1].contains("Playwright n'est pas installé"),
"{tools:?}"
);
}
/// Lot 44 : le navigateur piloté est celui de la façade. Un tour qui ouvre
/// une page l'exécute chez elle (rien par le Go), l'aperçu est servi par
/// /api/chat/cushot, et le Go passe par /internal/facade/v1/browser.
@@ -0,0 +1,614 @@
{
"files": {
"anim.gif": "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==",
"capture.jpg": "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 truncated
"capture.png": "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAoCAIAAADBrGu+AAAAZ0lEQVR4nOzS0QmAMBBEwQsG7b9ji9iPJTpwBdywb8/MNWsffPeaOfg+AHj6T/x8geMBEmoDLAAQAiQEEAIk1AZYACAESAggBEioDbAAQAiQEEAIkFAbYAGAECAhgBAgoe69AQAA//86MgyTWSqBGAAAAABJRU5ErkJggg==",
"cassee.png": "iVBORw0KGgphYsOubcOp",
"grande.jpeg": "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 truncated
"grande.png": "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 truncated
"haute.png": "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 truncated
"image.BMP": "Qk0gcGFzIHZyYWltZW50IHVuZSBpbWFnZQ==",
"image.webp": "UklGRhAAAABXRUJQVlA4IGZhdXg=",
"petite.png": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAIAAABPmPnhAAAAJUlEQVR4nGJhYGCQZGCUYmDESrIwyDMyMOBELAwKQ1QaEAAA//9xYwI0YqlbiQAAAABJRU5ErkJggg==",
"photo.jpg": "/9j/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIABQAKAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APgLTfh10/dfpXWab8Oun7r9K93034ddP3X6V1em/Drp+6/SvyqrxF/ePkcj4x2948I034c9P3X6V1em/Dnp+6/Svd9N+HXT91+ldXpvw56fuv0rxqvEX94/oTI+MdvePCNN+HXT91+laf8Awrr/AKZfpX0fpvw56fuv0rT/AOFdf9Mv0rypcRa/EfueC4x/dL3jiNN0S04/d11em6Jacfu6w9N7V1em9q/P6tSfc/xoyOrU095m7puiWnH7uur03QrTj93WHpvaus03tXjVak+5/QmR1amnvM29N0K04/d1p/2Faf8APOmab2rSryp1J33P3LBVqnsV7zP/2Q==",
"pleine.jpg": "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 truncated
"sous/tres.png": "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAH0lEQVR4nGJhYGAIZWAMZWBkYQhlZGAAIQQLEAAA//8aWAFpD3kcfgAAAABJRU5ErkJggg==",
"texte.txt": "cGFzIHVuZSBpbWFnZQ==",
"tournee.jpg": "/9j/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAYAAAAAAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIABQAKAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APgLTfh10/dfpXWab8Oun7r9K93034ddP3X6V1em/Drp+6/SvyqrxF/ePkcj4x2948I034c9P3X6V1em/Dnp+6/Svd9N+HXT91+ldXpvw56fuv0rxqvEX94/oTI+MdvePCNN+HXT91+laf8Awrr/AKZfpX0fpvw56fuv0rT/AOFdf9Mv0rypcRa/EfueC4x/dL3jiNN0S04/d11em6Jacfu6w9N7V1em9q/P6tSfc/xoyOrU095m7puiWnH7uur03QrTj93WHpvaus03tXjVak+5/QmR1amnvM29N0K04/d1p/2Faf8APOmab2rSryp1J33P3LBVqnsV7zP/2Q==",
"vide.png": ""
},
"steps": [
{
"name": "sans vision",
"tool": "see_image",
"args": {
"file": "petite.png"
},
"label": "petite.png",
"result": "[erreur] la vision n'est pas active sur ce preset (aucun projecteur MMPROJ configuré) — impossible de voir une image",
"probes": 0
},
{
"name": "chemin manquant",
"vision": true,
"tool": "see_image",
"args": {
"file": " "
},
"label": " ",
"result": "[erreur] format non reconnu comme image (attendu : png, jpg, gif, webp, bmp) : ",
"probes": 0
},
{
"name": "pas une image",
"vision": true,
"tool": "see_image",
"args": {
"file": "texte.txt"
},
"label": "texte.txt",
"result": "[erreur] format non reconnu comme image (attendu : png, jpg, gif, webp, bmp) : texte.txt",
"probes": 0
},
{
"name": "introuvable",
"vision": true,
"tool": "see_image",
"args": {
"file": "absente.png"
},
"label": "absente.png",
"result": "[erreur] fichier introuvable : absente.png",
"probes": 0
},
{
"name": "dossier",
"vision": true,
"tool": "see_image",
"args": {
"file": "dossier.png"
},
"label": "dossier.png",
"result": "[erreur] c'est un dossier, pas une image : dossier.png",
"probes": 0
},
{
"name": "trop lourde",
"vision": true,
"tool": "see_image",
"args": {
"file": "lourd.png"
},
"label": "lourd.png",
"result": "[erreur] image trop lourde (13 Mo, max 12 Mo) : lourd.png",
"probes": 0
},
{
"name": "le moteur ne voit pas",
"vision": true,
"tool": "see_image",
"args": {
"file": "petite.png"
},
"label": "petite.png",
"result": "[erreur] le moteur en service ne traite pas les images (projecteur non chargé ?) — impossible de voir petite.png",
"probes": 1
},
{
"name": "vide",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "vide.png"
},
"label": "vide.png",
"result": "[erreur] fichier vide : vide.png",
"probes": 1
},
{
"name": "voir petite.png",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "petite.png"
},
"label": "petite.png",
"result": "[ok] image chargée : petite.png\n[relais] Image demandée (petite.png) :",
"part": {
"mime": "image/png",
"same_as": "petite.png"
},
"probes": 1
},
{
"name": "voir grande.png",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "grande.png"
},
"label": "grande.png",
"result": "[ok] image chargée : grande.png\n[relais] Image demandée (grande.png) :",
"part": {
"h": 784,
"mime": "image/png",
"px": {
"0,0": "0,0,0,255",
"1,1": "0,0,2,255",
"100,50": "16,16,190,255",
"1567,783": "254,254,181,255",
"784,261": "127,84,52,255"
},
"w": 1568
},
"probes": 1
},
{
"name": "voir haute.png",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "haute.png"
},
"label": "haute.png",
"result": "[ok] image chargée : haute.png\n[relais] Image demandée (haute.png) :",
"part": {
"h": 1568,
"mime": "image/png",
"px": {
"0,0": "0,0,0,255",
"1,1": "0,0,2,255",
"100,50": "91,8,162,255",
"138,522": "126,84,202,255",
"276,1567": "253,254,205,255"
},
"w": 277
},
"probes": 1
},
{
"name": "voir photo.jpg",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "photo.jpg"
},
"label": "photo.jpg",
"result": "[ok] image chargée : photo.jpg\n[relais] Image demandée (photo.jpg) :",
"part": {
"mime": "image/jpeg",
"same_as": "photo.jpg"
},
"probes": 1
},
{
"name": "voir tournee.jpg",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "tournee.jpg"
},
"label": "tournee.jpg",
"result": "[ok] image chargée : tournee.jpg\n[relais] Image demandée (tournee.jpg) :",
"part": {
"h": 40,
"mime": "image/jpeg",
"w": 20
},
"probes": 1
},
{
"name": "voir grande.jpeg",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "grande.jpeg"
},
"label": "grande.jpeg",
"result": "[ok] image chargée : grande.jpeg\n[relais] Image demandée (grande.jpeg) :",
"part": {
"h": 784,
"mime": "image/jpeg",
"w": 1568
},
"probes": 1
},
{
"name": "voir anim.gif",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "anim.gif"
},
"label": "anim.gif",
"result": "[ok] image chargée : anim.gif\n[relais] Image demandée (anim.gif) :",
"part": {
"mime": "image/gif",
"same_as": "anim.gif"
},
"probes": 1
},
{
"name": "voir image.webp",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "image.webp"
},
"label": "image.webp",
"result": "[ok] image chargée : image.webp\n[relais] Image demandée (image.webp) :",
"part": {
"mime": "image/webp",
"same_as": "image.webp"
},
"probes": 1
},
{
"name": "voir image.BMP",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "image.BMP"
},
"label": "image.BMP",
"result": "[ok] image chargée : image.BMP\n[relais] Image demandée (image.BMP) :",
"part": {
"mime": "image/bmp",
"same_as": "image.BMP"
},
"probes": 1
},
{
"name": "voir cassee.png",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "cassee.png"
},
"label": "cassee.png",
"result": "[ok] image chargée : cassee.png\n[relais] Image demandée (cassee.png) :",
"part": {
"mime": "image/png",
"same_as": "cassee.png"
},
"probes": 1
},
{
"name": "voir sous/tres.png",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "sous/tres.png"
},
"label": "sous/tres.png",
"result": "[ok] image chargée : tres.png\n[relais] Image demandée (sous/tres.png) :",
"part": {
"mime": "image/png",
"same_as": "sous/tres.png"
},
"probes": 1
},
{
"name": "chemin absolu",
"vision": true,
"sees": true,
"tool": "see_image",
"args": {
"file": "{{FICHIERS}}/petite.png"
},
"label": "{{FICHIERS}}/petite.png",
"result": "[ok] image chargée : petite.png\n[relais] Image demandée ({{FICHIERS}}/petite.png) :",
"part": {
"mime": "image/png",
"same_as": "petite.png"
},
"probes": 1
},
{
"name": "capture sans url",
"tool": "web_screenshot",
"args": {},
"label": "",
"result": "[erreur] url manquante",
"probes": 0
},
{
"name": "url invalide",
"tool": "web_screenshot",
"args": {
"url": "ftp://x"
},
"label": "",
"result": "[erreur] url invalide : elle doit commencer par http:// ou https://",
"probes": 0
},
{
"name": "internet coupé",
"tool": "web_screenshot",
"args": {
"url": "https://exemple.test/"
},
"label": "",
"result": "[refusé] L'accès internet est coupé : la capture ne marche que sur une adresse locale (localhost / 127.0.0.1), par exemple ton serveur de dev. Active l'accès internet pour le web.",
"probes": 0
},
{
"name": "capture locale sans vision",
"image": "capture.jpg",
"tool": "web_screenshot",
"args": {
"url": "http://localhost:3000/app?x=1"
},
"label": "",
"result": "Capture enregistrée (captures/localhost-3000-{{T}}.jpg, 74 Ko).\nPour la montrer à l'utilisateur, recopie TELLE QUELLE cette ligne markdown dans ta réponse :\n![capture de localhost:3000](/api/chat/image?path=captures/localhost-3000-{{T}}.jpg)",
"shown": "captures/localhost-3000-{{T}}.jpg",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"http://localhost:3000/app?x=1",
"{{CAPTURES}}/localhost-3000-{{T}}.jpg"
],
"probes": 0,
"captures": [
"localhost-3000-{{T}}.jpg"
]
},
{
"name": "capture vue par le modèle",
"vision": true,
"sees": true,
"image": "capture.jpg",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "https://www.exemple.test/page#ancre",
"width": 1600
},
"label": "",
"result": "Capture enregistrée (captures/www.exemple.test-{{T}}.jpg, 74 Ko).\nPour la montrer à l'utilisateur, recopie TELLE QUELLE cette ligne markdown dans ta réponse :\n![capture de www.exemple.test](/api/chat/image?path=captures/www.exemple.test-{{T}}.jpg)\n[relais] Voici la capture demandée.",
"part": {
"mime": "image/jpeg",
"same_as": "capture.jpg"
},
"shown": "captures/www.exemple.test-{{T}}.jpg",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1600,800",
"--wait-for-timeout",
"3500",
"https://www.exemple.test/page#ancre",
"{{CAPTURES}}/www.exemple.test-{{T}}.jpg"
],
"probes": 1,
"captures": [
"localhost-3000-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "page entière réduite",
"vision": true,
"sees": true,
"image": "pleine.jpg",
"internet": true,
"tool": "web_screenshot",
"args": {
"full_page": true,
"url": "https://pleine.test/",
"width": 100
},
"label": "",
"result": "Capture enregistrée (captures/pleine.test-{{T}}.jpg, 253 Ko).\nPour la montrer à l'utilisateur, recopie TELLE QUELLE cette ligne markdown dans ta réponse :\n![capture de pleine.test](/api/chat/image?path=captures/pleine.test-{{T}}.jpg)\n[relais] Voici la capture demandée.",
"part": {
"h": 1568,
"mime": "image/jpeg",
"w": 669
},
"shown": "captures/pleine.test-{{T}}.jpg",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"--full-page",
"https://pleine.test/",
"{{CAPTURES}}/pleine.test-{{T}}.jpg"
],
"probes": 1,
"captures": [
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "vision mais moteur aveugle",
"vision": true,
"image": "capture.png",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "https://aveugle.test/"
},
"label": "",
"result": "Capture enregistrée (captures/aveugle.test-{{T}}.jpg, 0 Ko).\nPour la montrer à l'utilisateur, recopie TELLE QUELLE cette ligne markdown dans ta réponse :\n![capture de aveugle.test](/api/chat/image?path=captures/aveugle.test-{{T}}.jpg)",
"shown": "captures/aveugle.test-{{T}}.jpg",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"https://aveugle.test/",
"{{CAPTURES}}/aveugle.test-{{T}}.jpg"
],
"probes": 1,
"captures": [
"aveugle.test-{{T}}.jpg",
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "Playwright en échec",
"mode": "echec",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "https://x.test/"
},
"label": "",
"result": "[erreur] capture impossible : page.goto: net::ERR_NAME_NOT_RESOLVED at https://x · Call log: · - navigating",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"https://x.test/",
"{{CAPTURES}}/x.test-{{T}}.jpg"
],
"probes": 0,
"captures": [
"aveugle.test-{{T}}.jpg",
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "image vide",
"mode": "vide",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "https://vide.test/"
},
"label": "",
"result": "[erreur] Playwright n'a produit aucune image",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"https://vide.test/",
"{{CAPTURES}}/vide.test-{{T}}.jpg"
],
"probes": 0,
"captures": [
"aveugle.test-{{T}}.jpg",
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"vide.test-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "aucune image",
"mode": "rien",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "https://rien.test/"
},
"label": "",
"result": "[erreur] Playwright n'a produit aucune image",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"https://rien.test/",
"{{CAPTURES}}/rien.test-{{T}}.jpg"
],
"probes": 0,
"captures": [
"aveugle.test-{{T}}.jpg",
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"vide.test-{{T}}.jpg",
"www.exemple.test-{{T}}.jpg"
]
},
{
"name": "ménage des captures",
"image": "capture.png",
"internet": true,
"tool": "web_screenshot",
"args": {
"url": "http://127.0.0.1:8080/"
},
"label": "",
"result": "Capture enregistrée (captures/127.0.0.1-8080-{{T}}.jpg, 0 Ko).\nPour la montrer à l'utilisateur, recopie TELLE QUELLE cette ligne markdown dans ta réponse :\n![capture de 127.0.0.1:8080](/api/chat/image?path=captures/127.0.0.1-8080-{{T}}.jpg)",
"shown": "captures/127.0.0.1-8080-{{T}}.jpg",
"pw_args": [
"screenshot",
"--browser",
"chromium",
"--viewport-size",
"1280,800",
"--wait-for-timeout",
"3500",
"http://127.0.0.1:8080/",
"{{CAPTURES}}/127.0.0.1-8080-{{T}}.jpg"
],
"probes": 0,
"captures": [
"127.0.0.1-8080-{{T}}.jpg",
"aveugle.test-{{T}}.jpg",
"localhost-3000-{{T}}.jpg",
"pleine.test-{{T}}.jpg",
"vide.test-{{T}}.jpg",
"vieille-08.jpg",
"vieille-09.jpg",
"vieille-10.jpg",
"vieille-11.jpg",
"vieille-12.jpg",
"vieille-13.jpg",
"vieille-14.jpg",
"vieille-15.jpg",
"vieille-16.jpg",
"vieille-17.jpg",
"vieille-18.jpg",
"vieille-19.jpg",
"vieille-20.jpg",
"vieille-21.jpg",
"www.exemple.test-{{T}}.jpg"
]
}
]
}