@elizaos/sweagent-root 2.0.0-alpha

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 (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/package.json +71 -0
  4. package/python/LICENSE +21 -0
  5. package/python/config/README.md +15 -0
  6. package/python/config/bash_only.yaml +222 -0
  7. package/python/config/benchmarks/250212_sweagent_heavy_sbl.yaml +188 -0
  8. package/python/config/benchmarks/250225_anthropic_filemap_simple_review.yaml +75 -0
  9. package/python/config/benchmarks/250522_anthropic_filemap_simple_review.yaml +92 -0
  10. package/python/config/benchmarks/250526_anthropic_filemap_simple_review_sbl.yaml +93 -0
  11. package/python/config/benchmarks/anthropic_filemap_multilingual.yaml +66 -0
  12. package/python/config/coding_challenge.yaml +104 -0
  13. package/python/config/default.yaml +69 -0
  14. package/python/config/default_backticks.yaml +69 -0
  15. package/python/config/default_mm_no_images.yaml +82 -0
  16. package/python/config/default_mm_with_images.yaml +83 -0
  17. package/python/config/demo/default.yaml +80 -0
  18. package/python/config/demo/no_instructions.yaml +69 -0
  19. package/python/config/demo/only_bash.yaml +60 -0
  20. package/python/config/exotic/default_shell.yaml +52 -0
  21. package/python/config/exotic/windowed_replace.yaml +125 -0
  22. package/python/config/exotic/windowed_replace_late_repro.yaml +127 -0
  23. package/python/config/human/human.yaml +24 -0
  24. package/python/config/human/human_demo.yaml +52 -0
  25. package/python/config/sweagent_0_7/07.yaml +101 -0
  26. package/python/config/sweagent_0_7/07_fcalling.yaml +100 -0
  27. package/python/config/sweagent_0_7/07_from_url.yaml +114 -0
  28. package/python/config/sweagent_0_7/07_thought_action.yaml +102 -0
  29. package/python/config/sweagent_0_7/07_thought_action_xml.yaml +96 -0
  30. package/python/mlc_config.json +44 -0
  31. package/python/pyproject.toml +262 -0
  32. package/python/sweagent/__init__.py +114 -0
  33. package/python/sweagent/__main__.py +4 -0
  34. package/python/sweagent/agent/__init__.py +0 -0
  35. package/python/sweagent/agent/action_sampler.py +317 -0
  36. package/python/sweagent/agent/agents.py +1294 -0
  37. package/python/sweagent/agent/extra/shell_agent.py +106 -0
  38. package/python/sweagent/agent/history_processors.py +399 -0
  39. package/python/sweagent/agent/hooks/__init__.py +0 -0
  40. package/python/sweagent/agent/hooks/abstract.py +139 -0
  41. package/python/sweagent/agent/hooks/status.py +34 -0
  42. package/python/sweagent/agent/models.py +896 -0
  43. package/python/sweagent/agent/problem_statement.py +312 -0
  44. package/python/sweagent/agent/reviewer.py +664 -0
  45. package/python/sweagent/environment/__init__.py +0 -0
  46. package/python/sweagent/environment/hooks/__init__.py +0 -0
  47. package/python/sweagent/environment/hooks/abstract.py +60 -0
  48. package/python/sweagent/environment/hooks/status.py +28 -0
  49. package/python/sweagent/environment/repo.py +219 -0
  50. package/python/sweagent/environment/swe_env.py +276 -0
  51. package/python/sweagent/exceptions.py +54 -0
  52. package/python/sweagent/inspector/README.md +6 -0
  53. package/python/sweagent/inspector/__init__.py +0 -0
  54. package/python/sweagent/inspector/favicon.ico +0 -0
  55. package/python/sweagent/inspector/fileViewer.js +354 -0
  56. package/python/sweagent/inspector/icons/computer.png +0 -0
  57. package/python/sweagent/inspector/icons/edit_icon.svg +11 -0
  58. package/python/sweagent/inspector/icons/swe-agent-logo-50.png +0 -0
  59. package/python/sweagent/inspector/icons/swellama_blue.png +0 -0
  60. package/python/sweagent/inspector/icons/swellama_brown.png +0 -0
  61. package/python/sweagent/inspector/icons/swellama_grey.png +0 -0
  62. package/python/sweagent/inspector/icons/swellama_tan.png +0 -0
  63. package/python/sweagent/inspector/index.html +25 -0
  64. package/python/sweagent/inspector/server.py +354 -0
  65. package/python/sweagent/inspector/static.py +169 -0
  66. package/python/sweagent/inspector/style.css +454 -0
  67. package/python/sweagent/run/__init__.py +0 -0
  68. package/python/sweagent/run/_progress.py +158 -0
  69. package/python/sweagent/run/batch_instances.py +419 -0
  70. package/python/sweagent/run/common.py +387 -0
  71. package/python/sweagent/run/compare_runs.py +123 -0
  72. package/python/sweagent/run/extract_pred.py +19 -0
  73. package/python/sweagent/run/hooks/__init__.py +0 -0
  74. package/python/sweagent/run/hooks/abstract.py +67 -0
  75. package/python/sweagent/run/hooks/apply_patch.py +106 -0
  76. package/python/sweagent/run/hooks/open_pr.py +244 -0
  77. package/python/sweagent/run/hooks/swe_bench_evaluate.py +113 -0
  78. package/python/sweagent/run/inspector_cli.py +493 -0
  79. package/python/sweagent/run/merge_predictions.py +64 -0
  80. package/python/sweagent/run/quick_stats.py +96 -0
  81. package/python/sweagent/run/remove_unfinished.py +63 -0
  82. package/python/sweagent/run/rich_test.py +91 -0
  83. package/python/sweagent/run/run.py +147 -0
  84. package/python/sweagent/run/run_batch.py +442 -0
  85. package/python/sweagent/run/run_replay.py +219 -0
  86. package/python/sweagent/run/run_shell.py +155 -0
  87. package/python/sweagent/run/run_single.py +225 -0
  88. package/python/sweagent/run/run_traj_to_demo.py +85 -0
  89. package/python/sweagent/tools/__init__.py +0 -0
  90. package/python/sweagent/tools/bundle.py +57 -0
  91. package/python/sweagent/tools/commands.py +220 -0
  92. package/python/sweagent/tools/parsing.py +619 -0
  93. package/python/sweagent/tools/tools.py +430 -0
  94. package/python/sweagent/tools/utils.py +108 -0
  95. package/python/sweagent/types.py +102 -0
  96. package/python/sweagent/utils/__init__.py +0 -0
  97. package/python/sweagent/utils/config.py +80 -0
  98. package/python/sweagent/utils/files.py +27 -0
  99. package/python/sweagent/utils/github.py +118 -0
  100. package/python/sweagent/utils/jinja_warnings.py +14 -0
  101. package/python/sweagent/utils/log.py +175 -0
  102. package/python/sweagent/utils/patch_formatter.py +152 -0
  103. package/python/sweagent/utils/serialization.py +45 -0
  104. package/python/tests/__init__.py +0 -0
  105. package/python/tests/conftest.py +191 -0
  106. package/python/tests/test_agent.py +258 -0
  107. package/python/tests/test_batch_instance.py +43 -0
  108. package/python/tests/test_commands/_interactive_dummy.py +35 -0
  109. package/python/tests/test_commands/interactive_dummy_wrapper.sh +29 -0
  110. package/python/tests/test_data/config_files/dummy_interactive.yaml +62 -0
  111. package/python/tests/test_data/data_sources/ctf/crypto/Katy/Dockerfile +20 -0
  112. package/python/tests/test_data/data_sources/ctf/crypto/Katy/README.md +13 -0
  113. package/python/tests/test_data/data_sources/ctf/crypto/Katy/challenge.json +12 -0
  114. package/python/tests/test_data/data_sources/ctf/crypto/Katy/customrandom.c +50 -0
  115. package/python/tests/test_data/data_sources/ctf/crypto/Katy/docker-compose.yml +14 -0
  116. package/python/tests/test_data/data_sources/ctf/crypto/Katy/release +0 -0
  117. package/python/tests/test_data/data_sources/ctf/crypto/Katy/server +0 -0
  118. package/python/tests/test_data/data_sources/ctf/crypto/Katy/solver.py +12 -0
  119. package/python/tests/test_data/data_sources/ctf/forensics/flash/README.md +16 -0
  120. package/python/tests/test_data/data_sources/ctf/forensics/flash/challenge.json +9 -0
  121. package/python/tests/test_data/data_sources/ctf/forensics/flash/flash_c8429a430278283c0e571baebca3d139.zip +0 -0
  122. package/python/tests/test_data/data_sources/ctf/misc/networking_1/README.md +15 -0
  123. package/python/tests/test_data/data_sources/ctf/misc/networking_1/challenge.json +10 -0
  124. package/python/tests/test_data/data_sources/ctf/misc/networking_1/networking.pcap +0 -0
  125. package/python/tests/test_data/data_sources/ctf/pwn/warmup/Dockerfile +28 -0
  126. package/python/tests/test_data/data_sources/ctf/pwn/warmup/README.md +14 -0
  127. package/python/tests/test_data/data_sources/ctf/pwn/warmup/challenge.json +14 -0
  128. package/python/tests/test_data/data_sources/ctf/pwn/warmup/docker-compose.yml +14 -0
  129. package/python/tests/test_data/data_sources/ctf/pwn/warmup/flag.txt +1 -0
  130. package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup +0 -0
  131. package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup.c +26 -0
  132. package/python/tests/test_data/data_sources/ctf/pwn/warmup/warmup.py +9 -0
  133. package/python/tests/test_data/data_sources/ctf/rev/rock/README.md +14 -0
  134. package/python/tests/test_data/data_sources/ctf/rev/rock/challenge.json +8 -0
  135. package/python/tests/test_data/data_sources/ctf/rev/rock/rock +0 -0
  136. package/python/tests/test_data/data_sources/ctf/rev/rock/rock.cpp +167 -0
  137. package/python/tests/test_data/data_sources/ctf/rev/rock/solution.cpp +24 -0
  138. package/python/tests/test_data/data_sources/ctf/rev/rock/test_solver/solution.py +6 -0
  139. package/python/tests/test_data/data_sources/ctf/rev/rock/test_solver/test.sh +10 -0
  140. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/000-default.conf +18 -0
  141. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/Dockerfile +20 -0
  142. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/file.pl +38 -0
  143. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/forms.pl +40 -0
  144. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/cgi/hello.pl +11 -0
  145. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/challenge.json +12 -0
  146. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/docker-compose.yml +14 -0
  147. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/flag +1 -0
  148. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/index.html +11 -0
  149. package/python/tests/test_data/data_sources/ctf/web/i_got_id_demo/solution.txt +1 -0
  150. package/python/tests/test_data/data_sources/debug_20240322.json +1 -0
  151. package/python/tests/test_data/data_sources/expert_instances.yaml +16 -0
  152. package/python/tests/test_data/data_sources/human_eval.json +1 -0
  153. package/python/tests/test_data/data_sources/simple_instances.yaml +3 -0
  154. package/python/tests/test_data/data_sources/simple_instances_long.yaml +30 -0
  155. package/python/tests/test_data/data_sources/swe-bench-dev-easy.json +1 -0
  156. package/python/tests/test_data/data_sources/swe-bench-dev-easy_first_only.json +1 -0
  157. package/python/tests/test_data/data_sources/swe-bench-lite-test.json +1 -0
  158. package/python/tests/test_data/trajectories/gpt4__swe-agent-test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/6e44b9__sweagenttestrepo-1c2844.traj +342 -0
  159. package/python/tests/test_data/trajectories/gpt4__swe-agent-test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/solution_missing_colon.py +15 -0
  160. package/python/tests/test_data/trajectories/gpt4__swe-agent__test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/args.yaml +518 -0
  161. package/python/tests/test_data/trajectories/gpt4__swe-agent__test-repo__default_from_url__t-0.00__p-0.95__c-3.00__install-1/swe-agent__test-repo-i1.traj +124 -0
  162. package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/all_preds.jsonl +1 -0
  163. package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/args.yaml +520 -0
  164. package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/patches/pydicom__pydicom-1458.patch +18 -0
  165. package/python/tests/test_data/trajectories/gpt4__swe-bench-dev-easy_first_only__default__t-0.00__p-0.95__c-3.00__install-1/pydicom__pydicom-1458.traj +257 -0
  166. package/python/tests/test_env.py +66 -0
  167. package/python/tests/test_env_utils.py +129 -0
  168. package/python/tests/test_history_processors.py +40 -0
  169. package/python/tests/test_models.py +23 -0
  170. package/python/tests/test_openai_live.py +164 -0
  171. package/python/tests/test_packaging.py +7 -0
  172. package/python/tests/test_parsing.py +131 -0
  173. package/python/tests/test_problem_statement_multimodal.py +111 -0
  174. package/python/tests/test_quick_stats.py +42 -0
  175. package/python/tests/test_run.py +37 -0
  176. package/python/tests/test_run_batch.py +110 -0
  177. package/python/tests/test_run_hooks.py +114 -0
  178. package/python/tests/test_run_replay.py +33 -0
  179. package/python/tests/test_run_single.py +125 -0
  180. package/python/tests/test_tools_command_parsing.py +193 -0
  181. package/python/tests/test_utils.py +15 -0
  182. package/python/tests/tools/__init__.py +0 -0
  183. package/python/tests/tools/conftest.py +12 -0
  184. package/python/tests/tools/test_default_utils.py +153 -0
  185. package/python/tests/tools/test_edit_replace.py +0 -0
  186. package/python/tests/tools/test_split_string.py +82 -0
  187. package/python/tests/utils.py +29 -0
  188. package/python/tools/diff_state/bin/_state_diff_state +52 -0
  189. package/python/tools/diff_state/config.yaml +2 -0
  190. package/python/tools/edit_anthropic/bin/_state_anthropic +21 -0
  191. package/python/tools/edit_anthropic/bin/str_replace_editor +710 -0
  192. package/python/tools/edit_anthropic/config.yaml +56 -0
  193. package/python/tools/edit_anthropic/install.sh +3 -0
  194. package/python/tools/filemap/bin/filemap +45 -0
  195. package/python/tools/filemap/config.yaml +9 -0
  196. package/python/tools/filemap/install.sh +2 -0
  197. package/python/tools/forfeit/bin/exit_forfeit +5 -0
  198. package/python/tools/forfeit/config.yaml +5 -0
  199. package/python/tools/image_tools/bin/view_image +36 -0
  200. package/python/tools/image_tools/config.yaml +9 -0
  201. package/python/tools/multilingual_setup/bin/do_nothing +2 -0
  202. package/python/tools/multilingual_setup/config.yaml +1 -0
  203. package/python/tools/multilingual_setup/install.sh +45 -0
  204. package/python/tools/registry/bin/_read_env +10 -0
  205. package/python/tools/registry/bin/_write_env +10 -0
  206. package/python/tools/registry/config.yaml +1 -0
  207. package/python/tools/registry/install.sh +6 -0
  208. package/python/tools/registry/lib/__init__.py +0 -0
  209. package/python/tools/registry/lib/registry.py +56 -0
  210. package/python/tools/review_on_submit_m/README.md +6 -0
  211. package/python/tools/review_on_submit_m/bin/submit +54 -0
  212. package/python/tools/review_on_submit_m/config.yaml +6 -0
  213. package/python/tools/review_on_submit_m/install.sh +0 -0
  214. package/python/tools/search/bin/find_file +31 -0
  215. package/python/tools/search/bin/search_dir +39 -0
  216. package/python/tools/search/bin/search_file +55 -0
  217. package/python/tools/search/config.yaml +37 -0
  218. package/python/tools/search/install.sh +3 -0
  219. package/python/tools/submit/bin/submit +17 -0
  220. package/python/tools/submit/config.yaml +5 -0
  221. package/python/tools/web_browser/bin/click_mouse +41 -0
  222. package/python/tools/web_browser/bin/close_site +28 -0
  223. package/python/tools/web_browser/bin/double_click_mouse +37 -0
  224. package/python/tools/web_browser/bin/drag_mouse +46 -0
  225. package/python/tools/web_browser/bin/execute_script_on_page +39 -0
  226. package/python/tools/web_browser/bin/get_console_output +48 -0
  227. package/python/tools/web_browser/bin/move_mouse +35 -0
  228. package/python/tools/web_browser/bin/navigate_back +33 -0
  229. package/python/tools/web_browser/bin/navigate_forward +33 -0
  230. package/python/tools/web_browser/bin/open_site +36 -0
  231. package/python/tools/web_browser/bin/press_keys_on_page +51 -0
  232. package/python/tools/web_browser/bin/reload_page +33 -0
  233. package/python/tools/web_browser/bin/run_web_browser_server +394 -0
  234. package/python/tools/web_browser/bin/screenshot_site +38 -0
  235. package/python/tools/web_browser/bin/scroll_on_page +40 -0
  236. package/python/tools/web_browser/bin/set_browser_window_size +40 -0
  237. package/python/tools/web_browser/bin/type_text +34 -0
  238. package/python/tools/web_browser/bin/wait_time +39 -0
  239. package/python/tools/web_browser/config.yaml +155 -0
  240. package/python/tools/web_browser/install.sh +22 -0
  241. package/python/tools/web_browser/lib/browser_manager.py +404 -0
  242. package/python/tools/web_browser/lib/web_browser_config.py +33 -0
  243. package/python/tools/web_browser/lib/web_browser_utils.py +126 -0
  244. package/python/tools/web_browser/test_console.html +1 -0
  245. package/python/tools/windowed/bin/_state +25 -0
  246. package/python/tools/windowed/bin/create +29 -0
  247. package/python/tools/windowed/bin/goto +37 -0
  248. package/python/tools/windowed/bin/open +49 -0
  249. package/python/tools/windowed/bin/scroll_down +12 -0
  250. package/python/tools/windowed/bin/scroll_up +13 -0
  251. package/python/tools/windowed/config.yaml +38 -0
  252. package/python/tools/windowed/install.sh +15 -0
  253. package/python/tools/windowed/lib/__init__.py +0 -0
  254. package/python/tools/windowed/lib/flake8_utils.py +147 -0
  255. package/python/tools/windowed/lib/windowed_file.py +312 -0
  256. package/python/tools/windowed_edit_linting/bin/edit +128 -0
  257. package/python/tools/windowed_edit_linting/config.yaml +31 -0
  258. package/python/tools/windowed_edit_linting/install.sh +5 -0
  259. package/python/tools/windowed_edit_replace/bin/edit +172 -0
  260. package/python/tools/windowed_edit_replace/bin/insert +77 -0
  261. package/python/tools/windowed_edit_replace/config.yaml +60 -0
  262. package/python/tools/windowed_edit_replace/install.sh +5 -0
  263. package/python/tools/windowed_edit_rewrite/bin/edit +78 -0
  264. package/python/tools/windowed_edit_rewrite/config.yaml +11 -0
  265. package/python/tools/windowed_edit_rewrite/install.sh +5 -0
  266. package/python/trajectories/demonstrations/ctf/crypto/BabyEncryption.traj +318 -0
  267. package/python/trajectories/demonstrations/ctf/crypto/BabyTimeCapsule.traj +197 -0
  268. package/python/trajectories/demonstrations/ctf/crypto/eps.traj +289 -0
  269. package/python/trajectories/demonstrations/ctf/crypto/katy.traj +368 -0
  270. package/python/trajectories/demonstrations/ctf/forensics/flash.traj +102 -0
  271. package/python/trajectories/demonstrations/ctf/misc/networking_1.traj +102 -0
  272. package/python/trajectories/demonstrations/ctf/pwn/warmup.traj +159 -0
  273. package/python/trajectories/demonstrations/ctf/rev/rock.traj +251 -0
  274. package/python/trajectories/demonstrations/ctf/web/i_got_id_demo.traj +422 -0
  275. package/python/trajectories/demonstrations/function_calling_simple.traj +151 -0
  276. package/python/trajectories/demonstrations/human_thought__swe-bench-HumanEvalFix-python__lcb__t-0.00__p-0.95__c-4.00__install-0/humanevalfix-python-0.traj +129 -0
  277. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default__t-0.20__p-0.95__c-2.00__install-1___install_from_source/marshmallow-code__marshmallow-1867.traj +318 -0
  278. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default_sys-env_cursors_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +251 -0
  279. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__default_sys-env_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +399 -0
  280. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling__install-1/marshmallow-code__marshmallow-1867.traj +594 -0
  281. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling_replace__install-1/marshmallow-code__marshmallow-1867.traj +592 -0
  282. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__function_calling_replace_from_source/marshmallow-code__marshmallow-1867.traj +3316 -0
  283. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__xml_sys-env_cursors_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +251 -0
  284. package/python/trajectories/demonstrations/replay__marshmallow-code__marshmallow-1867__xml_sys-env_window100__t-0.20__p-0.95__c-2.00__install-1/marshmallow-code__marshmallow-1867.traj +399 -0
  285. package/python/trajectories/demonstrations/str_replace_anthropic_demo.yaml +432 -0
  286. package/rust/Cargo.toml +100 -0
  287. package/rust/README.md +49 -0
  288. package/rust/src/agent/action_sampler.rs +130 -0
  289. package/rust/src/agent/agents.rs +1029 -0
  290. package/rust/src/agent/history_processors.rs +277 -0
  291. package/rust/src/agent/hooks/mod.rs +208 -0
  292. package/rust/src/agent/mod.rs +24 -0
  293. package/rust/src/agent/models.rs +837 -0
  294. package/rust/src/agent/problem_statement.rs +355 -0
  295. package/rust/src/agent/reviewer.rs +505 -0
  296. package/rust/src/bin/sweagent.rs +784 -0
  297. package/rust/src/environment/deployment.rs +631 -0
  298. package/rust/src/environment/hooks/mod.rs +114 -0
  299. package/rust/src/environment/mod.rs +16 -0
  300. package/rust/src/environment/repo.rs +265 -0
  301. package/rust/src/environment/runtime.rs +237 -0
  302. package/rust/src/environment/swe_env.rs +248 -0
  303. package/rust/src/exceptions.rs +228 -0
  304. package/rust/src/lib.rs +68 -0
  305. package/rust/src/monitoring.rs +482 -0
  306. package/rust/src/run/hooks/mod.rs +134 -0
  307. package/rust/src/run/mod.rs +12 -0
  308. package/rust/src/run/run_batch.rs +563 -0
  309. package/rust/src/run/run_single.rs +196 -0
  310. package/rust/src/tools/bundle.rs +224 -0
  311. package/rust/src/tools/commands.rs +173 -0
  312. package/rust/src/tools/mod.rs +295 -0
  313. package/rust/src/tools/parsing.rs +354 -0
  314. package/rust/src/tools/registry.rs +143 -0
  315. package/rust/src/types.rs +554 -0
  316. package/rust/src/utils/config.rs +105 -0
  317. package/rust/src/utils/files.rs +137 -0
  318. package/rust/src/utils/github.rs +171 -0
  319. package/rust/src/utils/log.rs +65 -0
  320. package/rust/src/utils/mod.rs +17 -0
  321. package/rust/src/utils/serialization.rs +181 -0
  322. package/rust/src/utils/template.rs +173 -0
  323. package/typescript/README.md +335 -0
@@ -0,0 +1,394 @@
1
+ #!/root/python3.11/bin/python3
2
+ """Web Browser server ‒ Flask + Playwright backend."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import atexit
7
+ import functools
8
+ import signal
9
+ import sys
10
+ import time
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
15
+ sys.path.insert(0, lib_path)
16
+
17
+ from browser_manager import BrowserManager
18
+ from flask import Flask, Response, jsonify, request
19
+ from web_browser_config import ServerConfig
20
+ from web_browser_utils import catch_error, normalize_url, validate_request
21
+
22
+ config = ServerConfig()
23
+
24
+
25
+ browser_manager = BrowserManager()
26
+
27
+
28
+ def cleanup_on_exit():
29
+ """Cleanup function for atexit and signal handlers."""
30
+ browser_manager.cleanup()
31
+
32
+
33
+ def signal_handler(signum, frame):
34
+ """Handle shutdown signals."""
35
+ print(f"\nReceived signal {signum}, shutting down...")
36
+ cleanup_on_exit()
37
+ sys.exit(0)
38
+
39
+
40
+ # register cleanup handlers
41
+ atexit.register(cleanup_on_exit)
42
+ signal.signal(signal.SIGINT, signal_handler)
43
+ signal.signal(signal.SIGTERM, signal_handler)
44
+
45
+
46
+ app = Flask(__name__)
47
+
48
+
49
+ def require_website_open(func):
50
+ """Decorator to ensure a website is open before executing the route."""
51
+
52
+ @functools.wraps(func)
53
+ def wrapper(*args, **kwargs):
54
+ if not browser_manager.is_website_open():
55
+ return create_response({"status": "error", "message": "Please open a website first."}, False)
56
+ return func(*args, **kwargs)
57
+
58
+ return wrapper
59
+
60
+
61
+ def _get_response_metadata() -> dict[str, Any]:
62
+ """Gather comprehensive metadata for API responses."""
63
+ metadata = {}
64
+ if browser_manager.is_website_open():
65
+ metadata["Browser Type"] = browser_manager.browser_name
66
+ metadata["Mouse Position"] = f"({browser_manager.mouse_x},{browser_manager.mouse_y})"
67
+ metadata["Viewport Size"] = f"{browser_manager.window_width}×{browser_manager.window_height}"
68
+ with browser_manager._browser_lock() as page:
69
+ metadata["Current URL"] = page.url
70
+ metadata["Page Title"] = page.title()
71
+
72
+ scroll_info = page.evaluate("""() => ({
73
+ scroll_position: { x: window.pageXOffset || document.documentElement.scrollLeft, y: window.pageYOffset || document.documentElement.scrollTop },
74
+ page_dimensions: { width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight },
75
+ visible_dimensions: { width: window.innerWidth, height: window.innerHeight }
76
+ })""")
77
+ scroll_pos = scroll_info["scroll_position"]
78
+ page_dims = scroll_info["page_dimensions"]
79
+ visible_dims = scroll_info["visible_dimensions"]
80
+ metadata["Scroll Position"] = f"({scroll_pos['x']},{scroll_pos['y']})"
81
+ metadata["Page Dimensions"] = f"{page_dims['width']}×{page_dims['height']}"
82
+ metadata["Visible Dimensions"] = f"{visible_dims['width']}×{visible_dims['height']}"
83
+ return metadata
84
+
85
+
86
+ def create_response(data: dict[str, Any], return_screenshot: bool) -> Response:
87
+ """Create a JSON response with comprehensive metadata and optional screenshot."""
88
+ response_data = {**data}
89
+ if return_screenshot:
90
+ response_data.update(browser_manager.take_screenshot())
91
+ if "metadata" not in response_data:
92
+ response_data["metadata"] = {}
93
+ response_data["metadata"].update(_get_response_metadata())
94
+ return jsonify(response_data)
95
+
96
+
97
+ @app.route("/info", methods=["GET"])
98
+ @catch_error
99
+ def info():
100
+ if not browser_manager.is_website_open():
101
+ return create_response({"status": "success", "message": "No page open"}, False)
102
+ data = {
103
+ "status": "success",
104
+ "message": "Loaded info for current page",
105
+ }
106
+ return create_response(data, False)
107
+
108
+
109
+ @app.route("/close", methods=["POST"])
110
+ @catch_error
111
+ def close_browser():
112
+ browser_manager.cleanup()
113
+ browser_manager._init_browser()
114
+ return create_response({"status": "success", "message": "Closed browser"}, False)
115
+
116
+
117
+ @app.route("/set_window_size", methods=["POST"])
118
+ @validate_request("width", "height", "return_screenshot")
119
+ @require_website_open
120
+ @catch_error
121
+ def set_window_size():
122
+ width, height = request.json["width"], request.json["height"]
123
+ return_screenshot = request.json["return_screenshot"]
124
+ if width <= 0 or height <= 0:
125
+ return create_response(
126
+ {"status": "error", "message": f"Invalid dimensions ({width},{height}). Must be positive"}, False
127
+ )
128
+ with browser_manager._browser_lock() as page:
129
+ page.set_viewport_size({"width": width, "height": height})
130
+ browser_manager.window_width = width
131
+ browser_manager.window_height = height
132
+ browser_manager.constrain_mouse_position(page)
133
+ data = {"status": "success", "message": f"Set viewport to {width}×{height}"}
134
+ return create_response(data, return_screenshot)
135
+
136
+
137
+ @app.route("/screenshot", methods=["GET"])
138
+ @require_website_open
139
+ def screenshot():
140
+ data = {"status": "success", "message": "Screenshot"}
141
+ return create_response(data, True)
142
+
143
+
144
+ @app.route("/click", methods=["POST"])
145
+ @validate_request("x", "y", "button", "return_screenshot")
146
+ @catch_error
147
+ @require_website_open
148
+ def click():
149
+ x, y = round(request.json["x"]), round(request.json["y"])
150
+ button = request.json["button"]
151
+ return_screenshot = request.json["return_screenshot"]
152
+ x_valid, y_valid = browser_manager.validate_coordinates(x, y)
153
+ if not x_valid or not y_valid:
154
+ return create_response(
155
+ {
156
+ "status": "error",
157
+ "message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
158
+ },
159
+ False,
160
+ )
161
+ with browser_manager._browser_lock() as page:
162
+ page.mouse.click(x, y, button=button)
163
+ browser_manager.mouse_x, browser_manager.mouse_y = x, y
164
+ data = {"status": "success", "message": f"Clicked '{button}' at ({x},{y})"}
165
+ return create_response(data, return_screenshot)
166
+
167
+
168
+ @app.route("/double_click", methods=["POST"])
169
+ @validate_request("x", "y", "return_screenshot")
170
+ @catch_error
171
+ @require_website_open
172
+ def double_click():
173
+ x, y = round(request.json["x"]), round(request.json["y"])
174
+ return_screenshot = request.json["return_screenshot"]
175
+ x_valid, y_valid = browser_manager.validate_coordinates(x, y)
176
+ if not x_valid or not y_valid:
177
+ return create_response(
178
+ {
179
+ "status": "error",
180
+ "message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
181
+ },
182
+ False,
183
+ )
184
+ with browser_manager._browser_lock() as page:
185
+ page.mouse.dblclick(x, y)
186
+ browser_manager.mouse_x, browser_manager.mouse_y = x, y
187
+ data = {"status": "success", "message": f"Double‑clicked at ({x},{y})"}
188
+ return create_response(data, return_screenshot)
189
+
190
+
191
+ @app.route("/move", methods=["POST"])
192
+ @validate_request("x", "y", "return_screenshot")
193
+ @catch_error
194
+ @require_website_open
195
+ def move():
196
+ x, y = request.json["x"], request.json["y"]
197
+ return_screenshot = request.json["return_screenshot"]
198
+ x_valid, y_valid = browser_manager.validate_coordinates(x, y)
199
+ if not x_valid or not y_valid:
200
+ return create_response(
201
+ {
202
+ "status": "error",
203
+ "message": f"Invalid coordinates ({x},{y}). Must be within {browser_manager.window_width}x{browser_manager.window_height}",
204
+ },
205
+ False,
206
+ )
207
+ with browser_manager._browser_lock() as page:
208
+ page.mouse.move(x, y)
209
+ browser_manager.mouse_x, browser_manager.mouse_y = x, y
210
+ data = {"status": "success", "message": f"Moved mouse to ({x},{y})"}
211
+ return create_response(data, return_screenshot)
212
+
213
+
214
+ @app.route("/drag", methods=["POST"])
215
+ @validate_request("path", "return_screenshot")
216
+ @catch_error
217
+ @require_website_open
218
+ def drag():
219
+ path: list[list[int]] = request.json["path"]
220
+ return_screenshot = request.json["return_screenshot"]
221
+ if not path or len(path) < 2:
222
+ return create_response({"status": "error", "message": "Path needs at least two points"}, False)
223
+ for ix, point in enumerate(path):
224
+ if len(point) != 2:
225
+ return create_response(
226
+ {"status": "error", "message": f"Path point {ix} must have exactly 2 coordinates"}, False
227
+ )
228
+ x, y = point
229
+ x_valid, y_valid = browser_manager.validate_coordinates(x, y)
230
+ if not x_valid or not y_valid:
231
+ return create_response(
232
+ {
233
+ "status": "error",
234
+ "message": f"Invalid coordinates ({x},{y}) at path point {ix}. Must be within {browser_manager.window_width}x{browser_manager.window_height}",
235
+ },
236
+ False,
237
+ )
238
+
239
+ with browser_manager._browser_lock() as page:
240
+ page.mouse.move(*path[0])
241
+ page.mouse.down()
242
+ for x, y in path[1:]:
243
+ page.mouse.move(x, y)
244
+ page.mouse.up()
245
+ browser_manager.mouse_x, browser_manager.mouse_y = path[-1]
246
+ data = {"status": "success", "message": "Dragged the mouse along the path"}
247
+ return create_response(data, return_screenshot)
248
+
249
+
250
+ @app.route("/type", methods=["POST"])
251
+ @validate_request("text", "return_screenshot")
252
+ @catch_error
253
+ @require_website_open
254
+ def type_():
255
+ text = request.json["text"]
256
+ return_screenshot = request.json["return_screenshot"]
257
+ with browser_manager._browser_lock() as page:
258
+ page.keyboard.type(text)
259
+ data = {"status": "success", "message": f"Typed '{text}'"}
260
+ return create_response(data, return_screenshot)
261
+
262
+
263
+ @app.route("/scroll", methods=["POST"])
264
+ @validate_request("scroll_x", "scroll_y", "return_screenshot")
265
+ @catch_error
266
+ @require_website_open
267
+ def scroll():
268
+ delta_x, delta_y = request.json["scroll_x"], request.json["scroll_y"]
269
+ return_screenshot = request.json["return_screenshot"]
270
+ with browser_manager._browser_lock() as page:
271
+ page.mouse.wheel(delta_x, delta_y)
272
+ data = {"status": "success", "message": f"Scrolled by ({delta_x},{delta_y})"}
273
+ return create_response(data, return_screenshot)
274
+
275
+
276
+ @app.route("/execute_script", methods=["POST"])
277
+ @validate_request("script", "return_screenshot")
278
+ @catch_error
279
+ @require_website_open
280
+ def exec_script():
281
+ script = request.json["script"]
282
+ return_screenshot = request.json["return_screenshot"]
283
+ with browser_manager._browser_lock() as page:
284
+ result = page.evaluate(script)
285
+ data = {"status": "success", "message": (f"Script executed.\n<script_result>\n{result}\n</script_result>")}
286
+ return create_response(data, return_screenshot)
287
+
288
+
289
+ @app.route("/back", methods=["POST"])
290
+ @validate_request("return_screenshot")
291
+ @catch_error
292
+ @require_website_open
293
+ def back():
294
+ return_screenshot = request.json["return_screenshot"]
295
+ with browser_manager._browser_lock() as page:
296
+ page.go_back()
297
+ data = {"status": "success", "message": "Navigated back"}
298
+ return create_response(data, return_screenshot)
299
+
300
+
301
+ @app.route("/forward", methods=["POST"])
302
+ @validate_request("return_screenshot")
303
+ @catch_error
304
+ @require_website_open
305
+ def forward():
306
+ return_screenshot = request.json["return_screenshot"]
307
+ with browser_manager._browser_lock() as page:
308
+ page.go_forward()
309
+ data = {"status": "success", "message": "Navigated forward"}
310
+ return create_response(data, return_screenshot)
311
+
312
+
313
+ @app.route("/reload", methods=["POST"])
314
+ @validate_request("return_screenshot")
315
+ @catch_error
316
+ @require_website_open
317
+ def reload():
318
+ return_screenshot = request.json["return_screenshot"]
319
+ with browser_manager._browser_lock() as page:
320
+ page.reload()
321
+ data = {"status": "success", "message": "Reloaded the page"}
322
+ return create_response(data, return_screenshot)
323
+
324
+
325
+ @app.route("/wait", methods=["POST"])
326
+ @validate_request("ms", "return_screenshot")
327
+ @catch_error
328
+ @require_website_open
329
+ def wait():
330
+ milliseconds = request.json["ms"]
331
+ return_screenshot = request.json["return_screenshot"]
332
+ time.sleep(milliseconds / 1000.0)
333
+ data = {"status": "success", "message": f"Waited {milliseconds} ms"}
334
+ return create_response(data, return_screenshot)
335
+
336
+
337
+ @app.route("/keypress", methods=["POST"])
338
+ @validate_request("keys", "return_screenshot")
339
+ @catch_error
340
+ @require_website_open
341
+ def keypress():
342
+ keys: list[str] = request.json["keys"]
343
+ return_screenshot = request.json["return_screenshot"]
344
+ if not isinstance(keys, list):
345
+ return create_response({"status": "error", "message": "Keys must be a list"}, False)
346
+ if not keys:
347
+ return create_response({"status": "error", "message": "Keys list empty"}, False)
348
+ with browser_manager._browser_lock() as _:
349
+ for key in keys[:-1]:
350
+ browser_manager.key_down(key)
351
+ browser_manager.key_press(keys[-1])
352
+ for key in reversed(keys[:-1]):
353
+ browser_manager.key_up(key)
354
+ data = {"status": "success", "message": f"Pressed keys {keys}"}
355
+ return create_response(data, return_screenshot)
356
+
357
+
358
+ @app.route("/goto", methods=["POST"])
359
+ @validate_request("url", "return_screenshot")
360
+ @catch_error
361
+ def goto():
362
+ url = normalize_url(request.json["url"])
363
+ return_screenshot = request.json["return_screenshot"]
364
+ with browser_manager._browser_lock() as page:
365
+ page.goto(url, wait_until="load")
366
+ data = {"status": "success", "message": f"Navigated to {url}"}
367
+ return create_response(data, return_screenshot)
368
+
369
+
370
+ @app.route("/console", methods=["GET"])
371
+ @catch_error
372
+ @require_website_open
373
+ def get_console():
374
+ console_messages = browser_manager.get_console_output()
375
+ data = {
376
+ "status": "success",
377
+ "message": f"Retrieved {len(console_messages)} console messages",
378
+ "console_messages": console_messages,
379
+ }
380
+ return create_response(data, False)
381
+
382
+
383
+ def main():
384
+ """Run the Flask server with proper cleanup handling."""
385
+ try:
386
+ app.run(host="0.0.0.0", port=config.port, threaded=False, use_reloader=False)
387
+ except KeyboardInterrupt:
388
+ print("\nShutting down gracefully...")
389
+ finally:
390
+ cleanup_on_exit()
391
+
392
+
393
+ if __name__ == "__main__":
394
+ main()
@@ -0,0 +1,38 @@
1
+ #!/root/python3.11/bin/python3
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from argparse import ArgumentParser
6
+ from pathlib import Path
7
+
8
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
9
+ sys.path.insert(0, lib_path)
10
+
11
+ from web_browser_config import ClientConfig
12
+ from web_browser_utils import (
13
+ ScreenshotMode,
14
+ _handle_screenshot,
15
+ _print_response_with_metadata,
16
+ send_request,
17
+ )
18
+
19
+ config = ClientConfig()
20
+
21
+
22
+ def screenshot():
23
+ """Capture a screenshot and handle it according to the default config.screenshot_mode."""
24
+ response = send_request(config.port, "screenshot", "GET")
25
+ if response is None:
26
+ return
27
+ screenshot_data = response["screenshot"]
28
+ _print_response_with_metadata(response)
29
+ if config.screenshot_mode == ScreenshotMode.SAVE:
30
+ _handle_screenshot(screenshot_data, ScreenshotMode.SAVE)
31
+ else:
32
+ _handle_screenshot(screenshot_data, ScreenshotMode.PRINT)
33
+
34
+
35
+ if __name__ == "__main__":
36
+ parser = ArgumentParser()
37
+ args = parser.parse_args()
38
+ screenshot()
@@ -0,0 +1,40 @@
1
+ #!/root/python3.11/bin/python3
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from argparse import ArgumentParser
6
+ from pathlib import Path
7
+
8
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
9
+ sys.path.insert(0, lib_path)
10
+
11
+ from web_browser_config import ClientConfig
12
+ from web_browser_utils import (
13
+ _autosave_screenshot_from_response,
14
+ _print_response_with_metadata,
15
+ send_request,
16
+ )
17
+
18
+ config = ClientConfig()
19
+
20
+
21
+ def scroll(scroll_x, scroll_y):
22
+ """Scroll by (scroll_x, scroll_y) pixels at current mouse position."""
23
+ response = send_request(
24
+ config.port,
25
+ "scroll",
26
+ "POST",
27
+ {"scroll_x": scroll_x, "scroll_y": scroll_y, "return_screenshot": config.autoscreenshot},
28
+ )
29
+ if response is None:
30
+ return
31
+ _print_response_with_metadata(response)
32
+ _autosave_screenshot_from_response(response, config.screenshot_mode)
33
+
34
+
35
+ if __name__ == "__main__":
36
+ parser = ArgumentParser()
37
+ parser.add_argument("scroll_x", type=int, help="The number of pixels to scroll horizontally")
38
+ parser.add_argument("scroll_y", type=int, help="The number of pixels to scroll vertically")
39
+ args = parser.parse_args()
40
+ scroll(args.scroll_x, args.scroll_y)
@@ -0,0 +1,40 @@
1
+ #!/root/python3.11/bin/python3
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from argparse import ArgumentParser
6
+ from pathlib import Path
7
+
8
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
9
+ sys.path.insert(0, lib_path)
10
+
11
+ from web_browser_config import ClientConfig
12
+ from web_browser_utils import (
13
+ _autosave_screenshot_from_response,
14
+ _print_response_with_metadata,
15
+ send_request,
16
+ )
17
+
18
+ config = ClientConfig()
19
+
20
+
21
+ def set_window_size(width, height):
22
+ """Set the browser window size to the specified width and height."""
23
+ response = send_request(
24
+ config.port,
25
+ "set_window_size",
26
+ "POST",
27
+ {"width": width, "height": height, "return_screenshot": config.autoscreenshot},
28
+ )
29
+ if response is None:
30
+ return
31
+ _print_response_with_metadata(response)
32
+ _autosave_screenshot_from_response(response, config.screenshot_mode)
33
+
34
+
35
+ if __name__ == "__main__":
36
+ parser = ArgumentParser()
37
+ parser.add_argument("width", type=int, help="The new width of the browser window")
38
+ parser.add_argument("height", type=int, help="The new height of the browser window")
39
+ args = parser.parse_args()
40
+ set_window_size(args.width, args.height)
@@ -0,0 +1,34 @@
1
+ #!/root/python3.11/bin/python3
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from argparse import ArgumentParser
6
+ from pathlib import Path
7
+
8
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
9
+ sys.path.insert(0, lib_path)
10
+
11
+ from web_browser_config import ClientConfig
12
+ from web_browser_utils import (
13
+ _autosave_screenshot_from_response,
14
+ _print_response_with_metadata,
15
+ send_request,
16
+ )
17
+
18
+ config = ClientConfig()
19
+
20
+
21
+ def type(text):
22
+ """Type the given text at the current cursor position."""
23
+ response = send_request(config.port, "type", "POST", {"text": text, "return_screenshot": config.autoscreenshot})
24
+ if response is None:
25
+ return
26
+ _print_response_with_metadata(response)
27
+ _autosave_screenshot_from_response(response, config.screenshot_mode)
28
+
29
+
30
+ if __name__ == "__main__":
31
+ parser = ArgumentParser()
32
+ parser.add_argument("text", type=str, help="The text to type at the currently focused element")
33
+ args = parser.parse_args()
34
+ type(args.text)
@@ -0,0 +1,39 @@
1
+ #!/root/python3.11/bin/python3
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from argparse import ArgumentParser
6
+ from pathlib import Path
7
+
8
+ lib_path = str(Path(__file__).resolve().parent.parent / "lib")
9
+ sys.path.insert(0, lib_path)
10
+
11
+ from web_browser_config import ClientConfig
12
+ from web_browser_utils import (
13
+ _autosave_screenshot_from_response,
14
+ _print_response_with_metadata,
15
+ send_request,
16
+ )
17
+
18
+ config = ClientConfig()
19
+
20
+
21
+ def wait(ms):
22
+ """Wait for the specified number of milliseconds."""
23
+ response = send_request(
24
+ config.port,
25
+ "wait",
26
+ "POST",
27
+ {"ms": ms, "return_screenshot": config.autoscreenshot},
28
+ )
29
+ if response is None:
30
+ return
31
+ _print_response_with_metadata(response)
32
+ _autosave_screenshot_from_response(response, config.screenshot_mode)
33
+
34
+
35
+ if __name__ == "__main__":
36
+ parser = ArgumentParser()
37
+ parser.add_argument("ms", type=int, help="The number of milliseconds to wait")
38
+ args = parser.parse_args()
39
+ wait(args.ms)