Agent Zero AI framework
Defer Office desktop startup
Make the Office canvas mount passive so Xpra starts only when the Desktop surface is opened or an official Office document is created/opened. Track Desktop host visibility to unload hidden frames, stop monitors, dedupe viewport resize work, and set Xpra offscreen mode according to HTTPS support. Add a near-future note for the tunnel memory footprint. Show Office desktop startup progress Display a loading message while the Agent Zero Desktop environment is starting or restarting, so the right-canvas Desktop button gives immediate feedback before Xpra finishes waking up.
Alessandro committed
May 3, 2026 at 02:57 UTC
2d389af7279ae0b51c878eac6869899e7ded1bce
8 files changed
+162
-48
docs/agents/office-tunnel-memory-note.md
new
+20
@@ -0,0 +1,20 @@
1
+# Office Tunnel Memory Footprint Note
2
+
3
+During the ARM Desktop audit on 2026-05-03, `run_tunnel.py` was the clearest near-future memory optimization candidate. The process held roughly 573 MiB PSS while the main UI process held roughly 706 MiB PSS, even though the tunnel should mostly be a lightweight network edge.
4
+
5
+## Observed Shape
6
+
7
+- `run_tunnel.py` imports enough of the framework stack to pull in heavy provider and API dependencies.
8
+- The tunnel stays resident for the life of the container, so every eagerly imported module becomes steady-state memory.
9
+- The Desktop/Xpra service itself was not the largest outlier; the always-on tunnel process was.
10
+
11
+## Future Work
12
+
13
+- Split tunnel startup into a small import surface that only loads routing, auth, and socket plumbing required for health and proxy operation.
14
+- Lazy-import provider/framework modules only when a tunnel request truly needs them.
15
+- Review any `ApiHandler` or helper imports used by the tunnel path and replace broad framework imports with narrower functions.
16
+- Measure with `smem -P run_tunnel.py`, `/proc/<pid>/smaps_rollup`, and before/after cold-start RSS/PSS on ARM64.
17
+
18
+## Success Signal
19
+
20
+The tunnel process should remain useful as an always-on edge while dropping its idle PSS substantially below the main UI process. A good first target is under 250 MiB PSS on ARM64 without changing tunnel behavior.
helpers/virtual_desktop.py
+1
-1
@@ -131,7 +131,7 @@ def session_url(token: str, *, title: str = "Desktop") -> str:
131
"printing": "true",
132
"file_transfer": "true",
133
"sound": "false",
134
- "offscreen": "false",
134
+ "offscreen": "true",
135
"floating_menu": "false",
136
"xpramenu": "false",
137
},
plugins/_office/extensions/python/startup_migration/_20_office_routes.py
+1
-4
@@ -3,7 +3,7 @@ from __future__ import annotations
3
from helpers.extension import Extension
4
from helpers.print_style import PrintStyle
5
from plugins._office import hooks
6
-from plugins._office.helpers import libreoffice_desktop, libreoffice_desktop_routes
6
+from plugins._office.helpers import libreoffice_desktop_routes
7
8
9
class OfficeStartupCleanup(Extension):
@@ -14,6 +14,3 @@ class OfficeStartupCleanup(Extension):
14
PrintStyle.warning("Office runtime preparation reported errors:", result["errors"])
15
elif result.get("installed") or result.get("removed"):
16
PrintStyle.info("Office runtime prepared:", result)
17
- desktop = libreoffice_desktop.get_manager().ensure_system_desktop()
18
- if not desktop.get("available"):
19
- PrintStyle.warning("Office desktop startup was deferred:", desktop.get("error") or desktop)
plugins/_office/extensions/webui/right-canvas-panels/office-panel.html
+1
@@ -2,6 +2,7 @@
2
class="right-canvas-surface-panel office-canvas-surface"
3
data-surface-id="office"
4
x-show="$store.rightCanvas && $store.rightCanvas.isOpen && $store.rightCanvas.activeSurfaceId === 'office'"
5
+ x-effect="$store.office?.setDesktopHostVisible?.($store.rightCanvas && $store.rightCanvas.isOpen && $store.rightCanvas.activeSurfaceId === 'office')"
6
style="display: none;"
7
>
8
<x-component path="/plugins/_office/webui/office-panel.html"></x-component>
plugins/_office/helpers/libreoffice_desktop.py
+5
-3
@@ -271,21 +271,23 @@ class LibreOfficeDesktopManager:
271
session = self.get(session_id)
272
if not session:
273
return {"ok": False, "error": "LibreOffice desktop session not found."}
274
+ is_system_desktop = session.session_id == SYSTEM_SESSION_ID and session.extension == "desktop"
275
result = virtual_desktop.resize_display(
276
display=session.display,
277
width=width,
278
height=height,
279
max_width=MAX_SCREEN_WIDTH,
280
max_height=MAX_SCREEN_HEIGHT,
280
- window_class="libreoffice",
281
- keys=("Escape",),
281
+ window_class="" if is_system_desktop else "libreoffice",
282
+ keys=() if is_system_desktop else ("Escape",),
283
xauthority=self._xauthority(session),
284
home=str(session.profile_dir),
285
)
286
if result.get("ok"):
287
session.width = int(result["width"])
288
session.height = int(result["height"])
288
- self._dismiss_blocking_dialogs(session)
289
+ if not is_system_desktop:
290
+ self._dismiss_blocking_dialogs(session)
291
return result
292
293
def proxy_for_token(self, token: str) -> tuple[str, int] | None:
plugins/_office/webui/office-store.js
+117
-27
@@ -12,6 +12,7 @@ const SAVE_MESSAGE_MS = 1800;
12
const INPUT_PUSH_DELAY_MS = 650;
13
const DESKTOP_HEARTBEAT_MS = 3500;
14
const DESKTOP_RESIZE_DELAY_MS = 80;
15
+const DESKTOP_START_MESSAGE = "Starting Agent Zero Desktop environment";
16
const XPRA_DESKTOP_PRIME_INTERVAL_MS = 220;
17
const XPRA_DESKTOP_PRIME_ATTEMPTS = 120;
18
const SYSTEM_DESKTOP_FILE_ID = "system-desktop";
@@ -219,8 +220,11 @@ const model = {
220
_desktopResizeTarget: null,
221
_desktopResizeTimer: null,
222
_desktopResizeKey: "",
223
+ _desktopResizePendingKey: "",
224
_desktopResizeSuspended: false,
225
_desktopResizePending: false,
226
+ _desktopViewportSyncTimers: [],
227
+ _desktopHostVisible: false,
228
_desktopPrimeTimer: null,
229
_desktopPrimeAttempts: 0,
230
_desktopKeyboardActive: false,
@@ -237,10 +241,12 @@ const model = {
241
async onMount(element = null, options = {}) {
242
if (element) this._root = element;
243
this._mode = options?.mode === "modal" ? "modal" : "canvas";
240
- if (this._mode === "modal") this.setupFloatingModal(element);
241
- await this.refresh();
242
- await this.ensureDesktopSession({ select: !this.session });
243
- this.ensureActiveTab();
244
+ if (this._mode === "modal") {
245
+ this._desktopHostVisible = true;
246
+ this.setupFloatingModal(element);
247
+ await this.onOpen({ source: "modal" });
248
+ return;
249
+ }
250
this.queueRender();
251
},
252
@@ -259,7 +265,9 @@ const model = {
265
},
266
267
beforeHostHidden(options = {}) {
268
+ this._desktopHostVisible = false;
269
this.flushInput();
270
+ this.clearDesktopViewportSyncTimers();
271
this.unloadDesktopFrames();
272
},
273
@@ -267,6 +275,7 @@ const model = {
275
this.flushInput();
276
this.stopDesktopMonitor();
277
this.stopDesktopResizeObserver();
278
+ this.clearDesktopViewportSyncTimers();
279
this.stopXpraDesktopPrime();
280
this.stopDesktopKeyboardBridge();
281
this.stopDesktopClipboardBridge();
@@ -292,10 +301,23 @@ const model = {
301
this.updateDesktopMonitor();
302
return existing;
303
}
295
- if (this._desktopStarting) return await this._desktopStarting;
304
+ const showProgress = options.progress !== false;
305
+ const progressMessage = String(options.message || DESKTOP_START_MESSAGE);
306
+ if (this._desktopStarting) {
307
+ if (showProgress) {
308
+ this.loading = true;
309
+ this.message = progressMessage;
310
+ }
311
+ return await this._desktopStarting;
312
+ }
313
314
this._desktopStarting = (async () => {
315
try {
316
+ if (showProgress) {
317
+ this.loading = true;
318
+ this.message = progressMessage;
319
+ this.error = "";
320
+ }
321
const response = await callOffice("desktop");
322
if (response?.ok === false) throw new Error(response.error || "Desktop session could not be opened.");
323
const session = normalizeSession(response);
@@ -327,6 +349,10 @@ const model = {
349
this.error = error instanceof Error ? error.message : String(error);
350
return null;
351
} finally {
352
+ if (showProgress) {
353
+ this.loading = false;
354
+ if (this.message === progressMessage) this.message = "";
355
+ }
356
this._desktopStarting = null;
357
}
358
})();
@@ -493,7 +519,7 @@ const model = {
519
this.ensureActiveTab();
520
}
521
this.updateDesktopMonitor();
496
- await this.ensureDesktopSession({ select: !this.session });
522
+ this.ensureActiveTab();
523
await this.refresh();
524
},
525
@@ -836,7 +862,36 @@ const model = {
862
},
863
864
officialOfficeUrl(tab = this.session) {
839
- return tab?.desktop?.url || "";
865
+ const url = tab?.desktop?.url || "";
866
+ if (!url) return "";
867
+ try {
868
+ const parsed = new URL(url, window.location.href);
869
+ const secureContext = globalThis.isSecureContext === true;
870
+ parsed.searchParams.set("offscreen", secureContext ? "true" : "false");
871
+ parsed.searchParams.set("clipboard_poll", secureContext ? "true" : "false");
872
+ if (parsed.origin === window.location.origin) return `${parsed.pathname}${parsed.search}${parsed.hash}`;
873
+ return parsed.href;
874
+ } catch {
875
+ return url;
876
+ }
877
+ },
878
+
879
+ isDesktopHostVisible() {
880
+ if (this._mode === "modal") return true;
881
+ const canvas = globalThis.Alpine?.store?.("rightCanvas") || rightCanvasStore;
882
+ return Boolean(canvas?.isOpen && canvas.activeSurfaceId === "office");
883
+ },
884
+
885
+ setDesktopHostVisible(visible) {
886
+ const next = Boolean(visible);
887
+ if (!next && this._mode === "modal") return;
888
+ if (this._desktopHostVisible === next) return;
889
+ this._desktopHostVisible = next;
890
+ if (next) {
891
+ this.afterDesktopHostShown({ source: "canvas-visibility" });
892
+ } else {
893
+ this.beforeHostHidden({ reason: "hidden" });
894
+ }
895
},
896
897
desktopFrames() {
@@ -879,6 +934,7 @@ const model = {
934
},
935
936
restoreDesktopFrames() {
937
+ if (!this.isDesktopHostVisible()) return;
938
const url = this.officialOfficeUrl();
939
if (!url) return;
940
for (const frame of this.desktopFrames()) {
@@ -892,22 +948,21 @@ const model = {
948
949
afterDesktopHostShown() {
950
if (!this.hasOfficialOffice()) return;
951
+ this._desktopHostVisible = true;
952
this._desktopResizeKey = "";
953
+ this._desktopResizePendingKey = "";
954
this._desktopResizeSuspended = false;
955
this._desktopResizePending = false;
956
this.restoreDesktopFrames();
957
this.requestDesktopViewportSync({ force: true, frame: this.desktopFrame() });
900
- for (const delay of [720, 1280]) {
901
- globalThis.setTimeout(() => {
902
- this.requestDesktopViewportSync({ force: true, frame: this.desktopFrame() });
903
- }, delay);
904
- }
958
},
959
960
beforeDesktopHostHandoff() {
961
this.stopDesktopResizeObserver();
962
+ this.clearDesktopViewportSyncTimers();
963
this.stopXpraDesktopPrime();
964
this._desktopResizeKey = "";
965
+ this._desktopResizePendingKey = "";
966
this._desktopResizeSuspended = true;
967
this._desktopResizePending = true;
968
},
@@ -920,6 +975,7 @@ const model = {
975
976
onDesktopFrameLoaded(event = null) {
977
if (event?.target?.getAttribute?.("src") === "about:blank") return;
978
+ if (!this.isDesktopHostVisible()) return;
979
this.error = "";
980
this.queueDesktopFrameFocus(event?.target || null);
981
this.requestDesktopViewportSync({ force: true, frame: event?.target || null });
@@ -955,7 +1011,7 @@ const model = {
1011
},
1012
1013
updateDesktopMonitor() {
958
- if (!this.hasOfficialOffice()) {
1014
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) {
1015
this.stopDesktopMonitor();
1016
this.stopDesktopResizeObserver();
1017
this._desktopKeyboardActive = false;
@@ -975,7 +1031,7 @@ const model = {
1031
},
1032
1033
startDesktopResizeObserver() {
978
- if (!this.hasOfficialOffice()) {
1034
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) {
1035
this.stopDesktopResizeObserver();
1036
return;
1037
}
@@ -1017,6 +1073,7 @@ const model = {
1073
this._desktopResizeCleanup = null;
1074
this._desktopResizeTarget = null;
1075
this._desktopResizeKey = "";
1076
+ this._desktopResizePendingKey = "";
1077
this._desktopResizeSuspended = false;
1078
this._desktopResizePending = false;
1079
},
@@ -1027,6 +1084,7 @@ const model = {
1084
globalThis.clearTimeout(this._desktopResizeTimer);
1085
this._desktopResizeTimer = null;
1086
}
1087
+ this._desktopResizePendingKey = "";
1088
},
1089
1090
resumeDesktopResize() {
@@ -1046,7 +1104,15 @@ const model = {
1104
);
1105
},
1106
1107
+ clearDesktopViewportSyncTimers() {
1108
+ for (const timer of this._desktopViewportSyncTimers.splice(0)) {
1109
+ globalThis.clearTimeout(timer);
1110
+ }
1111
+ },
1112
+
1113
requestDesktopViewportSync(options = {}) {
1114
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) return;
1115
+ if (options.force) this.clearDesktopViewportSyncTimers();
1116
const run = (force = false) => {
1117
this.syncDesktopViewport({ ...options, force });
1118
};
@@ -1055,13 +1121,16 @@ const model = {
1121
} else {
1122
globalThis.setTimeout(() => run(Boolean(options.force)), 0);
1123
}
1058
- for (const delay of [140, 420]) {
1059
- globalThis.setTimeout(() => run(false), delay);
1060
- }
1124
+ if (options.followup === false) return;
1125
+ const timer = globalThis.setTimeout(() => {
1126
+ this._desktopViewportSyncTimers = this._desktopViewportSyncTimers.filter((item) => item !== timer);
1127
+ run(false);
1128
+ }, options.force ? 260 : 180);
1129
+ this._desktopViewportSyncTimers.push(timer);
1130
},
1131
1132
syncDesktopViewport(options = {}) {
1064
- if (!this.hasOfficialOffice()) return false;
1133
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) return false;
1134
const frame = this.desktopFrame(options.frame || null);
1135
if (!frame) return false;
1136
this.startDesktopResizeObserver();
@@ -1554,7 +1623,7 @@ const model = {
1623
},
1624
1625
queueDesktopResize(options = {}) {
1557
- if (!this.hasOfficialOffice()) return;
1626
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) return;
1627
const token = this.session?.desktop?.token || "";
1628
const frame = this.desktopFrame(options.frame || null);
1629
const target = frame?.parentElement || frame;
@@ -1565,18 +1634,33 @@ const model = {
1634
const width = Math.round(rect.width);
1635
const height = Math.round(rect.height);
1636
if (width < 320 || height < 220) return;
1568
- this.applyXpraDesktopFrameMode(frame, { requestServerResize: false, requestRefresh: false });
1637
+ const key = `${token}:${width}x${height}`;
1638
+ const refreshFrameOnly = () => {
1639
+ this.applyXpraDesktopFrameMode(frame, { requestServerResize: false, requestRefresh: false });
1640
+ };
1641
+ if (!serverResize) {
1642
+ refreshFrameOnly();
1643
+ return;
1644
+ }
1645
+ if (key === this._desktopResizeKey || key === this._desktopResizePendingKey) {
1646
+ refreshFrameOnly();
1647
+ return;
1648
+ }
1649
+ refreshFrameOnly();
1650
if (!force && this.shouldDeferDesktopResize()) {
1651
this._desktopResizePending = true;
1652
return;
1653
}
1573
- const key = `${token}:${width}x${height}`;
1574
- if (!serverResize) return;
1575
- if (!force && key === this._desktopResizeKey) return;
1654
if (this._desktopResizeTimer) globalThis.clearTimeout(this._desktopResizeTimer);
1655
+ this._desktopResizePendingKey = key;
1656
this._desktopResizeTimer = globalThis.setTimeout(async () => {
1657
this._desktopResizeTimer = null;
1658
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) {
1659
+ if (this._desktopResizePendingKey === key) this._desktopResizePendingKey = "";
1660
+ return;
1661
+ }
1662
if (!force && this.shouldDeferDesktopResize()) {
1663
+ if (this._desktopResizePendingKey === key) this._desktopResizePendingKey = "";
1664
this._desktopResizePending = true;
1665
return;
1666
}
@@ -1603,6 +1687,8 @@ const model = {
1687
}
1688
} catch (error) {
1689
console.warn("Desktop resize skipped", error);
1690
+ } finally {
1691
+ if (this._desktopResizePendingKey === key) this._desktopResizePendingKey = "";
1692
}
1693
}, DESKTOP_RESIZE_DELAY_MS);
1694
},
@@ -1711,7 +1797,7 @@ const model = {
1797
1798
startDesktopMonitor() {
1799
this.stopDesktopMonitor();
1714
- if (!this.hasOfficialOffice()) return;
1800
+ if (!this.hasOfficialOffice() || !this.isDesktopHostVisible()) return;
1801
const tabId = this.session?.tab_id || "";
1802
const sessionId = this.session?.desktop_session_id || this.session?.session_id || "";
1803
if (!tabId || !sessionId) return;
@@ -1720,7 +1806,7 @@ const model = {
1806
this._desktopHeartbeatMisses = 0;
1807
1808
const tick = async () => {
1723
- if (!this.session || this.session.tab_id !== tabId || !this.hasOfficialOffice()) return;
1809
+ if (!this.session || this.session.tab_id !== tabId || !this.hasOfficialOffice() || !this.isDesktopHostVisible()) return;
1810
try {
1811
const response = await callOffice("desktop_sync", {
1812
desktop_session_id: sessionId,
@@ -1773,8 +1859,12 @@ const model = {
1859
this.stopDesktopMonitor();
1860
this.stopDesktopResizeObserver();
1861
this.stopXpraDesktopPrime();
1776
- this.setMessage("Desktop is restarting");
1777
- await this.ensureDesktopSession({ force: true, select: this.activeTabId === tabId || Boolean(hiddenDesktopDocument) });
1862
+ this.message = "Desktop is restarting";
1863
+ await this.ensureDesktopSession({
1864
+ force: true,
1865
+ select: this.activeTabId === tabId || Boolean(hiddenDesktopDocument),
1866
+ message: "Desktop is restarting",
1867
+ });
1868
target._desktopClosed = false;
1869
await this.refresh();
1870
},
tests/test_office_canvas_setup.py
+14
-1
@@ -13,6 +13,9 @@ def test_document_canvas_uses_markdown_editor_and_official_libreoffice_desktop_f
13
store = (PROJECT_ROOT / "plugins" / "_office" / "webui" / "office-store.js").read_text(
14
encoding="utf-8",
15
)
16
+ canvas_panel = (
17
+ PROJECT_ROOT / "plugins" / "_office" / "extensions" / "webui" / "right-canvas-panels" / "office-panel.html"
18
+ ).read_text(encoding="utf-8")
19
20
assert "office-source-editor" in panel
21
assert "data-office-source" in panel
@@ -47,10 +50,18 @@ def test_document_canvas_uses_markdown_editor_and_official_libreoffice_desktop_f
50
assert "zoom: 1" not in store
51
assert 'callOffice("desktop")' in store
52
assert "ensureDesktopSession" in store
53
+ assert 'await this.onOpen({ source: "modal" });' in store
54
+ assert "setDesktopHostVisible" in store
55
+ assert "isDesktopHostVisible" in store
56
+ assert "clearDesktopViewportSyncTimers" in store
57
+ assert "setDesktopHostVisible" in canvas_panel
58
+ assert "Starting Agent Zero Desktop environment" in store
59
assert "handleOfficialOfficeClosed" in store
60
assert "ResizeObserver" in store
61
assert "_desktopResizeSuspended" in store
62
assert "_desktopResizePending" in store
63
+ assert "_desktopResizePendingKey" in store
64
+ assert "_desktopViewportSyncTimers" in store
65
assert "shouldDeferDesktopResize" in store
66
assert "right-canvas-resize-start" in store
67
assert "right-canvas-resize-end" in store
@@ -91,6 +102,8 @@ def test_document_canvas_uses_markdown_editor_and_official_libreoffice_desktop_f
102
assert "_desktopHeartbeatTimer" in store
103
assert "office-modal-focus-button" in store
104
assert "officialOfficeUrl" in store
105
+ assert 'parsed.searchParams.set("offscreen", secureContext ? "true" : "false")' in store
106
+ assert 'parsed.searchParams.set("clipboard_poll", secureContext ? "true" : "false")' in store
107
assert "hasOfficialOffice" in store
108
assert "isOfficeSocketData" in store
109
assert "office_command" not in store
@@ -233,7 +246,7 @@ def test_official_libreoffice_desktop_route_and_packages_are_declared():
246
assert '"quality": "85"' in primitive
247
assert '"speed": "80"' in primitive
248
assert '"printing": "true"' in primitive
236
- assert "offscreen" in primitive
249
+ assert '"offscreen": "true"' in primitive
250
assert "xpra" in desktop
251
assert "xpra-html5" in desktop
252
assert "Xvfb" in desktop
tests/test_office_document_store.py
+3
-12
@@ -684,7 +684,7 @@ def test_cleanup_hook_removes_stale_runtime_state_idempotently(tmp_path, monkeyp
684
assert marker.exists()
685
686
687
-def test_office_startup_bootstraps_persistent_desktop_runtime(monkeypatch):
687
+def test_office_startup_defers_persistent_desktop_runtime(monkeypatch):
688
calls = []
689
routes_module = types.ModuleType("plugins._office.helpers.libreoffice_desktop_routes")
690
routes_module.install_route_hooks = lambda: calls.append("routes")
@@ -697,25 +697,16 @@ def test_office_startup_bootstraps_persistent_desktop_runtime(monkeypatch):
697
698
from plugins._office.extensions.python.startup_migration import _20_office_routes as office_startup
699
700
- class Manager:
701
- def ensure_system_desktop(self):
702
- calls.append("desktop")
703
- return {"available": True, "session_id": "agent-zero-desktop"}
704
-
700
monkeypatch.setattr(
701
office_startup.hooks,
702
"cleanup_stale_runtime_state",
703
lambda: {"ok": True, "errors": [], "installed": [], "removed": []},
704
)
710
- monkeypatch.setattr(
711
- office_startup.libreoffice_desktop,
712
- "get_manager",
713
- lambda: Manager(),
714
- )
705
706
office_startup.OfficeStartupCleanup(agent=None).execute()
707
718
- assert calls == ["routes", "desktop"]
708
+ assert calls == ["routes"]
709
+ assert not hasattr(office_startup, "libreoffice_desktop")
710
711
712
def test_cleanup_hook_reruns_when_stale_packages_exist_after_old_marker(tmp_path, monkeypatch):