@elizaos/plugin-browser 2.0.0-beta.1 → 2.0.3-beta.3

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 (196) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -64
  3. package/dist/actions/browser-autofill-login.d.ts.map +1 -1
  4. package/dist/actions/browser-autofill-login.js.map +1 -1
  5. package/dist/actions/browser.d.ts +5 -6
  6. package/dist/actions/browser.d.ts.map +1 -1
  7. package/dist/actions/browser.js +312 -60
  8. package/dist/actions/browser.js.map +1 -1
  9. package/dist/actions/manage-browser-bridge.d.ts.map +1 -1
  10. package/dist/actions/manage-browser-bridge.js +10 -14
  11. package/dist/actions/manage-browser-bridge.js.map +1 -1
  12. package/dist/actions/wait-for-url-predicate.d.ts +34 -0
  13. package/dist/actions/wait-for-url-predicate.d.ts.map +1 -0
  14. package/dist/actions/wait-for-url-predicate.js +33 -0
  15. package/dist/actions/wait-for-url-predicate.js.map +1 -0
  16. package/dist/actions/wait-for-url.d.ts +64 -0
  17. package/dist/actions/wait-for-url.d.ts.map +1 -0
  18. package/dist/actions/wait-for-url.js +89 -0
  19. package/dist/actions/wait-for-url.js.map +1 -0
  20. package/dist/bridge-policy.d.ts +10 -0
  21. package/dist/bridge-policy.d.ts.map +1 -0
  22. package/dist/bridge-policy.js +37 -0
  23. package/dist/bridge-policy.js.map +1 -0
  24. package/dist/bridge-readiness.d.ts +16 -0
  25. package/dist/bridge-readiness.d.ts.map +1 -0
  26. package/dist/bridge-readiness.js +82 -0
  27. package/dist/bridge-readiness.js.map +1 -0
  28. package/dist/bridge-records.d.ts +9 -0
  29. package/dist/bridge-records.d.ts.map +1 -0
  30. package/dist/bridge-records.js +37 -0
  31. package/dist/bridge-records.js.map +1 -0
  32. package/dist/browser-capture-hooks.d.ts +9 -0
  33. package/dist/browser-capture-hooks.d.ts.map +1 -0
  34. package/dist/browser-capture-hooks.js +15 -0
  35. package/dist/browser-capture-hooks.js.map +1 -0
  36. package/dist/browser-service.d.ts +22 -4
  37. package/dist/browser-service.d.ts.map +1 -1
  38. package/dist/browser-service.js +63 -15
  39. package/dist/browser-service.js.map +1 -1
  40. package/dist/browser-workspace-hooks.d.ts +14 -0
  41. package/dist/browser-workspace-hooks.d.ts.map +1 -0
  42. package/dist/browser-workspace-hooks.js +15 -0
  43. package/dist/browser-workspace-hooks.js.map +1 -0
  44. package/dist/companion-auth.d.ts +34 -0
  45. package/dist/companion-auth.d.ts.map +1 -0
  46. package/dist/companion-auth.js +98 -0
  47. package/dist/companion-auth.js.map +1 -0
  48. package/dist/index.d.ts +12 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +66 -12
  51. package/dist/index.js.map +1 -1
  52. package/dist/message-adapter.d.ts +9 -0
  53. package/dist/message-adapter.d.ts.map +1 -0
  54. package/dist/message-adapter.js +104 -0
  55. package/dist/message-adapter.js.map +1 -0
  56. package/dist/packaging.d.ts.map +1 -1
  57. package/dist/packaging.js +2 -0
  58. package/dist/packaging.js.map +1 -1
  59. package/dist/parity/browser-matrix.d.ts +45 -0
  60. package/dist/parity/browser-matrix.d.ts.map +1 -0
  61. package/dist/parity/browser-matrix.js +361 -0
  62. package/dist/parity/browser-matrix.js.map +1 -0
  63. package/dist/parity/index.d.ts +5 -0
  64. package/dist/parity/index.d.ts.map +1 -0
  65. package/dist/parity/index.js +13 -0
  66. package/dist/parity/index.js.map +1 -0
  67. package/dist/password-manager-bridge.d.ts +50 -0
  68. package/dist/password-manager-bridge.d.ts.map +1 -0
  69. package/dist/password-manager-bridge.js +437 -0
  70. package/dist/password-manager-bridge.js.map +1 -0
  71. package/dist/plugin.d.ts.map +1 -1
  72. package/dist/plugin.js +8 -4
  73. package/dist/plugin.js.map +1 -1
  74. package/dist/providers/workspace.d.ts +1 -1
  75. package/dist/providers/workspace.js.map +1 -1
  76. package/dist/routes/bridge.d.ts.map +1 -1
  77. package/dist/routes/bridge.js +63 -14
  78. package/dist/routes/bridge.js.map +1 -1
  79. package/dist/routes/workspace-setup.d.ts.map +1 -1
  80. package/dist/routes/workspace-setup.js +1 -1
  81. package/dist/routes/workspace-setup.js.map +1 -1
  82. package/dist/routes/workspace.d.ts +1 -2
  83. package/dist/routes/workspace.d.ts.map +1 -1
  84. package/dist/routes/workspace.js +104 -4
  85. package/dist/routes/workspace.js.map +1 -1
  86. package/dist/schema.d.ts +2 -2
  87. package/dist/schema.js.map +1 -1
  88. package/dist/service.d.ts +1 -1
  89. package/dist/service.d.ts.map +1 -1
  90. package/dist/service.js.map +1 -1
  91. package/dist/targets/bridge-target.d.ts +1 -1
  92. package/dist/targets/bridge-target.d.ts.map +1 -1
  93. package/dist/targets/bridge-target.js.map +1 -1
  94. package/dist/targets/stagehand-target.d.ts +3 -0
  95. package/dist/targets/stagehand-target.d.ts.map +1 -0
  96. package/dist/targets/stagehand-target.js +187 -0
  97. package/dist/targets/stagehand-target.js.map +1 -0
  98. package/dist/workspace/browser-capture.d.ts +1 -1
  99. package/dist/workspace/browser-capture.d.ts.map +1 -1
  100. package/dist/workspace/browser-capture.js +33 -1
  101. package/dist/workspace/browser-capture.js.map +1 -1
  102. package/dist/workspace/browser-workspace-desktop.d.ts +1 -1
  103. package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -1
  104. package/dist/workspace/browser-workspace-desktop.js +66 -30
  105. package/dist/workspace/browser-workspace-desktop.js.map +1 -1
  106. package/dist/workspace/browser-workspace-errors.d.ts +62 -0
  107. package/dist/workspace/browser-workspace-errors.d.ts.map +1 -0
  108. package/dist/workspace/browser-workspace-errors.js +69 -0
  109. package/dist/workspace/browser-workspace-errors.js.map +1 -0
  110. package/dist/workspace/browser-workspace-forms.d.ts.map +1 -1
  111. package/dist/workspace/browser-workspace-forms.js +1 -1
  112. package/dist/workspace/browser-workspace-forms.js.map +1 -1
  113. package/dist/workspace/browser-workspace-helpers.d.ts +7 -0
  114. package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -1
  115. package/dist/workspace/browser-workspace-helpers.js +64 -6
  116. package/dist/workspace/browser-workspace-helpers.js.map +1 -1
  117. package/dist/workspace/browser-workspace-network.d.ts +1 -1
  118. package/dist/workspace/browser-workspace-network.d.ts.map +1 -1
  119. package/dist/workspace/browser-workspace-types.d.ts +15 -0
  120. package/dist/workspace/browser-workspace-types.d.ts.map +1 -1
  121. package/dist/workspace/browser-workspace-types.js.map +1 -1
  122. package/dist/workspace/browser-workspace-web.d.ts.map +1 -1
  123. package/dist/workspace/browser-workspace-web.js +34 -93
  124. package/dist/workspace/browser-workspace-web.js.map +1 -1
  125. package/dist/workspace/browser-workspace.d.ts +1 -1
  126. package/dist/workspace/browser-workspace.d.ts.map +1 -1
  127. package/dist/workspace/browser-workspace.js +9 -4
  128. package/dist/workspace/browser-workspace.js.map +1 -1
  129. package/dist/workspace/index.d.ts +1 -0
  130. package/dist/workspace/index.d.ts.map +1 -1
  131. package/dist/workspace/index.js +1 -0
  132. package/dist/workspace/index.js.map +1 -1
  133. package/package.json +29 -7
  134. package/registry-entry.json +75 -0
  135. package/dist/actions/browser-autofill-login.d.js +0 -1
  136. package/dist/actions/browser-autofill-login.d.js.map +0 -1
  137. package/dist/actions/browser.d.js +0 -1
  138. package/dist/actions/browser.d.js.map +0 -1
  139. package/dist/actions/manage-browser-bridge.d.js +0 -1
  140. package/dist/actions/manage-browser-bridge.d.js.map +0 -1
  141. package/dist/ambient-jsdom.d.js +0 -1
  142. package/dist/ambient-jsdom.d.js.map +0 -1
  143. package/dist/browser-service.d.js +0 -1
  144. package/dist/browser-service.d.js.map +0 -1
  145. package/dist/contracts.d.js +0 -1
  146. package/dist/contracts.d.js.map +0 -1
  147. package/dist/index.d.js +0 -21
  148. package/dist/index.d.js.map +0 -1
  149. package/dist/lifeops-session-contracts.d.js +0 -1
  150. package/dist/lifeops-session-contracts.d.js.map +0 -1
  151. package/dist/packaging.d.js +0 -1
  152. package/dist/packaging.d.js.map +0 -1
  153. package/dist/plugin.d.js +0 -1
  154. package/dist/plugin.d.js.map +0 -1
  155. package/dist/providers/workspace.d.js +0 -1
  156. package/dist/providers/workspace.d.js.map +0 -1
  157. package/dist/routes/bridge.d.js +0 -1
  158. package/dist/routes/bridge.d.js.map +0 -1
  159. package/dist/routes/workspace-account-gate.d.js +0 -1
  160. package/dist/routes/workspace-account-gate.d.js.map +0 -1
  161. package/dist/routes/workspace-setup.d.js +0 -1
  162. package/dist/routes/workspace-setup.d.js.map +0 -1
  163. package/dist/routes/workspace.d.js +0 -1
  164. package/dist/routes/workspace.d.js.map +0 -1
  165. package/dist/schema.d.js +0 -1
  166. package/dist/schema.d.js.map +0 -1
  167. package/dist/service.d.js +0 -1
  168. package/dist/service.d.js.map +0 -1
  169. package/dist/targets/bridge-target.d.js +0 -1
  170. package/dist/targets/bridge-target.d.js.map +0 -1
  171. package/dist/workspace/browser-capture.d.js +0 -1
  172. package/dist/workspace/browser-capture.d.js.map +0 -1
  173. package/dist/workspace/browser-workspace-desktop.d.js +0 -1
  174. package/dist/workspace/browser-workspace-desktop.d.js.map +0 -1
  175. package/dist/workspace/browser-workspace-elements.d.js +0 -1
  176. package/dist/workspace/browser-workspace-elements.d.js.map +0 -1
  177. package/dist/workspace/browser-workspace-forms.d.js +0 -1
  178. package/dist/workspace/browser-workspace-forms.d.js.map +0 -1
  179. package/dist/workspace/browser-workspace-helpers.d.js +0 -1
  180. package/dist/workspace/browser-workspace-helpers.d.js.map +0 -1
  181. package/dist/workspace/browser-workspace-jsdom.d.js +0 -1
  182. package/dist/workspace/browser-workspace-jsdom.d.js.map +0 -1
  183. package/dist/workspace/browser-workspace-network.d.js +0 -1
  184. package/dist/workspace/browser-workspace-network.d.js.map +0 -1
  185. package/dist/workspace/browser-workspace-snapshots.d.js +0 -1
  186. package/dist/workspace/browser-workspace-snapshots.d.js.map +0 -1
  187. package/dist/workspace/browser-workspace-state.d.js +0 -1
  188. package/dist/workspace/browser-workspace-state.d.js.map +0 -1
  189. package/dist/workspace/browser-workspace-types.d.js +0 -1
  190. package/dist/workspace/browser-workspace-types.d.js.map +0 -1
  191. package/dist/workspace/browser-workspace-web.d.js +0 -1
  192. package/dist/workspace/browser-workspace-web.d.js.map +0 -1
  193. package/dist/workspace/browser-workspace.d.js +0 -11
  194. package/dist/workspace/browser-workspace.d.js.map +0 -1
  195. package/dist/workspace/index.d.js +0 -3
  196. package/dist/workspace/index.d.js.map +0 -1
@@ -2,11 +2,15 @@ import { logger } from "@elizaos/core";
2
2
  import {
3
3
  BROWSER_SERVICE_TYPE
4
4
  } from "../browser-service.js";
5
- import { executeBrowserAutofillLogin } from "./browser-autofill-login.js";
6
5
  import {
7
6
  executeBrowserWorkspaceCommand,
8
7
  getBrowserWorkspaceMode
9
8
  } from "../workspace/browser-workspace.js";
9
+ import {
10
+ WAIT_FOR_URL_DEFAULT_POLL_INTERVAL_MS,
11
+ WAIT_FOR_URL_DEFAULT_TIMEOUT_MS,
12
+ waitForUrl
13
+ } from "./wait-for-url.js";
10
14
  function getMessageText(message) {
11
15
  const content = message?.content;
12
16
  if (typeof content === "string") {
@@ -19,10 +23,14 @@ function extractFirstUrl(value) {
19
23
  return match?.[0] ?? null;
20
24
  }
21
25
  function inferBrowserSubaction(params, messageText) {
22
- if (params?.action === "autofill-login" || params?.subaction === "autofill-login") {
26
+ const normalizedAction = normalizeBrowserAction(params?.action);
27
+ if (normalizedAction === "autofill-login" || params?.subaction === "autofill-login") {
23
28
  return "autofill-login";
24
29
  }
25
- const legacySubaction = normalizeLegacyBrowserAction(params?.action);
30
+ if (normalizedAction === "wait-for-url" || params?.subaction === "wait-for-url") {
31
+ return "wait-for-url";
32
+ }
33
+ const legacySubaction = normalizeLegacyBrowserAction(normalizedAction);
26
34
  if (legacySubaction) {
27
35
  return legacySubaction;
28
36
  }
@@ -44,8 +52,32 @@ function inferBrowserSubaction(params, messageText) {
44
52
  }
45
53
  return "state";
46
54
  }
47
- function normalizeLegacyBrowserAction(action) {
55
+ function normalizeBrowserAction(action) {
48
56
  switch (action) {
57
+ case "realistic_click":
58
+ return "realistic-click";
59
+ case "realistic_fill":
60
+ return "realistic-fill";
61
+ case "realistic_type":
62
+ return "realistic-type";
63
+ case "realistic_press":
64
+ return "realistic-press";
65
+ case "cursor_move":
66
+ return "cursor-move";
67
+ case "cursor_hide":
68
+ return "cursor-hide";
69
+ case "autofill_login":
70
+ return "autofill-login";
71
+ case "wait_for_url":
72
+ case "wait-for-url":
73
+ return "wait-for-url";
74
+ default:
75
+ return action;
76
+ }
77
+ }
78
+ function normalizeLegacyBrowserAction(action) {
79
+ const normalizedAction = normalizeBrowserAction(action);
80
+ switch (normalizedAction) {
49
81
  case "info":
50
82
  case "context":
51
83
  case "get_context":
@@ -56,15 +88,19 @@ function normalizeLegacyBrowserAction(action) {
56
88
  case "switch_tab":
57
89
  return "tab";
58
90
  case "autofill-login":
91
+ case "wait-for-url":
59
92
  return void 0;
60
93
  case void 0:
61
94
  return void 0;
62
95
  default:
63
- return action;
96
+ return isWorkspaceSubaction(normalizedAction) ? normalizedAction : void 0;
64
97
  }
65
98
  }
99
+ function isWorkspaceSubaction(action) {
100
+ return action === "back" || action === "click" || action === "close" || action === "forward" || action === "get" || action === "hide" || action === "navigate" || action === "open" || action === "press" || action === "reload" || action === "screenshot" || action === "show" || action === "snapshot" || action === "state" || action === "tab" || action === "type" || action === "wait" || action === "realistic-click" || action === "realistic-fill" || action === "realistic-type" || action === "realistic-press" || action === "cursor-move" || action === "cursor-hide";
101
+ }
66
102
  function normalizeLegacyTabAction(action) {
67
- switch (action) {
103
+ switch (normalizeBrowserAction(action)) {
68
104
  case "list_tabs":
69
105
  return "list";
70
106
  case "open_tab":
@@ -105,6 +141,193 @@ ${serialized}`;
105
141
  }
106
142
  return `Browser ${command.subaction} completed in ${result.mode} mode.`;
107
143
  }
144
+ function browserProgressRationale(command, params, messageText) {
145
+ const explicit = params?.rationale?.trim();
146
+ if (explicit) return explicit;
147
+ switch (command.subaction) {
148
+ case "open":
149
+ case "navigate":
150
+ return command.url ? `open ${command.url}` : "open requested page";
151
+ case "click":
152
+ case "realistic-click":
153
+ return command.selector ? `click ${command.selector}` : "click requested target";
154
+ case "type":
155
+ case "realistic-fill":
156
+ case "realistic-type":
157
+ return command.selector ? `fill ${command.selector}` : "type requested text";
158
+ case "press":
159
+ case "realistic-press":
160
+ return command.key ? `press ${command.key}` : "press requested key";
161
+ case "tab":
162
+ return command.tabAction ? `${command.tabAction} browser tab` : "manage browser tabs";
163
+ case "wait":
164
+ return command.selector ? `wait for ${command.selector}` : "wait for browser state";
165
+ case "state":
166
+ return messageText.trim() || "read browser state";
167
+ default:
168
+ return `run browser ${command.subaction}`;
169
+ }
170
+ }
171
+ function buildBrowserStepProgressContent(command, params, messageText, success, error) {
172
+ const rationale = error ? `failed: ${error}` : browserProgressRationale(command, params, messageText);
173
+ return {
174
+ text: `Step 1: ${command.subaction} \u2014 ${rationale}`,
175
+ source: "action_progress",
176
+ merge: "replace",
177
+ metadata: {
178
+ transient: true,
179
+ compactProgress: true,
180
+ progress: {
181
+ source: "browser",
182
+ actionName: "BROWSER",
183
+ step: 1,
184
+ kind: command.subaction,
185
+ rationale,
186
+ success,
187
+ error
188
+ }
189
+ }
190
+ };
191
+ }
192
+ async function emitBrowserStepProgress(callback, command, params, messageText, success, error) {
193
+ if (params?.streamProgress !== true || !callback) return;
194
+ try {
195
+ await callback(
196
+ buildBrowserStepProgressContent(
197
+ command,
198
+ params,
199
+ messageText,
200
+ success,
201
+ error
202
+ ),
203
+ "BROWSER"
204
+ );
205
+ } catch (callbackError) {
206
+ logger.warn(
207
+ {
208
+ src: "plugin:browser",
209
+ action: command.subaction,
210
+ error: callbackError instanceof Error ? callbackError.message : String(callbackError)
211
+ },
212
+ "Failed to emit browser progress callback"
213
+ );
214
+ }
215
+ }
216
+ function currentUrlFromResult(result) {
217
+ if (result.tab?.url) {
218
+ return result.tab.url;
219
+ }
220
+ if (typeof result.value === "string" && result.value.trim()) {
221
+ return result.value.trim();
222
+ }
223
+ if (Array.isArray(result.tabs)) {
224
+ const visible = result.tabs.find((tab) => tab.visible) ?? result.tabs[0];
225
+ if (visible?.url) {
226
+ return visible.url;
227
+ }
228
+ }
229
+ return null;
230
+ }
231
+ async function readCurrentBrowserUrl(browserService, target, tabId) {
232
+ const run = async (command) => browserService ? browserService.execute(command, target) : executeBrowserWorkspaceCommand(command);
233
+ try {
234
+ const got = await run({
235
+ subaction: "get",
236
+ getMode: "url",
237
+ id: tabId
238
+ });
239
+ const url = currentUrlFromResult(got);
240
+ if (url) {
241
+ return url;
242
+ }
243
+ } catch (error) {
244
+ logger.debug(
245
+ `[BROWSER] wait_for_url get-url poll failed, falling back to state: ${error instanceof Error ? error.message : String(error)}`
246
+ );
247
+ }
248
+ try {
249
+ const state = await run({ subaction: "state", id: tabId });
250
+ return currentUrlFromResult(state);
251
+ } catch (error) {
252
+ logger.debug(
253
+ `[BROWSER] wait_for_url state poll could not read URL: ${error instanceof Error ? error.message : String(error)}`
254
+ );
255
+ return null;
256
+ }
257
+ }
258
+ async function executeBrowserWaitForUrl(runtime, params, messageText, callback) {
259
+ const pattern = (params?.pattern ?? "").trim();
260
+ if (!pattern) {
261
+ const text = "wait_for_url needs a `pattern` (substring or regex) to watch for.";
262
+ logger.warn(`[BROWSER] ${text}`);
263
+ return {
264
+ text,
265
+ success: false,
266
+ values: { success: false, error: "BROWSER_WAIT_FOR_URL_NO_PATTERN" },
267
+ data: { actionName: "BROWSER", subaction: "wait_for_url" }
268
+ };
269
+ }
270
+ const browserService = runtime.getService(BROWSER_SERVICE_TYPE) ?? null;
271
+ const target = params?.target;
272
+ const startUrl = params?.url?.trim() || extractFirstUrl(messageText) || void 0;
273
+ const timeoutMs = params?.timeoutMs ?? WAIT_FOR_URL_DEFAULT_TIMEOUT_MS;
274
+ const pollIntervalMs = params?.pollIntervalMs ?? WAIT_FOR_URL_DEFAULT_POLL_INTERVAL_MS;
275
+ let tabId = params?.id?.trim() || void 0;
276
+ if (startUrl) {
277
+ const openCommand = {
278
+ subaction: tabId ? "navigate" : "open",
279
+ url: startUrl,
280
+ id: tabId
281
+ };
282
+ try {
283
+ const opened = browserService ? await browserService.execute(openCommand, target) : await executeBrowserWorkspaceCommand(openCommand);
284
+ tabId = opened.tab?.id ?? tabId;
285
+ } catch (error) {
286
+ const reason = error instanceof Error ? error.message : String(error);
287
+ logger.warn(
288
+ `[BROWSER] wait_for_url could not open ${startUrl}: ${reason}`
289
+ );
290
+ return {
291
+ text: `Couldn't open ${startUrl} to watch for "${pattern}": ${reason}`,
292
+ success: false,
293
+ values: { success: false, error: "BROWSER_WAIT_FOR_URL_OPEN_FAILED" },
294
+ data: { actionName: "BROWSER", subaction: "wait_for_url" }
295
+ };
296
+ }
297
+ }
298
+ await callback?.({
299
+ text: startUrl ? `I opened ${startUrl} \u2014 watching for "${pattern}" and I'll resume when it's reached.` : `Watching the current tab for "${pattern}" \u2014 I'll resume when it's reached.`
300
+ });
301
+ logger.info(
302
+ `[BROWSER] wait_for_url pattern="${pattern}" timeoutMs=${timeoutMs} pollIntervalMs=${pollIntervalMs} target=${target ?? "auto"}`
303
+ );
304
+ const outcome = await waitForUrl(
305
+ { pattern, timeoutMs, pollIntervalMs },
306
+ {
307
+ getCurrentUrl: () => readCurrentBrowserUrl(browserService, target, tabId),
308
+ emitStatus: async (text) => {
309
+ await callback?.({ text });
310
+ }
311
+ }
312
+ );
313
+ return {
314
+ text: outcome.message,
315
+ success: outcome.matched,
316
+ userFacingText: outcome.message,
317
+ values: {
318
+ success: outcome.matched,
319
+ subaction: "wait_for_url",
320
+ status: outcome.status,
321
+ matched: outcome.matched,
322
+ polls: outcome.polls
323
+ },
324
+ data: {
325
+ actionName: "BROWSER",
326
+ subaction: "wait_for_url",
327
+ outcome
328
+ }
329
+ };
330
+ }
108
331
  const browserAction = {
109
332
  name: "BROWSER",
110
333
  contexts: ["browser", "web", "automation", "secrets"],
@@ -115,7 +338,6 @@ const browserAction = {
115
338
  "CONTROL_BROWSER",
116
339
  "CONTROL_BROWSER_SESSION",
117
340
  "MANAGE_ELIZA_BROWSER_WORKSPACE",
118
- "MANAGE_LIFEOPS_BROWSER",
119
341
  "NAVIGATE_SITE",
120
342
  "OPEN_SITE",
121
343
  "USE_BROWSER",
@@ -128,16 +350,20 @@ const browserAction = {
128
350
  "LOG_INTO_SITE",
129
351
  "SIGN_IN_TO_SITE"
130
352
  ],
131
- description: "Single BROWSER action \u2014 control whichever browser target is registered. Targets are pluggable: `workspace` (electrobun-embedded BrowserView, the default; falls back to a JSDOM web mode when the desktop bridge isn't configured), `bridge` (the user's real Chrome/Safari via the Agent Browser Bridge companion extension), and `computeruse` (a local puppeteer-driven Chromium via plugin-computeruse). The agent uses what is available \u2014 the BrowserService picks the active target when none is specified. Use `subaction: \"autofill-login\"` with `domain` (and optional `username`, `submit`) to vault-gated autofill into an open workspace tab.",
132
- descriptionCompressed: "Browser tab/page control: open/navigate/click/type/screenshot/state; subaction autofill-login + domain autofill vault-gated credential into workspace tab pre-authorized in Settings Vault Logins. Bridge settings/status use MANAGE_BROWSER_BRIDGE.",
353
+ description: "BROWSER action. Control registered browser target: app workspace, bridge Chrome/Safari companion, computeruse Chromium, or Stagehand fallback. BrowserService picks target if omitted. action=autofill_login + domain vault-gated autofills open workspace tab. action=wait_for_url + pattern opens an optional url then watches the tab and resumes when its URL matches (OAuth callback, deploy/CI done), streaming progress.",
354
+ descriptionCompressed: "Browser open|navigate|click|type|screenshot|state|autofill_login|wait_for_url; bridge status elsewhere",
133
355
  validate: async () => true,
134
- handler: async (runtime, message, _state, options) => {
356
+ handler: async (runtime, message, _state, options, callback) => {
135
357
  const params = options?.parameters;
136
358
  const messageText = getMessageText(message);
137
359
  const subaction = inferBrowserSubaction(params, messageText);
138
360
  if (subaction === "autofill-login") {
361
+ const { executeBrowserAutofillLogin } = await import("./browser-autofill-login.js");
139
362
  return executeBrowserAutofillLogin(runtime, message, options);
140
363
  }
364
+ if (subaction === "wait-for-url") {
365
+ return executeBrowserWaitForUrl(runtime, params, messageText, callback);
366
+ }
141
367
  const url = params?.url?.trim() || extractFirstUrl(messageText) || void 0;
142
368
  const command = {
143
369
  id: params?.id?.trim(),
@@ -148,6 +374,7 @@ const browserAction = {
148
374
  subaction,
149
375
  tabAction: params?.tabAction ?? normalizeLegacyTabAction(params?.action),
150
376
  text: params?.text,
377
+ value: params?.text,
151
378
  timeoutMs: params?.timeoutMs,
152
379
  url,
153
380
  cursorDurationMs: params?.cursorDurationMs,
@@ -156,14 +383,19 @@ const browserAction = {
156
383
  x: params?.x,
157
384
  y: params?.y
158
385
  };
159
- const browserService = runtime.getService(
160
- BROWSER_SERVICE_TYPE
161
- );
386
+ const browserService = runtime.getService(BROWSER_SERVICE_TYPE);
162
387
  try {
163
388
  logger.info(
164
389
  `[BROWSER] ${command.subaction} via target=${params?.target ?? "auto"} (workspace mode=${getBrowserWorkspaceMode(process.env)})`
165
390
  );
166
391
  const result = browserService ? await browserService.execute(command, params?.target) : await executeBrowserWorkspaceCommand(command);
392
+ await emitBrowserStepProgress(
393
+ callback,
394
+ command,
395
+ params,
396
+ messageText,
397
+ true
398
+ );
167
399
  return {
168
400
  text: formatBrowserSessionResult(command, result),
169
401
  success: true,
@@ -179,10 +411,18 @@ const browserAction = {
179
411
  }
180
412
  };
181
413
  } catch (error) {
182
- const messageText2 = error instanceof Error ? error.message : "Browser action failed";
183
- logger.warn(`[BROWSER] Failed: ${messageText2}`);
414
+ const errorText = error instanceof Error ? error.message : "Browser action failed";
415
+ logger.warn(`[BROWSER] Failed: ${errorText}`);
416
+ await emitBrowserStepProgress(
417
+ callback,
418
+ command,
419
+ params,
420
+ messageText,
421
+ false,
422
+ errorText
423
+ );
184
424
  return {
185
- text: `Browser action failed: ${messageText2}`,
425
+ text: `Browser action failed: ${errorText}`,
186
426
  success: false,
187
427
  values: { success: false, error: "BROWSER_FAILED" },
188
428
  data: {
@@ -193,9 +433,27 @@ const browserAction = {
193
433
  }
194
434
  },
195
435
  parameters: [
436
+ {
437
+ name: "target",
438
+ description: "Optional browser target id. Common values: workspace, bridge, computeruse, stagehand.",
439
+ required: false,
440
+ schema: { type: "string" }
441
+ },
442
+ {
443
+ name: "streamProgress",
444
+ description: "When true, emit a compact Step 1 progress callback after the browser command dispatches.",
445
+ required: false,
446
+ schema: { type: "boolean", default: false }
447
+ },
448
+ {
449
+ name: "rationale",
450
+ description: "Optional rationale shown in streamProgress callback text.",
451
+ required: false,
452
+ schema: { type: "string" }
453
+ },
196
454
  {
197
455
  name: "action",
198
- description: "Browser action to perform. Legacy subaction is also accepted.",
456
+ description: "Browser action. Snake_case canonical; legacy kebab-case and subaction accepted.",
199
457
  required: false,
200
458
  schema: {
201
459
  type: "string",
@@ -224,49 +482,28 @@ const browserAction = {
224
482
  "wait",
225
483
  "close_tab",
226
484
  "switch_tab",
227
- "realistic-click",
228
- "realistic-fill",
229
- "realistic-type",
230
- "realistic-press",
231
- "cursor-move",
232
- "cursor-hide",
233
- "autofill-login"
485
+ "realistic_click",
486
+ "realistic_fill",
487
+ "realistic_type",
488
+ "realistic_press",
489
+ "cursor_move",
490
+ "cursor_hide",
491
+ "autofill_login",
492
+ "wait_for_url"
234
493
  ]
235
494
  }
236
495
  },
237
496
  {
238
- name: "subaction",
239
- description: "Legacy alias for action.",
497
+ name: "pattern",
498
+ description: "For action=wait_for_url: substring or /regex/ to match the tab URL (e.g. callback?code=, or /\\/done$/).",
240
499
  required: false,
241
- schema: {
242
- type: "string",
243
- enum: [
244
- "back",
245
- "click",
246
- "close",
247
- "forward",
248
- "get",
249
- "hide",
250
- "navigate",
251
- "open",
252
- "press",
253
- "reload",
254
- "screenshot",
255
- "show",
256
- "snapshot",
257
- "state",
258
- "tab",
259
- "type",
260
- "wait",
261
- "realistic-click",
262
- "realistic-fill",
263
- "realistic-type",
264
- "realistic-press",
265
- "cursor-move",
266
- "cursor-hide",
267
- "autofill-login"
268
- ]
269
- }
500
+ schema: { type: "string" }
501
+ },
502
+ {
503
+ name: "pollIntervalMs",
504
+ description: "For action=wait_for_url: poll cadence in ms. Default 2000.",
505
+ required: false,
506
+ schema: { type: "number" }
270
507
  },
271
508
  {
272
509
  name: "tabAction",
@@ -279,19 +516,19 @@ const browserAction = {
279
516
  },
280
517
  {
281
518
  name: "domain",
282
- description: "Required when subaction is autofill-login: registrable hostname (e.g. `github.com`).",
519
+ description: "Required for action=autofill_login: registrable hostname, e.g. github.com.",
283
520
  required: false,
284
521
  schema: { type: "string" }
285
522
  },
286
523
  {
287
524
  name: "username",
288
- description: "When using autofill-login: specific saved login; omit for most recently modified.",
525
+ description: "For autofill-login: saved login username; omit for latest.",
289
526
  required: false,
290
527
  schema: { type: "string" }
291
528
  },
292
529
  {
293
530
  name: "submit",
294
- description: "When using autofill-login: submit the form after filling (default false).",
531
+ description: "For autofill-login: submit after filling. Default false.",
295
532
  required: false,
296
533
  schema: { type: "boolean" }
297
534
  },
@@ -345,7 +582,7 @@ const browserAction = {
345
582
  },
346
583
  {
347
584
  name: "watchMode",
348
- description: "Hint that the user is watching; prefers realistic-* subactions for click/fill so the cursor moves visibly and pointer events fire faithfully.",
585
+ description: "User watching hint; prefer realistic-* click/fill, visible cursor, pointer events.",
349
586
  required: false,
350
587
  schema: { type: "boolean" }
351
588
  },
@@ -363,7 +600,7 @@ const browserAction = {
363
600
  },
364
601
  {
365
602
  name: "replace",
366
- description: "Replace existing input value when filling (vs append) \u2014 applies to realistic-fill",
603
+ description: "For realistic-fill: replace existing input, not append.",
367
604
  required: false,
368
605
  schema: { type: "boolean" }
369
606
  },
@@ -408,6 +645,21 @@ const browserAction = {
408
645
  text: "click completed in desktop mode."
409
646
  }
410
647
  }
648
+ ],
649
+ [
650
+ {
651
+ name: "{{name1}}",
652
+ content: {
653
+ text: "Open the GitHub OAuth page and let me know when it redirects back to our callback."
654
+ }
655
+ },
656
+ {
657
+ name: "{{agentName}}",
658
+ content: {
659
+ text: `I opened https://github.com/login/oauth/authorize \u2014 watching for "callback?code=" and I'll resume when it's reached.`,
660
+ actions: ["BROWSER"]
661
+ }
662
+ }
411
663
  ]
412
664
  ]
413
665
  };