Compare commits

...

260 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
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
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
adityasoni9998
a880f55a63 Added fixes for file downloads, goto action timeouts, and some other browser fixes. 2025-03-13 16:21:16 -04:00
adityasoni9998
35ab168b88 Merge branch 'main' into eval_fixes 2025-03-13 10:35:29 -04:00
adityasoni9998
a578cf39a9 Merge remote-tracking branch 'upstream/main' 2025-03-13 10:24:49 -04: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
25 changed files with 655 additions and 3 deletions

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

View File

@@ -308,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`

View File

@@ -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

View File

@@ -70,6 +70,7 @@ class CodeActAgent(Agent):
codeact_enable_browsing=self.config.codeact_enable_browsing,
codeact_enable_jupyter=self.config.codeact_enable_jupyter,
codeact_enable_llm_editor=self.config.codeact_enable_llm_editor,
codeact_enable_search_engine=self.config.enable_search_engine,
llm=self.llm,
)
logger.debug(

View File

@@ -15,6 +15,7 @@ from openhands.agenthub.codeact_agent.tools import (
FinishTool,
IPythonTool,
LLMBasedFileEditTool,
SearchEngineTool,
ThinkTool,
WebReadTool,
create_cmd_run_tool,
@@ -36,6 +37,7 @@ from openhands.events.action import (
FileReadAction,
IPythonRunCellAction,
MessageAction,
SearchAction,
)
from openhands.events.event import FileEditSource, FileReadSource
from openhands.events.tool import ToolCallMetadata
@@ -191,6 +193,15 @@ def response_to_actions(response: ModelResponse) -> list[Action]:
f'Missing required argument "url" in tool call {tool_call.function.name}'
)
action = BrowseURLAction(url=arguments['url'])
# ================================================
# SearchEngineTool (search the web using text queries)
# ================================================
elif tool_call.function.name == SearchEngineTool['function']['name']:
if 'query' not in arguments:
raise FunctionCallNotExistsError(
f'Missing required argument "query" in tool call {tool_call.function.name}'
)
action = SearchAction(query=arguments['query'])
else:
raise FunctionCallNotExistsError(
f'Tool {tool_call.function.name} is not registered. (arguments: {arguments}). Please check the tool name and retry with an existing tool.'
@@ -223,6 +234,7 @@ def get_tools(
codeact_enable_browsing: bool = False,
codeact_enable_llm_editor: bool = False,
codeact_enable_jupyter: bool = False,
codeact_enable_search_engine: bool = False,
llm: LLM | None = None,
) -> list[ChatCompletionToolParam]:
SIMPLIFIED_TOOL_DESCRIPTION_LLM_SUBSTRS = ['gpt-', 'o3', 'o1']
@@ -239,6 +251,8 @@ def get_tools(
ThinkTool,
FinishTool,
]
if codeact_enable_search_engine:
tools.append(SearchEngineTool)
if codeact_enable_browsing:
tools.append(WebReadTool)
tools.append(BrowserTool)

View File

@@ -3,6 +3,7 @@ from .browser import BrowserTool
from .finish import FinishTool
from .ipython import IPythonTool
from .llm_based_edit import LLMBasedFileEditTool
from .search_engine import SearchEngineTool
from .str_replace_editor import create_str_replace_editor_tool
from .think import ThinkTool
from .web_read import WebReadTool
@@ -13,6 +14,7 @@ __all__ = [
'FinishTool',
'IPythonTool',
'LLMBasedFileEditTool',
'SearchEngineTool',
'create_str_replace_editor_tool',
'WebReadTool',
'ThinkTool',

View File

@@ -0,0 +1,24 @@
from litellm import ChatCompletionToolParam, ChatCompletionToolParamFunctionChunk
_SEARCH_ENGINE_DESCRIPTION = """Execute a web search query (similar to Google search).
NOTE: When you need to search for information online, please use the `search_engine` tool rather than the `browser` or `web_read` tools. The `search_engine` tool connects directly to a search engine, which will help avoid CAPTCHA challenges that would otherwise block your access.
"""
SearchEngineTool = ChatCompletionToolParam(
type='function',
function=ChatCompletionToolParamFunctionChunk(
name='search_engine',
description=_SEARCH_ENGINE_DESCRIPTION,
parameters={
'type': 'object',
'properties': {
'query': {
'type': 'string',
'description': 'The web search query (must be a non-empty string).',
},
},
'required': ['query'],
},
),
)

View File

@@ -8,6 +8,7 @@ from openhands.core.config.config_utils import (
from openhands.core.config.extended_config import ExtendedConfig
from openhands.core.config.llm_config import LLMConfig
from openhands.core.config.sandbox_config import SandboxConfig
from openhands.core.config.search_config import SearchConfig
from openhands.core.config.security_config import SecurityConfig
from openhands.core.config.utils import (
finalize_config,
@@ -28,6 +29,7 @@ __all__ = [
'AppConfig',
'LLMConfig',
'SandboxConfig',
'SearchConfig',
'SecurityConfig',
'ExtendedConfig',
'load_app_config',

View File

@@ -2,7 +2,10 @@ from __future__ import annotations
from pydantic import BaseModel, Field, ValidationError
from openhands.core.config.condenser_config import CondenserConfig, NoOpCondenserConfig
from openhands.core.config.condenser_config import (
CondenserConfig,
NoOpCondenserConfig,
)
from openhands.core.logger import openhands_logger as logger
@@ -30,6 +33,7 @@ class AgentConfig(BaseModel):
disabled_microagents: list[str] = Field(default_factory=list)
enable_history_truncation: bool = Field(default=True)
enable_som_visual_browsing: bool = Field(default=False)
enable_search_engine: bool = Field(default=False)
condenser: CondenserConfig = Field(default_factory=NoOpCondenserConfig)
model_config = {'extra': 'forbid'}

View File

@@ -12,6 +12,7 @@ from openhands.core.config.config_utils import (
from openhands.core.config.extended_config import ExtendedConfig
from openhands.core.config.llm_config import LLMConfig
from openhands.core.config.sandbox_config import SandboxConfig
from openhands.core.config.search_config import SearchConfig
from openhands.core.config.security_config import SecurityConfig
@@ -53,6 +54,7 @@ class AppConfig(BaseModel):
default_agent: str = Field(default=OH_DEFAULT_AGENT)
sandbox: SandboxConfig = Field(default_factory=SandboxConfig)
security: SecurityConfig = Field(default_factory=SecurityConfig)
search: SearchConfig = Field(default_factory=SearchConfig)
extended: ExtendedConfig = Field(default_factory=lambda: ExtendedConfig({}))
runtime: str = Field(default='docker')
file_store: str = Field(default='local')

View File

@@ -0,0 +1,35 @@
"""Configuration for search engine functionality."""
import os
from typing import Any
from pydantic import BaseModel, Field, SecretStr
class SearchConfig(BaseModel):
"""Configuration for search engine functionality.
Attributes:
enabled: Whether search engine functionality is enabled.
api_key: The API key for the search engine.
api_url: The base URL for the search API.
"""
enabled: bool = Field(default=False)
api_key: SecretStr | None = Field(default=None)
api_url: str = Field(default="https://api.search.brave.com/res/v1/web/search")
model_config = {"extra": "forbid"}
def model_post_init(self, __context: Any) -> None:
"""Post-initialization hook to assign search-related variables to environment variables.
This ensures that these values are accessible to the search engine at runtime.
"""
super().model_post_init(__context)
# Set environment variables for search engine
if self.api_key:
os.environ["BRAVE_API_KEY"] = self.api_key.get_secret_value()
if self.api_url:
os.environ["BRAVE_API_URL"] = self.api_url

View File

@@ -82,6 +82,9 @@ class ActionTypeSchema(BaseModel):
SEND_PR: str = Field(default='send_pr')
"""Send a PR to github."""
SEARCH: str = Field(default='search')
"""Queries a search engine."""
RECALL: str = Field(default='recall')
"""Retrieves content from a user workspace, microagent, or other source."""

View File

@@ -49,6 +49,9 @@ class ObservationTypeSchema(BaseModel):
CONDENSE: str = Field(default='condense')
"""Result of a condensation operation."""
SEARCH: str = Field(default='search')
"""Result of querying a search engine."""
RECALL: str = Field(default='recall')
"""Result of a recall operation. This can be the workspace context, a microagent, or other types of information."""

View File

@@ -17,6 +17,7 @@ from openhands.events.action.files import (
FileWriteAction,
)
from openhands.events.action.message import MessageAction
from openhands.events.action.search_engine import SearchAction
__all__ = [
'Action',
@@ -36,5 +37,6 @@ __all__ = [
'MessageAction',
'ActionConfirmationStatus',
'AgentThinkAction',
'SearchAction',
'RecallAction',
]

View File

@@ -0,0 +1,24 @@
from dataclasses import dataclass
from typing import ClassVar
from openhands.core.schema import ActionType
from openhands.events.action.action import Action
@dataclass
class SearchAction(Action):
query: str
thought: str = ''
action: str = ActionType.SEARCH
runnable: ClassVar[bool] = True
@property
def message(self) -> str:
return f'I am querying the search engine to search for {self.query}'
def __str__(self) -> str:
ret = '**SearchAction**\n'
if self.thought:
ret += f'THOUGHT: {self.thought}\n'
ret += f'QUERY: {self.query}'
return ret

View File

@@ -5,6 +5,7 @@ from openhands.events.observation.agent import (
AgentThinkObservation,
RecallObservation,
)
from openhands.events.observation.search_engine import SearchEngineObservation
from openhands.events.observation.browse import BrowserOutputObservation
from openhands.events.observation.commands import (
CmdOutputMetadata,
@@ -42,6 +43,7 @@ __all__ = [
'SuccessObservation',
'UserRejectObservation',
'AgentCondensationObservation',
'SearchEngineObservation',
'RecallObservation',
'RecallType',
]

View File

@@ -0,0 +1,22 @@
from dataclasses import dataclass
from openhands.core.schema import ObservationType
from openhands.events.observation.observation import Observation
@dataclass
class SearchEngineObservation(Observation):
query: str
observation: str = ObservationType.SEARCH
@property
def message(self) -> str:
return f'Searched for: {self.query}'
def __str__(self) -> str:
ret = (
'**SearchEngineObservation**\n'
f'Query: {self.query}\n'
f'Search Results: {self.content}\n'
)
return ret

View File

@@ -22,6 +22,7 @@ from openhands.events.action.files import (
FileWriteAction,
)
from openhands.events.action.message import MessageAction
from openhands.events.action.search_engine import SearchAction
actions = (
NullAction,
@@ -39,6 +40,7 @@ actions = (
RecallAction,
ChangeAgentStateAction,
MessageAction,
SearchAction,
)
ACTION_TYPE_TO_CLASS = {action_class.action: action_class for action_class in actions} # type: ignore[attr-defined]

View File

@@ -27,6 +27,7 @@ from openhands.events.observation import (
FileEditObservation,
FileReadObservation,
IPythonRunCellObservation,
SearchEngineObservation,
UserRejectObservation,
)
from openhands.events.observation.agent import (
@@ -385,6 +386,9 @@ class ConversationMemory:
elif isinstance(obs, AgentCondensationObservation):
text = truncate_content(obs.content, max_message_chars)
message = Message(role='user', content=[TextContent(text=text)])
elif isinstance(obs, SearchEngineObservation):
text = truncate_content(obs.content, max_message_chars)
message = Message(role='user', content=[TextContent(text=text)])
elif (
isinstance(obs, RecallObservation)
and self.agent_config.enable_prompt_extensions

View File

@@ -41,6 +41,7 @@ from openhands.events.action import (
FileReadAction,
FileWriteAction,
IPythonRunCellAction,
SearchAction,
)
from openhands.events.event import FileEditSource, FileReadSource
from openhands.events.observation import (
@@ -56,6 +57,7 @@ from openhands.events.serialization import event_from_dict, event_to_dict
from openhands.runtime.browser import browse
from openhands.runtime.browser.browser_env import BrowserEnv
from openhands.runtime.plugins import ALL_PLUGINS, JupyterPlugin, Plugin, VSCodePlugin
from openhands.runtime.search_engine.brave_search import search
from openhands.runtime.utils.bash import BashSession
from openhands.runtime.utils.files import insert_lines, read_lines
from openhands.runtime.utils.memory_monitor import MemoryMonitor
@@ -163,7 +165,6 @@ class ActionExecutor:
self.start_time = time.time()
self.last_execution_time = self.start_time
self._initialized = False
self.max_memory_gb: int | None = None
if _override_max_memory_gb := os.environ.get('RUNTIME_MAX_MEMORY_GB', None):
self.max_memory_gb = int(_override_max_memory_gb)
@@ -464,6 +465,10 @@ class ActionExecutor:
async def browse_interactive(self, action: BrowseInteractiveAction) -> Observation:
return await browse(action, self.browser)
async def search(self, action: SearchAction) -> Observation:
obs = await call_sync_from_async(search, action)
return obs
def close(self):
self.memory_monitor.stop_monitoring()
if self.bash_session is not None:

View File

@@ -24,6 +24,7 @@ from openhands.events.action import (
FileReadAction,
FileWriteAction,
IPythonRunCellAction,
SearchAction,
)
from openhands.events.action.action import Action
from openhands.events.action.files import FileEditSource
@@ -297,6 +298,9 @@ class ActionExecutionClient(Runtime):
def browse_interactive(self, action: BrowseInteractiveAction) -> Observation:
return self.send_action_for_execution(action)
def search(self, action: SearchAction) -> Observation:
return self.send_action_for_execution(action)
def close(self) -> None:
# Make sure we don't close the session multiple times
# Can happen in evaluation

View File

@@ -0,0 +1,3 @@
from openhands.runtime.search_engine.brave_search import search
__all__ = ['search']

View File

@@ -0,0 +1,239 @@
import os
import re
import requests
import tenacity
from openhands.core.config import AppConfig
from openhands.events.action import SearchAction
from openhands.events.observation.error import ErrorObservation
from openhands.events.observation.search_engine import SearchEngineObservation
from openhands.utils.tenacity_stop import stop_if_should_exit
def get_title(result):
return f"### Title: {result['title']}\n" if 'title' in result else ''
def get_url(result):
return f"### URL: {result['url']}\n" if 'url' in result else ''
def get_description(result):
return (
f"### Description: {result['description']}\n" if 'description' in result else ''
)
def get_question(result):
return f"### Question: {result['question']}\n" if 'question' in result else ''
def get_answer(result):
return f"### Answer: {result['answer']}\n" if 'answer' in result else ''
def get_cluster(result):
if 'cluster' in result:
output = ''
for i, result_obj in enumerate(result['cluster']):
title = get_title(result_obj)
url = get_url(result_obj)
description = get_description(result_obj)
discussion_output = (
f'### Related webpage\n#{title}#{url}#{description}\n'
if url != ''
else ''
)
output += discussion_output
return output
else:
return ''
def response_to_markdown(results, query):
all_results = {}
# discussions
discussion_results = []
if 'discussions' in results and 'results' in results['discussions']['results']:
for result in results['discussions']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
cluster = get_cluster(result)
discussion_output = f'## Discussion\n{title}{url}{description}{cluster}\n'
discussion_results.append(discussion_output)
all_results['discussions'] = discussion_results
# FAQs
faq_results = []
if 'faq' in results and 'results' in results['faq']:
for result in results['faq']['results']:
title = get_title(result)
url = get_url(result)
question = get_question(result)
answer = get_answer(result)
faq_output = f'## FAQ\n{title}{url}{question}{answer}\n'
faq_results.append(faq_output)
all_results['faq'] = faq_results
# News
news_results = []
if 'news' in results and 'results' in results['news']:
for result in results['news']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
news_output = f'## News\n{title}{url}{description}\n'
news_results.append(news_output)
all_results['news'] = news_results
# Videos
video_results = []
if 'videos' in results and 'results' in results['videos']:
for result in results['videos']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
video_output = f'## Video\n{title}{url}{description}\n'
video_results.append(video_output)
all_results['videos'] = video_results
# Web Search Results
websearch_results = []
if 'web' in results and 'results' in results['web']:
for result in results['web']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
cluster = get_cluster(result)
if cluster:
websearch_output = f'## Webpage\n{title}{url}{description}\n{cluster}\n'
else:
websearch_output = f'## Webpage\n{title}{url}{description}\n'
websearch_results.append(websearch_output)
all_results['web'] = websearch_results
# infobox
infobox_results = []
if 'infobox' in results and 'results' in results['infobox']:
for result in results['infobox']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
infobox_output = f'## Infobox\n{title}{url}{description}\n'
infobox_results.append(infobox_output)
all_results['infobox'] = infobox_results
# locations
location_results = []
if 'locations' in results and 'results' in results['location']:
for result in results['locations']['results']:
title = get_title(result)
url = get_url(result)
description = get_description(result)
location_output = f'## Location\n{title}{url}{description}\n'
location_results.append(location_output)
all_results['locations'] = location_results
markdown = '# Search Results\n\n'
markdown += f'**Searched query**: {query}\n\n'
# ranked results if available
if 'mixed' in results:
for rank_type in ['main', 'top', 'side']:
if rank_type not in results['mixed']:
continue
for ranked_result in results['mixed'][rank_type]:
result_type = ranked_result['type']
if result_type in all_results:
include_all = ranked_result['all']
idx = ranked_result.get('index', None)
if include_all:
markdown += ''.join(all_results[result_type])
elif idx is not None and idx < len(all_results[result_type]):
markdown += all_results[result_type][idx]
for result_list in all_results.values():
for result in result_list:
if result in markdown:
continue
else:
markdown += result
else:
markdown += ''.join(
websearch_results
+ video_results
+ news_results
+ infobox_results
+ faq_results
+ discussion_results
+ location_results
)
return markdown
def return_error(retry_state: tenacity.RetryCallState):
return ErrorObservation('Failed to query Brave Search API.')
@tenacity.retry(
wait=tenacity.wait_exponential(min=2, max=10),
stop=tenacity.stop_after_attempt(5) | stop_if_should_exit(),
retry_error_callback=return_error,
)
def query_api(query: str, API_KEY, BRAVE_SEARCH_URL):
headers = {'Accept': 'application/json', 'X-Subscription-Token': API_KEY}
params: list[tuple[str, str | int | bool]] = [
('q', query),
('count', 20), # Number of results to return, max allowed = 20
('extra_snippets', False), # TODO: Should we keep it as true?
]
response = requests.get(
BRAVE_SEARCH_URL,
headers=headers,
params=params, # type: ignore
timeout=10,
)
response.raise_for_status() # Raise exception for 4XX/5XX responses
results = response.json()
markdown_content = response_to_markdown(results, query)
# TODO: Handle other types of HTML tags? I couldn't find any other tags in brave search responses for the queries I tried.
markdown_content = re.sub(r'</?strong>', '', markdown_content)
return SearchEngineObservation(query=query, content=markdown_content)
def search(action: SearchAction, config: AppConfig):
"""Execute a search query using the Brave Search API.
Args:
action: The search action containing the query.
config: The application configuration.
Returns:
SearchEngineObservation: The search results in markdown format.
ErrorObservation: If the query is empty or search is not enabled.
"""
if not config.search.enabled:
return ErrorObservation(
content='Search engine functionality is not enabled. Enable it by setting search.enabled=true in config.'
)
query = action.query
if query is None or len(query.strip()) == 0:
return ErrorObservation(
content='The query string for search_engine tool must be a non-empty string.'
)
if config.search.api_key is None:
return ErrorObservation(
content='Search API key not configured. Set search.api_key in config.'
)
return query_api(
query=query,
API_KEY=config.search.api_key.get_secret_value(),
BRAVE_SEARCH_URL=config.search.api_url
)

View File

@@ -0,0 +1,83 @@
"""Tests for the Brave Search functionality."""
from unittest.mock import Mock, patch
import pytest
from openhands.core.config import AppConfig, SearchConfig
from openhands.events.action import SearchAction
from openhands.events.observation.error import ErrorObservation
from openhands.events.observation.search_engine import SearchEngineObservation
from openhands.runtime.search_engine.brave_search import search
@pytest.fixture
def mock_config():
"""Create a mock config with search enabled."""
config = AppConfig()
config.search = SearchConfig(
enabled=True,
api_key="test_key",
api_url="https://test.url"
)
return config
@pytest.fixture
def mock_query_api():
"""Create a mock query_api function."""
with patch("openhands.runtime.search_engine.brave_search.query_api") as mock:
mock.return_value = SearchEngineObservation(
query="test query",
content="test content"
)
yield mock
def test_search_disabled(mock_query_api):
"""Test that search returns error when disabled."""
config = AppConfig()
config.search = SearchConfig(enabled=False)
action = SearchAction(query="test query")
result = search(action, config)
assert isinstance(result, ErrorObservation)
assert "not enabled" in result.content
mock_query_api.assert_not_called()
def test_search_no_api_key(mock_query_api):
"""Test that search returns error when API key is not set."""
config = AppConfig()
config.search = SearchConfig(enabled=True)
action = SearchAction(query="test query")
result = search(action, config)
assert isinstance(result, ErrorObservation)
assert "API key not configured" in result.content
mock_query_api.assert_not_called()
def test_search_empty_query(mock_query_api, mock_config):
"""Test that search returns error when query is empty."""
action = SearchAction(query="")
result = search(action, mock_config)
assert isinstance(result, ErrorObservation)
assert "must be a non-empty string" in result.content
mock_query_api.assert_not_called()
def test_search_success(mock_query_api, mock_config):
"""Test that search returns results when everything is configured correctly."""
action = SearchAction(query="test query")
result = search(action, mock_config)
assert isinstance(result, SearchEngineObservation)
assert result.query == "test query"
assert result.content == "test content"
mock_query_api.assert_called_once_with(
query="test query",
API_KEY="test_key",
BRAVE_SEARCH_URL="https://test.url"
)

View File

@@ -25,6 +25,7 @@ from openhands.core.message import ImageContent, Message, TextContent
from openhands.events.action import (
CmdRunAction,
MessageAction,
SearchAction,
)
from openhands.events.event import EventSource
from openhands.events.observation.commands import (
@@ -100,22 +101,26 @@ def test_get_tools_with_options():
codeact_enable_browsing=True,
codeact_enable_jupyter=True,
codeact_enable_llm_editor=True,
codeact_enable_search_engine=True,
)
tool_names = [tool['function']['name'] for tool in tools]
assert 'browser' in tool_names
assert 'execute_ipython_cell' in tool_names
assert 'edit_file' in tool_names
assert 'search_engine' in tool_names
# Test with all options disabled
tools = get_tools(
codeact_enable_browsing=False,
codeact_enable_jupyter=False,
codeact_enable_llm_editor=False,
codeact_enable_search_engine=False,
)
tool_names = [tool['function']['name'] for tool in tools]
assert 'browser' not in tool_names
assert 'execute_ipython_cell' not in tool_names
assert 'edit_file' not in tool_names
assert 'search_engine' not in tool_names
def test_cmd_run_tool():
@@ -176,6 +181,15 @@ def test_web_read_tool():
assert WebReadTool['function']['parameters']['required'] == ['url']
def test_search_engine_tool():
from openhands.agenthub.codeact_agent.tools import SearchEngineTool
assert SearchEngineTool['type'] == 'function'
assert SearchEngineTool['function']['name'] == 'search_engine'
assert 'query' in SearchEngineTool['function']['parameters']['properties']
assert SearchEngineTool['function']['parameters']['required'] == ['query']
def test_browser_tool():
assert BrowserTool['type'] == 'function'
assert BrowserTool['function']['name'] == 'browser'
@@ -212,6 +226,42 @@ def test_browser_tool():
assert 'description' in BrowserTool['function']['parameters']['properties']['code']
def test_response_to_actions_search_engine():
# Test response with search engine tool call
from litellm import ChatCompletionMessageToolCall, Choices, Message, ModelResponse
mock_response = ModelResponse(
id='mock_id',
choices=[
Choices(
message=Message(
content='Let me search for that',
tool_calls=[
ChatCompletionMessageToolCall(
id='tool_call_10',
function={
'name': 'search_engine',
'arguments': '{"query": "test query"}',
},
type='function',
)
],
role='assistant',
),
index=0,
finish_reason='tool_calls',
)
],
model='mock_model',
usage={'total_tokens': 100},
)
actions = response_to_actions(mock_response)
assert len(actions) == 1
assert isinstance(actions[0], SearchAction)
assert actions[0].query == 'test query'
def test_response_to_actions_invalid_tool():
# Test response with invalid tool call
mock_response = Mock()