ai-dev-browser 0.9.2__tar.gz → 0.9.4__tar.gz

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 (182) hide show
  1. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/PKG-INFO +1 -1
  2. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/browser.py +8 -0
  3. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/chrome.py +16 -2
  4. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/pool/job.py +49 -1
  5. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/pool/pool.py +30 -9
  6. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser.egg-info/PKG-INFO +1 -1
  7. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.github/workflows/ci.yml +0 -0
  8. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.github/workflows/publish.yml +0 -0
  9. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.gitignore +0 -0
  10. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.gitmodules +0 -0
  11. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.pre-commit-config.yaml +0 -0
  12. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/.secrets.baseline +0 -0
  13. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/LICENSE +0 -0
  14. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/README.md +0 -0
  15. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/__init__.py +0 -0
  16. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/_cli.py +0 -0
  17. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/_version.py +0 -0
  18. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/__init__.py +0 -0
  19. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/accessibility.py +0 -0
  20. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/animation.py +0 -0
  21. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/audits.py +0 -0
  22. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/autofill.py +0 -0
  23. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/background_service.py +0 -0
  24. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/bluetooth_emulation.py +0 -0
  25. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/browser.py +0 -0
  26. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/cache_storage.py +0 -0
  27. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/cast.py +0 -0
  28. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/console.py +0 -0
  29. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/crash_report_context.py +0 -0
  30. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/css.py +0 -0
  31. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/debugger.py +0 -0
  32. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/device_access.py +0 -0
  33. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/device_orientation.py +0 -0
  34. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/dom.py +0 -0
  35. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/dom_debugger.py +0 -0
  36. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/dom_snapshot.py +0 -0
  37. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/dom_storage.py +0 -0
  38. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/emulation.py +0 -0
  39. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/event_breakpoints.py +0 -0
  40. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/extensions.py +0 -0
  41. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/fed_cm.py +0 -0
  42. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/fetch.py +0 -0
  43. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/file_system.py +0 -0
  44. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/headless_experimental.py +0 -0
  45. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/heap_profiler.py +0 -0
  46. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/indexed_db.py +0 -0
  47. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/input_.py +0 -0
  48. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/inspector.py +0 -0
  49. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/io.py +0 -0
  50. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/layer_tree.py +0 -0
  51. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/log.py +0 -0
  52. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/media.py +0 -0
  53. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/memory.py +0 -0
  54. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/network.py +0 -0
  55. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/overlay.py +0 -0
  56. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/page.py +0 -0
  57. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/performance.py +0 -0
  58. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/performance_timeline.py +0 -0
  59. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/preload.py +0 -0
  60. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/profiler.py +0 -0
  61. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/pwa.py +0 -0
  62. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/py.typed +0 -0
  63. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/runtime.py +0 -0
  64. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/schema.py +0 -0
  65. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/security.py +0 -0
  66. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/service_worker.py +0 -0
  67. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/smart_card_emulation.py +0 -0
  68. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/storage.py +0 -0
  69. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/system_info.py +0 -0
  70. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/target.py +0 -0
  71. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/tethering.py +0 -0
  72. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/tracing.py +0 -0
  73. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/util.py +0 -0
  74. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/web_audio.py +0 -0
  75. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/web_authn.py +0 -0
  76. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/cdp/web_mcp.py +0 -0
  77. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/__init__.py +0 -0
  78. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/_case.py +0 -0
  79. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/_element.py +0 -0
  80. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/_tab.py +0 -0
  81. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/_transport.py +0 -0
  82. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/ax.py +0 -0
  83. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/cdp.py +0 -0
  84. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/cleanup.py +0 -0
  85. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/config.py +0 -0
  86. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/connection.py +0 -0
  87. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/cookies.py +0 -0
  88. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/dialog.py +0 -0
  89. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/download.py +0 -0
  90. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/elements.py +0 -0
  91. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/human.py +0 -0
  92. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/login.py +0 -0
  93. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/mouse.py +0 -0
  94. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/navigation.py +0 -0
  95. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/overlays.py +0 -0
  96. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/page.py +0 -0
  97. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/port.py +0 -0
  98. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/process.py +0 -0
  99. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/snapshot.py +0 -0
  100. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/storage.py +0 -0
  101. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/tabs.py +0 -0
  102. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/text_match.py +0 -0
  103. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/core/window.py +0 -0
  104. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/pool/__init__.py +0 -0
  105. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/pool/persistence.py +0 -0
  106. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/pool/worker.py +0 -0
  107. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/profile.py +0 -0
  108. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/py.typed +0 -0
  109. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/__init__.py +0 -0
  110. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/_generate.py +0 -0
  111. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/browser_list.py +0 -0
  112. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/browser_start.py +0 -0
  113. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/browser_stop.py +0 -0
  114. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/cdp_send.py +0 -0
  115. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/click_by_html_id.py +0 -0
  116. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/click_by_ref.py +0 -0
  117. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/click_by_text.py +0 -0
  118. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/click_by_xpath.py +0 -0
  119. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/cookies_list.py +0 -0
  120. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/cookies_load.py +0 -0
  121. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/cookies_save.py +0 -0
  122. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/dialog_respond.py +0 -0
  123. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/download.py +0 -0
  124. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/drag_by_ref.py +0 -0
  125. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/find_by_html_id.py +0 -0
  126. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/find_by_text.py +0 -0
  127. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/find_by_xpath.py +0 -0
  128. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/focus_by_ref.py +0 -0
  129. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/highlight_by_ref.py +0 -0
  130. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/hover_by_ref.py +0 -0
  131. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/html_by_ref.py +0 -0
  132. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/js_evaluate.py +0 -0
  133. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/login_interactive.py +0 -0
  134. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/mouse_click.py +0 -0
  135. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/mouse_drag.py +0 -0
  136. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/mouse_move.py +0 -0
  137. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_discover.py +0 -0
  138. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_emulate_focus.py +0 -0
  139. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_goto.py +0 -0
  140. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_html.py +0 -0
  141. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_info.py +0 -0
  142. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_reload.py +0 -0
  143. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_screenshot.py +0 -0
  144. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_scroll.py +0 -0
  145. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_wait_element.py +0 -0
  146. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_wait_ready.py +0 -0
  147. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/page_wait_url.py +0 -0
  148. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/screenshot_by_ref.py +0 -0
  149. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/select_by_ref.py +0 -0
  150. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/storage_get.py +0 -0
  151. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/storage_set.py +0 -0
  152. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/tab_close.py +0 -0
  153. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/tab_list.py +0 -0
  154. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/tab_new.py +0 -0
  155. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/tab_switch.py +0 -0
  156. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/type_by_ref.py +0 -0
  157. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/type_by_text.py +0 -0
  158. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/upload_by_ref.py +0 -0
  159. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser/tools/window_set.py +0 -0
  160. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser.egg-info/SOURCES.txt +0 -0
  161. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser.egg-info/dependency_links.txt +0 -0
  162. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser.egg-info/requires.txt +0 -0
  163. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/ai_dev_browser.egg-info/top_level.txt +0 -0
  164. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/pyproject.toml +0 -0
  165. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/scripts/sync_cdp.py +0 -0
  166. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/setup.cfg +0 -0
  167. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/__init__.py +0 -0
  168. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/conftest.py +0 -0
  169. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/__init__.py +0 -0
  170. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/scenarios_workspace.json +0 -0
  171. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_dialog_respond.py +0 -0
  172. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_find_and_interact_workflows.py +0 -0
  173. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_locator_workflows.py +0 -0
  174. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_multi_profile_pool.py +0 -0
  175. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_page_reload.py +0 -0
  176. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_startup_timeout.py +0 -0
  177. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_timeout_and_retry.py +0 -0
  178. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/integration/test_workspace_workflows.py +0 -0
  179. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/unit/test_case.py +0 -0
  180. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/unit/test_cli_param_type.py +0 -0
  181. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/tests/unit/test_no_acronym_rot.py +0 -0
  182. {ai_dev_browser-0.9.2 → ai_dev_browser-0.9.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: A browser for AI to develop web automation — human-like automation that works seamlessly in a world designed for humans
5
5
  Author: sudoprivacy
6
6
  License: AGPL-3.0
@@ -77,6 +77,7 @@ def browser_start(
77
77
  startup_timeout: float = 30.0,
78
78
  extra_args: list[str] | None = None,
79
79
  disable_default_args: list[str] | None = None,
80
+ silent_stderr: bool = False,
80
81
  ) -> dict:
81
82
  """Start or reuse a browser instance.
82
83
 
@@ -106,6 +107,12 @@ def browser_start(
106
107
  logic and what removing them costs (in particular,
107
108
  `--enable-automation` removal makes the Chrome invisible to
108
109
  `browser_list` workspace filter and `browser_cleanup`).
110
+ silent_stderr: If True, route Chrome's stderr to DEVNULL instead
111
+ of PIPE. Use in long-running / multi-agent scenarios where
112
+ you don't want Chrome's GPU/Crashpad/V8 subsystems filling
113
+ the pipe buffer. Trade-off: loses Chrome's exit-time stderr
114
+ in the error path (falls back to generic "Chrome exited
115
+ silently"). See `launch_chrome` docstring for details.
109
116
 
110
117
  Returns:
111
118
  dict with port, pid, headless, url, profile, reused, message
@@ -174,6 +181,7 @@ def browser_start(
174
181
  user_data_dir=str(user_data_dir) if user_data_dir else None,
175
182
  extra_args=extra_args,
176
183
  disable_default_args=disable_default_args,
184
+ silent_stderr=silent_stderr,
177
185
  )
178
186
 
179
187
  # Wait for Chrome to bind its debug port.
@@ -131,6 +131,7 @@ def launch_chrome(
131
131
  profile_prefix: str = DEFAULT_PROFILE_PREFIX,
132
132
  extra_args: list[str] | None = None,
133
133
  disable_default_args: list[str] | None = None,
134
+ silent_stderr: bool = False,
134
135
  start_url: str = "about:blank",
135
136
  disable_session_restore: bool = True,
136
137
  disable_session_crashed_bubble: bool = True,
@@ -148,6 +149,18 @@ def launch_chrome(
148
149
  user_data_dir: Custom user data directory. If None, creates a temp directory.
149
150
  profile_prefix: Prefix for temp profile directory name
150
151
  extra_args: Additional Chrome command-line arguments appended after defaults.
152
+ silent_stderr: If True, route Chrome's stderr to `subprocess.DEVNULL`
153
+ instead of `subprocess.PIPE`. Default False preserves current
154
+ behavior — `browser_start` captures Chrome's exit-time stderr
155
+ to surface in the "Chrome exited unexpectedly" error.
156
+
157
+ Set True in long-running multi-instance / multi-agent scenarios
158
+ where you don't need the diagnostic and want to avoid PIPE
159
+ buffer pressure from Chrome's GPU / Crashpad / V8 subsystems
160
+ (these subsystems ignore `--disable-logging` and emit
161
+ unconditional stderr). Trade-off: on a Chrome-exit-on-startup,
162
+ the error message falls back to the generic "Chrome exited
163
+ silently" wording with no captured detail.
151
164
  disable_default_args: List of default Chrome flags to remove before launch.
152
165
  Match is exact for `--flag` form and prefix-equality for `--flag=value`
153
166
  form (e.g. `["--enable-automation"]` strips both). Use this when a
@@ -261,16 +274,17 @@ def launch_chrome(
261
274
  # Use subprocess.Popen on all platforms
262
275
  # On Unix, use start_new_session to detach from parent
263
276
  # On Windows, CREATE_NEW_PROCESS_GROUP for similar isolation
277
+ stderr_target = subprocess.DEVNULL if silent_stderr else subprocess.PIPE
264
278
  if platform.system() == "Windows":
265
279
  popen_kwargs = {
266
280
  "stdout": subprocess.DEVNULL,
267
- "stderr": subprocess.PIPE,
281
+ "stderr": stderr_target,
268
282
  "creationflags": subprocess.CREATE_NEW_PROCESS_GROUP,
269
283
  }
270
284
  else:
271
285
  popen_kwargs = {
272
286
  "stdout": subprocess.DEVNULL,
273
- "stderr": subprocess.PIPE,
287
+ "stderr": stderr_target,
274
288
  "start_new_session": True,
275
289
  }
276
290
 
@@ -96,7 +96,15 @@ class JobResult:
96
96
  job_id: ID of the job this result belongs to
97
97
  success: True if job completed without error
98
98
  data: Return value from the client method (JSON-serializable)
99
- error: Error message if job failed
99
+ error: Error message if job failed (from `str(exception)`)
100
+ error_type: Exception class name if job failed (e.g.
101
+ `"GrokRateLimitError"`). Lets callers branch on exception
102
+ type without string-matching `error`. None on success.
103
+ error_bases: List of exception base-class names from the mro,
104
+ excluding `object` (e.g.
105
+ `["RateLimitError", "RuntimeError", "Exception"]`). Lets
106
+ callers match superclasses when the concrete type is
107
+ domain-specific but the base is standard. Empty on success.
100
108
  completed_at: Timestamp when job completed
101
109
  worker_id: ID of the worker that executed the job
102
110
 
@@ -107,15 +115,51 @@ class JobResult:
107
115
  data={"url": "https://example.com", "title": "Example"},
108
116
  worker_id=0,
109
117
  )
118
+
119
+ # Failure branching without text matching:
120
+ if not result.success:
121
+ if result.error_type == "GrokRateLimitError":
122
+ schedule_retry()
123
+ elif "TimeoutError" in result.error_bases:
124
+ ...
110
125
  """
111
126
 
112
127
  job_id: str
113
128
  success: bool
114
129
  data: Any = None
115
130
  error: str | None = None
131
+ error_type: str | None = None
132
+ error_bases: list[str] = field(default_factory=list)
116
133
  completed_at: datetime = field(default_factory=datetime.now)
117
134
  worker_id: int | None = None
118
135
 
136
+ @classmethod
137
+ def from_exception(
138
+ cls,
139
+ job_id: str,
140
+ exc: BaseException,
141
+ worker_id: int | None = None,
142
+ ) -> "JobResult":
143
+ """Build a failure result capturing the exception's type + mro.
144
+
145
+ Use inside worker exception handlers so callers downstream can
146
+ branch on `error_type` / `error_bases` without parsing
147
+ `error` text.
148
+ """
149
+ cls_chain = type(exc).__mro__
150
+ # mro ends with `object`; drop it. First element is the type
151
+ # itself, which we surface as `error_type`; the rest is bases.
152
+ error_type = cls_chain[0].__name__
153
+ error_bases = [c.__name__ for c in cls_chain[1:] if c is not object]
154
+ return cls(
155
+ job_id=job_id,
156
+ success=False,
157
+ error=str(exc),
158
+ error_type=error_type,
159
+ error_bases=error_bases,
160
+ worker_id=worker_id,
161
+ )
162
+
119
163
  def to_dict(self) -> dict:
120
164
  """Serialize result for persistence."""
121
165
  return {
@@ -123,6 +167,8 @@ class JobResult:
123
167
  "success": self.success,
124
168
  "data": self.data,
125
169
  "error": self.error,
170
+ "error_type": self.error_type,
171
+ "error_bases": self.error_bases,
126
172
  "completed_at": self.completed_at.isoformat(),
127
173
  "worker_id": self.worker_id,
128
174
  }
@@ -135,6 +181,8 @@ class JobResult:
135
181
  success=data["success"],
136
182
  data=data.get("data"),
137
183
  error=data.get("error"),
184
+ error_type=data.get("error_type"),
185
+ error_bases=data.get("error_bases") or [],
138
186
  completed_at=datetime.fromisoformat(data["completed_at"]),
139
187
  worker_id=data.get("worker_id"),
140
188
  )
@@ -697,7 +697,7 @@ class BrowserPool(Generic[ClientT]):
697
697
  )
698
698
 
699
699
  except Exception as e:
700
- await self._handle_job_failure(worker, job, str(e))
700
+ await self._handle_job_failure(worker, job, str(e), exc=e)
701
701
 
702
702
  finally:
703
703
  worker.mark_idle()
@@ -709,8 +709,22 @@ class BrowserPool(Generic[ClientT]):
709
709
  logger.error(f"Worker {worker.worker_id} loop error: {e}")
710
710
  await asyncio.sleep(1)
711
711
 
712
- async def _handle_job_failure(self, worker: Worker, job: Job, error: str) -> None:
713
- """Handle job failure - retry or mark as failed."""
712
+ async def _handle_job_failure(
713
+ self,
714
+ worker: Worker,
715
+ job: Job,
716
+ error: str,
717
+ *,
718
+ exc: BaseException | None = None,
719
+ ) -> None:
720
+ """Handle job failure - retry or mark as failed.
721
+
722
+ If `exc` is provided (exception caught in the worker loop), the
723
+ terminal `JobResult` captures `error_type` + `error_bases` so
724
+ callers can branch on exception type without parsing `error`.
725
+ Non-exception failures (e.g. `fail_condition` triggered) pass
726
+ only `error` and the type fields stay None / [].
727
+ """
714
728
  job.retries += 1
715
729
  worker.stats.fail += 1
716
730
 
@@ -725,12 +739,19 @@ class BrowserPool(Generic[ClientT]):
725
739
  f"({job.job_id[:8]}...), retry {job.retries}: {error}"
726
740
  )
727
741
  else:
728
- result = JobResult(
729
- job_id=job.job_id,
730
- success=False,
731
- error=error,
732
- worker_id=worker.worker_id,
733
- )
742
+ if exc is not None:
743
+ result = JobResult.from_exception(
744
+ job_id=job.job_id,
745
+ exc=exc,
746
+ worker_id=worker.worker_id,
747
+ )
748
+ else:
749
+ result = JobResult(
750
+ job_id=job.job_id,
751
+ success=False,
752
+ error=error,
753
+ worker_id=worker.worker_id,
754
+ )
734
755
  self._results[job.job_id] = result
735
756
  self._pending_jobs.pop(job.job_id, None)
736
757
  job.status = JobStatus.FAILED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: A browser for AI to develop web automation — human-like automation that works seamlessly in a world designed for humans
5
5
  Author: sudoprivacy
6
6
  License: AGPL-3.0
File without changes
File without changes
File without changes
File without changes