-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Labels
agent-friendlyImproves agent workflowsImproves agent workflowsenhancementNew feature or requestNew feature or requesthigh-impactHigh value for agents/usersHigh value for agents/users
Description
Summary
DOM action commands automatically show network requests they triggered, using event-driven network idle detection instead of arbitrary timeouts. Zero flags required - it just works.
Problem
After performing a DOM action, agents need to verify it triggered the expected API calls:
bdg dom click "button.submit"
# Did it work? What API calls happened?
bdg peek --network --last 5
# Manual correlation by timestamp... error-proneSolution: Auto-Show Triggered Requests
DOM actions automatically display triggered network requests:
bdg dom click "button.submit"Output:
Clicked: button.submit
Triggered:
POST /api/submit → 200 OK (1.2s)
GET /api/refresh → 200 OK (89ms)
Network idle after 1.4s
No flags. No trace commands. No workflow to remember.
Event-Driven Network Idle Detection
Instead of hardcoded wait times (unreliable, arbitrary), use CDP events to detect when network activity has settled:
async function waitForNetworkIdle(
options: { idleThreshold?: number; maxWait?: number } = {}
): Promise<NetworkRequest[]> {
const { idleThreshold = 100, maxWait = 10000 } = options;
let lastActivity = Date.now();
let pendingRequests = 0;
const triggeredRequests: NetworkRequest[] = [];
const actionTimestamp = Date.now();
const onRequestStart = (params: RequestWillBeSentParams) => {
pendingRequests++;
lastActivity = Date.now();
if (params.timestamp >= actionTimestamp) {
// Track requests that started after our action
triggeredRequests.push(createRequestFromParams(params));
}
};
const onRequestEnd = (params: LoadingFinishedParams) => {
pendingRequests = Math.max(0, pendingRequests - 1);
lastActivity = Date.now();
// Update request with completion status
updateRequestStatus(triggeredRequests, params);
};
// Subscribe to CDP events
cdp.on('Network.requestWillBeSent', onRequestStart);
cdp.on('Network.loadingFinished', onRequestEnd);
cdp.on('Network.loadingFailed', onRequestEnd);
try {
const start = Date.now();
while (Date.now() - start < maxWait) {
const timeSinceActivity = Date.now() - lastActivity;
// Network is idle when: no pending requests AND quiet for threshold
if (pendingRequests === 0 && timeSinceActivity >= idleThreshold) {
break;
}
await sleep(50);
}
} finally {
// Cleanup listeners
cdp.off('Network.requestWillBeSent', onRequestStart);
cdp.off('Network.loadingFinished', onRequestEnd);
cdp.off('Network.loadingFailed', onRequestEnd);
}
return triggeredRequests;
}Behavior by Scenario
| Scenario | Behavior | Total Time |
|---|---|---|
| Fast API (50ms) | Waits for completion + 100ms idle | ~150ms |
| Slow API (2s) | Waits for completion + 100ms idle | ~2.1s |
| Multiple requests | Waits for ALL to complete | Longest + 100ms |
| No requests triggered | Returns after 100ms idle | ~100ms |
| Hung/slow request | Max timeout safety net | 10s max |
| WebSocket messages | Included in triggered output | N/A |
Integration with DOM Commands
File: src/commands/dom/index.ts
// click handler
.action(async (selector, options) => {
await runCommand(async () => {
const result = await performClick(selector, options);
// Auto-capture triggered requests (unless --no-wait)
if (!options.noWait) {
const triggered = await waitForNetworkIdle();
return {
success: true,
data: { ...result, triggered }
};
}
return { success: true, data: result };
}, options, formatClickResult);
});Output Formats
Human-Readable (default)
Clicked: button.submit
Triggered:
POST /api/submit → 200 OK (1.2s)
GET /api/refresh → 200 OK (89ms)
WS wss://realtime.example.com ← 2 messages
Network idle after 1.4s
JSON (--json)
{
"action": "click",
"selector": "button.submit",
"success": true,
"triggered": {
"requests": [
{
"id": "req_123",
"method": "POST",
"url": "/api/submit",
"status": 200,
"duration": 1200
}
],
"websocket": [
{
"url": "wss://realtime.example.com",
"received": 2,
"sent": 0
}
],
"idleAfter": 1400
}
}Quiet Mode (-q)
Clicked: button.submit
Configuration
Environment variables for edge cases:
| Variable | Default | Description |
|---|---|---|
BDG_IDLE_THRESHOLD |
100 | ms of quiet to consider "idle" |
BDG_IDLE_TIMEOUT |
10000 | Max wait in ms (safety net) |
CLI override:
bdg dom click "button" --no-wait # Skip network idle detectionAffected Commands
All DOM action commands gain automatic triggered request display:
bdg dom clickbdg dom fillbdg dom submitbdg dom pressKey
Implementation Files
| File | Change |
|---|---|
src/telemetry/networkIdle.ts |
New: Network idle detection logic |
src/commands/dom/index.ts |
Integrate idle detection after actions |
src/commands/dom/helpers.ts |
Add waitForNetworkIdle helper |
src/ui/formatters/dom.ts |
Format triggered requests output |
src/commands/shared/optionTypes.ts |
Add noWait option type |
Error Handling
Timeout Reached
Clicked: button.submit
Triggered (timeout after 10s):
POST /api/submit → pending
Warning: Network did not idle within 10s. Some requests may still be in flight.
No Requests
Clicked: button.submit
No network requests triggered (idle after 100ms)
Testing Strategy
Unit Tests
waitForNetworkIdlewith mock CDP events- Idle threshold timing accuracy
- Max timeout enforcement
- Request correlation by timestamp
Integration Tests
# Fast endpoint
bdg https://httpbin.org/forms/post
bdg dom fill "input[name=custname]" "Test"
bdg dom click "button"
# Verify: POST /post appears in triggered
# Slow endpoint
bdg https://httpbin.org/delay/2
bdg dom eval "fetch('/delay/2')"
# Verify: Waits ~2.1s, shows request
# No network
bdg dom click "button.local-only"
# Verify: Shows "No network requests triggered"Benefits
- Zero learning curve - No flags to remember, no workflow
- Accurate - Event-driven, not arbitrary timeouts
- Fast - Only waits as long as needed
- Comprehensive - Captures all requests including WebSocket
- Agent-friendly - JSON output includes all correlation data
Acceptance Criteria
- DOM actions auto-display triggered network requests
- Uses CDP events for network idle detection (no hardcoded waits)
- Respects
BDG_IDLE_THRESHOLDandBDG_IDLE_TIMEOUTenv vars -
--no-waitflag skips idle detection - JSON output includes
triggeredobject - WebSocket messages included
- Timeout warning when max wait exceeded
- Works with
click,fill,submit,pressKey
Non-Goals
- Explicit
trace start/stopcommands (not needed with auto-detection) - Historical trace replay
- Trace persistence across sessions
Related
- Network telemetry:
src/telemetry/network.ts - DOM commands:
src/commands/dom/index.ts - TelemetryStore:
src/daemon/worker/TelemetryStore.ts - Roadmap:
docs/roadmap/ROADMAP.md(Section 2.1)
Metadata
Metadata
Assignees
Labels
agent-friendlyImproves agent workflowsImproves agent workflowsenhancementNew feature or requestNew feature or requesthigh-impactHigh value for agents/usersHigh value for agents/users