@nuanu-ai/agentbrowse 0.2.47 → 0.2.49

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 (198) hide show
  1. package/README.md +81 -10
  2. package/dist/agentpay-gateway.d.ts +9 -0
  3. package/dist/agentpay-gateway.d.ts.map +1 -1
  4. package/dist/agentpay-gateway.js +31 -1
  5. package/dist/agentpay-stagehand-llm.d.ts.map +1 -1
  6. package/dist/agentpay-stagehand-llm.js +9 -1
  7. package/dist/command-api-tracing.d.ts +19 -0
  8. package/dist/command-api-tracing.d.ts.map +1 -0
  9. package/dist/command-api-tracing.js +137 -0
  10. package/dist/commands/act.d.ts.map +1 -1
  11. package/dist/commands/act.js +822 -670
  12. package/dist/commands/act.test-harness.d.ts +6 -0
  13. package/dist/commands/act.test-harness.d.ts.map +1 -1
  14. package/dist/commands/act.test-harness.js +44 -1
  15. package/dist/commands/action-acceptance.d.ts.map +1 -1
  16. package/dist/commands/action-acceptance.js +115 -0
  17. package/dist/commands/captcha-solve.d.ts.map +1 -1
  18. package/dist/commands/captcha-solve.js +83 -16
  19. package/dist/commands/click-action-executor.d.ts +0 -1
  20. package/dist/commands/click-action-executor.d.ts.map +1 -1
  21. package/dist/commands/click-action-executor.js +31 -77
  22. package/dist/commands/close.d.ts +3 -3
  23. package/dist/commands/close.d.ts.map +1 -1
  24. package/dist/commands/close.js +178 -0
  25. package/dist/commands/descriptor-validation.d.ts.map +1 -1
  26. package/dist/commands/descriptor-validation.js +75 -57
  27. package/dist/commands/end-session.d.ts +25 -0
  28. package/dist/commands/end-session.d.ts.map +1 -0
  29. package/dist/commands/end-session.js +161 -0
  30. package/dist/commands/extract-stagehand-executor.js +1 -1
  31. package/dist/commands/extract.d.ts.map +1 -1
  32. package/dist/commands/extract.js +339 -202
  33. package/dist/commands/fill-secret.d.ts +3 -3
  34. package/dist/commands/fill-secret.d.ts.map +1 -1
  35. package/dist/commands/fill-secret.js +419 -234
  36. package/dist/commands/get-secrets-catalog.d.ts.map +1 -1
  37. package/dist/commands/get-secrets-catalog.js +66 -5
  38. package/dist/commands/init.d.ts.map +1 -1
  39. package/dist/commands/init.js +6 -3
  40. package/dist/commands/interaction-kernel.d.ts +46 -0
  41. package/dist/commands/interaction-kernel.d.ts.map +1 -0
  42. package/dist/commands/interaction-kernel.js +215 -0
  43. package/dist/commands/launch.d.ts +1 -3
  44. package/dist/commands/launch.d.ts.map +1 -1
  45. package/dist/commands/launch.js +115 -27
  46. package/dist/commands/navigate.d.ts.map +1 -1
  47. package/dist/commands/navigate.js +188 -45
  48. package/dist/commands/observe-accessibility.d.ts.map +1 -1
  49. package/dist/commands/observe-accessibility.js +46 -39
  50. package/dist/commands/observe-dom-label-contract.d.ts.map +1 -1
  51. package/dist/commands/observe-dom-label-contract.js +5 -0
  52. package/dist/commands/observe-inventory.d.ts +13 -0
  53. package/dist/commands/observe-inventory.d.ts.map +1 -1
  54. package/dist/commands/observe-inventory.js +320 -65
  55. package/dist/commands/observe-persistence.d.ts.map +1 -1
  56. package/dist/commands/observe-persistence.js +3 -0
  57. package/dist/commands/observe-projection.d.ts +1 -0
  58. package/dist/commands/observe-projection.d.ts.map +1 -1
  59. package/dist/commands/observe-projection.js +7 -2
  60. package/dist/commands/observe-protected.d.ts +1 -0
  61. package/dist/commands/observe-protected.d.ts.map +1 -1
  62. package/dist/commands/observe-protected.js +9 -4
  63. package/dist/commands/observe-semantics.d.ts.map +1 -1
  64. package/dist/commands/observe-semantics.js +5 -2
  65. package/dist/commands/observe-stagehand.d.ts +1 -0
  66. package/dist/commands/observe-stagehand.d.ts.map +1 -1
  67. package/dist/commands/observe-stagehand.js +2 -0
  68. package/dist/commands/observe.d.ts +2 -0
  69. package/dist/commands/observe.d.ts.map +1 -1
  70. package/dist/commands/observe.js +387 -203
  71. package/dist/commands/observe.test-harness.d.ts +8 -0
  72. package/dist/commands/observe.test-harness.d.ts.map +1 -1
  73. package/dist/commands/observe.test-harness.js +48 -1
  74. package/dist/commands/poll-secret.d.ts +6 -0
  75. package/dist/commands/poll-secret.d.ts.map +1 -0
  76. package/dist/commands/poll-secret.js +159 -0
  77. package/dist/commands/request-secret.d.ts +6 -0
  78. package/dist/commands/request-secret.d.ts.map +1 -0
  79. package/dist/commands/request-secret.js +284 -0
  80. package/dist/commands/screenshot.d.ts.map +1 -1
  81. package/dist/commands/screenshot.js +172 -7
  82. package/dist/commands/select-action-executor.d.ts.map +1 -1
  83. package/dist/commands/semantic-observe.d.ts +4 -0
  84. package/dist/commands/semantic-observe.d.ts.map +1 -1
  85. package/dist/commands/semantic-observe.js +388 -17
  86. package/dist/commands/start-session.d.ts +31 -0
  87. package/dist/commands/start-session.d.ts.map +1 -0
  88. package/dist/commands/start-session.js +347 -0
  89. package/dist/commands/status.d.ts +2 -1
  90. package/dist/commands/status.d.ts.map +1 -1
  91. package/dist/commands/status.js +166 -144
  92. package/dist/control-semantics.d.ts +1 -0
  93. package/dist/control-semantics.d.ts.map +1 -1
  94. package/dist/control-semantics.js +51 -9
  95. package/dist/generated/build-config.d.ts +2 -0
  96. package/dist/generated/build-config.d.ts.map +1 -0
  97. package/dist/generated/build-config.js +2 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +163 -63
  100. package/dist/otel-exporter.d.ts +58 -0
  101. package/dist/otel-exporter.d.ts.map +1 -0
  102. package/dist/otel-exporter.js +263 -0
  103. package/dist/otel-projector.d.ts +75 -0
  104. package/dist/otel-projector.d.ts.map +1 -0
  105. package/dist/otel-projector.js +409 -0
  106. package/dist/owned-browser.d.ts +1 -1
  107. package/dist/owned-browser.d.ts.map +1 -1
  108. package/dist/owned-browser.js +13 -1
  109. package/dist/owned-process.d.ts +2 -0
  110. package/dist/owned-process.d.ts.map +1 -1
  111. package/dist/owned-process.js +7 -3
  112. package/dist/playwright-runtime.d.ts +1 -1
  113. package/dist/playwright-runtime.d.ts.map +1 -1
  114. package/dist/playwright-runtime.js +8 -8
  115. package/dist/run-observability.d.ts +25 -0
  116. package/dist/run-observability.d.ts.map +1 -0
  117. package/dist/run-observability.js +115 -0
  118. package/dist/run-store.d.ts +274 -0
  119. package/dist/run-store.d.ts.map +1 -0
  120. package/dist/run-store.js +631 -0
  121. package/dist/runtime-metrics.d.ts +27 -0
  122. package/dist/runtime-metrics.d.ts.map +1 -0
  123. package/dist/runtime-metrics.js +66 -0
  124. package/dist/runtime-page-state.d.ts +11 -0
  125. package/dist/runtime-page-state.d.ts.map +1 -0
  126. package/dist/runtime-page-state.js +62 -0
  127. package/dist/runtime-protected-state.d.ts +16 -0
  128. package/dist/runtime-protected-state.d.ts.map +1 -0
  129. package/dist/runtime-protected-state.js +157 -0
  130. package/dist/runtime-state.d.ts +10 -44
  131. package/dist/runtime-state.d.ts.map +1 -1
  132. package/dist/runtime-state.js +57 -222
  133. package/dist/secrets/backend.d.ts +65 -16
  134. package/dist/secrets/backend.d.ts.map +1 -1
  135. package/dist/secrets/backend.js +135 -95
  136. package/dist/secrets/catalog-sync.d.ts.map +1 -1
  137. package/dist/secrets/catalog-sync.js +4 -1
  138. package/dist/secrets/form-matcher.d.ts +5 -5
  139. package/dist/secrets/form-matcher.d.ts.map +1 -1
  140. package/dist/secrets/form-matcher.js +292 -164
  141. package/dist/secrets/intent-output.d.ts +6 -10
  142. package/dist/secrets/intent-output.d.ts.map +1 -1
  143. package/dist/secrets/intent-output.js +4 -58
  144. package/dist/secrets/mock-agentpay-cabinet.d.ts +38 -27
  145. package/dist/secrets/mock-agentpay-cabinet.d.ts.map +1 -1
  146. package/dist/secrets/mock-agentpay-cabinet.js +177 -111
  147. package/dist/secrets/protected-artifact-guard.d.ts +2 -2
  148. package/dist/secrets/protected-artifact-guard.d.ts.map +1 -1
  149. package/dist/secrets/protected-artifact-guard.js +2 -2
  150. package/dist/secrets/protected-bindings.d.ts +1 -1
  151. package/dist/secrets/protected-bindings.d.ts.map +1 -1
  152. package/dist/secrets/protected-bindings.js +6 -0
  153. package/dist/secrets/protected-field-semantics.d.ts +9 -0
  154. package/dist/secrets/protected-field-semantics.d.ts.map +1 -0
  155. package/dist/secrets/protected-field-semantics.js +154 -0
  156. package/dist/secrets/protected-field-values.d.ts.map +1 -1
  157. package/dist/secrets/protected-field-values.js +3 -3
  158. package/dist/secrets/protected-fill.d.ts +1 -1
  159. package/dist/secrets/protected-fill.d.ts.map +1 -1
  160. package/dist/secrets/protected-fill.js +45 -149
  161. package/dist/secrets/protected-value-adapters.d.ts +2 -1
  162. package/dist/secrets/protected-value-adapters.d.ts.map +1 -1
  163. package/dist/secrets/protected-value-adapters.js +80 -1
  164. package/dist/secrets/request-output.d.ts +11 -0
  165. package/dist/secrets/request-output.d.ts.map +1 -0
  166. package/dist/secrets/request-output.js +75 -0
  167. package/dist/secrets/types.d.ts +15 -9
  168. package/dist/secrets/types.d.ts.map +1 -1
  169. package/dist/secrets/types.js +3 -0
  170. package/dist/session-event-exporter.d.ts +36 -0
  171. package/dist/session-event-exporter.d.ts.map +1 -0
  172. package/dist/session-event-exporter.js +428 -0
  173. package/dist/session.d.ts +16 -7
  174. package/dist/session.d.ts.map +1 -1
  175. package/dist/session.js +150 -23
  176. package/dist/sessions-backend.d.ts +354 -0
  177. package/dist/sessions-backend.d.ts.map +1 -0
  178. package/dist/sessions-backend.js +126 -0
  179. package/dist/solver/browser-launcher.d.ts +1 -1
  180. package/dist/solver/browser-launcher.d.ts.map +1 -1
  181. package/dist/solver/browser-launcher.js +39 -13
  182. package/dist/solver/captcha-solver.d.ts.map +1 -1
  183. package/dist/solver/captcha-solver.js +8 -1
  184. package/dist/solver/config.d.ts +0 -1
  185. package/dist/solver/config.d.ts.map +1 -1
  186. package/dist/solver/config.js +0 -22
  187. package/dist/solver/types.d.ts +1 -0
  188. package/dist/solver/types.d.ts.map +1 -1
  189. package/dist/workflow-session-completion.d.ts +33 -0
  190. package/dist/workflow-session-completion.d.ts.map +1 -0
  191. package/dist/workflow-session-completion.js +156 -0
  192. package/package.json +11 -1
  193. package/dist/commands/create-intent.d.ts +0 -6
  194. package/dist/commands/create-intent.d.ts.map +0 -1
  195. package/dist/commands/create-intent.js +0 -75
  196. package/dist/commands/poll-intent.d.ts +0 -6
  197. package/dist/commands/poll-intent.d.ts.map +0 -1
  198. package/dist/commands/poll-intent.js +0 -57
@@ -2,23 +2,101 @@
2
2
  * browse observe ["<instruction>"] — Discover available actions on the page.
3
3
  */
4
4
  import { saveSession } from '../session.js';
5
- import { bumpPageScopeEpoch, ensureRuntimeState, incrementMetric, replaceTargetsForPage, setCurrentPage, } from '../runtime-state.js';
5
+ import { ensureRuntimeState, replaceTargetsForPage } from '../runtime-state.js';
6
+ import { incrementMetric } from '../runtime-metrics.js';
7
+ import { bumpPageScopeEpoch, setCurrentPage } from '../runtime-page-state.js';
6
8
  import { connectPlaywright, disconnectPlaywright, resolveCurrentPageContext, syncSessionPage, } from '../playwright-runtime.js';
9
+ import { tracedStepOperation, withApiTraceContext } from '../command-api-tracing.js';
7
10
  import { outputContractFailure, outputJSON } from '../output.js';
11
+ import { appendCommandLifecycleEventBestEffort, captureStepSnapshotBestEffort, } from '../run-observability.js';
12
+ import { exportRunStepToOtlpHttpJsonBestEffort } from '../otel-exporter.js';
8
13
  import { domRuntimeResolution, stagehandRuntimeResolution } from '../runtime-resolution.js';
14
+ import { finishRunStep, startRunStep } from '../run-store.js';
9
15
  import { withStagehand } from '../stagehand-runtime.js';
10
16
  import { normalizePageSignature } from './descriptor-validation.js';
11
17
  import { collectDomTargets, __testDomTargetCollection as inventoryDomTargetCollection, __testStagehandDescriptor as inventoryStagehandDescriptor, } from './observe-inventory.js';
12
18
  import { enrichDomTargetsWithAccessibility } from './observe-accessibility.js';
13
19
  import { collectPageSignals } from './observe-signals.js';
14
20
  import { attachObservedTargetOwners, linkObservedSurfaceGraph, reconcileObservedTargetsForPage, persistObservedSurfacesForPage, toDomDescriptor, } from './observe-persistence.js';
15
- import { clearProtectedFillableFormsForPage, persistProtectedFillableFormsForPage, } from './observe-protected.js';
21
+ import { clearProtectedFillableFormsForPage, markProtectedFillableFormsUnknownForPage, persistProtectedFillableFormsForPage, } from './observe-protected.js';
16
22
  import { classifyObservePageState, shouldSuppressFillableFormsForObserve, } from './observe-page-state.js';
17
23
  import { annotateDomTargets, compressSemanticallyDuplicateTargets, orderBySurfaceCompetition, prioritizeGoalActionTargets, } from './observe-semantics.js';
18
24
  import { buildGroupedObserveScopes, buildGoalProjectionScopeRefs, buildGoalObserveInventoryCandidates, compactFillableForms, compactSignals, expandWorkflowGraphTargets, projectPersistedTargetsForGoal, selectTargetsForGoalMatches, } from './observe-projection.js';
19
25
  import { collectSurfaceDescriptors, selectScopesForOutput } from './observe-surfaces.js';
20
26
  import { toStagehandDescriptor } from './observe-stagehand.js';
21
27
  import { rerankDomTargetsForGoal } from './semantic-observe.js';
28
+ function finalizeObserveStepBestEffort(runId, stepId, options) {
29
+ if (!runId || !stepId) {
30
+ return;
31
+ }
32
+ try {
33
+ finishRunStep({
34
+ runId,
35
+ stepId,
36
+ ...options,
37
+ });
38
+ }
39
+ catch { }
40
+ }
41
+ async function emitObserveSuccess(session, step, payload) {
42
+ captureStepSnapshotBestEffort({
43
+ session,
44
+ step,
45
+ phase: 'after',
46
+ pageRef: typeof payload.pageRef === 'string' ? payload.pageRef : session.runtime?.currentPageRef,
47
+ url: typeof payload.url === 'string' ? payload.url : undefined,
48
+ title: typeof payload.title === 'string' ? payload.title : undefined,
49
+ });
50
+ appendCommandLifecycleEventBestEffort({
51
+ step,
52
+ phase: 'completed',
53
+ attributes: {
54
+ outcomeType: 'observation_completed',
55
+ ...(typeof payload.pageRef === 'string' ? { pageRef: payload.pageRef } : {}),
56
+ ...(typeof payload.resolvedBy === 'string' ? { resolvedBy: payload.resolvedBy } : {}),
57
+ },
58
+ });
59
+ finalizeObserveStepBestEffort(step?.runId, step?.stepId, {
60
+ success: true,
61
+ outcomeType: 'observation_completed',
62
+ message: typeof payload.message === 'string' ? payload.message : 'Observe completed.',
63
+ });
64
+ await exportRunStepToOtlpHttpJsonBestEffort(step?.runId, step?.stepId);
65
+ return outputJSON(payload);
66
+ }
67
+ async function emitObserveContractFailure(session, params) {
68
+ const step = params.runId && params.stepId
69
+ ? {
70
+ runId: params.runId,
71
+ stepId: params.stepId,
72
+ command: 'observe',
73
+ }
74
+ : null;
75
+ captureStepSnapshotBestEffort({
76
+ session,
77
+ step,
78
+ phase: 'point-in-time',
79
+ pageRef: typeof params.pageRef === 'string' ? params.pageRef : undefined,
80
+ });
81
+ appendCommandLifecycleEventBestEffort({
82
+ step,
83
+ phase: 'failed',
84
+ attributes: {
85
+ ...(params.outcomeType ? { outcomeType: params.outcomeType } : {}),
86
+ ...(typeof params.pageRef === 'string' ? { pageRef: params.pageRef } : {}),
87
+ ...(params.reason ? { reason: params.reason } : {}),
88
+ },
89
+ });
90
+ finalizeObserveStepBestEffort(params.runId, params.stepId, {
91
+ success: false,
92
+ outcomeType: params.outcomeType,
93
+ message: params.message,
94
+ reason: params.reason,
95
+ });
96
+ await exportRunStepToOtlpHttpJsonBestEffort(params.runId, params.stepId);
97
+ const { runId: _runId, stepId: _stepId, ...result } = params;
98
+ return outputContractFailure(result);
99
+ }
22
100
  export const __testDomTargetCollection = inventoryDomTargetCollection;
23
101
  export const __testStagehandDescriptor = {
24
102
  ...inventoryStagehandDescriptor,
@@ -31,233 +109,339 @@ export async function observe(session, instruction) {
31
109
  let stagehandFallbackReason = null;
32
110
  let browser = null;
33
111
  let observedScopes = [];
34
- if (!instruction) {
35
- try {
36
- browser = await connectPlaywright(session.cdpUrl);
37
- const resolvedPage = await resolveCurrentPageContext(browser, session);
38
- pageRef = resolvedPage.pageRef;
39
- const page = resolvedPage.page;
40
- const { url, title } = await syncSessionPage(session, pageRef, page);
41
- bumpPageScopeEpoch(session, pageRef);
42
- setCurrentPage(session, pageRef);
43
- const collectedTargets = await collectDomTargets(page);
44
- let observeAccessibilityStats;
45
- const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
46
- onStats: (stats) => {
47
- observeAccessibilityStats = stats;
48
- },
49
- }))));
50
- if (observeAccessibilityStats) {
51
- incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
52
- incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
53
- incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
54
- }
55
- const signals = compactSignals(await collectPageSignals(page).catch(() => []));
56
- const pageState = classifyObservePageState(signals);
57
- const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets);
58
- observedScopes = persisted.observedScopes;
59
- const surfaceRefMap = persisted.surfaceRefMap;
60
- if (domTargets.length > 0) {
61
- const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
62
- reconcileObservedTargetsForPage(session, pageRef, targets);
63
- attachObservedTargetOwners(domTargets, targets);
64
- observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
65
- const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
66
- ? clearProtectedFillableFormsForPage(session, pageRef)
67
- : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString());
68
- saveSession(session);
69
- disconnectPlaywright(browser);
70
- browser = null;
71
- outputJSON({
72
- success: true,
73
- pageRef,
74
- resolvedBy: 'dom',
75
- ...domRuntimeResolution(),
76
- scopes: buildGroupedObserveScopes({
77
- pageRef,
78
- title,
79
- scopes: selectScopesForOutput(observedScopes, targets),
80
- targets,
81
- }),
82
- signals,
83
- fillableForms: compactFillableForms(fillableForms),
84
- metrics: session.runtime?.metrics,
85
- message: targets.length === 0 ? 'No targets found.' : undefined,
86
- url,
87
- title,
112
+ const observeStep = session.activeRunId
113
+ ? startRunStep({
114
+ runId: session.activeRunId,
115
+ command: 'observe',
116
+ input: {
117
+ ...(instruction ? { instruction } : {}),
118
+ },
119
+ refs: {
120
+ pageRef,
121
+ },
122
+ protectedStep: Boolean(session.runtime?.protectedExposureByPage?.[pageRef]),
123
+ })
124
+ : null;
125
+ captureStepSnapshotBestEffort({
126
+ session,
127
+ step: observeStep,
128
+ phase: 'before',
129
+ pageRef,
130
+ });
131
+ appendCommandLifecycleEventBestEffort({
132
+ step: observeStep,
133
+ phase: 'started',
134
+ attributes: {
135
+ ...(instruction ? { instruction } : {}),
136
+ pageRef,
137
+ },
138
+ });
139
+ return withApiTraceContext({
140
+ runId: session.activeRunId,
141
+ stepId: observeStep?.stepId,
142
+ command: 'observe',
143
+ }, async () => {
144
+ const observePhaseAttributes = {
145
+ 'agentbrowse.observe.goal_based': Boolean(instruction),
146
+ };
147
+ if (!instruction) {
148
+ try {
149
+ browser = await tracedStepOperation(() => connectPlaywright(session.cdpUrl), {
150
+ spanName: 'agentbrowse.observe.connect_browser',
151
+ attributes: observePhaseAttributes,
88
152
  });
89
- return;
90
- }
91
- stagehandFallbackReason = 'deterministic-observe-empty';
92
- }
93
- catch (err) {
94
- domPassError = err instanceof Error ? err.message : String(err);
95
- stagehandFallbackReason = 'deterministic-observe-failed';
96
- }
97
- }
98
- if (instruction) {
99
- try {
100
- if (!browser) {
101
- browser = await connectPlaywright(session.cdpUrl);
102
- }
103
- const resolvedPage = await resolveCurrentPageContext(browser, session);
104
- pageRef = resolvedPage.pageRef;
105
- const page = resolvedPage.page;
106
- const { url, title } = await syncSessionPage(session, pageRef, page);
107
- bumpPageScopeEpoch(session, pageRef);
108
- setCurrentPage(session, pageRef);
109
- const collectedTargets = await collectDomTargets(page, {
110
- includeActivationAffordances: true,
111
- });
112
- let observeAccessibilityStats;
113
- const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await enrichDomTargetsWithAccessibility(page, collectedTargets, {
114
- onStats: (stats) => {
115
- observeAccessibilityStats = stats;
116
- },
117
- }))));
118
- if (observeAccessibilityStats) {
119
- incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
120
- incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
121
- incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
122
- }
123
- const signals = compactSignals(await collectPageSignals(page).catch(() => []));
124
- const pageState = classifyObservePageState(signals);
125
- const surfaceInputs = collectSurfaceDescriptors(pageRef, domTargets);
126
- if (domTargets.length > 0) {
127
- const rerankedCandidates = await rerankDomTargetsForGoal(instruction, buildGoalObserveInventoryCandidates(domTargets, surfaceInputs), { session });
128
- const { targets: goalMatchedTargets, selectedSurfaceIds } = selectTargetsForGoalMatches(domTargets, rerankedCandidates);
129
- const selectedTargets = prioritizeGoalActionTargets(instruction, expandWorkflowGraphTargets(domTargets, goalMatchedTargets, { selectedSurfaceIds }));
130
- const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets, {
131
- allSurfaceInputs: surfaceInputs,
132
- explicitSurfaceIds: selectedSurfaceIds,
153
+ const resolvedPage = await tracedStepOperation(() => resolveCurrentPageContext(browser, session), {
154
+ spanName: 'agentbrowse.observe.resolve_page_context',
155
+ attributes: observePhaseAttributes,
133
156
  });
157
+ pageRef = resolvedPage.pageRef;
158
+ const page = resolvedPage.page;
159
+ const { url, title } = await tracedStepOperation(() => syncSessionPage(session, pageRef, page), {
160
+ spanName: 'agentbrowse.observe.sync_session_page',
161
+ attributes: observePhaseAttributes,
162
+ });
163
+ bumpPageScopeEpoch(session, pageRef);
164
+ setCurrentPage(session, pageRef);
165
+ const collectedTargets = await tracedStepOperation(() => collectDomTargets(page), {
166
+ spanName: 'agentbrowse.observe.collect_dom_targets',
167
+ attributes: observePhaseAttributes,
168
+ });
169
+ let observeAccessibilityStats;
170
+ const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await tracedStepOperation(() => enrichDomTargetsWithAccessibility(page, collectedTargets, {
171
+ onStats: (stats) => {
172
+ observeAccessibilityStats = stats;
173
+ },
174
+ }), {
175
+ spanName: 'agentbrowse.observe.enrich_accessibility',
176
+ attributes: observePhaseAttributes,
177
+ }))));
178
+ if (observeAccessibilityStats) {
179
+ incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
180
+ incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
181
+ incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
182
+ }
183
+ const signals = compactSignals(await tracedStepOperation(() => collectPageSignals(page).catch(() => []), {
184
+ spanName: 'agentbrowse.observe.collect_page_signals',
185
+ attributes: observePhaseAttributes,
186
+ }));
187
+ const pageState = classifyObservePageState(signals);
188
+ const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets);
134
189
  observedScopes = persisted.observedScopes;
135
190
  const surfaceRefMap = persisted.surfaceRefMap;
136
- const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
137
- reconcileObservedTargetsForPage(session, pageRef, targets);
138
- attachObservedTargetOwners(domTargets, targets);
139
- observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
140
- const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
141
- ? clearProtectedFillableFormsForPage(session, pageRef)
142
- : await persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString());
143
- if (selectedTargets.length > 0 || selectedSurfaceIds.size > 0) {
144
- const projectedTargets = projectPersistedTargetsForGoal(domTargets, targets, selectedTargets);
145
- const explicitScopeRefs = buildGoalProjectionScopeRefs(projectedTargets, selectedSurfaceIds, surfaceRefMap);
191
+ if (domTargets.length > 0) {
192
+ const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
193
+ reconcileObservedTargetsForPage(session, pageRef, targets);
194
+ attachObservedTargetOwners(domTargets, targets);
195
+ observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
196
+ const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
197
+ ? clearProtectedFillableFormsForPage(session, pageRef)
198
+ : await tracedStepOperation(() => persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString()), {
199
+ spanName: 'agentbrowse.observe.persist_fillable_forms',
200
+ attributes: {
201
+ ...observePhaseAttributes,
202
+ 'agentbrowse.observe.target_count': targets.length,
203
+ },
204
+ });
146
205
  saveSession(session);
147
- disconnectPlaywright(browser);
206
+ await disconnectPlaywright(browser);
148
207
  browser = null;
149
- outputJSON({
208
+ return emitObserveSuccess(session, observeStep, {
150
209
  success: true,
151
210
  pageRef,
152
- resolvedBy: 'dom-rerank',
211
+ resolvedBy: 'dom',
153
212
  ...domRuntimeResolution(),
154
213
  scopes: buildGroupedObserveScopes({
155
214
  pageRef,
156
215
  title,
157
- scopes: selectScopesForOutput(observedScopes, projectedTargets, explicitScopeRefs),
158
- targets: projectedTargets,
216
+ scopes: selectScopesForOutput(observedScopes, targets),
217
+ targets,
159
218
  }),
160
219
  signals,
161
220
  fillableForms: compactFillableForms(fillableForms),
162
221
  metrics: session.runtime?.metrics,
222
+ message: targets.length === 0 ? 'No targets found.' : undefined,
163
223
  url,
164
224
  title,
165
225
  });
166
- return;
167
226
  }
168
- saveSession(session);
169
- disconnectPlaywright(browser);
170
- browser = null;
171
- outputJSON({
172
- success: true,
173
- pageRef,
174
- resolvedBy: 'dom-rerank',
175
- ...domRuntimeResolution(),
176
- scopes: [],
177
- signals,
178
- fillableForms: compactFillableForms(fillableForms),
179
- metrics: session.runtime?.metrics,
180
- message: 'No targets matched the requested goal.',
181
- url,
182
- title,
227
+ stagehandFallbackReason = 'deterministic-observe-empty';
228
+ }
229
+ catch (err) {
230
+ domPassError = err instanceof Error ? err.message : String(err);
231
+ stagehandFallbackReason = 'deterministic-observe-failed';
232
+ }
233
+ }
234
+ if (instruction) {
235
+ try {
236
+ if (!browser) {
237
+ browser = await tracedStepOperation(() => connectPlaywright(session.cdpUrl), {
238
+ spanName: 'agentbrowse.observe.connect_browser',
239
+ attributes: observePhaseAttributes,
240
+ });
241
+ }
242
+ const resolvedPage = await tracedStepOperation(() => resolveCurrentPageContext(browser, session), {
243
+ spanName: 'agentbrowse.observe.resolve_page_context',
244
+ attributes: observePhaseAttributes,
245
+ });
246
+ pageRef = resolvedPage.pageRef;
247
+ const page = resolvedPage.page;
248
+ const { url, title } = await tracedStepOperation(() => syncSessionPage(session, pageRef, page), {
249
+ spanName: 'agentbrowse.observe.sync_session_page',
250
+ attributes: observePhaseAttributes,
251
+ });
252
+ bumpPageScopeEpoch(session, pageRef);
253
+ setCurrentPage(session, pageRef);
254
+ const collectedTargets = await tracedStepOperation(() => collectDomTargets(page, {
255
+ includeActivationAffordances: true,
256
+ }), {
257
+ spanName: 'agentbrowse.observe.collect_dom_targets',
258
+ attributes: observePhaseAttributes,
259
+ });
260
+ let observeAccessibilityStats;
261
+ const domTargets = compressSemanticallyDuplicateTargets(orderBySurfaceCompetition(annotateDomTargets(await tracedStepOperation(() => enrichDomTargetsWithAccessibility(page, collectedTargets, {
262
+ onStats: (stats) => {
263
+ observeAccessibilityStats = stats;
264
+ },
265
+ }), {
266
+ spanName: 'agentbrowse.observe.enrich_accessibility',
267
+ attributes: observePhaseAttributes,
268
+ }))));
269
+ if (observeAccessibilityStats) {
270
+ incrementMetric(session, 'observeAxAttempts', observeAccessibilityStats.axAttempts);
271
+ incrementMetric(session, 'observeAxHits', observeAccessibilityStats.axHits);
272
+ incrementMetric(session, 'observeFallbackUses', observeAccessibilityStats.fallbackUses);
273
+ }
274
+ const signals = compactSignals(await tracedStepOperation(() => collectPageSignals(page).catch(() => []), {
275
+ spanName: 'agentbrowse.observe.collect_page_signals',
276
+ attributes: observePhaseAttributes,
277
+ }));
278
+ const pageState = classifyObservePageState(signals);
279
+ const surfaceInputs = collectSurfaceDescriptors(pageRef, domTargets);
280
+ if (domTargets.length > 0) {
281
+ const rerankedCandidates = await tracedStepOperation(() => rerankDomTargetsForGoal(instruction, buildGoalObserveInventoryCandidates(domTargets, surfaceInputs), { session }), {
282
+ spanName: 'agentbrowse.observe.rerank_goal_candidates',
283
+ attributes: {
284
+ ...observePhaseAttributes,
285
+ 'agentbrowse.observe.target_count': domTargets.length,
286
+ },
287
+ });
288
+ const { targets: goalMatchedTargets, selectedSurfaceIds } = selectTargetsForGoalMatches(domTargets, rerankedCandidates);
289
+ const selectedTargets = prioritizeGoalActionTargets(instruction, expandWorkflowGraphTargets(domTargets, goalMatchedTargets, { selectedSurfaceIds }));
290
+ const persisted = persistObservedSurfacesForPage(session, pageRef, domTargets, {
291
+ allSurfaceInputs: surfaceInputs,
292
+ explicitSurfaceIds: selectedSurfaceIds,
293
+ });
294
+ observedScopes = persisted.observedScopes;
295
+ const surfaceRefMap = persisted.surfaceRefMap;
296
+ const targets = replaceTargetsForPage(session, pageRef, domTargets.map((target) => toDomDescriptor(pageRef, target, surfaceRefMap)));
297
+ reconcileObservedTargetsForPage(session, pageRef, targets);
298
+ attachObservedTargetOwners(domTargets, targets);
299
+ observedScopes = linkObservedSurfaceGraph(session, pageRef, domTargets, targets, observedScopes, surfaceRefMap);
300
+ const fillableForms = shouldSuppressFillableFormsForObserve(pageState)
301
+ ? clearProtectedFillableFormsForPage(session, pageRef)
302
+ : await tracedStepOperation(() => persistProtectedFillableFormsForPage(session, pageRef, url, targets, new Date().toISOString()), {
303
+ spanName: 'agentbrowse.observe.persist_fillable_forms',
304
+ attributes: {
305
+ ...observePhaseAttributes,
306
+ 'agentbrowse.observe.target_count': targets.length,
307
+ },
308
+ });
309
+ if (selectedTargets.length > 0 || selectedSurfaceIds.size > 0) {
310
+ const projectedTargets = projectPersistedTargetsForGoal(domTargets, targets, selectedTargets);
311
+ const explicitScopeRefs = buildGoalProjectionScopeRefs(projectedTargets, selectedSurfaceIds, surfaceRefMap);
312
+ saveSession(session);
313
+ await disconnectPlaywright(browser);
314
+ browser = null;
315
+ return emitObserveSuccess(session, observeStep, {
316
+ success: true,
317
+ pageRef,
318
+ resolvedBy: 'dom-rerank',
319
+ ...domRuntimeResolution(),
320
+ scopes: buildGroupedObserveScopes({
321
+ pageRef,
322
+ title,
323
+ scopes: selectScopesForOutput(observedScopes, projectedTargets, explicitScopeRefs),
324
+ targets: projectedTargets,
325
+ }),
326
+ signals,
327
+ fillableForms: compactFillableForms(fillableForms),
328
+ metrics: session.runtime?.metrics,
329
+ url,
330
+ title,
331
+ });
332
+ }
333
+ saveSession(session);
334
+ await disconnectPlaywright(browser);
335
+ browser = null;
336
+ return emitObserveSuccess(session, observeStep, {
337
+ success: true,
338
+ pageRef,
339
+ resolvedBy: 'dom-rerank',
340
+ ...domRuntimeResolution(),
341
+ scopes: [],
342
+ signals,
343
+ fillableForms: compactFillableForms(fillableForms),
344
+ metrics: session.runtime?.metrics,
345
+ message: 'No targets matched the requested goal.',
346
+ url,
347
+ title,
348
+ });
349
+ }
350
+ stagehandFallbackReason = 'deterministic-observe-empty';
351
+ }
352
+ catch (err) {
353
+ domPassError = err instanceof Error ? err.message : String(err);
354
+ stagehandFallbackReason = 'deterministic-observe-failed';
355
+ }
356
+ }
357
+ try {
358
+ if (!browser) {
359
+ browser = await tracedStepOperation(() => connectPlaywright(session.cdpUrl), {
360
+ spanName: 'agentbrowse.observe.connect_browser',
361
+ attributes: observePhaseAttributes,
183
362
  });
184
- return;
185
363
  }
186
- stagehandFallbackReason = 'deterministic-observe-empty';
187
364
  }
188
365
  catch (err) {
189
- domPassError = err instanceof Error ? err.message : String(err);
190
- stagehandFallbackReason = 'deterministic-observe-failed';
191
- }
192
- }
193
- try {
194
- if (!browser) {
195
- browser = await connectPlaywright(session.cdpUrl);
366
+ const domFailure = domPassError && domPassError.length > 0 ? `; dom observe failed: ${domPassError}` : '';
367
+ return emitObserveContractFailure(session, {
368
+ error: 'browser_connection_failed',
369
+ outcomeType: 'blocked',
370
+ message: 'Observe could not start because AgentBrowse failed to connect to the browser.',
371
+ reason: `${err instanceof Error ? err.message : String(err)}${domFailure}`,
372
+ pageRef,
373
+ runId: session.activeRunId,
374
+ stepId: observeStep?.stepId,
375
+ });
196
376
  }
197
- }
198
- catch (err) {
199
- const domFailure = domPassError && domPassError.length > 0 ? `; dom observe failed: ${domPassError}` : '';
200
- outputContractFailure({
201
- error: 'browser_connection_failed',
202
- outcomeType: 'blocked',
203
- message: 'Observe could not start because AgentBrowse failed to connect to the browser.',
204
- reason: `${err instanceof Error ? err.message : String(err)}${domFailure}`,
205
- pageRef,
206
- });
207
- }
208
- try {
209
- const resolvedPage = await resolveCurrentPageContext(browser, session);
210
- pageRef = resolvedPage.pageRef;
211
- const page = resolvedPage.page;
212
- const { url, title } = await syncSessionPage(session, pageRef, page);
213
- bumpPageScopeEpoch(session, pageRef);
214
- setCurrentPage(session, pageRef);
215
- const signals = compactSignals(await collectPageSignals(page).catch(() => []));
216
- const actions = await withStagehand(session, async (stagehand) => {
217
- incrementMetric(session, 'stagehandCalls');
218
- return instruction
219
- ? (await stagehand.observe(instruction, { page }))
220
- : (await stagehand.observe({ page }));
221
- });
222
- const targets = replaceTargetsForPage(session, pageRef, await Promise.all(actions.map((action) => toStagehandDescriptor(pageRef, action, page, normalizePageSignature(url)))));
223
- const fillableForms = clearProtectedFillableFormsForPage(session, pageRef);
224
- saveSession(session);
225
- outputJSON({
226
- success: true,
227
- pageRef,
228
- resolvedBy: 'stagehand-observe',
229
- ...stagehandRuntimeResolution(stagehandFallbackReason ?? 'deterministic-observe-failed'),
230
- deterministicObserveError: domPassError ?? undefined,
231
- scopes: buildGroupedObserveScopes({
377
+ try {
378
+ const resolvedPage = await tracedStepOperation(() => resolveCurrentPageContext(browser, session), {
379
+ spanName: 'agentbrowse.observe.resolve_page_context',
380
+ attributes: observePhaseAttributes,
381
+ });
382
+ pageRef = resolvedPage.pageRef;
383
+ const page = resolvedPage.page;
384
+ const { url, title } = await tracedStepOperation(() => syncSessionPage(session, pageRef, page), {
385
+ spanName: 'agentbrowse.observe.sync_session_page',
386
+ attributes: observePhaseAttributes,
387
+ });
388
+ bumpPageScopeEpoch(session, pageRef);
389
+ setCurrentPage(session, pageRef);
390
+ const signals = compactSignals(await tracedStepOperation(() => collectPageSignals(page).catch(() => []), {
391
+ spanName: 'agentbrowse.observe.collect_page_signals',
392
+ attributes: observePhaseAttributes,
393
+ }));
394
+ const actions = await tracedStepOperation(() => withStagehand(session, async (stagehand) => {
395
+ incrementMetric(session, 'stagehandCalls');
396
+ return instruction
397
+ ? (await stagehand.observe(instruction, { page }))
398
+ : (await stagehand.observe({ page }));
399
+ }), {
400
+ spanName: 'agentbrowse.observe.stagehand_observe',
401
+ attributes: observePhaseAttributes,
402
+ });
403
+ const targets = replaceTargetsForPage(session, pageRef, await Promise.all(actions.map((action) => toStagehandDescriptor(pageRef, action, page, normalizePageSignature(url)))));
404
+ const fillableForms = markProtectedFillableFormsUnknownForPage(session, pageRef);
405
+ saveSession(session);
406
+ return emitObserveSuccess(session, observeStep, {
407
+ success: true,
232
408
  pageRef,
409
+ resolvedBy: 'stagehand-observe',
410
+ ...stagehandRuntimeResolution(stagehandFallbackReason ?? 'deterministic-observe-failed'),
411
+ deterministicObserveError: domPassError ?? undefined,
412
+ scopes: buildGroupedObserveScopes({
413
+ pageRef,
414
+ title,
415
+ scopes: selectScopesForOutput(observedScopes, targets),
416
+ targets,
417
+ }),
418
+ signals,
419
+ fillableForms: compactFillableForms(fillableForms),
420
+ metrics: session.runtime?.metrics,
421
+ message: targets.length === 0 ? 'No targets found.' : undefined,
422
+ url,
233
423
  title,
234
- scopes: selectScopesForOutput(observedScopes, targets),
235
- targets,
236
- }),
237
- signals,
238
- fillableForms: compactFillableForms(fillableForms),
239
- metrics: session.runtime?.metrics,
240
- message: targets.length === 0 ? 'No targets found.' : undefined,
241
- url,
242
- title,
243
- });
244
- }
245
- catch (err) {
246
- const stagehandError = err instanceof Error ? err.message : String(err);
247
- const details = domPassError
248
- ? `${stagehandError} (deterministic observe failed earlier: ${domPassError})`
249
- : stagehandError;
250
- outputContractFailure({
251
- error: 'observe_failed',
252
- outcomeType: 'blocked',
253
- message: 'Observe failed.',
254
- reason: details,
255
- pageRef,
256
- });
257
- }
258
- finally {
259
- if (browser) {
260
- disconnectPlaywright(browser);
424
+ });
261
425
  }
262
- }
426
+ catch (err) {
427
+ const stagehandError = err instanceof Error ? err.message : String(err);
428
+ const details = domPassError
429
+ ? `${stagehandError} (deterministic observe failed earlier: ${domPassError})`
430
+ : stagehandError;
431
+ return emitObserveContractFailure(session, {
432
+ error: 'observe_failed',
433
+ outcomeType: 'blocked',
434
+ message: 'Observe failed.',
435
+ reason: details,
436
+ pageRef,
437
+ runId: session.activeRunId,
438
+ stepId: observeStep?.stepId,
439
+ });
440
+ }
441
+ finally {
442
+ if (browser) {
443
+ await disconnectPlaywright(browser);
444
+ }
445
+ }
446
+ });
263
447
  }