viyv-browser-mcp 0.5.5 → 0.5.6
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.
- package/dist/index.js +342 -137
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,7 +27,15 @@ var TIMEOUTS = {
|
|
|
27
27
|
/** CDP idle detach delay */
|
|
28
28
|
CDP_IDLE_DETACH: 5e3,
|
|
29
29
|
/** Tab lock TTL (deadlock prevention) */
|
|
30
|
-
TAB_LOCK_TTL: 6e4
|
|
30
|
+
TAB_LOCK_TTL: 6e4,
|
|
31
|
+
/** Default scenario max_duration_ms (30 min) */
|
|
32
|
+
SCENARIO_MAX_DURATION: 18e5,
|
|
33
|
+
/** Buffer added to scenario max_duration for MCP timeout */
|
|
34
|
+
MCP_SCENARIO_BUFFER: 6e4,
|
|
35
|
+
/** MCP timeout for sm_job_run with wait_for_completion (4 hours) */
|
|
36
|
+
MCP_JOB_WAIT: 4 * 60 * 60 * 1e3,
|
|
37
|
+
/** Dialog pause timeout (2 min) — auto-fail if no resume */
|
|
38
|
+
DIALOG_PAUSE_TIMEOUT: 12e4
|
|
31
39
|
};
|
|
32
40
|
var LIMITS = {
|
|
33
41
|
/** Native Messaging max message size (Chrome limit) */
|
|
@@ -93,12 +101,13 @@ function decompressPayload(data, isCompressed) {
|
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
// src/native-host/transport.ts
|
|
96
|
-
var
|
|
104
|
+
var MAX_OUTBOUND_SIZE = 1024 * 1024;
|
|
105
|
+
var MAX_INBOUND_SIZE = 100 * 1024 * 1024;
|
|
97
106
|
function encodeMessage(message) {
|
|
98
107
|
const json = JSON.stringify(message);
|
|
99
108
|
const body = Buffer.from(json, "utf-8");
|
|
100
|
-
if (body.length >
|
|
101
|
-
throw new Error(`Message too large: ${body.length} bytes (max ${
|
|
109
|
+
if (body.length > MAX_OUTBOUND_SIZE) {
|
|
110
|
+
throw new Error(`Message too large: ${body.length} bytes (max ${MAX_OUTBOUND_SIZE})`);
|
|
102
111
|
}
|
|
103
112
|
const header = Buffer.alloc(4);
|
|
104
113
|
header.writeUInt32LE(body.length, 0);
|
|
@@ -114,8 +123,8 @@ function createMessageReader(stream, onMessage, onError, onClose) {
|
|
|
114
123
|
if (buffer.length < 4) break;
|
|
115
124
|
expectedLength = buffer.readUInt32LE(0);
|
|
116
125
|
buffer = buffer.subarray(4);
|
|
117
|
-
if (expectedLength >
|
|
118
|
-
onError?.(new Error(`Message too large: ${expectedLength} bytes`));
|
|
126
|
+
if (expectedLength > MAX_INBOUND_SIZE) {
|
|
127
|
+
onError?.(new Error(`Message too large: ${expectedLength} bytes (max ${MAX_INBOUND_SIZE})`));
|
|
119
128
|
expectedLength = null;
|
|
120
129
|
buffer = Buffer.alloc(0);
|
|
121
130
|
break;
|
|
@@ -297,16 +306,27 @@ function startBridge(options) {
|
|
|
297
306
|
const chrome = chromeConnections.get(chromeId);
|
|
298
307
|
if (chrome) {
|
|
299
308
|
chrome.send(message);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const fallback = chromeConnections.values().next().value;
|
|
312
|
+
if (fallback) {
|
|
313
|
+
process.stderr.write(
|
|
314
|
+
`${LOG_PREFIX2} WARNING: '${chromeId}' not found, using ${fallback.chromeId}
|
|
315
|
+
`
|
|
316
|
+
);
|
|
317
|
+
fallback.send(message);
|
|
300
318
|
} else {
|
|
301
319
|
process.stderr.write(
|
|
302
|
-
`${LOG_PREFIX2} WARNING:
|
|
320
|
+
`${LOG_PREFIX2} WARNING: No Chrome connections available, dropping message
|
|
303
321
|
`
|
|
304
322
|
);
|
|
305
|
-
chromeConnections.get(primaryChromeId)?.send(message);
|
|
306
323
|
}
|
|
307
324
|
}
|
|
308
325
|
function getChromeForAgent(agentId) {
|
|
309
|
-
|
|
326
|
+
const mapped = agentToChrome.get(agentId);
|
|
327
|
+
if (mapped && chromeConnections.has(mapped)) return mapped;
|
|
328
|
+
const first = chromeConnections.keys().next().value;
|
|
329
|
+
return first ?? primaryChromeId;
|
|
310
330
|
}
|
|
311
331
|
function connIdForAgent(agentId) {
|
|
312
332
|
return agentToConn.get(agentId);
|
|
@@ -373,12 +393,17 @@ function startBridge(options) {
|
|
|
373
393
|
agentToConn.set(agentId, connId);
|
|
374
394
|
mcpConnections.get(connId)?.agentIds.add(agentId);
|
|
375
395
|
const chromeProfile = message.chromeProfile;
|
|
376
|
-
|
|
377
|
-
if (chromeProfile &&
|
|
378
|
-
|
|
379
|
-
|
|
396
|
+
let resolvedChrome;
|
|
397
|
+
if (chromeProfile && chromeConnections.has(chromeProfile)) {
|
|
398
|
+
resolvedChrome = chromeProfile;
|
|
399
|
+
} else {
|
|
400
|
+
if (chromeProfile) {
|
|
401
|
+
process.stderr.write(
|
|
402
|
+
`${LOG_PREFIX2} WARNING: chromeProfile '${chromeProfile}' not found, using default
|
|
380
403
|
`
|
|
381
|
-
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
resolvedChrome = chromeConnections.keys().next().value ?? primaryChromeId;
|
|
382
407
|
}
|
|
383
408
|
agentToChrome.set(agentId, resolvedChrome);
|
|
384
409
|
chromeConnections.get(resolvedChrome)?.agentIds.add(agentId);
|
|
@@ -455,6 +480,75 @@ function startBridge(options) {
|
|
|
455
480
|
`);
|
|
456
481
|
}
|
|
457
482
|
}
|
|
483
|
+
function removeChromeConnection(chromeId) {
|
|
484
|
+
const chrome = chromeConnections.get(chromeId);
|
|
485
|
+
if (!chrome) return;
|
|
486
|
+
for (const agentId of [...chrome.agentIds]) {
|
|
487
|
+
const connId = connIdForAgent(agentId);
|
|
488
|
+
if (connId) {
|
|
489
|
+
sendToMcp(connId, {
|
|
490
|
+
id: randomUUID(),
|
|
491
|
+
type: "session_close",
|
|
492
|
+
agentId,
|
|
493
|
+
timestamp: Date.now()
|
|
494
|
+
});
|
|
495
|
+
cleanupAgent(agentId, connId);
|
|
496
|
+
} else {
|
|
497
|
+
agentToChrome.delete(agentId);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
chromeConnections.delete(chromeId);
|
|
501
|
+
broadcastChromeProfiles();
|
|
502
|
+
}
|
|
503
|
+
let primaryStdinClosed = false;
|
|
504
|
+
const ORPHAN_TIMEOUT = 6e4;
|
|
505
|
+
let orphanTimer = null;
|
|
506
|
+
function gracefulExit(reason) {
|
|
507
|
+
process.stderr.write(`${LOG_PREFIX2} ${reason}, exiting
|
|
508
|
+
`);
|
|
509
|
+
if (orphanTimer) {
|
|
510
|
+
clearTimeout(orphanTimer);
|
|
511
|
+
orphanTimer = null;
|
|
512
|
+
}
|
|
513
|
+
const closingMsg = JSON.stringify({ type: "bridge_closing", timestamp: Date.now() });
|
|
514
|
+
for (const [, conn] of mcpConnections) {
|
|
515
|
+
try {
|
|
516
|
+
conn.socket.write(`${closingMsg}
|
|
517
|
+
`);
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
for (const [, conn] of mcpConnections) {
|
|
522
|
+
conn.socket.destroy();
|
|
523
|
+
}
|
|
524
|
+
mcpConnections.clear();
|
|
525
|
+
agentToConn.clear();
|
|
526
|
+
agentToChrome.clear();
|
|
527
|
+
chromeConnections.clear();
|
|
528
|
+
requestOrigin.clear();
|
|
529
|
+
clearInterval(cleanupTimer2);
|
|
530
|
+
server?.close();
|
|
531
|
+
process.exit(0);
|
|
532
|
+
}
|
|
533
|
+
function maybeExitIfEmpty() {
|
|
534
|
+
if (!primaryStdinClosed) return;
|
|
535
|
+
if (chromeConnections.size > 0 && orphanTimer) {
|
|
536
|
+
clearTimeout(orphanTimer);
|
|
537
|
+
orphanTimer = null;
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
if (chromeConnections.size === 0 && mcpConnections.size === 0) {
|
|
541
|
+
gracefulExit("No connections remaining");
|
|
542
|
+
}
|
|
543
|
+
if (chromeConnections.size === 0 && !orphanTimer) {
|
|
544
|
+
orphanTimer = setTimeout(() => {
|
|
545
|
+
orphanTimer = null;
|
|
546
|
+
if (chromeConnections.size === 0) {
|
|
547
|
+
gracefulExit(`No Chrome reconnected within ${ORPHAN_TIMEOUT}ms`);
|
|
548
|
+
}
|
|
549
|
+
}, ORPHAN_TIMEOUT);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
458
552
|
function setupRelayConnection(socket) {
|
|
459
553
|
const chromeId = `chrome-${nextChromeIndex++}`;
|
|
460
554
|
const chrome = {
|
|
@@ -483,6 +577,7 @@ function startBridge(options) {
|
|
|
483
577
|
chrome.send({ type: "bridge_status", connected: true, timestamp: Date.now() });
|
|
484
578
|
}
|
|
485
579
|
broadcastChromeProfiles();
|
|
580
|
+
maybeExitIfEmpty();
|
|
486
581
|
const processData = createTcpLineReader((message) => handleChromeMessage(message), onError);
|
|
487
582
|
socket.on("data", processData);
|
|
488
583
|
socket.on("error", (error) => {
|
|
@@ -494,22 +589,8 @@ function startBridge(options) {
|
|
|
494
589
|
`${LOG_PREFIX2} Chrome relay disconnected: ${chromeId} (remaining chromes: ${chromeConnections.size - 1})
|
|
495
590
|
`
|
|
496
591
|
);
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
if (connId) {
|
|
500
|
-
sendToMcp(connId, {
|
|
501
|
-
id: randomUUID(),
|
|
502
|
-
type: "session_close",
|
|
503
|
-
agentId,
|
|
504
|
-
timestamp: Date.now()
|
|
505
|
-
});
|
|
506
|
-
cleanupAgent(agentId, connId);
|
|
507
|
-
} else {
|
|
508
|
-
agentToChrome.delete(agentId);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
chromeConnections.delete(chromeId);
|
|
512
|
-
broadcastChromeProfiles();
|
|
592
|
+
removeChromeConnection(chromeId);
|
|
593
|
+
maybeExitIfEmpty();
|
|
513
594
|
});
|
|
514
595
|
}
|
|
515
596
|
function handleTcpConnection(socket) {
|
|
@@ -616,6 +697,7 @@ function startBridge(options) {
|
|
|
616
697
|
if (mcpConnections.size === 0) {
|
|
617
698
|
notifyChromeConnected(false);
|
|
618
699
|
}
|
|
700
|
+
maybeExitIfEmpty();
|
|
619
701
|
});
|
|
620
702
|
}
|
|
621
703
|
server = createServer((socket) => handleTcpConnection(socket));
|
|
@@ -643,40 +725,14 @@ function startBridge(options) {
|
|
|
643
725
|
onError
|
|
644
726
|
);
|
|
645
727
|
notifyChromeConnected(false);
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
for (const [, conn] of mcpConnections) {
|
|
649
|
-
try {
|
|
650
|
-
conn.socket.write(`${closingMsg}
|
|
651
|
-
`);
|
|
652
|
-
} catch {
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
for (const [, conn] of mcpConnections) {
|
|
656
|
-
conn.socket.destroy();
|
|
657
|
-
}
|
|
658
|
-
mcpConnections.clear();
|
|
659
|
-
agentToConn.clear();
|
|
660
|
-
agentToChrome.clear();
|
|
661
|
-
chromeConnections.clear();
|
|
662
|
-
requestOrigin.clear();
|
|
663
|
-
clearInterval(cleanupTimer2);
|
|
664
|
-
server?.close();
|
|
665
|
-
server = null;
|
|
666
|
-
}
|
|
667
|
-
process.on("SIGINT", () => {
|
|
668
|
-
shutdown();
|
|
669
|
-
process.exit(0);
|
|
670
|
-
});
|
|
671
|
-
process.on("SIGTERM", () => {
|
|
672
|
-
shutdown();
|
|
673
|
-
process.exit(0);
|
|
674
|
-
});
|
|
728
|
+
process.on("SIGINT", () => gracefulExit("SIGINT received"));
|
|
729
|
+
process.on("SIGTERM", () => gracefulExit("SIGTERM received"));
|
|
675
730
|
process.stdin.on("end", () => {
|
|
676
|
-
process.stderr.write(`${LOG_PREFIX2} stdin closed
|
|
731
|
+
process.stderr.write(`${LOG_PREFIX2} Primary Chrome stdin closed
|
|
677
732
|
`);
|
|
678
|
-
|
|
679
|
-
|
|
733
|
+
primaryStdinClosed = true;
|
|
734
|
+
removeChromeConnection(primaryChromeId);
|
|
735
|
+
maybeExitIfEmpty();
|
|
680
736
|
});
|
|
681
737
|
});
|
|
682
738
|
}
|
|
@@ -920,10 +976,16 @@ Options:
|
|
|
920
976
|
- maxChars: Limit output size (default: 50000). Use 100000 for full page content.`;
|
|
921
977
|
|
|
922
978
|
// src/tools/core/handle-dialog.ts
|
|
923
|
-
var HANDLE_DIALOG_DESCRIPTION = `Handle JavaScript dialogs
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
979
|
+
var HANDLE_DIALOG_DESCRIPTION = `Handle JavaScript dialogs (alert, confirm, prompt).
|
|
980
|
+
|
|
981
|
+
Two modes:
|
|
982
|
+
1. Handle current dialog: provide action ('accept'/'dismiss') and optional text
|
|
983
|
+
2. Set next policy: provide nextPolicy to pre-configure how the next
|
|
984
|
+
auto-handled dialog will be processed. The policy is one-shot \u2014
|
|
985
|
+
consumed after a single dialog, then reverts to default behavior.
|
|
986
|
+
|
|
987
|
+
Use mode 2 after seeing _auto_handled_dialogs in a tool result to change
|
|
988
|
+
how the next dialog will be handled when you re-trigger the action.`;
|
|
927
989
|
|
|
928
990
|
// src/tools/core/hover.ts
|
|
929
991
|
var HOVER_DESCRIPTION = `Move mouse to coordinates or element without clicking.
|
|
@@ -1040,38 +1102,6 @@ Returns details of HTTP requests and responses including URL, method,
|
|
|
1040
1102
|
status code, headers, and timing information. Supports filtering
|
|
1041
1103
|
by URL pattern or resource type.`;
|
|
1042
1104
|
|
|
1043
|
-
// src/tools/sheets/descriptions.ts
|
|
1044
|
-
var SHEETS_READ_DESCRIPTION = `Read data from the active Google Sheets spreadsheet.
|
|
1045
|
-
|
|
1046
|
-
Uses the gviz/tq endpoint with session cookies \u2014 works with private sheets without OAuth.
|
|
1047
|
-
Supports range selection, tq query language for filtering/aggregation, and row limits.
|
|
1048
|
-
|
|
1049
|
-
tq query examples:
|
|
1050
|
-
- "SELECT A, B WHERE C > 100" \u2014 filter rows
|
|
1051
|
-
- "SELECT A, SUM(B) GROUP BY A" \u2014 aggregate
|
|
1052
|
-
- "SELECT * ORDER BY C DESC LIMIT 5" \u2014 sort and limit
|
|
1053
|
-
|
|
1054
|
-
Set formulas=true to read raw formulas (e.g., =IMAGE(), =HYPERLINK()) instead of computed values.
|
|
1055
|
-
Formula mode reads cell-by-cell via the formula bar, limited to 200 cells.
|
|
1056
|
-
The tab must be on a Google Sheets page (docs.google.com/spreadsheets/).`;
|
|
1057
|
-
var SHEETS_WRITE_DESCRIPTION = `Write data to the active Google Sheets spreadsheet.
|
|
1058
|
-
|
|
1059
|
-
For single cell: navigates to the cell via Name Box and types the value.
|
|
1060
|
-
For multiple cells: converts 2D array to TSV, copies to clipboard via Offscreen Document, then pastes with Ctrl+V. Sheets auto-expands TSV into multiple cells.
|
|
1061
|
-
|
|
1062
|
-
Provide either "value" (single cell string) or "values" (2D array), not both.
|
|
1063
|
-
The tab must be on a Google Sheets page.`;
|
|
1064
|
-
var SHEETS_INFO_DESCRIPTION = `Get metadata about the active Google Sheets spreadsheet.
|
|
1065
|
-
|
|
1066
|
-
Returns spreadsheet ID, document title, sheet list (name, index, row/col counts, active status), active cell reference, and URL.
|
|
1067
|
-
Uses DOM inspection and gviz/tq queries for sheet dimensions.
|
|
1068
|
-
The tab must be on a Google Sheets page.`;
|
|
1069
|
-
var SHEETS_NAVIGATE_DESCRIPTION = `Navigate within the active Google Sheets spreadsheet.
|
|
1070
|
-
|
|
1071
|
-
Jump to a specific cell (e.g., "A1", "Z100") via the Name Box, or switch to a different sheet tab by name.
|
|
1072
|
-
Both cell and sheet can be specified together.
|
|
1073
|
-
The tab must be on a Google Sheets page.`;
|
|
1074
|
-
|
|
1075
1105
|
// src/tools/semantic/sm-add-action.ts
|
|
1076
1106
|
var SM_ADD_ACTION_DESCRIPTION = `Define a semantic action (step sequence) for a registered page.
|
|
1077
1107
|
|
|
@@ -1152,6 +1182,10 @@ var SM_CAPABILITIES_DESCRIPTION = `Query semantic capabilities available for the
|
|
|
1152
1182
|
Returns the matched page definition, available actions, and fetches for the active tab.
|
|
1153
1183
|
Uses page signature matching (URL pattern + DOM markers) to identify the current page state.
|
|
1154
1184
|
|
|
1185
|
+
Parameters:
|
|
1186
|
+
- tabId: target tab
|
|
1187
|
+
- include_other_pages (optional): include list of other registered pages on the same domain (default: false). Enable when looking for related pages to navigate to.
|
|
1188
|
+
|
|
1155
1189
|
Returns:
|
|
1156
1190
|
- ok: whether a page match was found
|
|
1157
1191
|
- domain: hostname of the current tab
|
|
@@ -1159,7 +1193,7 @@ Returns:
|
|
|
1159
1193
|
- match_score: confidence score of the match
|
|
1160
1194
|
- actions[]: available actions with their parameters
|
|
1161
1195
|
- fetches[]: available data extractions with their parameters
|
|
1162
|
-
- other_pages[]: other registered pages on the same domain
|
|
1196
|
+
- other_pages[]: (only when include_other_pages=true) other registered pages on the same domain
|
|
1163
1197
|
- hint: guidance message when no page matches
|
|
1164
1198
|
|
|
1165
1199
|
Use this before sm_invoke or sm_fetch to discover what operations are available.
|
|
@@ -1246,15 +1280,52 @@ Returns:
|
|
|
1246
1280
|
- cascaded: (page deletion) lists of deleted targets, actions, fetches
|
|
1247
1281
|
- warnings: (target deletion) referencing actions/fetches that may break`;
|
|
1248
1282
|
|
|
1283
|
+
// src/tools/semantic/sm-execution-resume.ts
|
|
1284
|
+
var SM_EXECUTION_RESUME_DESCRIPTION = `Resume a paused scenario/job execution.
|
|
1285
|
+
|
|
1286
|
+
When execution is paused (e.g. a browser dialog appeared), use this tool to decide how to proceed.
|
|
1287
|
+
Check sm_execution_status or sm_job_report_get (status 'dialog_paused') to detect pauses.
|
|
1288
|
+
|
|
1289
|
+
Actions:
|
|
1290
|
+
- continue: Dialog already handled, continue to next step
|
|
1291
|
+
- retry: Set dialog policy and re-execute the step that triggered the dialog
|
|
1292
|
+
- skip_iteration: Skip to next loop iteration (only inside a loop)
|
|
1293
|
+
- skip_scenario: Skip entire scenario (marks as cancelled)
|
|
1294
|
+
- fail: Fail the current step (scenario continues or stops based on on_error)
|
|
1295
|
+
|
|
1296
|
+
Returns execution result or another dialog_paused if a new dialog appears.`;
|
|
1297
|
+
|
|
1298
|
+
// src/tools/semantic/sm-execution-status.ts
|
|
1299
|
+
var SM_EXECUTION_STATUS_DESCRIPTION = `Check what is currently executing on a tab.
|
|
1300
|
+
|
|
1301
|
+
Returns the execution type (job/scenario/none), IDs, progress, and pause state.
|
|
1302
|
+
Use this to see if a tab is busy before starting new work, or to get IDs for polling.
|
|
1303
|
+
|
|
1304
|
+
Parameters:
|
|
1305
|
+
- tabId: tab to check
|
|
1306
|
+
|
|
1307
|
+
Returns:
|
|
1308
|
+
- type: 'job' | 'scenario' | 'none'
|
|
1309
|
+
- label: execution label
|
|
1310
|
+
- started_at: execution start timestamp
|
|
1311
|
+
- job_id, job_report_id: (job only) IDs for polling with sm_job_report_get
|
|
1312
|
+
- scenario_id, report_id: (standalone scenario only) IDs for polling with sm_report_get
|
|
1313
|
+
- current_scenario: (job only) currently running scenario {scenario_id, scenario_label, report_id}
|
|
1314
|
+
- progress: (job only) {current_entry_index, total_entries, entries_completed}
|
|
1315
|
+
- is_paused: whether execution is paused due to dialog
|
|
1316
|
+
- pause_info: dialog details if paused`;
|
|
1317
|
+
|
|
1249
1318
|
// src/tools/semantic/sm-export.ts
|
|
1250
1319
|
var SM_EXPORT_DESCRIPTION = `Export semantic configuration as JSON.
|
|
1251
1320
|
|
|
1252
|
-
Exports pages, targets, actions, and fetches
|
|
1321
|
+
Exports pages, targets, actions, and fetches scoped by the current tab's page.
|
|
1253
1322
|
Secret parameter default values are stripped from the export.
|
|
1254
1323
|
Includes a SHA-256 checksum for integrity verification on import.
|
|
1255
1324
|
|
|
1256
1325
|
Parameters:
|
|
1257
|
-
-
|
|
1326
|
+
- tabId (required): Tab ID to identify the current page
|
|
1327
|
+
- scope (optional): "page" (default) exports only the current page's config, "domain" exports all pages for the tab's domain, "all" exports everything
|
|
1328
|
+
- file_path (optional): save to this path and return metadata only (keeps data out of context)
|
|
1258
1329
|
|
|
1259
1330
|
Returns:
|
|
1260
1331
|
- SemanticExport JSON with schema_version, checksum, pages[], targets[], actions[], fetches[]`;
|
|
@@ -1379,7 +1450,10 @@ Parameters:
|
|
|
1379
1450
|
|
|
1380
1451
|
Returns:
|
|
1381
1452
|
- job_id, job_label
|
|
1382
|
-
- snapshots[]: list of {snapshot_id, status, started_at, completed_at, duration_ms, scenario_count}
|
|
1453
|
+
- snapshots[]: list of {snapshot_id, job_report_id, status, started_at, completed_at, duration_ms, scenario_count, scenarios[]}
|
|
1454
|
+
- job_report_id: use with sm_job_report_get for detailed results
|
|
1455
|
+
- scenarios[]: per-scenario {scenario_id, scenario_label, report_id, status}
|
|
1456
|
+
- report_id: use with sm_report_get or sm_report_export for individual scenario data`;
|
|
1383
1457
|
var SM_JOB_COMPARE_DESCRIPTION = `Compare two job executions to see data changes between them.
|
|
1384
1458
|
|
|
1385
1459
|
Matches scenarios by scenario_id, data groups by result_key, and rows by loop_params. Computes per-cell diffs with numeric deltas.
|
|
@@ -1399,9 +1473,10 @@ Use this to inspect the full captured data for a single execution, including all
|
|
|
1399
1473
|
|
|
1400
1474
|
Parameters:
|
|
1401
1475
|
- snapshot_id: the snapshot to retrieve (SNP_xxxx)
|
|
1476
|
+
- summary_only: if true, omit data_groups from scenario snapshots to reduce payload size (default: false)
|
|
1402
1477
|
|
|
1403
1478
|
Returns:
|
|
1404
|
-
- snapshot: full JobSnapshot with scenario_snapshots and data_groups`;
|
|
1479
|
+
- snapshot: full JobSnapshot with scenario_snapshots and data_groups (or empty data_groups if summary_only)`;
|
|
1405
1480
|
|
|
1406
1481
|
// src/tools/semantic/sm-job-list.ts
|
|
1407
1482
|
var SM_JOB_LIST_DESCRIPTION = `List all defined jobs with entry counts and configuration.
|
|
@@ -1430,6 +1505,11 @@ var SM_JOB_REPORT_GET_DESCRIPTION = `Get job execution status and results.
|
|
|
1430
1505
|
Shows overall progress and per-scenario report summaries.
|
|
1431
1506
|
Use sm_report_get with individual report_ids for detailed scenario data.
|
|
1432
1507
|
|
|
1508
|
+
Poll this after sm_job_run to track progress:
|
|
1509
|
+
- status 'running': job is still executing
|
|
1510
|
+
- status 'dialog_paused': a browser dialog appeared, use sm_execution_resume to continue
|
|
1511
|
+
- status 'completed'/'failed': job finished
|
|
1512
|
+
|
|
1433
1513
|
Parameters:
|
|
1434
1514
|
- job_report_id: job report ID (JRP_xxxx)
|
|
1435
1515
|
|
|
@@ -1440,8 +1520,7 @@ Returns:
|
|
|
1440
1520
|
// src/tools/semantic/sm-job-run.ts
|
|
1441
1521
|
var SM_JOB_RUN_DESCRIPTION = `Execute a job on a browser tab. Scenarios run sequentially.
|
|
1442
1522
|
|
|
1443
|
-
|
|
1444
|
-
Set wait_for_completion=true to block until all scenarios finish.
|
|
1523
|
+
Always returns immediately with job_report_id. Poll sm_job_report_get to check progress.
|
|
1445
1524
|
|
|
1446
1525
|
Only one job or scenario can run per tab at a time.
|
|
1447
1526
|
|
|
@@ -1449,12 +1528,16 @@ Parameters:
|
|
|
1449
1528
|
- tabId: target tab for execution
|
|
1450
1529
|
- job_id: the job to execute
|
|
1451
1530
|
- params: optional per-scenario param overrides keyed by scenario_id
|
|
1452
|
-
- wait_for_completion: if true, wait for all scenarios to complete (default: false)
|
|
1453
1531
|
|
|
1454
1532
|
Returns:
|
|
1455
|
-
- job_report_id: ID of the created job report (JRP_xxxx)
|
|
1533
|
+
- job_report_id: ID of the created job report (JRP_xxxx) \u2014 use with sm_job_report_get to poll
|
|
1456
1534
|
- job_id: the executed job
|
|
1457
|
-
- status: 'running'
|
|
1535
|
+
- status: 'running' | 'failed' (failed = could not start)
|
|
1536
|
+
|
|
1537
|
+
Workflow:
|
|
1538
|
+
1. sm_job_run \u2192 get job_report_id
|
|
1539
|
+
2. sm_job_report_get(job_report_id) \u2192 poll until status is 'completed'/'failed'
|
|
1540
|
+
3. If status is 'dialog_paused', use sm_execution_resume to continue`;
|
|
1458
1541
|
|
|
1459
1542
|
// src/tools/semantic/sm-job-update.ts
|
|
1460
1543
|
var SM_JOB_UPDATE_DESCRIPTION = `Update an existing job definition.
|
|
@@ -1628,12 +1711,17 @@ Parameters:
|
|
|
1628
1711
|
- scenario_id: the scenario to execute
|
|
1629
1712
|
- params: parameter values for template substitution
|
|
1630
1713
|
- wait_for_completion: if true, wait for scenario to finish (up to max_duration_ms)
|
|
1714
|
+
- max_duration_ms (optional): override scenario timeout in milliseconds (default: scenario's own value, typically 1800000ms / 30min)
|
|
1631
1715
|
|
|
1632
1716
|
Returns:
|
|
1633
1717
|
- report_id: ID of the created report (RPT_xxxx)
|
|
1634
1718
|
- scenario_id: the executed scenario
|
|
1635
1719
|
- status: 'running' (async) or 'completed'/'failed' (when wait_for_completion=true)
|
|
1636
|
-
- error: error message if startup failed
|
|
1720
|
+
- error: error message if startup failed
|
|
1721
|
+
|
|
1722
|
+
When wait_for_completion=true, may return status 'dialog_paused' if a browser dialog
|
|
1723
|
+
appeared during execution. The dialog was auto-handled to unblock the page.
|
|
1724
|
+
Use sm_execution_resume to decide how to proceed.`;
|
|
1637
1725
|
|
|
1638
1726
|
// src/tools/semantic/sm-scenario-update.ts
|
|
1639
1727
|
var SM_SCENARIO_UPDATE_DESCRIPTION = `Update an existing scenario.
|
|
@@ -1664,14 +1752,16 @@ Parameters:
|
|
|
1664
1752
|
- page_id (optional): filter results to a specific page
|
|
1665
1753
|
- domain (optional): filter results to pages matching this domain
|
|
1666
1754
|
- test_resolve (optional): if true, resolve all targets on the current tab
|
|
1755
|
+
- summary_only (optional): return only summary counts and page list, omitting targets/actions/fetches/integrity arrays (default: true)
|
|
1667
1756
|
|
|
1668
1757
|
Returns:
|
|
1669
1758
|
- summary: {total_pages, total_targets, total_actions, total_fetches}
|
|
1670
1759
|
- pages[]: page definitions with page_type, domains, url_patterns, and counts
|
|
1671
|
-
-
|
|
1672
|
-
-
|
|
1673
|
-
-
|
|
1674
|
-
-
|
|
1760
|
+
- When summary_only is false, also includes:
|
|
1761
|
+
- targets[]: targets with locator info and optional resolve_result
|
|
1762
|
+
- actions[]: actions with step count and param names
|
|
1763
|
+
- fetches[]: fetches with field count
|
|
1764
|
+
- integrity[]: referential integrity warnings`;
|
|
1675
1765
|
|
|
1676
1766
|
// src/tools/semantic/sm-test-target.ts
|
|
1677
1767
|
var SM_TEST_TARGET_DESCRIPTION = `Test a specific target's locators against the current page.
|
|
@@ -1689,6 +1779,38 @@ Returns:
|
|
|
1689
1779
|
- element: resolved element info {tag, text, rect} if found
|
|
1690
1780
|
- test_status: updated test status saved to storage`;
|
|
1691
1781
|
|
|
1782
|
+
// src/tools/sheets/descriptions.ts
|
|
1783
|
+
var SHEETS_READ_DESCRIPTION = `Read data from the active Google Sheets spreadsheet.
|
|
1784
|
+
|
|
1785
|
+
Uses the gviz/tq endpoint with session cookies \u2014 works with private sheets without OAuth.
|
|
1786
|
+
Supports range selection, tq query language for filtering/aggregation, and row limits.
|
|
1787
|
+
|
|
1788
|
+
tq query examples:
|
|
1789
|
+
- "SELECT A, B WHERE C > 100" \u2014 filter rows
|
|
1790
|
+
- "SELECT A, SUM(B) GROUP BY A" \u2014 aggregate
|
|
1791
|
+
- "SELECT * ORDER BY C DESC LIMIT 5" \u2014 sort and limit
|
|
1792
|
+
|
|
1793
|
+
Set formulas=true to read raw formulas (e.g., =IMAGE(), =HYPERLINK()) instead of computed values.
|
|
1794
|
+
Formula mode reads cell-by-cell via the formula bar, limited to 200 cells.
|
|
1795
|
+
The tab must be on a Google Sheets page (docs.google.com/spreadsheets/).`;
|
|
1796
|
+
var SHEETS_WRITE_DESCRIPTION = `Write data to the active Google Sheets spreadsheet.
|
|
1797
|
+
|
|
1798
|
+
For single cell: navigates to the cell via Name Box and types the value.
|
|
1799
|
+
For multiple cells: converts 2D array to TSV, copies to clipboard via Offscreen Document, then pastes with Ctrl+V. Sheets auto-expands TSV into multiple cells.
|
|
1800
|
+
|
|
1801
|
+
Provide either "value" (single cell string) or "values" (2D array), not both.
|
|
1802
|
+
The tab must be on a Google Sheets page.`;
|
|
1803
|
+
var SHEETS_INFO_DESCRIPTION = `Get metadata about the active Google Sheets spreadsheet.
|
|
1804
|
+
|
|
1805
|
+
Returns spreadsheet ID, document title, sheet list (name, index, row/col counts, active status), active cell reference, and URL.
|
|
1806
|
+
Uses DOM inspection and gviz/tq queries for sheet dimensions.
|
|
1807
|
+
The tab must be on a Google Sheets page.`;
|
|
1808
|
+
var SHEETS_NAVIGATE_DESCRIPTION = `Navigate within the active Google Sheets spreadsheet.
|
|
1809
|
+
|
|
1810
|
+
Jump to a specific cell (e.g., "A1", "Z100") via the Name Box, or switch to a different sheet tab by name.
|
|
1811
|
+
Both cell and sheet can be specified together.
|
|
1812
|
+
The tab must be on a Google Sheets page.`;
|
|
1813
|
+
|
|
1692
1814
|
// src/tools/tabs/select-tab.ts
|
|
1693
1815
|
var SELECT_TAB_DESCRIPTION = `Switch focus to a specific tab by its identifier.
|
|
1694
1816
|
Makes the target tab the active tab in the agent's group,
|
|
@@ -1931,8 +2053,12 @@ var handleDialogTool = {
|
|
|
1931
2053
|
description: HANDLE_DIALOG_DESCRIPTION,
|
|
1932
2054
|
inputSchema: z.object({
|
|
1933
2055
|
tabId: z.coerce.number().describe("Tab ID"),
|
|
1934
|
-
action: z.enum(["accept", "dismiss"]).describe("Dialog action"),
|
|
1935
|
-
text: z.string().optional().describe("Text for prompt dialog")
|
|
2056
|
+
action: z.enum(["accept", "dismiss"]).optional().describe("Dialog action (required when handling current dialog)"),
|
|
2057
|
+
text: z.string().optional().describe("Text for prompt dialog"),
|
|
2058
|
+
nextPolicy: z.object({
|
|
2059
|
+
action: z.enum(["accept", "dismiss"]).describe("Action for next dialog"),
|
|
2060
|
+
text: z.string().optional().describe("Text for prompt dialog")
|
|
2061
|
+
}).optional().describe("Set one-shot policy for the next auto-handled dialog. Consumed after one use.")
|
|
1936
2062
|
})
|
|
1937
2063
|
};
|
|
1938
2064
|
var tabsContextTool = {
|
|
@@ -2117,7 +2243,8 @@ var smCapabilitiesTool = {
|
|
|
2117
2243
|
name: "sm_capabilities",
|
|
2118
2244
|
description: SM_CAPABILITIES_DESCRIPTION,
|
|
2119
2245
|
inputSchema: z.object({
|
|
2120
|
-
tabId: z.coerce.number().describe("Tab ID")
|
|
2246
|
+
tabId: z.coerce.number().describe("Tab ID"),
|
|
2247
|
+
include_other_pages: z.boolean().optional().describe("Include list of other registered pages on the same domain (default: false)")
|
|
2121
2248
|
})
|
|
2122
2249
|
};
|
|
2123
2250
|
var smInvokeTool = {
|
|
@@ -2210,7 +2337,17 @@ var smAddActionTool = {
|
|
|
2210
2337
|
).optional().describe("Parameter definitions"),
|
|
2211
2338
|
steps: z.array(
|
|
2212
2339
|
z.object({
|
|
2213
|
-
type: z.enum([
|
|
2340
|
+
type: z.enum([
|
|
2341
|
+
"click",
|
|
2342
|
+
"type",
|
|
2343
|
+
"select",
|
|
2344
|
+
"wait",
|
|
2345
|
+
"scroll",
|
|
2346
|
+
"key",
|
|
2347
|
+
"navigate",
|
|
2348
|
+
"file_upload",
|
|
2349
|
+
"script"
|
|
2350
|
+
]).describe("Step type"),
|
|
2214
2351
|
target_id: z.string().optional().describe("Target to act on"),
|
|
2215
2352
|
params: z.object({
|
|
2216
2353
|
text: z.string().optional(),
|
|
@@ -2278,7 +2415,8 @@ var smStatusTool = {
|
|
|
2278
2415
|
tabId: z.coerce.number().optional().describe("Tab ID (required for test_resolve)"),
|
|
2279
2416
|
page_id: z.string().optional().describe("Filter by page ID"),
|
|
2280
2417
|
domain: z.string().optional().describe("Filter results to pages matching this domain"),
|
|
2281
|
-
test_resolve: z.boolean().optional().describe("Test-resolve all targets")
|
|
2418
|
+
test_resolve: z.boolean().optional().describe("Test-resolve all targets"),
|
|
2419
|
+
summary_only: z.boolean().optional().describe("Return only summary counts and page list, omitting detail arrays (default: true)")
|
|
2282
2420
|
})
|
|
2283
2421
|
};
|
|
2284
2422
|
var smTestTargetTool = {
|
|
@@ -2302,7 +2440,8 @@ var smExportTool = {
|
|
|
2302
2440
|
name: "sm_export",
|
|
2303
2441
|
description: SM_EXPORT_DESCRIPTION,
|
|
2304
2442
|
inputSchema: z.object({
|
|
2305
|
-
|
|
2443
|
+
tabId: z.coerce.number().describe("Tab ID to identify the current page"),
|
|
2444
|
+
scope: z.enum(["page", "domain", "all"]).optional().describe("Export scope (default: page)"),
|
|
2306
2445
|
file_path: z.string().optional().describe("Save to this path and return metadata only (keeps data out of context)")
|
|
2307
2446
|
})
|
|
2308
2447
|
};
|
|
@@ -2434,7 +2573,8 @@ var smScenarioRunTool = {
|
|
|
2434
2573
|
tabId: z.coerce.number().describe("Tab ID for execution"),
|
|
2435
2574
|
scenario_id: z.string().describe("Scenario to execute"),
|
|
2436
2575
|
params: z.record(z.unknown()).optional().describe("Parameter values"),
|
|
2437
|
-
wait_for_completion: z.boolean().optional().describe("Wait for completion (default: false, async)")
|
|
2576
|
+
wait_for_completion: z.boolean().optional().describe("Wait for completion (default: false, async)"),
|
|
2577
|
+
max_duration_ms: z.coerce.number().optional().describe("Override scenario timeout in ms (default: scenario value, typically 1800000)")
|
|
2438
2578
|
})
|
|
2439
2579
|
};
|
|
2440
2580
|
var smReportListTool = {
|
|
@@ -2512,8 +2652,7 @@ var smJobRunTool = {
|
|
|
2512
2652
|
inputSchema: z.object({
|
|
2513
2653
|
tabId: z.coerce.number().describe("Tab ID to execute scenarios on"),
|
|
2514
2654
|
job_id: z.string().describe("Job ID to execute"),
|
|
2515
|
-
params: z.record(z.record(z.unknown())).optional().describe("Per-scenario param overrides keyed by scenario_id")
|
|
2516
|
-
wait_for_completion: z.boolean().optional().describe("Wait for all scenarios to complete (default: false)")
|
|
2655
|
+
params: z.record(z.record(z.unknown())).optional().describe("Per-scenario param overrides keyed by scenario_id")
|
|
2517
2656
|
})
|
|
2518
2657
|
};
|
|
2519
2658
|
var smJobCancelTool = {
|
|
@@ -2523,6 +2662,17 @@ var smJobCancelTool = {
|
|
|
2523
2662
|
tabId: z.coerce.number().describe("Tab ID where the job is running")
|
|
2524
2663
|
})
|
|
2525
2664
|
};
|
|
2665
|
+
var smExecutionResumeTool = {
|
|
2666
|
+
name: "sm_execution_resume",
|
|
2667
|
+
description: SM_EXECUTION_RESUME_DESCRIPTION,
|
|
2668
|
+
inputSchema: z.object({
|
|
2669
|
+
tabId: z.coerce.number().describe("Tab ID where execution is paused"),
|
|
2670
|
+
action: z.enum(["continue", "retry", "skip_iteration", "skip_scenario", "fail"]).describe("How to proceed after the dialog"),
|
|
2671
|
+
accept: z.boolean().optional().describe("For retry: accept (true) or dismiss (false) the dialog"),
|
|
2672
|
+
prompt_text: z.string().optional().describe("For retry on prompt dialogs: text to enter"),
|
|
2673
|
+
wait_for_completion: z.boolean().optional().default(true).describe("Wait for execution to finish or hit another pause")
|
|
2674
|
+
})
|
|
2675
|
+
};
|
|
2526
2676
|
var smJobReportGetTool = {
|
|
2527
2677
|
name: "sm_job_report_get",
|
|
2528
2678
|
description: SM_JOB_REPORT_GET_DESCRIPTION,
|
|
@@ -2561,7 +2711,15 @@ var smJobSnapshotGetTool = {
|
|
|
2561
2711
|
name: "sm_job_snapshot_get",
|
|
2562
2712
|
description: SM_JOB_SNAPSHOT_GET_DESCRIPTION,
|
|
2563
2713
|
inputSchema: z.object({
|
|
2564
|
-
snapshot_id: z.string().describe("Snapshot ID to retrieve (SNP_xxxx)")
|
|
2714
|
+
snapshot_id: z.string().describe("Snapshot ID to retrieve (SNP_xxxx)"),
|
|
2715
|
+
summary_only: z.boolean().optional().describe("If true, omit data_groups from scenario snapshots to reduce payload")
|
|
2716
|
+
})
|
|
2717
|
+
};
|
|
2718
|
+
var smExecutionStatusTool = {
|
|
2719
|
+
name: "sm_execution_status",
|
|
2720
|
+
description: SM_EXECUTION_STATUS_DESCRIPTION,
|
|
2721
|
+
inputSchema: z.object({
|
|
2722
|
+
tabId: z.coerce.number().describe("Tab ID to check execution status")
|
|
2565
2723
|
})
|
|
2566
2724
|
};
|
|
2567
2725
|
var dataBindingSchema = z.object({
|
|
@@ -2728,12 +2886,15 @@ var allTools = [
|
|
|
2728
2886
|
smJobListTool,
|
|
2729
2887
|
smJobRunTool,
|
|
2730
2888
|
smJobCancelTool,
|
|
2889
|
+
smExecutionResumeTool,
|
|
2731
2890
|
smJobReportGetTool,
|
|
2732
2891
|
smJobReportExportTool,
|
|
2733
2892
|
// Job History (3)
|
|
2734
2893
|
smJobHistoryTool,
|
|
2735
2894
|
smJobCompareTool,
|
|
2736
2895
|
smJobSnapshotGetTool,
|
|
2896
|
+
// Execution Status (1)
|
|
2897
|
+
smExecutionStatusTool,
|
|
2737
2898
|
// Custom View (5)
|
|
2738
2899
|
smCustomViewCreateTool,
|
|
2739
2900
|
smCustomViewUpdateTool,
|
|
@@ -2747,6 +2908,25 @@ var allTools = [
|
|
|
2747
2908
|
sheetsNavigateTool
|
|
2748
2909
|
];
|
|
2749
2910
|
|
|
2911
|
+
// src/tools/timeout.ts
|
|
2912
|
+
var FILE_EXPORT_TOOLS = /* @__PURE__ */ new Set(["sm_report_export", "sm_job_report_export", "sm_export"]);
|
|
2913
|
+
function computeToolTimeout(tool, input) {
|
|
2914
|
+
if (tool === "wait_for" && typeof input.timeout === "number") {
|
|
2915
|
+
return input.timeout + 5e3;
|
|
2916
|
+
}
|
|
2917
|
+
if (FILE_EXPORT_TOOLS.has(tool)) {
|
|
2918
|
+
return 3e5;
|
|
2919
|
+
}
|
|
2920
|
+
if (tool === "sm_scenario_run" && input.wait_for_completion === true) {
|
|
2921
|
+
const maxDuration = typeof input.max_duration_ms === "number" ? input.max_duration_ms : TIMEOUTS.SCENARIO_MAX_DURATION;
|
|
2922
|
+
return maxDuration + TIMEOUTS.MCP_SCENARIO_BUFFER;
|
|
2923
|
+
}
|
|
2924
|
+
if (tool === "sm_execution_resume" && input.wait_for_completion !== false) {
|
|
2925
|
+
return TIMEOUTS.MCP_JOB_WAIT;
|
|
2926
|
+
}
|
|
2927
|
+
return TIMEOUTS.MCP_TOOL;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2750
2930
|
// src/server.ts
|
|
2751
2931
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
2752
2932
|
var extensionSocket = null;
|
|
@@ -2770,7 +2950,6 @@ function coerceShape(shape) {
|
|
|
2770
2950
|
}
|
|
2771
2951
|
return result;
|
|
2772
2952
|
}
|
|
2773
|
-
var FILE_EXPORT_TOOLS = /* @__PURE__ */ new Set(["sm_report_export", "sm_job_report_export", "sm_export"]);
|
|
2774
2953
|
function handleFileExport(filePath, result) {
|
|
2775
2954
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
2776
2955
|
let content;
|
|
@@ -3348,6 +3527,29 @@ function handleExtensionMessage(message) {
|
|
|
3348
3527
|
});
|
|
3349
3528
|
}
|
|
3350
3529
|
}
|
|
3530
|
+
function formatAutoHandledDialogs(result) {
|
|
3531
|
+
const dialogs = result._auto_handled_dialogs;
|
|
3532
|
+
if (!dialogs?.length) return null;
|
|
3533
|
+
const lines = dialogs.map((d) => {
|
|
3534
|
+
const action = d.action === "accept" ? "accepted" : "dismissed";
|
|
3535
|
+
return `- [${d.type}] ${action}: "${d.message}"`;
|
|
3536
|
+
});
|
|
3537
|
+
return [
|
|
3538
|
+
"[Auto-handled dialog] A browser dialog appeared during this operation and was automatically handled:",
|
|
3539
|
+
...lines,
|
|
3540
|
+
"Use handle_dialog with nextPolicy to change how future dialogs are handled."
|
|
3541
|
+
].join("\n");
|
|
3542
|
+
}
|
|
3543
|
+
function formatDialogPaused(result) {
|
|
3544
|
+
if (result.status !== "dialog_paused") return null;
|
|
3545
|
+
const dp = result.dialog_pause;
|
|
3546
|
+
if (!dp) return null;
|
|
3547
|
+
return [
|
|
3548
|
+
`[Execution Paused] A ${dp.dialog_type} dialog appeared during "${dp.step_context}":`,
|
|
3549
|
+
`"${dp.dialog_message}" (auto-${dp.auto_action}ed)`,
|
|
3550
|
+
"Use sm_execution_resume to decide: continue, retry, skip_iteration, skip_scenario, or fail."
|
|
3551
|
+
].join("\n");
|
|
3552
|
+
}
|
|
3351
3553
|
async function callExtensionTool(tool, input) {
|
|
3352
3554
|
if (tool === "browser_health") {
|
|
3353
3555
|
return {
|
|
@@ -3413,10 +3615,7 @@ async function callExtensionTool(tool, input) {
|
|
|
3413
3615
|
const agentId = getDefaultAgentId();
|
|
3414
3616
|
touchSession(agentId);
|
|
3415
3617
|
const sock = extensionSocket;
|
|
3416
|
-
|
|
3417
|
-
if (tool === "wait_for" && typeof input.timeout === "number") {
|
|
3418
|
-
toolTimeout = input.timeout + 5e3;
|
|
3419
|
-
}
|
|
3618
|
+
const toolTimeout = computeToolTimeout(tool, input);
|
|
3420
3619
|
return new Promise((resolve2) => {
|
|
3421
3620
|
const onError = () => {
|
|
3422
3621
|
const pending = pendingRequests.get(requestId);
|
|
@@ -3486,19 +3685,25 @@ async function callExtensionTool(tool, input) {
|
|
|
3486
3685
|
}
|
|
3487
3686
|
return;
|
|
3488
3687
|
}
|
|
3688
|
+
const dialogNote = formatAutoHandledDialogs(result);
|
|
3689
|
+
const pauseNote = formatDialogPaused(result);
|
|
3489
3690
|
if (tool === "screenshot" && typeof result.data === "string") {
|
|
3490
3691
|
const { data, ...metadata } = result;
|
|
3491
3692
|
const mimeType = metadata.format === "png" ? "image/png" : "image/jpeg";
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
});
|
|
3693
|
+
const content = [
|
|
3694
|
+
{ type: "image", data, mimeType },
|
|
3695
|
+
{ type: "text", text: JSON.stringify(metadata) }
|
|
3696
|
+
];
|
|
3697
|
+
if (dialogNote) content.push({ type: "text", text: dialogNote });
|
|
3698
|
+
if (pauseNote) content.push({ type: "text", text: pauseNote });
|
|
3699
|
+
resolve2({ content });
|
|
3498
3700
|
} else {
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3701
|
+
const content = [
|
|
3702
|
+
{ type: "text", text: JSON.stringify(result) }
|
|
3703
|
+
];
|
|
3704
|
+
if (dialogNote) content.push({ type: "text", text: dialogNote });
|
|
3705
|
+
if (pauseNote) content.push({ type: "text", text: pauseNote });
|
|
3706
|
+
resolve2({ content });
|
|
3502
3707
|
}
|
|
3503
3708
|
},
|
|
3504
3709
|
reject: (error) => {
|