@depup/openai 7.32.0-depup.0 → 7.34.0-depup.0

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 (281) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +2 -2
  3. package/changes.json +1 -1
  4. package/helpers/browser.d.mts +634 -0
  5. package/helpers/browser.d.mts.map +1 -0
  6. package/helpers/browser.d.ts +634 -0
  7. package/helpers/browser.d.ts.map +1 -0
  8. package/helpers/browser.js +1148 -0
  9. package/helpers/browser.js.map +1 -0
  10. package/helpers/browser.mjs +1143 -0
  11. package/helpers/browser.mjs.map +1 -0
  12. package/helpers/computer.d.mts +133 -0
  13. package/helpers/computer.d.mts.map +1 -0
  14. package/helpers/computer.d.ts +133 -0
  15. package/helpers/computer.d.ts.map +1 -0
  16. package/helpers/computer.js +782 -0
  17. package/helpers/computer.js.map +1 -0
  18. package/helpers/computer.mjs +778 -0
  19. package/helpers/computer.mjs.map +1 -0
  20. package/helpers/decisions-tool-runner.d.mts +74 -0
  21. package/helpers/decisions-tool-runner.d.mts.map +1 -0
  22. package/helpers/decisions-tool-runner.d.ts +74 -0
  23. package/helpers/decisions-tool-runner.d.ts.map +1 -0
  24. package/helpers/decisions-tool-runner.js +491 -0
  25. package/helpers/decisions-tool-runner.js.map +1 -0
  26. package/helpers/decisions-tool-runner.mjs +486 -0
  27. package/helpers/decisions-tool-runner.mjs.map +1 -0
  28. package/helpers/responses-tool-runner.d.mts +241 -0
  29. package/helpers/responses-tool-runner.d.mts.map +1 -0
  30. package/helpers/responses-tool-runner.d.ts +241 -0
  31. package/helpers/responses-tool-runner.d.ts.map +1 -0
  32. package/helpers/responses-tool-runner.js +2525 -0
  33. package/helpers/responses-tool-runner.js.map +1 -0
  34. package/helpers/responses-tool-runner.mjs +2519 -0
  35. package/helpers/responses-tool-runner.mjs.map +1 -0
  36. package/index.d.mts +1 -0
  37. package/index.d.mts.map +1 -1
  38. package/index.d.ts +1 -0
  39. package/index.d.ts.map +1 -1
  40. package/index.js +3 -1
  41. package/index.js.map +1 -1
  42. package/index.mjs +1 -0
  43. package/index.mjs.map +1 -1
  44. package/internal/native-response-message.d.mts +4 -0
  45. package/internal/native-response-message.d.mts.map +1 -0
  46. package/internal/native-response-message.d.ts +4 -0
  47. package/internal/native-response-message.d.ts.map +1 -0
  48. package/internal/native-response-message.js +179 -0
  49. package/internal/native-response-message.js.map +1 -0
  50. package/internal/native-response-message.mjs +174 -0
  51. package/internal/native-response-message.mjs.map +1 -0
  52. package/internal/responses/response-accumulator.d.mts +8 -1
  53. package/internal/responses/response-accumulator.d.mts.map +1 -1
  54. package/internal/responses/response-accumulator.d.ts +8 -1
  55. package/internal/responses/response-accumulator.d.ts.map +1 -1
  56. package/internal/responses/response-accumulator.js +54 -30
  57. package/internal/responses/response-accumulator.js.map +1 -1
  58. package/internal/responses/response-accumulator.mjs +50 -30
  59. package/internal/responses/response-accumulator.mjs.map +1 -1
  60. package/internal/runner-diagnostics.d.mts +21 -0
  61. package/internal/runner-diagnostics.d.mts.map +1 -0
  62. package/internal/runner-diagnostics.d.ts +21 -0
  63. package/internal/runner-diagnostics.d.ts.map +1 -0
  64. package/internal/runner-diagnostics.js +57 -0
  65. package/internal/runner-diagnostics.js.map +1 -0
  66. package/internal/runner-diagnostics.mjs +53 -0
  67. package/internal/runner-diagnostics.mjs.map +1 -0
  68. package/internal/runner-lifecycle.d.mts +19 -0
  69. package/internal/runner-lifecycle.d.mts.map +1 -0
  70. package/internal/runner-lifecycle.d.ts +19 -0
  71. package/internal/runner-lifecycle.d.ts.map +1 -0
  72. package/internal/runner-lifecycle.js +230 -0
  73. package/internal/runner-lifecycle.js.map +1 -0
  74. package/internal/runner-lifecycle.mjs +221 -0
  75. package/internal/runner-lifecycle.mjs.map +1 -0
  76. package/internal/utils/log.d.mts.map +1 -1
  77. package/internal/utils/log.d.ts.map +1 -1
  78. package/internal/utils/log.js +4 -0
  79. package/internal/utils/log.js.map +1 -1
  80. package/internal/utils/log.mjs +4 -0
  81. package/internal/utils/log.mjs.map +1 -1
  82. package/lib/beta/agents/parse-result.d.mts +2 -0
  83. package/lib/beta/agents/parse-result.d.mts.map +1 -1
  84. package/lib/beta/agents/parse-result.d.ts +2 -0
  85. package/lib/beta/agents/parse-result.d.ts.map +1 -1
  86. package/lib/responses/ResponseStream.d.mts +2 -2
  87. package/lib/responses/ResponseStream.d.mts.map +1 -1
  88. package/lib/responses/ResponseStream.d.ts +2 -2
  89. package/lib/responses/ResponseStream.d.ts.map +1 -1
  90. package/lib/responses/ResponseStream.js +355 -20
  91. package/lib/responses/ResponseStream.js.map +1 -1
  92. package/lib/responses/ResponseStream.mjs +357 -22
  93. package/lib/responses/ResponseStream.mjs.map +1 -1
  94. package/package.json +3 -3
  95. package/resources/admin/organization/audit-logs.d.mts +1 -1
  96. package/resources/admin/organization/audit-logs.d.mts.map +1 -1
  97. package/resources/admin/organization/audit-logs.d.ts +1 -1
  98. package/resources/admin/organization/audit-logs.d.ts.map +1 -1
  99. package/resources/admin/organization/external-storage.d.mts +15 -3
  100. package/resources/admin/organization/external-storage.d.mts.map +1 -1
  101. package/resources/admin/organization/external-storage.d.ts +15 -3
  102. package/resources/admin/organization/external-storage.d.ts.map +1 -1
  103. package/resources/admin/organization/index.d.mts +2 -2
  104. package/resources/admin/organization/index.d.mts.map +1 -1
  105. package/resources/admin/organization/index.d.ts +2 -2
  106. package/resources/admin/organization/index.d.ts.map +1 -1
  107. package/resources/admin/organization/index.js.map +1 -1
  108. package/resources/admin/organization/index.mjs.map +1 -1
  109. package/resources/admin/organization/organization.d.mts +4 -4
  110. package/resources/admin/organization/organization.d.mts.map +1 -1
  111. package/resources/admin/organization/organization.d.ts +4 -4
  112. package/resources/admin/organization/organization.d.ts.map +1 -1
  113. package/resources/admin/organization/organization.js.map +1 -1
  114. package/resources/admin/organization/organization.mjs.map +1 -1
  115. package/resources/admin/organization/projects/api-keys.d.mts +32 -1
  116. package/resources/admin/organization/projects/api-keys.d.mts.map +1 -1
  117. package/resources/admin/organization/projects/api-keys.d.ts +32 -1
  118. package/resources/admin/organization/projects/api-keys.d.ts.map +1 -1
  119. package/resources/admin/organization/projects/api-keys.js +26 -0
  120. package/resources/admin/organization/projects/api-keys.js.map +1 -1
  121. package/resources/admin/organization/projects/api-keys.mjs +26 -0
  122. package/resources/admin/organization/projects/api-keys.mjs.map +1 -1
  123. package/resources/admin/organization/projects/index.d.mts +1 -1
  124. package/resources/admin/organization/projects/index.d.mts.map +1 -1
  125. package/resources/admin/organization/projects/index.d.ts +1 -1
  126. package/resources/admin/organization/projects/index.d.ts.map +1 -1
  127. package/resources/admin/organization/projects/index.js.map +1 -1
  128. package/resources/admin/organization/projects/index.mjs.map +1 -1
  129. package/resources/admin/organization/projects/projects.d.mts +3 -3
  130. package/resources/admin/organization/projects/projects.d.mts.map +1 -1
  131. package/resources/admin/organization/projects/projects.d.ts +3 -3
  132. package/resources/admin/organization/projects/projects.d.ts.map +1 -1
  133. package/resources/admin/organization/projects/projects.js.map +1 -1
  134. package/resources/admin/organization/projects/projects.mjs.map +1 -1
  135. package/resources/admin/organization/usage.d.mts +202 -1
  136. package/resources/admin/organization/usage.d.mts.map +1 -1
  137. package/resources/admin/organization/usage.d.ts +202 -1
  138. package/resources/admin/organization/usage.d.ts.map +1 -1
  139. package/resources/admin/organization/usage.js +19 -0
  140. package/resources/admin/organization/usage.js.map +1 -1
  141. package/resources/admin/organization/usage.mjs +19 -0
  142. package/resources/admin/organization/usage.mjs.map +1 -1
  143. package/resources/beta/agents/agents.d.mts +28 -10
  144. package/resources/beta/agents/agents.d.mts.map +1 -1
  145. package/resources/beta/agents/agents.d.ts +28 -10
  146. package/resources/beta/agents/agents.d.ts.map +1 -1
  147. package/resources/beta/agents/agents.js.map +1 -1
  148. package/resources/beta/agents/agents.mjs.map +1 -1
  149. package/resources/beta/agents/environments/environments.d.mts +2 -2
  150. package/resources/beta/agents/environments/environments.d.mts.map +1 -1
  151. package/resources/beta/agents/environments/environments.d.ts +2 -2
  152. package/resources/beta/agents/environments/environments.d.ts.map +1 -1
  153. package/resources/beta/agents/environments/files.d.mts +3 -2
  154. package/resources/beta/agents/environments/files.d.mts.map +1 -1
  155. package/resources/beta/agents/environments/files.d.ts +3 -2
  156. package/resources/beta/agents/environments/files.d.ts.map +1 -1
  157. package/resources/beta/agents/environments/files.js +3 -2
  158. package/resources/beta/agents/environments/files.js.map +1 -1
  159. package/resources/beta/agents/environments/files.mjs +3 -2
  160. package/resources/beta/agents/environments/files.mjs.map +1 -1
  161. package/resources/beta/agents/index.d.mts +1 -1
  162. package/resources/beta/agents/index.d.mts.map +1 -1
  163. package/resources/beta/agents/index.d.ts +1 -1
  164. package/resources/beta/agents/index.d.ts.map +1 -1
  165. package/resources/beta/agents/index.js.map +1 -1
  166. package/resources/beta/agents/index.mjs.map +1 -1
  167. package/resources/beta/agents/sessions/artifacts.d.mts +2 -10
  168. package/resources/beta/agents/sessions/artifacts.d.mts.map +1 -1
  169. package/resources/beta/agents/sessions/artifacts.d.ts +2 -10
  170. package/resources/beta/agents/sessions/artifacts.d.ts.map +1 -1
  171. package/resources/beta/agents/sessions/sessions.d.mts +35 -8
  172. package/resources/beta/agents/sessions/sessions.d.mts.map +1 -1
  173. package/resources/beta/agents/sessions/sessions.d.ts +35 -8
  174. package/resources/beta/agents/sessions/sessions.d.ts.map +1 -1
  175. package/resources/beta/agents/sessions/sessions.js.map +1 -1
  176. package/resources/beta/agents/sessions/sessions.mjs.map +1 -1
  177. package/resources/beta/agents/vaults/credentials.d.mts +9 -6
  178. package/resources/beta/agents/vaults/credentials.d.mts.map +1 -1
  179. package/resources/beta/agents/vaults/credentials.d.ts +9 -6
  180. package/resources/beta/agents/vaults/credentials.d.ts.map +1 -1
  181. package/resources/beta/agents/vaults/credentials.js +1 -1
  182. package/resources/beta/agents/vaults/credentials.js.map +1 -1
  183. package/resources/beta/agents/vaults/credentials.mjs +1 -1
  184. package/resources/beta/agents/vaults/credentials.mjs.map +1 -1
  185. package/resources/beta/agents/vaults/index.d.mts +1 -1
  186. package/resources/beta/agents/vaults/index.d.mts.map +1 -1
  187. package/resources/beta/agents/vaults/index.d.ts +1 -1
  188. package/resources/beta/agents/vaults/index.d.ts.map +1 -1
  189. package/resources/beta/agents/vaults/index.js.map +1 -1
  190. package/resources/beta/agents/vaults/index.mjs.map +1 -1
  191. package/resources/beta/agents/vaults/vaults.d.mts +38 -7
  192. package/resources/beta/agents/vaults/vaults.d.mts.map +1 -1
  193. package/resources/beta/agents/vaults/vaults.d.ts +38 -7
  194. package/resources/beta/agents/vaults/vaults.d.ts.map +1 -1
  195. package/resources/beta/agents/vaults/vaults.js +22 -1
  196. package/resources/beta/agents/vaults/vaults.js.map +1 -1
  197. package/resources/beta/agents/vaults/vaults.mjs +22 -1
  198. package/resources/beta/agents/vaults/vaults.mjs.map +1 -1
  199. package/resources/beta/responses/responses.d.mts +135 -3
  200. package/resources/beta/responses/responses.d.mts.map +1 -1
  201. package/resources/beta/responses/responses.d.ts +135 -3
  202. package/resources/beta/responses/responses.d.ts.map +1 -1
  203. package/resources/beta/responses/responses.js.map +1 -1
  204. package/resources/beta/responses/responses.mjs.map +1 -1
  205. package/resources/chat/completions/completions.d.mts +1 -1
  206. package/resources/chat/completions/completions.d.ts +1 -1
  207. package/resources/conversations/items.d.mts +46 -0
  208. package/resources/conversations/items.d.mts.map +1 -1
  209. package/resources/conversations/items.d.ts +46 -0
  210. package/resources/conversations/items.d.ts.map +1 -1
  211. package/resources/decisions.d.mts +48 -21
  212. package/resources/decisions.d.mts.map +1 -1
  213. package/resources/decisions.d.ts +48 -21
  214. package/resources/decisions.d.ts.map +1 -1
  215. package/resources/decisions.js +2 -11
  216. package/resources/decisions.js.map +1 -1
  217. package/resources/decisions.mjs +2 -11
  218. package/resources/decisions.mjs.map +1 -1
  219. package/resources/live/live.d.mts +1 -1
  220. package/resources/live/live.d.mts.map +1 -1
  221. package/resources/live/live.d.ts +1 -1
  222. package/resources/live/live.d.ts.map +1 -1
  223. package/resources/live/live.js.map +1 -1
  224. package/resources/live/live.mjs.map +1 -1
  225. package/resources/responses/responses.d.mts +141 -3
  226. package/resources/responses/responses.d.mts.map +1 -1
  227. package/resources/responses/responses.d.ts +141 -3
  228. package/resources/responses/responses.d.ts.map +1 -1
  229. package/resources/responses/responses.js.map +1 -1
  230. package/resources/responses/responses.mjs.map +1 -1
  231. package/resources/safety/alerts.d.mts +5 -0
  232. package/resources/safety/alerts.d.mts.map +1 -1
  233. package/resources/safety/alerts.d.ts +5 -0
  234. package/resources/safety/alerts.d.ts.map +1 -1
  235. package/resources/webhooks/webhooks.d.mts +5 -6
  236. package/resources/webhooks/webhooks.d.mts.map +1 -1
  237. package/resources/webhooks/webhooks.d.ts +5 -6
  238. package/resources/webhooks/webhooks.d.ts.map +1 -1
  239. package/resources/webhooks/webhooks.js.map +1 -1
  240. package/resources/webhooks/webhooks.mjs.map +1 -1
  241. package/src/helpers/browser.ts +1583 -0
  242. package/src/helpers/computer.ts +1001 -0
  243. package/src/helpers/decisions-tool-runner.ts +641 -0
  244. package/src/helpers/responses-tool-runner.ts +3265 -0
  245. package/src/index.ts +1 -0
  246. package/src/internal/native-response-message.ts +218 -0
  247. package/src/internal/responses/response-accumulator.ts +63 -32
  248. package/src/internal/runner-diagnostics.ts +93 -0
  249. package/src/internal/runner-lifecycle.ts +248 -0
  250. package/src/internal/utils/log.ts +4 -0
  251. package/src/lib/responses/ResponseStream.ts +387 -21
  252. package/src/resources/admin/organization/audit-logs.ts +2 -1
  253. package/src/resources/admin/organization/external-storage.ts +28 -2
  254. package/src/resources/admin/organization/index.ts +3 -0
  255. package/src/resources/admin/organization/organization.ts +6 -0
  256. package/src/resources/admin/organization/projects/api-keys.ts +45 -0
  257. package/src/resources/admin/organization/projects/index.ts +1 -0
  258. package/src/resources/admin/organization/projects/projects.ts +5 -0
  259. package/src/resources/admin/organization/usage.ts +259 -0
  260. package/src/resources/beta/agents/agents.ts +31 -8
  261. package/src/resources/beta/agents/environments/environments.ts +2 -2
  262. package/src/resources/beta/agents/environments/files.ts +3 -2
  263. package/src/resources/beta/agents/index.ts +1 -0
  264. package/src/resources/beta/agents/sessions/artifacts.ts +2 -12
  265. package/src/resources/beta/agents/sessions/sessions.ts +39 -9
  266. package/src/resources/beta/agents/vaults/credentials.ts +8 -7
  267. package/src/resources/beta/agents/vaults/index.ts +1 -0
  268. package/src/resources/beta/agents/vaults/vaults.ts +48 -7
  269. package/src/resources/beta/responses/responses.ts +159 -3
  270. package/src/resources/chat/completions/completions.ts +1 -1
  271. package/src/resources/conversations/items.ts +54 -0
  272. package/src/resources/decisions.ts +48 -21
  273. package/src/resources/live/live.ts +1 -0
  274. package/src/resources/responses/responses.ts +165 -3
  275. package/src/resources/safety/alerts.ts +6 -0
  276. package/src/resources/webhooks/webhooks.ts +11 -12
  277. package/src/version.ts +1 -1
  278. package/version.d.mts +1 -1
  279. package/version.d.ts +1 -1
  280. package/version.js +1 -1
  281. package/version.mjs +1 -1
@@ -0,0 +1,1148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BrowserToolset = exports.BrowserError = exports.DEFAULT_BROWSER_MEMBERS = exports.BROWSER_MEMBERS = void 0;
4
+ // BrowserError belongs beside the single public helper that consumes it.
5
+ // oxlint-disable max-classes-per-file
6
+ const error_1 = require("../error.js");
7
+ const values_1 = require("../internal/utils/values.js");
8
+ const runner_diagnostics_1 = require("../internal/runner-diagnostics.js");
9
+ const runner_lifecycle_1 = require("../internal/runner-lifecycle.js");
10
+ const ResponseInputItems_1 = require("../lib/responses/ResponseInputItems.js");
11
+ const fields = {
12
+ text: { type: 'string' },
13
+ optionalText: { type: ['string', 'null'] },
14
+ strings: { type: 'array', items: { type: 'string' } },
15
+ filter: { type: 'string', enum: ['all', 'interactive'] },
16
+ direction: { type: 'string', enum: ['up', 'down', 'left', 'right'] },
17
+ amount: { type: 'integer', minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
18
+ timeout: { type: 'integer', minimum: 1, maximum: 30000 },
19
+ region: {
20
+ type: 'array',
21
+ items: { type: 'integer', minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
22
+ minItems: 4,
23
+ maxItems: 4,
24
+ },
25
+ coordinate: { type: 'integer', minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
26
+ checked: { type: 'boolean' },
27
+ button: { type: 'string', enum: ['left', 'right', 'middle'] },
28
+ clickCount: { type: 'integer', enum: [1, 2, 3] },
29
+ modifiers: {
30
+ type: 'array',
31
+ items: { type: 'string', enum: ['Control', 'Alt', 'Meta', 'Shift'] },
32
+ minItems: 0,
33
+ maxItems: 4,
34
+ description: 'Unique modifier keys held for this operation.',
35
+ },
36
+ path: {
37
+ type: 'array',
38
+ items: {
39
+ type: 'object',
40
+ properties: {
41
+ x: { type: 'integer', minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
42
+ y: { type: 'integer', minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
43
+ },
44
+ required: ['x', 'y'],
45
+ additionalProperties: false,
46
+ },
47
+ minItems: 2,
48
+ maxItems: 100,
49
+ },
50
+ heldKeys: {
51
+ type: 'array',
52
+ items: { type: 'string', description: 'Nonempty driver-supported key, at most 64 UTF-8 bytes.' },
53
+ minItems: 1,
54
+ maxItems: 8,
55
+ description: 'Unique driver-supported keys held for this operation.',
56
+ },
57
+ holdDuration: { type: 'integer', minimum: 1, maximum: 3000 },
58
+ scope: {
59
+ type: ['string', 'null'],
60
+ description: 'Null or a nonempty driver-issued scope ref, at most 256 UTF-8 bytes. Never a selector.',
61
+ },
62
+ depth: { type: 'integer', minimum: 1, maximum: 32 },
63
+ diagnosticSource: { type: 'string', enum: ['console', 'network'] },
64
+ diagnosticLimit: { type: 'integer', minimum: 1, maximum: 100 },
65
+ script: { type: 'string', description: 'Nonempty page script containing valid Unicode.' },
66
+ fileGrant: { type: 'string', description: 'Nonempty caller-issued file grant, at most 256 UTF-8 bytes.' },
67
+ visibleText: {
68
+ type: 'string',
69
+ description: 'Nonempty visible text, at most 256 UTF-8 bytes after whitespace normalization.',
70
+ },
71
+ };
72
+ const members = {
73
+ navigate: {
74
+ description: 'Navigate a tab to a URL.',
75
+ changes: true,
76
+ args: { url: 'text', tab_id: 'optionalText' },
77
+ },
78
+ read_page: {
79
+ description: 'Read page structure and opaque interactive element refs.',
80
+ changes: false,
81
+ args: { tab_id: 'optionalText', filter: 'filter' },
82
+ },
83
+ read_page_scoped: {
84
+ description: 'Read within an observed section, or discover sections with a null root. Depth counts DOM levels.',
85
+ changes: false,
86
+ optIn: true,
87
+ args: { tab_id: 'optionalText', root: 'scope', depth: 'depth', filter: 'filter' },
88
+ },
89
+ read_diagnostics: {
90
+ description: 'Read a bounded, driver-filtered console or network summary. Requires approval.',
91
+ changes: false,
92
+ sensitive: true,
93
+ optIn: true,
94
+ args: { tab_id: 'optionalText', source: 'diagnosticSource', limit: 'diagnosticLimit' },
95
+ },
96
+ run_script: {
97
+ description: 'Run an approved script in an explicitly allowed page. Returns text.',
98
+ changes: true,
99
+ optIn: true,
100
+ args: { tab_id: 'optionalText', source: 'script', timeout_ms: 'timeout' },
101
+ },
102
+ upload_file: {
103
+ description: 'Upload a caller-approved file using its task-scoped grant. Requires separate file approval.',
104
+ changes: true,
105
+ optIn: true,
106
+ args: { grant_id: 'fileGrant' },
107
+ },
108
+ download_file: {
109
+ description: 'Retrieve a caller-approved file using its task-scoped grant. Requires separate file approval.',
110
+ changes: true,
111
+ optIn: true,
112
+ args: { grant_id: 'fileGrant' },
113
+ },
114
+ get_page_text: { description: 'Read visible page text.', changes: false, args: { tab_id: 'optionalText' } },
115
+ find: {
116
+ description: 'Find page elements by text or description.',
117
+ changes: false,
118
+ args: { query: 'text', tab_id: 'optionalText' },
119
+ },
120
+ click: {
121
+ description: 'Click an element by its opaque ref.',
122
+ changes: true,
123
+ args: { target: 'text', tab_id: 'optionalText' },
124
+ },
125
+ click_at: {
126
+ description: 'Click full-viewport CSS coordinates with a button, click count, and held modifiers.',
127
+ changes: true,
128
+ optIn: true,
129
+ args: {
130
+ tab_id: 'optionalText',
131
+ x: 'coordinate',
132
+ y: 'coordinate',
133
+ button: 'button',
134
+ click_count: 'clickCount',
135
+ keys: 'modifiers',
136
+ },
137
+ },
138
+ drag_path: {
139
+ description: 'Drag the left button through 2 to 100 full-viewport CSS points with held modifiers.',
140
+ changes: true,
141
+ optIn: true,
142
+ args: { tab_id: 'optionalText', path: 'path', keys: 'modifiers' },
143
+ },
144
+ hold_keys: {
145
+ description: 'Hold driver-supported keys for at most 3000 milliseconds, then release them.',
146
+ changes: true,
147
+ optIn: true,
148
+ args: { tab_id: 'optionalText', keys: 'heldKeys', duration_ms: 'holdDuration' },
149
+ },
150
+ type: {
151
+ description: 'Fill a referenced control or type at the current focus.',
152
+ changes: true,
153
+ args: { text: 'text', target: 'optionalText', tab_id: 'optionalText' },
154
+ },
155
+ key: {
156
+ description: 'Press a key combination.',
157
+ changes: true,
158
+ args: { keys: 'strings', tab_id: 'optionalText' },
159
+ },
160
+ scroll: {
161
+ description: 'Scroll the page in the given direction.',
162
+ changes: true,
163
+ args: { direction: 'direction', amount: 'amount', tab_id: 'optionalText' },
164
+ },
165
+ scroll_to: {
166
+ description: 'Scroll an already observed target into view. Read again before acting.',
167
+ changes: true,
168
+ args: { target: 'text', tab_id: 'optionalText' },
169
+ },
170
+ wait_for: {
171
+ description: 'Wait for reported visible text, within a bounded timeout in milliseconds.',
172
+ changes: false,
173
+ args: { text: 'visibleText', timeout_ms: 'timeout', tab_id: 'optionalText' },
174
+ },
175
+ select_option: {
176
+ description: 'Select values in a referenced select control.',
177
+ changes: true,
178
+ args: { target: 'text', values: 'strings', tab_id: 'optionalText' },
179
+ },
180
+ hover: {
181
+ description: 'Hover over a referenced element.',
182
+ changes: true,
183
+ args: { target: 'text', tab_id: 'optionalText' },
184
+ },
185
+ hover_at: {
186
+ description: 'Move the pointer to full-viewport CSS coordinates without pressing a button.',
187
+ changes: true,
188
+ optIn: true,
189
+ args: { tab_id: 'optionalText', x: 'coordinate', y: 'coordinate' },
190
+ },
191
+ set_checked: {
192
+ description: 'Set an observed checkbox to the requested state. Repeating the same value does not toggle it.',
193
+ changes: true,
194
+ optIn: true,
195
+ args: { tab_id: 'optionalText', target: 'text', checked: 'checked' },
196
+ },
197
+ screenshot: {
198
+ description: 'Capture the visible tab as an image.',
199
+ changes: false,
200
+ args: { tab_id: 'optionalText' },
201
+ },
202
+ zoom: {
203
+ description: 'Capture a region [x0,y0,x1,y1]. Subsequent coordinates stay in the full viewport.',
204
+ changes: false,
205
+ args: { tab_id: 'optionalText', region: 'region' },
206
+ },
207
+ new_tab: { description: 'Open a tab, optionally at a URL.', changes: true, args: { url: 'optionalText' } },
208
+ list_tabs: { description: 'List tabs, titles, URLs and active tab.', changes: false, args: {} },
209
+ switch_tab: { description: 'Activate a tab.', changes: true, args: { tab_id: 'text' } },
210
+ close_tab: { description: 'Close a tab.', changes: true, args: { tab_id: 'text' } },
211
+ };
212
+ /** Fixed member names, including opt-ins. This list never reads a driver. */
213
+ exports.BROWSER_MEMBERS = Object.freeze(
214
+ // SAFETY: Keys come from the fixed schema table rather than driver or model data.
215
+ Object.keys(members));
216
+ /** Standard members. A partial driver advertises only the members it implements. */
217
+ exports.DEFAULT_BROWSER_MEMBERS = Object.freeze(exports.BROWSER_MEMBERS.filter((member) => !(0, values_1.hasOwn)(members[member], 'optIn')));
218
+ const readOmissions = [
219
+ 'report_limit',
220
+ 'text_limit',
221
+ 'target_limit',
222
+ 'work_limit',
223
+ 'frame_limit',
224
+ 'unsupported_root',
225
+ 'unsupported_control',
226
+ 'remote_action',
227
+ 'private',
228
+ 'value',
229
+ 'name_limit',
230
+ ];
231
+ /** An intentional, user-safe driver error. Only this message may be sent back to the model. */
232
+ class BrowserError extends error_1.OpenAIError {
233
+ constructor() {
234
+ super(...arguments);
235
+ /** Stable error type for controlled driver failures. */
236
+ this.name = 'BrowserError';
237
+ }
238
+ }
239
+ exports.BrowserError = BrowserError;
240
+ function boundedStateText(value, limit, allowEmpty) {
241
+ return ((allowEmpty || value.length > 0) &&
242
+ !/[\uD800-\uDFFF]/u.test(value) &&
243
+ (limit === Number.POSITIVE_INFINITY || new TextEncoder().encode(value).length <= limit));
244
+ }
245
+ function stateCounter(value) {
246
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
247
+ }
248
+ const valid = {
249
+ text: (value) => typeof value === 'string',
250
+ optionalText: (value) => value === null || typeof value === 'string',
251
+ strings: (value) => Array.isArray(value) && value.every((part) => typeof part === 'string'),
252
+ filter: (value) => value === 'all' || value === 'interactive',
253
+ direction: (value) => typeof value === 'string' && ['up', 'down', 'left', 'right'].includes(value),
254
+ amount: (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0,
255
+ timeout: (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 1 && value <= 30000,
256
+ region: (value) => Array.isArray(value) &&
257
+ value.length === 4 &&
258
+ value.every((point) => typeof point === 'number' && Number.isSafeInteger(point) && point >= 0) &&
259
+ value[0] < value[2] &&
260
+ value[1] < value[3],
261
+ visibleText: (value) =>
262
+ // oxlint-disable-next-line unicorn/prefer-string-replace-all -- Public SDK source targets ES2020.
263
+ typeof value === 'string' && boundedStateText(value.replace(/\s+/gu, ' ').trim(), 256, false),
264
+ coordinate: stateCounter,
265
+ checked: (value) => typeof value === 'boolean',
266
+ button: (value) => value === 'left' || value === 'right' || value === 'middle',
267
+ clickCount: (value) => value === 1 || value === 2 || value === 3,
268
+ modifiers: (value) => Array.isArray(value) &&
269
+ value.length <= 4 &&
270
+ new Set(value).size === value.length &&
271
+ value.every((key) => ['Control', 'Alt', 'Meta', 'Shift'].includes(key)),
272
+ path: (value) => Array.isArray(value) &&
273
+ value.length >= 2 &&
274
+ value.length <= 100 &&
275
+ value.every((point) => (0, values_1.isObj)(point) &&
276
+ Object.keys(point).length === 2 &&
277
+ (0, values_1.hasOwn)(point, 'x') &&
278
+ (0, values_1.hasOwn)(point, 'y') &&
279
+ stateCounter(point['x']) &&
280
+ stateCounter(point['y'])),
281
+ heldKeys: (value) => Array.isArray(value) &&
282
+ value.length >= 1 &&
283
+ value.length <= 8 &&
284
+ new Set(value).size === value.length &&
285
+ value.every((key) => typeof key === 'string' && boundedStateText(key, 64, false)),
286
+ holdDuration: (value) => stateCounter(value) && value >= 1 && value <= 3000,
287
+ scope: (value) => value === null || (typeof value === 'string' && boundedStateText(value, 256, false)),
288
+ depth: (value) => stateCounter(value) && value >= 1 && value <= 32,
289
+ diagnosticSource: (value) => value === 'console' || value === 'network',
290
+ diagnosticLimit: (value) => stateCounter(value) && value >= 1 && value <= 100,
291
+ script: (value) => typeof value === 'string' && boundedStateText(value, Number.POSITIVE_INFINITY, false),
292
+ fileGrant: (value) => typeof value === 'string' && boundedStateText(value, 256, false),
293
+ };
294
+ function validateArguments(member, value) {
295
+ const spec = members[member].args;
296
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
297
+ throw new BrowserError('Browser arguments must be an object.');
298
+ }
299
+ const supplied = Object.entries(value);
300
+ const expected = Object.keys(spec);
301
+ if (supplied.length !== expected.length || supplied.some(([key]) => !expected.includes(key))) {
302
+ throw new BrowserError('Browser arguments contain missing or unknown fields.');
303
+ }
304
+ for (const [key, val] of supplied) {
305
+ const field = spec[key];
306
+ if (!field || !valid[field](val)) {
307
+ throw new BrowserError('Invalid browser argument value.');
308
+ }
309
+ }
310
+ }
311
+ function readText(value, limit, allowEmpty) {
312
+ if (typeof value !== 'string' || value.length > limit || !boundedStateText(value, limit, allowEmpty)) {
313
+ throw new TypeError('Invalid browser read text.');
314
+ }
315
+ return value;
316
+ }
317
+ function validImageBreakpoint(value) {
318
+ return (value === undefined ||
319
+ value === null ||
320
+ ((0, values_1.isObj)(value) &&
321
+ (0, runner_lifecycle_1.configuredOption)(value, 'mode') === 'explicit' &&
322
+ Object.keys(value).every((key) => key === 'mode')));
323
+ }
324
+ function validImageSource(value) {
325
+ return value === undefined || value === null || (typeof value === 'string' && !!value.trim());
326
+ }
327
+ function validImageDetail(value) {
328
+ return (value === undefined ||
329
+ value === null ||
330
+ value === 'auto' ||
331
+ value === 'low' ||
332
+ value === 'high' ||
333
+ value === 'original');
334
+ }
335
+ function snapshotImage(value, member) {
336
+ try {
337
+ if (!(0, values_1.isObj)(value)) {
338
+ throw new TypeError('Invalid browser image.');
339
+ }
340
+ const keys = Object.keys(value);
341
+ if (keys.some((key) => !['type', 'detail', 'image_url', 'file_id', 'prompt_cache_breakpoint'].includes(key))) {
342
+ throw new TypeError('Invalid browser image.');
343
+ }
344
+ const type = (0, runner_lifecycle_1.configuredOption)(value, 'type');
345
+ const detail = (0, runner_lifecycle_1.configuredOption)(value, 'detail');
346
+ const image_url = (0, runner_lifecycle_1.configuredOption)(value, 'image_url');
347
+ const file_id = (0, runner_lifecycle_1.configuredOption)(value, 'file_id');
348
+ const prompt_cache_breakpoint = (0, runner_lifecycle_1.configuredOption)(value, 'prompt_cache_breakpoint');
349
+ if (type !== 'input_image' ||
350
+ !validImageDetail(detail) ||
351
+ !validImageSource(image_url) ||
352
+ !validImageSource(file_id) ||
353
+ (typeof image_url !== 'string' && typeof file_id !== 'string') ||
354
+ !validImageBreakpoint(prompt_cache_breakpoint)) {
355
+ throw new TypeError('Invalid browser image.');
356
+ }
357
+ return {
358
+ type,
359
+ ...(detail === undefined ? {} : { detail }),
360
+ ...(image_url === undefined ? {} : { image_url }),
361
+ ...(file_id === undefined ? {} : { file_id }),
362
+ ...(prompt_cache_breakpoint === undefined
363
+ ? {}
364
+ : { prompt_cache_breakpoint: prompt_cache_breakpoint === null ? null : { mode: 'explicit' } }),
365
+ };
366
+ }
367
+ catch {
368
+ throw new error_1.OpenAIError(`Browser ${member} must return an input_image with at least one valid image_url or file_id.`);
369
+ }
370
+ }
371
+ function requireOwnArrayEntry(array, index) {
372
+ if (!(0, values_1.hasOwn)(array, index)) {
373
+ throw new TypeError('Invalid browser array entry.');
374
+ }
375
+ }
376
+ function optionalReadBoolean(source, key) {
377
+ const value = (0, runner_lifecycle_1.configuredOption)(source, key);
378
+ if (value === undefined || typeof value === 'boolean') {
379
+ return value;
380
+ }
381
+ throw new TypeError('Invalid browser read boolean.');
382
+ }
383
+ function browserRead(value, textOnly) {
384
+ try {
385
+ if (!(0, values_1.isObj)(value)) {
386
+ throw new TypeError('Invalid browser read.');
387
+ }
388
+ const version = (0, runner_lifecycle_1.configuredOption)(value, 'version');
389
+ const text = (0, runner_lifecycle_1.configuredOption)(value, 'text');
390
+ const elements = (0, runner_lifecycle_1.configuredOption)(value, 'elements');
391
+ const omitted = (0, runner_lifecycle_1.configuredOption)(value, 'omitted');
392
+ if (version !== 1 || !Array.isArray(elements) || !Array.isArray(omitted)) {
393
+ throw new TypeError('Invalid browser read.');
394
+ }
395
+ // Fix each V1 array's bounds once. Driver iterators and getters must not
396
+ // add targets or private metadata after their declared limits were checked.
397
+ const elementCount = elements.length;
398
+ const omittedCount = omitted.length;
399
+ if (!stateCounter(elementCount) ||
400
+ (textOnly && elementCount !== 0) ||
401
+ !stateCounter(omittedCount) ||
402
+ omittedCount > readOmissions.length) {
403
+ throw new TypeError('Invalid browser read.');
404
+ }
405
+ const projected = {
406
+ version: 1,
407
+ text: readText(text, Number.POSITIVE_INFINITY, true),
408
+ elements: Array.from({ length: elementCount }, (_, index) => {
409
+ requireOwnArrayEntry(elements, index);
410
+ const item = elements[index];
411
+ if (!(0, values_1.isObj)(item)) {
412
+ throw new TypeError('Invalid browser read element.');
413
+ }
414
+ const role = (0, runner_lifecycle_1.configuredOption)(item, 'role');
415
+ if (role !== 'button' &&
416
+ role !== 'textbox' &&
417
+ role !== 'combobox' &&
418
+ role !== 'checkbox' &&
419
+ role !== 'radio' &&
420
+ role !== 'slider' &&
421
+ role !== 'listbox') {
422
+ throw new TypeError('Invalid browser read role.');
423
+ }
424
+ const entry = {
425
+ ref: readText((0, runner_lifecycle_1.configuredOption)(item, 'ref'), 256, false),
426
+ role,
427
+ label: readText((0, runner_lifecycle_1.configuredOption)(item, 'label'), 256, false),
428
+ };
429
+ const fieldValue = (0, runner_lifecycle_1.configuredOption)(item, 'value');
430
+ if (fieldValue !== undefined) {
431
+ entry.value = readText(fieldValue, 512, true);
432
+ }
433
+ if (role === 'checkbox' || role === 'radio') {
434
+ const checked = optionalReadBoolean(item, 'checked');
435
+ if (checked !== undefined) {
436
+ entry.checked = checked;
437
+ }
438
+ }
439
+ const options = (0, runner_lifecycle_1.configuredOption)(item, 'options');
440
+ if (options !== undefined) {
441
+ if (!Array.isArray(options)) {
442
+ throw new TypeError('Invalid browser read options.');
443
+ }
444
+ const optionCount = options.length;
445
+ if (!stateCounter(optionCount)) {
446
+ throw new TypeError('Invalid browser read options.');
447
+ }
448
+ entry.options = Array.from({ length: optionCount }, (_option, optionIndex) => {
449
+ requireOwnArrayEntry(options, optionIndex);
450
+ const option = options[optionIndex];
451
+ if (!(0, values_1.isObj)(option)) {
452
+ throw new TypeError('Invalid browser read option.');
453
+ }
454
+ const choice = {
455
+ label: readText((0, runner_lifecycle_1.configuredOption)(option, 'label'), 256, false),
456
+ value: readText((0, runner_lifecycle_1.configuredOption)(option, 'value'), 512, true),
457
+ };
458
+ if (role === 'listbox') {
459
+ const selected = optionalReadBoolean(option, 'selected');
460
+ if (selected !== undefined) {
461
+ choice.selected = selected;
462
+ }
463
+ }
464
+ return choice;
465
+ });
466
+ }
467
+ return entry;
468
+ }),
469
+ omitted: Array.from({ length: omittedCount }, (_, index) => {
470
+ requireOwnArrayEntry(omitted, index);
471
+ const code = omitted[index];
472
+ const matched = readOmissions.find((known) => known === code);
473
+ if (matched === undefined) {
474
+ throw new TypeError('Invalid browser read omission.');
475
+ }
476
+ return matched;
477
+ }),
478
+ };
479
+ if (new Set(projected.elements.map((entry) => entry.ref)).size !== projected.elements.length ||
480
+ new Set(projected.omitted).size !== projected.omitted.length) {
481
+ throw new TypeError('Invalid browser read.');
482
+ }
483
+ return projected;
484
+ }
485
+ catch {
486
+ throw new error_1.OpenAIError('Browser read report failed.');
487
+ }
488
+ }
489
+ function scopedRead(value) {
490
+ try {
491
+ if (!(0, values_1.isObj)(value)) {
492
+ throw new TypeError('Invalid browser scopes.');
493
+ }
494
+ const source = (0, runner_lifecycle_1.configuredOption)(value, 'scopes');
495
+ if (!Array.isArray(source)) {
496
+ throw new TypeError('Invalid browser scopes.');
497
+ }
498
+ const count = source.length;
499
+ if (!stateCounter(count)) {
500
+ throw new TypeError('Invalid browser scopes.');
501
+ }
502
+ const report = browserRead(value, false);
503
+ const scopes = Array.from({ length: count }, (_, index) => {
504
+ requireOwnArrayEntry(source, index);
505
+ const scope = source[index];
506
+ if (!(0, values_1.isObj)(scope)) {
507
+ throw new TypeError('Invalid browser scope.');
508
+ }
509
+ return {
510
+ ref: readText((0, runner_lifecycle_1.configuredOption)(scope, 'ref'), 256, false),
511
+ label: readText((0, runner_lifecycle_1.configuredOption)(scope, 'label'), 256, false),
512
+ };
513
+ });
514
+ const refs = [...report.elements.map((element) => element.ref), ...scopes.map((scope) => scope.ref)];
515
+ const projected = { ...report, scopes };
516
+ if (new Set(refs).size !== refs.length) {
517
+ throw new TypeError('Invalid browser scopes.');
518
+ }
519
+ return projected;
520
+ }
521
+ catch {
522
+ throw new error_1.OpenAIError('Browser scoped read report failed.');
523
+ }
524
+ }
525
+ function fileOutcome(value) {
526
+ try {
527
+ if (!(0, values_1.isObj)(value) ||
528
+ Object.keys(value).some((key) => !['version', 'status', 'effect', 'cleanup'].includes(key))) {
529
+ throw new TypeError('Invalid browser file outcome.');
530
+ }
531
+ const version = (0, runner_lifecycle_1.configuredOption)(value, 'version');
532
+ const status = (0, runner_lifecycle_1.configuredOption)(value, 'status');
533
+ const effect = (0, runner_lifecycle_1.configuredOption)(value, 'effect');
534
+ const cleanup = (0, runner_lifecycle_1.configuredOption)(value, 'cleanup');
535
+ if (version !== 1 || (cleanup !== 'not_started' && cleanup !== 'pending' && cleanup !== 'completed')) {
536
+ throw new TypeError('Invalid browser file outcome.');
537
+ }
538
+ if (status === 'completed' && effect === 'completed') {
539
+ return { version, status, effect, cleanup };
540
+ }
541
+ if (status === 'refused' && effect === 'none') {
542
+ return { version, status, effect, cleanup };
543
+ }
544
+ if (status === 'unknown' && effect === 'unknown') {
545
+ return { version, status, effect, cleanup };
546
+ }
547
+ if (status === 'interrupted' && (effect === 'none' || effect === 'unknown')) {
548
+ return { version, status, effect, cleanup };
549
+ }
550
+ throw new TypeError('Invalid browser file outcome.');
551
+ }
552
+ catch {
553
+ throw new error_1.OpenAIError('Browser file result failed.');
554
+ }
555
+ }
556
+ function snapshotResult(member, result) {
557
+ if (member === 'zoom' || member === 'screenshot') {
558
+ return snapshotImage(result, member);
559
+ }
560
+ if (member === 'read_page_scoped') {
561
+ return scopedRead(result);
562
+ }
563
+ if (member === 'read_diagnostics') {
564
+ return browserRead(result, true);
565
+ }
566
+ if (member === 'upload_file' || member === 'download_file') {
567
+ return fileOutcome(result);
568
+ }
569
+ if (member === 'run_script') {
570
+ try {
571
+ return readText(result, Number.POSITIVE_INFINITY, true);
572
+ }
573
+ catch {
574
+ throw new error_1.OpenAIError('Browser script result failed.');
575
+ }
576
+ }
577
+ if (member === 'list_tabs' || result === null || result === undefined || typeof result === 'string') {
578
+ return result;
579
+ }
580
+ if (member === 'read_page' || member === 'find' || member === 'get_page_text') {
581
+ return browserRead(result, member === 'get_page_text');
582
+ }
583
+ throw new error_1.OpenAIError('Browser actions must return a string, null, or undefined.');
584
+ }
585
+ function resultCompleted(member, result) {
586
+ if (member === 'upload_file' || member === 'download_file') {
587
+ return (0, values_1.isObj)(result) && result['status'] === 'completed';
588
+ }
589
+ return true;
590
+ }
591
+ function nullableStateNotice(change, type, sequence, tab_id) {
592
+ if (type === 'navigation_refused') {
593
+ const reason = (0, runner_lifecycle_1.configuredOption)(change, 'reason');
594
+ if (reason !== 'policy' && reason !== 'unsupported') {
595
+ throw new TypeError('Invalid browser change.');
596
+ }
597
+ return { type, sequence, tab_id, reason };
598
+ }
599
+ const status = (0, runner_lifecycle_1.configuredOption)(change, 'status');
600
+ if (status !== 'blocked' && status !== 'started' && status !== 'completed' && status !== 'failed') {
601
+ throw new TypeError('Invalid browser change.');
602
+ }
603
+ return { type, sequence, tab_id, status };
604
+ }
605
+ function observedState(value) {
606
+ if (!(0, values_1.isObj)(value)) {
607
+ throw new TypeError('Invalid browser observation.');
608
+ }
609
+ const version = (0, runner_lifecycle_1.configuredOption)(value, 'version');
610
+ const sequence = (0, runner_lifecycle_1.configuredOption)(value, 'sequence');
611
+ const dropped_changes = (0, runner_lifecycle_1.configuredOption)(value, 'dropped_changes');
612
+ const title_truncated = (0, runner_lifecycle_1.configuredOption)(value, 'title_truncated');
613
+ const changes = (0, runner_lifecycle_1.configuredOption)(value, 'changes');
614
+ if (version !== 1 ||
615
+ !stateCounter(sequence) ||
616
+ !stateCounter(dropped_changes) ||
617
+ typeof title_truncated !== 'boolean' ||
618
+ !Array.isArray(changes)) {
619
+ throw new TypeError('Invalid browser observation.');
620
+ }
621
+ const { length } = changes;
622
+ if (!stateCounter(length) || sequence !== dropped_changes + length) {
623
+ throw new TypeError('Invalid browser observation.');
624
+ }
625
+ const projected = Array.from({ length }, (_, index) => {
626
+ requireOwnArrayEntry(changes, index);
627
+ const change = changes[index];
628
+ if (!(0, values_1.isObj)(change)) {
629
+ throw new TypeError('Invalid browser change.');
630
+ }
631
+ const type = (0, runner_lifecycle_1.configuredOption)(change, 'type');
632
+ const tab_id = (0, runner_lifecycle_1.configuredOption)(change, 'tab_id');
633
+ const position = dropped_changes + index + 1;
634
+ if ((0, runner_lifecycle_1.configuredOption)(change, 'sequence') !== position) {
635
+ throw new TypeError('Invalid browser change.');
636
+ }
637
+ if (type === 'navigation_refused' || type === 'download') {
638
+ if (tab_id !== null && (typeof tab_id !== 'string' || !boundedStateText(tab_id, 128, false))) {
639
+ throw new TypeError('Invalid browser change.');
640
+ }
641
+ return nullableStateNotice(change, type, position, tab_id);
642
+ }
643
+ if (typeof tab_id !== 'string' || !boundedStateText(tab_id, 128, false)) {
644
+ throw new TypeError('Invalid browser change.');
645
+ }
646
+ if (type === 'dialog_dismissed') {
647
+ const kind = (0, runner_lifecycle_1.configuredOption)(change, 'kind');
648
+ if (kind !== 'alert' &&
649
+ kind !== 'confirm' &&
650
+ kind !== 'prompt' &&
651
+ kind !== 'beforeunload' &&
652
+ kind !== 'other') {
653
+ throw new TypeError('Invalid browser change.');
654
+ }
655
+ return { type, sequence: position, tab_id, kind };
656
+ }
657
+ if (type !== 'tab_opened' && type !== 'tab_closed' && type !== 'tab_switched' && type !== 'navigation') {
658
+ throw new TypeError('Invalid browser change.');
659
+ }
660
+ return { type, sequence: position, tab_id };
661
+ });
662
+ return { version: 1, sequence, dropped_changes, title_truncated, changes: projected };
663
+ }
664
+ function stateOrigin(url) {
665
+ if (!boundedStateText(url, Number.POSITIVE_INFINITY, false)) {
666
+ throw new TypeError('Invalid browser URL.');
667
+ }
668
+ if (url === 'about:blank') {
669
+ return url;
670
+ }
671
+ const scheme = /^https?:\/\//iu.exec(url)?.[0];
672
+ const authority = scheme ? url.slice(scheme.length).split(/[/?#]/u, 1)[0] : undefined;
673
+ if (!scheme ||
674
+ !authority ||
675
+ [...authority].some((char) => char <= ' ' || char === '\u007F' || char === '\\')) {
676
+ throw new TypeError('Invalid browser URL.');
677
+ }
678
+ // V1 accepts no escaped host/port bytes or scoped IP addresses. Userinfo
679
+ // may still be escaped; it is never included in the projected origin.
680
+ const hostPort = authority.slice(authority.lastIndexOf('@') + 1);
681
+ if (hostPort.includes('%')) {
682
+ throw new TypeError('Invalid browser URL.');
683
+ }
684
+ const value = new URL(scheme + hostPort);
685
+ const host = value.hostname;
686
+ if (!host.startsWith('[')) {
687
+ const labels = host.replace(/\.$/u, '').split('.');
688
+ if (labels.some((label) => !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(label))) {
689
+ throw new TypeError('Invalid browser URL.');
690
+ }
691
+ // WHATWG expands abbreviated, octal, hex and integer IPv4. The shared
692
+ // observation subset allows only the explicit canonical four-octet form.
693
+ if (/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/u.test(host) && hostPort.split(':')[0] !== host) {
694
+ throw new TypeError('Invalid browser URL.');
695
+ }
696
+ }
697
+ if (!boundedStateText(value.origin, 2048, false)) {
698
+ throw new TypeError('Invalid browser URL.');
699
+ }
700
+ return value.origin;
701
+ }
702
+ function legacyStateURL(url) {
703
+ const parsed = new URL(url);
704
+ let projected = parsed.protocol;
705
+ if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
706
+ projected = parsed.origin;
707
+ }
708
+ else if (url === 'about:blank') {
709
+ projected = url;
710
+ }
711
+ if (!boundedStateText(projected, 2048, false)) {
712
+ throw new TypeError('Invalid browser URL.');
713
+ }
714
+ return projected;
715
+ }
716
+ async function readState(report, signal, previous) {
717
+ try {
718
+ const value = await report({ signal });
719
+ signal?.throwIfAborted();
720
+ if (!(0, values_1.isObj)(value)) {
721
+ throw new TypeError('Invalid browser state.');
722
+ }
723
+ const rawTabs = (0, runner_lifecycle_1.configuredOption)(value, 'tabs');
724
+ if (!Array.isArray(rawTabs)) {
725
+ throw new TypeError('Invalid browser state.');
726
+ }
727
+ const { length } = rawTabs;
728
+ const suppliedObservation = (0, runner_lifecycle_1.configuredOption)(value, 'observation');
729
+ const observation = suppliedObservation === undefined ? undefined : observedState(suppliedObservation);
730
+ if (previous &&
731
+ (!observation ||
732
+ observation.sequence < previous.sequence ||
733
+ observation.dropped_changes < previous.dropped_changes)) {
734
+ throw new TypeError('Invalid browser state.');
735
+ }
736
+ if (previous && observation) {
737
+ const offset = observation.dropped_changes - previous.dropped_changes;
738
+ for (let index = 0; index < previous.sequence - observation.dropped_changes; index += 1) {
739
+ if (JSON.stringify(observation.changes[index]) !== JSON.stringify(previous.changes[offset + index])) {
740
+ throw new TypeError('Invalid browser state.');
741
+ }
742
+ }
743
+ }
744
+ const tabs = Array.from({ length }, (_, index) => {
745
+ requireOwnArrayEntry(rawTabs, index);
746
+ const tab = rawTabs[index];
747
+ if (!(0, values_1.isObj)(tab)) {
748
+ throw new TypeError('Invalid browser state.');
749
+ }
750
+ const id = (0, runner_lifecycle_1.configuredOption)(tab, 'id');
751
+ const title = (0, runner_lifecycle_1.configuredOption)(tab, 'title');
752
+ const url = (0, runner_lifecycle_1.configuredOption)(tab, 'url');
753
+ const active = (0, runner_lifecycle_1.configuredOption)(tab, 'active');
754
+ if (typeof id !== 'string' ||
755
+ typeof title !== 'string' ||
756
+ typeof url !== 'string' ||
757
+ typeof active !== 'boolean') {
758
+ throw new TypeError('Invalid browser state.');
759
+ }
760
+ if (observation &&
761
+ (!boundedStateText(id, 128, false) || !boundedStateText(title, Number.POSITIVE_INFINITY, true))) {
762
+ throw new TypeError('Invalid browser state.');
763
+ }
764
+ let projectedTitle = title;
765
+ if (observation) {
766
+ // SAFETY: The native encoder reports how many complete UTF-16 units it read.
767
+ const { read } = new TextEncoder().encodeInto(title, new Uint8Array(1024));
768
+ if (read < title.length) {
769
+ projectedTitle = title.slice(0, read);
770
+ observation.title_truncated = true;
771
+ }
772
+ }
773
+ return { id, title: projectedTitle, url: observation ? stateOrigin(url) : legacyStateURL(url), active };
774
+ });
775
+ if (new Set(tabs.map((tab) => tab.id)).size !== tabs.length ||
776
+ (tabs.length > 0 && tabs.filter((tab) => tab.active).length !== 1)) {
777
+ throw new TypeError('Invalid browser state.');
778
+ }
779
+ return observation ? { tabs, observation } : { tabs };
780
+ }
781
+ catch {
782
+ signal?.throwIfAborted();
783
+ throw new error_1.OpenAIError('Browser state report failed.');
784
+ }
785
+ }
786
+ function selectedBrowserMembers(selection) {
787
+ if (selection === undefined) {
788
+ return undefined;
789
+ }
790
+ if (!Array.isArray(selection)) {
791
+ throw new TypeError('Browser members must be an array of unique fixed member names.');
792
+ }
793
+ const requested = new Set();
794
+ const { length } = selection;
795
+ for (let index = 0; index < length; index += 1) {
796
+ const name = (0, values_1.hasOwn)(selection, index) ? selection[index] : undefined;
797
+ if (typeof name !== 'string' || !(0, values_1.hasOwn)(members, name) || requested.has(name)) {
798
+ throw new TypeError('Browser members must be an array of unique fixed member names.');
799
+ }
800
+ requested.add(name);
801
+ }
802
+ return requested;
803
+ }
804
+ function requiresConsent(member) {
805
+ const spec = members[member];
806
+ return spec.changes || ('sensitive' in spec && (0, values_1.hasOwn)(spec, 'sensitive') && spec.sensitive);
807
+ }
808
+ // Only fresh helper-owned declarations, consent snapshots, state, and result projections reach this walk.
809
+ // oxlint-disable-next-line anti-slop/no-object-parameters -- The private walk handles heterogeneous projected records and arrays, never caller-owned objects.
810
+ function protectBrowserOutput(value) {
811
+ const pending = [value];
812
+ for (const record of pending) {
813
+ Object.defineProperty(record, 'toJSON', { value: undefined, writable: true, configurable: true });
814
+ const entries = Object.values(record);
815
+ for (const entry of entries) {
816
+ if (entry !== null && typeof entry === 'object') {
817
+ pending.push(entry);
818
+ }
819
+ }
820
+ }
821
+ return value;
822
+ }
823
+ // oxlint-disable-next-line anti-slop/no-object-parameters -- Serialize the same helper-owned projections protected by the private walk.
824
+ function serializeBrowserOutput(value) {
825
+ protectBrowserOutput(value);
826
+ return JSON.stringify(value);
827
+ }
828
+ /** Dispatches a fixed set of structured browser functions against a caller-owned driver. */
829
+ class BrowserToolset {
830
+ constructor(driver, options = {}) {
831
+ this.lifecycle = new runner_lifecycle_1.RunnerLifecycle();
832
+ this.enabled = new Map();
833
+ this.driver = driver;
834
+ this.options = options;
835
+ const reads = 'confirmReads' in options
836
+ ? selectedBrowserMembers((0, runner_lifecycle_1.configuredOption)(options, 'confirmReads'))
837
+ : undefined;
838
+ if (reads &&
839
+ ([...reads].some((name) => members[name].changes) ||
840
+ typeof (0, runner_lifecycle_1.configuredOption)(options, 'confirm') !== 'function')) {
841
+ throw new TypeError('confirmReads requires read-only members and a confirm callback.');
842
+ }
843
+ this.confirmReads = reads ?? new Set();
844
+ this.registerDriver(driver, options);
845
+ for (const member of this.confirmReads) {
846
+ if (!this.enabled.has(`browser_${member}`)) {
847
+ throw new TypeError('confirmReads must name an enabled browser read.');
848
+ }
849
+ }
850
+ }
851
+ registerDriver(driver, options) {
852
+ const selected = selectedBrowserMembers((0, runner_lifecycle_1.configuredOption)(options, 'members'));
853
+ const additional = selectedBrowserMembers((0, runner_lifecycle_1.configuredOption)(options, 'additionalMembers'));
854
+ if (selected !== undefined && additional !== undefined) {
855
+ throw new TypeError('Use either members or additionalMembers, not both.');
856
+ }
857
+ for (const name of exports.BROWSER_MEMBERS) {
858
+ const spec = members[name];
859
+ if (selected ? !selected.has(name) : (0, values_1.hasOwn)(spec, 'optIn') && !additional?.has(name)) {
860
+ continue;
861
+ }
862
+ const handler = name === 'list_tabs' ? undefined : (0, runner_lifecycle_1.configuredOption)(driver, name);
863
+ if (name === 'list_tabs' || typeof handler === 'function') {
864
+ BrowserToolset.requirePolicy(name, options);
865
+ // SAFETY: Fixed inventory name selects the handler; execution validates its matching argument schema.
866
+ const bound = handler?.bind(driver);
867
+ this.enabled.set(`browser_${name}`, { member: name, handler: bound });
868
+ }
869
+ else if (selected || additional?.has(name)) {
870
+ throw new TypeError('A selected browser member is not implemented by the driver.');
871
+ }
872
+ }
873
+ }
874
+ static requirePolicy(name, options) {
875
+ if (requiresConsent(name) && !(0, runner_lifecycle_1.configuredOption)(options, 'confirm')) {
876
+ throw new TypeError('BrowserToolset requires confirm for state-changing members or sensitive reads.');
877
+ }
878
+ if ((name === 'navigate' || name === 'new_tab') && !(0, runner_lifecycle_1.configuredOption)(options, 'urlPolicy')) {
879
+ throw new TypeError('BrowserToolset requires urlPolicy for navigation.');
880
+ }
881
+ }
882
+ /** Function declarations for the enabled members. A partial driver omits unsupported capabilities. */
883
+ tools() {
884
+ const tools = Array.from(this.enabled, ([name, { member }]) => {
885
+ const spec = members[member];
886
+ const properties = Object.fromEntries(Object.entries(spec.args).map(([key, field]) => [key, structuredClone(fields[field])]));
887
+ return {
888
+ type: 'function',
889
+ name,
890
+ description: spec.description,
891
+ strict: true,
892
+ parameters: {
893
+ type: 'object',
894
+ properties,
895
+ required: Object.keys(properties),
896
+ additionalProperties: false,
897
+ },
898
+ };
899
+ });
900
+ protectBrowserOutput(tools);
901
+ return tools;
902
+ }
903
+ /** Stop new work. If draining, await the current execute before closing your driver. */
904
+ close() {
905
+ return this.lifecycle.close();
906
+ }
907
+ /** Execute one completed browser function for a caller-managed loop.
908
+ * Accepts generated API call types and checks status before any driver work.
909
+ */
910
+ async execute(call, options = {}) {
911
+ const result = await this.executeWithStatus(call, (0, runner_lifecycle_1.configuredOption)(options, 'signal'));
912
+ return result.output;
913
+ }
914
+ /** Executes or skips a registered call and reports failure without parsing its public output.
915
+ * @internal
916
+ */
917
+ async executeWithStatus(call, signal, skip = false, onDiagnostic) {
918
+ this.lifecycle.enter();
919
+ try {
920
+ const result = await this.executeOwned(call, signal, skip, onDiagnostic);
921
+ protectBrowserOutput(result.output);
922
+ return result;
923
+ }
924
+ finally {
925
+ this.lifecycle.leave();
926
+ }
927
+ }
928
+ async approveRead(snapshot, member, skip, observer, signal) {
929
+ let stage = 'arguments';
930
+ let started = performance.now();
931
+ try {
932
+ if (skip || !('confirmReads' in this.options)) {
933
+ throw new BrowserError('Read declined.');
934
+ }
935
+ const args = JSON.parse(snapshot.arguments);
936
+ validateArguments(member, args);
937
+ // SAFETY: confirmReads contains only fixed read members and the arguments were validated above.
938
+ const context = {
939
+ phase: 'before_read',
940
+ member,
941
+ arguments: args,
942
+ call_id: snapshot.call_id,
943
+ state: null,
944
+ };
945
+ stage = 'approval';
946
+ started = performance.now();
947
+ const approved = await (0, runner_lifecycle_1.configuredOption)(this.options, 'confirm')?.call(this.options, protectBrowserOutput(structuredClone(context)), { signal });
948
+ signal?.throwIfAborted();
949
+ if (approved !== true) {
950
+ throw new BrowserError('Read declined.');
951
+ }
952
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, { api: 'browser', stage, reason: 'completed', call_id: snapshot.call_id, member }, started);
953
+ }
954
+ catch {
955
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, {
956
+ api: 'browser',
957
+ stage,
958
+ reason: (0, runner_diagnostics_1.diagnosticFailure)(stage, signal),
959
+ call_id: snapshot.call_id,
960
+ member,
961
+ }, started);
962
+ signal?.throwIfAborted();
963
+ return {
964
+ type: 'function_call_output',
965
+ call_id: snapshot.call_id,
966
+ output: [
967
+ { type: 'input_text', text: serializeBrowserOutput({ ok: false, error: 'Read declined.' }) },
968
+ ],
969
+ };
970
+ }
971
+ return undefined;
972
+ }
973
+ // oxlint-disable-next-line eslint/complexity -- TS4.9 needs explicit record checks here to retain the native call type.
974
+ async executeOwned(call, signal, skip = false, onDiagnostic) {
975
+ const snapshot = structuredClone(call);
976
+ if (snapshot === null ||
977
+ typeof snapshot !== 'object' ||
978
+ Array.isArray(snapshot) ||
979
+ !['name', 'type', 'call_id', 'status', 'arguments'].every((field) => (0, values_1.hasOwn)(snapshot, field))) {
980
+ throw new error_1.OpenAIError('BrowserToolset requires a completed registered call.');
981
+ }
982
+ const selected = this.enabled.get(snapshot.name);
983
+ if (!selected ||
984
+ snapshot.type !== 'function_call' ||
985
+ typeof snapshot.call_id !== 'string' ||
986
+ snapshot.status !== 'completed') {
987
+ throw new error_1.OpenAIError('BrowserToolset requires a completed registered call.');
988
+ }
989
+ const replay = (0, ResponseInputItems_1.toResponseInputItems)([snapshot]);
990
+ (0, runner_lifecycle_1.protectRunnerJSON)(replay);
991
+ JSON.stringify(replay);
992
+ signal?.throwIfAborted();
993
+ const { member, handler } = selected;
994
+ // These may change between executions; an active call keeps its selected consent and state callbacks.
995
+ const policy = this.policyFor(member, skip);
996
+ const observer = onDiagnostic ?? (0, runner_lifecycle_1.configuredOption)(this.options, 'onDiagnostic')?.bind(this.options);
997
+ const privateRead = this.confirmReads.has(member);
998
+ if (privateRead) {
999
+ const declined = await this.approveRead(snapshot, member, skip, observer, signal);
1000
+ if (declined) {
1001
+ return { ok: false, output: declined };
1002
+ }
1003
+ }
1004
+ let report;
1005
+ try {
1006
+ const reporter = (0, runner_lifecycle_1.configuredOption)(this.driver, 'state');
1007
+ if (typeof reporter !== 'function') {
1008
+ throw new TypeError('Browser state requires a reporter.');
1009
+ }
1010
+ report = reporter.bind(this.driver);
1011
+ }
1012
+ catch {
1013
+ throw new error_1.OpenAIError('Browser state report failed.');
1014
+ }
1015
+ const before = await readState(report, signal);
1016
+ signal?.throwIfAborted();
1017
+ const { ok, result, failure } = await BrowserToolset.perform(snapshot, member, handler, before, policy, privateRead, skip, observer, signal);
1018
+ signal?.throwIfAborted();
1019
+ // State failures stop; an uncertain state must never be presented as success or retried.
1020
+ const state = await readState(report, signal, (0, values_1.hasOwn)(before, 'observation') ? before.observation : undefined);
1021
+ signal?.throwIfAborted();
1022
+ return BrowserToolset.output(snapshot.call_id, member, state, ok, result, failure);
1023
+ }
1024
+ static async perform(snapshot, member, handler, before, policy, privateRead, skip, observer, signal) {
1025
+ let stage = 'arguments';
1026
+ let started = performance.now();
1027
+ let ok = false;
1028
+ let result;
1029
+ let failure;
1030
+ try {
1031
+ if (skip) {
1032
+ throw new BrowserError('Skipped because an earlier browser call failed. Observe current state and replan.');
1033
+ }
1034
+ const args = JSON.parse(snapshot.arguments);
1035
+ validateArguments(member, args);
1036
+ if (member === 'list_tabs') {
1037
+ result = before;
1038
+ }
1039
+ else if (handler) {
1040
+ stage = 'approval';
1041
+ started = performance.now();
1042
+ await BrowserToolset.authorize(member, args, before, snapshot.call_id, policy, signal, privateRead);
1043
+ if (!privateRead && (requiresConsent(member) || member === 'navigate' || member === 'new_tab')) {
1044
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, { api: 'browser', stage, reason: 'completed', call_id: snapshot.call_id, member }, started);
1045
+ }
1046
+ signal?.throwIfAborted();
1047
+ stage = 'action';
1048
+ started = performance.now();
1049
+ result = await handler(args, { signal });
1050
+ signal?.throwIfAborted();
1051
+ }
1052
+ ok = true;
1053
+ }
1054
+ catch (error) {
1055
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, {
1056
+ api: 'browser',
1057
+ stage,
1058
+ call_id: snapshot.call_id,
1059
+ member,
1060
+ reason: (0, runner_diagnostics_1.diagnosticFailure)(stage, signal),
1061
+ }, started);
1062
+ signal?.throwIfAborted();
1063
+ const message = error instanceof BrowserError ? error.message : undefined;
1064
+ failure = typeof message === 'string' ? message : 'Browser operation failed.';
1065
+ }
1066
+ // Snapshot successful opt-ins before any later callback or await. Contract
1067
+ // errors stop the run rather than becoming ordinary driver refusals.
1068
+ if (ok) {
1069
+ try {
1070
+ result = snapshotResult(member, result);
1071
+ }
1072
+ catch (error) {
1073
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, { api: 'browser', stage: 'output', reason: 'invalid_output', call_id: snapshot.call_id, member }, started);
1074
+ throw error;
1075
+ }
1076
+ if (handler && member !== 'list_tabs') {
1077
+ (0, runner_diagnostics_1.reportDiagnostic)(observer, { api: 'browser', stage: 'action', reason: 'completed', call_id: snapshot.call_id, member }, started);
1078
+ }
1079
+ ok = resultCompleted(member, result);
1080
+ }
1081
+ signal?.throwIfAborted();
1082
+ return { ok, result, failure };
1083
+ }
1084
+ policyFor(member, skip) {
1085
+ try {
1086
+ return {
1087
+ confirm: !skip && requiresConsent(member)
1088
+ ? (0, runner_lifecycle_1.configuredOption)(this.options, 'confirm')?.bind(this.options)
1089
+ : undefined,
1090
+ urlPolicy: !skip && (member === 'navigate' || member === 'new_tab')
1091
+ ? (0, runner_lifecycle_1.configuredOption)(this.options, 'urlPolicy')?.bind(this.options)
1092
+ : undefined,
1093
+ };
1094
+ }
1095
+ catch {
1096
+ throw new error_1.OpenAIError('Browser operation failed.');
1097
+ }
1098
+ }
1099
+ static output(callId, member, state, ok, result, failure) {
1100
+ const content = [
1101
+ {
1102
+ type: 'input_text',
1103
+ text: serializeBrowserOutput({
1104
+ ok,
1105
+ result: member === 'screenshot' || member === 'zoom' ? undefined : result,
1106
+ error: failure,
1107
+ state,
1108
+ }),
1109
+ },
1110
+ ];
1111
+ if (ok && (member === 'screenshot' || member === 'zoom')) {
1112
+ // SAFETY: snapshotResult validated and detached the selected image before the final state callback.
1113
+ const image = result;
1114
+ content.push(image);
1115
+ }
1116
+ return {
1117
+ ok,
1118
+ output: { type: 'function_call_output', call_id: callId, output: content },
1119
+ };
1120
+ }
1121
+ static async authorize(member, args, state, callId, policy, signal, readApproved = false) {
1122
+ // SAFETY: validateArguments matched the captured member against its fixed schema before authorization.
1123
+ const context = {
1124
+ member,
1125
+ arguments: args,
1126
+ // Keep absent observations captured for consent without adding them to driver or wire state.
1127
+ state: { ...state, observation: (0, values_1.hasOwn)(state, 'observation') ? state.observation : undefined },
1128
+ call_id: callId,
1129
+ };
1130
+ if (member === 'navigate' || member === 'new_tab') {
1131
+ const { url } = args;
1132
+ if (url !== null &&
1133
+ typeof url === 'string' &&
1134
+ (await policy.urlPolicy?.(protectBrowserOutput(structuredClone(context)), url, { signal })) !== true) {
1135
+ throw new BrowserError('URL policy declined navigation.');
1136
+ }
1137
+ }
1138
+ signal?.throwIfAborted();
1139
+ if (!readApproved &&
1140
+ requiresConsent(member) &&
1141
+ (await policy.confirm?.(protectBrowserOutput(structuredClone(context)), { signal })) !== true) {
1142
+ throw new BrowserError('Action declined.');
1143
+ }
1144
+ signal?.throwIfAborted();
1145
+ }
1146
+ }
1147
+ exports.BrowserToolset = BrowserToolset;
1148
+ //# sourceMappingURL=browser.js.map