fix: Glow-Bug + focusWorkingTab-Option
Glow-Fix (3 Ursachen behoben): - notifyGlow: schickt jetzt an targetTabId statt an den aktiven Tab des Nutzers. Vorher: Agent arbeitet in Tab B, Glow geht an Tab A (den der Nutzer gerade sieht) — Tab B leuchtet nie. - executeForBroker: notifyGlow(true) beim ersten Tool-Call, nicht erst bei 'round'. Vorher: targetTabId war bei 'round' noch null, currentTabId() gab undefined zurück, Glow wurde nie gesendet. - notifyTargetTab: Glow auf neuen Tab übertragen wenn Agent Tab wechselt. focusWorkingTab (neue Config-Option): - ExtensionConfig.focusWorkingTab: boolean (Default false) - notifyTargetTab: bringt Tab in Vordergrund wenn focusWorkingTab=true - Checkbox 'Tab live mitverfolgen' in Einstellungen > Anzeige & Sicherheit - false = Agent arbeitet im Hintergrund (bisheriges Verhalten) - true = Tab wird bei jedem Wechsel sichtbar
This commit is contained in:
+16
-2
@@ -183,6 +183,10 @@ async function executeForBroker(callId: string, name: string, input: Record<stri
|
|||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
let method: InteractionMethod = 'synthetic';
|
let method: InteractionMethod = 'synthetic';
|
||||||
|
|
||||||
|
// Glow beim ersten Tool-Call einschalten — zu diesem Zeitpunkt ist targetTabId
|
||||||
|
// noch null (wird erst in getActiveTab gesetzt), daher aktiven Tab nehmen.
|
||||||
|
notifyGlow(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sendToPanel({ type: 'tool_executing', callId, name, input });
|
sendToPanel({ type: 'tool_executing', callId, name, input });
|
||||||
const result = await runTool(name, input);
|
const result = await runTool(name, input);
|
||||||
@@ -214,7 +218,7 @@ function reportToolDone(
|
|||||||
sendToPanel({ type: 'tool_done', callId, name, result, error, durationMs, method });
|
sendToPanel({ type: 'tool_done', callId, name, result, error, durationMs, method });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sendet den aktuellen Target-Tab ans Panel. */
|
/** Sendet den aktuellen Target-Tab ans Panel und überträgt den Glow auf den neuen Tab. */
|
||||||
async function notifyTargetTab(): Promise<void> {
|
async function notifyTargetTab(): Promise<void> {
|
||||||
if (targetTabId === null) {
|
if (targetTabId === null) {
|
||||||
sendToPanel({ type: 'target_tab', tabId: null });
|
sendToPanel({ type: 'target_tab', tabId: null });
|
||||||
@@ -223,6 +227,13 @@ async function notifyTargetTab(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
const tab = await chrome.tabs.get(targetTabId);
|
const tab = await chrome.tabs.get(targetTabId);
|
||||||
sendToPanel({ type: 'target_tab', tabId: targetTabId, title: tab.title, url: tab.url });
|
sendToPanel({ type: 'target_tab', tabId: targetTabId, title: tab.title, url: tab.url });
|
||||||
|
// Glow auf den neuen Arbeits-Tab übertragen (falls Agent gerade läuft)
|
||||||
|
notifyGlow(true);
|
||||||
|
// Tab in den Vordergrund bringen wenn focusWorkingTab aktiv
|
||||||
|
const cfg = await loadConfig();
|
||||||
|
if (cfg.focusWorkingTab) {
|
||||||
|
await chrome.tabs.update(targetTabId, { active: true }).catch(() => {});
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
sendToPanel({ type: 'target_tab', tabId: null });
|
sendToPanel({ type: 'target_tab', tabId: null });
|
||||||
}
|
}
|
||||||
@@ -724,7 +735,10 @@ function notifyCursor(tabId: number, x: number, y: number, click?: 'left' | 'rig
|
|||||||
async function notifyGlow(on: boolean): Promise<void> {
|
async function notifyGlow(on: boolean): Promise<void> {
|
||||||
const cfg = await loadConfig();
|
const cfg = await loadConfig();
|
||||||
if (cfg.pageOverlay !== 'glow' && cfg.pageOverlay !== 'both') return;
|
if (cfg.pageOverlay !== 'glow' && cfg.pageOverlay !== 'both') return;
|
||||||
const id = await currentTabId().catch(() => undefined);
|
|
||||||
|
// Glow an den Arbeits-Tab schicken, nicht an den aktiven Tab des Nutzers.
|
||||||
|
// targetTabId ist null wenn noch kein Tool gelaufen ist — dann aktiven Tab nehmen.
|
||||||
|
const id = targetTabId ?? await currentTabId().catch(() => undefined);
|
||||||
if (typeof id !== 'number') return;
|
if (typeof id !== 'number') return;
|
||||||
chrome.tabs.sendMessage(id, { type: 'NEXUS_GLOW', on }).catch(() => {});
|
chrome.tabs.sendMessage(id, { type: 'NEXUS_GLOW', on }).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,6 +159,13 @@ export interface ExtensionConfig {
|
|||||||
* zurückholen. Dieser Riegel greift unabhängig vom Risikomodus.
|
* zurückholen. Dieser Riegel greift unabhängig vom Risikomodus.
|
||||||
*/
|
*/
|
||||||
blockMailSend: boolean;
|
blockMailSend: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arbeits-Tab in den Vordergrund bringen wenn der Agent ihn wechselt.
|
||||||
|
* false (Standard) = Agent arbeitet im Hintergrund, Nutzer kann anderen Tab nutzen.
|
||||||
|
* true = Tab wird bei jedem Wechsel sichtbar — gut zum Live-Zuschauen.
|
||||||
|
*/
|
||||||
|
focusWorkingTab: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SYSTEM_PROMPT = `Du steuerst einen echten Browser wie ein Mensch: mit Mauszeiger und Tastatur.
|
export const DEFAULT_SYSTEM_PROMPT = `Du steuerst einen echten Browser wie ein Mensch: mit Mauszeiger und Tastatur.
|
||||||
@@ -328,6 +335,7 @@ export const DEFAULT_CONFIG: ExtensionConfig = {
|
|||||||
memoryToken: '',
|
memoryToken: '',
|
||||||
memoryEnabled: false,
|
memoryEnabled: false,
|
||||||
blockMailSend: true,
|
blockMailSend: true,
|
||||||
|
focusWorkingTab: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STORAGE_KEY = 'nexus_ext_config';
|
const STORAGE_KEY = 'nexus_ext_config';
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ const paceMsInput = need<HTMLInputElement>('paceMs');
|
|||||||
const showCursorInput = need<HTMLInputElement>('showCursor');
|
const showCursorInput = need<HTMLInputElement>('showCursor');
|
||||||
const pageOverlaySelect = need<HTMLSelectElement>('pageOverlay');
|
const pageOverlaySelect = need<HTMLSelectElement>('pageOverlay');
|
||||||
const blockMailSendInput = need<HTMLInputElement>('blockMailSend');
|
const blockMailSendInput = need<HTMLInputElement>('blockMailSend');
|
||||||
|
const focusWorkingTabInput = need<HTMLInputElement>('focusWorkingTab');
|
||||||
const providerSelect = need<HTMLSelectElement>('provider');
|
const providerSelect = need<HTMLSelectElement>('provider');
|
||||||
const baseUrlInput = need<HTMLInputElement>('baseUrl');
|
const baseUrlInput = need<HTMLInputElement>('baseUrl');
|
||||||
const apiKeyInput = need<HTMLInputElement>('apiKey');
|
const apiKeyInput = need<HTMLInputElement>('apiKey');
|
||||||
@@ -379,6 +380,7 @@ function applyConfigToFields(cfg: ExtensionConfig): void {
|
|||||||
setFieldValue(paceMsInput, String(cfg.paceMs));
|
setFieldValue(paceMsInput, String(cfg.paceMs));
|
||||||
if (document.activeElement !== showCursorInput) showCursorInput.checked = cfg.showCursor;
|
if (document.activeElement !== showCursorInput) showCursorInput.checked = cfg.showCursor;
|
||||||
if (document.activeElement !== blockMailSendInput) blockMailSendInput.checked = cfg.blockMailSend;
|
if (document.activeElement !== blockMailSendInput) blockMailSendInput.checked = cfg.blockMailSend;
|
||||||
|
if (document.activeElement !== focusWorkingTabInput) focusWorkingTabInput.checked = cfg.focusWorkingTab ?? false;
|
||||||
|
|
||||||
setFieldValue(providerSelect, cfg.provider);
|
setFieldValue(providerSelect, cfg.provider);
|
||||||
setFieldValue(baseUrlInput, cfg.baseUrl);
|
setFieldValue(baseUrlInput, cfg.baseUrl);
|
||||||
@@ -685,6 +687,10 @@ function wireSettings(): void {
|
|||||||
patchConfigValue({ showCursor: showCursorInput.checked });
|
patchConfigValue({ showCursor: showCursorInput.checked });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
focusWorkingTabInput.addEventListener('change', () => {
|
||||||
|
patchConfigValue({ focusWorkingTab: focusWorkingTabInput.checked });
|
||||||
|
});
|
||||||
|
|
||||||
blockMailSendInput.addEventListener('change', () => {
|
blockMailSendInput.addEventListener('change', () => {
|
||||||
patchConfigValue({ blockMailSend: blockMailSendInput.checked });
|
patchConfigValue({ blockMailSend: blockMailSendInput.checked });
|
||||||
if (!blockMailSendInput.checked) {
|
if (!blockMailSendInput.checked) {
|
||||||
|
|||||||
@@ -1099,6 +1099,10 @@
|
|||||||
<input type="checkbox" id="showCursor">
|
<input type="checkbox" id="showCursor">
|
||||||
<label for="showCursor">Mauszeiger sichtbar einblenden</label>
|
<label for="showCursor">Mauszeiger sichtbar einblenden</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row check">
|
||||||
|
<input type="checkbox" id="focusWorkingTab">
|
||||||
|
<label for="focusWorkingTab" title="Tab bei jedem Wechsel in den Vordergrund bringen — gut zum Live-Zuschauen. Aus = Agent arbeitet im Hintergrund.">Tab live mitverfolgen (Vordergrund)</label>
|
||||||
|
</div>
|
||||||
<div class="row check">
|
<div class="row check">
|
||||||
<input type="checkbox" id="blockMailSend">
|
<input type="checkbox" id="blockMailSend">
|
||||||
<label for="blockMailSend" title="Klicks auf Senden-Schaltflächen in Mail-Oberflächen werden abgelehnt. Der Agent legt nur Entwürfe an.">Senden in Mails blockieren (nur Entwürfe)</label>
|
<label for="blockMailSend" title="Klicks auf Senden-Schaltflächen in Mail-Oberflächen werden abgelehnt. Der Agent legt nur Entwürfe an.">Senden in Mails blockieren (nur Entwürfe)</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user