@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,631 @@
1
+ //! Deployment implementations for SWE-agent environments
2
+
3
+ use crate::exceptions::{Result, SWEAgentError};
4
+ use async_trait::async_trait;
5
+ use serde::{Deserialize, Serialize};
6
+ use std::collections::HashMap;
7
+ use std::sync::Arc;
8
+ use tokio::process::{Child, Command};
9
+ use tokio::sync::Mutex;
10
+
11
+ /// Trait for deployment backends
12
+ #[async_trait]
13
+ pub trait Deployment: Send + Sync {
14
+ /// Start the deployment
15
+ async fn start(&mut self) -> Result<()>;
16
+
17
+ /// Stop the deployment
18
+ async fn stop(&mut self) -> Result<()>;
19
+
20
+ /// Check if deployment is running
21
+ fn is_running(&self) -> bool;
22
+
23
+ /// Execute a command in the deployment
24
+ async fn execute(&self, command: &str, timeout: Option<u64>) -> Result<String>;
25
+
26
+ /// Read a file from the deployment
27
+ async fn read_file(&self, path: &str) -> Result<String>;
28
+
29
+ /// Write a file in the deployment
30
+ async fn write_file(&self, path: &str, content: &str) -> Result<()>;
31
+
32
+ /// Get the working directory
33
+ fn get_cwd(&self) -> Option<String>;
34
+
35
+ /// Interrupt the current command
36
+ async fn interrupt(&self) -> Result<()>;
37
+ }
38
+
39
+ /// Configuration for Docker deployment
40
+ #[derive(Debug, Clone, Serialize, Deserialize)]
41
+ pub struct DockerDeploymentConfig {
42
+ #[serde(default = "default_image")]
43
+ pub image: String,
44
+ #[serde(default)]
45
+ pub python_standalone_dir: Option<String>,
46
+ #[serde(default)]
47
+ pub volumes: HashMap<String, String>,
48
+ #[serde(default)]
49
+ pub environment: HashMap<String, String>,
50
+ #[serde(default = "default_true")]
51
+ pub remove_on_stop: bool,
52
+ #[serde(default = "default_workdir")]
53
+ pub work_dir: String,
54
+ }
55
+
56
+ fn default_image() -> String {
57
+ "python:3.11".to_string()
58
+ }
59
+
60
+ fn default_true() -> bool {
61
+ true
62
+ }
63
+
64
+ fn default_workdir() -> String {
65
+ "/workspace".to_string()
66
+ }
67
+
68
+ impl Default for DockerDeploymentConfig {
69
+ fn default() -> Self {
70
+ Self {
71
+ image: default_image(),
72
+ python_standalone_dir: None,
73
+ volumes: HashMap::new(),
74
+ environment: HashMap::new(),
75
+ remove_on_stop: true,
76
+ work_dir: default_workdir(),
77
+ }
78
+ }
79
+ }
80
+
81
+ /// Docker-based deployment using docker CLI
82
+ pub struct DockerDeployment {
83
+ config: DockerDeploymentConfig,
84
+ container_id: Option<String>,
85
+ is_running: bool,
86
+ cwd: String,
87
+ }
88
+
89
+ impl DockerDeployment {
90
+ pub fn new(config: DockerDeploymentConfig) -> Self {
91
+ let cwd = config.work_dir.clone();
92
+ Self {
93
+ config,
94
+ container_id: None,
95
+ is_running: false,
96
+ cwd,
97
+ }
98
+ }
99
+
100
+ /// Execute docker command and return output
101
+ async fn docker_cmd(&self, args: &[&str]) -> Result<String> {
102
+ let output = Command::new("docker")
103
+ .args(args)
104
+ .output()
105
+ .await
106
+ .map_err(|e| SWEAgentError::DockerError(format!("Failed to run docker: {}", e)))?;
107
+
108
+ if !output.status.success() {
109
+ let stderr = String::from_utf8_lossy(&output.stderr);
110
+ return Err(SWEAgentError::DockerError(format!(
111
+ "Docker command failed: {}",
112
+ stderr
113
+ )));
114
+ }
115
+
116
+ Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
117
+ }
118
+ }
119
+
120
+ #[async_trait]
121
+ impl Deployment for DockerDeployment {
122
+ async fn start(&mut self) -> Result<()> {
123
+ tracing::info!(image = %self.config.image, "Starting Docker container");
124
+
125
+ // Build docker run command
126
+ let mut args = vec![
127
+ "run", "-d", // detached
128
+ "-it", // interactive with tty for shell
129
+ "--rm", // auto remove when stopped
130
+ ];
131
+
132
+ // Add working directory
133
+ args.push("-w");
134
+ args.push(&self.config.work_dir);
135
+
136
+ // Add volume mounts
137
+ let volume_args: Vec<String> = self
138
+ .config
139
+ .volumes
140
+ .iter()
141
+ .map(|(host, container)| format!("{}:{}", host, container))
142
+ .collect();
143
+ for vol in &volume_args {
144
+ args.push("-v");
145
+ args.push(vol);
146
+ }
147
+
148
+ // Add environment variables
149
+ let env_args: Vec<String> = self
150
+ .config
151
+ .environment
152
+ .iter()
153
+ .map(|(k, v)| format!("{}={}", k, v))
154
+ .collect();
155
+ for env in &env_args {
156
+ args.push("-e");
157
+ args.push(env);
158
+ }
159
+
160
+ // Add image and command (bash to keep it running)
161
+ args.push(&self.config.image);
162
+ args.push("bash");
163
+
164
+ let container_id = self.docker_cmd(&args).await?;
165
+
166
+ if container_id.is_empty() {
167
+ return Err(SWEAgentError::DockerError(
168
+ "Failed to get container ID".to_string(),
169
+ ));
170
+ }
171
+
172
+ self.container_id = Some(container_id.clone());
173
+ self.is_running = true;
174
+
175
+ tracing::info!(container_id = %container_id, "Docker container started");
176
+ Ok(())
177
+ }
178
+
179
+ async fn stop(&mut self) -> Result<()> {
180
+ if let Some(ref container_id) = self.container_id {
181
+ tracing::info!(container = %container_id, "Stopping Docker container");
182
+
183
+ // Stop container (will auto-remove due to --rm)
184
+ let _ = self.docker_cmd(&["stop", container_id]).await;
185
+ }
186
+
187
+ self.is_running = false;
188
+ self.container_id = None;
189
+
190
+ Ok(())
191
+ }
192
+
193
+ fn is_running(&self) -> bool {
194
+ self.is_running
195
+ }
196
+
197
+ async fn execute(&self, command: &str, timeout: Option<u64>) -> Result<String> {
198
+ let container_id = self
199
+ .container_id
200
+ .as_ref()
201
+ .ok_or_else(|| SWEAgentError::EnvironmentError("Container not running".to_string()))?;
202
+
203
+ if !self.is_running {
204
+ return Err(SWEAgentError::EnvironmentError(
205
+ "Container not running".to_string(),
206
+ ));
207
+ }
208
+
209
+ let timeout_secs = timeout.unwrap_or(30);
210
+
211
+ // Use docker exec with timeout
212
+ let result = tokio::time::timeout(
213
+ std::time::Duration::from_secs(timeout_secs),
214
+ self.docker_cmd(&["exec", container_id, "bash", "-c", command]),
215
+ )
216
+ .await;
217
+
218
+ match result {
219
+ Ok(Ok(output)) => Ok(output),
220
+ Ok(Err(e)) => Err(e),
221
+ Err(_) => Err(SWEAgentError::CommandTimeout {
222
+ timeout: timeout_secs,
223
+ command: command.to_string(),
224
+ }),
225
+ }
226
+ }
227
+
228
+ async fn read_file(&self, path: &str) -> Result<String> {
229
+ let container_id = self
230
+ .container_id
231
+ .as_ref()
232
+ .ok_or_else(|| SWEAgentError::EnvironmentError("Container not running".to_string()))?;
233
+
234
+ if !self.is_running {
235
+ return Err(SWEAgentError::EnvironmentError(
236
+ "Container not running".to_string(),
237
+ ));
238
+ }
239
+
240
+ // Use docker exec cat to read file
241
+ self.docker_cmd(&["exec", container_id, "cat", path])
242
+ .await
243
+ .map_err(|_| SWEAgentError::FileNotFound(path.to_string()))
244
+ }
245
+
246
+ async fn write_file(&self, path: &str, content: &str) -> Result<()> {
247
+ let container_id = self
248
+ .container_id
249
+ .as_ref()
250
+ .ok_or_else(|| SWEAgentError::EnvironmentError("Container not running".to_string()))?;
251
+
252
+ if !self.is_running {
253
+ return Err(SWEAgentError::EnvironmentError(
254
+ "Container not running".to_string(),
255
+ ));
256
+ }
257
+
258
+ // Create parent directories
259
+ if let Some(parent) = std::path::Path::new(path).parent() {
260
+ let mkdir_cmd = format!("mkdir -p {}", parent.display());
261
+ let _ = self
262
+ .docker_cmd(&["exec", container_id, "bash", "-c", &mkdir_cmd])
263
+ .await;
264
+ }
265
+
266
+ // Use heredoc to write content - escape single quotes
267
+ let escaped_content = content.replace('\'', "'\\''");
268
+ let write_cmd = format!(
269
+ "cat > '{}' << 'SWEAGENT_EOF'\n{}\nSWEAGENT_EOF",
270
+ path, escaped_content
271
+ );
272
+
273
+ self.docker_cmd(&["exec", container_id, "bash", "-c", &write_cmd])
274
+ .await?;
275
+
276
+ Ok(())
277
+ }
278
+
279
+ fn get_cwd(&self) -> Option<String> {
280
+ Some(self.cwd.clone())
281
+ }
282
+
283
+ async fn interrupt(&self) -> Result<()> {
284
+ if let Some(ref container_id) = self.container_id {
285
+ // Send SIGINT to all processes in container
286
+ let _ = self
287
+ .docker_cmd(&["exec", container_id, "pkill", "-INT", "-f", "."])
288
+ .await;
289
+ }
290
+ Ok(())
291
+ }
292
+ }
293
+
294
+ /// Local shell deployment (no Docker)
295
+ pub struct LocalDeployment {
296
+ is_running: bool,
297
+ cwd: String,
298
+ #[allow(dead_code)]
299
+ shell_process: Option<Arc<Mutex<Child>>>,
300
+ }
301
+
302
+ impl LocalDeployment {
303
+ pub fn new(cwd: Option<String>) -> Self {
304
+ Self {
305
+ is_running: false,
306
+ cwd: cwd.unwrap_or_else(|| {
307
+ std::env::current_dir()
308
+ .map(|p| p.to_string_lossy().to_string())
309
+ .unwrap_or_else(|_| "/tmp".to_string())
310
+ }),
311
+ shell_process: None,
312
+ }
313
+ }
314
+ }
315
+
316
+ #[async_trait]
317
+ impl Deployment for LocalDeployment {
318
+ async fn start(&mut self) -> Result<()> {
319
+ self.is_running = true;
320
+ tracing::info!(cwd = %self.cwd, "Local deployment started");
321
+ Ok(())
322
+ }
323
+
324
+ async fn stop(&mut self) -> Result<()> {
325
+ self.is_running = false;
326
+ tracing::info!("Local deployment stopped");
327
+ Ok(())
328
+ }
329
+
330
+ fn is_running(&self) -> bool {
331
+ self.is_running
332
+ }
333
+
334
+ async fn execute(&self, command: &str, timeout: Option<u64>) -> Result<String> {
335
+ if !self.is_running {
336
+ return Err(SWEAgentError::EnvironmentError(
337
+ "Deployment not running".to_string(),
338
+ ));
339
+ }
340
+
341
+ let timeout_secs = timeout.unwrap_or(30);
342
+
343
+ let result = tokio::time::timeout(std::time::Duration::from_secs(timeout_secs), async {
344
+ let output = Command::new("bash")
345
+ .arg("-c")
346
+ .arg(command)
347
+ .current_dir(&self.cwd)
348
+ .output()
349
+ .await
350
+ .map_err(|e| SWEAgentError::RuntimeError(e.to_string()))?;
351
+
352
+ let stdout = String::from_utf8_lossy(&output.stdout);
353
+ let stderr = String::from_utf8_lossy(&output.stderr);
354
+
355
+ if stderr.is_empty() {
356
+ Ok(stdout.to_string())
357
+ } else {
358
+ Ok(format!("{}{}", stdout, stderr))
359
+ }
360
+ })
361
+ .await;
362
+
363
+ match result {
364
+ Ok(Ok(output)) => Ok(output),
365
+ Ok(Err(e)) => Err(e),
366
+ Err(_) => Err(SWEAgentError::CommandTimeout {
367
+ timeout: timeout_secs,
368
+ command: command.to_string(),
369
+ }),
370
+ }
371
+ }
372
+
373
+ async fn read_file(&self, path: &str) -> Result<String> {
374
+ let full_path = if std::path::Path::new(path).is_absolute() {
375
+ std::path::PathBuf::from(path)
376
+ } else {
377
+ std::path::PathBuf::from(&self.cwd).join(path)
378
+ };
379
+
380
+ tokio::fs::read_to_string(&full_path)
381
+ .await
382
+ .map_err(|_| SWEAgentError::FileNotFound(path.to_string()))
383
+ }
384
+
385
+ async fn write_file(&self, path: &str, content: &str) -> Result<()> {
386
+ let full_path = if std::path::Path::new(path).is_absolute() {
387
+ std::path::PathBuf::from(path)
388
+ } else {
389
+ std::path::PathBuf::from(&self.cwd).join(path)
390
+ };
391
+
392
+ // Create parent directories
393
+ if let Some(parent) = full_path.parent() {
394
+ tokio::fs::create_dir_all(parent)
395
+ .await
396
+ .map_err(|e| SWEAgentError::IoError(e.to_string()))?;
397
+ }
398
+
399
+ tokio::fs::write(&full_path, content)
400
+ .await
401
+ .map_err(|e| SWEAgentError::IoError(e.to_string()))
402
+ }
403
+
404
+ fn get_cwd(&self) -> Option<String> {
405
+ Some(self.cwd.clone())
406
+ }
407
+
408
+ async fn interrupt(&self) -> Result<()> {
409
+ // For local deployment, we can't easily interrupt
410
+ // The timeout mechanism handles this
411
+ Ok(())
412
+ }
413
+ }
414
+
415
+ /// Mock deployment for testing
416
+ pub struct MockDeployment {
417
+ is_running: bool,
418
+ cwd: String,
419
+ files: std::sync::Mutex<HashMap<String, String>>,
420
+ command_outputs: HashMap<String, String>,
421
+ }
422
+
423
+ impl MockDeployment {
424
+ pub fn new() -> Self {
425
+ Self {
426
+ is_running: false,
427
+ cwd: "/workspace".to_string(),
428
+ files: std::sync::Mutex::new(HashMap::new()),
429
+ command_outputs: HashMap::new(),
430
+ }
431
+ }
432
+
433
+ pub fn with_file(self, path: impl Into<String>, content: impl Into<String>) -> Self {
434
+ if let Ok(mut files) = self.files.lock() {
435
+ files.insert(path.into(), content.into());
436
+ }
437
+ self
438
+ }
439
+
440
+ pub fn with_command_output(
441
+ mut self,
442
+ command: impl Into<String>,
443
+ output: impl Into<String>,
444
+ ) -> Self {
445
+ self.command_outputs.insert(command.into(), output.into());
446
+ self
447
+ }
448
+
449
+ /// Synchronous version for non-async contexts
450
+ pub fn add_file(&self, path: impl Into<String>, content: impl Into<String>) {
451
+ if let Ok(mut files) = self.files.lock() {
452
+ files.insert(path.into(), content.into());
453
+ }
454
+ }
455
+ }
456
+
457
+ impl Default for MockDeployment {
458
+ fn default() -> Self {
459
+ Self::new()
460
+ }
461
+ }
462
+
463
+ #[async_trait]
464
+ impl Deployment for MockDeployment {
465
+ async fn start(&mut self) -> Result<()> {
466
+ self.is_running = true;
467
+ Ok(())
468
+ }
469
+
470
+ async fn stop(&mut self) -> Result<()> {
471
+ self.is_running = false;
472
+ Ok(())
473
+ }
474
+
475
+ fn is_running(&self) -> bool {
476
+ self.is_running
477
+ }
478
+
479
+ async fn execute(&self, command: &str, _timeout: Option<u64>) -> Result<String> {
480
+ if !self.is_running {
481
+ return Err(SWEAgentError::EnvironmentError(
482
+ "Mock not running".to_string(),
483
+ ));
484
+ }
485
+
486
+ // Check for predefined outputs
487
+ if let Some(output) = self.command_outputs.get(command) {
488
+ return Ok(output.clone());
489
+ }
490
+
491
+ // Handle common commands
492
+ if command == "pwd" {
493
+ return Ok(self.cwd.clone());
494
+ }
495
+
496
+ // Handle cat command for reading files
497
+ if command.starts_with("cat ") {
498
+ let path = command.strip_prefix("cat ").unwrap().trim();
499
+ let files = self
500
+ .files
501
+ .lock()
502
+ .map_err(|e| SWEAgentError::RuntimeError(e.to_string()))?;
503
+ if let Some(content) = files.get(path) {
504
+ return Ok(content.clone());
505
+ }
506
+ return Err(SWEAgentError::FileNotFound(path.to_string()));
507
+ }
508
+
509
+ Ok(String::new())
510
+ }
511
+
512
+ async fn read_file(&self, path: &str) -> Result<String> {
513
+ let files = self
514
+ .files
515
+ .lock()
516
+ .map_err(|e| SWEAgentError::RuntimeError(e.to_string()))?;
517
+ files
518
+ .get(path)
519
+ .cloned()
520
+ .ok_or_else(|| SWEAgentError::FileNotFound(path.to_string()))
521
+ }
522
+
523
+ async fn write_file(&self, path: &str, content: &str) -> Result<()> {
524
+ let mut files = self
525
+ .files
526
+ .lock()
527
+ .map_err(|e| SWEAgentError::RuntimeError(e.to_string()))?;
528
+ files.insert(path.to_string(), content.to_string());
529
+ Ok(())
530
+ }
531
+
532
+ fn get_cwd(&self) -> Option<String> {
533
+ Some(self.cwd.clone())
534
+ }
535
+
536
+ async fn interrupt(&self) -> Result<()> {
537
+ Ok(())
538
+ }
539
+ }
540
+
541
+ /// Configuration for local deployment
542
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
543
+ pub struct LocalDeploymentConfig {
544
+ #[serde(default)]
545
+ pub cwd: Option<String>,
546
+ }
547
+
548
+ /// Configuration for deployments
549
+ #[derive(Debug, Clone, Serialize, Deserialize)]
550
+ #[serde(tag = "type", rename_all = "snake_case")]
551
+ pub enum DeploymentConfig {
552
+ Docker(DockerDeploymentConfig),
553
+ Local(LocalDeploymentConfig),
554
+ Mock,
555
+ }
556
+
557
+ impl Default for DeploymentConfig {
558
+ fn default() -> Self {
559
+ Self::Docker(DockerDeploymentConfig::default())
560
+ }
561
+ }
562
+
563
+ /// Create a deployment from configuration
564
+ pub fn get_deployment(config: DeploymentConfig) -> Box<dyn Deployment> {
565
+ match config {
566
+ DeploymentConfig::Docker(cfg) => Box::new(DockerDeployment::new(cfg)),
567
+ DeploymentConfig::Local(cfg) => Box::new(LocalDeployment::new(cfg.cwd)),
568
+ DeploymentConfig::Mock => Box::new(MockDeployment::new()),
569
+ }
570
+ }
571
+
572
+ // Re-export for convenience
573
+ pub use DockerDeployment as AbstractDeployment;
574
+
575
+ #[cfg(test)]
576
+ mod tests {
577
+ use super::*;
578
+
579
+ #[tokio::test]
580
+ async fn test_mock_deployment() {
581
+ let mut deployment = MockDeployment::new();
582
+
583
+ // Start the deployment first
584
+ deployment.start().await.unwrap();
585
+ assert!(deployment.is_running());
586
+
587
+ // Write a file
588
+ deployment
589
+ .write_file("/test.txt", "hello world")
590
+ .await
591
+ .unwrap();
592
+
593
+ // Read it back
594
+ let content = deployment.read_file("/test.txt").await.unwrap();
595
+ assert_eq!(content, "hello world");
596
+
597
+ deployment.stop().await.unwrap();
598
+ assert!(!deployment.is_running());
599
+ }
600
+
601
+ #[tokio::test]
602
+ async fn test_local_deployment_execute() {
603
+ let mut deployment = LocalDeployment::new(Some("/tmp".to_string()));
604
+ deployment.start().await.unwrap();
605
+
606
+ let output = deployment.execute("echo hello", Some(5)).await.unwrap();
607
+ assert!(output.contains("hello"));
608
+
609
+ deployment.stop().await.unwrap();
610
+ }
611
+
612
+ #[tokio::test]
613
+ async fn test_local_deployment_file_ops() {
614
+ let mut deployment = LocalDeployment::new(Some("/tmp".to_string()));
615
+ deployment.start().await.unwrap();
616
+
617
+ let test_file = "/tmp/sweagent_test_file.txt";
618
+ deployment
619
+ .write_file(test_file, "test content")
620
+ .await
621
+ .unwrap();
622
+
623
+ let content = deployment.read_file(test_file).await.unwrap();
624
+ assert_eq!(content, "test content");
625
+
626
+ // Cleanup
627
+ let _ = tokio::fs::remove_file(test_file).await;
628
+
629
+ deployment.stop().await.unwrap();
630
+ }
631
+ }