Compare commits

...

333 Commits

Author SHA1 Message Date
openhands 0c09a8062f Use SearchConfig for configuration instead of environment variables 2025-03-18 12:43:16 +00:00
openhands 7051669835 Revert unrelated changes to workflow and config files 2025-03-17 21:53:49 +00:00
openhands c1c7e8dc72 Change onBrokenLinks to warn to allow build to complete 2025-03-17 21:51:22 +00:00
openhands ecff077b5e Fix pydoc-markdown config to only document openhands module 2025-03-17 21:41:40 +00:00
openhands 4972b20986 Allow docs workflow to run on PRs targeting any branch and on forks 2025-03-17 21:34:27 +00:00
openhands 48db2a1c09 Fix docs workflow to run pydoc-markdown from root directory 2025-03-17 21:07:58 +00:00
openhands e6ea2c8a9b Merge remote-tracking branch 'aditya/search_engine' 2025-03-17 20:41:53 +00:00
openhands b8f04eea42 Add dedicated search configuration documentation 2025-03-17 20:33:36 +00:00
openhands 2f3b9cfe4a Add documentation for search engine feature 2025-03-17 20:16:12 +00:00
openhands bc4e8632e1 Sort imports alphabetically 2025-03-17 17:53:02 +00:00
openhands 2015c13826 Address review comments 2025-03-17 17:47:02 +00:00
openhands 1c72e2bb31 Add tests for search engine feature 2025-03-17 17:37:19 +00:00
openhands 22e13a0a4d Fix merge conflicts with main 2025-03-17 17:30:57 +00:00
openhands 05dabbbb13 Add SEARCH action type and SearchAction to __all__ 2025-03-17 17:09:08 +00:00
openhands de312941ee Merge main into search_engine 2025-03-17 17:06:02 +00:00
Engel Nyst a4b836b5f9 Don't try to send the new events in the UI (#7277) 2025-03-17 14:50:22 +01:00
Xingyao Wang a4d632498c SWE-Gym rollout stability fix & using a validated SWE-Gym set (#7182)
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-03-17 21:15:01 +08:00
Engel Nyst 4f017081fc Quick fix docs (#7299)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-17 05:50:05 +00:00
Engel Nyst 51fb1fae88 RecallObservations (#7292) 2025-03-17 03:18:22 +01:00
Graham Neubig 106b230fea Update Slack invitation links (#7296)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-17 02:06:48 +00:00
Xingyao Wang 9b262dd057 fix retry on ConnectionError & retry on remote runtime by default (#7294) 2025-03-17 01:18:54 +00:00
chuckbutkus 8074b261d3 Move current user_id to github_user_id and create a new user_id field (#7231)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Rohit Malhotra <rohitvinodmalhotra@gmail.com>
2025-03-16 16:32:27 -04:00
dependabot[bot] 999a59f938 chore(deps): bump the version-all group with 5 updates (#7253)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-16 19:51:08 +00:00
chuckbutkus fbba57d3b5 Fix saving of settings (#7282) 2025-03-16 19:06:46 +00:00
Engel Nyst 3f6c8a2338 Fix visual browsing (#7278)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-16 16:50:25 +01:00
Engel Nyst dd09d46ccb Remove DelegatorAgent (fix #7280)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-16 16:49:28 +01:00
tofarr 8897b45eeb Fix for too much reaction in logs (#7276) 2025-03-16 08:21:30 -06:00
Ryan H. Tran 30109e8f20 Separate tool descriptions to support models with limited description length (#7258) 2025-03-16 09:48:13 +01:00
Engel Nyst cc45f5d9c3 Add RecallActions and observations for retrieval of prompt extensions (#6909)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Calvin Smith <email@cjsmith.io>
2025-03-15 21:48:37 +01:00
tofarr e34a771e66 Fix for issue where initial command fails (#7254) 2025-03-14 14:49:57 -06:00
adityasoni9998 635dc5098a Rename env var to BRAVE_API_KEY and clean up dead code 2025-03-14 15:36:45 -04:00
adityasoni9998 3a765db531 Restore run_infer.sh. 2025-03-14 15:11:50 -04:00
adityasoni9998 929b971ef5 Minor fixes 2025-03-14 15:08:05 -04:00
adityasoni9998 d518fc8f8c Merge branch 'main' into search_engine 2025-03-14 14:51:00 -04:00
adityasoni9998 00d7425f4c Merge remote-tracking branch 'upstream/main' 2025-03-14 14:50:51 -04:00
adityasoni9998 b24e34c3eb Changes for search engine tool and minor error fix in browser process 2025-03-14 14:49:29 -04:00
tofarr ec763f8105 Fix for error where credits is accessed even when billing is disabled (#7250) 2025-03-14 15:10:54 +00:00
Ryan H. Tran 165c0cc42e Add doc for local runtime (#7234)
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-14 22:09:33 +08:00
adityasoni9998 a05b39d5c5 Added fixes for output formatting, scrolling, timeouts for actions other than goto, and file downloads. 2025-03-13 22:47:20 -04:00
dependabot[bot] 1b4f15235e chore(deps): bump the version-all group with 4 updates (#7241)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-13 22:15:47 +01:00
adityasoni9998 a880f55a63 Added fixes for file downloads, goto action timeouts, and some other browser fixes. 2025-03-13 16:21:16 -04:00
Calvin Smith 303b7ab180 (fix): Conditional imports resolved in SWE-bench eval script while multiprocessing enabled (#7244)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-13 13:29:11 -06:00
Rohit Malhotra 78d185b102 [Feat]: Support Gitlab PAT (#7064)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-13 14:44:49 -04:00
Ryan H. Tran 300bfbdf2d Upgrade openhands-aci to 0.2.6 (#7233) 2025-03-14 02:10:59 +08:00
Xingyao Wang e2f414bf26 chore: update doc for allhands doc (#7242)
Co-authored-by: mamoodi <mamoodiha@gmail.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-14 00:32:17 +08:00
Calvin Smith 3b955dd9d5 (fix): Improve formatting of summarizing LLM inputs (#7239)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-13 10:21:29 -06:00
sp.wack f1eb1f59c3 hotfix(frontend): Fix overriding tailwind animation classes (#7243) 2025-03-13 16:03:54 +00:00
sp.wack e1f6929d98 feat: saas new user modal (#7098)
Co-authored-by: Tim O'Farrell <tofarr@gmail.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-13 19:15:57 +04:00
adityasoni9998 35ab168b88 Merge branch 'main' into eval_fixes 2025-03-13 10:35:29 -04:00
Engel Nyst 2a7f926591 Detect condensation loops at 10 repetitions, not 3 (#7237) 2025-03-13 14:32:01 +00:00
adityasoni9998 a578cf39a9 Merge remote-tracking branch 'upstream/main' 2025-03-13 10:24:49 -04:00
Xingyao Wang b8daab721d Update agent message to use first-person perspective (#7197)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-13 04:39:24 +08:00
Robert Brennan b3cac69121 remove old microagents (#6964)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-12 16:18:19 -04:00
Boxuan Li 49a29c19cb Remove mention of non-existent config micro_agent_name (#7209) 2025-03-13 03:33:59 +08:00
Robert Brennan 7084b0238c Fix HTTPException not callable error in action_execution_server middleware (#7215)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-13 03:10:13 +08:00
Elena Chistova 38e866cde4 Fix official SWE-Bench docker image prefix (#7214) 2025-03-12 18:23:19 +00:00
sp.wack 6ec4bc74bf chore(frontend): Turn off query caching by default (#7222) 2025-03-12 17:52:11 +00:00
juanmichelini b36deca265 Added link to paper in commit0 README (#7221) 2025-03-12 17:17:22 +00:00
Engel Nyst 09d73d96c8 Add troubleshooting note for GitHub token in microagent (#7208)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-12 04:45:58 +01:00
dependabot[bot] 966c11f205 chore(deps): bump the version-all group across 1 directory with 17 updates (#7203)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-12 00:15:52 +00:00
Robert Brennan 5128377baa remove llamaindex (#7151)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-11 22:28:56 +00:00
Engel Nyst 924acb182b Add Swift Linux Installation Microagent (#7195)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-11 19:45:50 +00:00
tofarr 8043612420 Feat user settings (#7190) 2025-03-11 12:57:44 -06:00
Calvin Smith 637a1d5c17 Adds unit test for the interaction between agent controller truncation and condenser (#7186)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-11 09:57:15 -06:00
AutoLTX 5e521a4a6e Expose accumulate and llm_metric from eventstream (backend) (#7082)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-11 12:18:08 +01:00
chuckbutkus 2cb5b91300 Change names to prepare for moving to keycloak User ID (#7178) 2025-03-10 19:23:57 -04:00
answer-huang d6e601ea2e bugfix: selected_repository may includes more then two parts, could b… (#7114) 2025-03-10 19:47:33 +00:00
Rohit Malhotra ac680e7688 [Fix]: Remove remaining hard coded refs to sessions store (#7176)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-10 15:07:01 -04:00
mamoodi 4b04f09035 Update Cloud docs (#7158)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-10 14:00:06 -04:00
mamoodi e99f503e0f Release 0.28.1 (#7170) 2025-03-10 13:22:34 -04:00
Rohit Malhotra f51eb93d3e Add error logs to API response from GH Service (#7165) 2025-03-09 21:45:13 +00:00
mamoodi 7c2a98d1ce Change back the runtime binding address to 0.0.0.0 (#7161) 2025-03-09 11:37:10 -04:00
Ray Myers dc9489ddcd Include metadata like session_id in logs (#7145) 2025-03-08 00:28:51 +01:00
sp.wack 83851c398d chore(frontend): Restyle toasts and replace all current instances with new one (#6854) 2025-03-08 01:23:50 +04:00
Xingyao Wang a4908f9a75 [agent] system message + SWE-Bench instruction improvements (#7018) 2025-03-08 00:27:02 +08:00
Robert Brennan 366fd7ab8a Improve agent loop tracking and make concurrent limit configurable (#6945)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Tim O'Farrell <tofarr@gmail.com>
2025-03-07 09:19:50 -07:00
dependabot[bot] 318fcbcfc7 chore(deps): bump the version-all group across 1 directory with 21 updates (#7146)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-07 15:58:54 +00:00
sp.wack 521492f8f9 chore: Prevent user from modifying basic LLM settings in saas mode (#7137) 2025-03-07 19:14:06 +04:00
mamoodi 71f6b0b4a9 Release 0.28.0 (#7127)
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-07 09:17:01 -05:00
Xingyao Wang b146b63380 chore: temporary fix to get sonnet 3.7 working again (#7140) 2025-03-06 20:30:35 +00:00
Engel Nyst 22064d5555 Add condensation observation to history and detect its loop (#7132) 2025-03-06 18:52:45 +01:00
sp.wack 08735a9b72 Fix loading spinner (#7134) 2025-03-06 17:40:13 +00:00
tofarr 54f982589a Fix annoying Avatar flicker when loading (#7129) 2025-03-06 15:59:28 +00:00
Nan Jiang ec087993f1 rename commit0_bench to commit0 (#7124) 2025-03-06 02:55:39 +00:00
chuckbutkus f12e9e94f7 Offline session login (#7086)
Changes to allow the resolver to access keycloak and retrieve an offline token.
2025-03-05 21:58:34 +00:00
Xingyao Wang 9f720a9d69 [eval] SWE-Gym Integration (#6651)
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-03-05 20:15:02 +00:00
Xingyao Wang bbf40c6576 docs: cleanup and update SWE-Bench documentation; and remove the support of non-instance-level image (#7118)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-06 03:18:40 +08:00
Ivan Dagelic 1ffee80dcb feat: prompt instructions for runtimes (#6943)
Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>
2025-03-05 17:45:55 +01:00
dependabot[bot] 43bc944ac4 chore(deps-dev): bump typescript from 5.7.3 to 5.8.2 in /docs in the version-all group (#7116)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 15:09:49 +00:00
Xingyao Wang 4be33a079b Update SWE-Bench README.md about RemoteRuntime (#7108) 2025-03-05 23:00:54 +08:00
Aditya Bharat Soni c76a659cde Condenser for Browser Output Observations (#6578)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Rick van Hattem <wolph@wol.ph>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
Co-authored-by: tofarr <tofarr@gmail.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: Rohit Malhotra <rohitvinodmalhotra@gmail.com>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Akim Tsvigun <36672861+Aktsvigun@users.noreply.github.com>
Co-authored-by: Akim Tsvigun <aktsvigun@nebius.com>
Co-authored-by: mamoodi <mamoodiha@gmail.com>
Co-authored-by: OpenHands <opendevin@all-hands.dev>
Co-authored-by: Calvin Smith <email@cjsmith.io>
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Peter Dave Hello <hsu@peterdavehello.org>
Co-authored-by: Ray Myers <ray.myers@gmail.com>
2025-03-04 16:28:33 -05:00
dependabot[bot] 0f68a18cbb chore(deps): bump docker/setup-qemu-action from 3.4.0 to 3.6.0 (#7075)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-04 20:57:14 +00:00
Robert Brennan c9ebabd82d Add contact link to runtime settings label (#6880)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-05 00:49:53 +04:00
mamoodi ad932e45e8 Checkout HEAD instead of Merge Commit for builds (#7085) 2025-03-04 15:32:59 -05:00
sp.wack 3278caf3c2 Always enable GET /settings (#7101) 2025-03-04 14:54:26 -05:00
He Du 896d7b8b96 Openhands fix issue 7091 (#7092)
Co-authored-by: 杜贺 <duhe@duhedeMacBook-Pro-2.local>
2025-03-04 18:39:28 +01:00
Ryan H. Tran cb61282c39 Improve error detection for read and edit observations (#7090) 2025-03-04 15:05:15 +01:00
Graham Neubig 7a235ce6ff Fix/mypy routes (#6900)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-04 03:43:09 +00:00
adityasoni9998 d071acf501 Update browser tool description 2025-03-02 23:13:22 -05:00
adityasoni9998 f73edd7220 Merge remote-tracking branch 'upstream/main' 2025-03-02 22:10:00 -05:00
Engel Nyst 869e2911c6 [Refactor] split runtime initialization (create, connect, init) in cli scripts (#7036) 2025-03-02 22:09:50 -05:00
Graham Neubig 3004073d39 More explicit feedback message about how to report errors to developers (#7063) 2025-03-02 22:09:50 -05:00
Engel Nyst d050f481e8 Fix GitLab CI environment variable check (issue #7050) (#7052)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:50 -05:00
Ivan Dagelic 96654069f7 chore: daytona readme quick start verbosity (#7056)
Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>
2025-03-02 22:09:50 -05:00
Ivan Dagelic 78db84fe38 chore: update daytona readme (#7053)
Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>
2025-03-02 22:09:50 -05:00
mamoodi d6605dee56 Updates to the ISSUE TRIAGE (#7043) 2025-03-02 22:09:50 -05:00
Engel Nyst 92cc51951f Fix argument in swe-bench grading scripts (#7046) 2025-03-02 22:09:50 -05:00
David Thompson 72953443bc Update docker.py to support podman (#6778) 2025-03-02 22:09:50 -05:00
Engel Nyst 96e4831379 Separate microagent template (#7041) 2025-03-02 22:09:50 -05:00
きわみざむらい 06e698818f Create CITATION.cff (#7037) 2025-03-02 22:09:50 -05:00
Robert Brennan ea95639d2b Remove hard error on session reuse (#7026)
Co-authored-by: Tim O'Farrell <tofarr@gmail.com>
2025-03-02 22:09:50 -05:00
Ray Myers 3e4dd38212 Structured logging mode (#7034) 2025-03-02 22:09:49 -05:00
chuckbutkus de09b368ba Fix URL for staging stack (#7030) 2025-03-02 22:09:49 -05:00
Xingyao Wang b69ecc5cc2 Add Kubernetes microagent (#7028)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2025-03-02 22:09:49 -05:00
Xingyao Wang 979135b5e1 Add Docker microagent for installation and usage (#7027)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:49 -05:00
Christopher Pereira 0dec0fbab0 Bug fixes (#6460)
Co-authored-by: OH <openhands@example.com>
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-02 22:09:49 -05:00
chuckbutkus 69a1c9abc7 Keycloak changes (#6986) 2025-03-02 22:09:49 -05:00
Christopher Pereira 8a9fdbe7c5 Support docker_runtime_kwargs dict (#7025) 2025-03-02 22:09:49 -05:00
Calvin Smith fae10c8856 Fix: Update context window exceeded detection (#7024)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:49 -05:00
Ryan H. Tran 21ef0890bc Add diff for edit observation and display in UI (#7014) 2025-03-02 22:09:49 -05:00
Fredy Sierra 80b955279e feat: Adding sandbox property runtime_binding_address to specify whic… (#6992) 2025-03-02 22:09:49 -05:00
Xingyao Wang 8d0e4235b4 [agent] improve finish tool for sonnet 3.7 (#7002) 2025-03-02 22:09:49 -05:00
dependabot[bot] cdd9f5860d chore(deps-dev): bump llama-index from 0.12.20 to 0.12.21 in the llama group (#7015)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:49 -05:00
Engel Nyst f5c794212c Refactor to a helper class for the agent's history (ConversationMemory) (#7008)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Calvin Smith <email@cjsmith.io>
2025-03-02 22:09:49 -05:00
Magic Mai 7612a56a76 fix: Remove nested git repositories before adding files in SWE-bench (#6536)
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-02 22:09:49 -05:00
Engel Nyst 9db439f2c0 Separate additional_info template (#6996) 2025-03-02 22:09:49 -05:00
Xingyao Wang a74d972d99 Add Memory Monitor VSCode Extension (#6951)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:49 -05:00
Xingyao Wang f2503fe392 [agent] Add "thinking" tool only (#6977) 2025-03-02 22:09:49 -05:00
Engel Nyst fd27d4ffa3 Re-add separators between user messages (#7004) 2025-03-02 22:09:49 -05:00
dependabot[bot] 033f004952 chore(deps): bump the version-all group across 1 directory with 7 updates (#7005)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:49 -05:00
jaybutera 242e5b1ec6 add add_agent.md (#6891)
Co-authored-by: smd <>
2025-03-02 22:09:49 -05:00
tofarr 9c48604410 Page Refresh now restarts agent loop if status is STOPPED or ERROR (#6829) 2025-03-02 22:09:49 -05:00
Xingyao Wang 065ab7bdf5 feat: add sound and browser notifications for agent state changes (#6530)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:48 -05:00
mamoodi 57a1768a3e Release 0.27.0 (#6993) 2025-03-02 22:09:48 -05:00
tofarr 82abb2326d Refactor: Moving ConversationInfo to server module (#6981) 2025-03-02 22:09:48 -05:00
zchn 17dda08bb1 Fix image tag inconsistency in forked-PR workflows (#6998) 2025-03-02 22:09:48 -05:00
sp.wack c839a5f0cd hotfix(frontend): Truncate long conversation card titles (#7001) 2025-03-02 22:09:48 -05:00
tofarr d1546f4cbe Feat out of credits msg (#6969)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:48 -05:00
tofarr cb8cfe06a6 Fix for error cleaning stale (#6971) 2025-03-02 22:09:48 -05:00
Engel Nyst 7d0befc429 Refactor sandbox and security configurations (#6973) 2025-03-02 22:09:48 -05:00
Xingyao Wang 2ebc8169c0 [eval] Upgrade SWE-Bench to use official image and latest harness (#6838)
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-03-02 22:09:48 -05:00
dependabot[bot] 39ae2bd48c chore(deps): bump react-icons from 5.4.0 to 5.5.0 in /docs in the version-all group (#6962)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-02 22:09:48 -05:00
Xingyao Wang 32fda5fce4 [agent] System message update (#6787)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:48 -05:00
Ray Myers 855ccb8c63 Add system event listeners for monitoring (#6929) 2025-03-02 22:09:48 -05:00
Engel Nyst 994f4f8d23 Azure completion_tokens fix (take two) (#6975) 2025-03-02 22:09:48 -05:00
dependabot[bot] 288f46ab4d chore(deps): bump the version-all group across 1 directory with 11 updates (#6966)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:48 -05:00
Xingyao Wang 16c54e02c9 refactor: codeact tools into separate files (#6978) 2025-03-02 22:09:48 -05:00
Engel Nyst 4f5c7d26c7 Refactor agent_config loading from toml (#6967) 2025-03-02 22:09:48 -05:00
Engel Nyst 3815cfc318 Fix microagent matching to the user message, not previous enhancements (#6963) 2025-03-02 22:09:48 -05:00
sp.wack a44fd2c7ca hotfix(frontend): Consistent buttons and their styles throughout the app (#6835)
Co-authored-by: Robert Brennan <accounts@rbren.io>
2025-03-02 22:09:48 -05:00
Engel Nyst 1a9b284b9b Add selected_repo to command line (#6949) 2025-03-02 22:09:48 -05:00
tofarr 04175c747e Fix fd leak (#6950) 2025-03-02 22:09:48 -05:00
Ray Myers 7fa0959681 Add ability to define custom runtime classes (#6955)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:48 -05:00
Engel Nyst 9858c89155 Refactor llm config from toml and clean up (#6923) 2025-03-02 22:09:47 -05:00
Ryan H. Tran e2fb79620a fix: task_str validation not required for trajectory replay (#6957) 2025-03-02 22:09:47 -05:00
Rohit Malhotra 218dc545bf [Feat]: Adding endpoint for suggested tasks Openhands could tackle (#6844)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Robert Brennan 693da0a052 Add pause_closed_runtimes config to pause instead of stop runtimes (#6885)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Graham Neubig facd03aa29 feat(llm): Add Claude 3.7 backend configurations (#6937)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
sp.wack aebfa7666f chore(frontend): Claude 3.7 is visible in dropdown for selection (#6931) 2025-03-02 22:09:47 -05:00
mamoodi 6d248eee06 Add documentation checkbox to PR template (#6924) 2025-03-02 22:09:47 -05:00
mamoodi 53f8dc1061 Release 0.26.0 (#6915) 2025-03-02 22:09:47 -05:00
celek 584aa7c8b0 add extended generic section (#5932)
Co-authored-by: Christophe Elek <christophe.elek@gmail.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:47 -05:00
tofarr 2422d703e3 Revert "Fix file descriptor leak (#6897)" (#6921) 2025-03-02 22:09:47 -05:00
Mateusz Kwiatkowski 03cdded50b Replace shebang with /usr/bin/env bash for improved portability (#6876)
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-02 22:09:47 -05:00
Xingyao Wang 3e455ad323 chore: Make remote runtime class default to None (#6919) 2025-03-02 22:09:47 -05:00
Christopher Pereira 591e0d91a3 Handle Docker version string with +dfsg1 (#6732)
Co-authored-by: Christoper Pereira <kripper@gmail.com>
2025-03-02 22:09:47 -05:00
Engel Nyst bae3887040 Small rename to long term memory (#6914) 2025-03-02 22:09:47 -05:00
tofarr 5a1697940b Fix file descriptor leak (#6897)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Graham Neubig 8ba8990a52 Fix mypy errors in core directory (#6901)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Graham Neubig 974a46c582 Fix mypy errors in security/invariant directory (#6908)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Ivan Dagelic 30d76c3733 Daytona Runtime (#6863)
Signed-off-by: jsrzic <josip.srzic@gmail.com>
Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>
Co-authored-by: jsrzic <65179822+jsrzic@users.noreply.github.com>
2025-03-02 22:09:47 -05:00
sp.wack 8cd6e60415 hotfix: Fix switch color regression (#6881) 2025-03-02 22:09:47 -05:00
Engel Nyst cb3edf2885 Display session ID in CLI mode
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:47 -05:00
Engel Nyst 65524f171d Use LLM APIs responses in token counting (#5604)
Co-authored-by: Calvin Smith <email@cjsmith.io>
2025-03-02 22:09:47 -05:00
Engel Nyst c26c7478c2 Keep the first user message by default in condensers (#6888) 2025-03-02 22:09:47 -05:00
tofarr cf1265dec2 Fix for regression where conversations are not clickable (#6886) 2025-03-02 22:09:46 -05:00
Engel Nyst aa640afbe0 Revert "Fix: File Descriptor leak" (#6887) 2025-03-02 22:09:46 -05:00
tofarr afc76055d8 Fix: Increase Entropy Requirement for Secret Redaction to Reduce False Positives (#6875) 2025-03-02 22:09:46 -05:00
Dai Dao 11c37e04c1 refactor : Improve frontend setup doc and locale error (#6850)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:46 -05:00
tofarr b32b4beb73 Fix: File Descriptor leak (#6883) 2025-03-02 22:09:46 -05:00
Robert Brennan d36a477d3c Add info logs for microagent loading and triggering (#6882)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
Calvin Smith 25b01925fe (feat): Enable memory condensation from settings page (#6868)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-02 22:09:46 -05:00
Graham Neubig 4915d20cdd Fix mypy errors in agenthub directory (#6811)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:46 -05:00
Graham Neubig fe42b7e88f fix: Add missing type annotations in utils/ directory (#6687)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
sp.wack d26d925e04 chore(frontend): Remove latest conversation text in home screen (#6851) 2025-03-02 22:09:46 -05:00
tofarr f8d468cfff Fix jumpy conversation panel (#6874) 2025-03-02 22:09:46 -05:00
Boxuan Li 58cfd16c53 Save complete trajectory in presence of history truncation (#6751)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:46 -05:00
Boxuan Li 316322a942 Add enable_history_truncation option to disable history truncation (#6820)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:46 -05:00
Xingyao Wang aaf3e0819b Docs: Clarify config.toml usage in evaluation harness (#6828)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
dependabot[bot] 18d6deeb6c chore(deps): bump the version-all group across 1 directory with 10 updates (#6870)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
Engel Nyst cf727c9ac6 Fix: Simplify prompt caching for new Anthropic API (#6860)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
Rohit Malhotra 85c51410d7 [Bug]: Fix workflow definition for installation phase of resolver (#6861) 2025-03-02 22:09:46 -05:00
sp.wack 5a8056bf27 chore(frontend): Standardize custom colors used throughout the app (#6833) 2025-03-02 22:09:46 -05:00
Robert Brennan 2984ed740b Add conversation age limit configuration (#6763)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
tofarr dc045d2cde Fix: Less squashed logo (#6853) 2025-03-02 22:09:46 -05:00
sp.wack 507aa39c80 hotfix: Set proper minimum and maximum defaults that can be entered in billing input (#6842) 2025-03-02 22:09:46 -05:00
sp.wack 58ff252f50 hotfix: Remove external link in billing settings UI (#6841) 2025-03-02 22:09:46 -05:00
Calvin Smith 1ddb68e0fa fix: LLM summarization prompt handles user messages (#6837)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-02 22:09:46 -05:00
Engel Nyst e5fc1afb4e Refactor I/O utils; allow 'task' command line parameter in cli.py (#6187)
Co-authored-by: OpenHands Bot <openhands@all-hands.dev>
2025-03-02 22:09:46 -05:00
Engel Nyst 336eb98ea3 Clean up NullObservations from the stream (#6260) 2025-03-02 22:09:45 -05:00
mamoodi a25324304a Update documentation with new settings page (#6716)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:45 -05:00
mamoodi 659ca022f2 Release 0.25.0 (#6782) 2025-03-02 22:09:45 -05:00
Engel Nyst 578bf144d5 hotfix azure (#6806) 2025-03-02 22:09:45 -05:00
Xingyao Wang ec1ce2f9fa feat: better error logging for remote runtime (#6805) 2025-03-02 22:09:45 -05:00
Ryan H. Tran 83ecc2049e Update openhands-aci to 0.2.5 (#6834)
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-02 22:09:45 -05:00
diwu-sf bb559a2dca Fix download workspace zip file event loop hanging (#6722) 2025-03-02 22:09:45 -05:00
Calvin Smith d0ca8db912 fix: Avoid infinite loop with rolling condensers and history truncation (#6795)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-02 22:09:45 -05:00
Graham Neubig 6108434f06 Fix mypy errors in storage directory (#6809)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:45 -05:00
Ryan H. Tran ce218a167b Fix diskcache breaking CI & eval intermittently (#6817) 2025-03-02 22:09:45 -05:00
Graham Neubig 843f092b76 Fix type checking errors in resolver directory (#6738)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:45 -05:00
Xingyao Wang bf70965565 Add sysbox support to remote runtime for eval; Add memory monitor, stress tests to help debug memory issue (#6684)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-03-02 22:09:45 -05:00
Calvin Smith d5ee33811a enh: Refactor Event -> Message pipeline outside of CodeActAgent (#6715)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:45 -05:00
sp.wack a4c60d9986 feat(SaaS): Billing settings screen (#6495)
Co-authored-by: Tim O'Farrell <tofarr@gmail.com>
2025-03-02 22:09:45 -05:00
sp.wack 4f00bf4846 fix(frontend): Hide modal when in settings page if first time (#6792) 2025-03-02 22:09:45 -05:00
sp.wack 5ac5e229d6 hotfix: Conversation panel toggle should change color given state (#6791) 2025-03-02 22:09:45 -05:00
dependabot[bot] ffa5fbe9c2 chore(deps): bump the version-all group across 1 directory with 9 updates (#6783)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:45 -05:00
sp.wack d2398fef4b hotfix(frontend): Input set/unset state and disable runtime input (#6788) 2025-03-02 22:09:45 -05:00
sp.wack a5ea1db1af hotfix: Consistent background color (#6786) 2025-03-02 22:09:45 -05:00
nottherealironman a195ada8bf docs: add guide for minimum computing and storage requirements (#6575) 2025-03-02 22:09:45 -05:00
tofarr 1ef0d8fa21 CSS Fixes (#6770) 2025-03-02 22:09:44 -05:00
Rohit Malhotra dbe2b333a0 Add selected branch to convo metadata (#6773) 2025-03-02 22:09:44 -05:00
mamoodi e5679f6450 Update OpenHands Cloud docs with correct permissions and instructions (#6774) 2025-03-02 22:09:44 -05:00
Graham Neubig 7aeaac5261 Upgrade tree sitter (#6740)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
Rohit Malhotra 2f3bd3d808 [Docs]: Cloud Openhands (#6747)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: mamoodi <mamoodiha@gmail.com>
2025-03-02 22:09:44 -05:00
Rohit Malhotra c42c9cbaf8 hotfix(Secrets): Add event stream filter for refreshed secret (#6764) 2025-03-02 22:09:44 -05:00
tofarr a1ffdcea34 Enable the multi conversation UI for all users (#6374) 2025-03-02 22:09:44 -05:00
Xingyao Wang 2988b10d00 fix: disable prlimit since limiting --vm breaks nodejs (#6765) 2025-03-02 22:09:44 -05:00
tofarr 849d2719bf Improve SensitiveDataFilter and add comprehensive tests (#6755)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:44 -05:00
Robert Brennan cb9eeae313 Fix caps in status message (#6761) 2025-03-02 22:09:44 -05:00
Robert Brennan e5599ef094 Better LLM retry behavior (#6557)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
tofarr a3e134bdf4 Added iterate method and additional tests for search functions (#6756) 2025-03-02 22:09:44 -05:00
tofarr ee0225c062 feat: implement optimistic updates for conversation deletion (#6745)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
李师胡 debd00075d docs(runtime): fix broken links of benchmarks (#6744)
Co-authored-by: jianhao1 <jianhao1@taobao.com>
2025-03-02 22:09:44 -05:00
dependabot[bot] c6f4dddf70 chore(deps): bump the version-all group in /frontend with 4 updates (#6725)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
Arpan Koirala af2e91d6da fix: no interaction when clearing poetry cache (#6752) 2025-03-02 22:09:44 -05:00
Christopher Pereira 643664a0a9 Show docker build errors (#6695) 2025-03-02 22:09:44 -05:00
Boxuan Li 67fbf5906f A few fixes for TAC evaluation harness (#6586) 2025-03-02 22:09:44 -05:00
Boxuan Li 42ff2b70ed Add a sanity test for load_app_config and get_agent_config_arg (#6723) 2025-03-02 22:09:44 -05:00
Cheng Yang 5e469c588b docs: improve docstrings for CLI and config utils (#5398)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
dependabot[bot] 93e54418be chore(deps): bump the version-all group across 1 directory with 12 updates (#6736)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:44 -05:00
Ryan H. Tran 3ea122fa30 chore: upgrade openhands-aci to 0.2.2 (#6731) 2025-03-02 22:09:44 -05:00
Rohit Malhotra 1227e503b2 [Resolver]: Prep env in expectation of release (#6735) 2025-03-02 22:09:43 -05:00
sp.wack f16bab079c feat(frontend): Settings screen (#6550) 2025-03-02 22:09:43 -05:00
Rohit Malhotra c50bc33cb5 hotfix(Resolver): Workflow definition is out of sync with released package (#6719) 2025-03-02 22:09:43 -05:00
Rohit Malhotra 227f2f7dec fix: Simplify nested f-string to fix pydoc-markdown parsing (#6717) 2025-03-02 22:09:43 -05:00
wtiger9218 72237e4557 feat(resolver): implement gitlab resolver (#6458)
Signed-off-by: José Luis Di Biase <josx@interorganic.com.ar>
Co-authored-by: José Luis Di Biase <josx@interorganic.com.ar>
Co-authored-by: Oriana <oriana@camba.coop>
Co-authored-by: Charlie <charlie@camba.coop>
Co-authored-by: Juan Manuel Daza <61162223+juanmanueldaza@users.noreply.github.com>
Co-authored-by: Juan Manuel Daza <juandaza@camba.coop>
Co-authored-by: Cody Kociemba <cody@symbaventures.com>
Co-authored-by: Rohit Malhotra <rohitvinodmalhotra@gmail.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:43 -05:00
Boxuan Li a418d0dacf Evaluation harness: Add agent config option (#6662) 2025-03-02 22:09:43 -05:00
dependabot[bot] 871095184d chore(deps): bump the version-all group across 1 directory with 5 updates (#6712)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:43 -05:00
Calvin Smith dc4ca3ad91 fix: Filter AgentCondensationObservation events from agent state (#6705)
Co-authored-by: Calvin Smith <calvin@all-hands.dev>
2025-03-02 22:09:43 -05:00
tofarr 3626e29150 More effective remote runtime identification (#6714) 2025-03-02 22:09:43 -05:00
mamoodi 6c49c5e8e3 Release 0.24.0 (#6689) 2025-03-02 22:09:43 -05:00
tofarr 759a03f406 Agent session no longer stuck in starting on raised exception (#6703) 2025-03-02 22:09:43 -05:00
Rohit Malhotra bc188694af Feat: Add selected branch param to backend (#6508) 2025-03-02 22:09:43 -05:00
sp.wack 7f5d7675ee chore: Throw a 404 instead of returning defaults if settings does not exist (#6704) 2025-03-02 22:09:43 -05:00
tofarr 1f01edb0da Fix log formatting error (#6699) 2025-03-02 22:09:43 -05:00
Xingyao Wang 70d7982548 using all available system memory when RUNTIME_MAX_MEMORY_GB is not set (#6691) 2025-03-02 22:09:43 -05:00
sp.wack dfbd928b20 Revert "Only show start project button in conversations" (#6698) 2025-03-02 22:09:43 -05:00
Xingyao Wang e59878af5f refactor: do not add DEBUG env var when it is not set (#6690) 2025-03-02 22:09:43 -05:00
dependabot[bot] e2add5c57e chore(deps-dev): bump @tanstack/eslint-plugin-query from 5.66.0 to 5.66.1 in /frontend in the eslint group (#6682)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-02 22:09:43 -05:00
Robert Brennan 26f235ff00 Fix debug in remote runtime (#6688) 2025-03-02 22:09:43 -05:00
Xingyao Wang b71b723e91 refactor(runtime): Use openhands-aci file editor directly in runtime instead of execute it through ipython (#6671)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:43 -05:00
Eric Zhang 25b73f9606 fix(frontend): fix public github repo cannot be selected (#6680) 2025-03-02 22:09:43 -05:00
Xingyao Wang 807b0bfbfe feat(runtime): use prlimit to limit resource usage of command to avoid OOM Runtime Kill (#6338)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-03-02 22:09:43 -05:00
Engel Nyst a98f31fbdb Clean up global in llm.py (we figured it's not needed) (#6675) 2025-03-02 22:09:43 -05:00
Xingyao Wang 508dea41a0 Bump OpenHands ACI to 0.2.1 (#6678) 2025-03-02 22:09:42 -05:00
sp.wack fba1f1b7e7 hotfix: Typecheck routes during frontend build (#6676) 2025-03-02 22:09:42 -05:00
dependabot[bot] b60acd5073 chore(deps): bump the version-all group across 1 directory with 9 updates (#6667)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
dependabot[bot] 27e39fb377 chore(deps): bump docker/setup-qemu-action from 3.3.0 to 3.4.0 (#6666)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
Fredy Sierra a0c9451a32 fix: adding support for environment variables type dict (#6672)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
Graham Neubig fcfc807bf1 fix: Normalize whitespace when comparing patch context lines (#6541)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:42 -05:00
tofarr 1a5c252043 Fix for issue where temp file is empty (#6669) 2025-03-02 22:09:42 -05:00
Graham Neubig 8e55ced1a9 Fix issue #6262: Add success/failure indicators for file read/edit operations (#6653)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:42 -05:00
Rohit Malhotra 7113d387cb [Resolver]: Add target branch param (#6668) 2025-03-02 22:09:42 -05:00
dependabot[bot] 01d23ae05e chore(deps): bump the version-all group in /frontend with 4 updates (#6665)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
Rohit Malhotra 477b369f65 [Enhancement]: Handle GH token refresh inside runtime (#6632) 2025-03-02 22:09:42 -05:00
Robert Brennan 0588311628 Add comprehensive OpenHands glossary (#6310)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
2025-03-02 22:09:42 -05:00
Rohit Malhotra 6dce886b63 [Bug fix]: Standardize SecretStr use (#6660)
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:42 -05:00
tofarr 3d2268ef35 Removed in page callback (#6657) 2025-03-02 22:09:42 -05:00
dependabot[bot] 4b23a77464 chore(deps): bump the version-all group across 1 directory with 3 updates (#6648)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
zchn 04d5691cf7 fix(6223): More properly add 'pyproject.toml' and 'poetry.lock' to the pip package (#6658) 2025-03-02 22:09:42 -05:00
Xingyao Wang 102f2e4d60 fix: set tool_choice to none for non-fncall models (#6652) 2025-03-02 22:09:42 -05:00
sp.wack f2781a52c1 chore(frontend): Take into account other error message types (#6647) 2025-03-02 22:09:42 -05:00
Xingyao Wang 8cf58c62ba feat: Add LocalRuntime (#5284)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2025-03-02 22:09:42 -05:00
tofarr 72a4ece435 fix: handle SAAS mode properly in useSettings hook (#6646)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-03-02 22:09:42 -05:00
Graham Neubig edea1e967e Optimize memory usage in FileEditObservation (#6622)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2025-03-02 22:09:42 -05:00
adityasoni9998 840b35097b Added search engine tool in openhands. Refine prompt for GAIA. Made browsing tool single-action 2025-03-02 22:04:50 -05:00
adityasoni9998 e9c32f708f Merge branch 'main' into eval_fixes 2025-03-01 18:41:08 -05:00
adityasoni9998 19e5e5bbc1 Changes to GAIA prompt and browser tool. 2025-03-01 18:39:33 -05:00
adityasoni9998 e561aa974b Merge remote-tracking branch 'upstream/main' 2025-03-01 16:49:23 -05:00
adityasoni9998 3b7d86ec59 Code for evaluation run 2 on GAIA. 2025-03-01 15:26:04 -05:00
adityasoni9998 677488d450 Merge branch 'main' into browser_condenser 2025-02-27 12:20:52 -05:00
adityasoni9998 3b504e10fd Merge remote-tracking branch 'upstream/main' 2025-02-27 12:10:38 -05:00
adityasoni9998 b5391f5b77 Merge remote-tracking branch 'upstream/main' 2025-02-20 18:57:57 -05:00
adityasoni9998 3fa1fb72ac Merge remote-tracking branch 'upstream/main' 2025-02-06 20:52:45 -05:00
mamoodi 03f4745f7e Add o1 to verfied models (#6642) 2025-02-06 20:52:18 -05:00
Graham Neubig 945bdd7a6a Better error logging in posthog (#6346)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Ray Myers <ray.myers@gmail.com>
2025-02-06 20:52:18 -05:00
sp.wack 7c1c19c095 chore(frontend): Migrate from NextUI to HeroUI via codemod (#6635) 2025-02-06 20:52:18 -05:00
mamoodi f1911bec24 Only show start project button in conversations (#6626)
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2025-02-06 20:52:18 -05:00
dependabot[bot] 7e08383168 chore(deps): bump the version-all group across 1 directory with 15 updates (#6617)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2025-02-06 20:52:18 -05:00
Peter Dave Hello 0b361f318e Update and Improve zh-TW Traditional Chinese locale (#6621) 2025-02-06 20:52:18 -05:00
Graham Neubig 6e7aa1531e Fix memory leak in JSON encoder (#6620)
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2025-02-06 20:52:18 -05:00
Graham Neubig 904b2b3f9f Remove free disk space steps from workflows to test if they are necessary (#6618)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-02-06 20:52:18 -05:00
adityasoni9998 0f24032f05 Merge remote-tracking branch 'upstream/main' 2025-02-06 09:47:04 -05:00
adityasoni9998 f49b7a98d1 Merge remote-tracking branch 'upstream/main' 2025-02-05 19:13:27 -05:00
adityasoni9998 0b1ec8a621 Merge remote-tracking branch 'upstream/main' into main 2025-02-05 11:16:20 -05:00
Aditya Bharat Soni d35a225729 Merge branch 'main' into browser_condenser 2025-02-01 21:51:27 -05:00
Aditya Bharat Soni 3b05b68d3b Merge branch 'main' into browser_condenser 2025-02-01 15:35:17 -05:00
adityasoni9998 65bf992263 Browser output condenser to condense observation outputs from browser use when providing context to the LLM. 2025-02-01 14:15:10 -05:00
adityasoni9998 83fa5b08c0 Rename visual browsing flag in agent config. 2025-02-01 11:39:44 -05:00
adityasoni9998 ee1173e841 Merge branch 'main' into codeact_browsing 2025-02-01 11:37:32 -05:00
adityasoni9998 e66a1132c5 Merge remote-tracking branch 'upstream/main' 2025-02-01 11:37:15 -05:00
adityasoni9998 d34c41261b Merge branch 'main' into codeact_browsing 2025-01-30 13:48:32 -05:00
adityasoni9998 a699a0d306 Merge remote-tracking branch 'upstream/main' 2025-01-30 13:48:13 -05:00
adityasoni9998 818533f402 Merge branch 'main' into codeact_browsing 2025-01-30 13:47:28 -05:00
adityasoni9998 26c4f72e21 Merge remote-tracking branch 'upstream/main' 2025-01-30 13:46:05 -05:00
adityasoni9998 a7d38cd421 Undo changes in package-lock.json. 2025-01-27 18:42:45 -05:00
adityasoni9998 70772ccf31 Merge remote-tracking branch 'upstream/main' into codeact_browsing 2025-01-27 18:41:19 -05:00
adityasoni9998 6b94c97cc2 Merge remote-tracking branch 'upstream/main' 2025-01-27 18:38:45 -05:00
adityasoni9998 9b742c5042 Added LLM-check for visual browsing tool usage. (not support for GPT-4o models) 2025-01-26 13:09:14 -05:00
adityasoni9998 f45e7ec29f Merge branch 'main' into codeact_browsing 2025-01-25 20:33:09 -05:00
adityasoni9998 dfee306e06 Merge remote-tracking branch 'upstream/main' 2025-01-25 20:32:23 -05:00
adityasoni9998 4315c228fb Allow screenshot-based browsing in openhands with set-of-marks annotated screenshot. 2025-01-25 20:31:17 -05:00
adityasoni9998 f5eed29995 Visual browsing using Set-of-marks annotated screenshot in CodeActAgent 2025-01-24 19:21:49 -05:00
adityasoni9998 ce0979f715 Merge remote-tracking branch 'upstream/main' 2025-01-24 13:30:05 -05:00
adityasoni9998 072d956f3b Merge remote-tracking branch 'upstream/main' 2025-01-19 19:23:27 -05:00
adityasoni9998 dcdb44863e Merge remote-tracking branch 'upstream/main' 2024-12-06 10:09:39 -05:00
adityasoni9998 5258fe8d29 Merge remote-tracking branch 'upstream/main' 2024-12-05 22:57:48 -05:00
adityasoni9998 bad7ccfee4 Merge remote-tracking branch 'upstream/main' 2024-12-05 21:38:01 -05:00
adityasoni9998 1fef52a152 Merge remote-tracking branch 'upstream/main' 2024-11-05 19:07:55 -05:00
adityasoni9998 6aba4621da Merge remote-tracking branch 'upstream/main' 2024-10-12 14:32:09 -04:00
adityasoni9998 c2505c0e34 Merge remote-tracking branch 'upstream/main' 2024-10-07 00:27:34 -04:00
adityasoni9998 a3c8bcc2b9 Merge remote-tracking branch 'upstream/main' 2024-10-05 19:24:43 -04:00
adityasoni9998 965cee7d48 added gitignore 2024-09-28 19:37:43 -04:00
285 changed files with 13047 additions and 6632 deletions
-6
View File
@@ -10,12 +10,6 @@ updates:
pre-commit:
patterns:
- "pre-commit"
llama:
patterns:
- "llama*"
chromadb:
patterns:
- "chromadb"
browsergym:
patterns:
- "browsergym*"
+5 -1
View File
@@ -11,6 +11,7 @@ on:
paths:
- 'docs/**'
- '.github/workflows/deploy-docs.yml'
- 'pydoc-markdown.yml'
branches:
- main
@@ -39,7 +40,10 @@ jobs:
with:
python-version: '3.12'
- name: Generate Python Docs
run: rm -rf docs/modules/python && pip install pydoc-markdown && pydoc-markdown
run: |
rm -rf docs/modules/python
pip install pydoc-markdown
pydoc-markdown
- name: Install dependencies
run: cd docs && npm ci
- name: Build website
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
python-version: '3.12'
cache: 'poetry'
- name: Install Python dependencies using Poetry
run: poetry install --without evaluation,llama-index
run: poetry install --without evaluation
- name: Build Environment
run: make build
- name: Run tests
+8 -2
View File
@@ -41,8 +41,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.4.0
uses: docker/setup-qemu-action@v3.6.0
with:
image: tonistiigi/binfmt:latest
- name: Login to GHCR
@@ -90,8 +92,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.4.0
uses: docker/setup-qemu-action@v3.6.0
with:
image: tonistiigi/binfmt:latest
- name: Login to GHCR
@@ -154,6 +158,8 @@ jobs:
base_image: ['nikolaik']
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Cache Poetry dependencies
uses: actions/cache@v4
with:
+2 -70
View File
@@ -54,7 +54,7 @@ jobs:
Hi! I started running the integration tests on your PR. You will receive a comment with the results shortly.
- name: Install Python dependencies using Poetry
run: poetry install --without evaluation,llama-index
run: poetry install --without evaluation
- name: Configure config.toml for testing with Haiku
env:
@@ -117,68 +117,6 @@ jobs:
echo "EOF" >> $GITHUB_ENV
# -------------------------------------------------------------
# Run DelegatorAgent tests for Haiku, limited to t01 and t02
- name: Wait a little bit (again)
run: sleep 5
- name: Configure config.toml for testing DelegatorAgent (Haiku)
env:
LLM_MODEL: "litellm_proxy/claude-3-5-haiku-20241022"
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
MAX_ITERATIONS: 30
run: |
echo "[llm.eval]" > config.toml
echo "model = \"$LLM_MODEL\"" >> config.toml
echo "api_key = \"$LLM_API_KEY\"" >> config.toml
echo "base_url = \"$LLM_BASE_URL\"" >> config.toml
echo "temperature = 0.0" >> config.toml
- name: Run integration test evaluation for DelegatorAgent (Haiku)
env:
SANDBOX_FORCE_REBUILD_RUNTIME: True
run: |
poetry run ./evaluation/integration_tests/scripts/run_infer.sh llm.eval HEAD DelegatorAgent '' 30 $N_PROCESSES "t01_fix_simple_typo,t02_add_bash_hello" 'delegator_haiku_run'
# Find and export the delegator test results
REPORT_FILE_DELEGATOR_HAIKU=$(find evaluation/evaluation_outputs/outputs/integration_tests/DelegatorAgent/*haiku*_maxiter_30_N* -name "report.md" -type f | head -n 1)
echo "REPORT_FILE_DELEGATOR_HAIKU: $REPORT_FILE_DELEGATOR_HAIKU"
echo "INTEGRATION_TEST_REPORT_DELEGATOR_HAIKU<<EOF" >> $GITHUB_ENV
cat $REPORT_FILE_DELEGATOR_HAIKU >> $GITHUB_ENV
echo >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
# -------------------------------------------------------------
# Run DelegatorAgent tests for DeepSeek, limited to t01 and t02
- name: Wait a little bit (again)
run: sleep 5
- name: Configure config.toml for testing DelegatorAgent (DeepSeek)
env:
LLM_MODEL: "litellm_proxy/deepseek-chat"
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
MAX_ITERATIONS: 30
run: |
echo "[llm.eval]" > config.toml
echo "model = \"$LLM_MODEL\"" >> config.toml
echo "api_key = \"$LLM_API_KEY\"" >> config.toml
echo "base_url = \"$LLM_BASE_URL\"" >> config.toml
echo "temperature = 0.0" >> config.toml
- name: Run integration test evaluation for DelegatorAgent (DeepSeek)
env:
SANDBOX_FORCE_REBUILD_RUNTIME: True
run: |
poetry run ./evaluation/integration_tests/scripts/run_infer.sh llm.eval HEAD DelegatorAgent '' 30 $N_PROCESSES "t01_fix_simple_typo,t02_add_bash_hello" 'delegator_deepseek_run'
# Find and export the delegator test results
REPORT_FILE_DELEGATOR_DEEPSEEK=$(find evaluation/evaluation_outputs/outputs/integration_tests/DelegatorAgent/deepseek*_maxiter_30_N* -name "report.md" -type f | head -n 1)
echo "REPORT_FILE_DELEGATOR_DEEPSEEK: $REPORT_FILE_DELEGATOR_DEEPSEEK"
echo "INTEGRATION_TEST_REPORT_DELEGATOR_DEEPSEEK<<EOF" >> $GITHUB_ENV
cat $REPORT_FILE_DELEGATOR_DEEPSEEK >> $GITHUB_ENV
echo >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
# -------------------------------------------------------------
# Run VisualBrowsingAgent tests for DeepSeek, limited to t05 and t06
- name: Wait a little bit (again)
run: sleep 5
@@ -213,7 +151,7 @@ jobs:
run: |
TIMESTAMP=$(date +'%y-%m-%d-%H-%M')
cd evaluation/evaluation_outputs/outputs # Change to the outputs directory
tar -czvf ../../../integration_tests_${TIMESTAMP}.tar.gz integration_tests/CodeActAgent/* integration_tests/DelegatorAgent/* integration_tests/VisualBrowsingAgent/* # Only include the actual result directories
tar -czvf ../../../integration_tests_${TIMESTAMP}.tar.gz integration_tests/CodeActAgent/* integration_tests/VisualBrowsingAgent/* # Only include the actual result directories
- name: Upload evaluation results as artifact
uses: actions/upload-artifact@v4
@@ -254,12 +192,6 @@ jobs:
**Integration Tests Report (DeepSeek)**
DeepSeek LLM Test Results:
${{ env.INTEGRATION_TEST_REPORT_DEEPSEEK }}
---
**Integration Tests Report Delegator (Haiku)**
${{ env.INTEGRATION_TEST_REPORT_DELEGATOR_HAIKU }}
---
**Integration Tests Report Delegator (DeepSeek)**
${{ env.INTEGRATION_TEST_REPORT_DELEGATOR_DEEPSEEK }}
---
**Integration Tests Report VisualBrowsing (DeepSeek)**
${{ env.INTEGRATION_TEST_REPORT_VISUALBROWSING_DEEPSEEK }}
+2 -2
View File
@@ -44,11 +44,11 @@ jobs:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- name: Install Python dependencies using Poetry
run: poetry install --without evaluation,llama-index
run: poetry install --without evaluation
- name: Build Environment
run: make build
- name: Run Tests
run: poetry run pytest --forked -n auto --cov=openhands --cov-report=xml -svv ./tests/unit --ignore=tests/unit/test_long_term_memory.py
run: poetry run pytest --forked -n auto --cov=openhands --cov-report=xml -svv ./tests/unit
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
env:
+1 -1
View File
@@ -100,7 +100,7 @@ poetry run pytest ./tests/unit/test_*.py
To reduce build time (e.g., if no changes were made to the client-runtime component), you can use an existing Docker container image by
setting the SANDBOX_RUNTIME_CONTAINER_IMAGE environment variable to the desired Docker image.
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.27-nikolaik`
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.28-nikolaik`
## Develop inside Docker container
+1 -30
View File
@@ -133,7 +133,7 @@ install-python-dependencies:
export HNSWLIB_NO_NATIVE=1; \
poetry run pip install chroma-hnswlib; \
fi
@poetry install --without llama-index
@poetry install
@if [ -f "/etc/manjaro-release" ]; then \
echo "$(BLUE)Detected Manjaro Linux. Installing Playwright dependencies...$(RESET)"; \
poetry run pip install playwright; \
@@ -265,35 +265,6 @@ setup-config-prompts:
@read -p "Enter your LLM base URL [mostly used for local LLMs, leave blank if not needed - example: http://localhost:5001/v1/]: " llm_base_url; \
if [[ ! -z "$$llm_base_url" ]]; then echo "base_url=\"$$llm_base_url\"" >> $(CONFIG_FILE).tmp; fi
@echo "Enter your LLM Embedding Model"; \
echo "Choices are:"; \
echo " - openai"; \
echo " - azureopenai"; \
echo " - Embeddings available only with OllamaEmbedding:"; \
echo " - llama2"; \
echo " - mxbai-embed-large"; \
echo " - nomic-embed-text"; \
echo " - all-minilm"; \
echo " - stable-code"; \
echo " - bge-m3"; \
echo " - bge-large"; \
echo " - paraphrase-multilingual"; \
echo " - snowflake-arctic-embed"; \
echo " - Leave blank to default to 'BAAI/bge-small-en-v1.5' via huggingface"; \
read -p "> " llm_embedding_model; \
echo "embedding_model=\"$$llm_embedding_model\"" >> $(CONFIG_FILE).tmp; \
if [ "$$llm_embedding_model" = "llama2" ] || [ "$$llm_embedding_model" = "mxbai-embed-large" ] || [ "$$llm_embedding_model" = "nomic-embed-text" ] || [ "$$llm_embedding_model" = "all-minilm" ] || [ "$$llm_embedding_model" = "stable-code" ]; then \
read -p "Enter the local model URL for the embedding model (will set llm.embedding_base_url): " llm_embedding_base_url; \
echo "embedding_base_url=\"$$llm_embedding_base_url\"" >> $(CONFIG_FILE).tmp; \
elif [ "$$llm_embedding_model" = "azureopenai" ]; then \
read -p "Enter the Azure endpoint URL (will overwrite llm.base_url): " llm_base_url; \
echo "base_url=\"$$llm_base_url\"" >> $(CONFIG_FILE).tmp; \
read -p "Enter the Azure LLM Embedding Deployment Name: " llm_embedding_deployment_name; \
echo "embedding_deployment_name=\"$$llm_embedding_deployment_name\"" >> $(CONFIG_FILE).tmp; \
read -p "Enter the Azure API Version: " llm_api_version; \
echo "api_version=\"$$llm_api_version\"" >> $(CONFIG_FILE).tmp; \
fi
# Develop in container
docker-dev:
+5 -5
View File
@@ -12,7 +12,7 @@
<a href="https://codecov.io/github/All-Hands-AI/OpenHands?branch=main"><img alt="CodeCov" src="https://img.shields.io/codecov/c/github/All-Hands-AI/OpenHands?style=for-the-badge&color=blue"></a>
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/LICENSE"><img src="https://img.shields.io/github/license/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="MIT License"></a>
<br/>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community"></a>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community"></a>
<a href="https://discord.gg/ESHStjSjD4"><img src="https://img.shields.io/badge/Discord-Join%20Us-purple?logo=discord&logoColor=white&style=for-the-badge" alt="Join our Discord community"></a>
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/CREDITS.md"><img src="https://img.shields.io/badge/Project-Credits-blue?style=for-the-badge&color=FFE165&logo=github&logoColor=white" alt="Credits"></a>
<br/>
@@ -43,17 +43,17 @@ See the [Running OpenHands](https://docs.all-hands.dev/modules/usage/installatio
system requirements and more information.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.27
docker.all-hands.dev/all-hands-ai/openhands:0.28
```
You'll find OpenHands running at [http://localhost:3000](http://localhost:3000)!
@@ -96,7 +96,7 @@ troubleshooting resources, and advanced configuration options.
OpenHands is a community-driven project, and we welcome contributions from everyone. We do most of our communication
through Slack, so this is the best place to start, but we also are happy to have you contact us on Discord or Github:
- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg) - Here we talk about research, architecture, and future development.
- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw) - Here we talk about research, architecture, and future development.
- [Join our Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback.
- [Read or post Github Issues](https://github.com/All-Hands-AI/OpenHands/issues) - Check out the issues we're working on, or add your own ideas.
-12
View File
@@ -132,15 +132,6 @@ api_key = ""
# Custom LLM provider
#custom_llm_provider = ""
# Embedding API base URL
#embedding_base_url = ""
# Embedding deployment name
#embedding_deployment_name = ""
# Embedding model to use
embedding_model = "local"
# Maximum number of characters in an observation's content
#max_message_chars = 10000
@@ -227,9 +218,6 @@ codeact_enable_llm_editor = false
# whether the IPython tool is enabled
codeact_enable_jupyter = true
# Name of the micro agent to use for this agent
#micro_agent_name = ""
# Memory enabled
#memory_enabled = false
+1 -1
View File
@@ -26,7 +26,7 @@ RUN apt-get update -y \
COPY ./pyproject.toml ./poetry.lock ./
RUN touch README.md
RUN export POETRY_CACHE_DIR && poetry install --without evaluation,llama-index --no-root && rm -rf $POETRY_CACHE_DIR
RUN export POETRY_CACHE_DIR && poetry install --without evaluation --no-root && rm -rf $POETRY_CACHE_DIR
FROM python:3.12.3-slim AS openhands-app
+1 -1
View File
@@ -11,7 +11,7 @@ services:
- BACKEND_HOST=${BACKEND_HOST:-"0.0.0.0"}
- SANDBOX_API_HOSTNAME=host.docker.internal
#
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.27-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.28-nikolaik}
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
ports:
+1 -1
View File
@@ -7,7 +7,7 @@ services:
image: openhands:latest
container_name: openhands-app-${DATE:-}
environment:
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik}
#- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234} # enable this only if you want a specific non-root sandbox user but you will have to manually adjust permissions of openhands-state for this user
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
ports:
@@ -333,12 +333,6 @@ Pour les configurations de développement, vous pouvez également définir des c
Les options de configuration de l'agent sont définies dans les sections `[agent]` et `[agent.<agent_name>]` du fichier `config.toml`.
**Configuration du micro-agent**
- `micro_agent_name`
- Type : `str`
- Valeur par défaut : `""`
- Description : Nom du micro-agent à utiliser pour cet agent
**Configuration de la mémoire**
- `memory_enabled`
- Type : `bool`
@@ -52,7 +52,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -61,7 +61,7 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.cli
```
@@ -46,7 +46,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -56,6 +56,6 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.main -t "write a bash script that prints hi" --no-auto-continue
```
@@ -13,16 +13,16 @@
La façon la plus simple d'exécuter OpenHands est avec Docker.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.27
docker.all-hands.dev/all-hands-ai/openhands:0.28
```
Vous pouvez également exécuter OpenHands en mode [headless scriptable](https://docs.all-hands.dev/modules/usage/how-to/headless-mode), en tant que [CLI interactive](https://docs.all-hands.dev/modules/usage/how-to/cli-mode), ou en utilisant l'[Action GitHub OpenHands](https://docs.all-hands.dev/modules/usage/how-to/github-action).
@@ -42,7 +42,7 @@ Explorez le code source d'OpenHands sur [GitHub](https://github.com/All-Hands-AI
/>
</a>
<br></br>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg">
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw">
<img
src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge"
alt="Join our Slack community"
@@ -13,7 +13,7 @@ C'est le Runtime par défaut qui est utilisé lorsque vous démarrez OpenHands.
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```
@@ -328,12 +328,6 @@ LLM(大语言模型)配置选项在 `config.toml` 文件的 `[llm]` 部分中定
Agent 配置选项在 `config.toml` 文件的 `[agent]``[agent.<agent_name>]` 部分中定义。
**Microagent 配置**
- `micro_agent_name`
- 类型: `str`
- 默认值: `""`
- 描述: 用于此 agent 的 micro agent 名称
**内存配置**
- `memory_enabled`
- 类型: `bool`
@@ -50,7 +50,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -59,7 +59,7 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.cli
```
@@ -47,7 +47,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -57,6 +57,6 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.main -t "write a bash script that prints hi" --no-auto-continue
```
@@ -11,16 +11,16 @@
在 Docker 中运行 OpenHands 是最简单的方式。
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.27
docker.all-hands.dev/all-hands-ai/openhands:0.28
```
你也可以在可脚本化的[无头模式](https://docs.all-hands.dev/modules/usage/how-to/headless-mode)下运行 OpenHands,作为[交互式 CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode),或使用 [OpenHands GitHub Action](https://docs.all-hands.dev/modules/usage/how-to/github-action)。
@@ -42,7 +42,7 @@ OpenHands 是一个**自主 AI 软件工程师**,能够执行复杂的工程
/>
</a>
<br></br>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg">
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw">
<img
src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge"
alt="Join our Slack community"
@@ -11,7 +11,7 @@
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```
@@ -4,18 +4,30 @@ The GitHub Resolver automates code fixes and provides intelligent assistance for
## Setup
The Cloud Github Resolver is available automatically when you
The Cloud GitHub Resolver is available automatically when you
[grant OpenHands Cloud repository access](./openhands-cloud.md#adding-repositories).
## Usage
After granting OpenHands Cloud repository access, you can use the Cloud GitHub Resolver on the issues and pull requests
on the repository.
### Issues
On your repository, label an issue with `openhands`. OpenHands will attempt to fix the issue.
On your repository, label an issue with `openhands`. OpenHands will:
1. Comment on the issue to let you know it is working on it.
- You can click on the link to track the progress on OpenHands Cloud.
2. Open a pull request if it determines that the issue has been successfully resolved.
3. Comment on the issue with a summary of the performed tasks and a link to the pull request.
### Pull Requests
In order to get OpenHands to work on pull requests, use `@openhands` in top level or single inline comments to:
To get OpenHands to work on pull requests, use `@openhands` in top level or inline comments to:
- Ask questions
- Request updates
- Get code explanations
OpenHands will:
1. Comment on the PR to let you know it is working on it.
2. Perform the task.
+11 -5
View File
@@ -12,14 +12,16 @@ instructions on how to access it.
After visiting OpenHands Cloud, you will be asked to connect with your GitHub account:
1. After reading and accepting the terms of service, click `Connect to GitHub`.
2. Review the permissions requested by OpenHands and then click `Authorize OpenHands by All Hands AI`.
2. Review the permissions requested by OpenHands and then click `Authorize OpenHands AI`.
- OpenHands will require some permissions from your GitHub account. To read more about these permissions,
you can click the `Learn more` link on the GitHub authorize page.
## Adding Repositories
## Repository Access
### Adding Repository Access
You can grant OpenHands specific repository access:
1. Under the `Select a GitHub project` dropdown, select `Add more repositories...`.
1. Click the `Select a GitHub project` dropdown, select `Add more repositories...`.
2. Select the organization, then choose the specific repositories to grant OpenHands access to.
- Openhands requests short-lived tokens (8-hour expiry) with these permissions:
- Actions: Read and write
@@ -34,6 +36,10 @@ You can grant OpenHands specific repository access:
- Repository access for a user is granted based on:
- Granted permission for the repository.
- User's GitHub permissions (owner/collaborator).
3. Click on `Install & Authorize`.
You can manage repository access any time by following the above workflow or visiting the Settings page and selecting
`Configure GitHub Repositories` under the `GitHub Settings` section.
### Modifying Repository Access
You can modify repository access at any time by:
* Using the same `Select a GitHub project > Add more repositories` workflow, or
* Visiting the Settings page and selecting `Configure GitHub Repositories` under the `GitHub Settings` section.
+6 -33
View File
@@ -197,21 +197,6 @@ For development setups, you can also define custom named LLM configurations. See
- Default: `""`
- Description: Custom LLM provider
### Embeddings
- `embedding_base_url`
- Type: `str`
- Default: `""`
- Description: Embedding API base URL
- `embedding_deployment_name`
- Type: `str`
- Default: `""`
- Description: Embedding deployment name
- `embedding_model`
- Type: `str`
- Default: `"local"`
- Description: Embedding model to use
### Message Handling
- `max_message_chars`
@@ -296,23 +281,6 @@ For development setups, you can also define custom named LLM configurations. See
The agent configuration options are defined in the `[agent]` and `[agent.<agent_name>]` sections of the `config.toml` file.
### Microagent Configuration
- `micro_agent_name`
- Type: `str`
- Default: `""`
- Description: Name of the micro agent to use for this agent
### Memory Configuration
- `memory_enabled`
- Type: `bool`
- Default: `false`
- Description: Whether long-term memory (embeddings) is enabled
- `memory_max_threads`
- Type: `int`
- Default: `3`
- Description: The maximum number of threads indexing at the same time for embeddings
### LLM Configuration
- `llm_config`
- Type: `str`
@@ -340,6 +308,11 @@ The agent configuration options are defined in the `[agent]` and `[agent.<agent_
- Default: `false`
- Description: Whether Jupyter is enabled in the action space
- `enable_search_engine`
- Type: `bool`
- Default: `false`
- Description: Whether the search engine tool is enabled in the action space. See [Search Configuration](./search/search-configuration.md) for details.
- `enable_history_truncation`
- Type: `bool`
- Default: `true`
@@ -387,7 +360,7 @@ To use these with the docker command, pass in `-e SANDBOX_<option>`. Example: `-
- `runtime_binding_address`
- Type: `str`
- Default: `127.0.0.1`
- Default: `0.0.0.0`
- Description: The binding address for the runtime ports. It specifies which network interface on the host machine Docker should bind the runtime ports to.
### Linting and Plugins
+1 -1
View File
@@ -36,7 +36,7 @@ At this time, we will follow the following release process:
1. All people who contributed public feedback will receive an email describing the data release and being given an opportunity to opt out.
2. The person or people in charge of the data release will perform quality control of the data, removing low-quality feedback,
removing email submitter email addresses, and attempting to remove any sensitive information.
3. The data will be released publicly under the MIT license through commonly used sites such as github or Hugging Face.
3. The data will be released publicly under the MIT license through commonly used sites such as GitHub or Hugging Face.
### What if I want my data deleted?
+2 -2
View File
@@ -35,7 +35,7 @@ To run OpenHands in CLI mode with Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -45,7 +45,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.cli
```
+1 -1
View File
@@ -39,7 +39,7 @@ You can provide custom directions for OpenHands by following the [README for the
### Custom configurations
Github resolver will automatically check for valid [repository secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=webui#creating-secrets-for-a-repository) or [repository variables](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) to customize its behavior.
GitHub resolver will automatically check for valid [repository secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=webui#creating-secrets-for-a-repository) or [repository variables](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) to customize its behavior.
The customization options you can set are:
| **Attribute name** | **Type** | **Purpose** | **Example** |
+2 -2
View File
@@ -32,7 +32,7 @@ To run OpenHands in Headless mode with Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -43,7 +43,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.27 \
docker.all-hands.dev/all-hands-ai/openhands:0.28 \
python -m openhands.core.main -t "write a bash script that prints hi"
```
+4 -4
View File
@@ -58,17 +58,17 @@ A system with a modern processor and a minimum of **4GB RAM** is recommended to
The easiest way to run OpenHands is in Docker.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.27
docker.all-hands.dev/all-hands-ai/openhands:0.28
```
You'll find OpenHands running at http://localhost:3000!
@@ -76,7 +76,7 @@ You'll find OpenHands running at http://localhost:3000!
You can also [connect OpenHands to your local filesystem](https://docs.all-hands.dev/modules/usage/runtimes#connecting-to-your-filesystem),
run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/modules/usage/how-to/headless-mode),
interact with it via a [friendly CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode),
or run it on tagged issues with [a github action](https://docs.all-hands.dev/modules/usage/how-to/github-action).
or run it on tagged issues with [a GitHub action](https://docs.all-hands.dev/modules/usage/how-to/github-action).
## Setup
+1 -7
View File
@@ -31,17 +31,11 @@ You will need your ChatGPT deployment name which can be found on the deployments
- `Base URL` to your Azure API Base URL (e.g. `https://example-endpoint.openai.azure.com`)
- `API Key` to your Azure API key
## Embeddings
OpenHands uses llama-index for embeddings. You can find their documentation on Azure [here](https://docs.llamaindex.ai/en/stable/api_reference/embeddings/azure_openai/).
### Azure OpenAI Configuration
When running OpenHands, set the following environment variables using `-e` in the
When running OpenHands, set the following environment variable using `-e` in the
[docker run command](/modules/usage/installation#start-the-app):
```
LLM_EMBEDDING_MODEL="azureopenai"
LLM_EMBEDDING_DEPLOYMENT_NAME="<your-embedding-deployment-name>" # e.g. "TextEmbedding...<etc>"
LLM_API_VERSION="<api-version>" # e.g. "2024-02-15-preview"
```
+72 -5
View File
@@ -10,13 +10,16 @@ We also support "remote" runtimes, which are typically managed by third-parties.
They can make setup a bit simpler and more scalable, especially
if you're running many OpenHands conversations in parallel (e.g. to do evaluation).
Additionally, we provide a "local" runtime that runs directly on your machine without Docker,
which can be useful in controlled environments like CI pipelines.
## Docker Runtime
This is the default Runtime that's used when you start OpenHands. You might notice
some flags being passed to `docker run` that make this possible:
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.28-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```
@@ -56,11 +59,12 @@ any files that are mounted into its workspace.
This setup can cause some issues with file permissions (hence the `SANDBOX_USER_ID` variable)
but seems to work well on most systems.
## All Hands Runtime
The All Hands Runtime is currently in beta. You can request access by joining
the #remote-runtime-limited-beta channel on Slack ([see the README](https://github.com/All-Hands-AI/OpenHands?tab=readme-ov-file#-how-to-join-the-community) for an invite).
## OpenHands Remote Runtime
To use the All Hands Runtime, set the following environment variables when
OpenHands Remote Runtime is currently in beta (read [here](https://runtime.all-hands.dev/) for more details), it allows you to launch runtimes in parallel in the cloud.
Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
To use the OpenHands Remote Runtime, set the following environment variables when
starting OpenHands:
```bash
@@ -117,3 +121,66 @@ bash -i <(curl -sL https://get.daytona.io/openhands)
Once executed, OpenHands should be running locally and ready for use.
For more details and manual initialization, view the entire [README.md](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/runtime/impl/daytona/README.md)
## Local Runtime
The Local Runtime allows the OpenHands agent to execute actions directly on your local machine without using Docker. This runtime is primarily intended for controlled environments like CI pipelines or testing scenarios where Docker is not available.
:::caution
**Security Warning**: The Local Runtime runs without any sandbox isolation. The agent can directly access and modify files on your machine. Only use this runtime in controlled environments or when you fully understand the security implications.
:::
### Prerequisites
Before using the Local Runtime, ensure you have the following dependencies installed:
1. You have followed the [Development setup instructions](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md).
2. tmux is available on your system.
### Configuration
To use the Local Runtime, besides required configurations like the model, API key, you'll need to set the following options via environment variables or the [config.toml file](https://github.com/All-Hands-AI/OpenHands/blob/main/config.template.toml) when starting OpenHands:
- Via environment variables:
```bash
# Required
export RUNTIME=local
# Optional but recommended
export WORKSPACE_BASE=/path/to/your/workspace
```
- Via `config.toml`:
```toml
[core]
runtime = "local"
workspace_base = "/path/to/your/workspace"
```
If `WORKSPACE_BASE` is not set, the runtime will create a temporary directory for the agent to work in.
### Example Usage
Here's an example of how to start OpenHands with the Local Runtime in Headless Mode:
```bash
# Set the runtime type to local
export RUNTIME=local
# Optionally set a workspace directory
export WORKSPACE_BASE=/path/to/your/project
# Start OpenHands
poetry run python -m openhands.core.main -t "write a bash script that prints hi"
```
### Use Cases
The Local Runtime is particularly useful for:
- CI/CD pipelines where Docker is not available.
- Testing and development of OpenHands itself.
- Environments where container usage is restricted.
- Scenarios where direct file system access is required.
@@ -0,0 +1,113 @@
# Search Configuration
OpenHands provides a search engine capability that allows agents to perform web searches using the Brave Search API. This guide explains how to configure and use the search feature.
## Overview
The search engine feature enables agents to:
- Execute web search queries programmatically
- Get structured results including web pages, news, videos, and FAQs
- Avoid CAPTCHA challenges that often occur when using browser-based search
## Configuration
### Enabling Search
To enable the search engine feature, set the following in your `config.toml`:
```toml
[agent]
enable_search_engine = true
```
Or when using Docker, set the environment variable:
```bash
-e AGENT_ENABLE_SEARCH_ENGINE=true
```
### API Key Setup
The search feature requires a Brave Search API key. You can obtain one from the [Brave Search API Dashboard](https://api.search.brave.com/app/keys).
Set the API key in your `config.toml`:
```toml
[search]
enabled = true
api_key = "your-api-key-here"
```
Or when using Docker:
```bash
-e SEARCH_ENABLED=true
-e SEARCH_API_KEY="your-api-key-here"
```
## Search Results
When a search is performed, the results are returned in a structured format that includes:
- Web search results
- News articles
- Video content
- FAQ entries
- Discussion threads
- Infoboxes (when available)
- Location information (when relevant)
Each result type includes:
- Title
- URL (when applicable)
- Description or snippet
- Additional metadata specific to the result type
## Usage Example
When the search feature is enabled, agents can use the `search_engine` tool to perform searches. For example:
```python
# The agent can make a tool call like this:
{
"name": "search_engine",
"arguments": {
"query": "latest developments in AI"
}
}
```
The search results will be returned in a markdown-formatted structure that's easy for the agent to parse and understand.
## Best Practices
1. **Query Formulation**
- Keep queries focused and specific
- Include relevant keywords
- Avoid overly complex or compound queries
2. **Rate Limiting**
- Be mindful of API rate limits
- Cache results when appropriate
- Implement retries with exponential backoff for failed requests
3. **Error Handling**
- Handle API errors gracefully
- Provide meaningful feedback when searches fail
- Have fallback strategies when search is unavailable
## Troubleshooting
Common issues and solutions:
1. **Search Not Working**
- Verify `enable_search_engine` is set to `true`
- Confirm the Brave API key is correctly set
- Check API key permissions and quotas
2. **No Results**
- Verify the query is not empty
- Try reformulating the search query
- Check for any API response errors
3. **Rate Limiting**
- Monitor API usage
- Implement caching if needed
- Consider upgrading API tier if limits are consistently hit
+4 -4
View File
@@ -24,7 +24,7 @@
"@docusaurus/module-type-aliases": "^3.5.1",
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.5.1",
"typescript": "~5.7.3"
"typescript": "~5.8.2"
},
"engines": {
"node": ">=18.0"
@@ -17638,9 +17638,9 @@
}
},
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
+1 -1
View File
@@ -31,7 +31,7 @@
"@docusaurus/module-type-aliases": "^3.5.1",
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.5.1",
"typescript": "~5.7.3"
"typescript": "~5.8.2"
},
"browserslist": {
"production": [
+1 -1
View File
@@ -8,7 +8,7 @@ function CustomFooter() {
<footer className="custom-footer">
<div className="footer-content">
<div className="footer-icons">
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg" target="_blank" rel="noopener noreferrer">
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw" target="_blank" rel="noopener noreferrer">
<FaSlack />
</a>
<a href="https://discord.gg/ESHStjSjD4" target="_blank" rel="noopener noreferrer">
@@ -46,7 +46,7 @@ export function HomepageHeader() {
<a href="https://codecov.io/github/All-Hands-AI/OpenHands?branch=main"><img alt="CodeCov" src="https://img.shields.io/codecov/c/github/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" /></a>
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/LICENSE"><img src="https://img.shields.io/github/license/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="MIT License" /></a>
<br/>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ypg5jweb-d~6hObZDbXi_HEL8PDrbHg"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community" /></a>
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2ngejmfw6-9gW4APWOC9XUp1n~SiQ6iw"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community" /></a>
<a href="https://discord.gg/ESHStjSjD4"><img src="https://img.shields.io/badge/Discord-Join%20Us-purple?logo=discord&logoColor=white&style=for-the-badge" alt="Join our Discord community" /></a>
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/CREDITS.md"><img src="https://img.shields.io/badge/Project-Credits-blue?style=for-the-badge&color=FFE165&logo=github&logoColor=white" alt="Credits" /></a>
<br/>
+3 -2
View File
@@ -56,9 +56,10 @@ You can update the arguments in the script
./evaluation/benchmarks/aider_bench/scripts/run_infer.sh eval_gpt35_turbo HEAD CodeActAgent 100 1 "1,3,10"
```
### Run Inference on `RemoteRuntime` (experimental)
### Run Inference on `RemoteRuntime`
This is in beta. Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
This is in limited beta. Contact Xingyao over slack if you want to try this out!
```bash
./evaluation/benchmarks/aider_bench/scripts/run_infer.sh [model_config] [git-version] [agent] [eval_limit] [eval-num-workers] [eval_ids]
@@ -1,6 +1,6 @@
# Commit0 Evaluation with OpenHands
This folder contains the evaluation harness that we built on top of the original [Commit0](https://commit-0.github.io/) ([paper](TBD)).
This folder contains the evaluation harness that we built on top of the original [Commit0](https://commit-0.github.io/) ([paper](https://arxiv.org/abs/2412.01769v1)).
The evaluation consists of three steps:
@@ -23,10 +23,10 @@ Make sure your Docker daemon is running, and you have ample disk space (at least
When the `run_infer.sh` script is started, it will automatically pull the `lite` split in Commit0. For example, for instance ID `commit-0/minitorch`, it will try to pull our pre-build docker image `wentingzhao/minitorch` from DockerHub. This image will be used create an OpenHands runtime image where the agent will operate on.
```bash
./evaluation/benchmarks/commit0_bench/scripts/run_infer.sh [repo_split] [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
./evaluation/benchmarks/commit0/scripts/run_infer.sh [repo_split] [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
# Example
./evaluation/benchmarks/commit0_bench/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 16 100 8 wentingzhao/commit0_combined test
./evaluation/benchmarks/commit0/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 16 100 8 wentingzhao/commit0_combined test
```
where `model_config` is mandatory, and the rest are optional.
@@ -48,26 +48,25 @@ default, it is set to 1.
- `dataset`, a huggingface dataset name. e.g. `wentingzhao/commit0_combined`, specifies which dataset to evaluate on.
- `dataset_split`, split for the huggingface dataset. Notice only `test` is supported for Commit0.
Note that the `USE_INSTANCE_IMAGE` environment variable is always set to `true` for Commit0.
Let's say you'd like to run 10 instances using `llm.eval_sonnet` and CodeActAgent,
then your command would be:
```bash
./evaluation/benchmarks/commit0_bench/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 10 30 1 wentingzhao/commit0_combined test
./evaluation/benchmarks/commit0/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 10 30 1 wentingzhao/commit0_combined test
```
### Run Inference on `RemoteRuntime` (experimental)
### Run Inference on `RemoteRuntime`
This is in beta. Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
This is in limited beta. Contact Xingyao over slack if you want to try this out!
```bash
./evaluation/benchmarks/commit0_bench/scripts/run_infer.sh [repo_split] [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
./evaluation/benchmarks/commit0/scripts/run_infer.sh [repo_split] [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
# Example - This runs evaluation on CodeActAgent for 10 instances on "wentingzhao/commit0_combined"'s test set, with max 30 iteration per instances, with 1 number of workers running in parallel
ALLHANDS_API_KEY="YOUR-API-KEY" RUNTIME=remote SANDBOX_REMOTE_RUNTIME_API_URL="https://runtime.eval.all-hands.dev" EVAL_DOCKER_IMAGE_PREFIX="docker.io/wentingzhao" \
./evaluation/benchmarks/commit0_bench/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 10 30 1 wentingzhao/commit0_combined test
./evaluation/benchmarks/commit0/scripts/run_infer.sh lite llm.eval_sonnet HEAD CodeActAgent 10 30 1 wentingzhao/commit0_combined test
```
To clean-up all existing runtime you've already started, run:
@@ -39,7 +39,6 @@ from openhands.utils.async_utils import call_async_from_sync
from openhands.utils.shutdown_listener import sleep_if_should_continue
USE_HINT_TEXT = os.environ.get('USE_HINT_TEXT', 'false').lower() == 'true'
USE_INSTANCE_IMAGE = os.environ.get('USE_INSTANCE_IMAGE', 'false').lower() == 'true'
RUN_WITH_BROWSING = os.environ.get('RUN_WITH_BROWSING', 'false').lower() == 'true'
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
@@ -105,7 +104,6 @@ def get_config(
instance: pd.Series,
metadata: EvalMetadata,
) -> AppConfig:
assert USE_INSTANCE_IMAGE
repo_name = instance['repo'].split('/')[1]
base_container_image = get_instance_docker_image(repo_name)
logger.info(
@@ -303,16 +301,6 @@ def complete_runtime(
pytest_exit_code = obs.content.strip()
# logger.info(f'Pytest exit code: {pytest_exit_code}')
# Read the test report
action = CmdRunAction(command='cat report.json')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
# logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
isinstance(obs, CmdOutputObservation),
f'Failed to read test report: {str(obs)}',
)
# Get test IDs from instance
repo_name = instance['repo'].split('/')[1]
repo_name = repo_name.replace('.', '-')
@@ -323,8 +311,20 @@ def complete_runtime(
# logger.info(obs, extra={'msg_type': 'OBSERVATION'})
test_ids = obs.content.strip().split('\n')
# Read the test report
action = CmdRunAction(command='cat report.json')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
# logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
isinstance(obs, CmdOutputObservation),
f'Failed to read test report: {str(obs)}',
)
json_report = obs.content.strip()
try:
report = json.loads(obs.content)
report = json.loads(json_report)
tests = {x['nodeid']: x['call'] for x in report['tests'] if 'call' in x}
# Calculate test statistics
@@ -30,11 +30,6 @@ if [ -z "$MAX_ITER" ]; then
MAX_ITER=100
fi
if [ -z "$USE_INSTANCE_IMAGE" ]; then
echo "USE_INSTANCE_IMAGE not specified, use default true"
USE_INSTANCE_IMAGE=true
fi
if [ -z "$RUN_WITH_BROWSING" ]; then
echo "RUN_WITH_BROWSING not specified, use default false"
RUN_WITH_BROWSING=false
@@ -56,8 +51,6 @@ if [ -z "$SPLIT" ]; then
SPLIT="test"
fi
export USE_INSTANCE_IMAGE=$USE_INSTANCE_IMAGE
echo "USE_INSTANCE_IMAGE: $USE_INSTANCE_IMAGE"
export RUN_WITH_BROWSING=$RUN_WITH_BROWSING
echo "RUN_WITH_BROWSING: $RUN_WITH_BROWSING"
@@ -91,7 +84,7 @@ fi
function run_eval() {
local eval_note=$1
COMMAND="poetry run python evaluation/benchmarks/commit0_bench/run_infer.py \
COMMAND="poetry run python evaluation/benchmarks/commit0/run_infer.py \
--agent-cls $AGENT \
--llm-config $MODEL_CONFIG \
--max-iterations $MAX_ITER \
+4 -4
View File
@@ -13,6 +13,7 @@
# limitations under the License.
# This file is modified from https://github.com/ShishirPatil/gorilla/blob/main/eval/eval-scripts/ast_eval_hf.py
import tree_sitter_python as tspython
from tree_sitter import Language, Parser
@@ -39,10 +40,9 @@ def get_all_sub_trees(root_node):
# Parse the program into AST trees
def ast_parse(candidate, lang='python'):
LANGUAGE = Language('evaluation/gorilla/my-languages.so', lang)
parser = Parser()
parser.set_language(LANGUAGE)
def ast_parse(candidate):
LANGUAGE = Language(tspython.language())
parser = Parser(LANGUAGE)
candidate_tree = parser.parse(bytes(candidate, 'utf8')).root_node
return candidate_tree
+4 -4
View File
@@ -13,6 +13,7 @@
# limitations under the License.
# This file is modified from https://github.com/ShishirPatil/gorilla/blob/main/eval/eval-scripts/ast_eval_tf.py
import tree_sitter_python as tspython
from tree_sitter import Language, Parser
@@ -39,10 +40,9 @@ def get_all_sub_trees(root_node):
# Parse the program into AST trees
def ast_parse(candidate, lang='python'):
LANGUAGE = Language('evaluation/gorilla/my-languages.so', lang)
parser = Parser()
parser.set_language(LANGUAGE)
def ast_parse(candidate):
LANGUAGE = Language(tspython.language())
parser = Parser(LANGUAGE)
candidate_tree = parser.parse(bytes(candidate, 'utf8')).root_node
return candidate_tree
+4 -4
View File
@@ -13,6 +13,7 @@
# limitations under the License.
# This file is modified from https://github.com/ShishirPatil/gorilla/blob/main/eval/eval-scripts/ast_eval_th.py
import tree_sitter_python as tspython
from tree_sitter import Language, Parser
@@ -39,10 +40,9 @@ def get_all_sub_trees(root_node):
# Parse the program into AST trees
def ast_parse(candidate, lang='python'):
LANGUAGE = Language('evaluation/gorilla/my-languages.so', lang)
parser = Parser()
parser.set_language(LANGUAGE)
def ast_parse(candidate):
LANGUAGE = Language(tspython.language())
parser = Parser(LANGUAGE)
candidate_tree = parser.parse(bytes(candidate, 'utf8')).root_node
return candidate_tree
+9 -9
View File
@@ -71,19 +71,19 @@ def fetch_data(url, filename):
def get_data_for_hub(hub: str):
if hub == 'hf':
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/eval/eval-data/questions/huggingface/questions_huggingface_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/api/huggingface_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/apibench/huggingface_eval.json'
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/eval/eval-data/questions/huggingface/questions_huggingface_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/api/huggingface_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/apibench/huggingface_eval.json'
ast_eval = ast_eval_hf
elif hub == 'torch':
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/eval/eval-data/questions/torchhub/questions_torchhub_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/api/torchhub_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/apibench/torchhub_eval.json'
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/eval/eval-data/questions/torchhub/questions_torchhub_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/api/torchhub_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/apibench/torchhub_eval.json'
ast_eval = ast_eval_th
elif hub == 'tf':
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/eval/eval-data/questions/tensorflowhub/questions_tensorflowhub_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/api/tensorflowhub_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/main/data/apibench/tensorflow_eval.json'
question_data = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/eval/eval-data/questions/tensorflowhub/questions_tensorflowhub_0_shot.jsonl'
api_dataset = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/api/tensorflowhub_api.jsonl'
apibench = 'https://raw.githubusercontent.com/ShishirPatil/gorilla/refs/tags/v1.2/data/apibench/tensorflow_eval.json'
ast_eval = ast_eval_tf
question_data = fetch_data(question_data, 'question_data.jsonl')
+3 -2
View File
@@ -19,9 +19,10 @@ Access with browser the above MiniWoB URLs and see if they load correctly.
./evaluation/benchmarks/miniwob/scripts/run_infer.sh llm.claude-35-sonnet-eval
```
### Run Inference on `RemoteRuntime` (experimental)
### Run Inference on `RemoteRuntime`
This is in beta. Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
This is in limited beta. Contact Xingyao over slack if you want to try this out!
```bash
./evaluation/benchmarks/miniwob/scripts/run_infer.sh [model_config] [git-version] [agent] [note] [eval_limit] [num_workers]
+25 -78
View File
@@ -2,11 +2,13 @@
This folder contains the evaluation harness that we built on top of the original [SWE-Bench benchmark](https://www.swebench.com/) ([paper](https://arxiv.org/abs/2310.06770)).
**UPDATE (2/18/2025): We now support running SWE-Gym using the same evaluation harness here. For more details, checkout [this README](./SWE-Gym.md).
**UPDATE (7/1/2024): We now support the official SWE-Bench dockerized evaluation as announced [here](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md).**
The evaluation consists of three steps:
1. Environment setup: [install python environment](../../README.md#development-environment), [configure LLM config](../../README.md#configure-openhands-and-your-llm), and [pull docker](#openhands-swe-bench-instance-level-docker-support).
1. Environment setup: [install python environment](../../README.md#development-environment) and [configure LLM config](../../README.md#configure-openhands-and-your-llm).
2. [Run inference](#run-inference-on-swe-bench-instances): Generate a edit patch for each Github issue
3. [Evaluate patches using SWE-Bench docker](#evaluate-generated-patches)
@@ -14,22 +16,21 @@ The evaluation consists of three steps:
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
## OpenHands SWE-Bench Instance-level Docker Support
## Run Inference (Rollout) on SWE-Bench Instances: Generate Patch from Problem Statement
OpenHands now support using the [official evaluation docker](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md) for both **[inference](#run-inference-on-swe-bench-instances) and [evaluation](#evaluate-generated-patches)**.
This is now the default behavior.
### Running Locally with Docker
## Run Inference on SWE-Bench Instances
Make sure your Docker daemon is running, and you have ample disk space (at least 200-500GB, depends on the SWE-Bench set you are running on) for the instance-level docker image.
Make sure your Docker daemon is running, and you have ample disk space (at least 200-500GB, depends on the SWE-Bench set you are running on) for the [instance-level docker image](#openhands-swe-bench-instance-level-docker-support).
When the `run_infer.sh` script is started, it will automatically pull the relevant SWE-Bench images. For example, for instance ID `django_django-11011`, it will try to pull our pre-build docker image `sweb.eval.x86_64.django_s_django-11011` from DockerHub. This image will be used create an OpenHands runtime image where the agent will operate on.
When the `run_infer.sh` script is started, it will automatically pull the relevant SWE-Bench images.
For example, for instance ID `django_django-11011`, it will try to pull our pre-build docker image `sweb.eval.x86_64.django_s_django-11011` from DockerHub.
This image will be used create an OpenHands runtime image where the agent will operate on.
```bash
./evaluation/benchmarks/swe_bench/scripts/run_infer.sh [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
# Example
./evaluation/benchmarks/swe_bench/scripts/run_infer.sh llm.eval_gpt4_1106_preview HEAD CodeActAgent 300 30 1 princeton-nlp/SWE-bench_Lite test
./evaluation/benchmarks/swe_bench/scripts/run_infer.sh llm.eval_gpt4_1106_preview HEAD CodeActAgent 500 100 1 princeton-nlp/SWE-bench_Verified test
```
where `model_config` is mandatory, and the rest are optional.
@@ -47,14 +48,16 @@ in order to use `eval_limit`, you must also set `agent`.
default, it is set to 30.
- `num_workers`, e.g. `3`, is the number of parallel workers to run the evaluation. By
default, it is set to 1.
- `dataset`, a huggingface dataset name. e.g. `princeton-nlp/SWE-bench` or `princeton-nlp/SWE-bench_Lite`, specifies which dataset to evaluate on.
- `dataset`, a huggingface dataset name. e.g. `princeton-nlp/SWE-bench`, `princeton-nlp/SWE-bench_Lite`, or `princeton-nlp/SWE-bench_Verified`, specifies which dataset to evaluate on.
- `dataset_split`, split for the huggingface dataset. e.g., `test`, `dev`. Default to `test`.
There are also two optional environment variables you can set.
> [!CAUTION]
> Setting `num_workers` larger than 1 is not officially tested, YMMV.
There is also one optional environment variable you can set.
```bash
export USE_HINT_TEXT=true # if you want to use hint text in the evaluation. Default to false. Ignore this if you are not sure.
export USE_INSTANCE_IMAGE=true # if you want to use instance-level docker images. Default to true
```
Let's say you'd like to run 10 instances using `llm.eval_gpt4_1106_preview` and CodeActAgent,
@@ -65,9 +68,11 @@ then your command would be:
./evaluation/benchmarks/swe_bench/scripts/run_infer.sh llm.eval_gpt4_1106_preview HEAD CodeActAgent 10
```
### Run Inference on `RemoteRuntime` (experimental)
### Running in parallel with RemoteRuntime
This is in limited beta. Contact Xingyao over slack if you want to try this out!
OpenHands Remote Runtime is currently in beta (read [here](https://runtime.all-hands.dev/) for more details), it allows you to run rollout in parallel in the cloud, so you don't need a powerful machine to run evaluation.
Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
```bash
./evaluation/benchmarks/swe_bench/scripts/run_infer.sh [model_config] [git-version] [agent] [eval_limit] [max_iter] [num_workers] [dataset] [dataset_split]
@@ -100,41 +105,14 @@ After running the inference, you will obtain a `output.jsonl` (by default it wil
## Evaluate Generated Patches
### Download Docker Images
**(Recommended for reproducibility)** If you have extra local space (e.g., 200GB), you can try pull the [instance-level docker images](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md#choosing-the-right-cache_level) we've prepared by running:
```bash
evaluation/benchmarks/swe_bench/scripts/docker/pull_all_eval_docker.sh instance
```
If you want to save disk space a bit (e.g., with ~50GB free disk space), while speeding up the image pre-build process, you can pull the environment-level docker images:
```bash
evaluation/benchmarks/swe_bench/scripts/docker/pull_all_eval_docker.sh env
```
If you want to evaluate on the full SWE-Bench test set:
```bash
evaluation/benchmarks/swe_bench/scripts/docker/pull_all_eval_docker.sh instance full
```
### Run evaluation
### Run evaluation with official SWE-Bench harness (Recommend if you have local disk space)
With `output.jsonl` file, you can run `eval_infer.sh` to evaluate generated patches, and produce a fine-grained report.
**This evaluation is performed using the official dockerized evaluation announced [here](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md).**
> If you want to evaluate existing results, you should first run this to clone existing outputs
>
>```bash
>git clone https://huggingface.co/spaces/OpenHands/evaluation evaluation/evaluation_outputs
>```
> [!NOTE]
> This process will automatically download docker images from SWE-Bench official docker hub, please make sure you have enough disk space!
NOTE, you should have already pulled the instance-level OR env-level docker images following [this section](#openhands-swe-bench-instance-level-docker-support).
Then you can run the following:
```bash
./evaluation/benchmarks/swe_bench/scripts/eval_infer.sh $YOUR_OUTPUT_JSONL [instance_id] [dataset_name] [split]
@@ -163,9 +141,10 @@ The final results will be saved to `evaluation/evaluation_outputs/outputs/swe_be
- `report.json`: a JSON file that contains keys like `"resolved_ids"` pointing to instance IDs that are resolved by the agent.
- `logs/`: a directory of test logs
### Run evaluation with `RemoteRuntime` (experimental)
### Run evaluation with `RemoteRuntime`
This is in limited beta. Contact Xingyao over slack if you want to try this out!
OpenHands Remote Runtime is currently in beta (read [here](https://runtime.all-hands.dev/) for more details), it allows you to run rollout in parallel in the cloud, so you don't need a powerful machine to run evaluation.
Fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply if you want to try this out!
```bash
./evaluation/benchmarks/swe_bench/scripts/eval_infer_remote.sh [output.jsonl filepath] [num_workers]
@@ -180,35 +159,3 @@ To clean-up all existing runtimes that you've already started, run:
```bash
ALLHANDS_API_KEY="YOUR-API-KEY" ./evaluation/utils/scripts/cleanup_remote_runtime.sh
```
## Visualize Results
First you need to clone `https://huggingface.co/spaces/OpenHands/evaluation` and add your own running results from openhands into the `outputs` of the cloned repo.
```bash
git clone https://huggingface.co/spaces/OpenHands/evaluation
```
**(optional) setup streamlit environment with conda**:
```bash
cd evaluation
conda create -n streamlit python=3.10
conda activate streamlit
pip install -r requirements.txt
```
**run the visualizer**:
Then, in a separate Python environment with `streamlit` library, you can run the following:
```bash
# Make sure you are inside the cloned `evaluation` repo
conda activate streamlit # if you follow the optional conda env setup above
streamlit run app.py --server.port 8501 --server.address 0.0.0.0
```
Then you can access the SWE-Bench trajectory visualizer at `localhost:8501`.
## Submit your evaluation results
You can start your own fork of [our huggingface evaluation outputs](https://huggingface.co/spaces/OpenHands/evaluation) and submit a PR of your evaluation results following the guide [here](https://huggingface.co/docs/hub/en/repositories-pull-requests-discussions#pull-requests-and-discussions).
+128
View File
@@ -0,0 +1,128 @@
<h1 align="center"> Training Software Engineering Agents and Verifiers with SWE-Gym </h1>
<p align="center">
<a href="https://www.jiayipan.com/" style="text-decoration: none;">Jiayi Pan<sup>*,1</sup></a>,
<a href="https://xwang.dev/" style="text-decoration: none;">Xingyao Wang<sup>*,2</sup></a>,
<a href="https://www.phontron.com/" style="text-decoration: none;">Graham Neubig<sup>3</sup></a>,
<a href="https://www.cs.toronto.edu/~ndjaitly/" style="text-decoration: none;">Navdeep Jaitly<sup>4</sup></a>,
<a href="https://blender.cs.illinois.edu/hengji.html" style="text-decoration: none;">Heng Ji<sup>2</sup></a>,
<a href="https://www.alanesuhr.com/" style="text-decoration: none;">Alane Suhr<sup>^,1</sup></a>,
<a href="https://dreasysnail.github.io/" style="text-decoration: none;">Yizhe Zhang<sup>^,4</sup></a>
</p>
<p align="center">
<sup>1</sup>UC Berkeley, <sup>2</sup>UIUC, <sup>3</sup>CMU, <sup>4</sup>Apple </br>
<sub><sup>*</sup>Equal contribution, <sup>^</sup>Equal supervision</sub>
</p>
<p align="center">
<a href="https://arxiv.org/abs/2412.21139">📃 Paper</a>
<a href="https://huggingface.co/SWE-Gym" >🤗 Data & Models</a>
</p>
We present **SWE-Gym**, the first environment for training real-world software engineering agents.
We use it to train strong LM agents that achieve state-of-the-art open results on SWE-Bench, with early, promising scaling characteristics as we increase training and inference-time compute.
<p align="center">
<img src="https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/teaser.jpg?raw=true" width="100%" alt="teaser">
</p>
---
# Run SWE-Gym with OpenHands
The process of running SWE-Gym is very similar to how you'd run SWE-Bench evaluation.
1. First, clone OpenHands repo `git clone https://github.com/All-Hands-AI/OpenHands.git`
2. Then setup the repo following [Development.md](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md)
3. Then you can simply serve your own model as an OpenAI compatible endpoint, put those info in config.toml. You can do this by following instruction [here](../../README.md#setup).
4. And then simply do the following to sample for 16x parallelism:
```bash
export ALLHANDS_API_KEY=ah-yourkey # You don't need to set this when running these in local docker container
./evaluation/benchmarks/swe_bench/scripts/rollout_swegym.sh llm.mymodel-temp05 'train-t05' 16
```
NOTE: SWE-Gym sampling with parallelism is currently only tested with AllHands RemoteRuntime (limited beta). Fill [this form](https://docs.google.com/forms/d/e/1FAIpQLSckVz_JFwg2_mOxNZjCtr7aoBFI2Mwdan3f75J_TrdMS1JV2g/viewform) to apply for access.
5. When `rollout_swegym.sh` finishes, you will get a file called `output.with_completions.jsonl.gz`. Then you can use [`./scripts/swegym/convert_data.ipynb`](./scripts/swegym/convert_data.ipynb) to convert them into SFT data format.
---
# More info about SWE-Gym
Progress in agents for software engineering has been limited by the lack of training environments that both include rigorous verification for reinforcement learning and cover the expansive tasks encountered in real-world repository-level engineering.
We introduce SWE-Gym: An Open Environment for Training Software Engineering Agents & Verifiers.
Our baselines achieve new open SOTA - 32%/26% on SWE-Bench Verified/Lite, with promising scaling trends.
![SWE-Gym Scaling](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/scaling.jpg?raw=true)
*SWE-Gym enables scalable improvements for software engineering agents at both training and inference time. Our current results is primarily bottlenecked by training and inference compute, rather than the size of our environment.*
## SWE-Gym Environment
We create SWE-Gym, the first environment for training SWE agents, with **2.4K real tasks from 11 Python repos** & a Lite split of 234 instances. SWE-Gym combines real-world Python tasks, repository context, executable environments, and test verification to train agents for solving software engineering problems.
![SWE-Gym Repo Distribution](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/swe-gym.jpg?raw=true)
## SWE-Gym trains LMs as agents
When fine-tuned on less than 500 agent-environment interaction trajectories sampled from it from GPT-4o and Claude 3.5 Sonnet, we achieve **+14%** absolute gains on SWE-Bench Verified with an 32B LM-powered OpenHands agent.
![OpenHands Performance diff before and after training](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/oh-agent.jpg?raw=true)
## SWE-Gym enables self-improvement
SWE-Gym is also effective across agent scaffolds. With rejection sampling fine-tuning and MoatlessTools scaffold, our 32B and 7B models achieve 20% and 10% respectively on SWE-Bench Lite through self-improvement.
<p align="center">
<img src="https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/ml-agent.jpg?raw=true" width="80%" alt="Moatless self-improvement">
</p>
## SWE-Gym enables inference-time scaling
SWE-Gym enables inference-time scaling through verifiers trained on agent trajectories.
These verifiers identify most promising solutions via best-of-n selection, together with our learned agents, they achieve 32%/26% on SWE-Bench Verified/Lite, a new open SoTA.
![Inference Time Scaling for Moatless Agent](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/inference-ml.jpg?raw=true)
*Inference Time Scaling for Moatless Agent*
![Inference Time Scaling for OpenHands Agent](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/inference-oh.jpg?raw=true)
*Inference Time Scaling for OpenHands Agent*
## Our baselines on SWE-Gym shows strong scaling trends
Lastly, our ablations reveal strong scaling trends - performance is now bottlenecked by train and inference compute, rather than the size of our dataset. Pushing and improving these scaling trends further is an exciting direction for future work.
![](https://github.com/SWE-Gym/SWE-Gym/blob/main/assets/images/scaling.jpg?raw=true)
## Reproducing Results
**The Dataset**
To access SWE-Gym dataset, checkout our huggingface hub page [SWE-Gym](https://huggingface.co/SWE-Gym)
The environment constants are currently saved at [SWE-Bench-Fork](https://github.com/SWE-Gym/SWE-Bench-Fork)
We also have pre-built docker images for each instance under [xingyaoww/sweb.eval.x86_64](https://hub.docker.com/search?q=xingyaoww%2Fsweb.eval.x86_64.) prefix at docker hub.
## 📚 Citation
```bibtex
@misc{pan2024trainingsoftwareengineeringagents,
title={Training Software Engineering Agents and Verifiers with SWE-Gym},
author={Jiayi Pan and Xingyao Wang and Graham Neubig and Navdeep Jaitly and Heng Ji and Alane Suhr and Yizhe Zhang},
year={2024},
eprint={2412.21139},
archivePrefix={arXiv},
primaryClass={cs.SE},
url={https://arxiv.org/abs/2412.21139},
}
```
+75 -17
View File
@@ -1,22 +1,14 @@
import copy
import json
import os
import subprocess
import tempfile
import time
from dataclasses import dataclass
from functools import partial
from typing import Callable
import pandas as pd
from swebench.harness.grading import get_eval_report
from swebench.harness.run_evaluation import (
APPLY_PATCH_FAIL,
APPLY_PATCH_PASS,
)
from swebench.harness.test_spec.test_spec import (
SWEbenchInstance,
TestSpec,
make_test_spec,
)
from swebench.harness.utils import load_swebench_dataset
from tqdm import tqdm
from evaluation.benchmarks.swe_bench.resource.mapping import (
@@ -102,12 +94,22 @@ def get_config(metadata: EvalMetadata, instance: pd.Series) -> AppConfig:
return config
@dataclass
class ConditionalImports:
"""We instantiate the values in this dataclass differently if we're evaluating SWE-bench or SWE-Gym."""
get_eval_report: Callable
APPLY_PATCH_FAIL: str
APPLY_PATCH_PASS: str
def process_instance(
instance: pd.Series,
metadata: EvalMetadata,
reset_logger: bool = True,
log_dir: str | None = None,
runtime_failure_count: int = 0,
conditional_imports: ConditionalImports | None = None,
) -> EvalOutput:
"""
Evaluate agent performance on a SWE-bench problem instance.
@@ -119,9 +121,18 @@ def process_instance(
log_dir (str | None, default=None): Path to directory where log files will be written. Must
be provided if `reset_logger` is set.
conditional_imports: A dataclass containing values that are imported differently based on
whether we're evaluating SWE-bench or SWE-Gym.
Raises:
AssertionError: if the `reset_logger` flag is set without a provided log directory.
AssertionError: if `conditional_imports` is not provided.
"""
assert (
conditional_imports is not None
), 'conditional_imports must be provided to run process_instance using multiprocessing'
# Setup the logger properly, so you can run multi-processing to parallelize the evaluation
if reset_logger:
assert (
@@ -135,7 +146,7 @@ def process_instance(
config = get_config(metadata, instance)
instance_id = instance.instance_id
model_patch = instance['model_patch']
test_spec: TestSpec = instance['test_spec']
test_spec = instance['test_spec']
logger.info(f'Starting evaluation for instance {instance_id}.')
if 'test_result' not in instance.keys():
@@ -165,6 +176,11 @@ def process_instance(
logger.warning(
f'This is the {runtime_failure_count + 1}th attempt for instance {instance.instance_id}, setting resource factor to {config.sandbox.remote_runtime_resource_factor}'
)
metadata = copy.deepcopy(metadata)
metadata.details['runtime_failure_count'] = runtime_failure_count
metadata.details['remote_runtime_resource_factor'] = (
config.sandbox.remote_runtime_resource_factor
)
try:
runtime = create_runtime(config)
@@ -207,7 +223,9 @@ def process_instance(
instance['test_result']['apply_patch_output'] = apply_patch_output
if 'APPLY_PATCH_FAIL' in apply_patch_output:
logger.info(f'[{instance_id}] {APPLY_PATCH_FAIL}:\n{apply_patch_output}')
logger.info(
f'[{instance_id}] {conditional_imports.APPLY_PATCH_FAIL}:\n{apply_patch_output}'
)
instance['test_result']['report']['failed_apply_patch'] = True
return EvalOutput(
@@ -216,7 +234,9 @@ def process_instance(
metadata=metadata,
)
elif 'APPLY_PATCH_PASS' in apply_patch_output:
logger.info(f'[{instance_id}] {APPLY_PATCH_PASS}:\n{apply_patch_output}')
logger.info(
f'[{instance_id}] {conditional_imports.APPLY_PATCH_PASS}:\n{apply_patch_output}'
)
# Run eval script in background and save output to log file
log_file = '/tmp/eval_output.log'
@@ -282,14 +302,20 @@ def process_instance(
with open(test_output_path, 'w') as f:
f.write(test_output)
try:
_report = get_eval_report(
extra_kwargs = {}
if 'SWE-Gym' in metadata.dataset:
# SWE-Gym uses a different version of the package, hence a different eval report argument
extra_kwargs['log_path'] = test_output_path
else:
extra_kwargs['test_log_path'] = test_output_path
_report = conditional_imports.get_eval_report(
test_spec=test_spec,
prediction={
'model_patch': model_patch,
'instance_id': instance_id,
},
test_log_path=test_output_path,
include_tests_status=True,
**extra_kwargs,
)
report = _report[instance_id]
logger.info(
@@ -348,6 +374,29 @@ if __name__ == '__main__':
)
args, _ = parser.parse_known_args()
if 'SWE-Gym' in args.dataset:
from swegym.harness.grading import get_eval_report
from swegym.harness.run_evaluation import (
APPLY_PATCH_FAIL,
APPLY_PATCH_PASS,
)
from swegym.harness.test_spec import (
SWEbenchInstance,
make_test_spec,
)
from swegym.harness.utils import load_swebench_dataset
else: # Newer version of SWE-Bench have different import paths
from swebench.harness.grading import get_eval_report
from swebench.harness.run_evaluation import (
APPLY_PATCH_FAIL,
APPLY_PATCH_PASS,
)
from swebench.harness.test_spec.test_spec import (
SWEbenchInstance,
make_test_spec,
)
from swebench.harness.utils import load_swebench_dataset
# Load SWE-Bench dataset
full_dataset: list[SWEbenchInstance] = load_swebench_dataset(
args.dataset, args.split
@@ -426,12 +475,21 @@ if __name__ == '__main__':
.decode('utf-8')
.strip(), # Current commit
dataset=args.dataset, # Dataset name from args
details={},
)
# The evaluation harness constrains the signature of `process_instance_func` but we need to
# pass extra information. Build a new function object to avoid issues with multiprocessing.
process_instance_func = partial(
process_instance, log_dir=output_file.replace('.jsonl', '.logs')
process_instance,
log_dir=output_file.replace('.jsonl', '.logs'),
# We have to explicitly pass these imports to the process_instance function, otherwise
# they won't be available in the multiprocessing context.
conditional_imports=ConditionalImports(
get_eval_report=get_eval_report,
APPLY_PATCH_FAIL=APPLY_PATCH_FAIL,
APPLY_PATCH_PASS=APPLY_PATCH_PASS,
),
)
run_evaluation(
File diff suppressed because it is too large Load Diff
@@ -23,7 +23,7 @@ def get_resource_mapping(dataset_name: str) -> dict[str, float]:
if dataset_name not in _global_resource_mapping:
file_path = os.path.join(CUR_DIR, f'{dataset_name}.json')
if not os.path.exists(file_path):
logger.warning(f'Resource mapping for {dataset_name} not found.')
logger.info(f'Resource mapping for {dataset_name} not found.')
return None
with open(file_path, 'r') as f:
+148 -112
View File
@@ -1,4 +1,5 @@
import asyncio
import copy
import json
import os
import tempfile
@@ -44,7 +45,6 @@ from openhands.utils.async_utils import call_async_from_sync
from openhands.utils.shutdown_listener import sleep_if_should_continue
USE_HINT_TEXT = os.environ.get('USE_HINT_TEXT', 'false').lower() == 'true'
USE_INSTANCE_IMAGE = os.environ.get('USE_INSTANCE_IMAGE', 'true').lower() == 'true'
RUN_WITH_BROWSING = os.environ.get('RUN_WITH_BROWSING', 'false').lower() == 'true'
@@ -59,85 +59,108 @@ def _get_swebench_workspace_dir_name(instance: pd.Series) -> str:
def get_instruction(instance: pd.Series, metadata: EvalMetadata):
workspace_dir_name = _get_swebench_workspace_dir_name(instance)
# Instruction based on Anthropic's official trajectory
# https://github.com/eschluntz/swe-bench-experiments/tree/main/evaluation/verified/20241022_tools_claude-3-5-sonnet-updated/trajs
instruction = (
'<uploaded_files>\n'
f'/workspace/{workspace_dir_name}\n'
'</uploaded_files>\n'
f"I've uploaded a python code repository in the directory {workspace_dir_name}. Consider the following issue description:\n\n"
f'<issue_description>\n'
f'{instance.problem_statement}\n'
'</issue_description>\n\n'
'Can you help me implement the necessary changes to the repository so that the requirements specified in the <issue_description> are met?\n'
"I've already taken care of all changes to any of the test files described in the <issue_description>. This means you DON'T have to modify the testing logic or any of the tests in any way!\n"
"Also the development Python environment is already set up for you (i.e., all dependencies already installed), so you don't need to install other packages.\n"
'Your task is to make the minimal changes to non-test files in the /workspace directory to ensure the <issue_description> is satisfied.\n'
'Follow these steps to resolve the issue:\n'
'1. As a first step, it might be a good idea to explore the repo to familiarize yourself with its structure.\n'
'2. Create a script to reproduce the error and execute it with `python <filename.py>` using the BashTool, to confirm the error\n'
'3. Edit the sourcecode of the repo to resolve the issue\n'
'4. Rerun your reproduce script and confirm that the error is fixed!\n'
'5. Think about edgecases, add comprehensive tests for them in your reproduce script, and run them to make sure your fix handles them as well\n'
f'6. Once you are done with the initial implementation, please carefully re-read the problem description and check the difference between the current code and the base commit {instance["base_commit"]}. Do you think that the issue has been completely and comprehensively solved? Write tests to check the correctness of the solution, specifically focusing on tests that may point out any remaining problems that are not yet solved. Run all of the tests in the repo and check if any of them fail, and if they do fix the code. Repeat this process of carefully reading the problem description and current implementation, testing, and fixing any problems until you are confident that the current implementation is correct. Find and run any tests in the repo that are related to:\n'
' - The issue you are fixing\n'
' - The files you modified\n'
' - The functions you changed\n'
' Make sure all these tests pass with your changes.\n'
"Your thinking should be thorough and so it's fine if it's very long.\n"
)
instruction = f"""
<uploaded_files>
/workspace/{workspace_dir_name}
</uploaded_files>
I've uploaded a python code repository in the directory {workspace_dir_name}. Consider the following issue description:
<issue_description>
{instance.problem_statement}
</issue_description>
Can you help me implement the necessary changes to the repository so that the requirements specified in the <issue_description> are met?
I've already taken care of all changes to any of the test files described in the <issue_description>. This means you DON'T have to modify the testing logic or any of the tests in any way!
Also the development Python environment is already set up for you (i.e., all dependencies already installed), so you don't need to install other packages.
Your task is to make the minimal changes to non-test files in the /workspace/{workspace_dir_name} directory to ensure the <issue_description> is satisfied.
Follow these steps to resolve the issue:
1. EXPLORATION: First, thoroughly explore the repository structure using tools like `find` and `grep`.
- Identify all files mentioned in the problem statement
- Locate where the issue occurs in the codebase
- Understand the surrounding context and dependencies
- Use `grep` to search for relevant functions, classes, or error messages
2. ANALYSIS: Based on your exploration, think carefully about the problem and propose 2-5 possible approaches to fix the issue.
- Analyze the root cause of the problem
- Consider trade-offs between different solutions
- Select the most promising approach and explain your reasoning
3. TEST CREATION: Before implementing any fix, create a script to reproduce and verify the issue.
- Look at existing test files in the repository to understand the test format/structure
- Create a minimal reproduction script that demonstrates the issue
- Run your script to confirm the error exists
4. IMPLEMENTATION: Edit the source code to implement your chosen solution.
- Make minimal, focused changes to fix the issue
5. VERIFICATION: Test your implementation thoroughly.
- Run your reproduction script to verify the fix works
- Add edge cases to your test script to ensure comprehensive coverage
- Run existing tests related to the modified code to ensure you haven't broken anything
6. FINAL REVIEW: Carefully re-read the problem description and compare your changes with the base commit {instance["base_commit"]}.
- Ensure you've fully addressed all requirements
- Run any tests in the repository related to:
* The issue you are fixing
* The files you modified
* The functions you changed
- If any tests fail, revise your implementation until all tests pass
Be thorough in your exploration, testing, and reasoning. It's fine if your thinking process is lengthy - quality and completeness are more important than brevity.
"""
if RUN_WITH_BROWSING:
instruction += (
'<IMPORTANT!>\n'
'You SHOULD NEVER attempt to browse the web. '
'</IMPORTANT!>\n'
)
instruction += """
<IMPORTANT!>
You SHOULD NEVER attempt to browse the web.
</IMPORTANT!>
"""
return instruction
# TODO: migrate all swe-bench docker to ghcr.io/openhands
DOCKER_IMAGE_PREFIX = os.environ.get('EVAL_DOCKER_IMAGE_PREFIX', 'docker.io/xingyaoww/')
logger.info(f'Using docker image prefix: {DOCKER_IMAGE_PREFIX}')
DEFAULT_DOCKER_IMAGE_PREFIX = os.environ.get('EVAL_DOCKER_IMAGE_PREFIX', 'docker.io/xingyaoww/')
logger.info(f'Default docker image prefix: {DEFAULT_DOCKER_IMAGE_PREFIX}')
def get_instance_docker_image(instance_id: str, official_image: bool = False) -> str:
if official_image:
# Official SWE-Bench image
# swebench/sweb.eval.x86_64.django_1776_django-11333:v1
docker_image_prefix = 'docker.io/swebench/'
repo, name = instance_id.split('__')
image_name = f'sweb.eval.x86_64.{repo}_1776_{name}:latest'
logger.warning(f'Using official SWE-Bench image: {image_name}')
else:
# OpenHands version of the image
docker_image_prefix = DEFAULT_DOCKER_IMAGE_PREFIX
image_name = 'sweb.eval.x86_64.' + instance_id
image_name = image_name.replace(
'__', '_s_'
) # to comply with docker image naming convention
return (DOCKER_IMAGE_PREFIX.rstrip('/') + '/' + image_name).lower()
return (docker_image_prefix.rstrip('/') + '/' + image_name).lower()
def get_config(
instance: pd.Series,
metadata: EvalMetadata,
) -> AppConfig:
SWE_BENCH_CONTAINER_IMAGE = 'ghcr.io/opendevin/eval-swe-bench:full-v1.2.1'
if USE_INSTANCE_IMAGE:
# We use a different instance image for the each instance of swe-bench eval
use_official_image = bool(
'verified' in metadata.dataset.lower() or 'lite' in metadata.dataset.lower()
)
base_container_image = get_instance_docker_image(
instance['instance_id'], use_official_image
)
logger.info(
f'Using instance container image: {base_container_image}. '
f'Please make sure this image exists. '
f'Submit an issue on https://github.com/All-Hands-AI/OpenHands if you run into any issues.'
)
else:
base_container_image = SWE_BENCH_CONTAINER_IMAGE
logger.info(f'Using swe-bench container image: {base_container_image}')
# We use a different instance image for the each instance of swe-bench eval
use_official_image = bool(
('verified' in metadata.dataset.lower() or 'lite' in metadata.dataset.lower())
and 'swe-gym' not in metadata.dataset.lower()
)
base_container_image = get_instance_docker_image(
instance['instance_id'], use_official_image
)
logger.info(
f'Using instance container image: {base_container_image}. '
f'Please make sure this image exists. '
f'Submit an issue on https://github.com/All-Hands-AI/OpenHands if you run into any issues.'
)
sandbox_config = get_default_sandbox_config_for_eval()
sandbox_config.base_container_image = base_container_image
@@ -209,75 +232,65 @@ def initialize_runtime(
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(obs.exit_code == 0, f'Failed to export USER: {str(obs)}')
if USE_INSTANCE_IMAGE:
# inject the init script
script_dir = os.path.dirname(__file__)
# inject the init script
script_dir = os.path.dirname(__file__)
# inject the instance info
action = CmdRunAction(command='mkdir -p /swe_util/eval_data/instances')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
obs.exit_code == 0,
f'Failed to create /swe_util/eval_data/instances: {str(obs)}',
)
# inject the instance info
action = CmdRunAction(command='mkdir -p /swe_util/eval_data/instances')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
obs.exit_code == 0,
f'Failed to create /swe_util/eval_data/instances: {str(obs)}',
)
swe_instance_json_name = 'swe-bench-instance.json'
with tempfile.TemporaryDirectory() as temp_dir:
# Construct the full path for the desired file name within the temporary directory
temp_file_path = os.path.join(temp_dir, swe_instance_json_name)
# Write to the file with the desired name within the temporary directory
with open(temp_file_path, 'w') as f:
if not isinstance(instance, dict):
json.dump([instance.to_dict()], f)
else:
json.dump([instance], f)
swe_instance_json_name = 'swe-bench-instance.json'
with tempfile.TemporaryDirectory() as temp_dir:
# Construct the full path for the desired file name within the temporary directory
temp_file_path = os.path.join(temp_dir, swe_instance_json_name)
# Write to the file with the desired name within the temporary directory
with open(temp_file_path, 'w') as f:
if not isinstance(instance, dict):
json.dump([instance.to_dict()], f)
else:
json.dump([instance], f)
# Copy the file to the desired location
runtime.copy_to(temp_file_path, '/swe_util/eval_data/instances/')
# Copy the file to the desired location
runtime.copy_to(temp_file_path, '/swe_util/eval_data/instances/')
# inject the instance swe entry
runtime.copy_to(
str(os.path.join(script_dir, 'scripts/setup/instance_swe_entry.sh')),
'/swe_util/',
)
action = CmdRunAction(command='cat ~/.bashrc')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(obs.exit_code == 0, f'Failed to cat ~/.bashrc: {str(obs)}')
action = CmdRunAction(command='source ~/.bashrc')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
if isinstance(obs, ErrorObservation):
logger.error(f'Failed to source ~/.bashrc: {str(obs)}')
assert_and_raise(obs.exit_code == 0, f'Failed to source ~/.bashrc: {str(obs)}')
action = CmdRunAction(command='cat ~/.bashrc')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(obs.exit_code == 0, f'Failed to cat ~/.bashrc: {str(obs)}')
action = CmdRunAction(command='source /swe_util/instance_swe_entry.sh')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
obs.exit_code == 0,
f'Failed to source /swe_util/instance_swe_entry.sh: {str(obs)}',
)
else:
action = CmdRunAction(command='source /swe_util/swe_entry.sh')
action.set_hard_timeout(1800)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
obs.exit_code == 0,
f'Failed to source /swe_util/swe_entry.sh: {str(obs)}',
)
action = CmdRunAction(command='source ~/.bashrc')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
if isinstance(obs, ErrorObservation):
logger.error(f'Failed to source ~/.bashrc: {str(obs)}')
assert_and_raise(obs.exit_code == 0, f'Failed to source ~/.bashrc: {str(obs)}')
action = CmdRunAction(command='source /swe_util/instance_swe_entry.sh')
action.set_hard_timeout(600)
logger.info(action, extra={'msg_type': 'ACTION'})
obs = runtime.run_action(action)
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert_and_raise(
obs.exit_code == 0,
f'Failed to source /swe_util/instance_swe_entry.sh: {str(obs)}',
)
action = CmdRunAction(command=f'cd /workspace/{workspace_dir_name}')
action.set_hard_timeout(600)
@@ -464,6 +477,13 @@ def process_instance(
logger.warning(
f'This is the {runtime_failure_count + 1}th attempt for instance {instance.instance_id}, setting resource factor to {config.sandbox.remote_runtime_resource_factor}'
)
metadata = copy.deepcopy(metadata)
metadata.details['runtime_failure_count'] = runtime_failure_count
metadata.details['remote_runtime_resource_factor'] = (
config.sandbox.remote_runtime_resource_factor
)
runtime = create_runtime(config)
call_async_from_sync(runtime.connect)
@@ -572,6 +592,22 @@ if __name__ == '__main__':
logger.info(
f'Loaded dataset {args.dataset} with split {args.split}: {len(swe_bench_tests)} tasks'
)
if 'SWE-Gym' in args.dataset:
with open(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'split',
'swegym_verified_instances.json',
),
'r',
) as f:
swegym_verified_instances = json.load(f)
swe_bench_tests = swe_bench_tests[
swe_bench_tests['instance_id'].isin(swegym_verified_instances)
]
logger.info(
f'{len(swe_bench_tests)} tasks left after filtering for SWE-Gym verified instances'
)
llm_config = None
if args.llm_config:
@@ -615,6 +651,6 @@ if __name__ == '__main__':
output_file,
args.eval_num_workers,
process_instance,
timeout_seconds=120 * 60, # 2 hour PER instance should be more than enough
timeout_seconds=8 * 60 * 60, # 8 hour PER instance should be more than enough
max_retries=5,
)
@@ -24,7 +24,7 @@ def load_completions(output_dir: str, instance_id: str):
# create messages
messages = result['messages']
messages.append(result['response']['choices'][0]['message'])
tools = result['kwargs']['tools']
tools = result['kwargs'].get('tools', [])
return {
'messages': messages,
'tools': tools,
@@ -75,7 +75,7 @@ def load_completions(instance_id: str):
# create messages
messages = result['messages']
messages.append(result['response']['choices'][0]['message'])
tools = result['kwargs']['tools']
tools = result['kwargs'].get('tools', None)
return {
'messages': messages,
'tools': tools,
@@ -9,7 +9,7 @@ parser.add_argument(
'--dataset_name',
type=str,
help='Name of the dataset to download',
default='princeton-nlp/SWE-bench_Lite',
default='princeton-nlp/SWE-bench_Verified',
)
parser.add_argument('--split', type=str, help='Split to download', default='test')
args = parser.parse_args()
@@ -20,7 +20,12 @@ print(
f'Downloading gold patches from {args.dataset_name} (split: {args.split}) to {output_filepath}'
)
patches = [
{'instance_id': row['instance_id'], 'model_patch': row['patch']} for row in dataset
{
'instance_id': row['instance_id'],
'model_patch': row['patch'],
'model_name_or_path': 'gold',
}
for row in dataset
]
print(f'{len(patches)} gold patches loaded')
pd.DataFrame(patches).to_json(output_filepath, lines=True, orient='records')
+132
View File
@@ -0,0 +1,132 @@
#!/bin/bash
# NOTE: this script is for rolling out the SWE-Gym dataset for **TRAINING**
# For more information, please refer to
# 1. the Github Repo: https://github.com/SWE-Gym/SWE-Gym
# 2. the paper: https://arxiv.org/abs/2412.21139
MODEL=$1 # eg your llm config name in config.toml (eg: "llm.claude-3-5-sonnet-20241022-t05")
EXP_NAME=$2 # "train-t05"
N_WORKERS=${3:-64}
N_RUNS=${4:-1}
export EXP_NAME=$EXP_NAME
# use 2x resources for rollout since some codebases are pretty resource-intensive
export DEFAULT_RUNTIME_RESOURCE_FACTOR=2
echo "MODEL: $MODEL"
echo "EXP_NAME: $EXP_NAME"
DATASET="SWE-Gym/SWE-Gym" # change this to the "/SWE-Gym-Lite" if you want to rollout the lite subset
SPLIT="train"
if [ -z "$ALLHANDS_API_KEY" ]; then
echo "ALLHANDS_API_KEY is not set. Will rollout and evaluate locally using Docker. WARNING: A large value of N_WORKERS will result in a large number of Docker containers being spun up and may crash your machine."
export RUNTIME=docker
else
echo "ALLHANDS_API_KEY is set. Continuing rollout and evaluation with remote runtime..."
export RUNTIME=remote
export SANDBOX_REMOTE_RUNTIME_API_URL="https://runtime.eval.all-hands.dev"
export EVAL_DOCKER_IMAGE_PREFIX="us-central1-docker.pkg.dev/evaluation-092424/swe-bench-images"
fi
EVAL_LIMIT=3000
MAX_ITER=100
# ===== Run inference =====
source "evaluation/utils/version_control.sh"
get_openhands_version
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
echo "MODEL_CONFIG: $MODEL_CONFIG"
echo "DATASET: $DATASET"
echo "SPLIT: $SPLIT"
# Default to NOT use Hint
export USE_INSTANCE_IMAGE=true
export USE_HINT_TEXT=false
export RUN_WITH_BROWSING=false
echo "USE_HINT_TEXT: $USE_HINT_TEXT"
EVAL_NOTE="$OPENHANDS_VERSION-no-hint-$EXP_NAME"
function run_eval() {
local eval_note=$1
COMMAND="poetry run python evaluation/benchmarks/swe_bench/run_infer.py \
--agent-cls CodeActAgent \
--llm-config $MODEL \
--max-iterations $MAX_ITER \
--eval-num-workers $N_WORKERS \
--eval-note $eval_note \
--dataset $DATASET \
--split $SPLIT"
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
# Run the command
eval $COMMAND
}
for run_idx in $(seq 1 $N_RUNS); do
while true; do
echo "### Running inference... ###"
unset SANDBOX_ENV_GITHUB_TOKEN # prevent the agent from using the github token to push
current_eval_note="$EVAL_NOTE-run_$run_idx"
echo "EVAL_NOTE: $current_eval_note"
INFER_OUTPUT=$(run_eval $current_eval_note)
INFER_STATUS=$? # Capture the exit status of run_infer.sh
echo "INFER_STATUS: $INFER_STATUS"
echo "### Cleaning up remote runtime... ###"
./evaluation/utils/scripts/cleanup_remote_runtime.sh
if [ $INFER_STATUS -eq 0 ]; then
echo "### Inference completed successfully. ###"
break
else
echo "### Inference failed with exit code $INFER_STATUS. Retrying... ###"
fi
done
# Extract the output directory using the special delimiters
OUTPUT_FILE=$(echo "$INFER_OUTPUT" | grep -o '### OUTPUT FILE:.* ###' | sed 's/### OUTPUT FILE: \(.*\) ###/\1/')
echo "Got OUTPUT_FILE: $OUTPUT_FILE"
while true; do
echo "### Evaluating on $OUTPUT_FILE ... ###"
COMMAND="poetry run python evaluation/benchmarks/swe_bench/eval_infer.py \
--eval-num-workers $((N_WORKERS * 2)) \
--input-file $OUTPUT_FILE \
--dataset $DATASET \
--split $SPLIT"
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
echo "Running command: $COMMAND"
# Run the command
eval $COMMAND
EVAL_STATUS=$?
if [ $EVAL_STATUS -eq 0 ]; then
echo "### Evaluation completed successfully. ###"
break
else
echo "### Evaluation failed with exit code $EVAL_STATUS. Retrying... ###"
fi
./evaluation/utils/scripts/cleanup_remote_runtime.sh
done
# update the output with evaluation results
echo "### Updating the output with evaluation results... ###"
poetry run python evaluation/benchmarks/swe_bench/scripts/eval/update_output_with_eval.py $OUTPUT_FILE
echo "### Combining the final completions... ###"
poetry run python evaluation/benchmarks/swe_bench/scripts/eval/combine_final_completions.py $OUTPUT_FILE
echo "### DONE for run $run_idx! ###"
echo "You can find the final output at $(dirname $OUTPUT_FILE)/$FINAL_OUTPUT_FILE"
done
@@ -29,11 +29,6 @@ if [ -z "$MAX_ITER" ]; then
MAX_ITER=100
fi
if [ -z "$USE_INSTANCE_IMAGE" ]; then
echo "USE_INSTANCE_IMAGE not specified, use default true"
USE_INSTANCE_IMAGE=true
fi
if [ -z "$RUN_WITH_BROWSING" ]; then
echo "RUN_WITH_BROWSING not specified, use default false"
RUN_WITH_BROWSING=false
@@ -50,8 +45,6 @@ if [ -z "$SPLIT" ]; then
SPLIT="test"
fi
export USE_INSTANCE_IMAGE=$USE_INSTANCE_IMAGE
echo "USE_INSTANCE_IMAGE: $USE_INSTANCE_IMAGE"
export RUN_WITH_BROWSING=$RUN_WITH_BROWSING
echo "RUN_WITH_BROWSING: $RUN_WITH_BROWSING"
@@ -0,0 +1,287 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"import pandas as pd\n",
"from tqdm import tqdm\n",
"\n",
"tqdm.pandas()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 1. Load raw data and convert to training data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import gzip\n",
"import json\n",
"\n",
"from tqdm import tqdm\n",
"\n",
"FILE_PATHS = [\n",
" 'YOURPATH-no-hint-train-t05-run_1/output.with_completions.jsonl.gz',\n",
" 'YOURPATH-no-hint-train-t05-run_2/output.with_completions.jsonl.gz',\n",
"]\n",
"\n",
"# More memory efficient for large files\n",
"# Initialize lists to store the data\n",
"data = []\n",
"\n",
"\n",
"# Read file line by line\n",
"for FILE_PATH in FILE_PATHS:\n",
" with gzip.open(FILE_PATH, 'rb') as f: # Use 'rb' for gzipped files\n",
" for i, line in tqdm(\n",
" enumerate(f), desc=f\"Processing {FILE_PATH.split('/')[-1]}\"\n",
" ):\n",
" # Parse only the fields we need\n",
" raw_data = json.loads(line)\n",
" data.append(\n",
" {\n",
" 'resolved': raw_data['report']['resolved'],\n",
" 'messages': raw_data['raw_completions']['messages']\n",
" if raw_data['raw_completions'] is not None\n",
" else None,\n",
" 'git_patch': raw_data['test_result'].get('git_patch', ''),\n",
" 'tools': raw_data['raw_completions']['tools']\n",
" if raw_data['raw_completions'] is not None\n",
" and 'tools' in raw_data['raw_completions']\n",
" else None,\n",
" }\n",
" )\n",
"\n",
"# Convert to DataFrame after collecting all data\n",
"df = pd.DataFrame(data)\n",
"print(f'#total amount of data={len(df)}')\n",
"df = df[~df['messages'].isna()]\n",
"print(f'#total amount of data after removing nan={len(df)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Filter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def _contains_multiple_tool_calls(messages: list[dict]) -> bool:\n",
" return any(\n",
" message.get('tool_calls') and len(message['tool_calls']) > 1\n",
" for message in messages\n",
" )\n",
"\n",
"\n",
"df['contains_multiple_tool_calls'] = df['messages'].apply(_contains_multiple_tool_calls)\n",
"display(df.groupby(['contains_multiple_tool_calls'])['resolved'].sum())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import copy\n",
"\n",
"# Convert function calling messages to non-function calling messages\n",
"from openhands.llm.fn_call_converter import (\n",
" FunctionCallConversionError,\n",
" convert_fncall_messages_to_non_fncall_messages,\n",
" convert_from_multiple_tool_calls_to_single_tool_call_messages,\n",
")\n",
"\n",
"total_failed = 0\n",
"\n",
"\n",
"def _convert_messages(messages: list[dict], tools: list[dict]) -> list[dict]:\n",
" global total_failed\n",
" message_copy = copy.deepcopy(messages)\n",
" for message in message_copy:\n",
" if message['content'] is None:\n",
" message['content'] = ''\n",
" try:\n",
" return convert_fncall_messages_to_non_fncall_messages(\n",
" message_copy, tools, add_in_context_learning_example=False\n",
" )\n",
" except FunctionCallConversionError:\n",
" total_failed += 1\n",
" # print(f'Failed to convert messages: {messages}\\nTools: {tools}')\n",
" # traceback.print_exc()\n",
" return None\n",
"\n",
"\n",
"df['converted_messages'] = df.apply(\n",
" lambda row: convert_from_multiple_tool_calls_to_single_tool_call_messages(\n",
" row['messages'], ignore_final_tool_result=True\n",
" ),\n",
" axis=1,\n",
")\n",
"df['nonfncall_messages'] = df.apply(\n",
" lambda row: _convert_messages(row['converted_messages'], row['tools']), axis=1\n",
")\n",
"print('total nan', df['nonfncall_messages'].isna().sum())\n",
"df = df[~df['nonfncall_messages'].isna()]\n",
"print(f'Total failed: {total_failed}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tokenization"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pandarallel import pandarallel\n",
"from transformers import AutoTokenizer\n",
"\n",
"os.environ['TOKENIZERS_PARALLELISM'] = 'false'\n",
"pandarallel.initialize(progress_bar=True, verbose=1, nb_workers=16)\n",
"tokenizer = AutoTokenizer.from_pretrained('Qwen/Qwen2.5-7B-Instruct')\n",
"df['n_tokens'] = df['rm_conv'].parallel_apply(\n",
" lambda x: len(tokenizer.apply_chat_template(x))\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(f'BEFORE: #total={len(df)}')\n",
"df_selected = df[df['n_tokens'] < 131072]\n",
"print(f'AFTER(truncated to 128k): #total={len(df_selected)}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_selected['n_tokens'].describe()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ecdf of n_tokens\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"\n",
"display(df.groupby(['resolved'])['n_tokens'].describe())\n",
"sns.ecdfplot(x='n_tokens', data=df, hue='resolved')\n",
"plt.show()\n",
"\n",
"print(f'#total={len(df)}')\n",
"df_selected = df[df['n_tokens'] < 131072]\n",
"print(f'#selected={len(df_selected)}')\n",
"display(df_selected.groupby(['resolved'])['n_tokens'].describe())\n",
"sns.ecdfplot(x='n_tokens', data=df_selected, hue='resolved')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_selected[~df_selected['resolved']]['n_tokens'].describe()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_selected['resolved'].value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_selected.groupby(['resolved'])['n_tokens'].describe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Save Resolved Messages for SFT"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_selected[df_selected['resolved']][['nonfncall_messages']].rename(\n",
" columns={'nonfncall_messages': 'messages'}\n",
").to_json(\n",
" os.path.join(\n",
" 'YOUR_OUTPUT_FOLDER',\n",
" f'policy_traj_128k_swegym_{df_selected[\"resolved\"].value_counts()[True]}i.jsonl',\n",
" ),\n",
" lines=True,\n",
" orient='records',\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "openhands-ai-CPy6G0pU-py3.12",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
File diff suppressed because it is too large Load Diff
@@ -34,7 +34,6 @@ from openhands.utils.async_utils import call_async_from_sync
FAKE_RESPONSES = {
'CodeActAgent': fake_user_response,
'DelegatorAgent': fake_user_response,
'VisualBrowsingAgent': fake_user_response,
}
@@ -4,8 +4,10 @@ import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, test, vi } from "vitest";
import OpenHands from "#/api/open-hands";
import { PaymentForm } from "#/components/features/payment/payment-form";
import * as featureFlags from "#/utils/feature-flags";
describe("PaymentForm", () => {
const billingSettingsSpy = vi.spyOn(featureFlags, "BILLING_SETTINGS");
const getBalanceSpy = vi.spyOn(OpenHands, "getBalance");
const createCheckoutSessionSpy = vi.spyOn(OpenHands, "createCheckoutSession");
const getConfigSpy = vi.spyOn(OpenHands, "getConfig");
@@ -26,6 +28,7 @@ describe("PaymentForm", () => {
GITHUB_CLIENT_ID: "123",
POSTHOG_CLIENT_KEY: "456",
});
billingSettingsSpy.mockReturnValue(true);
});
afterEach(() => {
+12 -17
View File
@@ -2,11 +2,13 @@ import { createRoutesStub } from "react-router";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import { renderWithProviders } from "test-utils";
import { screen, waitFor } from "@testing-library/react";
import toast from "react-hot-toast";
import App from "#/routes/_oh.app/route";
import OpenHands from "#/api/open-hands";
import * as CustomToast from "#/utils/custom-toast-handlers";
describe("App", () => {
const errorToastSpy = vi.spyOn(CustomToast, "displayErrorToast");
const RouteStub = createRoutesStub([
{ Component: App, path: "/conversation/:conversationId" },
]);
@@ -34,26 +36,19 @@ describe("App", () => {
await screen.findByTestId("app-route");
});
it(
"should call endSession if the user does not have permission to view conversation",
async () => {
const errorToastSpy = vi.spyOn(toast, "error");
const getConversationSpy = vi.spyOn(OpenHands, "getConversation");
it("should call endSession if the user does not have permission to view conversation", async () => {
const getConversationSpy = vi.spyOn(OpenHands, "getConversation");
getConversationSpy.mockResolvedValue(null);
renderWithProviders(
<RouteStub initialEntries={["/conversation/9999"]} />,
);
getConversationSpy.mockResolvedValue(null);
renderWithProviders(<RouteStub initialEntries={["/conversation/9999"]} />);
await waitFor(() => {
expect(endSessionMock).toHaveBeenCalledOnce();
expect(errorToastSpy).toHaveBeenCalledOnce();
});
},
);
await waitFor(() => {
expect(endSessionMock).toHaveBeenCalledOnce();
expect(errorToastSpy).toHaveBeenCalledOnce();
});
});
it("should not call endSession if the user has permission", async () => {
const errorToastSpy = vi.spyOn(toast, "error");
const getConversationSpy = vi.spyOn(OpenHands, "getConversation");
getConversationSpy.mockResolvedValue({
+93 -51
View File
@@ -8,6 +8,7 @@ import MainApp from "#/routes/_oh/route";
import SettingsScreen from "#/routes/settings";
import Home from "#/routes/_oh._index/route";
import OpenHands from "#/api/open-hands";
import * as FeatureFlags from "#/utils/feature-flags";
const createAxiosNotFoundErrorObject = () =>
new AxiosError(
@@ -25,32 +26,32 @@ const createAxiosNotFoundErrorObject = () =>
},
);
const getSettingsSpy = vi.spyOn(OpenHands, "getSettings");
const RouterStub = createRoutesStub([
{
// layout route
Component: MainApp,
path: "/",
children: [
{
// home route
Component: Home,
path: "/",
},
{
Component: SettingsScreen,
path: "/settings",
},
],
},
]);
afterEach(() => {
vi.clearAllMocks();
});
describe("Home Screen", () => {
const getSettingsSpy = vi.spyOn(OpenHands, "getSettings");
const RouterStub = createRoutesStub([
{
// layout route
Component: MainApp,
path: "/",
children: [
{
// home route
Component: Home,
path: "/",
},
{
Component: SettingsScreen,
path: "/settings",
},
],
},
]);
afterEach(() => {
vi.clearAllMocks();
});
it("should render the home screen", () => {
renderWithProviders(<RouterStub initialEntries={["/"]} />);
});
@@ -77,41 +78,82 @@ describe("Home Screen", () => {
const settingsScreen = await screen.findByTestId("settings-screen");
expect(settingsScreen).toBeInTheDocument();
});
});
describe("Settings 404", () => {
it("should open the settings modal if GET /settings fails with a 404", async () => {
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
describe("Settings 404", () => {
const getConfigSpy = vi.spyOn(OpenHands, "getConfig");
renderWithProviders(<RouterStub initialEntries={["/"]} />);
it("should open the settings modal if GET /settings fails with a 404", async () => {
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
const settingsModal = await screen.findByTestId("ai-config-modal");
expect(settingsModal).toBeInTheDocument();
});
renderWithProviders(<RouterStub initialEntries={["/"]} />);
it("should navigate to the settings screen when clicking the advanced settings button", async () => {
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
const settingsModal = await screen.findByTestId("ai-config-modal");
expect(settingsModal).toBeInTheDocument();
});
const user = userEvent.setup();
renderWithProviders(<RouterStub initialEntries={["/"]} />);
it("should navigate to the settings screen when clicking the advanced settings button", async () => {
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
const settingsScreen = screen.queryByTestId("settings-screen");
expect(settingsScreen).not.toBeInTheDocument();
const user = userEvent.setup();
renderWithProviders(<RouterStub initialEntries={["/"]} />);
const settingsModal = await screen.findByTestId("ai-config-modal");
expect(settingsModal).toBeInTheDocument();
const settingsScreen = screen.queryByTestId("settings-screen");
expect(settingsScreen).not.toBeInTheDocument();
const advancedSettingsButton = await screen.findByTestId(
"advanced-settings-link",
);
await user.click(advancedSettingsButton);
const settingsModal = await screen.findByTestId("ai-config-modal");
expect(settingsModal).toBeInTheDocument();
const settingsScreenAfter = await screen.findByTestId("settings-screen");
expect(settingsScreenAfter).toBeInTheDocument();
const advancedSettingsButton = await screen.findByTestId(
"advanced-settings-link",
);
await user.click(advancedSettingsButton);
const settingsModalAfter = screen.queryByTestId("ai-config-modal");
expect(settingsModalAfter).not.toBeInTheDocument();
});
const settingsScreenAfter = await screen.findByTestId("settings-screen");
expect(settingsScreenAfter).toBeInTheDocument();
const settingsModalAfter = screen.queryByTestId("ai-config-modal");
expect(settingsModalAfter).not.toBeInTheDocument();
});
it("should not open the settings modal if GET /settings fails but is SaaS mode", async () => {
// TODO: Remove HIDE_LLM_SETTINGS check once released
vi.spyOn(FeatureFlags, "HIDE_LLM_SETTINGS").mockReturnValue(true);
// @ts-expect-error - we only need APP_MODE for this test
getConfigSpy.mockResolvedValue({ APP_MODE: "saas" });
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
renderWithProviders(<RouterStub initialEntries={["/"]} />);
// small hack to wait for the modal to not appear
await expect(
screen.findByTestId("ai-config-modal", {}, { timeout: 1000 }),
).rejects.toThrow();
});
});
describe("Setup Payment modal", () => {
const getConfigSpy = vi.spyOn(OpenHands, "getConfig");
afterEach(() => {
vi.resetAllMocks();
});
it("should only render if SaaS mode and is new user", async () => {
// @ts-expect-error - we only need the APP_MODE for this test
getConfigSpy.mockResolvedValue({
APP_MODE: "saas",
});
vi.spyOn(FeatureFlags, "BILLING_SETTINGS").mockReturnValue(true);
const error = createAxiosNotFoundErrorObject();
getSettingsSpy.mockRejectedValue(error);
renderWithProviders(<RouterStub initialEntries={["/"]} />);
const setupPaymentModal = await screen.findByTestId("proceed-to-stripe-button");
expect(setupPaymentModal).toBeInTheDocument();
});
});
+139 -17
View File
@@ -1,6 +1,15 @@
import { render, screen, waitFor, within } from "@testing-library/react";
import { createRoutesStub } from "react-router";
import { afterEach, describe, expect, it, test, vi } from "vitest";
import {
afterEach,
beforeAll,
beforeEach,
describe,
expect,
it,
test,
vi,
} from "vitest";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import userEvent, { UserEvent } from "@testing-library/user-event";
import OpenHands from "#/api/open-hands";
@@ -11,6 +20,7 @@ import { MOCK_DEFAULT_USER_SETTINGS } from "#/mocks/handlers";
import { PostApiSettings } from "#/types/settings";
import * as ConsentHandlers from "#/utils/handle-capture-consent";
import AccountSettings from "#/routes/account-settings";
import * as FeatureFlags from "#/utils/feature-flags";
const toggleAdvancedSettings = async (user: UserEvent) => {
const advancedSwitch = await screen.findByTestId("advanced-settings-switch");
@@ -29,6 +39,11 @@ describe("Settings Screen", () => {
useAppLogout: vi.fn().mockReturnValue({ handleLogout: handleLogoutMock }),
}));
beforeAll(() => {
// TODO: Remove this once we release
vi.spyOn(FeatureFlags, "HIDE_LLM_SETTINGS").mockReturnValue(true);
});
afterEach(() => {
vi.clearAllMocks();
});
@@ -67,6 +82,14 @@ describe("Settings Screen", () => {
});
describe("Account Settings", () => {
beforeEach(() => {
getConfigSpy.mockResolvedValue({
APP_MODE: "oss",
GITHUB_CLIENT_ID: "123",
POSTHOG_CLIENT_KEY: "456",
});
});
it("should render the account settings", async () => {
renderSettingsScreen();
@@ -280,6 +303,14 @@ describe("Settings Screen", () => {
});
describe("LLM Settings", () => {
beforeEach(() => {
getConfigSpy.mockResolvedValue({
APP_MODE: "oss",
GITHUB_CLIENT_ID: "123",
POSTHOG_CLIENT_KEY: "456",
});
});
it("should render the basic LLM settings by default", async () => {
renderSettingsScreen();
@@ -427,8 +458,7 @@ describe("Settings Screen", () => {
expect(input).not.toBeInTheDocument();
});
it("should render the runtime settings input if SaaS mode", async () => {
const user = userEvent.setup();
it.skip("should render the runtime settings input if SaaS mode", async () => {
getConfigSpy.mockResolvedValue({
APP_MODE: "saas",
GITHUB_CLIENT_ID: "123",
@@ -436,12 +466,10 @@ describe("Settings Screen", () => {
});
renderSettingsScreen();
await toggleAdvancedSettings(user);
screen.getByTestId("runtime-settings-input");
await screen.findByTestId("runtime-settings-input");
});
it("should set the default runtime setting set", async () => {
it.skip("should set the default runtime setting set", async () => {
getConfigSpy.mockResolvedValue({
APP_MODE: "saas",
GITHUB_CLIENT_ID: "123",
@@ -455,13 +483,11 @@ describe("Settings Screen", () => {
renderSettingsScreen();
await toggleAdvancedSettings(userEvent.setup());
const input = await screen.findByTestId("runtime-settings-input");
expect(input).toHaveValue("1x (2 core, 8G)");
});
it("should always have the runtime input disabled", async () => {
it.skip("should always have the runtime input disabled", async () => {
getConfigSpy.mockResolvedValue({
APP_MODE: "saas",
GITHUB_CLIENT_ID: "123",
@@ -470,8 +496,6 @@ describe("Settings Screen", () => {
renderSettingsScreen();
await toggleAdvancedSettings(userEvent.setup());
const input = await screen.findByTestId("runtime-settings-input");
expect(input).toBeDisabled();
});
@@ -490,8 +514,6 @@ describe("Settings Screen", () => {
renderSettingsScreen();
await toggleAdvancedSettings(user);
const input = await screen.findByTestId("runtime-settings-input");
await user.click(input);
@@ -699,7 +721,7 @@ describe("Settings Screen", () => {
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({
llm_api_key: "", // empty because it's not set previously
github_token: undefined,
provider_tokens: undefined,
language: "no",
}),
);
@@ -736,7 +758,7 @@ describe("Settings Screen", () => {
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({
github_token: undefined,
provider_tokens: undefined,
llm_api_key: "", // empty because it's not set previously
llm_model: "openai/gpt-4o",
}),
@@ -779,7 +801,7 @@ describe("Settings Screen", () => {
expect(saveSettingsSpy).toHaveBeenCalledWith({
...mockCopy,
github_token: undefined, // not set
provider_tokens: undefined, // not set
llm_api_key: "", // reset as well
});
expect(screen.queryByTestId("reset-modal")).not.toBeInTheDocument();
@@ -953,4 +975,104 @@ describe("Settings Screen", () => {
);
});
});
describe("SaaS mode", () => {
beforeEach(() => {
getConfigSpy.mockResolvedValue({
APP_MODE: "saas",
GITHUB_CLIENT_ID: "123",
POSTHOG_CLIENT_KEY: "456",
});
});
it("should hide the entire LLM section", async () => {
renderSettingsScreen();
await waitFor(() => {
screen.getByTestId("account-settings-form"); // wait for the account settings form to render
const llmSection = screen.queryByTestId("llm-settings-section");
expect(llmSection).not.toBeInTheDocument();
});
});
it("should not render LLM Provider, LLM Model, and LLM API Key inputs", async () => {
renderSettingsScreen();
await waitFor(() => {
screen.getByTestId("account-settings-form"); // wait for the account settings form to render
const providerInput = screen.queryByTestId("llm-provider-input");
const modelInput = screen.queryByTestId("llm-model-input");
const apiKeyInput = screen.queryByTestId("llm-api-key-input");
const llmApiKeyHelpAnchor = screen.queryByTestId(
"llm-api-key-help-anchor",
);
const advancedSettingsSwitch = screen.queryByTestId(
"advanced-settings-switch",
);
expect(providerInput).not.toBeInTheDocument();
expect(modelInput).not.toBeInTheDocument();
expect(apiKeyInput).not.toBeInTheDocument();
expect(llmApiKeyHelpAnchor).not.toBeInTheDocument();
expect(advancedSettingsSwitch).not.toBeInTheDocument();
});
});
// We might want to bring this back if users wish to set advanced settings
it.skip("should render advanced settings by default", async () => {
renderSettingsScreen();
await waitFor(() => {
screen.getByTestId("account-settings-form"); // wait for the account settings form to render
const agentInput = screen.getByTestId("agent-input"); // this is only rendered in advanced mode
expect(agentInput).toBeInTheDocument();
// we should not allow the user to change these fields
const customModelInput = screen.queryByTestId("llm-custom-model-input");
const baseUrlInput = screen.queryByTestId("base-url-input");
expect(customModelInput).not.toBeInTheDocument();
expect(baseUrlInput).not.toBeInTheDocument();
});
});
it("should not submit the unwanted fields when saving", async () => {
const user = userEvent.setup();
renderSettingsScreen();
const saveButton = await screen.findByText("Save Changes");
await user.click(saveButton);
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({
llm_api_key: undefined,
llm_base_url: undefined,
llm_model: undefined,
}),
);
});
it("should not submit the unwanted fields when resetting", async () => {
const user = userEvent.setup();
renderSettingsScreen();
const resetButton = await screen.findByText("Reset to defaults");
await user.click(resetButton);
const modal = await screen.findByTestId("reset-modal");
const confirmButton = within(modal).getByText("Reset");
await user.click(confirmButton);
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({
llm_api_key: undefined,
llm_base_url: undefined,
llm_model: undefined,
}),
);
});
});
});
+88 -1
View File
@@ -1,7 +1,9 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { handleStatusMessage } from "#/services/actions";
import { handleStatusMessage, handleActionMessage } from "#/services/actions";
import store from "#/store";
import { trackError } from "#/utils/error-handler";
import ActionType from "#/types/action-type";
import { ActionMessage } from "#/types/message";
// Mock dependencies
vi.mock("#/utils/error-handler", () => ({
@@ -56,4 +58,89 @@ describe("Actions Service", () => {
}));
});
});
describe("handleActionMessage", () => {
it("should use first-person perspective for task completion messages", () => {
// Test partial completion
const messagePartial: ActionMessage = {
id: 1,
action: ActionType.FINISH,
source: "agent",
message: "",
timestamp: new Date().toISOString(),
args: {
final_thought: "",
task_completed: "partial",
outputs: "",
thought: ""
}
};
// Mock implementation to capture the message
let capturedPartialMessage = "";
(store.dispatch as any).mockImplementation((action: any) => {
if (action.type === "chat/addAssistantMessage" &&
action.payload.includes("believe that the task was **completed partially**")) {
capturedPartialMessage = action.payload;
}
});
handleActionMessage(messagePartial);
expect(capturedPartialMessage).toContain("I believe that the task was **completed partially**");
// Test not completed
const messageNotCompleted: ActionMessage = {
id: 2,
action: ActionType.FINISH,
source: "agent",
message: "",
timestamp: new Date().toISOString(),
args: {
final_thought: "",
task_completed: "false",
outputs: "",
thought: ""
}
};
// Mock implementation to capture the message
let capturedNotCompletedMessage = "";
(store.dispatch as any).mockImplementation((action: any) => {
if (action.type === "chat/addAssistantMessage" &&
action.payload.includes("believe that the task was **not completed**")) {
capturedNotCompletedMessage = action.payload;
}
});
handleActionMessage(messageNotCompleted);
expect(capturedNotCompletedMessage).toContain("I believe that the task was **not completed**");
// Test completed successfully
const messageCompleted: ActionMessage = {
id: 3,
action: ActionType.FINISH,
source: "agent",
message: "",
timestamp: new Date().toISOString(),
args: {
final_thought: "",
task_completed: "true",
outputs: "",
thought: ""
}
};
// Mock implementation to capture the message
let capturedCompletedMessage = "";
(store.dispatch as any).mockImplementation((action: any) => {
if (action.type === "chat/addAssistantMessage" &&
action.payload.includes("believe that the task was **completed successfully**")) {
capturedCompletedMessage = action.payload;
}
});
handleActionMessage(messageCompleted);
expect(capturedCompletedMessage).toContain("I believe that the task was **completed successfully**");
});
});
});
+64 -41
View File
@@ -1,8 +1,12 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { trackError, showErrorToast, showChatError } from "#/utils/error-handler";
import posthog from "posthog-js";
import toast from "react-hot-toast";
import {
trackError,
showErrorToast,
showChatError,
} from "#/utils/error-handler";
import * as Actions from "#/services/actions";
import * as CustomToast from "#/utils/custom-toast-handlers";
vi.mock("posthog-js", () => ({
default: {
@@ -10,12 +14,6 @@ vi.mock("posthog-js", () => ({
},
}));
vi.mock("react-hot-toast", () => ({
default: {
error: vi.fn(),
},
}));
vi.mock("#/services/actions", () => ({
handleStatusMessage: vi.fn(),
}));
@@ -38,9 +36,12 @@ describe("Error Handler", () => {
trackError(error);
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Test error"), {
error_source: "test",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Test error"),
{
error_source: "test",
},
);
});
it("should include additional metadata in PostHog event", () => {
@@ -55,15 +56,19 @@ describe("Error Handler", () => {
trackError(error);
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Test error"), {
error_source: "test",
extra: "info",
details: { foo: "bar" },
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Test error"),
{
error_source: "test",
extra: "info",
details: { foo: "bar" },
},
);
});
});
describe("showErrorToast", () => {
const errorToastSpy = vi.spyOn(CustomToast, "displayErrorToast");
it("should log error and show toast", () => {
const error = {
message: "Toast error",
@@ -73,12 +78,15 @@ describe("Error Handler", () => {
showErrorToast(error);
// Verify PostHog logging
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Toast error"), {
error_source: "toast-test",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Toast error"),
{
error_source: "toast-test",
},
);
// Verify toast was shown
expect(toast.error).toHaveBeenCalled();
expect(errorToastSpy).toHaveBeenCalled();
});
it("should include metadata in PostHog event when showing toast", () => {
@@ -90,10 +98,13 @@ describe("Error Handler", () => {
showErrorToast(error);
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Toast error"), {
error_source: "toast-test",
context: "testing",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Toast error"),
{
error_source: "toast-test",
context: "testing",
},
);
});
it("should log errors from different sources with appropriate metadata", () => {
@@ -104,10 +115,13 @@ describe("Error Handler", () => {
metadata: { id: "error.agent" },
});
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Agent error"), {
error_source: "agent-status",
id: "error.agent",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Agent error"),
{
error_source: "agent-status",
id: "error.agent",
},
);
showErrorToast({
message: "Server error",
@@ -115,11 +129,14 @@ describe("Error Handler", () => {
metadata: { error_code: 500, details: "Internal error" },
});
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Server error"), {
error_source: "server",
error_code: 500,
details: "Internal error",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Server error"),
{
error_source: "server",
error_code: 500,
details: "Internal error",
},
);
});
it("should log feedback submission errors with conversation context", () => {
@@ -130,11 +147,14 @@ describe("Error Handler", () => {
metadata: { conversationId: "123", error },
});
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Feedback submission failed"), {
error_source: "feedback",
conversationId: "123",
error,
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Feedback submission failed"),
{
error_source: "feedback",
conversationId: "123",
error,
},
);
});
});
@@ -149,9 +169,12 @@ describe("Error Handler", () => {
showChatError(error);
// Verify PostHog logging
expect(posthog.captureException).toHaveBeenCalledWith(new Error("Chat error"), {
error_source: "chat-test",
});
expect(posthog.captureException).toHaveBeenCalledWith(
new Error("Chat error"),
{
error_source: "chat-test",
},
);
// Verify error message was shown in chat
expect(Actions.handleStatusMessage).toHaveBeenCalledWith({
+895 -490
View File
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -1,6 +1,6 @@
{
"name": "openhands-frontend",
"version": "0.27.0",
"version": "0.28.1",
"private": true,
"type": "module",
"engines": {
@@ -9,43 +9,43 @@
"dependencies": {
"@heroui/react": "2.7.4",
"@monaco-editor/react": "^4.7.0-rc.0",
"@react-router/node": "^7.2.0",
"@react-router/serve": "^7.2.0",
"@react-types/shared": "^3.27.0",
"@react-router/node": "^7.3.0",
"@react-router/serve": "^7.3.0",
"@react-types/shared": "^3.28.0",
"@reduxjs/toolkit": "^2.6.0",
"@stripe/react-stripe-js": "^3.1.1",
"@stripe/stripe-js": "^5.7.0",
"@tanstack/react-query": "^5.66.11",
"@stripe/react-stripe-js": "^3.3.0",
"@stripe/stripe-js": "^5.10.0",
"@tanstack/react-query": "^5.67.2",
"@vitejs/plugin-react": "^4.3.2",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.4.0",
"axios": "^1.8.1",
"axios": "^1.8.2",
"clsx": "^2.1.1",
"eslint-config-airbnb-typescript": "^18.0.0",
"framer-motion": "^12.4.7",
"framer-motion": "^12.4.10",
"i18next": "^24.2.2",
"i18next-browser-languagedetector": "^8.0.4",
"i18next-http-backend": "^3.0.2",
"isbot": "^5.1.23",
"jose": "^6.0.8",
"monaco-editor": "^0.52.2",
"posthog-js": "^1.225.1",
"posthog-js": "^1.229.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-highlight": "^0.15.0",
"react-hot-toast": "^2.5.1",
"react-i18next": "^15.4.1",
"react-icons": "^5.5.0",
"react-markdown": "^10.0.1",
"react-markdown": "^10.1.0",
"react-redux": "^9.2.0",
"react-router": "^7.2.0",
"react-router": "^7.3.0",
"react-syntax-highlighter": "^15.6.1",
"react-textarea-autosize": "^8.5.7",
"remark-gfm": "^4.0.1",
"sirv-cli": "^3.0.1",
"socket.io-client": "^4.8.1",
"tailwind-merge": "^3.0.2",
"vite": "^6.2.0",
"vite": "^6.2.1",
"web-vitals": "^3.5.2",
"ws": "^8.18.1"
},
@@ -80,29 +80,29 @@
},
"devDependencies": {
"@mswjs/socket.io-binding": "^0.1.1",
"@playwright/test": "^1.50.1",
"@react-router/dev": "^7.2.0",
"@playwright/test": "^1.51.0",
"@react-router/dev": "^7.3.0",
"@tailwindcss/typography": "^0.5.16",
"@tanstack/eslint-plugin-query": "^5.66.1",
"@tanstack/eslint-plugin-query": "^5.67.2",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.1",
"@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^22.13.8",
"@types/node": "^22.13.9",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@types/react-highlight": "^0.12.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/ws": "^8.5.14",
"@types/ws": "^8.18.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitest/coverage-v8": "^3.0.7",
"@vitest/coverage-v8": "^3.0.8",
"autoprefixer": "^10.4.20",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-prettier": "^10.0.2",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.2.3",
+1 -1
View File
@@ -8,7 +8,7 @@
* - Please do NOT serve this file on production.
*/
const PACKAGE_VERSION = '2.7.0'
const PACKAGE_VERSION = '2.7.3'
const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
+7
View File
@@ -281,6 +281,13 @@ class OpenHands {
return data.redirect_url;
}
static async createBillingSessionResponse(): Promise<string> {
const { data } = await openHands.post(
"/api/billing/create-customer-setup-session",
);
return data.redirect_url;
}
static async getBalance(): Promise<string> {
const { data } = await openHands.get<{ credits: string }>(
"/api/billing/credits",
+1
View File
@@ -48,6 +48,7 @@ export interface GetConfigResponse {
APP_SLUG?: string;
GITHUB_CLIENT_ID: string;
POSTHOG_CLIENT_KEY: string;
STRIPE_PUBLISHABLE_KEY?: string;
}
export interface GetVSCodeUrlResponse {
@@ -1,5 +1,4 @@
import { useDispatch, useSelector } from "react-redux";
import toast from "react-hot-toast";
import React from "react";
import posthog from "posthog-js";
import { useParams } from "react-router";
@@ -23,6 +22,7 @@ import { ScrollToBottomButton } from "#/components/shared/buttons/scroll-to-bott
import { LoadingSpinner } from "#/components/shared/loading-spinner";
import { useGetTrajectory } from "#/hooks/mutation/use-get-trajectory";
import { downloadTrajectory } from "#/utils/download-files";
import { displayErrorToast } from "#/utils/custom-toast-handlers";
function getEntryPoint(
hasRepository: boolean | null,
@@ -98,7 +98,7 @@ export function ChatInterface() {
const onClickExportTrajectoryButton = () => {
if (!params.conversationId) {
toast.error("ConversationId unknown, cannot download trajectory");
displayErrorToast("ConversationId unknown, cannot download trajectory");
return;
}
@@ -110,7 +110,7 @@ export function ChatInterface() {
);
},
onError: (error) => {
toast.error(error.message);
displayErrorToast(error.message);
},
});
};
@@ -0,0 +1,48 @@
import { useMutation } from "@tanstack/react-query";
import { Trans, useTranslation } from "react-i18next";
import AllHandsLogo from "#/assets/branding/all-hands-logo.svg?react";
import { ModalBackdrop } from "#/components/shared/modals/modal-backdrop";
import { ModalBody } from "#/components/shared/modals/modal-body";
import OpenHands from "#/api/open-hands";
import { BrandButton } from "../settings/brand-button";
import { displayErrorToast } from "#/utils/custom-toast-handlers";
export function SetupPaymentModal() {
const { t } = useTranslation();
const { mutate, isPending } = useMutation({
mutationFn: OpenHands.createBillingSessionResponse,
onSuccess: (data) => {
window.location.href = data;
},
onError: () => {
displayErrorToast(t("BILLING$ERROR_WHILE_CREATING_SESSION"));
},
});
return (
<ModalBackdrop>
<ModalBody className="border border-tertiary">
<AllHandsLogo width={68} height={46} />
<div className="flex flex-col gap-2 w-full items-center text-center">
<h1 className="text-2xl font-bold">{t("BILLING$YOUVE_GOT_50")}</h1>
<p>
<Trans
i18nKey="BILLING$CLAIM_YOUR_50"
components={{ b: <strong /> }}
/>
</p>
</div>
<BrandButton
testId="proceed-to-stripe-button"
type="submit"
variant="primary"
className="w-full"
isDisabled={isPending}
onClick={mutate}
>
{t("BILLING$PROCEED_TO_STRIPE")}
</BrandButton>
</ModalBody>
</ModalBackdrop>
);
}
@@ -1,9 +1,10 @@
import { Autocomplete, AutocompleteItem } from "@heroui/react";
import { ReactNode } from "react";
import { OptionalTag } from "./optional-tag";
interface SettingsDropdownInputProps {
testId: string;
label: string;
label: ReactNode;
name: string;
items: { key: React.Key; label: string }[];
showOptionalTag?: boolean;
@@ -29,7 +30,7 @@ export function SettingsDropdownInput({
{showOptionalTag && <OptionalTag />}
</div>
<Autocomplete
aria-label={label}
aria-label={typeof label === "string" ? label : name}
data-testid={testId}
name={name}
defaultItems={items}
@@ -2,7 +2,6 @@ import React from "react";
import { FaListUl } from "react-icons/fa";
import { useDispatch } from "react-redux";
import posthog from "posthog-js";
import toast from "react-hot-toast";
import { NavLink, useLocation } from "react-router";
import { useGitHubUser } from "#/hooks/query/use-github-user";
import { UserActions } from "./user-actions";
@@ -10,7 +9,6 @@ import { AllHandsLogoButton } from "#/components/shared/buttons/all-hands-logo-b
import { DocsButton } from "#/components/shared/buttons/docs-button";
import { ExitProjectButton } from "#/components/shared/buttons/exit-project-button";
import { SettingsButton } from "#/components/shared/buttons/settings-button";
import { LoadingSpinner } from "#/components/shared/loading-spinner";
import { SettingsModal } from "#/components/shared/modals/settings/settings-modal";
import { useCurrentSettings } from "#/context/settings-context";
import { useSettings } from "#/hooks/query/use-settings";
@@ -23,6 +21,8 @@ import { ConversationPanelWrapper } from "../conversation-panel/conversation-pan
import { useLogout } from "#/hooks/mutation/use-logout";
import { useConfig } from "#/hooks/query/use-config";
import { cn } from "#/utils/utils";
import { displayErrorToast } from "#/utils/custom-toast-handlers";
import { HIDE_LLM_SETTINGS } from "#/utils/feature-flags";
export function Sidebar() {
const location = useLocation();
@@ -43,7 +43,12 @@ export function Sidebar() {
const [conversationPanelIsOpen, setConversationPanelIsOpen] =
React.useState(false);
// TODO: Remove HIDE_LLM_SETTINGS check once released
const isSaas = HIDE_LLM_SETTINGS() && config?.APP_MODE === "saas";
React.useEffect(() => {
if (isSaas) return;
if (location.pathname === "/settings") {
setSettingsModalIsOpen(false);
} else if (
@@ -53,10 +58,10 @@ export function Sidebar() {
) {
// We don't show toast errors for settings in the global error handler
// because we have a special case for 404 errors
toast.error(
displayErrorToast(
"Something went wrong while fetching settings. Please reload the page.",
);
} else if (settingsError?.status === 404) {
} else if (config?.APP_MODE === "oss" && settingsError?.status === 404) {
setSettingsModalIsOpen(true);
}
}, [
@@ -111,15 +116,13 @@ export function Sidebar() {
>
<SettingsButton />
</NavLink>
{!user.isLoading && (
<UserActions
user={
user.data ? { avatar_url: user.data.avatar_url } : undefined
}
onLogout={handleLogout}
/>
)}
{user.isLoading && <LoadingSpinner size="small" />}
<UserActions
user={
user.data ? { avatar_url: user.data.avatar_url } : undefined
}
onLogout={handleLogout}
isLoading={user.isFetching}
/>
</div>
</nav>
@@ -5,9 +5,10 @@ import { AccountSettingsContextMenu } from "../context-menu/account-settings-con
interface UserActionsProps {
onLogout: () => void;
user?: { avatar_url: string };
isLoading?: boolean;
}
export function UserActions({ onLogout, user }: UserActionsProps) {
export function UserActions({ onLogout, user, isLoading }: UserActionsProps) {
const [accountContextMenuIsVisible, setAccountContextMenuIsVisible] =
React.useState(false);
@@ -26,7 +27,11 @@ export function UserActions({ onLogout, user }: UserActionsProps) {
return (
<div data-testid="user-actions" className="w-8 h-8 relative">
<UserAvatar avatarUrl={user?.avatar_url} onClick={toggleAccountMenu} />
<UserAvatar
avatarUrl={user?.avatar_url}
onClick={toggleAccountMenu}
isLoading={isLoading}
/>
{accountContextMenuIsVisible && (
<AccountSettingsContextMenu
@@ -43,15 +43,18 @@ export function SettingsForm({ settings, models, onClose }: SettingsFormProps) {
const handleFormSubmission = async (formData: FormData) => {
const newSettings = extractSettings(formData);
await saveUserSettings(newSettings);
onClose();
resetOngoingSession();
await saveUserSettings(newSettings, {
onSuccess: () => {
onClose();
resetOngoingSession();
posthog.capture("settings_saved", {
LLM_MODEL: newSettings.LLM_MODEL,
LLM_API_KEY: newSettings.LLM_API_KEY ? "SET" : "UNSET",
REMOTE_RUNTIME_RESOURCE_FACTOR:
newSettings.REMOTE_RUNTIME_RESOURCE_FACTOR,
posthog.capture("settings_saved", {
LLM_MODEL: newSettings.LLM_MODEL,
LLM_API_KEY: newSettings.LLM_API_KEY ? "SET" : "UNSET",
REMOTE_RUNTIME_RESOURCE_FACTOR:
newSettings.REMOTE_RUNTIME_RESOURCE_FACTOR,
});
},
});
};
+2 -2
View File
@@ -1,10 +1,10 @@
import React from "react";
import { MutateOptions } from "@tanstack/react-query";
import toast from "react-hot-toast";
import { useSettings } from "#/hooks/query/use-settings";
import { useSaveSettings } from "#/hooks/mutation/use-save-settings";
import { PostSettings, Settings } from "#/types/settings";
import { retrieveAxiosErrorMessage } from "#/utils/retrieve-axios-error-message";
import { displayErrorToast } from "#/utils/custom-toast-handlers";
type SaveUserSettingsConfig = {
onSuccess: MutateOptions<void, Error, Partial<PostSettings>>["onSuccess"];
@@ -47,7 +47,7 @@ export function SettingsProvider({ children }: SettingsProviderProps) {
onSuccess: config?.onSuccess,
onError: (error) => {
const errorMessage = retrieveAxiosErrorMessage(error);
toast.error(errorMessage);
displayErrorToast(errorMessage);
},
});
};
@@ -17,7 +17,7 @@ const saveSettingsMutationFn = async (settings: Partial<PostSettings>) => {
? ""
: settings.LLM_API_KEY?.trim() || undefined,
remote_runtime_resource_factor: settings.REMOTE_RUNTIME_RESOURCE_FACTOR,
github_token: settings.github_token,
provider_tokens: settings.provider_tokens,
unset_github_token: settings.unset_github_token,
enable_default_condenser: settings.ENABLE_DEFAULT_CONDENSER,
enable_sound_notifications: settings.ENABLE_SOUND_NOTIFICATIONS,
@@ -1,8 +1,8 @@
import { useMutation } from "@tanstack/react-query";
import toast from "react-hot-toast";
import { Feedback } from "#/api/open-hands.types";
import OpenHands from "#/api/open-hands";
import { useConversation } from "#/context/conversation-context";
import { displayErrorToast } from "#/utils/custom-toast-handlers";
type SubmitFeedbackArgs = {
feedback: Feedback;
@@ -14,7 +14,7 @@ export const useSubmitFeedback = () => {
mutationFn: ({ feedback }: SubmitFeedbackArgs) =>
OpenHands.submitFeedback(conversationId, feedback),
onError: (error) => {
toast.error(error.message);
displayErrorToast(error.message);
},
});
};
@@ -11,4 +11,6 @@ export const useAIConfigOptions = () =>
useQuery({
queryKey: ["ai-config-options"],
queryFn: fetchAiConfigOptions,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
@@ -14,5 +14,7 @@ export const useAppInstallations = () => {
githubTokenIsSet &&
!!config?.GITHUB_CLIENT_ID &&
config?.APP_MODE === "saas",
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
};
@@ -50,6 +50,8 @@ export const useAppRepositories = () => {
Array.isArray(installations) &&
installations.length > 0 &&
config?.APP_MODE === "saas",
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
// TODO: Once we create our custom dropdown component, we should fetch data onEndReached
+2 -1
View File
@@ -1,6 +1,7 @@
import { useQuery } from "@tanstack/react-query";
import { useConfig } from "./use-config";
import OpenHands from "#/api/open-hands";
import { BILLING_SETTINGS } from "#/utils/feature-flags";
export const useBalance = () => {
const { data: config } = useConfig();
@@ -8,6 +9,6 @@ export const useBalance = () => {
return useQuery({
queryKey: ["user", "balance"],
queryFn: OpenHands.getBalance,
enabled: config?.APP_MODE === "saas",
enabled: config?.APP_MODE === "saas" && BILLING_SETTINGS(),
});
};
+2
View File
@@ -5,4 +5,6 @@ export const useConfig = () =>
useQuery({
queryKey: ["config"],
queryFn: OpenHands.getConfig,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
@@ -18,6 +18,8 @@ export const useConversationConfig = () => {
return OpenHands.getRuntimeId(conversationId);
},
enabled: status !== WsClientProviderStatus.DISCONNECTED && !!conversationId,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
React.useEffect(() => {
@@ -19,6 +19,8 @@ export const useGitHubUser = () => {
queryFn: OpenHands.getGitHubUser,
enabled: githubTokenIsSet && !!config?.APP_MODE,
retry: false,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
React.useEffect(() => {
@@ -15,6 +15,7 @@ export const useIsAuthed = () => {
queryFn: () => OpenHands.authenticate(appMode!),
enabled: !!appMode,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
retry: false,
meta: {
disableToast: true,
@@ -23,5 +23,7 @@ export const useListFiles = (config: UseListFilesConfig = DEFAULT_CONFIG) => {
queryKey: ["files", conversationId, config?.path],
queryFn: () => OpenHands.getFiles(conversationId, config?.path),
enabled: !!(isActive && config?.enabled),
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
};
@@ -7,5 +7,7 @@ export function useSearchRepositories(query: string) {
queryFn: () => OpenHands.searchGitHubRepositories(query, 3),
enabled: !!query,
select: (data) => data.map((repo) => ({ ...repo, is_public: true })),
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
}
+4 -3
View File
@@ -3,7 +3,6 @@ import React from "react";
import posthog from "posthog-js";
import OpenHands from "#/api/open-hands";
import { useAuth } from "#/context/auth-context";
import { useConfig } from "#/hooks/query/use-config";
import { DEFAULT_SETTINGS } from "#/services/settings";
const getSettingsQueryFn = async () => {
@@ -22,21 +21,23 @@ const getSettingsQueryFn = async () => {
ENABLE_DEFAULT_CONDENSER: apiSettings.enable_default_condenser,
ENABLE_SOUND_NOTIFICATIONS: apiSettings.enable_sound_notifications,
USER_CONSENTS_TO_ANALYTICS: apiSettings.user_consents_to_analytics,
PROVIDER_TOKENS: apiSettings.provider_tokens,
IS_NEW_USER: false,
};
};
export const useSettings = () => {
const { setGitHubTokenIsSet, githubTokenIsSet } = useAuth();
const { data: config } = useConfig();
const query = useQuery({
queryKey: ["settings", githubTokenIsSet],
queryFn: getSettingsQueryFn,
enabled: config?.APP_MODE !== "saas" || githubTokenIsSet,
// Only retry if the error is not a 404 because we
// would want to show the modal immediately if the
// settings are not found
retry: (_, error) => error.status !== 404,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
meta: {
disableToast: true,
},
@@ -7,4 +7,6 @@ export const useUserConversation = (cid: string | null) =>
queryFn: () => OpenHands.getConversation(cid!),
enabled: !!cid,
retry: false,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
@@ -9,6 +9,5 @@ export const useUserConversations = () => {
queryKey: ["user", "conversations"],
queryFn: OpenHands.getUserConversations,
enabled: !!userIsAuthenticated,
staleTime: 0,
});
};
@@ -15,6 +15,8 @@ export const useUserRepositories = () => {
initialPageParam: 1,
getNextPageParam: (lastPage) => lastPage.nextPage,
enabled: githubTokenIsSet && config?.APP_MODE === "oss",
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
// TODO: Once we create our custom dropdown component, we should fetch data onEndReached
@@ -13,6 +13,8 @@ export const useVSCodeUrl = (config: { enabled: boolean }) => {
},
enabled: !!conversationId && config.enabled,
refetchOnMount: false,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes
});
return data;
+5
View File
@@ -312,4 +312,9 @@ export enum I18nKey {
BUTTON$MARK_NOT_HELPFUL = "BUTTON$MARK_NOT_HELPFUL",
BUTTON$EXPORT_CONVERSATION = "BUTTON$EXPORT_CONVERSATION",
BILLING$CLICK_TO_TOP_UP = "BILLING$CLICK_TO_TOP_UP",
BILLING$YOUVE_GOT_50 = "BILLING$YOUVE_GOT_50",
BILLING$ERROR_WHILE_CREATING_SESSION = "BILLING$ERROR_WHILE_CREATING_SESSION",
BILLING$CLAIM_YOUR_50 = "BILLING$CLAIM_YOUR_50",
BILLING$PROCEED_TO_STRIPE = "BILLING$PROCEED_TO_STRIPE",
BILLING$YOURE_IN = "BILLING$YOURE_IN",
}
+75
View File
@@ -4647,5 +4647,80 @@
"fr": "Ajouter des fonds à votre compte",
"tr": "Hesabınıza bakiye ekleyin",
"de": "Guthaben zu Ihrem Konto hinzufügen"
},
"BILLING$YOUVE_GOT_50": {
"en": "You've got $50 in free OpenHands credits",
"ja": "OpenHandsの無料クレジット$50を獲得しました",
"zh-CN": "您获得了 $50 的 OpenHands 免费额度",
"zh-TW": "您獲得了 $50 的 OpenHands 免費額度",
"ko-KR": "OpenHands 무료 크레딧 $50를 받았습니다",
"no": "Du har fått $50 i gratis OpenHands-kreditter",
"it": "Hai ottenuto $50 in crediti gratuiti OpenHands",
"pt": "Você ganhou $50 em créditos gratuitos OpenHands",
"es": "Has recibido $50 en créditos gratuitos de OpenHands",
"ar": "لديك 50$ من رصيد OpenHands المجاني",
"fr": "Vous avez reçu $50 de crédits OpenHands gratuits",
"tr": "OpenHands'de $50 ücretsiz kredi kazandınız",
"de": "Sie haben $50 in kostenlosen OpenHands-Guthaben erhalten"
},
"BILLING$ERROR_WHILE_CREATING_SESSION": {
"en": "Error occurred while setting up your payment session. Please try again later.",
"ja": "お支払いセッションの設定中にエラーが発生しました。後ほど再度お試しください。",
"zh-CN": "设置支付会话时发生错误。请稍后再试。",
"zh-TW": "設置支付會話時發生錯誤。請稍後再試。",
"ko-KR": "결제 세션 설정 중 오류가 발생했습니다. 나중에 다시 시도해 주세요.",
"no": "Det oppstod en feil under oppsett av betalingsøkten. Vennligst prøv igjen senere.",
"it": "Si è verificato un errore durante la configurazione della sessione di pagamento. Si prega di riprovare più tardi.",
"pt": "Ocorreu um erro ao configurar sua sessão de pagamento. Por favor, tente novamente mais tarde.",
"es": "Se produjo un error al configurar tu sesión de pago. Por favor, inténtalo de nuevo más tarde.",
"ar": "حدث خطأ أثناء إعداد جلسة الدفع الخاصة بك. يرجى المحاولة مرة أخرى لاحقًا.",
"fr": "Une erreur s'est produite lors de la configuration de votre session de paiement. Veuillez réessayer plus tard.",
"tr": "Ödeme oturumunuz kurulurken bir hata oluştu. Lütfen daha sonra tekrar deneyin.",
"de": "Beim Einrichten Ihrer Zahlungssitzung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut."
},
"BILLING$CLAIM_YOUR_50": {
"en": "Add a credit card with Stripe to claim your $50. <b>We won't charge you without asking first!</b>",
"ja": "Stripeでクレジットカードを追加して$50を獲得。<b>事前の確認なしで請求することはありません!</b>",
"zh-CN": "添加 Stripe 信用卡以领取 $50。<b>我们不会在未经您同意的情况下收费!</b>",
"zh-TW": "添加 Stripe 信用卡以領取 $50。<b>我們不會在未經您同意的情況下收費!</b>",
"ko-KR": "Stripe에 신용카드를 추가하여 $50를 받으세요. <b>사전 동의 없이 요금이 청구되지 않습니다!</b>",
"no": "Legg til et kredittkort med Stripe for å få $50. <b>Vi belaster deg ikke uten å spørre først!</b>",
"it": "Aggiungi una carta di credito con Stripe per ottenere $50. <b>Non ti addebiteremo nulla senza chiedere prima!</b>",
"pt": "Adicione um cartão de crédito com Stripe para receber $50. <b>Não cobraremos sem perguntar primeiro!</b>",
"es": "Añade una tarjeta de crédito con Stripe para reclamar tus $50. <b>¡No te cobraremos sin preguntarte primero!</b>",
"ar": "أضف بطاقة ائتمان مع Stripe للحصول على 50$. <b>لن نقوم بالخصم دون إذن مسبق!</b>",
"fr": "Ajoutez une carte de crédit avec Stripe pour obtenir 50$. <b>Nous ne vous facturerons pas sans vous demander d'abord !</b>",
"tr": "50$ almak için Stripe ile kredi kartı ekleyin. <b>Önce sormadan ücret almayacağız!</b>",
"de": "Fügen Sie eine Kreditkarte mit Stripe hinzu, um $50 zu erhalten. <b>Wir belasten Sie nicht ohne vorherige Zustimmung!</b>"
},
"BILLING$PROCEED_TO_STRIPE": {
"en": "Add Billing Info",
"ja": "請求情報を追加",
"zh-CN": "添加账单信息",
"zh-TW": "添加帳單資訊",
"ko-KR": "결제 정보 추가",
"no": "Legg til betalingsinformasjon",
"it": "Aggiungi informazioni di fatturazione",
"pt": "Adicionar informações de pagamento",
"es": "Añadir información de facturación",
"ar": "إضافة معلومات الفواتير",
"fr": "Ajouter les informations de facturation",
"tr": "Fatura Bilgisi Ekle",
"de": "Zahlungsinformationen hinzufügen"
},
"BILLING$YOURE_IN": {
"en": "You're in! You can start using your $50 in free credits now.",
"ja": "登録完了!$50分の無料クレジットを今すぐご利用いただけます。",
"zh-CN": "您已加入!现在可以开始使用$50的免费额度了。",
"zh-TW": "您已加入!現在可以開始使用$50的免費額度了。",
"ko-KR": "가입 완료! 지금 바로 $50 상당의 무료 크레딧을 사용하실 수 있습니다.",
"no": "Du er med! Du kan begynne å bruke dine $50 i gratis kreditter nå.",
"it": "Ci sei! Puoi iniziare a utilizzare i tuoi $50 in crediti gratuiti ora.",
"pt": "Você está dentro! Você pode começar a usar seus $50 em créditos gratuitos agora.",
"es": "¡Ya estás dentro! Puedes empezar a usar tus $50 en créditos gratuitos ahora.",
"ar": "أنت معنا! يمكنك البدء في استخدام رصيدك المجاني البالغ 50 دولارًا الآن.",
"fr": "C'est fait ! Vous pouvez commencer à utiliser vos 50 $ de crédits gratuits maintenant.",
"tr": "Başardın! Şimdi $50 değerindeki ücretsiz kredilerini kullanmaya başlayabilirsin.",
"de": "Du bist dabei! Du kannst jetzt deine $50 an kostenlosen Guthaben nutzen."
}
}

Some files were not shown because too many files have changed in this diff Show More