@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,37 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+
5
+
6
+ def test_run_cli_no_arg_error():
7
+ args = [
8
+ "sweagent",
9
+ ]
10
+ output = subprocess.run(args, check=False, capture_output=True)
11
+ print(output.stdout.decode())
12
+ print(output.stderr.decode())
13
+ assert output.returncode in [1, 2]
14
+ assert "run-batch" in output.stdout.decode()
15
+ assert "run-replay" in output.stdout.decode()
16
+ assert "run" in output.stdout.decode()
17
+
18
+
19
+ def test_run_cli_main_help():
20
+ args = [
21
+ "sweagent",
22
+ "--help",
23
+ ]
24
+ output = subprocess.run(args, check=True, capture_output=True)
25
+ assert "run-batch" in output.stdout.decode()
26
+ assert "run-replay" in output.stdout.decode()
27
+ assert "run" in output.stdout.decode()
28
+
29
+
30
+ def test_run_cli_subcommand_help():
31
+ args = [
32
+ "sweagent",
33
+ "run",
34
+ "--help",
35
+ ]
36
+ output = subprocess.run(args, check=True, capture_output=True)
37
+ assert "--config" in output.stdout.decode()
@@ -0,0 +1,110 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+ from sweagent.run.run import main
6
+
7
+
8
+ @pytest.mark.slow
9
+ def test_expert_instances(test_data_sources_path: Path, tmp_path: Path):
10
+ ds_path = test_data_sources_path / "expert_instances.yaml"
11
+ assert ds_path.exists()
12
+ cmd = [
13
+ "run-batch",
14
+ "--agent.model.name",
15
+ "instant_empty_submit",
16
+ "--instances.type",
17
+ "expert_file",
18
+ "--instances.path",
19
+ str(ds_path),
20
+ "--output_dir",
21
+ str(tmp_path),
22
+ "--raise_exceptions",
23
+ "True",
24
+ ]
25
+ main(cmd)
26
+ for _id in ["simple_test_problem", "simple_test_problem_2"]:
27
+ assert (tmp_path / f"{_id}" / f"{_id}.traj").exists(), list(tmp_path.iterdir())
28
+
29
+
30
+ @pytest.mark.slow
31
+ def test_simple_instances(test_data_sources_path: Path, tmp_path: Path):
32
+ ds_path = test_data_sources_path / "simple_instances.yaml"
33
+ assert ds_path.exists()
34
+ cmd = [
35
+ "run-batch",
36
+ "--agent.model.name",
37
+ "instant_empty_submit",
38
+ "--instances.path",
39
+ str(ds_path),
40
+ "--output_dir",
41
+ str(tmp_path),
42
+ "--raise_exceptions",
43
+ "True",
44
+ ]
45
+ main(cmd)
46
+ assert (tmp_path / "simple_test_problem" / "simple_test_problem.traj").exists(), list(tmp_path.iterdir())
47
+
48
+
49
+ def test_empty_instances_simple(test_data_sources_path: Path, tmp_path: Path):
50
+ ds_path = test_data_sources_path / "simple_instances.yaml"
51
+ assert ds_path.exists()
52
+ cmd = [
53
+ "run-batch",
54
+ "--agent.model.name",
55
+ "instant_empty_submit",
56
+ "--instances.path",
57
+ str(ds_path),
58
+ "--output_dir",
59
+ str(tmp_path),
60
+ "--raise_exceptions",
61
+ "True",
62
+ "--instances.filter",
63
+ "doesnotmatch",
64
+ ]
65
+ with pytest.raises(ValueError, match="No instances to run"):
66
+ main(cmd)
67
+
68
+
69
+ def test_empty_instances_expert(test_data_sources_path: Path, tmp_path: Path):
70
+ ds_path = test_data_sources_path / "expert_instances.yaml"
71
+ assert ds_path.exists()
72
+ cmd = [
73
+ "run-batch",
74
+ "--agent.model.name",
75
+ "instant_empty_submit",
76
+ "--instances.path",
77
+ str(ds_path),
78
+ "--instances.type",
79
+ "expert_file",
80
+ "--output_dir",
81
+ str(tmp_path),
82
+ "--raise_exceptions",
83
+ "True",
84
+ "--instances.filter",
85
+ "doesnotmatch",
86
+ ]
87
+ with pytest.raises(ValueError, match="No instances to run"):
88
+ main(cmd)
89
+
90
+
91
+ # This doesn't work because we need to retrieve environment variables from the environment
92
+ # in order to format our templates.
93
+ # def test_run_batch_swe_bench_instances(tmp_path: Path):
94
+ # cmd = [
95
+ # "run-batch",
96
+ # "--agent.model.name",
97
+ # "instant_empty_submit",
98
+ # "--instances.subset",
99
+ # "lite",
100
+ # "--instances.split",
101
+ # "test",
102
+ # "--instances.slice",
103
+ # "0:1",
104
+ # "--output_dir",
105
+ # str(tmp_path),
106
+ # "--raise_exceptions",
107
+ # "--instances.deployment.type",
108
+ # "dummy",
109
+ # ]
110
+ # main(cmd)
@@ -0,0 +1,114 @@
1
+ import os
2
+
3
+ import pytest
4
+
5
+ from sweagent.agent.problem_statement import GithubIssue
6
+ from sweagent.run.hooks.open_pr import OpenPRConfig, OpenPRHook
7
+ from sweagent.types import AgentRunResult
8
+
9
+
10
+ def _fake_issue_from_url(url: str):
11
+ # Minimal object shape used by OpenPRHook.should_open_pr
12
+ issue_number = url.rstrip("/").split("/")[-1]
13
+
14
+ class Issue:
15
+ def __init__(self, state: str, assignee, locked: bool):
16
+ self.state = state
17
+ self.assignee = assignee
18
+ self.locked = locked
19
+
20
+ if issue_number == "16":
21
+ return Issue(state="closed", assignee=None, locked=False)
22
+ if issue_number == "17":
23
+ return Issue(state="open", assignee="someone", locked=False)
24
+ if issue_number == "18":
25
+ return Issue(state="open", assignee=None, locked=True)
26
+ if issue_number == "19":
27
+ return Issue(state="open", assignee=None, locked=False)
28
+ return Issue(state="open", assignee=None, locked=False)
29
+
30
+
31
+ def _fake_associated_commit_urls(_org: str, _repo: str, issue_number: str, *, token: str = ""):
32
+ if issue_number == "19":
33
+ return ["https://github.com/swe-agent/test-repo/commit/abc123"]
34
+ return []
35
+
36
+
37
+ @pytest.fixture
38
+ def open_pr_hook_init_for_sop(monkeypatch: pytest.MonkeyPatch):
39
+ # Patch network calls in OpenPRHook
40
+ import sweagent.run.hooks.open_pr as open_pr
41
+
42
+ def fake_get_issue(url: str, token: str = ""):
43
+ if "github.com" not in url or "/issues/" not in url:
44
+ msg = f"Invalid GitHub issue URL: {url}"
45
+ raise open_pr.InvalidGithubURL(msg)
46
+ return _fake_issue_from_url(url)
47
+
48
+ monkeypatch.setattr(open_pr, "_get_gh_issue_data", fake_get_issue)
49
+ monkeypatch.setattr(open_pr, "_get_associated_commit_urls", _fake_associated_commit_urls)
50
+
51
+ hook = OpenPRHook(config=OpenPRConfig(skip_if_commits_reference_issue=True))
52
+ hook._token = os.environ.get("GITHUB_TOKEN", "")
53
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/1")
54
+ return hook
55
+
56
+
57
+ @pytest.fixture
58
+ def agent_run_result():
59
+ return AgentRunResult(
60
+ info={
61
+ "submission": "asdf",
62
+ "exit_status": "submitted",
63
+ },
64
+ trajectory=[],
65
+ )
66
+
67
+
68
+ def test_should_open_pr_fail_submission(open_pr_hook_init_for_sop, agent_run_result):
69
+ hook = open_pr_hook_init_for_sop
70
+ agent_run_result.info["submission"] = None
71
+ assert not hook.should_open_pr(agent_run_result)
72
+
73
+
74
+ def test_should_open_pr_fail_exit(open_pr_hook_init_for_sop, agent_run_result):
75
+ hook = open_pr_hook_init_for_sop
76
+ agent_run_result.info["exit_status"] = "fail"
77
+ assert not hook.should_open_pr(agent_run_result)
78
+
79
+
80
+ def test_should_open_pr_fail_invalid_url(open_pr_hook_init_for_sop, agent_run_result):
81
+ hook = open_pr_hook_init_for_sop
82
+ hook._problem_statement = type("PS", (), {"github_url": "asdf"})()
83
+ assert not hook.should_open_pr(agent_run_result)
84
+
85
+
86
+ def test_should_open_pr_fail_closed(open_pr_hook_init_for_sop, agent_run_result):
87
+ hook = open_pr_hook_init_for_sop
88
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/16")
89
+ assert not hook.should_open_pr(agent_run_result)
90
+
91
+
92
+ def test_should_open_pr_fail_assigned(open_pr_hook_init_for_sop, agent_run_result):
93
+ hook = open_pr_hook_init_for_sop
94
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/17")
95
+ assert not hook.should_open_pr(agent_run_result)
96
+
97
+
98
+ def test_should_open_pr_fail_locked(open_pr_hook_init_for_sop, agent_run_result):
99
+ hook = open_pr_hook_init_for_sop
100
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/18")
101
+ assert not hook.should_open_pr(agent_run_result)
102
+
103
+
104
+ def test_should_open_pr_fail_has_pr(open_pr_hook_init_for_sop, agent_run_result):
105
+ hook = open_pr_hook_init_for_sop
106
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/19")
107
+ assert not hook.should_open_pr(agent_run_result)
108
+
109
+
110
+ def test_should_open_pr_success_has_pr_override(open_pr_hook_init_for_sop, agent_run_result):
111
+ hook = open_pr_hook_init_for_sop
112
+ hook._problem_statement = GithubIssue(github_url="https://github.com/swe-agent/test-repo/issues/19")
113
+ hook._config.skip_if_commits_reference_issue = False
114
+ assert hook.should_open_pr(agent_run_result)
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+
5
+ import pytest
6
+ from swerex.deployment.config import DockerDeploymentConfig
7
+
8
+ from sweagent.run.run_replay import RunReplay, RunReplayConfig
9
+
10
+
11
+ @pytest.fixture
12
+ def rr_config(swe_agent_test_repo_traj, tmp_path, swe_agent_test_repo_clone):
13
+ return RunReplayConfig(
14
+ traj_path=swe_agent_test_repo_traj,
15
+ deployment=DockerDeploymentConfig(image="python:3.11"),
16
+ output_dir=tmp_path,
17
+ )
18
+
19
+
20
+ def test_replay(rr_config):
21
+ rr = RunReplay.from_config(rr_config, _catch_errors=False, _require_zero_exit_code=True)
22
+ rr.main()
23
+
24
+
25
+ def test_run_cli_help():
26
+ args = [
27
+ "sweagent",
28
+ "run-replay",
29
+ "--help",
30
+ ]
31
+ output = subprocess.run(args, capture_output=True)
32
+ assert output.returncode == 0
33
+ assert "Replay a trajectory file" in output.stdout.decode()
@@ -0,0 +1,125 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+
7
+ from sweagent import CONFIG_DIR, TOOLS_DIR
8
+ from sweagent.agent.agents import DefaultAgentConfig
9
+ from sweagent.agent.models import InstantEmptySubmitModelConfig
10
+ from sweagent.environment.swe_env import EnvironmentConfig
11
+ from sweagent.run.common import BasicCLI
12
+ from sweagent.run.hooks.abstract import RunHook
13
+ from sweagent.run.run_single import RunSingle, RunSingleConfig
14
+ from sweagent.tools.bundle import Bundle
15
+
16
+
17
+ class RaisesExceptionHook(RunHook):
18
+ def on_instance_start(self, *args, **kwargs):
19
+ msg = "test exception"
20
+ raise ValueError(msg)
21
+
22
+
23
+ @pytest.mark.slow
24
+ def test_run_single_raises_exception():
25
+ rsc = RunSingleConfig(agent=DefaultAgentConfig(model=InstantEmptySubmitModelConfig()))
26
+ rs = RunSingle.from_config(rsc)
27
+ rs.add_hook(RaisesExceptionHook())
28
+ with pytest.raises(ValueError, match="test exception"):
29
+ rs.run()
30
+
31
+
32
+ @pytest.fixture
33
+ def agent_config_with_commands():
34
+ ac = DefaultAgentConfig(model=InstantEmptySubmitModelConfig())
35
+ ac.tools.bundles = [
36
+ Bundle(path=TOOLS_DIR / "registry"),
37
+ Bundle(path=TOOLS_DIR / "windowed"),
38
+ Bundle(path=TOOLS_DIR / "submit"),
39
+ ]
40
+ ac.tools.env_variables = {"WINDOW": 100}
41
+ assert (TOOLS_DIR / "submit").exists()
42
+ # Make sure dependent properties are set
43
+ ac.tools.model_post_init(None)
44
+ return ac
45
+
46
+
47
+ @pytest.mark.slow
48
+ def test_hidden_tools(tmpdir):
49
+ ac = DefaultAgentConfig(model=InstantEmptySubmitModelConfig())
50
+ ac.tools.env_variables = {"WINDOW": 100}
51
+ ac.tools.bundles = [
52
+ Bundle(path=TOOLS_DIR / "registry"),
53
+ Bundle(path=TOOLS_DIR / "windowed", hidden_tools=["scroll_up"]),
54
+ Bundle(path=TOOLS_DIR / "submit"),
55
+ ]
56
+ ac.model.name = "instant_empty_submit"
57
+ rsc = RunSingleConfig(
58
+ env=EnvironmentConfig(),
59
+ agent=ac,
60
+ output_dir=Path(tmpdir),
61
+ )
62
+ rs = RunSingle.from_config(rsc)
63
+ rs.run()
64
+
65
+
66
+ @pytest.mark.slow
67
+ def test_run_ies(tmpdir, agent_config_with_commands):
68
+ # ies = instant empty submit
69
+ ac = agent_config_with_commands
70
+ ac.model.name = "instant_empty_submit"
71
+ rsc = RunSingleConfig(
72
+ env=EnvironmentConfig(),
73
+ agent=ac,
74
+ output_dir=Path(tmpdir),
75
+ )
76
+ rs = RunSingle.from_config(rsc)
77
+ rs.agent.tools.mock_state = {"open_file": "asdf123", "working_dir": "/root"}
78
+ rs.run()
79
+
80
+
81
+ @pytest.mark.slow
82
+ @pytest.mark.parametrize("repo", ["local", "github"])
83
+ @pytest.mark.parametrize("problem_statement_source", ["github", "local", "text"])
84
+ def test_run_ies_repo_ps_matrix(
85
+ tmpdir,
86
+ swe_agent_test_repo_clone,
87
+ repo,
88
+ problem_statement_source,
89
+ ):
90
+ output_formats = ["traj", "pred", "patch"]
91
+ for fmt in output_formats:
92
+ assert not list(Path(tmpdir).glob(f"*.{fmt}"))
93
+ if problem_statement_source == "github":
94
+ ps_args = ["--problem_statement.github_url", "https://github.com/swe-agent/test-repo/issues/1"]
95
+ elif problem_statement_source == "local":
96
+ ps_args = ["--problem_statement.path", str(swe_agent_test_repo_clone / "problem_statements" / "1.md")]
97
+ elif problem_statement_source == "text":
98
+ ps_args = ["--problem_statement.text='this is a test'"]
99
+ else:
100
+ raise ValueError(problem_statement_source)
101
+ if repo == "local":
102
+ repo_args = ["--env.repo.path", str(swe_agent_test_repo_clone)]
103
+ elif repo == "github":
104
+ repo_args = ["--env.repo.github_url", "https://github.com/swe-agent/test-repo"]
105
+ else:
106
+ raise ValueError(repo)
107
+ args = [
108
+ "--agent.model.name=instant_empty_submit",
109
+ "--output_dir",
110
+ str(tmpdir),
111
+ *ps_args,
112
+ *repo_args,
113
+ "--config",
114
+ str(CONFIG_DIR / "default_backticks.yaml"),
115
+ ]
116
+ print(args)
117
+ rs_config = BasicCLI(RunSingleConfig).get_config(args)
118
+ print(rs_config)
119
+ rs = RunSingle.from_config(rs_config) # type: ignore
120
+ with tmpdir.as_cwd():
121
+ # Test that we can run run.py also independently from repo dir
122
+ rs.run()
123
+ for fmt in output_formats:
124
+ print(fmt, list(Path(tmpdir).iterdir()))
125
+ assert len(list(Path(tmpdir).rglob(f"*.{fmt}"))) == 1
@@ -0,0 +1,193 @@
1
+ import pytest
2
+
3
+ from sweagent.tools.commands import Argument, Command
4
+
5
+
6
+ def test_command_parsing_formats():
7
+ """Test various signature formats and default parsing."""
8
+ # Default format (no signature)
9
+ command = Command(
10
+ name="test_cmd",
11
+ docstring="A test command",
12
+ arguments=[
13
+ Argument(name="arg1", type="string", description="First argument", required=True),
14
+ Argument(name="arg2", type="integer", description="Second argument", required=False),
15
+ ],
16
+ )
17
+ assert command.invoke_format == "test_cmd {arg1} {arg2} "
18
+
19
+ # Angle brackets
20
+ command = Command(
21
+ name="goto",
22
+ signature="goto <line_number>",
23
+ docstring="moves the window to show line_number",
24
+ arguments=[Argument(name="line_number", type="integer", description="line number", required=True)],
25
+ )
26
+ assert command.invoke_format == "goto {line_number}"
27
+
28
+ # Optional brackets (stripped in invoke_format)
29
+ command = Command(
30
+ name="open",
31
+ signature='open "<path>" [<line_number>]',
32
+ docstring="opens file at path",
33
+ arguments=[
34
+ Argument(name="path", type="string", description="file path", required=True),
35
+ Argument(name="line_number", type="integer", description="line number", required=False),
36
+ ],
37
+ )
38
+ assert command.invoke_format == 'open "{path}" {line_number}'
39
+
40
+ # Flag-style arguments
41
+ command = Command(
42
+ name="grep",
43
+ signature="grep --pattern <pattern> --file <file>",
44
+ docstring="search for pattern in file",
45
+ arguments=[
46
+ Argument(name="pattern", type="string", description="search pattern", required=True),
47
+ Argument(name="file", type="string", description="file to search", required=True),
48
+ ],
49
+ )
50
+ assert command.invoke_format == "grep --pattern {pattern} --file {file}"
51
+
52
+ # No arguments
53
+ command = Command(name="scroll_up", signature="scroll_up", docstring="scrolls up", arguments=[])
54
+ assert command.invoke_format == "scroll_up"
55
+
56
+
57
+ def test_argument_validation():
58
+ """Test argument validation rules."""
59
+ # Required arguments must come before optional ones
60
+ with pytest.raises(ValueError, match="Required argument.*cannot come after optional arguments"):
61
+ Command(
62
+ name="bad_order",
63
+ docstring="bad argument order",
64
+ arguments=[
65
+ Argument(name="optional", type="string", description="optional", required=False),
66
+ Argument(name="required", type="string", description="required", required=True),
67
+ ],
68
+ )
69
+
70
+ # Duplicate argument names
71
+ with pytest.raises(ValueError, match="Duplicate argument names"):
72
+ Command(
73
+ name="duplicate",
74
+ docstring="duplicate args",
75
+ arguments=[
76
+ Argument(name="arg1", type="string", description="first", required=True),
77
+ Argument(name="arg1", type="string", description="duplicate", required=True),
78
+ ],
79
+ )
80
+
81
+
82
+ def test_argument_name_patterns():
83
+ """Test valid and invalid argument name patterns."""
84
+ # Valid names including single characters
85
+ valid_names = ["a", "x", "n", "simple", "with_underscore", "with-dash", "with123numbers", "_starts_with_underscore"]
86
+
87
+ for name in valid_names:
88
+ command = Command(
89
+ name="test",
90
+ docstring="test",
91
+ arguments=[Argument(name=name, type="string", description="test", required=True)],
92
+ )
93
+ assert command.arguments[0].name == name
94
+
95
+ # Invalid names
96
+ invalid_names = ["123starts_with_number", ""]
97
+
98
+ for name in invalid_names:
99
+ with pytest.raises(ValueError, match="Invalid argument name"):
100
+ Command(
101
+ name="test",
102
+ docstring="test",
103
+ arguments=[Argument(name=name, type="string", description="test", required=True)],
104
+ )
105
+
106
+
107
+ def test_signature_argument_consistency():
108
+ """Test that signatures and arguments must be consistent."""
109
+ # Missing argument in signature
110
+ with pytest.raises(ValueError, match="Missing argument.*in signature"):
111
+ Command(
112
+ name="missing_arg",
113
+ signature="missing_arg <existing_arg>",
114
+ docstring="missing argument in signature",
115
+ arguments=[
116
+ Argument(name="existing_arg", type="string", description="exists", required=True),
117
+ Argument(name="missing_arg", type="string", description="not in signature", required=True),
118
+ ],
119
+ )
120
+
121
+ # Extra argument in signature
122
+ with pytest.raises(ValueError, match="Argument names.*do not match"):
123
+ Command(
124
+ name="extra_arg",
125
+ signature="extra_arg <arg1> <extra>",
126
+ docstring="extra argument in signature",
127
+ arguments=[Argument(name="arg1", type="string", description="exists", required=True)],
128
+ )
129
+
130
+
131
+ def test_function_calling_tool_generation():
132
+ """Test OpenAI function calling tool generation."""
133
+ command = Command(
134
+ name="test_function",
135
+ docstring="A test function for OpenAI",
136
+ arguments=[
137
+ Argument(name="required_arg", type="string", description="Required string argument", required=True),
138
+ Argument(
139
+ name="enum_arg", type="string", description="Enum argument", required=True, enum=["option1", "option2"]
140
+ ),
141
+ Argument(name="optional_arg", type="integer", description="Optional integer argument", required=False),
142
+ ],
143
+ )
144
+
145
+ tool = command.get_function_calling_tool()
146
+
147
+ assert tool["type"] == "function"
148
+ assert tool["function"]["name"] == "test_function"
149
+ assert tool["function"]["description"] == "A test function for OpenAI"
150
+
151
+ properties = tool["function"]["parameters"]["properties"]
152
+ assert properties["required_arg"]["type"] == "string"
153
+ assert properties["optional_arg"]["type"] == "integer"
154
+ assert properties["enum_arg"]["enum"] == ["option1", "option2"]
155
+
156
+ required = tool["function"]["parameters"]["required"]
157
+ assert "required_arg" in required
158
+ assert "enum_arg" in required
159
+ assert "optional_arg" not in required
160
+
161
+
162
+ def test_multiline_command():
163
+ """Test multi-line commands with end markers."""
164
+ command = Command(
165
+ name="edit",
166
+ signature="edit <filename>",
167
+ docstring="Edit a file with multi-line content",
168
+ end_name="EOF",
169
+ arguments=[Argument(name="filename", type="string", description="file to edit", required=True)],
170
+ )
171
+
172
+ assert command.invoke_format == "edit {filename}"
173
+ assert command.end_name == "EOF"
174
+
175
+
176
+ def test_custom_argument_format():
177
+ """Test custom argument formatting."""
178
+ command = Command(
179
+ name="custom_format",
180
+ docstring="Test custom argument formatting",
181
+ arguments=[
182
+ Argument(
183
+ name="arg1",
184
+ type="string",
185
+ description="Custom formatted argument",
186
+ required=True,
187
+ argument_format="--{value}",
188
+ )
189
+ ],
190
+ )
191
+
192
+ assert command.arguments[0].argument_format == "--{value}"
193
+ assert command.invoke_format == "custom_format {arg1} "
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from sweagent import REPO_ROOT
6
+ from sweagent.utils.config import _convert_path_to_abspath, _convert_paths_to_abspath
7
+
8
+
9
+ def test_convert_path_to_abspath():
10
+ assert _convert_path_to_abspath("sadf") == REPO_ROOT / "sadf"
11
+ assert _convert_path_to_abspath("/sadf") == Path("/sadf")
12
+
13
+
14
+ def test_convert_paths_to_abspath():
15
+ assert _convert_paths_to_abspath([Path("sadf"), Path("/sadf")]) == [REPO_ROOT / "sadf", Path("/sadf")]
File without changes
@@ -0,0 +1,12 @@
1
+ from unittest import mock
2
+
3
+ import pytest
4
+
5
+
6
+ @pytest.fixture
7
+ def with_tmp_env_file(tmp_path):
8
+ env_file = tmp_path / ".swe-agent-env"
9
+ env_file.write_text("{}")
10
+ with mock.patch.dict("os.environ", {"SWE_AGENT_ENV_FILE": str(env_file)}, clear=True):
11
+ yield env_file
12
+ env_file.unlink()