Skip to content
Open
437 changes: 372 additions & 65 deletions src/chrome/src/agent/agent.js

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/chrome/src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ async function loadScreenshotRedaction() {
}
const screenshotRedactionReady = loadScreenshotRedaction().catch(() => {});

// Image budget (issue #311): screenshot quality + how many screenshots the
// agent may capture per turn, and the max image dimension. Defaults preserve
// the previous behavior (auto detail, unlimited screenshots, 1568px cap).
async function loadImageBudget() {
const stored = await chrome.storage.local.get(['imageDetail', 'maxScreenshotsPerTurn', 'maxImageDimension']);
agent.applyImageBudgetFromStorage(stored);
}
// Retained so handleMessage can await hydration on a cold SW start — the first
// chat must not race ahead of the persisted image-budget settings (issue #311).
const imageBudgetReady = loadImageBudget().catch(() => {});

async function loadStrictSecretMode() {
const stored = await chrome.storage.local.get('strictSecretMode');
if (stored.strictSecretMode != null) agent.strictSecretMode = !!stored.strictSecretMode;
Expand Down Expand Up @@ -731,6 +742,13 @@ chrome.storage.onChanged.addListener((changes) => {
if (changes.screenshotRedaction) {
agent.screenshotRedaction = !!changes.screenshotRedaction.newValue;
}
if (changes.imageDetail || changes.maxScreenshotsPerTurn || changes.maxImageDimension) {
agent.applyImageBudgetFromStorage({
imageDetail: changes.imageDetail ? changes.imageDetail.newValue : undefined,
maxScreenshotsPerTurn: changes.maxScreenshotsPerTurn ? changes.maxScreenshotsPerTurn.newValue : undefined,
maxImageDimension: changes.maxImageDimension ? changes.maxImageDimension.newValue : undefined,
});
}
if (changes[API_MUTATION_OBSERVER_KEY]) {
setApiMutationObserverEnabled(changes[API_MUTATION_OBSERVER_KEY].newValue === true);
}
Expand Down Expand Up @@ -1516,6 +1534,7 @@ async function handleMessage(msg, sender) {
// storage round-trip on every message.
await Promise.all([planBeforeActReady, planReviewReady, customSkillsReady, userMemoryReady]);
await screenshotRedactionReady;
await imageBudgetReady;
}

switch (msg.action) {
Expand Down
13 changes: 13 additions & 0 deletions src/chrome/src/ui/locales/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,19 @@ export default {
"st.redaction.toggle.label": "إخفاء المحتوى الحساس في لقطات الشاشة",
"st.redaction.toggle.desc": "قبل إرسال لقطة الشاشة إلى نموذج رؤية، يقوم بتغبيش حقول النماذج والنص الذي يبدو كبريد إلكتروني أو رقم هاتف. يعمل الكشف بالكامل على جهازك — لا يُنقل أي شيء إضافي.",
"st.redaction.warning": "⚠️ هذا تعتيم بأفضل جهد ومن نوع fail-open: إذا تعذّر تشغيل التعتيم على صفحة ما (مثلًا مباشرة بعد التنقل، أو في عارضات PDF، أو على صفحات المتصفح المقيّدة)، فستُرسل لقطة الشاشة كما هي دون تعتيم. يعتمد الكشف فقط على استدلالات DOM — النص المرسوم على عنصر canvas، أو البيانات الشخصية داخل الصور، أو أي شيء لا يُعرف كحقل نموذج أو نص بريد/هاتف قد يفلت من الكشف، كما أن نص الصفحة المُرسل إلى النموذج لا يُعتَّم بهذا الإعداد. هذا ليس ضمانًا أمنيًا. للخصوصية الكاملة، استخدم نموذجًا محليًا/دون اتصال (llama.cpp أو Ollama): عندها لن تغادر لقطات الشاشة جهازك إطلاقًا ولن تعود هناك حاجة للتعتيم.",
"st.imageBudget.heading": "ميزانية الصور",
"st.imageBudget.desc": "يتحكم في حجم لقطات الشاشة وعدد ما يلتقطه الوكيل لكل جولة للرؤية. تقليل التفاصيل والأبعاد يخفض التكلفة والكمون على النقاط الطرفية الصغيرة؛ زيادتها تحافظ على الدقة. القيم الافتراضية تطابق السلوك السابق.",
"st.imageBudget.detail.label": "تفاصيل الصورة",
"st.imageBudget.detail.desc": "تفاصيل صورة الرؤية المُرسلة إلى النموذج. «high» يحافظ على مزيد من التفاصيل (مزيد من الرموز والتكلفة)؛ «low» يرسل صورة أصغر وأرخص؛ «auto» يترك القرار للمزوّد. يعتمد على المزوّد.",
"st.imageBudget.detail.high": "عالية (مزيد من التفاصيل والتكلفة)",
"st.imageBudget.detail.low": "منخفضة (أرخص وأقل تفاصيل)",
"st.imageBudget.detail.auto": "تلقائي (افتراضي المزوّد)",
"st.imageBudget.maxPerTurn.label": "أقصى لقطات لكل جولة",
"st.imageBudget.maxPerTurn.desc": "كم لقطة تلقائية يمكن للوكيل التقاطها للرؤية في جولة واحدة (0 = بلا حد). القيم الأقل تخفض التكلفة؛ عند استنفاد الميزانية تُتخطى اللقطات التلقائية اللاحقة في تلك الجولة.",
"st.imageBudget.maxPerTurn.unlimited": "بلا حد",
"st.imageBudget.maxDimension.label": "أقصى بُعد للصورة",
"st.imageBudget.maxDimension.desc": "أطول ضلع (العرض أو الارتفاع) بالبكسل لأي لقطة تُرسل إلى الرؤية. حد أصغر يصغّر الصور قبل الإرسال فيخفض الرموز والتكلفة. حد أكبر يحافظ على الدقة.",
"st.imageBudget.warning": "⚠️ تنطبق هذه الإعدادات على اللقطات المخصصة للرؤية (لقطة تلقائية، /screenshot، صفحة كاملة، verify_form). الصور المحفوظة يدويًا بدقة كاملة لا تتأثر. «Image detail» تحترمه نقاط النهاية بأسلوب OpenAI؛ قد يتجاهلها مزوّدون آخرون.",
"sp.slash.export_traces": "تصدير سلسلة الأدوات (التتبعات)",
"sp.export_traces.none": "لا توجد تتبعات لهذه المحادثة. فعّل «تسجيل التتبعات» في الإعدادات ثم أعد التشغيل.",
"sp.export_traces.error": "تعذّر تصدير التتبعات.",
Expand Down
17 changes: 17 additions & 0 deletions src/chrome/src/ui/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,23 @@ export default {
'st.transcription.failed': 'Failed: {error}',
'st.transcription.fill_required': 'Fill in Base URL and Model first.',

// Image budget (issue #311): tune screenshot quality + how many
// screenshots the agent may capture/send per turn, and how large each
// image may be. All controls live on the Multimodal tab.
'st.imageBudget.heading': 'Image budget',
'st.imageBudget.desc': 'Control screenshot size and how many the agent captures for vision per turn. Lower detail and dimension cuts cost and latency for smaller endpoints; higher keeps fidelity. Defaults match the previous behavior.',
'st.imageBudget.detail.label': 'Image detail',
'st.imageBudget.detail.desc': 'Vision image detail sent to the model. "high" keeps more detail (more tokens, higher cost); "low" sends a smaller, cheaper image; "auto" lets the provider decide. Provider-dependent.',
'st.imageBudget.detail.high': 'High (more detail, more cost)',
'st.imageBudget.detail.low': 'Low (cheaper, less detail)',
'st.imageBudget.detail.auto': 'Auto (provider default)',
'st.imageBudget.maxPerTurn.label': 'Max screenshots per turn',
'st.imageBudget.maxPerTurn.desc': 'How many auto-screenshots the agent may capture for vision within a single turn (0 = unlimited). Lower values reduce cost; once the budget is spent further auto-screenshots are skipped for that turn.',
'st.imageBudget.maxPerTurn.unlimited': 'Unlimited',
'st.imageBudget.maxDimension.label': 'Max image dimension',
'st.imageBudget.maxDimension.desc': 'Largest side (width or height) in pixels for any screenshot sent to vision. Smaller caps shrink images before they are sent, cutting tokens and cost. Larger caps keep fidelity.',
'st.imageBudget.warning': '⚠️ These settings apply to screenshots captured for vision (auto-screenshot, /screenshot, full-page, verify_form). Manually saved full-resolution images are unaffected. "Image detail" is honored by OpenAI-style endpoints; other providers may ignore it.',

// Screenshot redaction (issue #312): local, best-effort PII blurring that
// runs in-browser before any screenshot reaches a vision model.
'st.redaction.heading': 'Screenshot redaction',
Expand Down
13 changes: 13 additions & 0 deletions src/chrome/src/ui/locales/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,19 @@ export default {
"st.redaction.toggle.label": "Redactar contenido sensible en las capturas de pantalla",
"st.redaction.toggle.desc": "Antes de enviar una captura de pantalla a un modelo de visión, difumina los campos de formulario y el texto que parezca un correo electrónico o un número de teléfono. La detección se ejecuta enteramente en tu dispositivo — no se transmite nada adicional.",
"st.redaction.warning": "⚠️ Es una redacción best-effort y fail-open: si no se puede aplicar en una página (por ejemplo justo después de una navegación, en visores de PDF o en páginas restringidas del navegador), la captura se envía igualmente sin redactar. La detección usa solo heurísticas del DOM — texto dibujado en un canvas, datos personales dentro de imágenes, o cualquier cosa no reconocida como campo de formulario o texto de correo/teléfono puede pasar desapercibida, y el texto de la página enviado al modelo no se redacta con este ajuste. No es una garantía de seguridad. Para privacidad total, usa un modelo local/sin conexión (llama.cpp, Ollama): las capturas nunca saldrán de tu equipo y la redacción deja de ser necesaria.",
"st.imageBudget.heading": "Presupuesto de imágenes",
"st.imageBudget.desc": "Controla el tamaño de las capturas y cuántas toma el agente por turno para visión. Menor detalle y dimensión reducen coste y latencia en endpoints pequeños; mayor valor mantiene la fidelidad. Los valores predeterminados coinciden con el comportamiento anterior.",
"st.imageBudget.detail.label": "Detalle de imagen",
"st.imageBudget.detail.desc": "Detalle de la imagen de visión enviada al modelo. «high» conserva más detalle (más tokens y coste); «low» envía una imagen más pequeña y barata; «auto» deja decidir al proveedor. Depende del proveedor.",
"st.imageBudget.detail.high": "Alto (más detalle, más coste)",
"st.imageBudget.detail.low": "Bajo (más barato, menos detalle)",
"st.imageBudget.detail.auto": "Automático (predeterminado del proveedor)",
"st.imageBudget.maxPerTurn.label": "Máx. capturas por turno",
"st.imageBudget.maxPerTurn.desc": "Cuántas capturas automáticas puede tomar el agente para visión en un solo turno (0 = ilimitado). Valores más bajos reducen el coste; cuando se agota el presupuesto, no se toman más capturas automáticas en ese turno.",
"st.imageBudget.maxPerTurn.unlimited": "Ilimitado",
"st.imageBudget.maxDimension.label": "Dimensión máxima de imagen",
"st.imageBudget.maxDimension.desc": "Lado mayor (ancho o alto) en píxeles de cualquier captura enviada a visión. Un tope más bajo reduce las imágenes antes de enviarlas, cortando tokens y coste. Un tope más alto mantiene la fidelidad.",
"st.imageBudget.warning": "⚠️ Estos ajustes se aplican a capturas para visión (auto-captura, /screenshot, página completa, verify_form). Las imágenes guardadas manualmente a resolución completa no se ven afectadas. «Image detail» lo respetan endpoints estilo OpenAI; otros proveedores pueden ignorarlo.",
"sp.slash.export_traces": "Exportar la cadena de herramientas (trazas)",
"sp.export_traces.none": "No hay trazas para esta conversación. Activa «Registrar trazas» en Ajustes y vuelve a ejecutar.",
"sp.export_traces.error": "No se pudieron exportar las trazas.",
Expand Down
13 changes: 13 additions & 0 deletions src/chrome/src/ui/locales/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,19 @@ export default {
"st.redaction.toggle.label": "Flouter le contenu sensible dans les captures d'écran",
"st.redaction.toggle.desc": "Avant qu'une capture d'écran soit envoyée à un modèle de vision, floute les champs de formulaire et le texte qui ressemble à un e-mail ou un numéro de téléphone. La détection s'exécute entièrement sur votre appareil — rien de plus n'est transmis.",
"st.redaction.warning": "⚠️ Meilleur effort et fail-open : si le floutage ne peut pas s'exécuter sur une page (par exemple juste après une navigation, dans les visionneuses PDF, ou sur des pages restreintes du navigateur), la capture est quand même envoyée non floutée. La détection utilise uniquement des heuristiques DOM — texte dessiné sur un canvas, données personnelles dans des images, ou tout ce qui n'est pas reconnu comme champ de formulaire ou texte e-mail/téléphone peut passer inaperçu, et le texte de la page envoyé au modèle n'est pas flouté par ce réglage. Ce n'est PAS une garantie de sécurité. Pour une confidentialité totale, utilisez un modèle local/hors ligne (llama.cpp, Ollama) : les captures ne quittent alors jamais votre machine et le floutage devient inutile.",
"st.imageBudget.heading": "Budget d’images",
"st.imageBudget.desc": "Contrôle la taille des captures et le nombre que l’agent prend pour la vision par tour. Moins de détail et une dimension plus petite réduisent le coût et la latence sur les petits endpoints ; plus élevé conserve la fidélité. Les valeurs par défaut reprennent le comportement précédent.",
"st.imageBudget.detail.label": "Détail d’image",
"st.imageBudget.detail.desc": "Détail d’image vision envoyé au modèle. « high » garde plus de détail (plus de tokens et de coût) ; « low » envoie une image plus petite et moins chère ; « auto » laisse le fournisseur décider. Dépend du fournisseur.",
"st.imageBudget.detail.high": "Élevé (plus de détail, plus de coût)",
"st.imageBudget.detail.low": "Faible (moins cher, moins de détail)",
"st.imageBudget.detail.auto": "Auto (défaut du fournisseur)",
"st.imageBudget.maxPerTurn.label": "Captures max. par tour",
"st.imageBudget.maxPerTurn.desc": "Nombre de captures auto que l’agent peut prendre pour la vision dans un tour (0 = illimité). Une valeur plus basse réduit le coût ; une fois le budget épuisé, les captures auto suivantes sont ignorées pour ce tour.",
"st.imageBudget.maxPerTurn.unlimited": "Illimité",
"st.imageBudget.maxDimension.label": "Dimension max. d’image",
"st.imageBudget.maxDimension.desc": "Plus grand côté (largeur ou hauteur) en pixels pour toute capture envoyée à la vision. Un plafond plus bas réduit les images avant envoi, ce qui coupe tokens et coût. Un plafond plus haut conserve la fidélité.",
"st.imageBudget.warning": "⚠️ Ces réglages s’appliquent aux captures pour la vision (auto-capture, /screenshot, page entière, verify_form). Les images enregistrées manuellement en pleine résolution ne sont pas affectées. « Image detail » est respecté par les endpoints de type OpenAI ; d’autres fournisseurs peuvent l’ignorer.",
"sp.slash.export_traces": "Exporter la chaîne d'outils (traces)",
"sp.export_traces.none": "Aucune trace pour cette conversation. Activez « Enregistrer les traces » dans les paramètres, puis relancez.",
"sp.export_traces.error": "Impossible d'exporter les traces.",
Expand Down
13 changes: 13 additions & 0 deletions src/chrome/src/ui/locales/he.js
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,19 @@ export default {
"st.redaction.toggle.label": "טשטש תוכן רגיש בצילומי מסך",
"st.redaction.toggle.desc": "לפני שצילום מסך נשלח למודל ראייה, מטשטש שדות טופס וטקסט שנראה כמו אימייל או מספר טלפון. הזיהוי פועל כולו במכשיר שלך — שום דבר נוסף לא מועבר.",
"st.redaction.warning": "⚠️ זהו טשטוש במאמץ סביר (best-effort) מסוג fail-open: אם הטשטוש לא יכול לפעול בדף מסוים (למשל מיד אחרי ניווט, בצפייה בקבצי PDF, או בדפי דפדפן מוגבלים), צילום המסך עדיין יישלח ללא טשטוש. הזיהוי מסתמך רק על היוריסטיקות DOM — טקסט המצויר על canvas, מידע אישי בתוך תמונות, או כל דבר שלא מזוהה כשדה טופס או כטקסט אימייל/טלפון עלול לחמוק, וטקסט הדף הנשלח למודל אינו מטושטש על ידי הגדרה זו. זו אינה ערבות אבטחה. לפרטיות מלאה, השתמש במודל מקומי/לא מקוון (llama.cpp, Ollama): כך צילומי מסך לעולם לא יעזבו את המכשיר שלך והטשטוש כבר לא יידרש.",
"st.imageBudget.heading": "תקציב תמונות",
"st.imageBudget.desc": "שולט בגודל צילומי המסך ובכמה פעמים הסוכן מצלם לצורכי ראייה בכל תור. פרט ומימד נמוכים יותר מפחיתים עלות והשהיה בקצוות קטנים; גבוהים יותר שומרים על נאמנות. ברירות המחדל תואמות להתנהגות הקודמת.",
"st.imageBudget.detail.label": "רמת פירוט תמונה",
"st.imageBudget.detail.desc": "רמת פירוט תמונת הראייה שנשלחת למודל. «high» שומר יותר פרטים (יותר טוקנים ועלות); «low» שולח תמונה קטנה וזולה יותר; «auto» משאיר לספק להחליט. תלוי בספק.",
"st.imageBudget.detail.high": "גבוה (יותר פרטים, יותר עלות)",
"st.imageBudget.detail.low": "נמוך (זול יותר, פחות פרטים)",
"st.imageBudget.detail.auto": "אוטומטי (ברירת מחדל של הספק)",
"st.imageBudget.maxPerTurn.label": "מקס׳ צילומים לתור",
"st.imageBudget.maxPerTurn.desc": "כמה צילומי מסך אוטומטיים הסוכן רשאי לצלם לראייה בתור אחד (0 = ללא הגבלה). ערכים נמוכים מפחיתים עלות; כשהתקציב נגמר, צילומים אוטומטיים נוספים בתור הזה מדולגים.",
"st.imageBudget.maxPerTurn.unlimited": "ללא הגבלה",
"st.imageBudget.maxDimension.label": "ממד תמונה מרבי",
"st.imageBudget.maxDimension.desc": "הצלע הארוכה (רוחב או גובה) בפיקסלים לכל צילום שנשלח לראייה. תקרה נמוכה יותר מקטינה תמונות לפני השליחה ומורידה טוקנים ועלות. תקרה גבוהה יותר שומרת נאמנות.",
"st.imageBudget.warning": "⚠️ ההגדרות האלה חלות על צילומים לראייה (צילום אוטומטי, /screenshot, עמוד מלא, verify_form). תמונות שנשמרו ידנית ברזולוציה מלאה אינן מושפעות. «Image detail» מכובד על ידי נקודות קצה בסגנון OpenAI; ספקים אחרים עשויים להתעלם.",
"sp.slash.export_traces": "ייצוא שרשרת הכלים (מעקבים)",
"sp.export_traces.none": "אין מעקבים לשיחה זו. הפעילו את «הקלטת מעקבים» בהגדרות והריצו שוב.",
"sp.export_traces.error": "לא ניתן לייצא מעקבים.",
Expand Down
Loading