athena-browser-mcp 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +35 -5
  2. package/dist/src/browser/page-network-tracker.d.ts +88 -0
  3. package/dist/src/browser/page-network-tracker.d.ts.map +1 -0
  4. package/dist/src/browser/page-network-tracker.js +271 -0
  5. package/dist/src/browser/page-network-tracker.js.map +1 -0
  6. package/dist/src/browser/page-stabilization.d.ts +35 -0
  7. package/dist/src/browser/page-stabilization.d.ts.map +1 -0
  8. package/dist/src/browser/page-stabilization.js +42 -0
  9. package/dist/src/browser/page-stabilization.js.map +1 -0
  10. package/dist/src/browser/session-manager.d.ts +4 -0
  11. package/dist/src/browser/session-manager.d.ts.map +1 -1
  12. package/dist/src/browser/session-manager.js +34 -0
  13. package/dist/src/browser/session-manager.js.map +1 -1
  14. package/dist/src/observation/eid-linker.d.ts +84 -0
  15. package/dist/src/observation/eid-linker.d.ts.map +1 -0
  16. package/dist/src/observation/eid-linker.js +268 -0
  17. package/dist/src/observation/eid-linker.js.map +1 -0
  18. package/dist/src/observation/index.d.ts +12 -0
  19. package/dist/src/observation/index.d.ts.map +1 -0
  20. package/dist/src/observation/index.js +15 -0
  21. package/dist/src/observation/index.js.map +1 -0
  22. package/dist/src/observation/observation-accumulator.d.ts +58 -0
  23. package/dist/src/observation/observation-accumulator.d.ts.map +1 -0
  24. package/dist/src/observation/observation-accumulator.js +213 -0
  25. package/dist/src/observation/observation-accumulator.js.map +1 -0
  26. package/dist/src/observation/observation.types.d.ts +108 -0
  27. package/dist/src/observation/observation.types.d.ts.map +1 -0
  28. package/dist/src/observation/observation.types.js +44 -0
  29. package/dist/src/observation/observation.types.js.map +1 -0
  30. package/dist/src/observation/observer-script.d.ts +19 -0
  31. package/dist/src/observation/observer-script.d.ts.map +1 -0
  32. package/dist/src/observation/observer-script.js +519 -0
  33. package/dist/src/observation/observer-script.js.map +1 -0
  34. package/dist/src/snapshot/snapshot.types.d.ts +6 -0
  35. package/dist/src/snapshot/snapshot.types.d.ts.map +1 -1
  36. package/dist/src/snapshot/snapshot.types.js.map +1 -1
  37. package/dist/src/state/diff-engine.d.ts.map +1 -1
  38. package/dist/src/state/diff-engine.js +129 -1
  39. package/dist/src/state/diff-engine.js.map +1 -1
  40. package/dist/src/state/state-manager.d.ts.map +1 -1
  41. package/dist/src/state/state-manager.js +9 -0
  42. package/dist/src/state/state-manager.js.map +1 -1
  43. package/dist/src/state/state-renderer.d.ts +13 -0
  44. package/dist/src/state/state-renderer.d.ts.map +1 -1
  45. package/dist/src/state/state-renderer.js +172 -2
  46. package/dist/src/state/state-renderer.js.map +1 -1
  47. package/dist/src/state/types.d.ts +37 -0
  48. package/dist/src/state/types.d.ts.map +1 -1
  49. package/dist/src/tools/browser-tools.d.ts.map +1 -1
  50. package/dist/src/tools/browser-tools.js +15 -1
  51. package/dist/src/tools/browser-tools.js.map +1 -1
  52. package/dist/src/tools/execute-action.d.ts +22 -6
  53. package/dist/src/tools/execute-action.d.ts.map +1 -1
  54. package/dist/src/tools/execute-action.js +80 -21
  55. package/dist/src/tools/execute-action.js.map +1 -1
  56. package/dist/src/tools/tool-schemas.d.ts +68 -68
  57. package/package.json +2 -2
package/README.md CHANGED
@@ -6,12 +6,42 @@
6
6
 
7
7
  MCP server for AI browser automation - 18 tools with semantic element targeting.
8
8
 
9
- ## Design Philosophy
9
+ ## Why Athena?
10
10
 
11
- 1. **Semantic element IDs** - Stable `eid` references survive DOM mutations
12
- 2. **XML state responses** - Structured page state with layers, actionables, and diffs
13
- 3. **Multi-frame support** - Extract content from iframes (cookie consent, widgets)
14
- 4. **Automatic retry** - Stale element recovery with fresh snapshot
11
+ LLM agents face two hard constraints: limited context windows and expensive tokens. Yet browser automation requires understanding complex, ever-changing page state. Traditional tools dump raw accessibility trees or screenshots, wasting precious context and creating needle-in-haystack problems where agents struggle to locate relevant elements.
12
+
13
+ Athena solves this with **semantic page snapshots** - compact, structured representations designed for LLM consumption:
14
+
15
+ - **Token-efficient** - Hierarchical layers and regions eliminate noise, fitting more page understanding into less context
16
+ - **High recall** - Structured XML with semantic element IDs lets agents find elements without scanning entire DOM trees
17
+ - **Intuitive querying** - `find_elements` with semantic filters (kind, label, region) so agents ask for what they need
18
+ - **Stable references** - Semantic `eid`s survive DOM mutations, eliminating stale element errors
19
+
20
+ The result: fewer tokens, faster task completion, and higher-quality outputs with fewer errors.
21
+
22
+ ## Benchmark
23
+
24
+ Comparison between Athena Browser MCP and Playwright MCP on real-world browser automation tasks. Tests run in Claude Code with Claude Opus 4.5.
25
+
26
+ | # | Task | Agent | Result | Tokens Used | Time Taken |
27
+ | --- | ------------------------------------------------------------------------------------- | -------------- | ---------- | ----------- | ---------- |
28
+ | 1 | Login → Create wishlist "Summer Escapes" → Add beach property (Airbnb) | **Athena** | ✅ Success | 92,870 | 2m 08s |
29
+ | | | **Playwright** | ✅ Success | 137,063 | 5m 23s |
30
+ | 2 | Bangkok Experiences → Food tour → Extract itinerary & pricing (Airbnb) | **Athena** | ✅ Success | 87,194 | 3m 27s |
31
+ | | | **Playwright** | ✅ Success | 94,942 | 3m 38s |
32
+ | 3 | Miami → Beachfront stays under $300 → Top 3 names + prices (Airbnb) | **Athena** | ✅ Success | 124,597 | 5m 38s |
33
+ | | | **Playwright** | ✅ Success | 122,077 | 4m 51s |
34
+ | 4 | Paris → "Play" section → Top 5 titles + descriptions (Airbnb) | **Athena** | ❌ Failed | 146,575 | 4m 15s |
35
+ | | | **Playwright** | ❌ Failed | 189,495 | 7m 37s |
36
+ | 5 | Navigate Apple → find iPhone → configure iPhone 17 → add 256GB Black → confirm in bag | **Athena** | ✅ Success | 65,629 | 3m 30s |
37
+ | | | **Playwright** | ✅ Success | 102,754 | 6m 59s |
38
+
39
+ **Total Results:**
40
+
41
+ - **Tokens**: Athena used **125,341 fewer tokens** (~19.4% more efficient)
42
+ - **Time**: Athena completed tasks **9m 30s faster** (~33.4% faster)
43
+
44
+ _Benchmark on a larger dataset coming soon._
15
45
 
16
46
  ## Architecture
17
47
 
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Page Network Tracker
3
+ *
4
+ * Tracks in-flight network requests for a page and provides a reliable
5
+ * "network quiet" wait mechanism. Unlike Playwright's waitForLoadState('networkidle'),
6
+ * this tracks requests triggered after page load (e.g., by user actions).
7
+ *
8
+ * Uses a generation counter to safely handle navigation - late events from
9
+ * previous documents are ignored.
10
+ */
11
+ import type { Page } from 'playwright';
12
+ /**
13
+ * Tracks network requests for a single page.
14
+ *
15
+ * Attach to a page via `attach()`, then use `waitForQuiet()` to wait for
16
+ * network activity to settle. Call `markNavigation()` when navigating to
17
+ * safely reset state without race conditions.
18
+ */
19
+ export declare class PageNetworkTracker {
20
+ private page;
21
+ private inflightCount;
22
+ private generation;
23
+ private currentGeneration;
24
+ private quietTimer;
25
+ private quietWindowMs;
26
+ private quietResolvers;
27
+ private onRequest;
28
+ private onRequestFinished;
29
+ private onRequestFailed;
30
+ /**
31
+ * Attach network event listeners to a page.
32
+ *
33
+ * Must be called before `waitForQuiet()` can be used.
34
+ * Safe to call multiple times - will detach previous listeners first.
35
+ */
36
+ attach(page: Page): void;
37
+ /**
38
+ * Detach all event listeners and cleanup timers.
39
+ *
40
+ * Call this when the page is closed or no longer needs tracking.
41
+ */
42
+ detach(): void;
43
+ /**
44
+ * Mark that a navigation occurred.
45
+ *
46
+ * This safely resets state by bumping the generation counter, so any
47
+ * late events from the previous document are ignored. Use this instead
48
+ * of directly resetting state to avoid race conditions.
49
+ */
50
+ markNavigation(): void;
51
+ /**
52
+ * Wait for network to become quiet (no inflight requests for quietWindowMs).
53
+ *
54
+ * @param timeoutMs - Maximum time to wait before returning false
55
+ * @param quietWindowMs - Time with 0 inflight requests to consider "idle"
56
+ * @returns true if network became quiet, false if timed out (never throws)
57
+ */
58
+ waitForQuiet(timeoutMs: number, quietWindowMs?: number): Promise<boolean>;
59
+ /**
60
+ * Get current inflight request count (for debugging/testing).
61
+ */
62
+ getInflightCount(): number;
63
+ /**
64
+ * Check if tracker is attached to a page.
65
+ */
66
+ isAttached(): boolean;
67
+ private cancelQuietTimer;
68
+ private checkQuiet;
69
+ private startQuietTimer;
70
+ }
71
+ /**
72
+ * Get or create a network tracker for a page.
73
+ *
74
+ * Note: This does NOT automatically attach the tracker.
75
+ * Call `tracker.attach(page)` after getting the tracker.
76
+ */
77
+ export declare function getOrCreateTracker(page: Page): PageNetworkTracker;
78
+ /**
79
+ * Remove and detach the tracker for a page.
80
+ *
81
+ * Call this when a page is closed to ensure proper cleanup.
82
+ */
83
+ export declare function removeTracker(page: Page): void;
84
+ /**
85
+ * Check if a page has a tracker attached.
86
+ */
87
+ export declare function hasTracker(page: Page): boolean;
88
+ //# sourceMappingURL=page-network-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-network-tracker.d.ts","sourceRoot":"","sources":["../../../src/browser/page-network-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,YAAY,CAAC;AAKhD;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAG9B,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,cAAc,CAAyE;IAG/F,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,eAAe,CAAyC;IAEhE;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IA6CxB;;;;OAIG;IACH,MAAM,IAAI,IAAI;IA6Bd;;;;;;OAMG;IACH,cAAc,IAAI,IAAI;IAkDtB;;;;;;OAMG;IACG,YAAY,CAChB,SAAS,EAAE,MAAM,EACjB,aAAa,GAAE,MAAgC,GAC9C,OAAO,CAAC,OAAO,CAAC;IAuBnB;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,UAAU,IAAI,OAAO;IAMrB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,eAAe;CAexB;AAYD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB,CAOjE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAM9C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAE9C"}
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Page Network Tracker
3
+ *
4
+ * Tracks in-flight network requests for a page and provides a reliable
5
+ * "network quiet" wait mechanism. Unlike Playwright's waitForLoadState('networkidle'),
6
+ * this tracks requests triggered after page load (e.g., by user actions).
7
+ *
8
+ * Uses a generation counter to safely handle navigation - late events from
9
+ * previous documents are ignored.
10
+ */
11
+ /** Default quiet window - time with 0 inflight requests to consider "idle" */
12
+ const DEFAULT_QUIET_WINDOW_MS = 500;
13
+ /**
14
+ * Tracks network requests for a single page.
15
+ *
16
+ * Attach to a page via `attach()`, then use `waitForQuiet()` to wait for
17
+ * network activity to settle. Call `markNavigation()` when navigating to
18
+ * safely reset state without race conditions.
19
+ */
20
+ export class PageNetworkTracker {
21
+ page = null;
22
+ inflightCount = 0;
23
+ generation = 0;
24
+ currentGeneration = 0;
25
+ // Quiet window state
26
+ quietTimer = null;
27
+ quietWindowMs = DEFAULT_QUIET_WINDOW_MS;
28
+ quietResolvers = [];
29
+ // Event handlers (stored for cleanup via page.off())
30
+ onRequest = null;
31
+ onRequestFinished = null;
32
+ onRequestFailed = null;
33
+ /**
34
+ * Attach network event listeners to a page.
35
+ *
36
+ * Must be called before `waitForQuiet()` can be used.
37
+ * Safe to call multiple times - will detach previous listeners first.
38
+ */
39
+ attach(page) {
40
+ // Detach from previous page if any
41
+ if (this.page) {
42
+ this.detach();
43
+ }
44
+ this.page = page;
45
+ this.generation++;
46
+ this.currentGeneration = this.generation;
47
+ this.inflightCount = 0;
48
+ const gen = this.currentGeneration;
49
+ this.onRequest = (req) => {
50
+ // Ignore stale events from previous document
51
+ if (this.currentGeneration !== gen)
52
+ return;
53
+ // Ignore websockets (persistent connections)
54
+ if (req.resourceType() === 'websocket')
55
+ return;
56
+ this.inflightCount++;
57
+ this.cancelQuietTimer();
58
+ };
59
+ this.onRequestFinished = (req) => {
60
+ if (this.currentGeneration !== gen)
61
+ return;
62
+ if (req.resourceType() === 'websocket')
63
+ return;
64
+ // Never go below 0 (handles edge cases)
65
+ this.inflightCount = Math.max(0, this.inflightCount - 1);
66
+ this.checkQuiet();
67
+ };
68
+ this.onRequestFailed = (req) => {
69
+ if (this.currentGeneration !== gen)
70
+ return;
71
+ if (req.resourceType() === 'websocket')
72
+ return;
73
+ this.inflightCount = Math.max(0, this.inflightCount - 1);
74
+ this.checkQuiet();
75
+ };
76
+ page.on('request', this.onRequest);
77
+ page.on('requestfinished', this.onRequestFinished);
78
+ page.on('requestfailed', this.onRequestFailed);
79
+ }
80
+ /**
81
+ * Detach all event listeners and cleanup timers.
82
+ *
83
+ * Call this when the page is closed or no longer needs tracking.
84
+ */
85
+ detach() {
86
+ if (this.page) {
87
+ if (this.onRequest) {
88
+ this.page.off('request', this.onRequest);
89
+ }
90
+ if (this.onRequestFinished) {
91
+ this.page.off('requestfinished', this.onRequestFinished);
92
+ }
93
+ if (this.onRequestFailed) {
94
+ this.page.off('requestfailed', this.onRequestFailed);
95
+ }
96
+ }
97
+ this.onRequest = null;
98
+ this.onRequestFinished = null;
99
+ this.onRequestFailed = null;
100
+ this.page = null;
101
+ // Cancel any pending quiet timers
102
+ this.cancelQuietTimer();
103
+ // Reject all pending waiters with false (not idle)
104
+ for (const { resolve, timeoutId } of this.quietResolvers) {
105
+ clearTimeout(timeoutId);
106
+ resolve(false);
107
+ }
108
+ this.quietResolvers = [];
109
+ }
110
+ /**
111
+ * Mark that a navigation occurred.
112
+ *
113
+ * This safely resets state by bumping the generation counter, so any
114
+ * late events from the previous document are ignored. Use this instead
115
+ * of directly resetting state to avoid race conditions.
116
+ */
117
+ markNavigation() {
118
+ this.generation++;
119
+ this.currentGeneration = this.generation;
120
+ this.inflightCount = 0;
121
+ this.cancelQuietTimer();
122
+ // Re-attach handlers with new generation if we have a page
123
+ if (this.page) {
124
+ const page = this.page;
125
+ // Detach old handlers
126
+ if (this.onRequest) {
127
+ page.off('request', this.onRequest);
128
+ }
129
+ if (this.onRequestFinished) {
130
+ page.off('requestfinished', this.onRequestFinished);
131
+ }
132
+ if (this.onRequestFailed) {
133
+ page.off('requestfailed', this.onRequestFailed);
134
+ }
135
+ // Create new handlers with updated generation
136
+ const gen = this.currentGeneration;
137
+ this.onRequest = (req) => {
138
+ if (this.currentGeneration !== gen)
139
+ return;
140
+ if (req.resourceType() === 'websocket')
141
+ return;
142
+ this.inflightCount++;
143
+ this.cancelQuietTimer();
144
+ };
145
+ this.onRequestFinished = (req) => {
146
+ if (this.currentGeneration !== gen)
147
+ return;
148
+ if (req.resourceType() === 'websocket')
149
+ return;
150
+ this.inflightCount = Math.max(0, this.inflightCount - 1);
151
+ this.checkQuiet();
152
+ };
153
+ this.onRequestFailed = (req) => {
154
+ if (this.currentGeneration !== gen)
155
+ return;
156
+ if (req.resourceType() === 'websocket')
157
+ return;
158
+ this.inflightCount = Math.max(0, this.inflightCount - 1);
159
+ this.checkQuiet();
160
+ };
161
+ page.on('request', this.onRequest);
162
+ page.on('requestfinished', this.onRequestFinished);
163
+ page.on('requestfailed', this.onRequestFailed);
164
+ }
165
+ }
166
+ /**
167
+ * Wait for network to become quiet (no inflight requests for quietWindowMs).
168
+ *
169
+ * @param timeoutMs - Maximum time to wait before returning false
170
+ * @param quietWindowMs - Time with 0 inflight requests to consider "idle"
171
+ * @returns true if network became quiet, false if timed out (never throws)
172
+ */
173
+ async waitForQuiet(timeoutMs, quietWindowMs = DEFAULT_QUIET_WINDOW_MS) {
174
+ // Store the quiet window for checkQuiet() to use
175
+ this.quietWindowMs = quietWindowMs;
176
+ return new Promise((resolve) => {
177
+ const hardTimeout = setTimeout(() => {
178
+ // Remove this resolver from the list
179
+ const index = this.quietResolvers.findIndex((r) => r.timeoutId === hardTimeout);
180
+ if (index !== -1) {
181
+ this.quietResolvers.splice(index, 1);
182
+ }
183
+ resolve(false);
184
+ }, timeoutMs);
185
+ this.quietResolvers.push({ resolve, timeoutId: hardTimeout });
186
+ // If already idle, start quiet timer immediately
187
+ if (this.inflightCount === 0) {
188
+ this.startQuietTimer();
189
+ }
190
+ });
191
+ }
192
+ /**
193
+ * Get current inflight request count (for debugging/testing).
194
+ */
195
+ getInflightCount() {
196
+ return this.inflightCount;
197
+ }
198
+ /**
199
+ * Check if tracker is attached to a page.
200
+ */
201
+ isAttached() {
202
+ return this.page !== null;
203
+ }
204
+ // --- Private methods ---
205
+ cancelQuietTimer() {
206
+ if (this.quietTimer) {
207
+ clearTimeout(this.quietTimer);
208
+ this.quietTimer = null;
209
+ }
210
+ }
211
+ checkQuiet() {
212
+ if (this.inflightCount === 0 && this.quietResolvers.length > 0) {
213
+ this.startQuietTimer();
214
+ }
215
+ }
216
+ startQuietTimer() {
217
+ // Cancel any existing timer first
218
+ this.cancelQuietTimer();
219
+ // Start quiet window timer
220
+ this.quietTimer = setTimeout(() => {
221
+ this.quietTimer = null;
222
+ // Resolve all pending waiters
223
+ for (const { resolve, timeoutId } of this.quietResolvers) {
224
+ clearTimeout(timeoutId);
225
+ resolve(true);
226
+ }
227
+ this.quietResolvers = [];
228
+ }, this.quietWindowMs);
229
+ }
230
+ }
231
+ // --- Global Registry ---
232
+ /**
233
+ * WeakMap registry for page-scoped trackers.
234
+ *
235
+ * Using WeakMap keyed by Page object provides automatic cleanup when
236
+ * the Page is garbage collected, avoiding memory leaks.
237
+ */
238
+ const trackers = new WeakMap();
239
+ /**
240
+ * Get or create a network tracker for a page.
241
+ *
242
+ * Note: This does NOT automatically attach the tracker.
243
+ * Call `tracker.attach(page)` after getting the tracker.
244
+ */
245
+ export function getOrCreateTracker(page) {
246
+ let tracker = trackers.get(page);
247
+ if (!tracker) {
248
+ tracker = new PageNetworkTracker();
249
+ trackers.set(page, tracker);
250
+ }
251
+ return tracker;
252
+ }
253
+ /**
254
+ * Remove and detach the tracker for a page.
255
+ *
256
+ * Call this when a page is closed to ensure proper cleanup.
257
+ */
258
+ export function removeTracker(page) {
259
+ const tracker = trackers.get(page);
260
+ if (tracker) {
261
+ tracker.detach();
262
+ trackers.delete(page);
263
+ }
264
+ }
265
+ /**
266
+ * Check if a page has a tracker attached.
267
+ */
268
+ export function hasTracker(page) {
269
+ return trackers.has(page);
270
+ }
271
+ //# sourceMappingURL=page-network-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-network-tracker.js","sourceRoot":"","sources":["../../../src/browser/page-network-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Page Stabilization Utilities
3
+ *
4
+ * Shared utilities for waiting on network activity to settle.
5
+ * Used by session-manager and execute-action.
6
+ *
7
+ * IMPORTANT: This module uses PageNetworkTracker for reliable network idle
8
+ * detection. Unlike Playwright's waitForLoadState('networkidle'), the tracker
9
+ * monitors actual request/response events and works for in-page actions
10
+ * (not just navigation load states).
11
+ */
12
+ import type { Page } from 'playwright';
13
+ /** Default timeout for network idle waiting after actions (ms) */
14
+ export declare const ACTION_NETWORK_IDLE_TIMEOUT_MS = 3000;
15
+ /** Default timeout for network idle waiting after navigation (ms) */
16
+ export declare const NAVIGATION_NETWORK_IDLE_TIMEOUT_MS = 5000;
17
+ /** Default quiet window - time with 0 inflight requests to consider "idle" (ms) */
18
+ export declare const DEFAULT_QUIET_WINDOW_MS = 500;
19
+ /**
20
+ * Wait for network to become quiet (no pending requests for 500ms).
21
+ *
22
+ * This catches pending API calls triggered by actions. Uses PageNetworkTracker
23
+ * which monitors request/response events directly, providing reliable detection
24
+ * of network activity for both navigation and in-page actions.
25
+ *
26
+ * Unlike Playwright's waitForLoadState('networkidle'), this works correctly
27
+ * for fetch/XHR requests triggered by user actions after page load.
28
+ *
29
+ * @param page - Playwright Page instance
30
+ * @param timeoutMs - Maximum time to wait for network idle
31
+ * @param quietWindowMs - Time with 0 inflight requests to consider "idle" (default: 500ms)
32
+ * @returns Whether network became idle (false = timed out, but that's OK - never throws)
33
+ */
34
+ export declare function waitForNetworkQuiet(page: Page, timeoutMs: number, quietWindowMs?: number): Promise<boolean>;
35
+ //# sourceMappingURL=page-stabilization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-stabilization.d.ts","sourceRoot":"","sources":["../../../src/browser/page-stabilization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,kEAAkE;AAClE,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAEnD,qEAAqE;AACrE,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAEvD,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,EACjB,aAAa,GAAE,MAAgC,GAC9C,OAAO,CAAC,OAAO,CAAC,CASlB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Page Stabilization Utilities
3
+ *
4
+ * Shared utilities for waiting on network activity to settle.
5
+ * Used by session-manager and execute-action.
6
+ *
7
+ * IMPORTANT: This module uses PageNetworkTracker for reliable network idle
8
+ * detection. Unlike Playwright's waitForLoadState('networkidle'), the tracker
9
+ * monitors actual request/response events and works for in-page actions
10
+ * (not just navigation load states).
11
+ */
12
+ import { getOrCreateTracker } from './page-network-tracker.js';
13
+ /** Default timeout for network idle waiting after actions (ms) */
14
+ export const ACTION_NETWORK_IDLE_TIMEOUT_MS = 3000;
15
+ /** Default timeout for network idle waiting after navigation (ms) */
16
+ export const NAVIGATION_NETWORK_IDLE_TIMEOUT_MS = 5000;
17
+ /** Default quiet window - time with 0 inflight requests to consider "idle" (ms) */
18
+ export const DEFAULT_QUIET_WINDOW_MS = 500;
19
+ /**
20
+ * Wait for network to become quiet (no pending requests for 500ms).
21
+ *
22
+ * This catches pending API calls triggered by actions. Uses PageNetworkTracker
23
+ * which monitors request/response events directly, providing reliable detection
24
+ * of network activity for both navigation and in-page actions.
25
+ *
26
+ * Unlike Playwright's waitForLoadState('networkidle'), this works correctly
27
+ * for fetch/XHR requests triggered by user actions after page load.
28
+ *
29
+ * @param page - Playwright Page instance
30
+ * @param timeoutMs - Maximum time to wait for network idle
31
+ * @param quietWindowMs - Time with 0 inflight requests to consider "idle" (default: 500ms)
32
+ * @returns Whether network became idle (false = timed out, but that's OK - never throws)
33
+ */
34
+ export async function waitForNetworkQuiet(page, timeoutMs, quietWindowMs = DEFAULT_QUIET_WINDOW_MS) {
35
+ const tracker = getOrCreateTracker(page);
36
+ // Ensure tracker is attached (may not be if page was created outside SessionManager)
37
+ if (!tracker.isAttached()) {
38
+ tracker.attach(page);
39
+ }
40
+ return tracker.waitForQuiet(timeoutMs, quietWindowMs);
41
+ }
42
+ //# sourceMappingURL=page-stabilization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-stabilization.js","sourceRoot":"","sources":["../../../src/browser/page-stabilization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,kEAAkE;AAClE,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAEnD,qEAAqE;AACrE,MAAM,CAAC,MAAM,kCAAkC,GAAG,IAAI,CAAC;AAEvD,mFAAmF;AACnF,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAU,EACV,SAAiB,EACjB,gBAAwB,uBAAuB;IAE/C,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEzC,qFAAqF;IACrF,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AACxD,CAAC"}
@@ -194,6 +194,10 @@ export declare class SessionManager {
194
194
  /**
195
195
  * Navigate a page to a URL
196
196
  *
197
+ * Waits for both DOM ready and network idle to ensure the page is fully loaded.
198
+ * Network idle timeout is generous (5s) but never throws - pages with persistent
199
+ * connections (websockets, long-polling, analytics) may never reach idle.
200
+ *
197
201
  * @param page_id - The page identifier
198
202
  * @param url - URL to navigate to
199
203
  * @throws Error if page not found or navigation fails
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/browser/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/browser/session-manager.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,9 @@ import { PlaywrightCdpClient } from '../cdp/playwright-cdp-client.js';
9
9
  import { PageRegistry } from './page-registry.js';
10
10
  import { getLogger } from '../shared/services/logging.service.js';
11
11
  import { BrowserSessionError } from '../shared/errors/browser-session.error.js';
12
+ import { observationAccumulator } from '../observation/index.js';
13
+ import { waitForNetworkQuiet, NAVIGATION_NETWORK_IDLE_TIMEOUT_MS } from './page-stabilization.js';
14
+ import { getOrCreateTracker, removeTracker } from './page-network-tracker.js';
12
15
  /** Default CDP port for Athena Browser */
13
16
  const DEFAULT_CDP_PORT = 9223;
14
17
  /** Default CDP host */
@@ -307,6 +310,13 @@ export class SessionManager {
307
310
  this.registry.updateMetadata(handle.page_id, {
308
311
  url: page.url(),
309
312
  });
313
+ // Inject observation accumulator for DOM mutation tracking
314
+ await observationAccumulator.inject(page);
315
+ // Attach network tracker for this page
316
+ const tracker = getOrCreateTracker(page);
317
+ tracker.attach(page);
318
+ // Cleanup tracker on unexpected page close
319
+ page.on('close', () => removeTracker(page));
310
320
  this.logger.debug('Adopted page', { page_id: handle.page_id, url: page.url() });
311
321
  return handle;
312
322
  }
@@ -336,6 +346,13 @@ export class SessionManager {
336
346
  url: page.url(),
337
347
  });
338
348
  }
349
+ // Inject observation accumulator for DOM mutation tracking
350
+ await observationAccumulator.inject(page);
351
+ // Attach network tracker for this page
352
+ const tracker = getOrCreateTracker(page);
353
+ tracker.attach(page);
354
+ // Cleanup tracker on unexpected page close
355
+ page.on('close', () => removeTracker(page));
339
356
  return handle;
340
357
  }
341
358
  /**
@@ -406,6 +423,8 @@ export class SessionManager {
406
423
  if (!handle) {
407
424
  return false;
408
425
  }
426
+ // Cleanup network tracker before closing
427
+ removeTracker(handle.page);
409
428
  try {
410
429
  // Close CDP session first
411
430
  await handle.cdp.close();
@@ -434,6 +453,10 @@ export class SessionManager {
434
453
  /**
435
454
  * Navigate a page to a URL
436
455
  *
456
+ * Waits for both DOM ready and network idle to ensure the page is fully loaded.
457
+ * Network idle timeout is generous (5s) but never throws - pages with persistent
458
+ * connections (websockets, long-polling, analytics) may never reach idle.
459
+ *
437
460
  * @param page_id - The page identifier
438
461
  * @param url - URL to navigate to
439
462
  * @throws Error if page not found or navigation fails
@@ -444,10 +467,21 @@ export class SessionManager {
444
467
  throw new Error('Page not found');
445
468
  }
446
469
  try {
470
+ // Wait for DOM ready first (fast baseline)
447
471
  await handle.page.goto(url, { waitUntil: 'domcontentloaded' });
472
+ // Mark navigation on tracker (bumps generation to ignore stale events)
473
+ const tracker = getOrCreateTracker(handle.page);
474
+ tracker.markNavigation();
475
+ // Then wait for network to settle (catches API calls)
476
+ const networkIdle = await waitForNetworkQuiet(handle.page, NAVIGATION_NETWORK_IDLE_TIMEOUT_MS);
477
+ if (!networkIdle) {
478
+ this.logger.debug('Network did not reach idle state', { page_id, url });
479
+ }
448
480
  this.registry.updateMetadata(page_id, {
449
481
  url: handle.page.url(),
450
482
  });
483
+ // Re-inject observation accumulator (new document context)
484
+ await observationAccumulator.inject(handle.page);
451
485
  this.logger.debug('Navigated page', { page_id, url });
452
486
  }
453
487
  catch (error) {