@mercuryo-ai/agentbrowse 0.2.60 → 0.2.61

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 (46) hide show
  1. package/README.md +30 -5
  2. package/dist/browser-session-state.d.ts +39 -0
  3. package/dist/browser-session-state.d.ts.map +1 -1
  4. package/dist/browser-session-state.js +63 -1
  5. package/dist/commands/act.d.ts.map +1 -1
  6. package/dist/commands/act.js +539 -535
  7. package/dist/commands/attach.d.ts.map +1 -1
  8. package/dist/commands/attach.js +5 -10
  9. package/dist/commands/browser-connection-failure.d.ts +9 -0
  10. package/dist/commands/browser-connection-failure.d.ts.map +1 -0
  11. package/dist/commands/browser-connection-failure.js +15 -0
  12. package/dist/commands/browser-status.d.ts.map +1 -1
  13. package/dist/commands/browser-status.js +26 -30
  14. package/dist/commands/close.d.ts.map +1 -1
  15. package/dist/commands/close.js +5 -0
  16. package/dist/commands/extract.d.ts.map +1 -1
  17. package/dist/commands/extract.js +147 -144
  18. package/dist/commands/launch.d.ts.map +1 -1
  19. package/dist/commands/launch.js +11 -8
  20. package/dist/commands/navigate.d.ts.map +1 -1
  21. package/dist/commands/navigate.js +79 -73
  22. package/dist/commands/observe-inventory.d.ts +1 -0
  23. package/dist/commands/observe-inventory.d.ts.map +1 -1
  24. package/dist/commands/observe-inventory.js +15 -3
  25. package/dist/commands/observe.d.ts.map +1 -1
  26. package/dist/commands/observe.js +260 -272
  27. package/dist/commands/screenshot.d.ts.map +1 -1
  28. package/dist/commands/screenshot.js +50 -64
  29. package/dist/library.d.ts +2 -1
  30. package/dist/library.d.ts.map +1 -1
  31. package/dist/library.js +2 -1
  32. package/dist/protected-fill.d.ts.map +1 -1
  33. package/dist/protected-fill.js +46 -7
  34. package/dist/sticky-owner-host-entry.d.ts +2 -0
  35. package/dist/sticky-owner-host-entry.d.ts.map +1 -0
  36. package/dist/sticky-owner-host-entry.js +97 -0
  37. package/dist/sticky-owner.d.ts +15 -0
  38. package/dist/sticky-owner.d.ts.map +1 -0
  39. package/dist/sticky-owner.js +431 -0
  40. package/docs/configuration.md +36 -4
  41. package/docs/getting-started.md +28 -4
  42. package/docs/troubleshooting.md +42 -6
  43. package/package.json +1 -1
  44. package/dist/protected-fill-browser.d.ts +0 -22
  45. package/dist/protected-fill-browser.d.ts.map +0 -1
  46. package/dist/protected-fill-browser.js +0 -52
@@ -7,7 +7,7 @@ import { ensureRuntimeState, replaceTargetsForPage } from '../runtime-state.js';
7
7
  import { incrementMetric } from '../runtime-metrics.js';
8
8
  import { bumpPageScopeEpoch, setCurrentPage } from '../runtime-page-state.js';
9
9
  import { getProtectedExposure } from '../runtime-protected-state.js';
10
- import { connectPlaywright, disconnectPlaywright, resolveCurrentPageContext, syncSessionPage, } from '../playwright-runtime.js';
10
+ import { resolveCurrentPageContext, syncSessionPage } from '../playwright-runtime.js';
11
11
  import { tracedStepOperation, withApiTraceContext } from '../command-api-tracing.js';
12
12
  import { captureDiagnosticSnapshotBestEffort, finishDiagnosticStepBestEffort, recordCommandLifecycleEventBestEffort, startDiagnosticStep, } from '../diagnostics.js';
13
13
  import { outputContractFailure, outputJSON, } from '../output.js';
@@ -21,6 +21,8 @@ import { enrichDomTargetsWithAccessibility } from './observe-accessibility.js';
21
21
  import { collectPageSignals } from './observe-signals.js';
22
22
  import { attachObservedTargetOwners, linkObservedSurfaceGraph, reconcileObservedTargetsForPage, persistObservedSurfacesForPage, toDomDescriptor, } from './observe-persistence.js';
23
23
  import { clearProtectedFillableFormsForPage, markProtectedFillableFormsUnknownForPage, persistProtectedFillableFormsForPage, } from './observe-protected.js';
24
+ import { withStickyOwnerBrowser } from '../sticky-owner.js';
25
+ import { describeBrowserConnectionFailure } from './browser-connection-failure.js';
24
26
  import { classifyObservePageState, shouldSuppressFillableFormsForObserve, } from './observe-page-state.js';
25
27
  import { annotateDomTargets, compressSemanticallyDuplicateTargets, orderBySurfaceCompetition, prioritizeGoalActionTargets, } from './observe-semantics.js';
26
28
  import { buildGroupedObserveScopes, buildGoalProjectionScopeRefs, buildGoalObserveInventoryCandidates, compactFillableForms, compactSignals, expandWorkflowGraphTargets, projectPersistedTargetsForGoal, selectTargetsForGoalMatches, } from './observe-projection.js';
@@ -174,7 +176,6 @@ export async function observeBrowser(session, instruction) {
174
176
  let pageRef = runtime.currentPageRef;
175
177
  let domPassError = null;
176
178
  let stagehandFallbackReason = null;
177
- let browser = null;
178
179
  let observedScopes = [];
179
180
  const observeStep = startDiagnosticStep({
180
181
  runId: session.activeRunId,
@@ -219,50 +220,250 @@ export async function observeBrowser(session, instruction) {
219
220
  stepId: observeStep?.stepId,
220
221
  });
221
222
  }
222
- if (!instruction) {
223
- try {
224
- browser = await connectPlaywright(session.cdpUrl);
225
- const resolvedPage = await resolveCurrentPageContext(browser, session);
226
- pageRef = resolvedPage.pageRef;
227
- const page = resolvedPage.page;
228
- const previousPageUrl = session.runtime?.pages?.[pageRef]?.url;
229
- const { url, title } = await syncSessionPage(session, pageRef, page);
230
- const protectedExposure = getProtectedExposure(session, pageRef);
231
- bumpPageScopeEpoch(session, pageRef);
232
- setCurrentPage(session, pageRef);
233
- const collectedTargets = await collectDomTargets(page);
234
- let observeAccessibilityStats;
235
- const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
236
- onStats: (stats) => {
237
- observeAccessibilityStats = stats;
238
- },
239
- }))));
240
- if (observeAccessibilityStats) {
241
- incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
242
- incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
243
- incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
223
+ try {
224
+ return await withStickyOwnerBrowser(session, async (browser) => {
225
+ if (!instruction) {
226
+ try {
227
+ const resolvedPage = await resolveCurrentPageContext(browser, session);
228
+ pageRef = resolvedPage.pageRef;
229
+ const page = resolvedPage.page;
230
+ const previousPageUrl = session.runtime?.pages?.[pageRef]?.url;
231
+ const { url, title } = await syncSessionPage(session, pageRef, page);
232
+ const protectedExposure = getProtectedExposure(session, pageRef);
233
+ bumpPageScopeEpoch(session, pageRef);
234
+ setCurrentPage(session, pageRef);
235
+ const collectedTargets = await collectDomTargets(page);
236
+ let observeAccessibilityStats;
237
+ const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
238
+ onStats: (stats) => {
239
+ observeAccessibilityStats = stats;
240
+ },
241
+ }))));
242
+ if (observeAccessibilityStats) {
243
+ incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
244
+ incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
245
+ incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
246
+ }
247
+ const pageSignals = await collectPageSignals(page).catch(() => []);
248
+ const pageState = classifyObservePageState(pageSignals);
249
+ const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets);
250
+ observedScopes = persisted.observedScopes;
251
+ const surfaceRefMap = persisted.surfaceRefMap;
252
+ if (domTargets.length > 0) {
253
+ const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
254
+ reconcileObservedTargetsForPage(session, pageRef, targets);
255
+ attachObservedTargetOwners(domTargets, targets);
256
+ observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
257
+ const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
258
+ ? clearProtectedFillableFormsForPage(session, pageRef)
259
+ : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString(), { previousPageUrl });
260
+ return buildObserveSuccessResult(session, observeStep, {
261
+ success: true,
262
+ observationMode: 'deterministic_dom',
263
+ pageRef,
264
+ resolvedBy: 'dom',
265
+ ...domRuntimeResolution(),
266
+ scopes: buildGroupedObserveScopes({
267
+ pageRef,
268
+ title,
269
+ scopes: selectScopesForOutput(observedScopes, targets),
270
+ targets,
271
+ }),
272
+ signals: compactSignals(pageSignals),
273
+ fillableForms: compactFillableForms(fillableForms),
274
+ metrics: session.runtime?.metrics,
275
+ message: targets.length === 0 ? 'This observe pass returned zero targets.' : undefined,
276
+ ...buildObservePageMetadata({
277
+ url,
278
+ title,
279
+ protectedExposure,
280
+ }),
281
+ });
282
+ }
283
+ if (!allowAssistive) {
284
+ return buildObserveSuccessResult(session, observeStep, {
285
+ success: true,
286
+ observationMode: 'deterministic_dom',
287
+ pageRef,
288
+ resolvedBy: 'dom',
289
+ ...domRuntimeResolution(),
290
+ scopes: [],
291
+ signals: compactSignals(pageSignals),
292
+ fillableForms: [],
293
+ metrics: session.runtime?.metrics,
294
+ message: 'This observe pass returned zero targets.',
295
+ ...buildObservePageMetadata({
296
+ url,
297
+ title,
298
+ protectedExposure,
299
+ }),
300
+ });
301
+ }
302
+ stagehandFallbackReason = 'deterministic-observe-empty';
303
+ }
304
+ catch (err) {
305
+ domPassError = err instanceof Error ? err.message : String(err);
306
+ if (!allowAssistive) {
307
+ return buildObserveContractFailureResult(session, {
308
+ step: observeStep,
309
+ error: 'observe_failed',
310
+ outcomeType: 'blocked',
311
+ message: 'Observe failed.',
312
+ reason: domPassError,
313
+ pageRef,
314
+ runId: session.activeRunId,
315
+ stepId: observeStep?.stepId,
316
+ });
317
+ }
318
+ stagehandFallbackReason = 'deterministic-observe-failed';
319
+ }
244
320
  }
245
- const pageSignals = await collectPageSignals(page).catch(() => []);
246
- const pageState = classifyObservePageState(pageSignals);
247
- const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets);
248
- observedScopes = persisted.observedScopes;
249
- const surfaceRefMap = persisted.surfaceRefMap;
250
- if (domTargets.length > 0) {
251
- const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
252
- reconcileObservedTargetsForPage(session, pageRef, targets);
253
- attachObservedTargetOwners(domTargets, targets);
254
- observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
255
- const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
256
- ? clearProtectedFillableFormsForPage(session, pageRef)
257
- : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString(), { previousPageUrl });
258
- await disconnectPlaywright(browser);
259
- browser = null;
321
+ if (instruction) {
322
+ try {
323
+ const resolvedPage = await resolveCurrentPageContext(browser, session);
324
+ pageRef = resolvedPage.pageRef;
325
+ const page = resolvedPage.page;
326
+ const previousPageUrl = session.runtime?.pages?.[pageRef]?.url;
327
+ const { url, title } = await syncSessionPage(session, pageRef, page);
328
+ const protectedExposure = getProtectedExposure(session, pageRef);
329
+ if (protectedExposure) {
330
+ return buildObserveContractFailureResult(session, {
331
+ step: observeStep,
332
+ ...buildProtectedObserveBlockedResult(protectedExposure, 'goal-rerank'),
333
+ pageRef,
334
+ runId: session.activeRunId,
335
+ stepId: observeStep?.stepId,
336
+ });
337
+ }
338
+ bumpPageScopeEpoch(session, pageRef);
339
+ setCurrentPage(session, pageRef);
340
+ const collectedTargets = await collectDomTargets(page, {
341
+ includeActivationAffordances: true,
342
+ });
343
+ let observeAccessibilityStats;
344
+ const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
345
+ onStats: (stats) => {
346
+ observeAccessibilityStats = stats;
347
+ },
348
+ }))));
349
+ if (observeAccessibilityStats) {
350
+ incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
351
+ incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
352
+ incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
353
+ }
354
+ const pageSignals = await collectPageSignals(page).catch(() => []);
355
+ const pageState = classifyObservePageState(pageSignals);
356
+ const surfaceInputs = collectSurfaceDescriptors(pageRef, domTargets);
357
+ if (domTargets.length > 0) {
358
+ const rerankedCandidates = await tracedStepOperation(() => rerankDomTargetsForGoal(instruction, buildGoalObserveInventoryCandidates(domTargets, surfaceInputs), { session }), {
359
+ spanName: 'agentbrowse.observe.rerank_goal_candidates',
360
+ attributes: {
361
+ ...observePhaseAttributes,
362
+ 'agentbrowse.observe.target_count': domTargets.length,
363
+ },
364
+ });
365
+ const { targets: goalMatchedTargets, selectedSurfaceIds } = selectTargetsForGoalMatches(domTargets, rerankedCandidates);
366
+ const selectedTargets = prioritizeGoalActionTargets(instruction, expandWorkflowGraphTargets(domTargets, goalMatchedTargets, {
367
+ selectedSurfaceIds,
368
+ }));
369
+ const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets, {
370
+ allSurfaceInputs: surfaceInputs,
371
+ explicitSurfaceIds: selectedSurfaceIds,
372
+ });
373
+ observedScopes = persisted.observedScopes;
374
+ const surfaceRefMap = persisted.surfaceRefMap;
375
+ const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
376
+ reconcileObservedTargetsForPage(session, pageRef, targets);
377
+ attachObservedTargetOwners(domTargets, targets);
378
+ observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
379
+ const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
380
+ ? clearProtectedFillableFormsForPage(session, pageRef)
381
+ : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString(), { previousPageUrl });
382
+ if (selectedTargets.length > 0 || selectedSurfaceIds.size > 0) {
383
+ const projectedTargets = projectPersistedTargetsForGoal(domTargets, targets, selectedTargets);
384
+ const explicitScopeRefs = buildGoalProjectionScopeRefs(projectedTargets, selectedSurfaceIds, surfaceRefMap);
385
+ return buildObserveSuccessResult(session, observeStep, {
386
+ success: true,
387
+ observationMode: canUseAssistiveLlm
388
+ ? 'goal_assistive_rerank'
389
+ : 'goal_heuristic_shortlist',
390
+ pageRef,
391
+ resolvedBy: 'dom-rerank',
392
+ ...domRuntimeResolution(),
393
+ scopes: buildGroupedObserveScopes({
394
+ pageRef,
395
+ title,
396
+ scopes: selectScopesForOutput(observedScopes, projectedTargets, explicitScopeRefs),
397
+ targets: projectedTargets,
398
+ }),
399
+ signals: compactSignals(pageSignals),
400
+ fillableForms: compactFillableForms(fillableForms),
401
+ metrics: session.runtime?.metrics,
402
+ url,
403
+ title,
404
+ });
405
+ }
406
+ return buildObserveSuccessResult(session, observeStep, {
407
+ success: true,
408
+ observationMode: canUseAssistiveLlm
409
+ ? 'goal_assistive_rerank'
410
+ : 'goal_heuristic_shortlist',
411
+ pageRef,
412
+ resolvedBy: 'dom-rerank',
413
+ ...domRuntimeResolution(),
414
+ scopes: [],
415
+ signals: compactSignals(pageSignals),
416
+ fillableForms: compactFillableForms(fillableForms),
417
+ metrics: session.runtime?.metrics,
418
+ message: 'This goal-based observe pass returned zero matching targets.',
419
+ url,
420
+ title,
421
+ });
422
+ }
423
+ stagehandFallbackReason = 'deterministic-observe-empty';
424
+ }
425
+ catch (err) {
426
+ domPassError = err instanceof Error ? err.message : String(err);
427
+ stagehandFallbackReason = 'deterministic-observe-failed';
428
+ }
429
+ }
430
+ try {
431
+ const resolvedPage = await resolveCurrentPageContext(browser, session);
432
+ pageRef = resolvedPage.pageRef;
433
+ const page = resolvedPage.page;
434
+ const { url, title } = await syncSessionPage(session, pageRef, page);
435
+ const protectedExposure = getProtectedExposure(session, pageRef);
436
+ if (protectedExposure) {
437
+ return buildObserveContractFailureResult(session, {
438
+ step: observeStep,
439
+ ...buildProtectedObserveBlockedResult(protectedExposure, 'stagehand-fallback'),
440
+ fallbackReason: stagehandFallbackReason ?? undefined,
441
+ deterministicObserveError: domPassError ?? undefined,
442
+ pageRef,
443
+ runId: session.activeRunId,
444
+ stepId: observeStep?.stepId,
445
+ });
446
+ }
447
+ bumpPageScopeEpoch(session, pageRef);
448
+ setCurrentPage(session, pageRef);
449
+ const pageSignals = await collectPageSignals(page).catch(() => []);
450
+ const actions = await withStagehand(session, async (stagehand) => {
451
+ incrementMetric(session, 'stagehandCalls');
452
+ return instruction
453
+ ? (await stagehand.observe(instruction, {
454
+ page,
455
+ }))
456
+ : (await stagehand.observe({ page }));
457
+ });
458
+ const targets = replaceTargetsForPage(session, pageRef, await Promise.all(actions.map((action) => toStagehandDescriptor(pageRef, action, page, normalizePageSignature(url)))));
459
+ const fillableForms = markProtectedFillableFormsUnknownForPage(session, pageRef);
260
460
  return buildObserveSuccessResult(session, observeStep, {
261
461
  success: true,
262
- observationMode: 'deterministic_dom',
462
+ observationMode: 'goal_assistive_stagehand',
263
463
  pageRef,
264
- resolvedBy: 'dom',
265
- ...domRuntimeResolution(),
464
+ resolvedBy: 'stagehand-observe',
465
+ ...stagehandRuntimeResolution(stagehandFallbackReason ?? 'deterministic-observe-failed'),
466
+ deterministicObserveError: domPassError ?? undefined,
266
467
  scopes: buildGroupedObserveScopes({
267
468
  pageRef,
268
469
  title,
@@ -273,259 +474,46 @@ export async function observeBrowser(session, instruction) {
273
474
  fillableForms: compactFillableForms(fillableForms),
274
475
  metrics: session.runtime?.metrics,
275
476
  message: targets.length === 0 ? 'This observe pass returned zero targets.' : undefined,
276
- ...buildObservePageMetadata({
277
- url,
278
- title,
279
- protectedExposure,
280
- }),
281
- });
282
- }
283
- if (!allowAssistive) {
284
- await disconnectPlaywright(browser);
285
- browser = null;
286
- return buildObserveSuccessResult(session, observeStep, {
287
- success: true,
288
- observationMode: 'deterministic_dom',
289
- pageRef,
290
- resolvedBy: 'dom',
291
- ...domRuntimeResolution(),
292
- scopes: [],
293
- signals: compactSignals(pageSignals),
294
- fillableForms: [],
295
- metrics: session.runtime?.metrics,
296
- message: 'This observe pass returned zero targets.',
297
- ...buildObservePageMetadata({
298
- url,
299
- title,
300
- protectedExposure,
301
- }),
477
+ url,
478
+ title,
302
479
  });
303
480
  }
304
- stagehandFallbackReason = 'deterministic-observe-empty';
305
- }
306
- catch (err) {
307
- domPassError = err instanceof Error ? err.message : String(err);
308
- if (!allowAssistive) {
481
+ catch (err) {
482
+ const stagehandError = err instanceof Error ? err.message : String(err);
483
+ const details = domPassError
484
+ ? `${stagehandError} (deterministic observe failed earlier: ${domPassError})`
485
+ : stagehandError;
309
486
  return buildObserveContractFailureResult(session, {
310
487
  step: observeStep,
311
488
  error: 'observe_failed',
312
489
  outcomeType: 'blocked',
313
490
  message: 'Observe failed.',
314
- reason: domPassError,
491
+ reason: details,
315
492
  pageRef,
316
493
  runId: session.activeRunId,
317
494
  stepId: observeStep?.stepId,
318
495
  });
319
496
  }
320
- stagehandFallbackReason = 'deterministic-observe-failed';
321
- }
322
- }
323
- if (instruction) {
324
- try {
325
- if (!browser) {
326
- browser = await connectPlaywright(session.cdpUrl);
327
- }
328
- const resolvedPage = await resolveCurrentPageContext(browser, session);
329
- pageRef = resolvedPage.pageRef;
330
- const page = resolvedPage.page;
331
- const previousPageUrl = session.runtime?.pages?.[pageRef]?.url;
332
- const { url, title } = await syncSessionPage(session, pageRef, page);
333
- const protectedExposure = getProtectedExposure(session, pageRef);
334
- if (protectedExposure) {
335
- return buildObserveContractFailureResult(session, {
336
- step: observeStep,
337
- ...buildProtectedObserveBlockedResult(protectedExposure, 'goal-rerank'),
338
- pageRef,
339
- runId: session.activeRunId,
340
- stepId: observeStep?.stepId,
341
- });
342
- }
343
- bumpPageScopeEpoch(session, pageRef);
344
- setCurrentPage(session, pageRef);
345
- const collectedTargets = await collectDomTargets(page, {
346
- includeActivationAffordances: true,
347
- });
348
- let observeAccessibilityStats;
349
- const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
350
- onStats: (stats) => {
351
- observeAccessibilityStats = stats;
352
- },
353
- }))));
354
- if (observeAccessibilityStats) {
355
- incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
356
- incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
357
- incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
358
- }
359
- const pageSignals = await collectPageSignals(page).catch(() => []);
360
- const pageState = classifyObservePageState(pageSignals);
361
- const surfaceInputs = collectSurfaceDescriptors(pageRef, domTargets);
362
- if (domTargets.length > 0) {
363
- const rerankedCandidates = await tracedStepOperation(() => rerankDomTargetsForGoal(instruction, buildGoalObserveInventoryCandidates(domTargets, surfaceInputs), { session }), {
364
- spanName: 'agentbrowse.observe.rerank_goal_candidates',
365
- attributes: {
366
- ...observePhaseAttributes,
367
- 'agentbrowse.observe.target_count': domTargets.length,
368
- },
369
- });
370
- const { targets: goalMatchedTargets, selectedSurfaceIds } = selectTargetsForGoalMatches(domTargets, rerankedCandidates);
371
- const selectedTargets = prioritizeGoalActionTargets(instruction, expandWorkflowGraphTargets(domTargets, goalMatchedTargets, {
372
- selectedSurfaceIds,
373
- }));
374
- const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets, {
375
- allSurfaceInputs: surfaceInputs,
376
- explicitSurfaceIds: selectedSurfaceIds,
377
- });
378
- observedScopes = persisted.observedScopes;
379
- const surfaceRefMap = persisted.surfaceRefMap;
380
- const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
381
- reconcileObservedTargetsForPage(session, pageRef, targets);
382
- attachObservedTargetOwners(domTargets, targets);
383
- observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
384
- const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
385
- ? clearProtectedFillableFormsForPage(session, pageRef)
386
- : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString(), { previousPageUrl });
387
- if (selectedTargets.length > 0 || selectedSurfaceIds.size > 0) {
388
- const projectedTargets = projectPersistedTargetsForGoal(domTargets, targets, selectedTargets);
389
- const explicitScopeRefs = buildGoalProjectionScopeRefs(projectedTargets, selectedSurfaceIds, surfaceRefMap);
390
- await disconnectPlaywright(browser);
391
- browser = null;
392
- return buildObserveSuccessResult(session, observeStep, {
393
- success: true,
394
- observationMode: canUseAssistiveLlm
395
- ? 'goal_assistive_rerank'
396
- : 'goal_heuristic_shortlist',
397
- pageRef,
398
- resolvedBy: 'dom-rerank',
399
- ...domRuntimeResolution(),
400
- scopes: buildGroupedObserveScopes({
401
- pageRef,
402
- title,
403
- scopes: selectScopesForOutput(observedScopes, projectedTargets, explicitScopeRefs),
404
- targets: projectedTargets,
405
- }),
406
- signals: compactSignals(pageSignals),
407
- fillableForms: compactFillableForms(fillableForms),
408
- metrics: session.runtime?.metrics,
409
- url,
410
- title,
411
- });
412
- }
413
- await disconnectPlaywright(browser);
414
- browser = null;
415
- return buildObserveSuccessResult(session, observeStep, {
416
- success: true,
417
- observationMode: canUseAssistiveLlm
418
- ? 'goal_assistive_rerank'
419
- : 'goal_heuristic_shortlist',
420
- pageRef,
421
- resolvedBy: 'dom-rerank',
422
- ...domRuntimeResolution(),
423
- scopes: [],
424
- signals: compactSignals(pageSignals),
425
- fillableForms: compactFillableForms(fillableForms),
426
- metrics: session.runtime?.metrics,
427
- message: 'This goal-based observe pass returned zero matching targets.',
428
- url,
429
- title,
430
- });
431
- }
432
- stagehandFallbackReason = 'deterministic-observe-empty';
433
- }
434
- catch (err) {
435
- domPassError = err instanceof Error ? err.message : String(err);
436
- stagehandFallbackReason = 'deterministic-observe-failed';
437
- }
438
- }
439
- try {
440
- if (!browser) {
441
- browser = await connectPlaywright(session.cdpUrl);
442
- }
443
- }
444
- catch (err) {
445
- const domFailure = domPassError && domPassError.length > 0 ? `; dom observe failed: ${domPassError}` : '';
446
- return buildObserveContractFailureResult(session, {
447
- step: observeStep,
448
- error: 'browser_connection_failed',
449
- outcomeType: 'blocked',
450
- message: 'Observe could not start because AgentBrowse failed to connect to the browser.',
451
- reason: `${err instanceof Error ? err.message : String(err)}${domFailure}`,
452
- pageRef,
453
- runId: session.activeRunId,
454
- stepId: observeStep?.stepId,
455
- });
456
- }
457
- try {
458
- const resolvedPage = await resolveCurrentPageContext(browser, session);
459
- pageRef = resolvedPage.pageRef;
460
- const page = resolvedPage.page;
461
- const { url, title } = await syncSessionPage(session, pageRef, page);
462
- const protectedExposure = getProtectedExposure(session, pageRef);
463
- if (protectedExposure) {
464
- return buildObserveContractFailureResult(session, {
465
- step: observeStep,
466
- ...buildProtectedObserveBlockedResult(protectedExposure, 'stagehand-fallback'),
467
- fallbackReason: stagehandFallbackReason ?? undefined,
468
- deterministicObserveError: domPassError ?? undefined,
469
- pageRef,
470
- runId: session.activeRunId,
471
- stepId: observeStep?.stepId,
472
- });
473
- }
474
- bumpPageScopeEpoch(session, pageRef);
475
- setCurrentPage(session, pageRef);
476
- const pageSignals = await collectPageSignals(page).catch(() => []);
477
- const actions = await withStagehand(session, async (stagehand) => {
478
- incrementMetric(session, 'stagehandCalls');
479
- return instruction
480
- ? (await stagehand.observe(instruction, {
481
- page,
482
- }))
483
- : (await stagehand.observe({ page }));
484
- });
485
- const targets = replaceTargetsForPage(session, pageRef, await Promise.all(actions.map((action) => toStagehandDescriptor(pageRef, action, page, normalizePageSignature(url)))));
486
- const fillableForms = markProtectedFillableFormsUnknownForPage(session, pageRef);
487
- return buildObserveSuccessResult(session, observeStep, {
488
- success: true,
489
- observationMode: 'goal_assistive_stagehand',
490
- pageRef,
491
- resolvedBy: 'stagehand-observe',
492
- ...stagehandRuntimeResolution(stagehandFallbackReason ?? 'deterministic-observe-failed'),
493
- deterministicObserveError: domPassError ?? undefined,
494
- scopes: buildGroupedObserveScopes({
495
- pageRef,
496
- title,
497
- scopes: selectScopesForOutput(observedScopes, targets),
498
- targets,
499
- }),
500
- signals: compactSignals(pageSignals),
501
- fillableForms: compactFillableForms(fillableForms),
502
- metrics: session.runtime?.metrics,
503
- message: targets.length === 0 ? 'This observe pass returned zero targets.' : undefined,
504
- url,
505
- title,
506
497
  });
507
498
  }
508
499
  catch (err) {
509
- const stagehandError = err instanceof Error ? err.message : String(err);
510
- const details = domPassError
511
- ? `${stagehandError} (deterministic observe failed earlier: ${domPassError})`
512
- : stagehandError;
500
+ const browserConnectionFailure = describeBrowserConnectionFailure(err, {
501
+ defaultMessage: instruction
502
+ ? 'Observe could not start because AgentBrowse failed to connect to the browser.'
503
+ : 'Observe failed.',
504
+ unrecoverableSessionMessage: 'Observe could not start because the previous browser session is no longer reachable.',
505
+ });
513
506
  return buildObserveContractFailureResult(session, {
514
507
  step: observeStep,
515
- error: 'observe_failed',
508
+ error: instruction ? 'browser_connection_failed' : 'observe_failed',
516
509
  outcomeType: 'blocked',
517
- message: 'Observe failed.',
518
- reason: details,
510
+ message: browserConnectionFailure.message,
511
+ reason: browserConnectionFailure.reason,
519
512
  pageRef,
520
513
  runId: session.activeRunId,
521
514
  stepId: observeStep?.stepId,
522
515
  });
523
516
  }
524
- finally {
525
- if (browser) {
526
- await disconnectPlaywright(browser);
527
- }
528
- }
529
517
  });
530
518
  }
531
519
  /** CLI wrapper for `observeBrowser(...)` that persists the observed runtime state. */
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/commands/screenshot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAqBzE,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,6FAIzB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB,0EAI3B,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,4CAA4C;AAC5C,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,mBAAmB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC,qBAAqB,EAAE,SAAS,GAAG,2BAA2B,CAAC,CAAC;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAkJjF,0DAA0D;AAC1D,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAwH3B;AAED,qGAAqG;AACrG,wBAAsB,UAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjG"}
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/commands/screenshot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAkBzE,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,6FAIzB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB,0EAI3B,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,4CAA4C;AAC5C,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,mBAAmB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC,qBAAqB,EAAE,SAAS,GAAG,2BAA2B,CAAC,CAAC;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAkJjF,0DAA0D;AAC1D,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CA2G3B;AAED,qGAAqG;AACrG,wBAAsB,UAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjG"}