@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,9 +2,13 @@
2
2
  * browse close — Close the browser and clean up session.
3
3
  */
4
4
  import { deleteSession, isOwnedSession, loadSession } from '../session.js';
5
+ import { finishRunRecord, finishRunStep, pruneLocalRuns, startRunStep } from '../run-store.js';
6
+ import { appendCommandLifecycleEventBestEffort, captureStepSnapshotBestEffort, } from '../run-observability.js';
7
+ import { exportRunRootToOtlpHttpJsonBestEffort, exportRunStepToOtlpHttpJsonBestEffort, } from '../otel-exporter.js';
5
8
  import { info } from '../output.js';
6
9
  import { closeOwnedBrowser } from '../owned-browser.js';
7
10
  import { isManagedBrowserPid } from '../owned-process.js';
11
+ import { completeWorkflowSessionRemote } from '../workflow-session-completion.js';
8
12
  function isCloseableManagedSession(session) {
9
13
  if (!session) {
10
14
  return false;
@@ -14,11 +18,100 @@ function isCloseableManagedSession(session) {
14
18
  }
15
19
  return !session.identity && isManagedBrowserPid(session.pid);
16
20
  }
21
+ function formatUnknownError(error) {
22
+ if (error instanceof Error) {
23
+ return error.message;
24
+ }
25
+ if (typeof error === 'string') {
26
+ return error;
27
+ }
28
+ if (error && typeof error === 'object') {
29
+ try {
30
+ return JSON.stringify(error);
31
+ }
32
+ catch {
33
+ return Object.prototype.toString.call(error);
34
+ }
35
+ }
36
+ return String(error);
37
+ }
38
+ async function finalizeRunBestEffort(runId, options) {
39
+ if (!runId) {
40
+ return;
41
+ }
42
+ try {
43
+ finishRunRecord(runId, {
44
+ status: options.status,
45
+ finalOutcome: {
46
+ success: options.success,
47
+ outcomeType: options.outcomeType,
48
+ message: options.message,
49
+ ...(options.reason ? { reason: options.reason } : {}),
50
+ },
51
+ });
52
+ }
53
+ catch (error) {
54
+ info(`[close] failed to finalize local run ${runId}: ${formatUnknownError(error)}`);
55
+ }
56
+ }
57
+ function pruneLocalRunsBestEffort() {
58
+ try {
59
+ const result = pruneLocalRuns();
60
+ if (result.deletedRunIds.length > 0) {
61
+ info(`[close] pruned stale local run${result.deletedRunIds.length === 1 ? '' : 's'} ${result.deletedRunIds.join(', ')}`);
62
+ }
63
+ if (result.failedRunIds.length > 0) {
64
+ info(`[close] failed to prune local run${result.failedRunIds.length === 1 ? '' : 's'} ${result.failedRunIds.map((entry) => `${entry.runId}: ${entry.reason}`).join('; ')}`);
65
+ }
66
+ }
67
+ catch (error) {
68
+ info(`[close] local run prune failed: ${formatUnknownError(error)}`);
69
+ }
70
+ }
17
71
  export async function close() {
18
72
  const session = loadSession();
73
+ const closeStep = session?.activeRunId
74
+ ? startRunStep({
75
+ runId: session.activeRunId,
76
+ command: 'close',
77
+ input: {
78
+ hadSession: session !== null,
79
+ closeableManagedSession: isCloseableManagedSession(session),
80
+ },
81
+ })
82
+ : null;
83
+ if (session) {
84
+ captureStepSnapshotBestEffort({
85
+ session,
86
+ step: closeStep,
87
+ phase: 'before',
88
+ });
89
+ }
90
+ appendCommandLifecycleEventBestEffort({
91
+ step: closeStep,
92
+ phase: 'started',
93
+ attributes: {
94
+ hadSession: session !== null,
95
+ closeableManagedSession: isCloseableManagedSession(session),
96
+ },
97
+ });
19
98
  if (isCloseableManagedSession(session)) {
20
99
  const closeResult = await closeOwnedBrowser(session);
21
100
  if (!closeResult.success) {
101
+ appendCommandLifecycleEventBestEffort({
102
+ step: closeStep,
103
+ phase: 'failed',
104
+ attributes: {
105
+ outcomeType: 'browser_close_failed',
106
+ reason: closeResult.reason,
107
+ },
108
+ });
109
+ await finalizeStepBestEffort(session?.activeRunId, closeStep?.stepId, {
110
+ success: false,
111
+ outcomeType: 'browser_close_failed',
112
+ message: 'Browser close failed.',
113
+ reason: closeResult.reason,
114
+ });
22
115
  info(`Owned browser close failed; keeping session record: ${closeResult.reason}`);
23
116
  return {
24
117
  success: false,
@@ -30,8 +123,93 @@ export async function close() {
30
123
  }
31
124
  info(`Closed owned browser via ${closeResult.method}`);
32
125
  }
126
+ if (session?.intentSessionId) {
127
+ const remoteCompletion = await completeWorkflowSessionRemote({
128
+ session,
129
+ stepId: closeStep?.stepId,
130
+ command: 'close',
131
+ terminalStatus: 'canceled',
132
+ runStatus: 'aborted',
133
+ summary: 'Browser session closed before the workflow completed.',
134
+ outcomeType: 'workflow_session_canceled',
135
+ message: 'Workflow session canceled because the browser was closed.',
136
+ reason: 'The active browser session was closed by the close command.',
137
+ });
138
+ if (!remoteCompletion.success) {
139
+ const reason = remoteCompletion.reason;
140
+ const failureError = remoteCompletion.error === 'backend_session_complete_failed'
141
+ ? 'workflow_session_complete_failed'
142
+ : remoteCompletion.error;
143
+ const failureMessage = 'Browser closed but workflow session completion failed.';
144
+ appendCommandLifecycleEventBestEffort({
145
+ step: closeStep,
146
+ phase: 'failed',
147
+ attributes: {
148
+ outcomeType: remoteCompletion.error === 'backend_session_complete_failed'
149
+ ? 'workflow_session_complete_failed'
150
+ : remoteCompletion.error,
151
+ reason,
152
+ },
153
+ });
154
+ await finalizeStepBestEffort(session?.activeRunId, closeStep?.stepId, {
155
+ success: false,
156
+ outcomeType: remoteCompletion.error === 'backend_session_complete_failed'
157
+ ? 'workflow_session_complete_failed'
158
+ : remoteCompletion.error,
159
+ message: failureMessage,
160
+ reason,
161
+ skipExport: true,
162
+ });
163
+ return {
164
+ success: false,
165
+ error: failureError,
166
+ outcomeType: remoteCompletion.error === 'backend_session_complete_failed' ? 'failed' : 'blocked',
167
+ message: failureMessage,
168
+ reason,
169
+ };
170
+ }
171
+ }
172
+ appendCommandLifecycleEventBestEffort({
173
+ step: closeStep,
174
+ phase: 'completed',
175
+ attributes: {
176
+ outcomeType: 'browser_closed',
177
+ },
178
+ });
33
179
  if (session) {
34
180
  deleteSession();
35
181
  }
182
+ await finalizeStepBestEffort(session?.activeRunId, closeStep?.stepId, {
183
+ success: true,
184
+ outcomeType: 'browser_closed',
185
+ message: 'Browser session closed.',
186
+ });
187
+ await finalizeRunBestEffort(session?.activeRunId, {
188
+ status: 'aborted',
189
+ success: false,
190
+ outcomeType: 'browser_closed',
191
+ message: 'Browser session closed.',
192
+ reason: 'The active browser session was closed by the close command.',
193
+ });
194
+ await exportRunRootToOtlpHttpJsonBestEffort(session?.activeRunId);
195
+ pruneLocalRunsBestEffort();
36
196
  return { success: true };
37
197
  }
198
+ async function finalizeStepBestEffort(runId, stepId, options) {
199
+ if (!runId || !stepId) {
200
+ return;
201
+ }
202
+ try {
203
+ finishRunStep({
204
+ runId,
205
+ stepId,
206
+ ...options,
207
+ });
208
+ }
209
+ catch (error) {
210
+ info(`[close] failed to finalize local run step ${stepId}: ${formatUnknownError(error)}`);
211
+ }
212
+ if (!options.skipExport) {
213
+ await exportRunStepToOtlpHttpJsonBestEffort(runId, stepId);
214
+ }
215
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"descriptor-validation.d.ts","sourceRoot":"","sources":["../../src/commands/descriptor-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,eAAO,MAAM,4BAA4B,QAaxC,CAAC;AAEF,iBAAS,gCAAgC,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAwBF,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWtF;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAWxC;AAOD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,sBAAsB,GAAG,IAAI,GACtC,OAAO,CAoCT;AAED,eAAO,MAAM,0BAA0B;;;;;CAKtC,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6EnF"}
1
+ {"version":3,"file":"descriptor-validation.d.ts","sourceRoot":"","sources":["../../src/commands/descriptor-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,eAAO,MAAM,4BAA4B,QAaxC,CAAC;AAEF,iBAAS,gCAAgC,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAiGF,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWtF;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAWxC;AAOD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,sBAAsB,GAAG,IAAI,GACtC,OAAO,CAoCT;AAED,eAAO,MAAM,0BAA0B;;;;;CAKtC,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQnF"}
@@ -46,6 +46,78 @@ const LOCATOR_BINDING_SNAPSHOT_SCRIPT = String.raw `
46
46
  autocomplete: element.getAttribute('autocomplete')?.trim() || undefined,
47
47
  };
48
48
  `;
49
+ const LOCATOR_OUTER_HTML_SCRIPT = String.raw `
50
+ if (!(element instanceof HTMLElement)) {
51
+ return null;
52
+ }
53
+
54
+ const ownerWindow = element.ownerDocument?.defaultView || window;
55
+ const TextCtor = ownerWindow.Text;
56
+ const ElementCtor = ownerWindow.Element;
57
+ const ShadowRootCtor = ownerWindow.ShadowRoot;
58
+ const voidTags = new Set([
59
+ 'area',
60
+ 'base',
61
+ 'br',
62
+ 'col',
63
+ 'embed',
64
+ 'hr',
65
+ 'img',
66
+ 'input',
67
+ 'link',
68
+ 'meta',
69
+ 'param',
70
+ 'source',
71
+ 'track',
72
+ 'wbr',
73
+ ]);
74
+
75
+ const escapeText = (value) =>
76
+ value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
77
+
78
+ const escapeAttribute = (value) =>
79
+ value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
80
+
81
+ const serializeChildren = (parent) =>
82
+ Array.from(parent.childNodes)
83
+ .map((node) => serializeNode(node))
84
+ .join('');
85
+
86
+ const serializeNode = (node) => {
87
+ if (node instanceof TextCtor) {
88
+ return escapeText(node.textContent ?? '');
89
+ }
90
+
91
+ if (!(node instanceof ElementCtor)) {
92
+ return '';
93
+ }
94
+
95
+ const tag = node.tagName.toLowerCase();
96
+ if (['script', 'style', 'noscript', 'template'].includes(tag)) {
97
+ return '';
98
+ }
99
+
100
+ const attrs = node
101
+ .getAttributeNames()
102
+ .sort()
103
+ .map((name) => ' ' + name + '="' + escapeAttribute(node.getAttribute(name) ?? '') + '"')
104
+ .join('');
105
+ const shadowRoot =
106
+ node.shadowRoot && node.shadowRoot instanceof ShadowRootCtor ? node.shadowRoot : null;
107
+ const shadowHtml = shadowRoot
108
+ ? '<div data-agentbrowse-shadow-root="open">' + serializeChildren(shadowRoot) + '</div>'
109
+ : '';
110
+ const childHtml = serializeChildren(node);
111
+
112
+ if (voidTags.has(tag)) {
113
+ return '<' + tag + attrs + '>' + shadowHtml;
114
+ }
115
+
116
+ return '<' + tag + attrs + '>' + shadowHtml + childHtml + '</' + tag + '>';
117
+ };
118
+
119
+ return serializeNode(element);
120
+ `;
49
121
  export async function readLocatorDomSignature(locator) {
50
122
  try {
51
123
  return await locator
@@ -110,63 +182,9 @@ export const __testDescriptorValidation = {
110
182
  };
111
183
  export async function readLocatorOuterHtml(locator) {
112
184
  try {
113
- return await locator.first().evaluate((element) => {
114
- if (!(element instanceof HTMLElement)) {
115
- return null;
116
- }
117
- const ownerWindow = element.ownerDocument?.defaultView || window;
118
- const TextCtor = ownerWindow.Text;
119
- const ElementCtor = ownerWindow.Element;
120
- const ShadowRootCtor = ownerWindow.ShadowRoot;
121
- const voidTags = new Set([
122
- 'area',
123
- 'base',
124
- 'br',
125
- 'col',
126
- 'embed',
127
- 'hr',
128
- 'img',
129
- 'input',
130
- 'link',
131
- 'meta',
132
- 'param',
133
- 'source',
134
- 'track',
135
- 'wbr',
136
- ]);
137
- const escapeText = (value) => value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
138
- const escapeAttribute = (value) => value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
139
- const serializeChildren = (parent) => Array.from(parent.childNodes)
140
- .map((node) => serializeNode(node))
141
- .join('');
142
- const serializeNode = (node) => {
143
- if (node instanceof TextCtor) {
144
- return escapeText(node.textContent ?? '');
145
- }
146
- if (!(node instanceof ElementCtor)) {
147
- return '';
148
- }
149
- const tag = node.tagName.toLowerCase();
150
- if (['script', 'style', 'noscript', 'template'].includes(tag)) {
151
- return '';
152
- }
153
- const attrs = node
154
- .getAttributeNames()
155
- .sort()
156
- .map((name) => ` ${name}="${escapeAttribute(node.getAttribute(name) ?? '')}"`)
157
- .join('');
158
- const shadowRoot = node.shadowRoot && node.shadowRoot instanceof ShadowRootCtor ? node.shadowRoot : null;
159
- const shadowHtml = shadowRoot
160
- ? `<div data-agentbrowse-shadow-root="open">${serializeChildren(shadowRoot)}</div>`
161
- : '';
162
- const childHtml = serializeChildren(node);
163
- if (voidTags.has(tag)) {
164
- return `<${tag}${attrs}>${shadowHtml}`;
165
- }
166
- return `<${tag}${attrs}>${shadowHtml}${childHtml}</${tag}>`;
167
- };
168
- return serializeNode(element);
169
- });
185
+ return await locator
186
+ .first()
187
+ .evaluate((element, source) => Function('element', source)(element), LOCATOR_OUTER_HTML_SCRIPT);
170
188
  }
171
189
  catch {
172
190
  return null;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * browse end-session — Mark the current workflow session as completed without closing the browser.
3
+ */
4
+ import { type BrowseSession } from '../session.js';
5
+ export type EndSessionSuccessResult = {
6
+ success: true;
7
+ runId: string;
8
+ intentSessionId: string;
9
+ status: string;
10
+ lastEventSeq: number;
11
+ browserSessionId: string | null;
12
+ completedAt: string;
13
+ outcomeType: 'workflow_session_completed';
14
+ message: 'Workflow session completed.';
15
+ };
16
+ export type EndSessionFailureResult = {
17
+ success: false;
18
+ error: 'workflow_session_unavailable' | 'workflow_run_unavailable' | 'workflow_step_unavailable' | 'backend_session_complete_failed';
19
+ outcomeType: 'blocked' | 'failed';
20
+ message: 'Workflow session end failed.';
21
+ reason: string;
22
+ };
23
+ export type EndSessionResult = EndSessionSuccessResult | EndSessionFailureResult;
24
+ export declare function endSession(session: BrowseSession): Promise<EndSessionResult>;
25
+ //# sourceMappingURL=end-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end-session.d.ts","sourceRoot":"","sources":["../../src/commands/end-session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAOhE,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,4BAA4B,CAAC;IAC1C,OAAO,EAAE,6BAA6B,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EACD,8BAA8B,GAC9B,0BAA0B,GAC1B,2BAA2B,GAC3B,iCAAiC,CAAC;IACtC,WAAW,EAAE,SAAS,GAAG,QAAQ,CAAC;IAClC,OAAO,EAAE,8BAA8B,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AA0DjF,wBAAsB,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0IlF"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * browse end-session — Mark the current workflow session as completed without closing the browser.
3
+ */
4
+ import { withApiTraceContext } from '../command-api-tracing.js';
5
+ import { exportRunRootToOtlpHttpJsonBestEffort, exportRunStepToOtlpHttpJsonBestEffort, } from '../otel-exporter.js';
6
+ import { info } from '../output.js';
7
+ import { appendCommandLifecycleEventBestEffort, captureStepSnapshotBestEffort, } from '../run-observability.js';
8
+ import { finishRunRecord, finishRunStep, startRunStep } from '../run-store.js';
9
+ import { saveSession } from '../session.js';
10
+ import { clearWorkflowState, completeWorkflowSessionRemote, formatUnknownWorkflowCompletionError, } from '../workflow-session-completion.js';
11
+ function finalizeEndSessionStepBestEffort(runId, stepId, options) {
12
+ if (!runId || !stepId) {
13
+ return;
14
+ }
15
+ try {
16
+ finishRunStep({
17
+ runId,
18
+ stepId,
19
+ ...options,
20
+ });
21
+ }
22
+ catch (error) {
23
+ info(`[end-session] failed to finalize local run step ${stepId}: ${formatUnknownWorkflowCompletionError(error)}`);
24
+ }
25
+ }
26
+ function finalizeRunRecordBestEffort(runId, options) {
27
+ if (!runId) {
28
+ return;
29
+ }
30
+ try {
31
+ finishRunRecord(runId, {
32
+ status: options.status,
33
+ finalOutcome: {
34
+ success: options.success,
35
+ ...(options.outcomeType ? { outcomeType: options.outcomeType } : {}),
36
+ ...(options.message ? { message: options.message } : {}),
37
+ ...(options.reason ? { reason: options.reason } : {}),
38
+ },
39
+ });
40
+ }
41
+ catch (error) {
42
+ info(`[end-session] failed to finalize local run ${runId}: ${formatUnknownWorkflowCompletionError(error)}`);
43
+ }
44
+ }
45
+ export async function endSession(session) {
46
+ const endSessionStep = session.activeRunId
47
+ ? startRunStep({
48
+ runId: session.activeRunId,
49
+ command: 'end-session',
50
+ input: {
51
+ hasWorkflowSession: Boolean(session.intentSessionId),
52
+ currentRequestId: session.currentRequestId ?? null,
53
+ },
54
+ })
55
+ : null;
56
+ const endSessionStepHandle = session.activeRunId && endSessionStep?.stepId
57
+ ? {
58
+ runId: session.activeRunId,
59
+ stepId: endSessionStep.stepId,
60
+ command: 'end-session',
61
+ }
62
+ : null;
63
+ captureStepSnapshotBestEffort({
64
+ session,
65
+ step: endSessionStepHandle,
66
+ phase: 'before',
67
+ pageRef: session.runtime?.currentPageRef,
68
+ });
69
+ appendCommandLifecycleEventBestEffort({
70
+ step: endSessionStepHandle,
71
+ phase: 'started',
72
+ attributes: {
73
+ hasWorkflowSession: Boolean(session.intentSessionId),
74
+ currentRequestId: session.currentRequestId ?? null,
75
+ pageRef: session.runtime?.currentPageRef,
76
+ },
77
+ });
78
+ return withApiTraceContext({
79
+ runId: session.activeRunId,
80
+ stepId: endSessionStep?.stepId,
81
+ command: 'end-session',
82
+ }, async () => {
83
+ const remoteCompletion = await completeWorkflowSessionRemote({
84
+ session,
85
+ stepId: endSessionStep?.stepId,
86
+ command: 'end-session',
87
+ terminalStatus: 'completed',
88
+ runStatus: 'completed',
89
+ summary: 'Workflow session completed.',
90
+ outcomeType: 'workflow_session_completed',
91
+ message: 'Workflow session completed.',
92
+ });
93
+ if (!remoteCompletion.success) {
94
+ const outcomeType = remoteCompletion.error === 'backend_session_complete_failed' ? 'backend_session_complete_failed' : 'blocked';
95
+ appendCommandLifecycleEventBestEffort({
96
+ step: endSessionStepHandle,
97
+ phase: 'failed',
98
+ attributes: {
99
+ outcomeType,
100
+ reason: remoteCompletion.reason,
101
+ },
102
+ });
103
+ finalizeEndSessionStepBestEffort(session.activeRunId, endSessionStep?.stepId, {
104
+ success: false,
105
+ outcomeType,
106
+ message: 'Workflow session end failed.',
107
+ reason: remoteCompletion.reason,
108
+ });
109
+ await exportRunStepToOtlpHttpJsonBestEffort(session.activeRunId, endSessionStep?.stepId);
110
+ return {
111
+ success: false,
112
+ error: remoteCompletion.error,
113
+ outcomeType: remoteCompletion.error === 'backend_session_complete_failed' ? 'failed' : 'blocked',
114
+ message: 'Workflow session end failed.',
115
+ reason: remoteCompletion.reason,
116
+ };
117
+ }
118
+ captureStepSnapshotBestEffort({
119
+ session,
120
+ step: endSessionStepHandle,
121
+ phase: 'after',
122
+ pageRef: session.runtime?.currentPageRef,
123
+ });
124
+ appendCommandLifecycleEventBestEffort({
125
+ step: endSessionStepHandle,
126
+ phase: 'completed',
127
+ attributes: {
128
+ outcomeType: 'workflow_session_completed',
129
+ intentSessionId: remoteCompletion.response.session.id,
130
+ remoteLastEventSeq: remoteCompletion.response.session.last_event_seq,
131
+ pageRef: session.runtime?.currentPageRef,
132
+ },
133
+ });
134
+ finalizeEndSessionStepBestEffort(remoteCompletion.runId, remoteCompletion.stepId ?? undefined, {
135
+ success: true,
136
+ outcomeType: 'workflow_session_completed',
137
+ message: 'Workflow session completed.',
138
+ });
139
+ finalizeRunRecordBestEffort(remoteCompletion.runId, {
140
+ status: 'completed',
141
+ success: true,
142
+ outcomeType: 'workflow_session_completed',
143
+ message: 'Workflow session completed.',
144
+ });
145
+ const nextSession = clearWorkflowState(session);
146
+ saveSession(nextSession);
147
+ await exportRunStepToOtlpHttpJsonBestEffort(remoteCompletion.runId, remoteCompletion.stepId ?? undefined);
148
+ await exportRunRootToOtlpHttpJsonBestEffort(remoteCompletion.runId);
149
+ return {
150
+ success: true,
151
+ runId: remoteCompletion.runId,
152
+ intentSessionId: remoteCompletion.response.session.id,
153
+ status: remoteCompletion.response.session.status,
154
+ lastEventSeq: remoteCompletion.response.session.last_event_seq,
155
+ browserSessionId: remoteCompletion.response.browser_session_id,
156
+ completedAt: remoteCompletion.completedAt,
157
+ outcomeType: 'workflow_session_completed',
158
+ message: 'Workflow session completed.',
159
+ };
160
+ });
161
+ }
@@ -1,7 +1,7 @@
1
1
  import { extract as runExtract } from '@browserbasehq/stagehand/lib/inference.js';
2
2
  import { v3Logger } from '@browserbasehq/stagehand/lib/v3/logger.js';
3
3
  import { captureHybridSnapshot } from '@browserbasehq/stagehand/lib/v3/understudy/a11y/snapshot/index.js';
4
- import { incrementMetric, recordLlmUsage, recordPayloadBudget } from '../runtime-state.js';
4
+ import { incrementMetric, recordLlmUsage, recordPayloadBudget } from '../runtime-metrics.js';
5
5
  import { stagehandRuntimeResolution } from '../runtime-resolution.js';
6
6
  import { withStagehand } from '../stagehand-runtime.js';
7
7
  import { readLocatorOuterHtml } from './descriptor-validation.js';
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAmOnD,wBAAsB,OAAO,CAC3B,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA6Of"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAyUnD,wBAAsB,OAAO,CAC3B,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA8Sf"}