Spaces:
Build error
Build error
Upload 964 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +13 -0
- CITATION.cff +55 -0
- CODE_OF_CONDUCT.md +147 -0
- COMMUNITY.md +43 -0
- CONTRIBUTING.md +123 -0
- CREDITS.md +312 -0
- Development.md +181 -0
- ISSUE_TRIAGE.md +27 -0
- LICENSE.txt +25 -0
- MANIFEST.in +5 -0
- Makefile.make +335 -0
- README.md +146 -9
- README_CN.md +146 -0
- build.sh +4 -0
- config.template.toml +417 -0
- containers/README.md +12 -0
- containers/app/Dockerfile +98 -0
- containers/app/config.sh +4 -0
- containers/app/entrypoint.sh +61 -0
- containers/build.sh +182 -0
- containers/dev/Dockerfile +124 -0
- containers/dev/README.md +57 -0
- containers/dev/compose.yml +38 -0
- containers/dev/dev.sh +39 -0
- containers/e2b-sandbox/Dockerfile +19 -0
- containers/e2b-sandbox/README.md +15 -0
- containers/e2b-sandbox/e2b.toml +14 -0
- containers/runtime/README.md +12 -0
- containers/runtime/config.sh +7 -0
- dev_config/python/mypy.ini +9 -0
- dev_config/python/ruff.toml +39 -0
- docker-compose.yml +23 -0
- docs/DOC_STYLE_GUIDE.md +67 -0
- docs/docs.json +204 -0
- docs/favicon.svg +19 -0
- docs/index.mdx +16 -0
- docs/logo-square.png +3 -0
- docs/logo/dark.svg +29 -0
- docs/logo/light.svg +29 -0
- docs/openapi.json +2091 -0
- docs/static/img/backend_architecture.png +3 -0
- docs/static/img/backend_architecture.puml +201 -0
- docs/static/img/backend_architecture.svg +0 -0
- docs/static/img/connect-repo.png +0 -0
- docs/static/img/docs/api-key-generation.png +0 -0
- docs/static/img/logo-square.png +3 -0
- docs/static/img/logo.png +0 -0
- docs/static/img/oh-features.png +3 -0
- docs/static/img/results.png +3 -0
- docs/static/img/screenshot.png +3 -0
.gitattributes
CHANGED
@@ -33,3 +33,16 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
docs/logo-square.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
docs/static/img/backend_architecture.png filter=lfs diff=lfs merge=lfs -text
|
38 |
+
docs/static/img/logo-square.png filter=lfs diff=lfs merge=lfs -text
|
39 |
+
docs/static/img/oh-features.png filter=lfs diff=lfs merge=lfs -text
|
40 |
+
docs/static/img/results.png filter=lfs diff=lfs merge=lfs -text
|
41 |
+
docs/static/img/screenshot.png filter=lfs diff=lfs merge=lfs -text
|
42 |
+
docs/static/img/system_architecture_overview.png filter=lfs diff=lfs merge=lfs -text
|
43 |
+
docs/static/img/teaser.mp4 filter=lfs diff=lfs merge=lfs -text
|
44 |
+
docs/usage/llms/screenshots/1_select_power_user.png filter=lfs diff=lfs merge=lfs -text
|
45 |
+
docs/usage/llms/screenshots/2_select_model.png filter=lfs diff=lfs merge=lfs -text
|
46 |
+
docs/usage/llms/screenshots/4_set_context_window.png filter=lfs diff=lfs merge=lfs -text
|
47 |
+
docs/usage/llms/screenshots/5_copy_url.png filter=lfs diff=lfs merge=lfs -text
|
48 |
+
evaluation/static/example_task_1.png filter=lfs diff=lfs merge=lfs -text
|
CITATION.cff
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cff-version: 1.2.0
|
2 |
+
message: "If you use this software, please cite it using the following metadata."
|
3 |
+
title: "OpenHands: An Open Platform for AI Software Developers as Generalist Agents"
|
4 |
+
authors:
|
5 |
+
- family-names: Wang
|
6 |
+
given-names: Xingyao
|
7 |
+
- family-names: Li
|
8 |
+
given-names: Boxuan
|
9 |
+
- family-names: Song
|
10 |
+
given-names: Yufan
|
11 |
+
- family-names: Xu
|
12 |
+
given-names: Frank F.
|
13 |
+
- family-names: Tang
|
14 |
+
given-names: Xiangru
|
15 |
+
- family-names: Zhuge
|
16 |
+
given-names: Mingchen
|
17 |
+
- family-names: Pan
|
18 |
+
given-names: Jiayi
|
19 |
+
- family-names: Song
|
20 |
+
given-names: Yueqi
|
21 |
+
- family-names: Li
|
22 |
+
given-names: Bowen
|
23 |
+
- family-names: Singh
|
24 |
+
given-names: Jaskirat
|
25 |
+
- family-names: Tran
|
26 |
+
given-names: Hoang H.
|
27 |
+
- family-names: Li
|
28 |
+
given-names: Fuqiang
|
29 |
+
- family-names: Ma
|
30 |
+
given-names: Ren
|
31 |
+
- family-names: Zheng
|
32 |
+
given-names: Mingzhang
|
33 |
+
- family-names: Qian
|
34 |
+
given-names: Bill
|
35 |
+
- family-names: Shao
|
36 |
+
given-names: Yanjun
|
37 |
+
- family-names: Muennighoff
|
38 |
+
given-names: Niklas
|
39 |
+
- family-names: Zhang
|
40 |
+
given-names: Yizhe
|
41 |
+
- family-names: Hui
|
42 |
+
given-names: Binyuan
|
43 |
+
- family-names: Lin
|
44 |
+
given-names: Junyang
|
45 |
+
- family-names: Brennan
|
46 |
+
given-names: Robert
|
47 |
+
- family-names: Peng
|
48 |
+
given-names: Hao
|
49 |
+
- family-names: Ji
|
50 |
+
given-names: Heng
|
51 |
+
- family-names: Neubig
|
52 |
+
given-names: Graham
|
53 |
+
year: 2024
|
54 |
+
doi: "10.48550/arXiv.2407.16741"
|
55 |
+
url: "https://arxiv.org/abs/2407.16741"
|
CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
# Contributor Covenant Code of Conduct
|
3 |
+
|
4 |
+
## Our Pledge
|
5 |
+
|
6 |
+
We as members, contributors, and leaders pledge to make participation in our
|
7 |
+
community a harassment-free experience for everyone, regardless of age, body
|
8 |
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
9 |
+
identity and expression, level of experience, education, socio-economic status,
|
10 |
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
11 |
+
identity and orientation.
|
12 |
+
|
13 |
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
14 |
+
diverse, inclusive, and healthy community.
|
15 |
+
|
16 |
+
## Our Standards
|
17 |
+
|
18 |
+
Examples of behavior that contributes to a positive environment for our
|
19 |
+
community include:
|
20 |
+
|
21 |
+
* Demonstrating empathy and kindness toward other people.
|
22 |
+
* Being respectful of differing opinions, viewpoints, and experiences.
|
23 |
+
* Giving and gracefully accepting constructive feedback.
|
24 |
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
25 |
+
and learning from the experience.
|
26 |
+
* Focusing on what is best not just for us as individuals, but for the overall
|
27 |
+
community.
|
28 |
+
|
29 |
+
Examples of unacceptable behavior include:
|
30 |
+
|
31 |
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
32 |
+
any kind.
|
33 |
+
* Trolling, insulting or derogatory comments, and personal or political attacks.
|
34 |
+
* Public or private harassment.
|
35 |
+
* Publishing others' private information, such as a physical or email address,
|
36 |
+
without their explicit permission.
|
37 |
+
* Other conduct which could reasonably be considered inappropriate in a
|
38 |
+
professional setting.
|
39 |
+
|
40 |
+
## Enforcement Responsibilities
|
41 |
+
|
42 |
+
Community leaders are responsible for clarifying and enforcing our standards of
|
43 |
+
acceptable behavior and will take appropriate and fair corrective action in
|
44 |
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
45 |
+
or harmful.
|
46 |
+
|
47 |
+
Community leaders have the right and responsibility to remove, edit, or reject
|
48 |
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
49 |
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
50 |
+
decisions when appropriate.
|
51 |
+
|
52 |
+
## Scope
|
53 |
+
|
54 |
+
This Code of Conduct applies within all community spaces, and also applies when
|
55 |
+
an individual is officially representing the community in public spaces.
|
56 |
+
Examples of representing our community include using an official email address,
|
57 |
+
posting via an official social media account, or acting as an appointed
|
58 |
+
representative at an online or offline event.
|
59 |
+
|
60 |
+
## Enforcement
|
61 |
+
|
62 |
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
63 |
+
reported to the community leaders responsible for enforcement at
|
64 | |
65 |
+
All complaints will be reviewed and investigated promptly and fairly.
|
66 |
+
|
67 |
+
All community leaders are obligated to respect the privacy and security of the
|
68 |
+
reporter of any incident.
|
69 |
+
|
70 |
+
## Enforcement Guidelines
|
71 |
+
|
72 |
+
Community leaders will follow these Community Impact Guidelines in determining
|
73 |
+
the consequences for any action they deem in violation of this Code of Conduct:
|
74 |
+
|
75 |
+
### 1. Correction
|
76 |
+
|
77 |
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
78 |
+
unprofessional or unwelcome in the community.
|
79 |
+
|
80 |
+
**Consequence**: A private, written warning from community leaders, providing
|
81 |
+
clarity around the nature of the violation and an explanation of why the
|
82 |
+
behavior was inappropriate. A public apology may be requested.
|
83 |
+
|
84 |
+
### 2. Warning
|
85 |
+
|
86 |
+
**Community Impact**: A violation through a single incident or series of
|
87 |
+
actions.
|
88 |
+
|
89 |
+
**Consequence**: A warning with consequences for continued behavior. No
|
90 |
+
interaction with the people involved, including unsolicited interaction with
|
91 |
+
those enforcing the Code of Conduct, for a specified period of time. This
|
92 |
+
includes avoiding interactions in community spaces as well as external channels
|
93 |
+
like social media. Violating these terms may lead to a temporary or permanent
|
94 |
+
ban.
|
95 |
+
|
96 |
+
### 3. Temporary Ban
|
97 |
+
|
98 |
+
**Community Impact**: A serious violation of community standards, including
|
99 |
+
sustained inappropriate behavior.
|
100 |
+
|
101 |
+
**Consequence**: A temporary ban from any sort of interaction or public
|
102 |
+
communication with the community for a specified period of time. No public or
|
103 |
+
private interaction with the people involved, including unsolicited interaction
|
104 |
+
with those enforcing the Code of Conduct, is allowed during this period.
|
105 |
+
Violating these terms may lead to a permanent ban.
|
106 |
+
|
107 |
+
### 4. Permanent Ban
|
108 |
+
|
109 |
+
**Community Impact**: Demonstrating a pattern of violation of community
|
110 |
+
standards, including sustained inappropriate behavior, harassment of an
|
111 |
+
individual, or aggression toward or disparagement of classes of individuals.
|
112 |
+
|
113 |
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
114 |
+
community.
|
115 |
+
|
116 |
+
### Slack and Discord Etiquettes
|
117 |
+
|
118 |
+
These Slack and Discord etiquette guidelines are designed to foster an inclusive, respectful, and productive environment for all community members. By following these best practices, we ensure effective communication and collaboration while minimizing disruptions. Let’s work together to build a supportive and welcoming community!
|
119 |
+
|
120 |
+
- Communicate respectfully and professionally, avoiding sarcasm or harsh language, and remember that tone can be difficult to interpret in text.
|
121 |
+
- Use threads for specific discussions to keep channels organized and easier to follow.
|
122 |
+
- Tag others only when their input is critical or urgent, and use @here, @channel or @everyone sparingly to minimize disruptions.
|
123 |
+
- Be patient, as open-source contributors and maintainers often have other commitments and may need time to respond.
|
124 |
+
- Post questions or discussions in the most relevant channel (e.g., for [slack - #general](https://openhands-ai.slack.com/archives/C06P5NCGSFP) for general topics, [slack - #questions](https://openhands-ai.slack.com/archives/C06U8UTKSAD) for queries/questions, [discord - #general](https://discord.com/channels/1222935860639563850/1222935861386018885)).
|
125 |
+
- When asking for help or raising issues, include necessary details like links, screenshots, or clear explanations to provide context.
|
126 |
+
- Keep discussions in public channels whenever possible to allow others to benefit from the conversation, unless the matter is sensitive or private.
|
127 |
+
- Always adhere to [our standards](https://github.com/All-Hands-AI/OpenHands/blob/main/CODE_OF_CONDUCT.md#our-standards) to ensure a welcoming and collaborative environment.
|
128 |
+
- If you choose to mute a channel, consider setting up alerts for topics that still interest you to stay engaged. For Slack, Go to Settings → Notifications → My Keywords to add specific keywords that will notify you when mentioned. For example, if you're here for discussions about LLMs, mute the channel if it’s too busy, but set notifications to alert you only when “LLMs” appears in messages. Also for Discord, go to the channel notifications and choose the option that best describes your need.
|
129 |
+
|
130 |
+
## Attribution
|
131 |
+
|
132 |
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
133 |
+
version 2.1, available at
|
134 |
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
135 |
+
|
136 |
+
Community Impact Guidelines were inspired by
|
137 |
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
138 |
+
|
139 |
+
For answers to common questions about this code of conduct, see the FAQ at
|
140 |
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
141 |
+
[https://www.contributor-covenant.org/translations][translations].
|
142 |
+
|
143 |
+
[homepage]: https://www.contributor-covenant.org
|
144 |
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
145 |
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
146 |
+
[FAQ]: https://www.contributor-covenant.org/faq
|
147 |
+
[translations]: https://www.contributor-covenant.org/translations
|
COMMUNITY.md
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 🙌 The OpenHands Community
|
2 |
+
|
3 |
+
The OpenHands community is built around the belief that (1) AI and AI agents are going to fundamentally change the way
|
4 |
+
we build software, and (2) if this is true, we should do everything we can to make sure that the benefits provided by
|
5 |
+
such powerful technology are accessible to everyone.
|
6 |
+
|
7 |
+
If this resonates with you, we'd love to have you join us in our quest!
|
8 |
+
|
9 |
+
## 🤝 How to Join
|
10 |
+
|
11 |
+
Check out our [How to Join the Community section.](https://github.com/All-Hands-AI/OpenHands?tab=readme-ov-file#-how-to-join-the-community)
|
12 |
+
|
13 |
+
## 💪 Becoming a Contributor
|
14 |
+
|
15 |
+
We welcome contributions from everyone! Whether you're a developer, a researcher, or simply enthusiastic about advancing
|
16 |
+
the field of software engineering with AI, there are many ways to get involved:
|
17 |
+
|
18 |
+
- **Code Contributions:** Help us develop new core functionality, improve our agents, improve the frontend and other
|
19 |
+
interfaces, or anything else that would help make OpenHands better.
|
20 |
+
- **Research and Evaluation:** Contribute to our understanding of LLMs in software engineering, participate in
|
21 |
+
evaluating the models, or suggest improvements.
|
22 |
+
- **Feedback and Testing:** Use the OpenHands toolset, report bugs, suggest features, or provide feedback on usability.
|
23 |
+
|
24 |
+
For details, please check [CONTRIBUTING.md](./CONTRIBUTING.md).
|
25 |
+
|
26 |
+
## Code of Conduct
|
27 |
+
|
28 |
+
We have a [Code of Conduct](./CODE_OF_CONDUCT.md) that we expect all contributors to adhere to.
|
29 |
+
Long story short, we are aiming for an open, welcoming, diverse, inclusive, and healthy community.
|
30 |
+
All contributors are expected to contribute to building this sort of community.
|
31 |
+
|
32 |
+
## 🛠️ Becoming a Maintainer
|
33 |
+
|
34 |
+
For contributors who have made significant and sustained contributions to the project, there is a possibility of joining
|
35 |
+
the maintainer team. The process for this is as follows:
|
36 |
+
|
37 |
+
1. Any contributor who has made sustained and high-quality contributions to the codebase can be nominated by any
|
38 |
+
maintainer. If you feel that you may qualify you can reach out to any of the maintainers that have reviewed your PRs and ask if you can be nominated.
|
39 |
+
2. Once a maintainer nominates a new maintainer, there will be a discussion period among the maintainers for at least 3 days.
|
40 |
+
3. If no concerns are raised the nomination will be accepted by acclamation, and if concerns are raised there will be a discussion and possible vote.
|
41 |
+
|
42 |
+
Note that just making many PRs does not immediately imply that you will become a maintainer. We will be looking
|
43 |
+
at sustained high-quality contributions over a period of time, as well as good teamwork and adherence to our [Code of Conduct](./CODE_OF_CONDUCT.md).
|
CONTRIBUTING.md
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Contributing
|
2 |
+
|
3 |
+
Thanks for your interest in contributing to OpenHands! We welcome and appreciate contributions.
|
4 |
+
|
5 |
+
## Understanding OpenHands's CodeBase
|
6 |
+
|
7 |
+
To understand the codebase, please refer to the README in each module:
|
8 |
+
- [frontend](./frontend/README.md)
|
9 |
+
- [evaluation](./evaluation/README.md)
|
10 |
+
- [openhands](./openhands/README.md)
|
11 |
+
- [agenthub](./openhands/agenthub/README.md)
|
12 |
+
- [server](./openhands/server/README.md)
|
13 |
+
|
14 |
+
## Setting up Your Development Environment
|
15 |
+
|
16 |
+
We have a separate doc [Development.md](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md) that tells you how to set up a development workflow.
|
17 |
+
|
18 |
+
## How Can I Contribute?
|
19 |
+
|
20 |
+
There are many ways that you can contribute:
|
21 |
+
|
22 |
+
1. **Download and use** OpenHands, and send [issues](https://github.com/All-Hands-AI/OpenHands/issues) when you encounter something that isn't working or a feature that you'd like to see.
|
23 |
+
2. **Send feedback** after each session by [clicking the thumbs-up thumbs-down buttons](https://docs.all-hands.dev/usage/feedback), so we can see where things are working and failing, and also build an open dataset for training code agents.
|
24 |
+
3. **Improve the Codebase** by sending [PRs](#sending-pull-requests-to-openhands) (see details below). In particular, we have some [good first issues](https://github.com/All-Hands-AI/OpenHands/labels/good%20first%20issue) that may be ones to start on.
|
25 |
+
|
26 |
+
## What Can I Build?
|
27 |
+
Here are a few ways you can help improve the codebase.
|
28 |
+
|
29 |
+
#### UI/UX
|
30 |
+
We're always looking to improve the look and feel of the application. If you've got a small fix
|
31 |
+
for something that's bugging you, feel free to open up a PR that changes the [`./frontend`](./frontend) directory.
|
32 |
+
|
33 |
+
If you're looking to make a bigger change, add a new UI element, or significantly alter the style
|
34 |
+
of the application, please open an issue first, or better, join the #frontend channel in our Slack
|
35 |
+
to gather consensus from our design team first.
|
36 |
+
|
37 |
+
#### Improving the agent
|
38 |
+
Our main agent is the CodeAct agent. You can [see its prompts here](https://github.com/All-Hands-AI/OpenHands/tree/main/openhands/agenthub/codeact_agent).
|
39 |
+
|
40 |
+
Changes to these prompts, and to the underlying behavior in Python, can have a huge impact on user experience.
|
41 |
+
You can try modifying the prompts to see how they change the behavior of the agent as you use the app
|
42 |
+
locally, but we will need to do an end-to-end evaluation of any changes here to ensure that the agent
|
43 |
+
is getting better over time.
|
44 |
+
|
45 |
+
We use the [SWE-bench](https://www.swebench.com/) benchmark to test our agent. You can join the #evaluation
|
46 |
+
channel in Slack to learn more.
|
47 |
+
|
48 |
+
#### Adding a new agent
|
49 |
+
You may want to experiment with building new types of agents. You can add an agent to [`openhands/agenthub`](./openhands/agenthub)
|
50 |
+
to help expand the capabilities of OpenHands.
|
51 |
+
|
52 |
+
#### Adding a new runtime
|
53 |
+
The agent needs a place to run code and commands. When you run OpenHands on your laptop, it uses a Docker container
|
54 |
+
to do this by default. But there are other ways of creating a sandbox for the agent.
|
55 |
+
|
56 |
+
If you work for a company that provides a cloud-based runtime, you could help us add support for that runtime
|
57 |
+
by implementing the [interface specified here](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/runtime/base.py).
|
58 |
+
|
59 |
+
#### Testing
|
60 |
+
When you write code, it is also good to write tests. Please navigate to the [`./tests`](./tests) folder to see existing test suites.
|
61 |
+
At the moment, we have two kinds of tests: [`unit`](./tests/unit) and [`integration`](./evaluation/integration_tests). Please refer to the README for each test suite. These tests also run on GitHub's continuous integration to ensure quality of the project.
|
62 |
+
|
63 |
+
## Sending Pull Requests to OpenHands
|
64 |
+
|
65 |
+
You'll need to fork our repository to send us a Pull Request. You can learn more
|
66 |
+
about how to fork a GitHub repo and open a PR with your changes in [this article](https://medium.com/swlh/forks-and-pull-requests-how-to-contribute-to-github-repos-8843fac34ce8).
|
67 |
+
|
68 |
+
### Pull Request title
|
69 |
+
As described [here](https://github.com/commitizen/conventional-commit-types/blob/master/index.json), a valid PR title should begin with one of the following prefixes:
|
70 |
+
|
71 |
+
- `feat`: A new feature
|
72 |
+
- `fix`: A bug fix
|
73 |
+
- `docs`: Documentation only changes
|
74 |
+
- `style`: Changes that do not affect the meaning of the code (white space, formatting, missing semicolons, etc.)
|
75 |
+
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
76 |
+
- `perf`: A code change that improves performance
|
77 |
+
- `test`: Adding missing tests or correcting existing tests
|
78 |
+
- `build`: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
79 |
+
- `ci`: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
|
80 |
+
- `chore`: Other changes that don't modify src or test files
|
81 |
+
- `revert`: Reverts a previous commit
|
82 |
+
|
83 |
+
For example, a PR title could be:
|
84 |
+
- `refactor: modify package path`
|
85 |
+
- `feat(frontend): xxxx`, where `(frontend)` means that this PR mainly focuses on the frontend component.
|
86 |
+
|
87 |
+
You may also check out previous PRs in the [PR list](https://github.com/All-Hands-AI/OpenHands/pulls).
|
88 |
+
|
89 |
+
### Pull Request description
|
90 |
+
- If your PR is small (such as a typo fix), you can go brief.
|
91 |
+
- If it contains a lot of changes, it's better to write more details.
|
92 |
+
|
93 |
+
If your changes are user-facing (e.g. a new feature in the UI, a change in behavior, or a bugfix)
|
94 |
+
please include a short message that we can add to our changelog.
|
95 |
+
|
96 |
+
## How to Make Effective Contributions
|
97 |
+
|
98 |
+
### Opening Issues
|
99 |
+
|
100 |
+
If you notice any bugs or have any feature requests please open them via the [issues page](https://github.com/All-Hands-AI/OpenHands/issues). We will triage based on how critical the bug is or how potentially useful the improvement is, discuss, and implement the ones that the community has interest/effort for.
|
101 |
+
|
102 |
+
Further, if you see an issue you like, please leave a "thumbs-up" or a comment, which will help us prioritize.
|
103 |
+
|
104 |
+
### Making Pull Requests
|
105 |
+
|
106 |
+
We're generally happy to consider all pull requests with the evaluation process varying based on the type of change:
|
107 |
+
|
108 |
+
#### For Small Improvements
|
109 |
+
|
110 |
+
Small improvements with few downsides are typically reviewed and approved quickly.
|
111 |
+
One thing to check when making changes is to ensure that all continuous integration tests pass, which you can check before getting a review.
|
112 |
+
|
113 |
+
#### For Core Agent Changes
|
114 |
+
|
115 |
+
We need to be more careful with changes to the core agent, as it is imperative to maintain high quality. These PRs are evaluated based on three key metrics:
|
116 |
+
|
117 |
+
1. **Accuracy**
|
118 |
+
2. **Efficiency**
|
119 |
+
3. **Code Complexity**
|
120 |
+
|
121 |
+
If it improves accuracy, efficiency, or both with only a minimal change to code quality, that's great we're happy to merge it in!
|
122 |
+
If there are bigger tradeoffs (e.g. helping efficiency a lot and hurting accuracy a little) we might want to put it behind a feature flag.
|
123 |
+
Either way, please feel free to discuss on github issues or slack, and we will give guidance and preliminary feedback.
|
CREDITS.md
ADDED
@@ -0,0 +1,312 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Credits
|
2 |
+
|
3 |
+
## Contributors
|
4 |
+
|
5 |
+
We would like to thank all the [contributors](https://github.com/All-Hands-AI/OpenHands/graphs/contributors) who have helped make OpenHands possible. We greatly appreciate your dedication and hard work.
|
6 |
+
|
7 |
+
## Open Source Projects
|
8 |
+
|
9 |
+
OpenHands includes and adapts the following open source projects. We are grateful for their contributions to the open source community:
|
10 |
+
|
11 |
+
#### [SWE Agent](https://github.com/princeton-nlp/swe-agent)
|
12 |
+
- License: MIT License
|
13 |
+
- Description: Adapted for use in OpenHands's agent hub
|
14 |
+
|
15 |
+
#### [Aider](https://github.com/paul-gauthier/aider)
|
16 |
+
- License: Apache License 2.0
|
17 |
+
- Description: AI pair programming tool. OpenHands has adapted and integrated its linter module for code-related tasks in [`agentskills utilities`](https://github.com/All-Hands-AI/OpenHands/tree/main/openhands/runtime/plugins/agent_skills/utils/aider)
|
18 |
+
|
19 |
+
#### [BrowserGym](https://github.com/ServiceNow/BrowserGym)
|
20 |
+
- License: Apache License 2.0
|
21 |
+
- Description: Adapted in implementing the browsing agent
|
22 |
+
|
23 |
+
|
24 |
+
### Reference Implementations for Evaluation Benchmarks
|
25 |
+
OpenHands integrates code of the reference implementations for the following agent evaluation benchmarks:
|
26 |
+
|
27 |
+
#### [HumanEval](https://github.com/openai/human-eval)
|
28 |
+
- License: MIT License
|
29 |
+
|
30 |
+
#### [DSP](https://github.com/microsoft/DataScienceProblems)
|
31 |
+
- License: MIT License
|
32 |
+
|
33 |
+
#### [HumanEvalPack](https://github.com/bigcode-project/bigcode-evaluation-harness)
|
34 |
+
- License: Apache License 2.0
|
35 |
+
|
36 |
+
#### [AgentBench](https://github.com/THUDM/AgentBench)
|
37 |
+
- License: Apache License 2.0
|
38 |
+
|
39 |
+
#### [SWE-Bench](https://github.com/princeton-nlp/SWE-bench)
|
40 |
+
- License: MIT License
|
41 |
+
|
42 |
+
#### [BIRD](https://bird-bench.github.io/)
|
43 |
+
- License: MIT License
|
44 |
+
- Dataset: CC-BY-SA 4.0
|
45 |
+
|
46 |
+
#### [Gorilla APIBench](https://github.com/ShishirPatil/gorilla)
|
47 |
+
- License: Apache License 2.0
|
48 |
+
|
49 |
+
#### [GPQA](https://github.com/idavidrein/gpqa)
|
50 |
+
- License: MIT License
|
51 |
+
|
52 |
+
#### [ProntoQA](https://github.com/asaparov/prontoqa)
|
53 |
+
- License: Apache License 2.0
|
54 |
+
|
55 |
+
|
56 |
+
## Open Source licenses
|
57 |
+
|
58 |
+
### MIT License
|
59 |
+
|
60 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
61 |
+
|
62 |
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
63 |
+
|
64 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
65 |
+
|
66 |
+
### BSD 3-Clause License
|
67 |
+
|
68 |
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
69 |
+
|
70 |
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
71 |
+
|
72 |
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
73 |
+
|
74 |
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
75 |
+
|
76 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
77 |
+
|
78 |
+
### Apache License 2.0
|
79 |
+
|
80 |
+
|
81 |
+
Apache License
|
82 |
+
Version 2.0, January 2004
|
83 |
+
http://www.apache.org/licenses/
|
84 |
+
|
85 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
86 |
+
|
87 |
+
1. Definitions.
|
88 |
+
|
89 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
90 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
91 |
+
|
92 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
93 |
+
the copyright owner that is granting the License.
|
94 |
+
|
95 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
96 |
+
other entities that control, are controlled by, or are under common
|
97 |
+
control with that entity. For the purposes of this definition,
|
98 |
+
"control" means (i) the power, direct or indirect, to cause the
|
99 |
+
direction or management of such entity, whether by contract or
|
100 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
101 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
102 |
+
|
103 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
104 |
+
exercising permissions granted by this License.
|
105 |
+
|
106 |
+
"Source" form shall mean the preferred form for making modifications,
|
107 |
+
including but not limited to software source code, documentation
|
108 |
+
source, and configuration files.
|
109 |
+
|
110 |
+
"Object" form shall mean any form resulting from mechanical
|
111 |
+
transformation or translation of a Source form, including but
|
112 |
+
not limited to compiled object code, generated documentation,
|
113 |
+
and conversions to other media types.
|
114 |
+
|
115 |
+
"Work" shall mean the work of authorship, whether in Source or
|
116 |
+
Object form, made available under the License, as indicated by a
|
117 |
+
copyright notice that is included in or attached to the work
|
118 |
+
(an example is provided in the Appendix below).
|
119 |
+
|
120 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
121 |
+
form, that is based on (or derived from) the Work and for which the
|
122 |
+
editorial revisions, annotations, elaborations, or other modifications
|
123 |
+
represent, as a whole, an original work of authorship. For the purposes
|
124 |
+
of this License, Derivative Works shall not include works that remain
|
125 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
126 |
+
the Work and Derivative Works thereof.
|
127 |
+
|
128 |
+
"Contribution" shall mean any work of authorship, including
|
129 |
+
the original version of the Work and any modifications or additions
|
130 |
+
to that Work or Derivative Works thereof, that is intentionally
|
131 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
132 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
133 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
134 |
+
means any form of electronic, verbal, or written communication sent
|
135 |
+
to the Licensor or its representatives, including but not limited to
|
136 |
+
communication on electronic mailing lists, source code control systems,
|
137 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
138 |
+
Licensor for the purpose of discussing and improving the Work, but
|
139 |
+
excluding communication that is conspicuously marked or otherwise
|
140 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
141 |
+
|
142 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
143 |
+
on behalf of whom a Contribution has been received by Licensor and
|
144 |
+
subsequently incorporated within the Work.
|
145 |
+
|
146 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
147 |
+
this License, each Contributor hereby grants to You a perpetual,
|
148 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
149 |
+
copyright license to reproduce, prepare Derivative Works of,
|
150 |
+
publicly display, publicly perform, sublicense, and distribute the
|
151 |
+
Work and such Derivative Works in Source or Object form.
|
152 |
+
|
153 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
154 |
+
this License, each Contributor hereby grants to You a perpetual,
|
155 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
156 |
+
(except as stated in this section) patent license to make, have made,
|
157 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
158 |
+
where such license applies only to those patent claims licensable
|
159 |
+
by such Contributor that are necessarily infringed by their
|
160 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
161 |
+
with the Work to which such Contribution(s) was submitted. If You
|
162 |
+
institute patent litigation against any entity (including a
|
163 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
164 |
+
or a Contribution incorporated within the Work constitutes direct
|
165 |
+
or contributory patent infringement, then any patent licenses
|
166 |
+
granted to You under this License for that Work shall terminate
|
167 |
+
as of the date such litigation is filed.
|
168 |
+
|
169 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
170 |
+
Work or Derivative Works thereof in any medium, with or without
|
171 |
+
modifications, and in Source or Object form, provided that You
|
172 |
+
meet the following conditions:
|
173 |
+
|
174 |
+
(a) You must give any other recipients of the Work or
|
175 |
+
Derivative Works a copy of this License; and
|
176 |
+
|
177 |
+
(b) You must cause any modified files to carry prominent notices
|
178 |
+
stating that You changed the files; and
|
179 |
+
|
180 |
+
(c) You must retain, in the Source form of any Derivative Works
|
181 |
+
that You distribute, all copyright, patent, trademark, and
|
182 |
+
attribution notices from the Source form of the Work,
|
183 |
+
excluding those notices that do not pertain to any part of
|
184 |
+
the Derivative Works; and
|
185 |
+
|
186 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
187 |
+
distribution, then any Derivative Works that You distribute must
|
188 |
+
include a readable copy of the attribution notices contained
|
189 |
+
within such NOTICE file, excluding those notices that do not
|
190 |
+
pertain to any part of the Derivative Works, in at least one
|
191 |
+
of the following places: within a NOTICE text file distributed
|
192 |
+
as part of the Derivative Works; within the Source form or
|
193 |
+
documentation, if provided along with the Derivative Works; or,
|
194 |
+
within a display generated by the Derivative Works, if and
|
195 |
+
wherever such third-party notices normally appear. The contents
|
196 |
+
of the NOTICE file are for informational purposes only and
|
197 |
+
do not modify the License. You may add Your own attribution
|
198 |
+
notices within Derivative Works that You distribute, alongside
|
199 |
+
or as an addendum to the NOTICE text from the Work, provided
|
200 |
+
that such additional attribution notices cannot be construed
|
201 |
+
as modifying the License.
|
202 |
+
|
203 |
+
You may add Your own copyright statement to Your modifications and
|
204 |
+
may provide additional or different license terms and conditions
|
205 |
+
for use, reproduction, or distribution of Your modifications, or
|
206 |
+
for any such Derivative Works as a whole, provided Your use,
|
207 |
+
reproduction, and distribution of the Work otherwise complies with
|
208 |
+
the conditions stated in this License.
|
209 |
+
|
210 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
211 |
+
any Contribution intentionally submitted for inclusion in the Work
|
212 |
+
by You to the Licensor shall be under the terms and conditions of
|
213 |
+
this License, without any additional terms or conditions.
|
214 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
215 |
+
the terms of any separate license agreement you may have executed
|
216 |
+
with Licensor regarding such Contributions.
|
217 |
+
|
218 |
+
6. Trademarks. This License does not grant permission to use the trade
|
219 |
+
names, trademarks, service marks, or product names of the Licensor,
|
220 |
+
except as required for reasonable and customary use in describing the
|
221 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
222 |
+
|
223 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
224 |
+
agreed to in writing, Licensor provides the Work (and each
|
225 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
226 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
227 |
+
implied, including, without limitation, any warranties or conditions
|
228 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
229 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
230 |
+
appropriateness of using or redistributing the Work and assume any
|
231 |
+
risks associated with Your exercise of permissions under this License.
|
232 |
+
|
233 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
234 |
+
whether in tort (including negligence), contract, or otherwise,
|
235 |
+
unless required by applicable law (such as deliberate and grossly
|
236 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
237 |
+
liable to You for damages, including any direct, indirect, special,
|
238 |
+
incidental, or consequential damages of any character arising as a
|
239 |
+
result of this License or out of the use or inability to use the
|
240 |
+
Work (including but not limited to damages for loss of goodwill,
|
241 |
+
work stoppage, computer failure or malfunction, or any and all
|
242 |
+
other commercial damages or losses), even if such Contributor
|
243 |
+
has been advised of the possibility of such damages.
|
244 |
+
|
245 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
246 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
247 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
248 |
+
or other liability obligations and/or rights consistent with this
|
249 |
+
License. However, in accepting such obligations, You may act only
|
250 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
251 |
+
of any other Contributor, and only if You agree to indemnify,
|
252 |
+
defend, and hold each Contributor harmless for any liability
|
253 |
+
incurred by, or claims asserted against, such Contributor by reason
|
254 |
+
of your accepting any such warranty or additional liability.
|
255 |
+
|
256 |
+
END OF TERMS AND CONDITIONS
|
257 |
+
|
258 |
+
APPENDIX: How to apply the Apache License to your work.
|
259 |
+
|
260 |
+
To apply the Apache License to your work, attach the following
|
261 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
262 |
+
replaced with your own identifying information. (Don't include
|
263 |
+
the brackets!) The text should be enclosed in the appropriate
|
264 |
+
comment syntax for the file format. We also recommend that a
|
265 |
+
file or class name and description of purpose be included on the
|
266 |
+
same "printed page" as the copyright notice for easier
|
267 |
+
identification within third-party archives.
|
268 |
+
|
269 |
+
Copyright [yyyy] [name of copyright owner]
|
270 |
+
|
271 |
+
|
272 |
+
|
273 |
+
### Non-Open Source Reference Implementations:
|
274 |
+
|
275 |
+
#### [MultiPL-E](https://github.com/nuprl/MultiPL-E)
|
276 |
+
- License: BSD 3-Clause License with Machine Learning Restriction
|
277 |
+
|
278 |
+
BSD 3-Clause License with Machine Learning Restriction
|
279 |
+
|
280 |
+
Copyright (c) 2022, Northeastern University, Oberlin College, Roblox Inc,
|
281 |
+
Stevens Institute of Technology, University of Massachusetts Amherst, and
|
282 |
+
Wellesley College.
|
283 |
+
|
284 |
+
All rights reserved.
|
285 |
+
|
286 |
+
Redistribution and use in source and binary forms, with or without
|
287 |
+
modification, are permitted provided that the following conditions are met:
|
288 |
+
|
289 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
290 |
+
list of conditions and the following disclaimer.
|
291 |
+
|
292 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
293 |
+
this list of conditions and the following disclaimer in the documentation
|
294 |
+
and/or other materials provided with the distribution.
|
295 |
+
|
296 |
+
3. Neither the name of the copyright holder nor the names of its
|
297 |
+
contributors may be used to endorse or promote products derived from
|
298 |
+
this software without specific prior written permission.
|
299 |
+
|
300 |
+
4. The contents of this repository may not be used as training data for any
|
301 |
+
machine learning model, including but not limited to neural networks.
|
302 |
+
|
303 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
304 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
305 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
306 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
307 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
308 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
309 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
310 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
311 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
312 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Development.md
ADDED
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Development Guide
|
2 |
+
|
3 |
+
This guide is for people working on OpenHands and editing the source code.
|
4 |
+
If you wish to contribute your changes, check out the
|
5 |
+
[CONTRIBUTING.md](https://github.com/All-Hands-AI/OpenHands/blob/main/CONTRIBUTING.md)
|
6 |
+
on how to clone and setup the project initially before moving on. Otherwise,
|
7 |
+
you can clone the OpenHands project directly.
|
8 |
+
|
9 |
+
## Start the Server for Development
|
10 |
+
|
11 |
+
### 1. Requirements
|
12 |
+
|
13 |
+
- Linux, Mac OS, or [WSL on Windows](https://learn.microsoft.com/en-us/windows/wsl/install) [Ubuntu >= 22.04]
|
14 |
+
- [Docker](https://docs.docker.com/engine/install/) (For those on MacOS, make sure to allow the default Docker socket to be used from advanced settings!)
|
15 |
+
- [Python](https://www.python.org/downloads/) = 3.12
|
16 |
+
- [NodeJS](https://nodejs.org/en/download/package-manager) >= 22.x
|
17 |
+
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer) >= 1.8
|
18 |
+
- OS-specific dependencies:
|
19 |
+
- Ubuntu: build-essential => `sudo apt-get install build-essential python3.12-dev`
|
20 |
+
- WSL: netcat => `sudo apt-get install netcat`
|
21 |
+
|
22 |
+
Make sure you have all these dependencies installed before moving on to `make build`.
|
23 |
+
|
24 |
+
#### Dev container
|
25 |
+
|
26 |
+
There is a [dev container](https://containers.dev/) available which provides a
|
27 |
+
pre-configured environment with all the necessary dependencies installed if you
|
28 |
+
are using a [supported editor or tool](https://containers.dev/supporting). For
|
29 |
+
example, if you are using Visual Studio Code (VS Code) with the
|
30 |
+
[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
31 |
+
extension installed, you can open the project in a dev container by using the
|
32 |
+
_Dev Container: Reopen in Container_ command from the Command Palette
|
33 |
+
(Ctrl+Shift+P).
|
34 |
+
|
35 |
+
#### Develop without sudo access
|
36 |
+
|
37 |
+
If you want to develop without system admin/sudo access to upgrade/install `Python` and/or `NodeJs`, you can use
|
38 |
+
`conda` or `mamba` to manage the packages for you:
|
39 |
+
|
40 |
+
```bash
|
41 |
+
# Download and install Mamba (a faster version of conda)
|
42 |
+
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
|
43 |
+
bash Miniforge3-$(uname)-$(uname -m).sh
|
44 |
+
|
45 |
+
# Install Python 3.12, nodejs, and poetry
|
46 |
+
mamba install python=3.12
|
47 |
+
mamba install conda-forge::nodejs
|
48 |
+
mamba install conda-forge::poetry
|
49 |
+
```
|
50 |
+
|
51 |
+
### 2. Build and Setup The Environment
|
52 |
+
|
53 |
+
Begin by building the project which includes setting up the environment and installing dependencies. This step ensures
|
54 |
+
that OpenHands is ready to run on your system:
|
55 |
+
|
56 |
+
```bash
|
57 |
+
make build
|
58 |
+
```
|
59 |
+
|
60 |
+
### 3. Configuring the Language Model
|
61 |
+
|
62 |
+
OpenHands supports a diverse array of Language Models (LMs) through the powerful [litellm](https://docs.litellm.ai) library.
|
63 |
+
|
64 |
+
To configure the LM of your choice, run:
|
65 |
+
|
66 |
+
```bash
|
67 |
+
make setup-config
|
68 |
+
```
|
69 |
+
|
70 |
+
This command will prompt you to enter the LLM API key, model name, and other variables ensuring that OpenHands is
|
71 |
+
tailored to your specific needs. Note that the model name will apply only when you run headless. If you use the UI,
|
72 |
+
please set the model in the UI.
|
73 |
+
|
74 |
+
Note: If you have previously run OpenHands using the docker command, you may have already set some environmental
|
75 |
+
variables in your terminal. The final configurations are set from highest to lowest priority:
|
76 |
+
Environment variables > config.toml variables > default variables
|
77 |
+
|
78 |
+
**Note on Alternative Models:**
|
79 |
+
See [our documentation](https://docs.all-hands.dev/usage/llms) for recommended models.
|
80 |
+
|
81 |
+
### 4. Running the application
|
82 |
+
|
83 |
+
#### Option A: Run the Full Application
|
84 |
+
|
85 |
+
Once the setup is complete, this command starts both the backend and frontend servers, allowing you to interact with OpenHands:
|
86 |
+
|
87 |
+
```bash
|
88 |
+
make run
|
89 |
+
```
|
90 |
+
|
91 |
+
#### Option B: Individual Server Startup
|
92 |
+
|
93 |
+
- **Start the Backend Server:** If you prefer, you can start the backend server independently to focus on
|
94 |
+
backend-related tasks or configurations.
|
95 |
+
|
96 |
+
```bash
|
97 |
+
make start-backend
|
98 |
+
```
|
99 |
+
|
100 |
+
- **Start the Frontend Server:** Similarly, you can start the frontend server on its own to work on frontend-related
|
101 |
+
components or interface enhancements.
|
102 |
+
```bash
|
103 |
+
make start-frontend
|
104 |
+
```
|
105 |
+
|
106 |
+
### 6. LLM Debugging
|
107 |
+
|
108 |
+
If you encounter any issues with the Language Model (LM) or you're simply curious, export DEBUG=1 in the environment and restart the backend.
|
109 |
+
OpenHands will log the prompts and responses in the logs/llm/CURRENT_DATE directory, allowing you to identify the causes.
|
110 |
+
|
111 |
+
### 7. Help
|
112 |
+
|
113 |
+
Need help or info on available targets and commands? Use the help command for all the guidance you need with OpenHands.
|
114 |
+
|
115 |
+
```bash
|
116 |
+
make help
|
117 |
+
```
|
118 |
+
|
119 |
+
### 8. Testing
|
120 |
+
|
121 |
+
To run tests, refer to the following:
|
122 |
+
|
123 |
+
#### Unit tests
|
124 |
+
|
125 |
+
```bash
|
126 |
+
poetry run pytest ./tests/unit/test_*.py
|
127 |
+
```
|
128 |
+
|
129 |
+
### 9. Add or update dependency
|
130 |
+
|
131 |
+
1. Add your dependency in `pyproject.toml` or use `poetry add xxx`.
|
132 |
+
2. Update the poetry.lock file via `poetry lock --no-update`.
|
133 |
+
|
134 |
+
### 9. Use existing Docker image
|
135 |
+
|
136 |
+
To reduce build time (e.g., if no changes were made to the client-runtime component), you can use an existing Docker
|
137 |
+
container image by setting the SANDBOX_RUNTIME_CONTAINER_IMAGE environment variable to the desired Docker image.
|
138 |
+
|
139 |
+
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.41-nikolaik`
|
140 |
+
|
141 |
+
## Develop inside Docker container
|
142 |
+
|
143 |
+
TL;DR
|
144 |
+
|
145 |
+
```bash
|
146 |
+
make docker-dev
|
147 |
+
```
|
148 |
+
|
149 |
+
See more details [here](./containers/dev/README.md).
|
150 |
+
|
151 |
+
If you are just interested in running `OpenHands` without installing all the required tools on your host.
|
152 |
+
|
153 |
+
```bash
|
154 |
+
make docker-run
|
155 |
+
```
|
156 |
+
|
157 |
+
If you do not have `make` on your host, run:
|
158 |
+
|
159 |
+
```bash
|
160 |
+
cd ./containers/dev
|
161 |
+
./dev.sh
|
162 |
+
```
|
163 |
+
|
164 |
+
You do need [Docker](https://docs.docker.com/engine/install/) installed on your host though.
|
165 |
+
|
166 |
+
## Key Documentation Resources
|
167 |
+
|
168 |
+
Here's a guide to the important documentation files in the repository:
|
169 |
+
|
170 |
+
- [/README.md](./README.md): Main project overview, features, and basic setup instructions
|
171 |
+
- [/Development.md](./Development.md) (this file): Comprehensive guide for developers working on OpenHands
|
172 |
+
- [/CONTRIBUTING.md](./CONTRIBUTING.md): Guidelines for contributing to the project, including code style and PR process
|
173 |
+
- [/docs/DOC_STYLE_GUIDE.md](./docs/DOC_STYLE_GUIDE.md): Standards for writing and maintaining project documentation
|
174 |
+
- [/openhands/README.md](./openhands/README.md): Details about the backend Python implementation
|
175 |
+
- [/frontend/README.md](./frontend/README.md): Frontend React application setup and development guide
|
176 |
+
- [/containers/README.md](./containers/README.md): Information about Docker containers and deployment
|
177 |
+
- [/tests/unit/README.md](./tests/unit/README.md): Guide to writing and running unit tests
|
178 |
+
- [/evaluation/README.md](./evaluation/README.md): Documentation for the evaluation framework and benchmarks
|
179 |
+
- [/microagents/README.md](./microagents/README.md): Information about the microagents architecture and implementation
|
180 |
+
- [/openhands/server/README.md](./openhands/server/README.md): Server implementation details and API documentation
|
181 |
+
- [/openhands/runtime/README.md](./openhands/runtime/README.md): Documentation for the runtime environment and execution model
|
ISSUE_TRIAGE.md
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Issue Triage
|
2 |
+
These are the procedures and guidelines on how issues are triaged in this repo by the maintainers.
|
3 |
+
|
4 |
+
## General
|
5 |
+
* All issues must be tagged with **enhancement**, **bug** or **troubleshooting/help**.
|
6 |
+
* Issues may be tagged with what it relates to (**agent quality**, **resolver**, **CLI**, etc.).
|
7 |
+
|
8 |
+
## Severity
|
9 |
+
* **High**: High visibility issues or affecting many users.
|
10 |
+
* **Critical**: Affecting all users or potential security issues.
|
11 |
+
|
12 |
+
## Difficulty
|
13 |
+
* Issues with low implementation difficulty may be tagged with **good first issue**.
|
14 |
+
|
15 |
+
## Not Enough Information
|
16 |
+
* User is asked to provide more information (logs, how to reproduce, etc.) when the issue is not clear.
|
17 |
+
* If an issue is unclear and the author does not provide more information or respond to a request,
|
18 |
+
the issue may be closed as **not planned** (Usually after a week).
|
19 |
+
|
20 |
+
## Multiple Requests/Fixes in One Issue
|
21 |
+
* These issues will be narrowed down to one request/fix so the issue is more easily tracked and fixed.
|
22 |
+
* Issues may be broken down into multiple issues if required.
|
23 |
+
|
24 |
+
## Stale and Auto Closures
|
25 |
+
* In order to keep a maintainable backlog, issues that have no activity within 30 days are automatically marked as **Stale**.
|
26 |
+
* If issues marked as **Stale** continue to have no activity for 7 more days, they will automatically be closed as not planned.
|
27 |
+
* Issues may be reopened by maintainers if deemed important.
|
LICENSE.txt
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The MIT License (MIT)
|
2 |
+
=====================
|
3 |
+
|
4 |
+
Copyright © 2023
|
5 |
+
|
6 |
+
Permission is hereby granted, free of charge, to any person
|
7 |
+
obtaining a copy of this software and associated documentation
|
8 |
+
files (the “Software”), to deal in the Software without
|
9 |
+
restriction, including without limitation the rights to use,
|
10 |
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the
|
12 |
+
Software is furnished to do so, subject to the following
|
13 |
+
conditions:
|
14 |
+
|
15 |
+
The above copyright notice and this permission notice shall be
|
16 |
+
included in all copies or substantial portions of the Software.
|
17 |
+
|
18 |
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
OTHER DEALINGS IN THE SOFTWARE.
|
MANIFEST.in
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Exclude all Python bytecode files
|
2 |
+
global-exclude *.pyc
|
3 |
+
|
4 |
+
# Exclude Python cache directories
|
5 |
+
global-exclude __pycache__
|
Makefile.make
ADDED
@@ -0,0 +1,335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
SHELL=/usr/bin/env bash
|
2 |
+
# Makefile for OpenHands project
|
3 |
+
|
4 |
+
# Variables
|
5 |
+
BACKEND_HOST ?= "127.0.0.1"
|
6 |
+
BACKEND_PORT = 3000
|
7 |
+
BACKEND_HOST_PORT = "$(BACKEND_HOST):$(BACKEND_PORT)"
|
8 |
+
FRONTEND_HOST ?= "127.0.0.1"
|
9 |
+
FRONTEND_PORT = 3001
|
10 |
+
DEFAULT_WORKSPACE_DIR = "./workspace"
|
11 |
+
DEFAULT_MODEL = "gpt-4o"
|
12 |
+
CONFIG_FILE = config.toml
|
13 |
+
PRE_COMMIT_CONFIG_PATH = "./dev_config/python/.pre-commit-config.yaml"
|
14 |
+
PYTHON_VERSION = 3.12
|
15 |
+
|
16 |
+
# ANSI color codes
|
17 |
+
GREEN=$(shell tput -Txterm setaf 2)
|
18 |
+
YELLOW=$(shell tput -Txterm setaf 3)
|
19 |
+
RED=$(shell tput -Txterm setaf 1)
|
20 |
+
BLUE=$(shell tput -Txterm setaf 6)
|
21 |
+
RESET=$(shell tput -Txterm sgr0)
|
22 |
+
|
23 |
+
# Build
|
24 |
+
build:
|
25 |
+
@echo "$(GREEN)Building project...$(RESET)"
|
26 |
+
@$(MAKE) -s check-dependencies
|
27 |
+
@$(MAKE) -s install-python-dependencies
|
28 |
+
@$(MAKE) -s install-frontend-dependencies
|
29 |
+
@$(MAKE) -s install-pre-commit-hooks
|
30 |
+
@$(MAKE) -s build-frontend
|
31 |
+
@echo "$(GREEN)Build completed successfully.$(RESET)"
|
32 |
+
|
33 |
+
check-dependencies:
|
34 |
+
@echo "$(YELLOW)Checking dependencies...$(RESET)"
|
35 |
+
@$(MAKE) -s check-system
|
36 |
+
@$(MAKE) -s check-python
|
37 |
+
@$(MAKE) -s check-npm
|
38 |
+
@$(MAKE) -s check-nodejs
|
39 |
+
ifeq ($(INSTALL_DOCKER),)
|
40 |
+
@$(MAKE) -s check-docker
|
41 |
+
endif
|
42 |
+
@$(MAKE) -s check-poetry
|
43 |
+
@$(MAKE) -s check-tmux
|
44 |
+
@echo "$(GREEN)Dependencies checked successfully.$(RESET)"
|
45 |
+
|
46 |
+
check-system:
|
47 |
+
@echo "$(YELLOW)Checking system...$(RESET)"
|
48 |
+
@if [ "$(shell uname)" = "Darwin" ]; then \
|
49 |
+
echo "$(BLUE)macOS detected.$(RESET)"; \
|
50 |
+
elif [ "$(shell uname)" = "Linux" ]; then \
|
51 |
+
if [ -f "/etc/manjaro-release" ]; then \
|
52 |
+
echo "$(BLUE)Manjaro Linux detected.$(RESET)"; \
|
53 |
+
else \
|
54 |
+
echo "$(BLUE)Linux detected.$(RESET)"; \
|
55 |
+
fi; \
|
56 |
+
elif [ "$$(uname -r | grep -i microsoft)" ]; then \
|
57 |
+
echo "$(BLUE)Windows Subsystem for Linux detected.$(RESET)"; \
|
58 |
+
else \
|
59 |
+
echo "$(RED)Unsupported system detected. Please use macOS, Linux, or Windows Subsystem for Linux (WSL).$(RESET)"; \
|
60 |
+
exit 1; \
|
61 |
+
fi
|
62 |
+
|
63 |
+
check-python:
|
64 |
+
@echo "$(YELLOW)Checking Python installation...$(RESET)"
|
65 |
+
@if command -v python$(PYTHON_VERSION) > /dev/null; then \
|
66 |
+
echo "$(BLUE)$(shell python$(PYTHON_VERSION) --version) is already installed.$(RESET)"; \
|
67 |
+
else \
|
68 |
+
echo "$(RED)Python $(PYTHON_VERSION) is not installed. Please install Python $(PYTHON_VERSION) to continue.$(RESET)"; \
|
69 |
+
exit 1; \
|
70 |
+
fi
|
71 |
+
|
72 |
+
check-npm:
|
73 |
+
@echo "$(YELLOW)Checking npm installation...$(RESET)"
|
74 |
+
@if command -v npm > /dev/null; then \
|
75 |
+
echo "$(BLUE)npm $(shell npm --version) is already installed.$(RESET)"; \
|
76 |
+
else \
|
77 |
+
echo "$(RED)npm is not installed. Please install Node.js to continue.$(RESET)"; \
|
78 |
+
exit 1; \
|
79 |
+
fi
|
80 |
+
|
81 |
+
check-nodejs:
|
82 |
+
@echo "$(YELLOW)Checking Node.js installation...$(RESET)"
|
83 |
+
@if command -v node > /dev/null; then \
|
84 |
+
NODE_VERSION=$(shell node --version | sed -E 's/v//g'); \
|
85 |
+
IFS='.' read -r -a NODE_VERSION_ARRAY <<< "$$NODE_VERSION"; \
|
86 |
+
if [ "$${NODE_VERSION_ARRAY[0]}" -ge 22 ]; then \
|
87 |
+
echo "$(BLUE)Node.js $$NODE_VERSION is already installed.$(RESET)"; \
|
88 |
+
else \
|
89 |
+
echo "$(RED)Node.js 22.x or later is required. Please install Node.js 22.x or later to continue.$(RESET)"; \
|
90 |
+
exit 1; \
|
91 |
+
fi; \
|
92 |
+
else \
|
93 |
+
echo "$(RED)Node.js is not installed. Please install Node.js to continue.$(RESET)"; \
|
94 |
+
exit 1; \
|
95 |
+
fi
|
96 |
+
|
97 |
+
check-docker:
|
98 |
+
@echo "$(YELLOW)Checking Docker installation...$(RESET)"
|
99 |
+
@if command -v docker > /dev/null; then \
|
100 |
+
echo "$(BLUE)$(shell docker --version) is already installed.$(RESET)"; \
|
101 |
+
else \
|
102 |
+
echo "$(RED)Docker is not installed. Please install Docker to continue.$(RESET)"; \
|
103 |
+
exit 1; \
|
104 |
+
fi
|
105 |
+
|
106 |
+
check-tmux:
|
107 |
+
@echo "$(YELLOW)Checking tmux installation...$(RESET)"
|
108 |
+
@if command -v tmux > /dev/null; then \
|
109 |
+
echo "$(BLUE)$(shell tmux -V) is already installed.$(RESET)"; \
|
110 |
+
else \
|
111 |
+
echo "$(YELLOW)╔════════════════════════════════════════════════════════════════════════════╗$(RESET)"; \
|
112 |
+
echo "$(YELLOW)║ OPTIONAL: tmux is not installed. ║$(RESET)"; \
|
113 |
+
echo "$(YELLOW)║ Some advanced terminal features may not work without tmux. ║$(RESET)"; \
|
114 |
+
echo "$(YELLOW)║ You can install it if needed, but it's not required for development. ║$(RESET)"; \
|
115 |
+
echo "$(YELLOW)╚════════════════════════════════════════════════════════════════════════════╝$(RESET)"; \
|
116 |
+
fi
|
117 |
+
|
118 |
+
check-poetry:
|
119 |
+
@echo "$(YELLOW)Checking Poetry installation...$(RESET)"
|
120 |
+
@if command -v poetry > /dev/null; then \
|
121 |
+
POETRY_VERSION=$(shell poetry --version 2>&1 | sed -E 's/Poetry \(version ([0-9]+\.[0-9]+\.[0-9]+)\)/\1/'); \
|
122 |
+
IFS='.' read -r -a POETRY_VERSION_ARRAY <<< "$$POETRY_VERSION"; \
|
123 |
+
if [ $${POETRY_VERSION_ARRAY[0]} -gt 1 ] || ([ $${POETRY_VERSION_ARRAY[0]} -eq 1 ] && [ $${POETRY_VERSION_ARRAY[1]} -ge 8 ]); then \
|
124 |
+
echo "$(BLUE)$(shell poetry --version) is already installed.$(RESET)"; \
|
125 |
+
else \
|
126 |
+
echo "$(RED)Poetry 1.8 or later is required. You can install poetry by running the following command, then adding Poetry to your PATH:"; \
|
127 |
+
echo "$(RED) curl -sSL https://install.python-poetry.org | python$(PYTHON_VERSION) -$(RESET)"; \
|
128 |
+
echo "$(RED)More detail here: https://python-poetry.org/docs/#installing-with-the-official-installer$(RESET)"; \
|
129 |
+
exit 1; \
|
130 |
+
fi; \
|
131 |
+
else \
|
132 |
+
echo "$(RED)Poetry is not installed. You can install poetry by running the following command, then adding Poetry to your PATH:"; \
|
133 |
+
echo "$(RED) curl -sSL https://install.python-poetry.org | python$(PYTHON_VERSION) -$(RESET)"; \
|
134 |
+
echo "$(RED)More detail here: https://python-poetry.org/docs/#installing-with-the-official-installer$(RESET)"; \
|
135 |
+
exit 1; \
|
136 |
+
fi
|
137 |
+
|
138 |
+
install-python-dependencies:
|
139 |
+
@echo "$(GREEN)Installing Python dependencies...$(RESET)"
|
140 |
+
@if [ -z "${TZ}" ]; then \
|
141 |
+
echo "Defaulting TZ (timezone) to UTC"; \
|
142 |
+
export TZ="UTC"; \
|
143 |
+
fi
|
144 |
+
poetry env use python$(PYTHON_VERSION)
|
145 |
+
@if [ "$(shell uname)" = "Darwin" ]; then \
|
146 |
+
echo "$(BLUE)Installing chroma-hnswlib...$(RESET)"; \
|
147 |
+
export HNSWLIB_NO_NATIVE=1; \
|
148 |
+
poetry run pip install chroma-hnswlib; \
|
149 |
+
fi
|
150 |
+
@if [ -n "${POETRY_GROUP}" ]; then \
|
151 |
+
echo "Installing only POETRY_GROUP=${POETRY_GROUP}"; \
|
152 |
+
poetry install --only $${POETRY_GROUP}; \
|
153 |
+
else \
|
154 |
+
poetry install --with dev,test,runtime; \
|
155 |
+
fi
|
156 |
+
@if [ "${INSTALL_PLAYWRIGHT}" != "false" ] && [ "${INSTALL_PLAYWRIGHT}" != "0" ]; then \
|
157 |
+
if [ -f "/etc/manjaro-release" ]; then \
|
158 |
+
echo "$(BLUE)Detected Manjaro Linux. Installing Playwright dependencies...$(RESET)"; \
|
159 |
+
poetry run pip install playwright; \
|
160 |
+
poetry run playwright install chromium; \
|
161 |
+
else \
|
162 |
+
if [ ! -f cache/playwright_chromium_is_installed.txt ]; then \
|
163 |
+
echo "Running playwright install --with-deps chromium..."; \
|
164 |
+
poetry run playwright install --with-deps chromium; \
|
165 |
+
mkdir -p cache; \
|
166 |
+
touch cache/playwright_chromium_is_installed.txt; \
|
167 |
+
else \
|
168 |
+
echo "Setup already done. Skipping playwright installation."; \
|
169 |
+
fi \
|
170 |
+
fi \
|
171 |
+
else \
|
172 |
+
echo "Skipping Playwright installation (INSTALL_PLAYWRIGHT=${INSTALL_PLAYWRIGHT})."; \
|
173 |
+
fi
|
174 |
+
@echo "$(GREEN)Python dependencies installed successfully.$(RESET)"
|
175 |
+
|
176 |
+
install-frontend-dependencies:
|
177 |
+
@echo "$(YELLOW)Setting up frontend environment...$(RESET)"
|
178 |
+
@echo "$(YELLOW)Detect Node.js version...$(RESET)"
|
179 |
+
@cd frontend && node ./scripts/detect-node-version.js
|
180 |
+
echo "$(BLUE)Installing frontend dependencies with npm...$(RESET)"
|
181 |
+
@cd frontend && npm install
|
182 |
+
@echo "$(GREEN)Frontend dependencies installed successfully.$(RESET)"
|
183 |
+
|
184 |
+
install-pre-commit-hooks:
|
185 |
+
@echo "$(YELLOW)Installing pre-commit hooks...$(RESET)"
|
186 |
+
@git config --unset-all core.hooksPath || true
|
187 |
+
@poetry run pre-commit install --config $(PRE_COMMIT_CONFIG_PATH)
|
188 |
+
@echo "$(GREEN)Pre-commit hooks installed successfully.$(RESET)"
|
189 |
+
|
190 |
+
lint-backend:
|
191 |
+
@echo "$(YELLOW)Running linters...$(RESET)"
|
192 |
+
@poetry run pre-commit run --files openhands/**/* evaluation/**/* tests/**/* --show-diff-on-failure --config $(PRE_COMMIT_CONFIG_PATH)
|
193 |
+
|
194 |
+
lint-frontend:
|
195 |
+
@echo "$(YELLOW)Running linters for frontend...$(RESET)"
|
196 |
+
@cd frontend && npm run lint
|
197 |
+
|
198 |
+
lint:
|
199 |
+
@$(MAKE) -s lint-frontend
|
200 |
+
@$(MAKE) -s lint-backend
|
201 |
+
|
202 |
+
test-frontend:
|
203 |
+
@echo "$(YELLOW)Running tests for frontend...$(RESET)"
|
204 |
+
@cd frontend && npm run test
|
205 |
+
|
206 |
+
test:
|
207 |
+
@$(MAKE) -s test-frontend
|
208 |
+
|
209 |
+
build-frontend:
|
210 |
+
@echo "$(YELLOW)Building frontend...$(RESET)"
|
211 |
+
@cd frontend && npm run prepare && npm run build
|
212 |
+
|
213 |
+
# Start backend
|
214 |
+
start-backend:
|
215 |
+
@echo "$(YELLOW)Starting backend...$(RESET)"
|
216 |
+
@poetry run uvicorn openhands.server.listen:app --host $(BACKEND_HOST) --port $(BACKEND_PORT) --reload --reload-exclude "./workspace"
|
217 |
+
|
218 |
+
# Start frontend
|
219 |
+
start-frontend:
|
220 |
+
@echo "$(YELLOW)Starting frontend...$(RESET)"
|
221 |
+
@cd frontend && \
|
222 |
+
if grep -qi microsoft /proc/version 2>/dev/null; then \
|
223 |
+
echo "Detected WSL environment. Using 'dev_wsl'"; \
|
224 |
+
SCRIPT=dev_wsl; \
|
225 |
+
else \
|
226 |
+
SCRIPT=dev; \
|
227 |
+
fi; \
|
228 |
+
VITE_BACKEND_HOST=$(BACKEND_HOST_PORT) VITE_FRONTEND_PORT=$(FRONTEND_PORT) npm run $$SCRIPT -- --port $(FRONTEND_PORT) --host $(BACKEND_HOST)
|
229 |
+
|
230 |
+
# Common setup for running the app (non-callable)
|
231 |
+
_run_setup:
|
232 |
+
@if [ "$(OS)" = "Windows_NT" ]; then \
|
233 |
+
echo "$(RED) Windows is not supported, use WSL instead!$(RESET)"; \
|
234 |
+
exit 1; \
|
235 |
+
fi
|
236 |
+
@mkdir -p logs
|
237 |
+
@echo "$(YELLOW)Starting backend server...$(RESET)"
|
238 |
+
@poetry run uvicorn openhands.server.listen:app --host $(BACKEND_HOST) --port $(BACKEND_PORT) &
|
239 |
+
@echo "$(YELLOW)Waiting for the backend to start...$(RESET)"
|
240 |
+
@until nc -z localhost $(BACKEND_PORT); do sleep 0.1; done
|
241 |
+
@echo "$(GREEN)Backend started successfully.$(RESET)"
|
242 |
+
|
243 |
+
# Run the app (standard mode)
|
244 |
+
run:
|
245 |
+
@echo "$(YELLOW)Running the app...$(RESET)"
|
246 |
+
@$(MAKE) -s _run_setup
|
247 |
+
@$(MAKE) -s start-frontend
|
248 |
+
@echo "$(GREEN)Application started successfully.$(RESET)"
|
249 |
+
|
250 |
+
# Run the app (in docker)
|
251 |
+
docker-run: WORKSPACE_BASE ?= $(PWD)/workspace
|
252 |
+
docker-run:
|
253 |
+
@if [ -f /.dockerenv ]; then \
|
254 |
+
echo "Running inside a Docker container. Exiting..."; \
|
255 |
+
exit 0; \
|
256 |
+
else \
|
257 |
+
echo "$(YELLOW)Running the app in Docker $(OPTIONS)...$(RESET)"; \
|
258 |
+
export WORKSPACE_BASE=${WORKSPACE_BASE}; \
|
259 |
+
export SANDBOX_USER_ID=$(shell id -u); \
|
260 |
+
export DATE=$(shell date +%Y%m%d%H%M%S); \
|
261 |
+
docker compose up $(OPTIONS); \
|
262 |
+
fi
|
263 |
+
|
264 |
+
|
265 |
+
# Setup config.toml
|
266 |
+
setup-config:
|
267 |
+
@echo "$(YELLOW)Setting up config.toml...$(RESET)"
|
268 |
+
@$(MAKE) setup-config-prompts
|
269 |
+
@mv $(CONFIG_FILE).tmp $(CONFIG_FILE)
|
270 |
+
@echo "$(GREEN)Config.toml setup completed.$(RESET)"
|
271 |
+
|
272 |
+
setup-config-prompts:
|
273 |
+
@echo "[core]" > $(CONFIG_FILE).tmp
|
274 |
+
|
275 |
+
@read -p "Enter your workspace directory (as absolute path) [default: $(DEFAULT_WORKSPACE_DIR)]: " workspace_dir; \
|
276 |
+
workspace_dir=$${workspace_dir:-$(DEFAULT_WORKSPACE_DIR)}; \
|
277 |
+
echo "workspace_base=\"$$workspace_dir\"" >> $(CONFIG_FILE).tmp
|
278 |
+
|
279 |
+
@echo "" >> $(CONFIG_FILE).tmp
|
280 |
+
|
281 |
+
@echo "[llm]" >> $(CONFIG_FILE).tmp
|
282 |
+
@read -p "Enter your LLM model name, used for running without UI. Set the model in the UI after you start the app. (see https://docs.litellm.ai/docs/providers for full list) [default: $(DEFAULT_MODEL)]: " llm_model; \
|
283 |
+
llm_model=$${llm_model:-$(DEFAULT_MODEL)}; \
|
284 |
+
echo "model=\"$$llm_model\"" >> $(CONFIG_FILE).tmp
|
285 |
+
|
286 |
+
@read -p "Enter your LLM api key: " llm_api_key; \
|
287 |
+
echo "api_key=\"$$llm_api_key\"" >> $(CONFIG_FILE).tmp
|
288 |
+
|
289 |
+
@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; \
|
290 |
+
if [[ ! -z "$$llm_base_url" ]]; then echo "base_url=\"$$llm_base_url\"" >> $(CONFIG_FILE).tmp; fi
|
291 |
+
|
292 |
+
setup-config-basic:
|
293 |
+
@printf '%s\n' \
|
294 |
+
'[core]' \
|
295 |
+
'workspace_base="./workspace"' \
|
296 |
+
> config.toml
|
297 |
+
@echo "$(GREEN)config.toml created.$(RESET)"
|
298 |
+
|
299 |
+
openhands-cloud-run:
|
300 |
+
@$(MAKE) run BACKEND_HOST="0.0.0.0" BACKEND_PORT="12000" FRONTEND_HOST="0.0.0.0" FRONTEND_PORT="12001"
|
301 |
+
|
302 |
+
# Develop in container
|
303 |
+
docker-dev:
|
304 |
+
@if [ -f /.dockerenv ]; then \
|
305 |
+
echo "Running inside a Docker container. Exiting..."; \
|
306 |
+
exit 0; \
|
307 |
+
else \
|
308 |
+
echo "$(YELLOW)Build and run in Docker $(OPTIONS)...$(RESET)"; \
|
309 |
+
./containers/dev/dev.sh $(OPTIONS); \
|
310 |
+
fi
|
311 |
+
|
312 |
+
# Clean up all caches
|
313 |
+
clean:
|
314 |
+
@echo "$(YELLOW)Cleaning up caches...$(RESET)"
|
315 |
+
@rm -rf openhands/.cache
|
316 |
+
@echo "$(GREEN)Caches cleaned up successfully.$(RESET)"
|
317 |
+
|
318 |
+
# Help
|
319 |
+
help:
|
320 |
+
@echo "$(BLUE)Usage: make [target]$(RESET)"
|
321 |
+
@echo "Targets:"
|
322 |
+
@echo " $(GREEN)build$(RESET) - Build project, including environment setup and dependencies."
|
323 |
+
@echo " $(GREEN)lint$(RESET) - Run linters on the project."
|
324 |
+
@echo " $(GREEN)setup-config$(RESET) - Setup the configuration for OpenHands by providing LLM API key,"
|
325 |
+
@echo " LLM Model name, and workspace directory."
|
326 |
+
@echo " $(GREEN)start-backend$(RESET) - Start the backend server for the OpenHands project."
|
327 |
+
@echo " $(GREEN)start-frontend$(RESET) - Start the frontend server for the OpenHands project."
|
328 |
+
@echo " $(GREEN)run$(RESET) - Run the OpenHands application, starting both backend and frontend servers."
|
329 |
+
@echo " Backend Log file will be stored in the 'logs' directory."
|
330 |
+
@echo " $(GREEN)docker-dev$(RESET) - Build and run the OpenHands application in Docker."
|
331 |
+
@echo " $(GREEN)docker-run$(RESET) - Run the OpenHands application, starting both backend and frontend servers in Docker."
|
332 |
+
@echo " $(GREEN)help$(RESET) - Display this help message, providing information on available targets."
|
333 |
+
|
334 |
+
# Phony targets
|
335 |
+
.PHONY: build check-dependencies check-system check-python check-npm check-nodejs check-docker check-poetry install-python-dependencies install-frontend-dependencies install-pre-commit-hooks lint-backend lint-frontend lint test-frontend test build-frontend start-backend start-frontend _run_setup run run-wsl setup-config setup-config-prompts setup-config-basic openhands-cloud-run docker-dev docker-run clean help
|
README.md
CHANGED
@@ -1,9 +1,146 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<a name="readme-top"></a>
|
2 |
+
|
3 |
+
<div align="center">
|
4 |
+
<img src="./docs/static/img/logo.png" alt="Logo" width="200">
|
5 |
+
<h1 align="center">OpenHands: Code Less, Make More</h1>
|
6 |
+
</div>
|
7 |
+
|
8 |
+
|
9 |
+
<div align="center">
|
10 |
+
<a href="https://github.com/All-Hands-AI/OpenHands/graphs/contributors"><img src="https://img.shields.io/github/contributors/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="Contributors"></a>
|
11 |
+
<a href="https://github.com/All-Hands-AI/OpenHands/stargazers"><img src="https://img.shields.io/github/stars/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="Stargazers"></a>
|
12 |
+
<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>
|
13 |
+
<br/>
|
14 |
+
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-34zm4j0gj-Qz5kRHoca8DFCbqXPS~f_A"><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>
|
15 |
+
<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>
|
16 |
+
<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>
|
17 |
+
<br/>
|
18 |
+
<a href="https://docs.all-hands.dev/usage/getting-started"><img src="https://img.shields.io/badge/Documentation-000?logo=googledocs&logoColor=FFE165&style=for-the-badge" alt="Check out the documentation"></a>
|
19 |
+
<a href="https://arxiv.org/abs/2407.16741"><img src="https://img.shields.io/badge/Paper%20on%20Arxiv-000?logoColor=FFE165&logo=arxiv&style=for-the-badge" alt="Paper on Arxiv"></a>
|
20 |
+
<a href="https://docs.google.com/spreadsheets/d/1wOUdFCMyY6Nt0AIqF705KN4JKOWgeI4wUGUP60krXXs/edit?gid=0#gid=0"><img src="https://img.shields.io/badge/Benchmark%20score-000?logoColor=FFE165&logo=huggingface&style=for-the-badge" alt="Evaluation Benchmark Score"></a>
|
21 |
+
<hr>
|
22 |
+
</div>
|
23 |
+
|
24 |
+
Welcome to OpenHands (formerly OpenDevin), a platform for software development agents powered by AI.
|
25 |
+
|
26 |
+
OpenHands agents can do anything a human developer can: modify code, run commands, browse the web,
|
27 |
+
call APIs, and yes—even copy code snippets from StackOverflow.
|
28 |
+
|
29 |
+
Learn more at [docs.all-hands.dev](https://docs.all-hands.dev), or [sign up for OpenHands Cloud](https://app.all-hands.dev) to get started.
|
30 |
+
|
31 |
+
> [!IMPORTANT]
|
32 |
+
> Using OpenHands for work? We'd love to chat! Fill out
|
33 |
+
> [this short form](https://docs.google.com/forms/d/e/1FAIpQLSet3VbGaz8z32gW9Wm-Grl4jpt5WgMXPgJ4EDPVmCETCBpJtQ/viewform)
|
34 |
+
> to join our Design Partner program, where you'll get early access to commercial features and the opportunity to provide input on our product roadmap.
|
35 |
+
|
36 |
+

|
37 |
+
|
38 |
+
## ☁️ OpenHands Cloud
|
39 |
+
The easiest way to get started with OpenHands is on [OpenHands Cloud](https://app.all-hands.dev),
|
40 |
+
which comes with $50 in free credits for new users.
|
41 |
+
|
42 |
+
## 💻 Running OpenHands Locally
|
43 |
+
|
44 |
+
OpenHands can also run on your local system using Docker.
|
45 |
+
See the [Running OpenHands](https://docs.all-hands.dev/usage/installation) guide for
|
46 |
+
system requirements and more information.
|
47 |
+
|
48 |
+
> [!WARNING]
|
49 |
+
> On a public network? See our [Hardened Docker Installation Guide](https://docs.all-hands.dev/usage/runtimes/docker#hardened-docker-installation)
|
50 |
+
> to secure your deployment by restricting network binding and implementing additional security measures.
|
51 |
+
|
52 |
+
|
53 |
+
```bash
|
54 |
+
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.41-nikolaik
|
55 |
+
|
56 |
+
docker run -it --rm --pull=always \
|
57 |
+
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.41-nikolaik \
|
58 |
+
-e LOG_ALL_EVENTS=true \
|
59 |
+
-v /var/run/docker.sock:/var/run/docker.sock \
|
60 |
+
-v ~/.openhands-state:/.openhands-state \
|
61 |
+
-p 3000:3000 \
|
62 |
+
--add-host host.docker.internal:host-gateway \
|
63 |
+
--name openhands-app \
|
64 |
+
docker.all-hands.dev/all-hands-ai/openhands:0.41
|
65 |
+
```
|
66 |
+
|
67 |
+
You'll find OpenHands running at [http://localhost:3000](http://localhost:3000)!
|
68 |
+
|
69 |
+
When you open the application, you'll be asked to choose an LLM provider and add an API key.
|
70 |
+
[Anthropic's Claude Sonnet 4](https://www.anthropic.com/api) (`anthropic/claude-sonnet-4-20250514`)
|
71 |
+
works best, but you have [many options](https://docs.all-hands.dev/usage/llms).
|
72 |
+
|
73 |
+
## 💡 Other ways to run OpenHands
|
74 |
+
|
75 |
+
> [!CAUTION]
|
76 |
+
> OpenHands is meant to be run by a single user on their local workstation.
|
77 |
+
> It is not appropriate for multi-tenant deployments where multiple users share the same instance. There is no built-in authentication, isolation, or scalability.
|
78 |
+
>
|
79 |
+
> If you're interested in running OpenHands in a multi-tenant environment, please
|
80 |
+
> [get in touch with us](https://docs.google.com/forms/d/e/1FAIpQLSet3VbGaz8z32gW9Wm-Grl4jpt5WgMXPgJ4EDPVmCETCBpJtQ/viewform)
|
81 |
+
> for advanced deployment options.
|
82 |
+
|
83 |
+
You can also [connect OpenHands to your local filesystem](https://docs.all-hands.dev/usage/runtimes/docker#connecting-to-your-filesystem),
|
84 |
+
run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/usage/how-to/headless-mode),
|
85 |
+
interact with it via a [friendly CLI](https://docs.all-hands.dev/usage/how-to/cli-mode),
|
86 |
+
or run it on tagged issues with [a github action](https://docs.all-hands.dev/usage/how-to/github-action).
|
87 |
+
|
88 |
+
Visit [Running OpenHands](https://docs.all-hands.dev/usage/installation) for more information and setup instructions.
|
89 |
+
|
90 |
+
If you want to modify the OpenHands source code, check out [Development.md](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md).
|
91 |
+
|
92 |
+
Having issues? The [Troubleshooting Guide](https://docs.all-hands.dev/usage/troubleshooting) can help.
|
93 |
+
|
94 |
+
## 📖 Documentation
|
95 |
+
<a href="https://deepwiki.com/All-Hands-AI/OpenHands"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki" title="Autogenerated Documentation by DeepWiki"></a>
|
96 |
+
|
97 |
+
To learn more about the project, and for tips on using OpenHands,
|
98 |
+
check out our [documentation](https://docs.all-hands.dev/usage/getting-started).
|
99 |
+
|
100 |
+
There you'll find resources on how to use different LLM providers,
|
101 |
+
troubleshooting resources, and advanced configuration options.
|
102 |
+
|
103 |
+
## 🤝 How to Join the Community
|
104 |
+
|
105 |
+
OpenHands is a community-driven project, and we welcome contributions from everyone. We do most of our communication
|
106 |
+
through Slack, so this is the best place to start, but we also are happy to have you contact us on Discord or Github:
|
107 |
+
|
108 |
+
- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-34zm4j0gj-Qz5kRHoca8DFCbqXPS~f_A) - Here we talk about research, architecture, and future development.
|
109 |
+
- [Join our Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback.
|
110 |
+
- [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.
|
111 |
+
|
112 |
+
See more about the community in [COMMUNITY.md](./COMMUNITY.md) or find details on contributing in [CONTRIBUTING.md](./CONTRIBUTING.md).
|
113 |
+
|
114 |
+
## 📈 Progress
|
115 |
+
|
116 |
+
See the monthly OpenHands roadmap [here](https://github.com/orgs/All-Hands-AI/projects/1) (updated at the maintainer's meeting at the end of each month).
|
117 |
+
|
118 |
+
<p align="center">
|
119 |
+
<a href="https://star-history.com/#All-Hands-AI/OpenHands&Date">
|
120 |
+
<img src="https://api.star-history.com/svg?repos=All-Hands-AI/OpenHands&type=Date" width="500" alt="Star History Chart">
|
121 |
+
</a>
|
122 |
+
</p>
|
123 |
+
|
124 |
+
## 📜 License
|
125 |
+
|
126 |
+
Distributed under the MIT License. See [`LICENSE`](./LICENSE) for more information.
|
127 |
+
|
128 |
+
## 🙏 Acknowledgements
|
129 |
+
|
130 |
+
OpenHands is built by a large number of contributors, and every contribution is greatly appreciated! We also build upon other open source projects, and we are deeply thankful for their work.
|
131 |
+
|
132 |
+
For a list of open source projects and licenses used in OpenHands, please see our [CREDITS.md](./CREDITS.md) file.
|
133 |
+
|
134 |
+
## 📚 Cite
|
135 |
+
|
136 |
+
```
|
137 |
+
@misc{openhands,
|
138 |
+
title={{OpenHands: An Open Platform for AI Software Developers as Generalist Agents}},
|
139 |
+
author={Xingyao Wang and Boxuan Li and Yufan Song and Frank F. Xu and Xiangru Tang and Mingchen Zhuge and Jiayi Pan and Yueqi Song and Bowen Li and Jaskirat Singh and Hoang H. Tran and Fuqiang Li and Ren Ma and Mingzhang Zheng and Bill Qian and Yanjun Shao and Niklas Muennighoff and Yizhe Zhang and Binyuan Hui and Junyang Lin and Robert Brennan and Hao Peng and Heng Ji and Graham Neubig},
|
140 |
+
year={2024},
|
141 |
+
eprint={2407.16741},
|
142 |
+
archivePrefix={arXiv},
|
143 |
+
primaryClass={cs.SE},
|
144 |
+
url={https://arxiv.org/abs/2407.16741},
|
145 |
+
}
|
146 |
+
```
|
README_CN.md
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<a name="readme-top"></a>
|
3 |
+
|
4 |
+
<div align="center">
|
5 |
+
<img src="./docs/static/img/logo.png" alt="Logo" width="200">
|
6 |
+
<h1 align="center">OpenHands: 少写代码,多做事</h1>
|
7 |
+
</div>
|
8 |
+
|
9 |
+
|
10 |
+
<div align="center">
|
11 |
+
<a href="https://github.com/All-Hands-AI/OpenHands/graphs/contributors"><img src="https://img.shields.io/github/contributors/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="Contributors"></a>
|
12 |
+
<a href="https://github.com/All-Hands-AI/OpenHands/stargazers"><img src="https://img.shields.io/github/stars/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="Stargazers"></a>
|
13 |
+
<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>
|
14 |
+
<br/>
|
15 |
+
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-34zm4j0gj-Qz5kRHoca8DFCbqXPS~f_A"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="加入我们的Slack社区"></a>
|
16 |
+
<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="加入我们的Discord社区"></a>
|
17 |
+
<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="致谢"></a>
|
18 |
+
<br/>
|
19 |
+
<a href="https://docs.all-hands.dev/usage/getting-started"><img src="https://img.shields.io/badge/Documentation-000?logo=googledocs&logoColor=FFE165&style=for-the-badge" alt="查看文档"></a>
|
20 |
+
<a href="https://arxiv.org/abs/2407.16741"><img src="https://img.shields.io/badge/Paper%20on%20Arxiv-000?logoColor=FFE165&logo=arxiv&style=for-the-badge" alt="Arxiv论文"></a>
|
21 |
+
<a href="https://docs.google.com/spreadsheets/d/1wOUdFCMyY6Nt0AIqF705KN4JKOWgeI4wUGUP60krXXs/edit?gid=0#gid=0"><img src="https://img.shields.io/badge/Benchmark%20score-000?logoColor=FFE165&logo=huggingface&style=for-the-badge" alt="评估基准分数"></a>
|
22 |
+
<hr>
|
23 |
+
</div>
|
24 |
+
|
25 |
+
欢迎使用OpenHands(前身为OpenDevin),这是一个由AI驱动的软件开发代理平台。
|
26 |
+
|
27 |
+
OpenHands代理可以完成人类开发者能做的任何事情:修改代码、运行命令、浏览网页、调用API,甚至从StackOverflow复制代码片段。
|
28 |
+
|
29 |
+
在[docs.all-hands.dev](https://docs.all-hands.dev)了解更多信息,或[注册OpenHands Cloud](https://app.all-hands.dev)开始使用。
|
30 |
+
|
31 |
+
> [!IMPORTANT]
|
32 |
+
> 在工作中使用OpenHands?我们很想与您交流!填写
|
33 |
+
> [这份简短表格](https://docs.google.com/forms/d/e/1FAIpQLSet3VbGaz8z32gW9Wm-Grl4jpt5WgMXPgJ4EDPVmCETCBpJtQ/viewform)
|
34 |
+
> 加入我们的设计合作伙伴计划,您将获得商业功能的早期访问权限,并有机会对我们的产品路线图提供意见。
|
35 |
+
|
36 |
+

|
37 |
+
|
38 |
+
## ☁️ OpenHands Cloud
|
39 |
+
开始使用OpenHands的最简单方式是在[OpenHands Cloud](https://app.all-hands.dev)上,
|
40 |
+
新用户可获得$50的免费额度。
|
41 |
+
|
42 |
+
## 💻 在本地运行OpenHands
|
43 |
+
|
44 |
+
OpenHands也可以使用Docker在本地系统上运行。
|
45 |
+
查看[运行OpenHands](https://docs.all-hands.dev/usage/installation)指南了解
|
46 |
+
系统要求和更多信息。
|
47 |
+
|
48 |
+
> [!WARNING]
|
49 |
+
> 在公共网络上?请参阅我们的[强化Docker安装指南](https://docs.all-hands.dev/usage/runtimes/docker#hardened-docker-installation)
|
50 |
+
> 通过限制网络绑定和实施其他安全措施来保护您的部署。
|
51 |
+
|
52 |
+
|
53 |
+
```bash
|
54 |
+
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.41-nikolaik
|
55 |
+
|
56 |
+
docker run -it --rm --pull=always \
|
57 |
+
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.41-nikolaik \
|
58 |
+
-e LOG_ALL_EVENTS=true \
|
59 |
+
-v /var/run/docker.sock:/var/run/docker.sock \
|
60 |
+
-v ~/.openhands-state:/.openhands-state \
|
61 |
+
-p 3000:3000 \
|
62 |
+
--add-host host.docker.internal:host-gateway \
|
63 |
+
--name openhands-app \
|
64 |
+
docker.all-hands.dev/all-hands-ai/openhands:0.41
|
65 |
+
```
|
66 |
+
|
67 |
+
您将在[http://localhost:3000](http://localhost:3000)找到运行中的OpenHands!
|
68 |
+
|
69 |
+
打开应用程序时,您将被要求选择一个LLM提供商并添加API密钥。
|
70 |
+
[Anthropic的Claude Sonnet 4](https://www.anthropic.com/api)(`anthropic/claude-sonnet-4-20250514`)
|
71 |
+
效果最佳,但您还有[许多选择](https://docs.all-hands.dev/usage/llms)。
|
72 |
+
|
73 |
+
## 💡 运行OpenHands的其他方式
|
74 |
+
|
75 |
+
> [!CAUTION]
|
76 |
+
> OpenHands旨在由单个用户在其本地工作站上运行。
|
77 |
+
> 它不适合多租户部署,即多个用户共享同一实例。没有内置的身份验证、隔离或可扩展性。
|
78 |
+
>
|
79 |
+
> 如果您有兴趣在多租户环境中运行OpenHands,请
|
80 |
+
> [与我们联系](https://docs.google.com/forms/d/e/1FAIpQLSet3VbGaz8z32gW9Wm-Grl4jpt5WgMXPgJ4EDPVmCETCBpJtQ/viewform)
|
81 |
+
> 了解高级部署选项。
|
82 |
+
|
83 |
+
您还可以[将OpenHands连接到本地文件系统](https://docs.all-hands.dev/usage/runtimes/docker#connecting-to-your-filesystem),
|
84 |
+
以可编程的[无头模���](https://docs.all-hands.dev/usage/how-to/headless-mode)运行OpenHands,
|
85 |
+
通过[友好的CLI](https://docs.all-hands.dev/usage/how-to/cli-mode)与其交互,
|
86 |
+
或使用[GitHub Action](https://docs.all-hands.dev/usage/how-to/github-action)在标记的问题上运行它。
|
87 |
+
|
88 |
+
访问[运行OpenHands](https://docs.all-hands.dev/usage/installation)获取更多信息和设置说明。
|
89 |
+
|
90 |
+
如果您想修改OpenHands源代码,请查看[Development.md](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md)。
|
91 |
+
|
92 |
+
遇到问题?[故障排除指南](https://docs.all-hands.dev/usage/troubleshooting)可以提供帮助。
|
93 |
+
|
94 |
+
## 📖 文档
|
95 |
+
<a href="https://deepwiki.com/All-Hands-AI/OpenHands"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki" title="DeepWiki自动生成文档"></a>
|
96 |
+
|
97 |
+
要了解有关项目的更多信息,以及使用OpenHands的技巧,
|
98 |
+
请查看我们的[文档](https://docs.all-hands.dev/usage/getting-started)。
|
99 |
+
|
100 |
+
在那里,您将找到有关如何使用不同LLM提供商、
|
101 |
+
故障排除资源和高级配置选项的资源。
|
102 |
+
|
103 |
+
## 🤝 如何加入社区
|
104 |
+
|
105 |
+
OpenHands是一个社区驱动的项目,我们欢迎每个人的贡献。我们大部分沟通
|
106 |
+
通过Slack进行,因此这是开始的最佳场所,但我们也很乐意您通过Discord或Github与我们联系:
|
107 |
+
|
108 |
+
- [加入我们的Slack工作空间](https://join.slack.com/t/openhands-ai/shared_invite/zt-34zm4j0gj-Qz5kRHoca8DFCbqXPS~f_A) - 这里我们讨论研究、架构和未来发展。
|
109 |
+
- [加入我们的Discord服务器](https://discord.gg/ESHStjSjD4) - 这是一个社区运营的服务器,用于一般讨论、问题和反馈。
|
110 |
+
- [阅读或发布Github问题](https://github.com/All-Hands-AI/OpenHands/issues) - 查看我们正在处理的问题,或添加您自己的想法。
|
111 |
+
|
112 |
+
在[COMMUNITY.md](./COMMUNITY.md)中了解更多关于社区的信息,或在[CONTRIBUTING.md](./CONTRIBUTING.md)中找到有关贡献的详细信息。
|
113 |
+
|
114 |
+
## 📈 进展
|
115 |
+
|
116 |
+
在[这里](https://github.com/orgs/All-Hands-AI/projects/1)查看OpenHands月度路线图(每月月底在维护者会议上更新)。
|
117 |
+
|
118 |
+
<p align="center">
|
119 |
+
<a href="https://star-history.com/#All-Hands-AI/OpenHands&Date">
|
120 |
+
<img src="https://api.star-history.com/svg?repos=All-Hands-AI/OpenHands&type=Date" width="500" alt="Star History Chart">
|
121 |
+
</a>
|
122 |
+
</p>
|
123 |
+
|
124 |
+
## 📜 许可证
|
125 |
+
|
126 |
+
根据MIT许可证分发。有关更多信息,请参阅[`LICENSE`](./LICENSE)。
|
127 |
+
|
128 |
+
## 🙏 致谢
|
129 |
+
|
130 |
+
OpenHands由大量贡献者构建,每一份贡献都备受感谢!我们还借鉴了其他开源项目,对他们的工作深表感谢。
|
131 |
+
|
132 |
+
有关OpenHands中使用的开源项目和许可证列表,请参阅我们的[CREDITS.md](./CREDITS.md)文件。
|
133 |
+
|
134 |
+
## 📚 引用
|
135 |
+
|
136 |
+
```
|
137 |
+
@misc{openhands,
|
138 |
+
title={{OpenHands: An Open Platform for AI Software Developers as Generalist Agents}},
|
139 |
+
author={Xingyao Wang and Boxuan Li and Yufan Song and Frank F. Xu and Xiangru Tang and Mingchen Zhuge and Jiayi Pan and Yueqi Song and Bowen Li and Jaskirat Singh and Hoang H. Tran and Fuqiang Li and Ren Ma and Mingzhang Zheng and Bill Qian and Yanjun Shao and Niklas Muennighoff and Yizhe Zhang and Binyuan Hui and Junyang Lin and Robert Brennan and Hao Peng and Heng Ji and Graham Neubig},
|
140 |
+
year={2024},
|
141 |
+
eprint={2407.16741},
|
142 |
+
archivePrefix={arXiv},
|
143 |
+
primaryClass={cs.SE},
|
144 |
+
url={https://arxiv.org/abs/2407.16741},
|
145 |
+
}
|
146 |
+
```
|
build.sh
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
set -e
|
3 |
+
|
4 |
+
poetry build -v
|
config.template.toml
ADDED
@@ -0,0 +1,417 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
###################### OpenHands Configuration Example ######################
|
2 |
+
#
|
3 |
+
# All settings have default values, so you only need to uncomment and
|
4 |
+
# modify what you want to change
|
5 |
+
# The fields within each section are sorted in alphabetical order.
|
6 |
+
#
|
7 |
+
##############################################################################
|
8 |
+
|
9 |
+
#################################### Core ####################################
|
10 |
+
# General core configurations
|
11 |
+
##############################################################################
|
12 |
+
[core]
|
13 |
+
# API key for E2B
|
14 |
+
#e2b_api_key = ""
|
15 |
+
|
16 |
+
# API key for Modal
|
17 |
+
#modal_api_token_id = ""
|
18 |
+
#modal_api_token_secret = ""
|
19 |
+
|
20 |
+
# API key for Daytona
|
21 |
+
#daytona_api_key = ""
|
22 |
+
|
23 |
+
# Daytona Target
|
24 |
+
#daytona_target = ""
|
25 |
+
|
26 |
+
# Base path for the workspace
|
27 |
+
#workspace_base = "./workspace"
|
28 |
+
|
29 |
+
# Cache directory path
|
30 |
+
#cache_dir = "/tmp/cache"
|
31 |
+
|
32 |
+
# Reasoning effort for o1 models (low, medium, high, or not set)
|
33 |
+
#reasoning_effort = "medium"
|
34 |
+
|
35 |
+
# Debugging enabled
|
36 |
+
#debug = false
|
37 |
+
|
38 |
+
# Disable color in terminal output
|
39 |
+
#disable_color = false
|
40 |
+
|
41 |
+
# Path to store trajectories, can be a folder or a file
|
42 |
+
# If it's a folder, the session id will be used as the file name
|
43 |
+
#save_trajectory_path="./trajectories"
|
44 |
+
|
45 |
+
# Whether to save screenshots in the trajectory
|
46 |
+
# The screenshots are encoded and can make trajectory json files very large
|
47 |
+
#save_screenshots_in_trajectory = false
|
48 |
+
|
49 |
+
# Path to replay a trajectory, must be a file path
|
50 |
+
# If provided, trajectory will be loaded and replayed before the
|
51 |
+
# agent responds to any user instruction
|
52 |
+
#replay_trajectory_path = ""
|
53 |
+
|
54 |
+
# File store path
|
55 |
+
#file_store_path = "/tmp/file_store"
|
56 |
+
|
57 |
+
# File store type
|
58 |
+
#file_store = "memory"
|
59 |
+
|
60 |
+
# Maximum file size for uploads, in megabytes
|
61 |
+
#file_uploads_max_file_size_mb = 0
|
62 |
+
|
63 |
+
# Maximum budget per task, 0.0 means no limit
|
64 |
+
#max_budget_per_task = 0.0
|
65 |
+
|
66 |
+
# Maximum number of iterations
|
67 |
+
#max_iterations = 250
|
68 |
+
|
69 |
+
# Path to mount the workspace in the sandbox
|
70 |
+
#workspace_mount_path_in_sandbox = "/workspace"
|
71 |
+
|
72 |
+
# Path to mount the workspace
|
73 |
+
#workspace_mount_path = ""
|
74 |
+
|
75 |
+
# Path to rewrite the workspace mount path to
|
76 |
+
#workspace_mount_rewrite = ""
|
77 |
+
|
78 |
+
# Run as openhands
|
79 |
+
#run_as_openhands = true
|
80 |
+
|
81 |
+
# Runtime environment
|
82 |
+
#runtime = "docker"
|
83 |
+
|
84 |
+
# Name of the default agent
|
85 |
+
#default_agent = "CodeActAgent"
|
86 |
+
|
87 |
+
# JWT secret for authentication
|
88 |
+
#jwt_secret = ""
|
89 |
+
|
90 |
+
# Restrict file types for file uploads
|
91 |
+
#file_uploads_restrict_file_types = false
|
92 |
+
|
93 |
+
# List of allowed file extensions for uploads
|
94 |
+
#file_uploads_allowed_extensions = [".*"]
|
95 |
+
|
96 |
+
# Whether to enable the default LLM summarizing condenser when no condenser is specified in config
|
97 |
+
# When true, a LLMSummarizingCondenserConfig will be used as the default condenser
|
98 |
+
# When false, a NoOpCondenserConfig (no summarization) will be used
|
99 |
+
#enable_default_condenser = true
|
100 |
+
|
101 |
+
# Maximum number of concurrent conversations per user
|
102 |
+
#max_concurrent_conversations = 3
|
103 |
+
|
104 |
+
# Maximum age of conversations in seconds before they are automatically closed
|
105 |
+
#conversation_max_age_seconds = 864000 # 10 days
|
106 |
+
|
107 |
+
#################################### LLM #####################################
|
108 |
+
# Configuration for LLM models (group name starts with 'llm')
|
109 |
+
# use 'llm' for the default LLM config
|
110 |
+
##############################################################################
|
111 |
+
[llm]
|
112 |
+
# AWS access key ID
|
113 |
+
#aws_access_key_id = ""
|
114 |
+
|
115 |
+
# AWS region name
|
116 |
+
#aws_region_name = ""
|
117 |
+
|
118 |
+
# AWS secret access key
|
119 |
+
#aws_secret_access_key = ""
|
120 |
+
|
121 |
+
# API key to use (For Headless / CLI only - In Web this is overridden by Session Init)
|
122 |
+
api_key = ""
|
123 |
+
|
124 |
+
# API base URL (For Headless / CLI only - In Web this is overridden by Session Init)
|
125 |
+
#base_url = ""
|
126 |
+
|
127 |
+
# API version
|
128 |
+
#api_version = ""
|
129 |
+
|
130 |
+
# Cost per input token
|
131 |
+
#input_cost_per_token = 0.0
|
132 |
+
|
133 |
+
# Cost per output token
|
134 |
+
#output_cost_per_token = 0.0
|
135 |
+
|
136 |
+
# Custom LLM provider
|
137 |
+
#custom_llm_provider = ""
|
138 |
+
|
139 |
+
# Maximum number of characters in an observation's content
|
140 |
+
#max_message_chars = 10000
|
141 |
+
|
142 |
+
# Maximum number of input tokens
|
143 |
+
#max_input_tokens = 0
|
144 |
+
|
145 |
+
# Maximum number of output tokens
|
146 |
+
#max_output_tokens = 0
|
147 |
+
|
148 |
+
# Model to use. (For Headless / CLI only - In Web this is overridden by Session Init)
|
149 |
+
model = "gpt-4o"
|
150 |
+
|
151 |
+
# Number of retries to attempt when an operation fails with the LLM.
|
152 |
+
# Increase this value to allow more attempts before giving up
|
153 |
+
#num_retries = 8
|
154 |
+
|
155 |
+
# Maximum wait time (in seconds) between retry attempts
|
156 |
+
# This caps the exponential backoff to prevent excessively long
|
157 |
+
#retry_max_wait = 120
|
158 |
+
|
159 |
+
# Minimum wait time (in seconds) between retry attempts
|
160 |
+
# This sets the initial delay before the first retry
|
161 |
+
#retry_min_wait = 15
|
162 |
+
|
163 |
+
# Multiplier for exponential backoff calculation
|
164 |
+
# The wait time increases by this factor after each failed attempt
|
165 |
+
# A value of 2.0 means each retry waits twice as long as the previous one
|
166 |
+
#retry_multiplier = 2.0
|
167 |
+
|
168 |
+
# Drop any unmapped (unsupported) params without causing an exception
|
169 |
+
#drop_params = false
|
170 |
+
|
171 |
+
# Modify params for litellm to do transformations like adding a default message, when a message is empty.
|
172 |
+
# Note: this setting is global, unlike drop_params, it cannot be overridden in each call to litellm.
|
173 |
+
#modify_params = true
|
174 |
+
|
175 |
+
# Using the prompt caching feature if provided by the LLM and supported
|
176 |
+
#caching_prompt = true
|
177 |
+
|
178 |
+
# Base URL for the OLLAMA API
|
179 |
+
#ollama_base_url = ""
|
180 |
+
|
181 |
+
# Temperature for the API
|
182 |
+
#temperature = 0.0
|
183 |
+
|
184 |
+
# Timeout for the API
|
185 |
+
#timeout = 0
|
186 |
+
|
187 |
+
# Top p for the API
|
188 |
+
#top_p = 1.0
|
189 |
+
|
190 |
+
# If model is vision capable, this option allows to disable image processing (useful for cost reduction).
|
191 |
+
#disable_vision = true
|
192 |
+
|
193 |
+
# Custom tokenizer to use for token counting
|
194 |
+
# https://docs.litellm.ai/docs/completion/token_usage
|
195 |
+
#custom_tokenizer = ""
|
196 |
+
|
197 |
+
# Whether to use native tool calling if supported by the model. Can be true, false, or None by default, which chooses the model's default behavior based on the evaluation.
|
198 |
+
# ATTENTION: Based on evaluation, enabling native function calling may lead to worse results
|
199 |
+
# in some scenarios. Use with caution and consider testing with your specific use case.
|
200 |
+
# https://github.com/All-Hands-AI/OpenHands/pull/4711
|
201 |
+
#native_tool_calling = None
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
[llm.gpt4o-mini]
|
206 |
+
api_key = ""
|
207 |
+
model = "gpt-4o"
|
208 |
+
|
209 |
+
|
210 |
+
#################################### Agent ###################################
|
211 |
+
# Configuration for agents (group name starts with 'agent')
|
212 |
+
# Use 'agent' for the default agent config
|
213 |
+
# otherwise, group name must be `agent.<agent_name>` (case-sensitive), e.g.
|
214 |
+
# agent.CodeActAgent
|
215 |
+
##############################################################################
|
216 |
+
[agent]
|
217 |
+
|
218 |
+
# Whether the browsing tool is enabled
|
219 |
+
enable_browsing = true
|
220 |
+
|
221 |
+
# Whether the LLM draft editor is enabled
|
222 |
+
enable_llm_editor = false
|
223 |
+
|
224 |
+
# Whether the standard editor tool (str_replace_editor) is enabled
|
225 |
+
# Only has an effect if enable_llm_editor is False
|
226 |
+
enable_editor = true
|
227 |
+
|
228 |
+
# Whether the IPython tool is enabled
|
229 |
+
enable_jupyter = true
|
230 |
+
|
231 |
+
# Whether the command tool is enabled
|
232 |
+
enable_cmd = true
|
233 |
+
|
234 |
+
# Whether the think tool is enabled
|
235 |
+
enable_think = true
|
236 |
+
|
237 |
+
# Whether the finish tool is enabled
|
238 |
+
enable_finish = true
|
239 |
+
|
240 |
+
# LLM config group to use
|
241 |
+
#llm_config = 'your-llm-config-group'
|
242 |
+
|
243 |
+
# Whether to use prompt extension (e.g., microagent, repo/runtime info) at all
|
244 |
+
#enable_prompt_extensions = true
|
245 |
+
|
246 |
+
# List of microagents to disable
|
247 |
+
#disabled_microagents = []
|
248 |
+
|
249 |
+
# Whether history should be truncated to continue the session when hitting LLM context
|
250 |
+
# length limit
|
251 |
+
enable_history_truncation = true
|
252 |
+
|
253 |
+
[agent.RepoExplorerAgent]
|
254 |
+
# Example: use a cheaper model for RepoExplorerAgent to reduce cost, especially
|
255 |
+
# useful when an agent doesn't demand high quality but uses a lot of tokens
|
256 |
+
llm_config = 'gpt3'
|
257 |
+
|
258 |
+
[agent.CustomAgent]
|
259 |
+
# Example: use a custom agent from a different package
|
260 |
+
# This will be automatically be registered as a new agent named "CustomAgent"
|
261 |
+
classpath = "my_package.my_module.MyCustomAgent"
|
262 |
+
|
263 |
+
#################################### Sandbox ###################################
|
264 |
+
# Configuration for the sandbox
|
265 |
+
##############################################################################
|
266 |
+
[sandbox]
|
267 |
+
# Sandbox timeout in seconds
|
268 |
+
#timeout = 120
|
269 |
+
|
270 |
+
# Sandbox user ID
|
271 |
+
#user_id = 1000
|
272 |
+
|
273 |
+
# Container image to use for the sandbox
|
274 |
+
#base_container_image = "nikolaik/python-nodejs:python3.12-nodejs22"
|
275 |
+
|
276 |
+
# Use host network
|
277 |
+
#use_host_network = false
|
278 |
+
|
279 |
+
# Runtime extra build args
|
280 |
+
#runtime_extra_build_args = ["--network=host", "--add-host=host.docker.internal:host-gateway"]
|
281 |
+
|
282 |
+
# Enable auto linting after editing
|
283 |
+
#enable_auto_lint = false
|
284 |
+
|
285 |
+
# Whether to initialize plugins
|
286 |
+
#initialize_plugins = true
|
287 |
+
|
288 |
+
# Extra dependencies to install in the runtime image
|
289 |
+
#runtime_extra_deps = ""
|
290 |
+
|
291 |
+
# Environment variables to set at the launch of the runtime
|
292 |
+
#runtime_startup_env_vars = {}
|
293 |
+
|
294 |
+
# BrowserGym environment to use for evaluation
|
295 |
+
#browsergym_eval_env = ""
|
296 |
+
|
297 |
+
# Platform to use for building the runtime image (e.g., "linux/amd64")
|
298 |
+
#platform = ""
|
299 |
+
|
300 |
+
# Force rebuild of runtime image even if it exists
|
301 |
+
#force_rebuild_runtime = false
|
302 |
+
|
303 |
+
# Runtime container image to use (if not provided, will be built from base_container_image)
|
304 |
+
#runtime_container_image = ""
|
305 |
+
|
306 |
+
# Keep runtime alive after session ends
|
307 |
+
#keep_runtime_alive = false
|
308 |
+
|
309 |
+
# Pause closed runtimes instead of stopping them
|
310 |
+
#pause_closed_runtimes = false
|
311 |
+
|
312 |
+
# Delay in seconds before closing idle runtimes
|
313 |
+
#close_delay = 300
|
314 |
+
|
315 |
+
# Remove all containers when stopping the runtime
|
316 |
+
#rm_all_containers = false
|
317 |
+
|
318 |
+
# Enable GPU support in the runtime
|
319 |
+
#enable_gpu = false
|
320 |
+
|
321 |
+
# Additional Docker runtime kwargs
|
322 |
+
#docker_runtime_kwargs = {}
|
323 |
+
|
324 |
+
# Specific port to use for VSCode. If not set, a random port will be chosen.
|
325 |
+
# Useful when deploying OpenHands in a remote machine where you need to expose a specific port.
|
326 |
+
#vscode_port = 41234
|
327 |
+
|
328 |
+
# Volume mounts in the format 'host_path:container_path[:mode]'
|
329 |
+
# e.g. '/my/host/dir:/workspace:rw'
|
330 |
+
# Multiple mounts can be specified using commas
|
331 |
+
# e.g. '/path1:/workspace/path1,/path2:/workspace/path2:ro'
|
332 |
+
|
333 |
+
# Configure volumes under the [sandbox] section:
|
334 |
+
# [sandbox]
|
335 |
+
# volumes = "/my/host/dir:/workspace:rw,/path2:/workspace/path2:ro"
|
336 |
+
|
337 |
+
#################################### Security ###################################
|
338 |
+
# Configuration for security features
|
339 |
+
##############################################################################
|
340 |
+
[security]
|
341 |
+
|
342 |
+
# Enable confirmation mode (For Headless / CLI only - In Web this is overridden by Session Init)
|
343 |
+
#confirmation_mode = false
|
344 |
+
|
345 |
+
# The security analyzer to use (For Headless / CLI only - In Web this is overridden by Session Init)
|
346 |
+
#security_analyzer = ""
|
347 |
+
|
348 |
+
# Whether to enable security analyzer
|
349 |
+
#enable_security_analyzer = false
|
350 |
+
|
351 |
+
#################################### Condenser #################################
|
352 |
+
# Condensers control how conversation history is managed and compressed when
|
353 |
+
# the context grows too large. Each agent uses one condenser configuration.
|
354 |
+
##############################################################################
|
355 |
+
[condenser]
|
356 |
+
# The type of condenser to use. Available options:
|
357 |
+
# - "noop": No condensing, keeps full history (default)
|
358 |
+
# - "observation_masking": Keeps full event structure but masks older observations
|
359 |
+
# - "recent": Keeps only recent events and discards older ones
|
360 |
+
# - "llm": Uses an LLM to summarize conversation history
|
361 |
+
# - "amortized": Intelligently forgets older events while preserving important context
|
362 |
+
# - "llm_attention": Uses an LLM to prioritize most relevant context
|
363 |
+
type = "noop"
|
364 |
+
|
365 |
+
# Examples for each condenser type (uncomment and modify as needed):
|
366 |
+
|
367 |
+
# 1. NoOp Condenser - No additional settings needed
|
368 |
+
#type = "noop"
|
369 |
+
|
370 |
+
# 2. Observation Masking Condenser
|
371 |
+
#type = "observation_masking"
|
372 |
+
# Number of most-recent events where observations will not be masked
|
373 |
+
#attention_window = 100
|
374 |
+
|
375 |
+
# 3. Recent Events Condenser
|
376 |
+
#type = "recent"
|
377 |
+
# Number of initial events to always keep (typically includes task description)
|
378 |
+
#keep_first = 1
|
379 |
+
# Maximum number of events to keep in history
|
380 |
+
#max_events = 100
|
381 |
+
|
382 |
+
# 4. LLM Summarizing Condenser
|
383 |
+
#type = "llm"
|
384 |
+
# Reference to an LLM config to use for summarization
|
385 |
+
#llm_config = "condenser"
|
386 |
+
# Number of initial events to always keep (typically includes task description)
|
387 |
+
#keep_first = 1
|
388 |
+
# Maximum size of history before triggering summarization
|
389 |
+
#max_size = 100
|
390 |
+
|
391 |
+
# 5. Amortized Forgetting Condenser
|
392 |
+
#type = "amortized"
|
393 |
+
# Number of initial events to always keep (typically includes task description)
|
394 |
+
#keep_first = 1
|
395 |
+
# Maximum size of history before triggering forgetting
|
396 |
+
#max_size = 100
|
397 |
+
|
398 |
+
# 6. LLM Attention Condenser
|
399 |
+
#type = "llm_attention"
|
400 |
+
# Reference to an LLM config to use for attention scoring
|
401 |
+
#llm_config = "condenser"
|
402 |
+
# Number of initial events to always keep (typically includes task description)
|
403 |
+
#keep_first = 1
|
404 |
+
# Maximum size of history before triggering attention mechanism
|
405 |
+
#max_size = 100
|
406 |
+
|
407 |
+
# Example of a custom LLM configuration for condensers that require an LLM
|
408 |
+
# If not provided, it falls back to the default LLM
|
409 |
+
#[llm.condenser]
|
410 |
+
#model = "gpt-4o"
|
411 |
+
#temperature = 0.1
|
412 |
+
#max_input_tokens = 1024
|
413 |
+
|
414 |
+
#################################### Eval ####################################
|
415 |
+
# Configuration for the evaluation, please refer to the specific evaluation
|
416 |
+
# plugin for the available options
|
417 |
+
##############################################################################
|
containers/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Docker Containers
|
2 |
+
|
3 |
+
Each folder here contains a Dockerfile, and a config.sh describing how to build
|
4 |
+
the images and where to push them. These images are built and pushed in GitHub Actions
|
5 |
+
by the `ghcr.yml` workflow.
|
6 |
+
|
7 |
+
## Building Manually
|
8 |
+
|
9 |
+
```bash
|
10 |
+
docker build -f containers/app/Dockerfile -t openhands .
|
11 |
+
docker build -f containers/sandbox/Dockerfile -t sandbox .
|
12 |
+
```
|
containers/app/Dockerfile
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
ARG OPENHANDS_BUILD_VERSION=dev
|
2 |
+
FROM node:21.7.2-bookworm-slim AS frontend-builder
|
3 |
+
|
4 |
+
WORKDIR /app
|
5 |
+
|
6 |
+
COPY ./frontend/package.json frontend/package-lock.json ./
|
7 |
+
RUN npm install -g [email protected]
|
8 |
+
RUN npm ci
|
9 |
+
|
10 |
+
COPY ./frontend ./
|
11 |
+
RUN npm run build
|
12 |
+
|
13 |
+
FROM python:3.12.3-slim AS backend-builder
|
14 |
+
|
15 |
+
WORKDIR /app
|
16 |
+
ENV PYTHONPATH='/app'
|
17 |
+
|
18 |
+
ENV POETRY_NO_INTERACTION=1 \
|
19 |
+
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
20 |
+
POETRY_VIRTUALENVS_CREATE=1 \
|
21 |
+
POETRY_CACHE_DIR=/tmp/poetry_cache
|
22 |
+
|
23 |
+
RUN apt-get update -y \
|
24 |
+
&& apt-get install -y curl make git build-essential \
|
25 |
+
&& python3 -m pip install poetry==1.8.2 --break-system-packages
|
26 |
+
|
27 |
+
COPY ./pyproject.toml ./poetry.lock ./
|
28 |
+
RUN touch README.md
|
29 |
+
RUN export POETRY_CACHE_DIR && poetry install --no-root && rm -rf $POETRY_CACHE_DIR
|
30 |
+
|
31 |
+
FROM python:3.12.3-slim AS openhands-app
|
32 |
+
|
33 |
+
WORKDIR /app
|
34 |
+
|
35 |
+
ARG OPENHANDS_BUILD_VERSION #re-declare for this section
|
36 |
+
|
37 |
+
ENV RUN_AS_OPENHANDS=true
|
38 |
+
# A random number--we need this to be different from the user's UID on the host machine
|
39 |
+
ENV OPENHANDS_USER_ID=42420
|
40 |
+
ENV SANDBOX_LOCAL_RUNTIME_URL=http://host.docker.internal
|
41 |
+
ENV USE_HOST_NETWORK=false
|
42 |
+
ENV WORKSPACE_BASE=/opt/workspace_base
|
43 |
+
ENV OPENHANDS_BUILD_VERSION=$OPENHANDS_BUILD_VERSION
|
44 |
+
ENV SANDBOX_USER_ID=0
|
45 |
+
ENV FILE_STORE=local
|
46 |
+
ENV FILE_STORE_PATH=/.openhands-state
|
47 |
+
RUN mkdir -p $FILE_STORE_PATH
|
48 |
+
RUN mkdir -p $WORKSPACE_BASE
|
49 |
+
|
50 |
+
RUN apt-get update -y \
|
51 |
+
&& apt-get install -y curl ssh sudo \
|
52 |
+
&& rm -rf /var/lib/apt/lists/*
|
53 |
+
|
54 |
+
# Default is 1000, but OSX is often 501
|
55 |
+
RUN sed -i 's/^UID_MIN.*/UID_MIN 499/' /etc/login.defs
|
56 |
+
# Default is 60000, but we've seen up to 200000
|
57 |
+
RUN sed -i 's/^UID_MAX.*/UID_MAX 1000000/' /etc/login.defs
|
58 |
+
|
59 |
+
RUN groupadd app
|
60 |
+
RUN useradd -l -m -u $OPENHANDS_USER_ID -s /bin/bash openhands && \
|
61 |
+
usermod -aG app openhands && \
|
62 |
+
usermod -aG sudo openhands && \
|
63 |
+
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
64 |
+
RUN chown -R openhands:app /app && chmod -R 770 /app
|
65 |
+
RUN sudo chown -R openhands:app $WORKSPACE_BASE && sudo chmod -R 770 $WORKSPACE_BASE
|
66 |
+
USER openhands
|
67 |
+
|
68 |
+
ENV VIRTUAL_ENV=/app/.venv \
|
69 |
+
PATH="/app/.venv/bin:$PATH" \
|
70 |
+
PYTHONPATH='/app'
|
71 |
+
|
72 |
+
COPY --chown=openhands:app --chmod=770 --from=backend-builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
|
73 |
+
|
74 |
+
COPY --chown=openhands:app --chmod=770 ./microagents ./microagents
|
75 |
+
COPY --chown=openhands:app --chmod=770 ./openhands ./openhands
|
76 |
+
COPY --chown=openhands:app --chmod=777 ./openhands/runtime/plugins ./openhands/runtime/plugins
|
77 |
+
COPY --chown=openhands:app --chmod=770 ./openhands/agenthub ./openhands/agenthub
|
78 |
+
COPY --chown=openhands:app ./pyproject.toml ./pyproject.toml
|
79 |
+
COPY --chown=openhands:app ./poetry.lock ./poetry.lock
|
80 |
+
COPY --chown=openhands:app ./README.md ./README.md
|
81 |
+
COPY --chown=openhands:app ./MANIFEST.in ./MANIFEST.in
|
82 |
+
COPY --chown=openhands:app ./LICENSE ./LICENSE
|
83 |
+
|
84 |
+
# This is run as "openhands" user, and will create __pycache__ with openhands:openhands ownership
|
85 |
+
RUN python openhands/core/download.py # No-op to download assets
|
86 |
+
# Add this line to set group ownership of all files/directories not already in "app" group
|
87 |
+
# openhands:openhands -> openhands:app
|
88 |
+
RUN find /app \! -group app -exec chgrp app {} +
|
89 |
+
|
90 |
+
COPY --chown=openhands:app --chmod=770 --from=frontend-builder /app/build ./frontend/build
|
91 |
+
COPY --chown=openhands:app --chmod=770 ./containers/app/entrypoint.sh /app/entrypoint.sh
|
92 |
+
|
93 |
+
USER root
|
94 |
+
|
95 |
+
WORKDIR /app
|
96 |
+
|
97 |
+
ENTRYPOINT ["/app/entrypoint.sh"]
|
98 |
+
CMD ["uvicorn", "openhands.server.listen:app", "--host", "0.0.0.0", "--port", "3000"]
|
containers/app/config.sh
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DOCKER_REGISTRY=ghcr.io
|
2 |
+
DOCKER_ORG=all-hands-ai
|
3 |
+
DOCKER_IMAGE=openhands
|
4 |
+
DOCKER_BASE_DIR="."
|
containers/app/entrypoint.sh
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
set -eo pipefail
|
3 |
+
|
4 |
+
echo "Starting OpenHands..."
|
5 |
+
if [[ $NO_SETUP == "true" ]]; then
|
6 |
+
echo "Skipping setup, running as $(whoami)"
|
7 |
+
"$@"
|
8 |
+
exit 0
|
9 |
+
fi
|
10 |
+
|
11 |
+
if [ "$(id -u)" -ne 0 ]; then
|
12 |
+
echo "The OpenHands entrypoint.sh must run as root"
|
13 |
+
exit 1
|
14 |
+
fi
|
15 |
+
|
16 |
+
if [ -z "$SANDBOX_USER_ID" ]; then
|
17 |
+
echo "SANDBOX_USER_ID is not set"
|
18 |
+
exit 1
|
19 |
+
fi
|
20 |
+
|
21 |
+
if [ -z "$WORKSPACE_MOUNT_PATH" ]; then
|
22 |
+
# This is set to /opt/workspace in the Dockerfile. But if the user isn't mounting, we want to unset it so that OpenHands doesn't mount at all
|
23 |
+
unset WORKSPACE_BASE
|
24 |
+
fi
|
25 |
+
|
26 |
+
if [[ "$SANDBOX_USER_ID" -eq 0 ]]; then
|
27 |
+
echo "Running OpenHands as root"
|
28 |
+
export RUN_AS_OPENHANDS=false
|
29 |
+
"$@"
|
30 |
+
else
|
31 |
+
echo "Setting up enduser with id $SANDBOX_USER_ID"
|
32 |
+
if id "enduser" &>/dev/null; then
|
33 |
+
echo "User enduser already exists. Skipping creation."
|
34 |
+
else
|
35 |
+
if ! useradd -l -m -u $SANDBOX_USER_ID -s /bin/bash enduser; then
|
36 |
+
echo "Failed to create user enduser with id $SANDBOX_USER_ID. Moving openhands user."
|
37 |
+
incremented_id=$(($SANDBOX_USER_ID + 1))
|
38 |
+
usermod -u $incremented_id openhands
|
39 |
+
if ! useradd -l -m -u $SANDBOX_USER_ID -s /bin/bash enduser; then
|
40 |
+
echo "Failed to create user enduser with id $SANDBOX_USER_ID for a second time. Exiting."
|
41 |
+
exit 1
|
42 |
+
fi
|
43 |
+
fi
|
44 |
+
fi
|
45 |
+
usermod -aG app enduser
|
46 |
+
# get the user group of /var/run/docker.sock and set openhands to that group
|
47 |
+
DOCKER_SOCKET_GID=$(stat -c '%g' /var/run/docker.sock)
|
48 |
+
echo "Docker socket group id: $DOCKER_SOCKET_GID"
|
49 |
+
if getent group $DOCKER_SOCKET_GID; then
|
50 |
+
echo "Group with id $DOCKER_SOCKET_GID already exists"
|
51 |
+
else
|
52 |
+
echo "Creating group with id $DOCKER_SOCKET_GID"
|
53 |
+
groupadd -g $DOCKER_SOCKET_GID docker
|
54 |
+
fi
|
55 |
+
|
56 |
+
mkdir -p /home/enduser/.cache/huggingface/hub/
|
57 |
+
|
58 |
+
usermod -aG $DOCKER_SOCKET_GID enduser
|
59 |
+
echo "Running as enduser"
|
60 |
+
su enduser /bin/bash -c "${*@Q}" # This magically runs any arguments passed to the script as a command
|
61 |
+
fi
|
containers/build.sh
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
set -eo pipefail
|
3 |
+
|
4 |
+
# Initialize variables with default values
|
5 |
+
image_name=""
|
6 |
+
org_name=""
|
7 |
+
push=0
|
8 |
+
load=0
|
9 |
+
tag_suffix=""
|
10 |
+
dry_run=0
|
11 |
+
|
12 |
+
# Function to display usage information
|
13 |
+
usage() {
|
14 |
+
echo "Usage: $0 -i <image_name> [-o <org_name>] [--push] [--load] [-t <tag_suffix>] [--dry]"
|
15 |
+
echo " -i: Image name (required)"
|
16 |
+
echo " -o: Organization name"
|
17 |
+
echo " --push: Push the image"
|
18 |
+
echo " --load: Load the image"
|
19 |
+
echo " -t: Tag suffix"
|
20 |
+
echo " --dry: Don't build, only create build-args.json"
|
21 |
+
exit 1
|
22 |
+
}
|
23 |
+
|
24 |
+
# Parse command-line options
|
25 |
+
while [[ $# -gt 0 ]]; do
|
26 |
+
case $1 in
|
27 |
+
-i) image_name="$2"; shift 2 ;;
|
28 |
+
-o) org_name="$2"; shift 2 ;;
|
29 |
+
--push) push=1; shift ;;
|
30 |
+
--load) load=1; shift ;;
|
31 |
+
-t) tag_suffix="$2"; shift 2 ;;
|
32 |
+
--dry) dry_run=1; shift ;;
|
33 |
+
*) usage ;;
|
34 |
+
esac
|
35 |
+
done
|
36 |
+
# Check if required arguments are provided
|
37 |
+
if [[ -z "$image_name" ]]; then
|
38 |
+
echo "Error: Image name is required."
|
39 |
+
usage
|
40 |
+
fi
|
41 |
+
|
42 |
+
echo "Building: $image_name"
|
43 |
+
tags=()
|
44 |
+
|
45 |
+
OPENHANDS_BUILD_VERSION="dev"
|
46 |
+
|
47 |
+
cache_tag_base="buildcache"
|
48 |
+
cache_tag="$cache_tag_base"
|
49 |
+
|
50 |
+
if [[ -n $RELEVANT_SHA ]]; then
|
51 |
+
git_hash=$(git rev-parse --short "$RELEVANT_SHA")
|
52 |
+
tags+=("$git_hash")
|
53 |
+
tags+=("$RELEVANT_SHA")
|
54 |
+
fi
|
55 |
+
|
56 |
+
if [[ -n $GITHUB_REF_NAME ]]; then
|
57 |
+
# check if ref name is a version number
|
58 |
+
if [[ $GITHUB_REF_NAME =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
59 |
+
major_version=$(echo "$GITHUB_REF_NAME" | cut -d. -f1)
|
60 |
+
minor_version=$(echo "$GITHUB_REF_NAME" | cut -d. -f1,2)
|
61 |
+
tags+=("$major_version" "$minor_version")
|
62 |
+
tags+=("latest")
|
63 |
+
fi
|
64 |
+
sanitized_ref_name=$(echo "$GITHUB_REF_NAME" | sed 's/[^a-zA-Z0-9.-]\+/-/g')
|
65 |
+
OPENHANDS_BUILD_VERSION=$sanitized_ref_name
|
66 |
+
sanitized_ref_name=$(echo "$sanitized_ref_name" | tr '[:upper:]' '[:lower:]') # lower case is required in tagging
|
67 |
+
tags+=("$sanitized_ref_name")
|
68 |
+
cache_tag+="-${sanitized_ref_name}"
|
69 |
+
fi
|
70 |
+
|
71 |
+
if [[ -n $tag_suffix ]]; then
|
72 |
+
cache_tag+="-${tag_suffix}"
|
73 |
+
for i in "${!tags[@]}"; do
|
74 |
+
tags[$i]="${tags[$i]}-$tag_suffix"
|
75 |
+
done
|
76 |
+
fi
|
77 |
+
|
78 |
+
echo "Tags: ${tags[@]}"
|
79 |
+
|
80 |
+
if [[ "$image_name" == "openhands" ]]; then
|
81 |
+
dir="./containers/app"
|
82 |
+
elif [[ "$image_name" == "runtime" ]]; then
|
83 |
+
dir="./containers/runtime"
|
84 |
+
else
|
85 |
+
dir="./containers/$image_name"
|
86 |
+
fi
|
87 |
+
|
88 |
+
if [[ (! -f "$dir/Dockerfile") && "$image_name" != "runtime" ]]; then
|
89 |
+
# Allow runtime to be built without a Dockerfile
|
90 |
+
echo "No Dockerfile found"
|
91 |
+
exit 1
|
92 |
+
fi
|
93 |
+
if [[ ! -f "$dir/config.sh" ]]; then
|
94 |
+
echo "No config.sh found for Dockerfile"
|
95 |
+
exit 1
|
96 |
+
fi
|
97 |
+
|
98 |
+
source "$dir/config.sh"
|
99 |
+
|
100 |
+
if [[ -n "$org_name" ]]; then
|
101 |
+
DOCKER_ORG="$org_name"
|
102 |
+
fi
|
103 |
+
|
104 |
+
# If $DOCKER_IMAGE_SOURCE_TAG is set, add it to the tags
|
105 |
+
if [[ -n "$DOCKER_IMAGE_SOURCE_TAG" ]]; then
|
106 |
+
tags+=("$DOCKER_IMAGE_SOURCE_TAG")
|
107 |
+
fi
|
108 |
+
# If $DOCKER_IMAGE_TAG is set, add it to the tags
|
109 |
+
if [[ -n "$DOCKER_IMAGE_TAG" ]]; then
|
110 |
+
tags+=("$DOCKER_IMAGE_TAG")
|
111 |
+
fi
|
112 |
+
|
113 |
+
DOCKER_REPOSITORY="$DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_IMAGE"
|
114 |
+
DOCKER_REPOSITORY=${DOCKER_REPOSITORY,,} # lowercase
|
115 |
+
echo "Repo: $DOCKER_REPOSITORY"
|
116 |
+
echo "Base dir: $DOCKER_BASE_DIR"
|
117 |
+
|
118 |
+
args=""
|
119 |
+
full_tags=()
|
120 |
+
for tag in "${tags[@]}"; do
|
121 |
+
args+=" -t $DOCKER_REPOSITORY:$tag"
|
122 |
+
full_tags+=("$DOCKER_REPOSITORY:$tag")
|
123 |
+
done
|
124 |
+
|
125 |
+
|
126 |
+
if [[ $push -eq 1 ]]; then
|
127 |
+
args+=" --push"
|
128 |
+
args+=" --cache-to=type=registry,ref=$DOCKER_REPOSITORY:$cache_tag,mode=max"
|
129 |
+
fi
|
130 |
+
|
131 |
+
if [[ $load -eq 1 ]]; then
|
132 |
+
args+=" --load"
|
133 |
+
fi
|
134 |
+
|
135 |
+
echo "Args: $args"
|
136 |
+
|
137 |
+
# Modify the platform selection based on --load flag
|
138 |
+
if [[ $load -eq 1 ]]; then
|
139 |
+
# When loading, build only for the current platform
|
140 |
+
platform=$(docker version -f '{{.Server.Os}}/{{.Server.Arch}}')
|
141 |
+
else
|
142 |
+
# For push or without load, build for multiple platforms
|
143 |
+
platform="linux/amd64,linux/arm64"
|
144 |
+
fi
|
145 |
+
if [[ $dry_run -eq 1 ]]; then
|
146 |
+
echo "Dry Run is enabled. Writing build config to docker-build-dry.json"
|
147 |
+
jq -n \
|
148 |
+
--argjson tags "$(printf '%s\n' "${full_tags[@]}" | jq -R . | jq -s .)" \
|
149 |
+
--arg platform "$platform" \
|
150 |
+
--arg openhands_build_version "$OPENHANDS_BUILD_VERSION" \
|
151 |
+
--arg dockerfile "$dir/Dockerfile" \
|
152 |
+
'{
|
153 |
+
tags: $tags,
|
154 |
+
platform: $platform,
|
155 |
+
build_args: [
|
156 |
+
"OPENHANDS_BUILD_VERSION=" + $openhands_build_version
|
157 |
+
],
|
158 |
+
dockerfile: $dockerfile
|
159 |
+
}' > docker-build-dry.json
|
160 |
+
|
161 |
+
exit 0
|
162 |
+
fi
|
163 |
+
|
164 |
+
|
165 |
+
|
166 |
+
echo "Building for platform(s): $platform"
|
167 |
+
|
168 |
+
docker buildx build \
|
169 |
+
$args \
|
170 |
+
--build-arg OPENHANDS_BUILD_VERSION="$OPENHANDS_BUILD_VERSION" \
|
171 |
+
--cache-from=type=registry,ref=$DOCKER_REPOSITORY:$cache_tag \
|
172 |
+
--cache-from=type=registry,ref=$DOCKER_REPOSITORY:$cache_tag_base-main \
|
173 |
+
--platform $platform \
|
174 |
+
--provenance=false \
|
175 |
+
-f "$dir/Dockerfile" \
|
176 |
+
"$DOCKER_BASE_DIR"
|
177 |
+
|
178 |
+
# If load was requested, print the loaded images
|
179 |
+
if [[ $load -eq 1 ]]; then
|
180 |
+
echo "Local images built:"
|
181 |
+
docker images "$DOCKER_REPOSITORY" --format "{{.Repository}}:{{.Tag}}"
|
182 |
+
fi
|
containers/dev/Dockerfile
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# syntax=docker/dockerfile:1
|
2 |
+
|
3 |
+
###
|
4 |
+
FROM ubuntu:22.04 AS dind
|
5 |
+
|
6 |
+
# https://docs.docker.com/engine/install/ubuntu/
|
7 |
+
RUN apt-get update && apt-get install -y \
|
8 |
+
ca-certificates \
|
9 |
+
curl \
|
10 |
+
&& install -m 0755 -d /etc/apt/keyrings \
|
11 |
+
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
|
12 |
+
&& chmod a+r /etc/apt/keyrings/docker.asc \
|
13 |
+
&& echo \
|
14 |
+
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
15 |
+
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
16 |
+
|
17 |
+
RUN apt-get update && apt-get install -y \
|
18 |
+
docker-ce \
|
19 |
+
docker-ce-cli \
|
20 |
+
containerd.io \
|
21 |
+
docker-buildx-plugin \
|
22 |
+
docker-compose-plugin \
|
23 |
+
&& rm -rf /var/lib/apt/lists/* \
|
24 |
+
&& apt-get clean \
|
25 |
+
&& apt-get autoremove -y
|
26 |
+
|
27 |
+
###
|
28 |
+
FROM dind AS openhands
|
29 |
+
|
30 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
31 |
+
|
32 |
+
#
|
33 |
+
RUN apt-get update && apt-get install -y \
|
34 |
+
bash \
|
35 |
+
build-essential \
|
36 |
+
curl \
|
37 |
+
git \
|
38 |
+
git-lfs \
|
39 |
+
software-properties-common \
|
40 |
+
make \
|
41 |
+
netcat \
|
42 |
+
sudo \
|
43 |
+
wget \
|
44 |
+
&& rm -rf /var/lib/apt/lists/* \
|
45 |
+
&& apt-get clean \
|
46 |
+
&& apt-get autoremove -y
|
47 |
+
|
48 |
+
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md
|
49 |
+
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
50 |
+
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
51 |
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
52 |
+
&& apt-get update && apt-get -y install \
|
53 |
+
gh \
|
54 |
+
&& rm -rf /var/lib/apt/lists/* \
|
55 |
+
&& apt-get clean \
|
56 |
+
&& apt-get autoremove -y
|
57 |
+
|
58 |
+
# Python 3.12
|
59 |
+
RUN add-apt-repository ppa:deadsnakes/ppa \
|
60 |
+
&& apt-get update \
|
61 |
+
&& apt-get install -y python3.12 python3.12-venv python3.12-dev python3-pip \
|
62 |
+
&& ln -s /usr/bin/python3.12 /usr/bin/python
|
63 |
+
|
64 |
+
# NodeJS >= 22.x
|
65 |
+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
66 |
+
&& apt-get install -y nodejs
|
67 |
+
|
68 |
+
# Poetry >= 1.8
|
69 |
+
RUN curl -fsSL https://install.python-poetry.org | python3.12 - \
|
70 |
+
&& ln -s ~/.local/bin/poetry /usr/local/bin/poetry
|
71 |
+
|
72 |
+
#
|
73 |
+
RUN <<EOF
|
74 |
+
#!/bin/bash
|
75 |
+
printf "#!/bin/bash
|
76 |
+
set +x
|
77 |
+
uname -a
|
78 |
+
docker --version
|
79 |
+
gh --version | head -n 1
|
80 |
+
git --version
|
81 |
+
#
|
82 |
+
python --version
|
83 |
+
echo node `node --version`
|
84 |
+
echo npm `npm --version`
|
85 |
+
poetry --version
|
86 |
+
netcat -h 2>&1 | head -n 1
|
87 |
+
" > /version.sh
|
88 |
+
chmod a+x /version.sh
|
89 |
+
EOF
|
90 |
+
|
91 |
+
###
|
92 |
+
FROM openhands AS dev
|
93 |
+
|
94 |
+
RUN apt-get update && apt-get install -y \
|
95 |
+
dnsutils \
|
96 |
+
file \
|
97 |
+
iproute2 \
|
98 |
+
jq \
|
99 |
+
lsof \
|
100 |
+
ripgrep \
|
101 |
+
silversearcher-ag \
|
102 |
+
vim \
|
103 |
+
&& rm -rf /var/lib/apt/lists/* \
|
104 |
+
&& apt-get clean \
|
105 |
+
&& apt-get autoremove -y
|
106 |
+
|
107 |
+
WORKDIR /app
|
108 |
+
|
109 |
+
# cache build dependencies
|
110 |
+
RUN \
|
111 |
+
--mount=type=bind,source=./,target=/app/,rw \
|
112 |
+
<<EOF
|
113 |
+
#!/bin/bash
|
114 |
+
make -s clean
|
115 |
+
make -s check-dependencies
|
116 |
+
make -s install-python-dependencies
|
117 |
+
|
118 |
+
# NOTE
|
119 |
+
# node_modules are .dockerignore-d therefore not mountable
|
120 |
+
# make -s install-frontend-dependencies
|
121 |
+
EOF
|
122 |
+
|
123 |
+
#
|
124 |
+
CMD ["bash"]
|
containers/dev/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Develop in Docker
|
2 |
+
|
3 |
+
> [!WARNING]
|
4 |
+
> This is not officially supported and may not work.
|
5 |
+
|
6 |
+
Install [Docker](https://docs.docker.com/engine/install/) on your host machine and run:
|
7 |
+
|
8 |
+
```bash
|
9 |
+
make docker-dev
|
10 |
+
# same as:
|
11 |
+
cd ./containers/dev
|
12 |
+
./dev.sh
|
13 |
+
```
|
14 |
+
|
15 |
+
It could take some time if you are running for the first time as Docker will pull all the tools required for building OpenHands. The next time you run again, it should be instant.
|
16 |
+
|
17 |
+
## Build and run
|
18 |
+
|
19 |
+
If everything goes well, you should be inside a container after Docker finishes building the `openhands:dev` image similar to the following:
|
20 |
+
|
21 |
+
```bash
|
22 |
+
Build and run in Docker ...
|
23 |
+
root@93fc0005fcd2:/app#
|
24 |
+
```
|
25 |
+
|
26 |
+
You may now proceed with the normal [build and run](../../Development.md) workflow as if you were on the host.
|
27 |
+
|
28 |
+
## Make changes
|
29 |
+
|
30 |
+
The source code on the host is mounted as `/app` inside docker. You may edit the files as usual either inside the Docker container or on your host with your favorite IDE/editors.
|
31 |
+
|
32 |
+
The following are also mapped as readonly from your host:
|
33 |
+
|
34 |
+
```yaml
|
35 |
+
# host credentials
|
36 |
+
- $HOME/.git-credentials:/root/.git-credentials:ro
|
37 |
+
- $HOME/.gitconfig:/root/.gitconfig:ro
|
38 |
+
- $HOME/.npmrc:/root/.npmrc:ro
|
39 |
+
```
|
40 |
+
|
41 |
+
## VSCode
|
42 |
+
|
43 |
+
Alternatively, if you use VSCode, you could also [attach to the running container](https://code.visualstudio.com/docs/devcontainers/attach-container).
|
44 |
+
|
45 |
+
See details for [developing in docker](https://code.visualstudio.com/docs/devcontainers/containers) or simply ask `OpenHands` ;-)
|
46 |
+
|
47 |
+
## Rebuild dev image
|
48 |
+
|
49 |
+
You could optionally pass additional options to the build script.
|
50 |
+
|
51 |
+
```bash
|
52 |
+
make docker-dev OPTIONS="--build"
|
53 |
+
# or
|
54 |
+
./containers/dev/dev.sh --build
|
55 |
+
```
|
56 |
+
|
57 |
+
See [docker compose run](https://docs.docker.com/reference/cli/docker/compose/run/) for more options.
|
containers/dev/compose.yml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
services:
|
3 |
+
dev:
|
4 |
+
privileged: true
|
5 |
+
build:
|
6 |
+
context: ${OPENHANDS_WORKSPACE:-../../}
|
7 |
+
dockerfile: ./containers/dev/Dockerfile
|
8 |
+
image: openhands:dev
|
9 |
+
container_name: openhands-dev
|
10 |
+
environment:
|
11 |
+
- BACKEND_HOST=${BACKEND_HOST:-"0.0.0.0"}
|
12 |
+
- SANDBOX_API_HOSTNAME=host.docker.internal
|
13 |
+
#
|
14 |
+
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.41-nikolaik}
|
15 |
+
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
16 |
+
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
17 |
+
ports:
|
18 |
+
- "3000:3000"
|
19 |
+
extra_hosts:
|
20 |
+
- "host.docker.internal:host-gateway"
|
21 |
+
volumes:
|
22 |
+
- /var/run/docker.sock:/var/run/docker.sock
|
23 |
+
- ${WORKSPACE_BASE:-$PWD/workspace}:/opt/workspace_base
|
24 |
+
# source code
|
25 |
+
- ${OPENHANDS_WORKSPACE:-../../}:/app
|
26 |
+
# host credentials
|
27 |
+
- $HOME/.git-credentials:/root/.git-credentials:ro
|
28 |
+
- $HOME/.gitconfig:/root/.gitconfig:ro
|
29 |
+
- $HOME/.npmrc:/root/.npmrc:ro
|
30 |
+
# cache
|
31 |
+
- cache-data:/root/.cache
|
32 |
+
pull_policy: never
|
33 |
+
stdin_open: true
|
34 |
+
tty: true
|
35 |
+
|
36 |
+
##
|
37 |
+
volumes:
|
38 |
+
cache-data:
|
containers/dev/dev.sh
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
set -o pipefail
|
3 |
+
|
4 |
+
function get_docker() {
|
5 |
+
echo "Docker is required to build and run OpenHands."
|
6 |
+
echo "https://docs.docker.com/get-started/get-docker/"
|
7 |
+
exit 1
|
8 |
+
}
|
9 |
+
|
10 |
+
function check_tools() {
|
11 |
+
command -v docker &>/dev/null || get_docker
|
12 |
+
}
|
13 |
+
|
14 |
+
function exit_if_indocker() {
|
15 |
+
if [ -f /.dockerenv ]; then
|
16 |
+
echo "Running inside a Docker container. Exiting..."
|
17 |
+
exit 1
|
18 |
+
fi
|
19 |
+
}
|
20 |
+
|
21 |
+
#
|
22 |
+
exit_if_indocker
|
23 |
+
|
24 |
+
check_tools
|
25 |
+
|
26 |
+
##
|
27 |
+
OPENHANDS_WORKSPACE=$(git rev-parse --show-toplevel)
|
28 |
+
|
29 |
+
cd "$OPENHANDS_WORKSPACE/containers/dev/" || exit 1
|
30 |
+
|
31 |
+
##
|
32 |
+
export BACKEND_HOST="0.0.0.0"
|
33 |
+
#
|
34 |
+
export SANDBOX_USER_ID=$(id -u)
|
35 |
+
export WORKSPACE_BASE=${WORKSPACE_BASE:-$OPENHANDS_WORKSPACE/workspace}
|
36 |
+
|
37 |
+
docker compose run --rm --service-ports "$@" dev
|
38 |
+
|
39 |
+
##
|
containers/e2b-sandbox/Dockerfile
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM ubuntu:22.04
|
2 |
+
|
3 |
+
# install basic packages
|
4 |
+
RUN apt-get update && apt-get install -y \
|
5 |
+
curl \
|
6 |
+
wget \
|
7 |
+
git \
|
8 |
+
vim \
|
9 |
+
nano \
|
10 |
+
unzip \
|
11 |
+
zip \
|
12 |
+
python3 \
|
13 |
+
python3-pip \
|
14 |
+
python3-venv \
|
15 |
+
python3-dev \
|
16 |
+
build-essential \
|
17 |
+
openssh-server \
|
18 |
+
sudo \
|
19 |
+
&& rm -rf /var/lib/apt/lists/*
|
containers/e2b-sandbox/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# How to build custom E2B sandbox for OpenHands
|
2 |
+
|
3 |
+
[E2B](https://e2b.dev) is an [open-source](https://github.com/e2b-dev/e2b) secure cloud environment (sandbox) made for running AI-generated code and agents. E2B offers [Python](https://pypi.org/project/e2b/) and [JS/TS](https://www.npmjs.com/package/e2b) SDK to spawn and control these sandboxes.
|
4 |
+
|
5 |
+
|
6 |
+
1. Install the CLI with NPM.
|
7 |
+
```sh
|
8 |
+
npm install -g @e2b/cli@latest
|
9 |
+
```
|
10 |
+
Full CLI API is [here](https://e2b.dev/docs/cli/installation).
|
11 |
+
|
12 |
+
1. Build the sandbox
|
13 |
+
```sh
|
14 |
+
e2b template build --dockerfile ./Dockerfile --name "openhands"
|
15 |
+
```
|
containers/e2b-sandbox/e2b.toml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This is a config for E2B sandbox template.
|
2 |
+
# You can use 'template_id' (785n69crgahmz0lkdw9h) or 'template_name (openhands) from this config to spawn a sandbox:
|
3 |
+
|
4 |
+
# Python SDK
|
5 |
+
# from e2b import Sandbox
|
6 |
+
# sandbox = Sandbox(template='openhands')
|
7 |
+
|
8 |
+
# JS SDK
|
9 |
+
# import { Sandbox } from 'e2b'
|
10 |
+
# const sandbox = await Sandbox.create({ template: 'openhands' })
|
11 |
+
|
12 |
+
dockerfile = "Dockerfile"
|
13 |
+
template_name = "openhands"
|
14 |
+
template_id = "785n69crgahmz0lkdw9h"
|
containers/runtime/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Dynamically constructed Dockerfile
|
2 |
+
|
3 |
+
This folder builds a runtime image (sandbox), which will use a dynamically generated `Dockerfile`
|
4 |
+
that depends on the `base_image` **AND** a [Python source distribution](https://docs.python.org/3.10/distutils/sourcedist.html) that is based on the current commit of `openhands`.
|
5 |
+
|
6 |
+
The following command will generate a `Dockerfile` file for `nikolaik/python-nodejs:python3.12-nodejs22` (the default base image), an updated `config.sh` and the runtime source distribution files/folders into `containers/runtime`:
|
7 |
+
|
8 |
+
```bash
|
9 |
+
poetry run python3 openhands/runtime/utils/runtime_build.py \
|
10 |
+
--base_image nikolaik/python-nodejs:python3.12-nodejs22 \
|
11 |
+
--build_folder containers/runtime
|
12 |
+
```
|
containers/runtime/config.sh
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DOCKER_REGISTRY=ghcr.io
|
2 |
+
DOCKER_ORG=all-hands-ai
|
3 |
+
DOCKER_BASE_DIR="./containers/runtime"
|
4 |
+
DOCKER_IMAGE=runtime
|
5 |
+
# These variables will be appended by the runtime_build.py script
|
6 |
+
# DOCKER_IMAGE_TAG=
|
7 |
+
# DOCKER_IMAGE_SOURCE_TAG=
|
dev_config/python/mypy.ini
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[mypy]
|
2 |
+
warn_unused_configs = True
|
3 |
+
ignore_missing_imports = True
|
4 |
+
check_untyped_defs = True
|
5 |
+
explicit_package_bases = True
|
6 |
+
warn_unreachable = True
|
7 |
+
warn_redundant_casts = True
|
8 |
+
no_implicit_optional = True
|
9 |
+
strict_optional = True
|
dev_config/python/ruff.toml
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[lint]
|
2 |
+
select = [
|
3 |
+
"E",
|
4 |
+
"W",
|
5 |
+
"F",
|
6 |
+
"I",
|
7 |
+
"Q",
|
8 |
+
"B",
|
9 |
+
"ASYNC",
|
10 |
+
"UP006", # Use `list` instead of `List` for annotations
|
11 |
+
"UP007", # Use `X | Y` instead of `Union[X, Y]`
|
12 |
+
"UP008", # Use `X | None` instead of `Optional[X]`
|
13 |
+
]
|
14 |
+
|
15 |
+
ignore = [
|
16 |
+
"E501",
|
17 |
+
"B003",
|
18 |
+
"B007",
|
19 |
+
"B009",
|
20 |
+
"B010",
|
21 |
+
"B904",
|
22 |
+
"B018",
|
23 |
+
# Temporarily ignore ASYNC rules until they can be properly fixed in a separate PR
|
24 |
+
"ASYNC110",
|
25 |
+
"ASYNC220",
|
26 |
+
"ASYNC221",
|
27 |
+
"ASYNC230",
|
28 |
+
"ASYNC251",
|
29 |
+
]
|
30 |
+
|
31 |
+
[lint.flake8-quotes]
|
32 |
+
docstring-quotes = "double"
|
33 |
+
inline-quotes = "single"
|
34 |
+
|
35 |
+
[format]
|
36 |
+
quote-style = "single"
|
37 |
+
|
38 |
+
[lint.flake8-bugbear]
|
39 |
+
extend-immutable-calls = ["Depends", "fastapi.Depends", "fastapi.params.Depends"]
|
docker-compose.yml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
services:
|
3 |
+
openhands:
|
4 |
+
build:
|
5 |
+
context: ./
|
6 |
+
dockerfile: ./containers/app/Dockerfile
|
7 |
+
image: openhands:latest
|
8 |
+
container_name: openhands-app-${DATE:-}
|
9 |
+
environment:
|
10 |
+
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.41-nikolaik}
|
11 |
+
#- 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
|
12 |
+
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
13 |
+
ports:
|
14 |
+
- "3000:3000"
|
15 |
+
extra_hosts:
|
16 |
+
- "host.docker.internal:host-gateway"
|
17 |
+
volumes:
|
18 |
+
- /var/run/docker.sock:/var/run/docker.sock
|
19 |
+
- ~/.openhands-state:/.openhands-state
|
20 |
+
- ${WORKSPACE_BASE:-$PWD/workspace}:/opt/workspace_base
|
21 |
+
pull_policy: build
|
22 |
+
stdin_open: true
|
23 |
+
tty: true
|
docs/DOC_STYLE_GUIDE.md
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Documentation Style Guide
|
2 |
+
|
3 |
+
## General Writing Principles
|
4 |
+
|
5 |
+
- **Clarity & Conciseness**: Always prioritize clarity and brevity. Avoid unnecessary jargon or overly complex explanations.
|
6 |
+
Keep sentences short and to the point.
|
7 |
+
- **Gradual Complexity**: Start with the simplest, most basic setup, and then gradually introduce more advanced
|
8 |
+
concepts and configurations.
|
9 |
+
|
10 |
+
## Formatting Guidelines
|
11 |
+
|
12 |
+
### Headers
|
13 |
+
|
14 |
+
Use **Title Case** for the first and second level headers.
|
15 |
+
|
16 |
+
Example:
|
17 |
+
- **Basic Usage**
|
18 |
+
- **Advanced Configuration Options**
|
19 |
+
|
20 |
+
### Lists
|
21 |
+
|
22 |
+
When listing items or options, use bullet points to enhance readability.
|
23 |
+
|
24 |
+
Example:
|
25 |
+
- Option A
|
26 |
+
- Option B
|
27 |
+
- Option C
|
28 |
+
|
29 |
+
### Procedures
|
30 |
+
|
31 |
+
For instructions or processes that need to be followed in a specific order, use numbered steps.
|
32 |
+
|
33 |
+
Example:
|
34 |
+
1. Step one: Do this.
|
35 |
+
- First this sub step.
|
36 |
+
- Then this sub step.
|
37 |
+
2. Step two: Complete this action.
|
38 |
+
3. Step three: Verify the result.
|
39 |
+
|
40 |
+
### Code Blocks
|
41 |
+
|
42 |
+
* Use code blocks for multi-line inputs, outputs, commands and code samples.
|
43 |
+
|
44 |
+
Example:
|
45 |
+
```bash
|
46 |
+
docker run -it \
|
47 |
+
-e THIS=this \
|
48 |
+
-e THAT=that
|
49 |
+
...
|
50 |
+
```
|
51 |
+
|
52 |
+
### Use of Note and Warning
|
53 |
+
|
54 |
+
When adding a note or warning, use the built-in note and warning syntax.
|
55 |
+
|
56 |
+
Example:
|
57 |
+
<Note>
|
58 |
+
This section is for advanced users only.
|
59 |
+
</Note>
|
60 |
+
|
61 |
+
### Referring to UI Elements
|
62 |
+
|
63 |
+
When referencing UI elements, use ``.
|
64 |
+
|
65 |
+
Example:
|
66 |
+
1. Toggle the `Advanced` option
|
67 |
+
2. Enter your model in the `Custom Model` textbox.
|
docs/docs.json
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "https://mintlify.com/docs.json",
|
3 |
+
"theme": "mint",
|
4 |
+
"name": "All Hands Docs",
|
5 |
+
"colors": {
|
6 |
+
"primary": "#99873c",
|
7 |
+
"light": "#ffe165",
|
8 |
+
"dark": "#ffe165"
|
9 |
+
},
|
10 |
+
"background": {
|
11 |
+
"color": {
|
12 |
+
"light": "#f7f3ee",
|
13 |
+
"dark": "#0B0D0E"
|
14 |
+
}
|
15 |
+
},
|
16 |
+
"appearance": {
|
17 |
+
"default": "light"
|
18 |
+
},
|
19 |
+
"favicon": "/logo-square.png",
|
20 |
+
"navigation": {
|
21 |
+
"tabs": [
|
22 |
+
{
|
23 |
+
"tab": "Docs",
|
24 |
+
"pages": [
|
25 |
+
"index",
|
26 |
+
"usage/installation",
|
27 |
+
"usage/getting-started",
|
28 |
+
"usage/key-features",
|
29 |
+
{
|
30 |
+
"group": "OpenHands Cloud",
|
31 |
+
"pages": [
|
32 |
+
"usage/cloud/openhands-cloud",
|
33 |
+
{
|
34 |
+
"group": "Integrations",
|
35 |
+
"pages": [
|
36 |
+
"usage/cloud/github-installation",
|
37 |
+
"usage/cloud/gitlab-installation"
|
38 |
+
]
|
39 |
+
},
|
40 |
+
"usage/cloud/cloud-ui",
|
41 |
+
"usage/cloud/cloud-api"
|
42 |
+
]
|
43 |
+
},
|
44 |
+
{
|
45 |
+
"group": "Running OpenHands Locally",
|
46 |
+
"pages": [
|
47 |
+
"usage/local-setup",
|
48 |
+
"usage/how-to/gui-mode",
|
49 |
+
"usage/how-to/cli-mode",
|
50 |
+
"usage/how-to/headless-mode",
|
51 |
+
"usage/how-to/github-action"
|
52 |
+
]
|
53 |
+
},
|
54 |
+
{
|
55 |
+
"group": "Customization",
|
56 |
+
"pages": [
|
57 |
+
"usage/prompting/prompting-best-practices",
|
58 |
+
"usage/prompting/repository",
|
59 |
+
{
|
60 |
+
"group": "Microagents",
|
61 |
+
"pages": [
|
62 |
+
"usage/prompting/microagents-overview",
|
63 |
+
"usage/prompting/microagents-repo",
|
64 |
+
"usage/prompting/microagents-keyword",
|
65 |
+
"usage/prompting/microagents-org",
|
66 |
+
"usage/prompting/microagents-public"
|
67 |
+
]
|
68 |
+
}
|
69 |
+
]
|
70 |
+
},
|
71 |
+
{
|
72 |
+
"group": "Advanced Configuration",
|
73 |
+
"pages": [
|
74 |
+
{
|
75 |
+
"group": "LLM Configuration",
|
76 |
+
"pages": [
|
77 |
+
"usage/llms/llms",
|
78 |
+
{
|
79 |
+
"group": "Providers",
|
80 |
+
"pages": [
|
81 |
+
"usage/llms/azure-llms",
|
82 |
+
"usage/llms/google-llms",
|
83 |
+
"usage/llms/groq",
|
84 |
+
"usage/llms/local-llms",
|
85 |
+
"usage/llms/litellm-proxy",
|
86 |
+
"usage/llms/openai-llms",
|
87 |
+
"usage/llms/openrouter"
|
88 |
+
]
|
89 |
+
}
|
90 |
+
]
|
91 |
+
},
|
92 |
+
{
|
93 |
+
"group": "Runtime Configuration",
|
94 |
+
"pages": [
|
95 |
+
"usage/runtimes/overview",
|
96 |
+
{
|
97 |
+
"group": "Providers",
|
98 |
+
"pages": [
|
99 |
+
"usage/runtimes/docker",
|
100 |
+
"usage/runtimes/remote",
|
101 |
+
"usage/runtimes/local",
|
102 |
+
{
|
103 |
+
"group": "Third-Party Providers",
|
104 |
+
"pages": [
|
105 |
+
"usage/runtimes/modal",
|
106 |
+
"usage/runtimes/daytona",
|
107 |
+
"usage/runtimes/runloop",
|
108 |
+
"usage/runtimes/e2b"
|
109 |
+
]
|
110 |
+
}
|
111 |
+
]
|
112 |
+
}
|
113 |
+
]
|
114 |
+
},
|
115 |
+
"usage/configuration-options",
|
116 |
+
"usage/how-to/custom-sandbox-guide",
|
117 |
+
"usage/search-engine-setup",
|
118 |
+
"usage/mcp"
|
119 |
+
]
|
120 |
+
},
|
121 |
+
{
|
122 |
+
"group": "Troubleshooting & Feedback",
|
123 |
+
"pages": [
|
124 |
+
"usage/troubleshooting/troubleshooting",
|
125 |
+
"usage/feedback"
|
126 |
+
]
|
127 |
+
},
|
128 |
+
{
|
129 |
+
"group": "OpenHands Developers",
|
130 |
+
"pages": [
|
131 |
+
"usage/how-to/development-overview",
|
132 |
+
{
|
133 |
+
"group": "Architecture",
|
134 |
+
"pages": [
|
135 |
+
"usage/architecture/backend",
|
136 |
+
"usage/architecture/runtime"
|
137 |
+
]
|
138 |
+
},
|
139 |
+
"usage/how-to/debugging",
|
140 |
+
"usage/how-to/evaluation-harness",
|
141 |
+
"usage/how-to/websocket-connection"
|
142 |
+
]
|
143 |
+
}
|
144 |
+
]
|
145 |
+
},
|
146 |
+
{
|
147 |
+
"tab": "API Reference",
|
148 |
+
"openapi": "/openapi.json"
|
149 |
+
}
|
150 |
+
],
|
151 |
+
"global": {
|
152 |
+
"anchors": [
|
153 |
+
{
|
154 |
+
"anchor": "Company",
|
155 |
+
"href": "https://www.all-hands.dev/",
|
156 |
+
"icon": "house"
|
157 |
+
},
|
158 |
+
{
|
159 |
+
"anchor": "Blog",
|
160 |
+
"href": "https://www.all-hands.dev/blog",
|
161 |
+
"icon": "newspaper"
|
162 |
+
},
|
163 |
+
{
|
164 |
+
"anchor": "OpenHands Cloud",
|
165 |
+
"href": "https://app.all-hands.dev",
|
166 |
+
"icon": "cloud"
|
167 |
+
}
|
168 |
+
]
|
169 |
+
}
|
170 |
+
},
|
171 |
+
"logo": {
|
172 |
+
"light": "/logo/light.svg",
|
173 |
+
"dark": "/logo/dark.svg"
|
174 |
+
},
|
175 |
+
"navbar": {
|
176 |
+
"links": [
|
177 |
+
],
|
178 |
+
"primary": {
|
179 |
+
"type": "github",
|
180 |
+
"href": "https://github.com/All-Hands-AI/OpenHands"
|
181 |
+
}
|
182 |
+
},
|
183 |
+
"footer": {
|
184 |
+
"socials": {
|
185 |
+
"slack": "https://join.slack.com/t/openhands-ai/shared_invite/zt-34zm4j0gj-Qz5kRHoca8DFCbqXPS~f_A",
|
186 |
+
"github": "https://github.com/All-Hands-AI/OpenHands",
|
187 |
+
"discord": "https://discord.gg/ESHStjSjD4"
|
188 |
+
}
|
189 |
+
},
|
190 |
+
"contextual": {
|
191 |
+
"options": [
|
192 |
+
"copy",
|
193 |
+
"view",
|
194 |
+
"chatgpt",
|
195 |
+
"claude"
|
196 |
+
]
|
197 |
+
},
|
198 |
+
"redirects": [
|
199 |
+
{
|
200 |
+
"source": "/modules/:slug*",
|
201 |
+
"destination": "/:slug*"
|
202 |
+
}
|
203 |
+
]
|
204 |
+
}
|
docs/favicon.svg
ADDED
|
docs/index.mdx
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Introduction
|
3 |
+
description: OpenHands - Code Less, Make More
|
4 |
+
icon: book-open
|
5 |
+
mode: wide
|
6 |
+
---
|
7 |
+
Use AI to tackle the toil in your backlog. Our agents have all the same tools as a human developer: they can modify code, run commands, browse the web, call APIs, and yes-even copy code snippets from StackOverflow.
|
8 |
+
|
9 |
+
<iframe
|
10 |
+
className="w-full aspect-video"
|
11 |
+
src="https://www.youtube.com/embed/oB4JR98KRAA"
|
12 |
+
title="YouTube video player"
|
13 |
+
frameborder="0"
|
14 |
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
15 |
+
allowfullscreen
|
16 |
+
></iframe>
|
docs/logo-square.png
ADDED
![]() |
Git LFS Details
|
docs/logo/dark.svg
ADDED
|
docs/logo/light.svg
ADDED
|
docs/openapi.json
ADDED
@@ -0,0 +1,2091 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"openapi": "3.0.3",
|
3 |
+
"info": {
|
4 |
+
"title": "OpenHands API",
|
5 |
+
"description": "OpenHands: Code Less, Make More",
|
6 |
+
"version": "1.0.0"
|
7 |
+
},
|
8 |
+
"servers": [
|
9 |
+
{
|
10 |
+
"url": "https://app.all-hands.dev",
|
11 |
+
"description": "Production server"
|
12 |
+
},
|
13 |
+
{
|
14 |
+
"url": "http://localhost:3000",
|
15 |
+
"description": "Local development server"
|
16 |
+
}
|
17 |
+
],
|
18 |
+
"paths": {
|
19 |
+
"/health": {
|
20 |
+
"get": {
|
21 |
+
"summary": "Health check",
|
22 |
+
"description": "Check if the API is running",
|
23 |
+
"operationId": "health",
|
24 |
+
"responses": {
|
25 |
+
"200": {
|
26 |
+
"description": "API is running",
|
27 |
+
"content": {
|
28 |
+
"text/plain": {
|
29 |
+
"schema": {
|
30 |
+
"type": "string",
|
31 |
+
"example": "OK"
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
37 |
+
}
|
38 |
+
},
|
39 |
+
"/api/conversations/{conversation_id}/config": {
|
40 |
+
"get": {
|
41 |
+
"summary": "Get runtime configuration",
|
42 |
+
"description": "Retrieve the runtime configuration (session ID and runtime ID)",
|
43 |
+
"operationId": "getRemoteRuntimeConfig",
|
44 |
+
"parameters": [
|
45 |
+
{
|
46 |
+
"name": "conversation_id",
|
47 |
+
"in": "path",
|
48 |
+
"required": true,
|
49 |
+
"schema": {
|
50 |
+
"type": "string"
|
51 |
+
},
|
52 |
+
"description": "Conversation ID"
|
53 |
+
}
|
54 |
+
],
|
55 |
+
"responses": {
|
56 |
+
"200": {
|
57 |
+
"description": "Runtime configuration",
|
58 |
+
"content": {
|
59 |
+
"application/json": {
|
60 |
+
"schema": {
|
61 |
+
"type": "object",
|
62 |
+
"properties": {
|
63 |
+
"runtime_id": {
|
64 |
+
"type": "string",
|
65 |
+
"nullable": true
|
66 |
+
},
|
67 |
+
"session_id": {
|
68 |
+
"type": "string",
|
69 |
+
"nullable": true
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
}
|
77 |
+
}
|
78 |
+
},
|
79 |
+
"/api/conversations/{conversation_id}/vscode-url": {
|
80 |
+
"get": {
|
81 |
+
"summary": "Get VSCode URL",
|
82 |
+
"description": "Get the VSCode URL for the conversation",
|
83 |
+
"operationId": "getVscodeUrl",
|
84 |
+
"parameters": [
|
85 |
+
{
|
86 |
+
"name": "conversation_id",
|
87 |
+
"in": "path",
|
88 |
+
"required": true,
|
89 |
+
"schema": {
|
90 |
+
"type": "string"
|
91 |
+
},
|
92 |
+
"description": "Conversation ID"
|
93 |
+
}
|
94 |
+
],
|
95 |
+
"responses": {
|
96 |
+
"200": {
|
97 |
+
"description": "VSCode URL",
|
98 |
+
"content": {
|
99 |
+
"application/json": {
|
100 |
+
"schema": {
|
101 |
+
"type": "object",
|
102 |
+
"properties": {
|
103 |
+
"vscode_url": {
|
104 |
+
"type": "string",
|
105 |
+
"nullable": true
|
106 |
+
}
|
107 |
+
}
|
108 |
+
}
|
109 |
+
}
|
110 |
+
}
|
111 |
+
},
|
112 |
+
"500": {
|
113 |
+
"description": "Error getting VSCode URL",
|
114 |
+
"content": {
|
115 |
+
"application/json": {
|
116 |
+
"schema": {
|
117 |
+
"type": "object",
|
118 |
+
"properties": {
|
119 |
+
"vscode_url": {
|
120 |
+
"type": "string",
|
121 |
+
"nullable": true
|
122 |
+
},
|
123 |
+
"error": {
|
124 |
+
"type": "string"
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
128 |
+
}
|
129 |
+
}
|
130 |
+
}
|
131 |
+
}
|
132 |
+
}
|
133 |
+
},
|
134 |
+
"/api/conversations/{conversation_id}/web-hosts": {
|
135 |
+
"get": {
|
136 |
+
"summary": "Get runtime hosts",
|
137 |
+
"description": "Get the hosts used by the runtime",
|
138 |
+
"operationId": "getHosts",
|
139 |
+
"parameters": [
|
140 |
+
{
|
141 |
+
"name": "conversation_id",
|
142 |
+
"in": "path",
|
143 |
+
"required": true,
|
144 |
+
"schema": {
|
145 |
+
"type": "string"
|
146 |
+
},
|
147 |
+
"description": "Conversation ID"
|
148 |
+
}
|
149 |
+
],
|
150 |
+
"responses": {
|
151 |
+
"200": {
|
152 |
+
"description": "Runtime hosts",
|
153 |
+
"content": {
|
154 |
+
"application/json": {
|
155 |
+
"schema": {
|
156 |
+
"type": "object",
|
157 |
+
"properties": {
|
158 |
+
"hosts": {
|
159 |
+
"type": "array",
|
160 |
+
"items": {
|
161 |
+
"type": "string"
|
162 |
+
}
|
163 |
+
}
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
167 |
+
}
|
168 |
+
},
|
169 |
+
"500": {
|
170 |
+
"description": "Error getting runtime hosts",
|
171 |
+
"content": {
|
172 |
+
"application/json": {
|
173 |
+
"schema": {
|
174 |
+
"type": "object",
|
175 |
+
"properties": {
|
176 |
+
"hosts": {
|
177 |
+
"type": "array",
|
178 |
+
"items": {
|
179 |
+
"type": "string"
|
180 |
+
},
|
181 |
+
"nullable": true
|
182 |
+
},
|
183 |
+
"error": {
|
184 |
+
"type": "string"
|
185 |
+
}
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
189 |
+
}
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
},
|
194 |
+
"/api/conversations/{conversation_id}/submit-feedback": {
|
195 |
+
"post": {
|
196 |
+
"summary": "Submit feedback",
|
197 |
+
"description": "Submit user feedback for a conversation",
|
198 |
+
"operationId": "submitFeedback",
|
199 |
+
"parameters": [
|
200 |
+
{
|
201 |
+
"name": "conversation_id",
|
202 |
+
"in": "path",
|
203 |
+
"required": true,
|
204 |
+
"schema": {
|
205 |
+
"type": "string"
|
206 |
+
},
|
207 |
+
"description": "Conversation ID"
|
208 |
+
}
|
209 |
+
],
|
210 |
+
"requestBody": {
|
211 |
+
"required": true,
|
212 |
+
"content": {
|
213 |
+
"application/json": {
|
214 |
+
"schema": {
|
215 |
+
"type": "object",
|
216 |
+
"properties": {
|
217 |
+
"email": {
|
218 |
+
"type": "string",
|
219 |
+
"format": "email"
|
220 |
+
},
|
221 |
+
"version": {
|
222 |
+
"type": "string"
|
223 |
+
},
|
224 |
+
"permissions": {
|
225 |
+
"type": "string",
|
226 |
+
"default": "private"
|
227 |
+
},
|
228 |
+
"polarity": {
|
229 |
+
"type": "string"
|
230 |
+
},
|
231 |
+
"feedback": {
|
232 |
+
"type": "string"
|
233 |
+
}
|
234 |
+
}
|
235 |
+
}
|
236 |
+
}
|
237 |
+
}
|
238 |
+
},
|
239 |
+
"responses": {
|
240 |
+
"200": {
|
241 |
+
"description": "Feedback submitted successfully",
|
242 |
+
"content": {
|
243 |
+
"application/json": {
|
244 |
+
"schema": {
|
245 |
+
"type": "object"
|
246 |
+
}
|
247 |
+
}
|
248 |
+
}
|
249 |
+
},
|
250 |
+
"500": {
|
251 |
+
"description": "Error submitting feedback",
|
252 |
+
"content": {
|
253 |
+
"application/json": {
|
254 |
+
"schema": {
|
255 |
+
"type": "object",
|
256 |
+
"properties": {
|
257 |
+
"error": {
|
258 |
+
"type": "string"
|
259 |
+
}
|
260 |
+
}
|
261 |
+
}
|
262 |
+
}
|
263 |
+
}
|
264 |
+
}
|
265 |
+
}
|
266 |
+
}
|
267 |
+
},
|
268 |
+
"/api/conversations/{conversation_id}/list-files": {
|
269 |
+
"get": {
|
270 |
+
"summary": "List files",
|
271 |
+
"description": "List files in the specified path",
|
272 |
+
"operationId": "listFiles",
|
273 |
+
"parameters": [
|
274 |
+
{
|
275 |
+
"name": "conversation_id",
|
276 |
+
"in": "path",
|
277 |
+
"required": true,
|
278 |
+
"schema": {
|
279 |
+
"type": "string"
|
280 |
+
},
|
281 |
+
"description": "Conversation ID"
|
282 |
+
},
|
283 |
+
{
|
284 |
+
"name": "path",
|
285 |
+
"in": "query",
|
286 |
+
"required": false,
|
287 |
+
"schema": {
|
288 |
+
"type": "string"
|
289 |
+
},
|
290 |
+
"description": "Path to list files from"
|
291 |
+
}
|
292 |
+
],
|
293 |
+
"responses": {
|
294 |
+
"200": {
|
295 |
+
"description": "List of files",
|
296 |
+
"content": {
|
297 |
+
"application/json": {
|
298 |
+
"schema": {
|
299 |
+
"type": "array",
|
300 |
+
"items": {
|
301 |
+
"type": "string"
|
302 |
+
}
|
303 |
+
}
|
304 |
+
}
|
305 |
+
}
|
306 |
+
},
|
307 |
+
"404": {
|
308 |
+
"description": "Runtime not initialized",
|
309 |
+
"content": {
|
310 |
+
"application/json": {
|
311 |
+
"schema": {
|
312 |
+
"type": "object",
|
313 |
+
"properties": {
|
314 |
+
"error": {
|
315 |
+
"type": "string"
|
316 |
+
}
|
317 |
+
}
|
318 |
+
}
|
319 |
+
}
|
320 |
+
}
|
321 |
+
},
|
322 |
+
"500": {
|
323 |
+
"description": "Error listing files",
|
324 |
+
"content": {
|
325 |
+
"application/json": {
|
326 |
+
"schema": {
|
327 |
+
"type": "object",
|
328 |
+
"properties": {
|
329 |
+
"error": {
|
330 |
+
"type": "string"
|
331 |
+
}
|
332 |
+
}
|
333 |
+
}
|
334 |
+
}
|
335 |
+
}
|
336 |
+
}
|
337 |
+
}
|
338 |
+
}
|
339 |
+
},
|
340 |
+
"/api/conversations/{conversation_id}/select-file": {
|
341 |
+
"get": {
|
342 |
+
"summary": "Get file content",
|
343 |
+
"description": "Retrieve the content of a specified file",
|
344 |
+
"operationId": "selectFile",
|
345 |
+
"parameters": [
|
346 |
+
{
|
347 |
+
"name": "conversation_id",
|
348 |
+
"in": "path",
|
349 |
+
"required": true,
|
350 |
+
"schema": {
|
351 |
+
"type": "string"
|
352 |
+
},
|
353 |
+
"description": "Conversation ID"
|
354 |
+
},
|
355 |
+
{
|
356 |
+
"name": "file",
|
357 |
+
"in": "query",
|
358 |
+
"required": true,
|
359 |
+
"schema": {
|
360 |
+
"type": "string"
|
361 |
+
},
|
362 |
+
"description": "Path of the file to be retrieved"
|
363 |
+
}
|
364 |
+
],
|
365 |
+
"responses": {
|
366 |
+
"200": {
|
367 |
+
"description": "File content",
|
368 |
+
"content": {
|
369 |
+
"application/json": {
|
370 |
+
"schema": {
|
371 |
+
"type": "object",
|
372 |
+
"properties": {
|
373 |
+
"code": {
|
374 |
+
"type": "string"
|
375 |
+
}
|
376 |
+
}
|
377 |
+
}
|
378 |
+
}
|
379 |
+
}
|
380 |
+
},
|
381 |
+
"415": {
|
382 |
+
"description": "Unable to open binary file",
|
383 |
+
"content": {
|
384 |
+
"application/json": {
|
385 |
+
"schema": {
|
386 |
+
"type": "object",
|
387 |
+
"properties": {
|
388 |
+
"error": {
|
389 |
+
"type": "string"
|
390 |
+
}
|
391 |
+
}
|
392 |
+
}
|
393 |
+
}
|
394 |
+
}
|
395 |
+
},
|
396 |
+
"500": {
|
397 |
+
"description": "Error opening file",
|
398 |
+
"content": {
|
399 |
+
"application/json": {
|
400 |
+
"schema": {
|
401 |
+
"type": "object",
|
402 |
+
"properties": {
|
403 |
+
"error": {
|
404 |
+
"type": "string"
|
405 |
+
}
|
406 |
+
}
|
407 |
+
}
|
408 |
+
}
|
409 |
+
}
|
410 |
+
}
|
411 |
+
}
|
412 |
+
}
|
413 |
+
},
|
414 |
+
"/api/conversations/{conversation_id}/zip-directory": {
|
415 |
+
"get": {
|
416 |
+
"summary": "Download workspace as zip",
|
417 |
+
"description": "Download the current workspace as a zip file",
|
418 |
+
"operationId": "zipCurrentWorkspace",
|
419 |
+
"parameters": [
|
420 |
+
{
|
421 |
+
"name": "conversation_id",
|
422 |
+
"in": "path",
|
423 |
+
"required": true,
|
424 |
+
"schema": {
|
425 |
+
"type": "string"
|
426 |
+
},
|
427 |
+
"description": "Conversation ID"
|
428 |
+
}
|
429 |
+
],
|
430 |
+
"responses": {
|
431 |
+
"200": {
|
432 |
+
"description": "Workspace zip file",
|
433 |
+
"content": {
|
434 |
+
"application/zip": {
|
435 |
+
"schema": {
|
436 |
+
"type": "string",
|
437 |
+
"format": "binary"
|
438 |
+
}
|
439 |
+
}
|
440 |
+
}
|
441 |
+
},
|
442 |
+
"500": {
|
443 |
+
"description": "Error zipping workspace",
|
444 |
+
"content": {
|
445 |
+
"application/json": {
|
446 |
+
"schema": {
|
447 |
+
"type": "object",
|
448 |
+
"properties": {
|
449 |
+
"error": {
|
450 |
+
"type": "string"
|
451 |
+
}
|
452 |
+
}
|
453 |
+
}
|
454 |
+
}
|
455 |
+
}
|
456 |
+
}
|
457 |
+
}
|
458 |
+
}
|
459 |
+
},
|
460 |
+
"/api/conversations/{conversation_id}/git/changes": {
|
461 |
+
"get": {
|
462 |
+
"summary": "Get git changes",
|
463 |
+
"description": "Get git changes in the workspace",
|
464 |
+
"operationId": "gitChanges",
|
465 |
+
"parameters": [
|
466 |
+
{
|
467 |
+
"name": "conversation_id",
|
468 |
+
"in": "path",
|
469 |
+
"required": true,
|
470 |
+
"schema": {
|
471 |
+
"type": "string"
|
472 |
+
},
|
473 |
+
"description": "Conversation ID"
|
474 |
+
}
|
475 |
+
],
|
476 |
+
"responses": {
|
477 |
+
"200": {
|
478 |
+
"description": "Git changes",
|
479 |
+
"content": {
|
480 |
+
"application/json": {
|
481 |
+
"schema": {
|
482 |
+
"type": "object"
|
483 |
+
}
|
484 |
+
}
|
485 |
+
}
|
486 |
+
},
|
487 |
+
"500": {
|
488 |
+
"description": "Error getting git changes",
|
489 |
+
"content": {
|
490 |
+
"application/json": {
|
491 |
+
"schema": {
|
492 |
+
"type": "object",
|
493 |
+
"properties": {
|
494 |
+
"error": {
|
495 |
+
"type": "string"
|
496 |
+
}
|
497 |
+
}
|
498 |
+
}
|
499 |
+
}
|
500 |
+
}
|
501 |
+
}
|
502 |
+
}
|
503 |
+
}
|
504 |
+
},
|
505 |
+
"/api/conversations/{conversation_id}/git/diff": {
|
506 |
+
"get": {
|
507 |
+
"summary": "Get git diff",
|
508 |
+
"description": "Get git diff for a specific file",
|
509 |
+
"operationId": "gitDiff",
|
510 |
+
"parameters": [
|
511 |
+
{
|
512 |
+
"name": "conversation_id",
|
513 |
+
"in": "path",
|
514 |
+
"required": true,
|
515 |
+
"schema": {
|
516 |
+
"type": "string"
|
517 |
+
},
|
518 |
+
"description": "Conversation ID"
|
519 |
+
},
|
520 |
+
{
|
521 |
+
"name": "path",
|
522 |
+
"in": "query",
|
523 |
+
"required": true,
|
524 |
+
"schema": {
|
525 |
+
"type": "string"
|
526 |
+
},
|
527 |
+
"description": "Path of the file to get diff for"
|
528 |
+
}
|
529 |
+
],
|
530 |
+
"responses": {
|
531 |
+
"200": {
|
532 |
+
"description": "Git diff",
|
533 |
+
"content": {
|
534 |
+
"application/json": {
|
535 |
+
"schema": {
|
536 |
+
"type": "string"
|
537 |
+
}
|
538 |
+
}
|
539 |
+
}
|
540 |
+
},
|
541 |
+
"500": {
|
542 |
+
"description": "Error getting git diff",
|
543 |
+
"content": {
|
544 |
+
"application/json": {
|
545 |
+
"schema": {
|
546 |
+
"type": "object",
|
547 |
+
"properties": {
|
548 |
+
"error": {
|
549 |
+
"type": "string"
|
550 |
+
}
|
551 |
+
}
|
552 |
+
}
|
553 |
+
}
|
554 |
+
}
|
555 |
+
}
|
556 |
+
}
|
557 |
+
}
|
558 |
+
},
|
559 |
+
"/api/conversations/{conversation_id}/trajectory": {
|
560 |
+
"get": {
|
561 |
+
"summary": "Get trajectory",
|
562 |
+
"description": "Get the conversation trajectory",
|
563 |
+
"operationId": "getTrajectory",
|
564 |
+
"parameters": [
|
565 |
+
{
|
566 |
+
"name": "conversation_id",
|
567 |
+
"in": "path",
|
568 |
+
"required": true,
|
569 |
+
"schema": {
|
570 |
+
"type": "string"
|
571 |
+
},
|
572 |
+
"description": "Conversation ID"
|
573 |
+
}
|
574 |
+
],
|
575 |
+
"responses": {
|
576 |
+
"200": {
|
577 |
+
"description": "Conversation trajectory",
|
578 |
+
"content": {
|
579 |
+
"application/json": {
|
580 |
+
"schema": {
|
581 |
+
"type": "object",
|
582 |
+
"properties": {
|
583 |
+
"trajectory": {
|
584 |
+
"type": "array",
|
585 |
+
"items": {
|
586 |
+
"type": "object"
|
587 |
+
}
|
588 |
+
}
|
589 |
+
}
|
590 |
+
}
|
591 |
+
}
|
592 |
+
}
|
593 |
+
},
|
594 |
+
"500": {
|
595 |
+
"description": "Error getting trajectory",
|
596 |
+
"content": {
|
597 |
+
"application/json": {
|
598 |
+
"schema": {
|
599 |
+
"type": "object",
|
600 |
+
"properties": {
|
601 |
+
"trajectory": {
|
602 |
+
"type": "array",
|
603 |
+
"items": {
|
604 |
+
"type": "object"
|
605 |
+
},
|
606 |
+
"nullable": true
|
607 |
+
},
|
608 |
+
"error": {
|
609 |
+
"type": "string"
|
610 |
+
}
|
611 |
+
}
|
612 |
+
}
|
613 |
+
}
|
614 |
+
}
|
615 |
+
}
|
616 |
+
}
|
617 |
+
}
|
618 |
+
},
|
619 |
+
"/api/conversations/{conversation_id}/security/{path}": {
|
620 |
+
"get": {
|
621 |
+
"summary": "Security analyzer API (GET)",
|
622 |
+
"description": "Catch-all route for security analyzer API GET requests",
|
623 |
+
"operationId": "securityApiGet",
|
624 |
+
"parameters": [
|
625 |
+
{
|
626 |
+
"name": "conversation_id",
|
627 |
+
"in": "path",
|
628 |
+
"required": true,
|
629 |
+
"schema": {
|
630 |
+
"type": "string"
|
631 |
+
},
|
632 |
+
"description": "Conversation ID"
|
633 |
+
},
|
634 |
+
{
|
635 |
+
"name": "path",
|
636 |
+
"in": "path",
|
637 |
+
"required": true,
|
638 |
+
"schema": {
|
639 |
+
"type": "string"
|
640 |
+
},
|
641 |
+
"description": "Security analyzer API path"
|
642 |
+
}
|
643 |
+
],
|
644 |
+
"responses": {
|
645 |
+
"200": {
|
646 |
+
"description": "Security analyzer response",
|
647 |
+
"content": {
|
648 |
+
"application/json": {
|
649 |
+
"schema": {
|
650 |
+
"type": "object"
|
651 |
+
}
|
652 |
+
}
|
653 |
+
}
|
654 |
+
},
|
655 |
+
"404": {
|
656 |
+
"description": "Security analyzer not initialized",
|
657 |
+
"content": {
|
658 |
+
"application/json": {
|
659 |
+
"schema": {
|
660 |
+
"type": "object",
|
661 |
+
"properties": {
|
662 |
+
"detail": {
|
663 |
+
"type": "string"
|
664 |
+
}
|
665 |
+
}
|
666 |
+
}
|
667 |
+
}
|
668 |
+
}
|
669 |
+
}
|
670 |
+
}
|
671 |
+
},
|
672 |
+
"post": {
|
673 |
+
"summary": "Security analyzer API (POST)",
|
674 |
+
"description": "Catch-all route for security analyzer API POST requests",
|
675 |
+
"operationId": "securityApiPost",
|
676 |
+
"parameters": [
|
677 |
+
{
|
678 |
+
"name": "conversation_id",
|
679 |
+
"in": "path",
|
680 |
+
"required": true,
|
681 |
+
"schema": {
|
682 |
+
"type": "string"
|
683 |
+
},
|
684 |
+
"description": "Conversation ID"
|
685 |
+
},
|
686 |
+
{
|
687 |
+
"name": "path",
|
688 |
+
"in": "path",
|
689 |
+
"required": true,
|
690 |
+
"schema": {
|
691 |
+
"type": "string"
|
692 |
+
},
|
693 |
+
"description": "Security analyzer API path"
|
694 |
+
}
|
695 |
+
],
|
696 |
+
"requestBody": {
|
697 |
+
"required": false,
|
698 |
+
"content": {
|
699 |
+
"application/json": {
|
700 |
+
"schema": {
|
701 |
+
"type": "object"
|
702 |
+
}
|
703 |
+
}
|
704 |
+
}
|
705 |
+
},
|
706 |
+
"responses": {
|
707 |
+
"200": {
|
708 |
+
"description": "Security analyzer response",
|
709 |
+
"content": {
|
710 |
+
"application/json": {
|
711 |
+
"schema": {
|
712 |
+
"type": "object"
|
713 |
+
}
|
714 |
+
}
|
715 |
+
}
|
716 |
+
},
|
717 |
+
"404": {
|
718 |
+
"description": "Security analyzer not initialized",
|
719 |
+
"content": {
|
720 |
+
"application/json": {
|
721 |
+
"schema": {
|
722 |
+
"type": "object",
|
723 |
+
"properties": {
|
724 |
+
"detail": {
|
725 |
+
"type": "string"
|
726 |
+
}
|
727 |
+
}
|
728 |
+
}
|
729 |
+
}
|
730 |
+
}
|
731 |
+
}
|
732 |
+
}
|
733 |
+
},
|
734 |
+
"put": {
|
735 |
+
"summary": "Security analyzer API (PUT)",
|
736 |
+
"description": "Catch-all route for security analyzer API PUT requests",
|
737 |
+
"operationId": "securityApiPut",
|
738 |
+
"parameters": [
|
739 |
+
{
|
740 |
+
"name": "conversation_id",
|
741 |
+
"in": "path",
|
742 |
+
"required": true,
|
743 |
+
"schema": {
|
744 |
+
"type": "string"
|
745 |
+
},
|
746 |
+
"description": "Conversation ID"
|
747 |
+
},
|
748 |
+
{
|
749 |
+
"name": "path",
|
750 |
+
"in": "path",
|
751 |
+
"required": true,
|
752 |
+
"schema": {
|
753 |
+
"type": "string"
|
754 |
+
},
|
755 |
+
"description": "Security analyzer API path"
|
756 |
+
}
|
757 |
+
],
|
758 |
+
"requestBody": {
|
759 |
+
"required": false,
|
760 |
+
"content": {
|
761 |
+
"application/json": {
|
762 |
+
"schema": {
|
763 |
+
"type": "object"
|
764 |
+
}
|
765 |
+
}
|
766 |
+
}
|
767 |
+
},
|
768 |
+
"responses": {
|
769 |
+
"200": {
|
770 |
+
"description": "Security analyzer response",
|
771 |
+
"content": {
|
772 |
+
"application/json": {
|
773 |
+
"schema": {
|
774 |
+
"type": "object"
|
775 |
+
}
|
776 |
+
}
|
777 |
+
}
|
778 |
+
},
|
779 |
+
"404": {
|
780 |
+
"description": "Security analyzer not initialized",
|
781 |
+
"content": {
|
782 |
+
"application/json": {
|
783 |
+
"schema": {
|
784 |
+
"type": "object",
|
785 |
+
"properties": {
|
786 |
+
"detail": {
|
787 |
+
"type": "string"
|
788 |
+
}
|
789 |
+
}
|
790 |
+
}
|
791 |
+
}
|
792 |
+
}
|
793 |
+
}
|
794 |
+
}
|
795 |
+
},
|
796 |
+
"delete": {
|
797 |
+
"summary": "Security analyzer API (DELETE)",
|
798 |
+
"description": "Catch-all route for security analyzer API DELETE requests",
|
799 |
+
"operationId": "securityApiDelete",
|
800 |
+
"parameters": [
|
801 |
+
{
|
802 |
+
"name": "conversation_id",
|
803 |
+
"in": "path",
|
804 |
+
"required": true,
|
805 |
+
"schema": {
|
806 |
+
"type": "string"
|
807 |
+
},
|
808 |
+
"description": "Conversation ID"
|
809 |
+
},
|
810 |
+
{
|
811 |
+
"name": "path",
|
812 |
+
"in": "path",
|
813 |
+
"required": true,
|
814 |
+
"schema": {
|
815 |
+
"type": "string"
|
816 |
+
},
|
817 |
+
"description": "Security analyzer API path"
|
818 |
+
}
|
819 |
+
],
|
820 |
+
"responses": {
|
821 |
+
"200": {
|
822 |
+
"description": "Security analyzer response",
|
823 |
+
"content": {
|
824 |
+
"application/json": {
|
825 |
+
"schema": {
|
826 |
+
"type": "object"
|
827 |
+
}
|
828 |
+
}
|
829 |
+
}
|
830 |
+
},
|
831 |
+
"404": {
|
832 |
+
"description": "Security analyzer not initialized",
|
833 |
+
"content": {
|
834 |
+
"application/json": {
|
835 |
+
"schema": {
|
836 |
+
"type": "object",
|
837 |
+
"properties": {
|
838 |
+
"detail": {
|
839 |
+
"type": "string"
|
840 |
+
}
|
841 |
+
}
|
842 |
+
}
|
843 |
+
}
|
844 |
+
}
|
845 |
+
}
|
846 |
+
}
|
847 |
+
}
|
848 |
+
},
|
849 |
+
"/api/conversations": {
|
850 |
+
"post": {
|
851 |
+
"summary": "Create new conversation",
|
852 |
+
"description": "Initialize a new conversation",
|
853 |
+
"operationId": "newConversation",
|
854 |
+
"requestBody": {
|
855 |
+
"required": true,
|
856 |
+
"content": {
|
857 |
+
"application/json": {
|
858 |
+
"schema": {
|
859 |
+
"type": "object",
|
860 |
+
"properties": {
|
861 |
+
"repository": {
|
862 |
+
"type": "string",
|
863 |
+
"nullable": true,
|
864 |
+
"description": "Full name of the repository (e.g., owner/repo)"
|
865 |
+
},
|
866 |
+
"git_provider": {
|
867 |
+
"type": "string",
|
868 |
+
"nullable": true,
|
869 |
+
"description": "The Git provider (e.g., github or gitlab). If omitted, all configured providers are checked for the repository."
|
870 |
+
},
|
871 |
+
"selected_branch": {
|
872 |
+
"type": "string",
|
873 |
+
"nullable": true
|
874 |
+
},
|
875 |
+
"initial_user_msg": {
|
876 |
+
"type": "string",
|
877 |
+
"nullable": true
|
878 |
+
},
|
879 |
+
"conversation_instructions": {
|
880 |
+
"type": "string",
|
881 |
+
"nullable": true,
|
882 |
+
"description": "Optional instructions the agent must follow throughout the conversation while addressing the user's initial task"
|
883 |
+
},
|
884 |
+
"image_urls": {
|
885 |
+
"type": "array",
|
886 |
+
"items": {
|
887 |
+
"type": "string"
|
888 |
+
},
|
889 |
+
"nullable": true
|
890 |
+
},
|
891 |
+
"replay_json": {
|
892 |
+
"type": "string",
|
893 |
+
"nullable": true
|
894 |
+
}
|
895 |
+
}
|
896 |
+
}
|
897 |
+
}
|
898 |
+
}
|
899 |
+
},
|
900 |
+
"responses": {
|
901 |
+
"200": {
|
902 |
+
"description": "Conversation created successfully",
|
903 |
+
"content": {
|
904 |
+
"application/json": {
|
905 |
+
"schema": {
|
906 |
+
"type": "object",
|
907 |
+
"properties": {
|
908 |
+
"status": {
|
909 |
+
"type": "string",
|
910 |
+
"example": "ok"
|
911 |
+
},
|
912 |
+
"conversation_id": {
|
913 |
+
"type": "string"
|
914 |
+
}
|
915 |
+
}
|
916 |
+
}
|
917 |
+
}
|
918 |
+
}
|
919 |
+
},
|
920 |
+
"400": {
|
921 |
+
"description": "Error creating conversation",
|
922 |
+
"content": {
|
923 |
+
"application/json": {
|
924 |
+
"schema": {
|
925 |
+
"type": "object",
|
926 |
+
"properties": {
|
927 |
+
"status": {
|
928 |
+
"type": "string",
|
929 |
+
"example": "error"
|
930 |
+
},
|
931 |
+
"message": {
|
932 |
+
"type": "string"
|
933 |
+
},
|
934 |
+
"msg_id": {
|
935 |
+
"type": "string"
|
936 |
+
}
|
937 |
+
}
|
938 |
+
}
|
939 |
+
}
|
940 |
+
}
|
941 |
+
}
|
942 |
+
}
|
943 |
+
},
|
944 |
+
"get": {
|
945 |
+
"summary": "Search conversations",
|
946 |
+
"description": "Search for conversations",
|
947 |
+
"operationId": "searchConversations",
|
948 |
+
"parameters": [
|
949 |
+
{
|
950 |
+
"name": "page_id",
|
951 |
+
"in": "query",
|
952 |
+
"required": false,
|
953 |
+
"schema": {
|
954 |
+
"type": "string"
|
955 |
+
},
|
956 |
+
"description": "Page ID for pagination"
|
957 |
+
},
|
958 |
+
{
|
959 |
+
"name": "limit",
|
960 |
+
"in": "query",
|
961 |
+
"required": false,
|
962 |
+
"schema": {
|
963 |
+
"type": "integer",
|
964 |
+
"default": 20
|
965 |
+
},
|
966 |
+
"description": "Number of conversations to return"
|
967 |
+
}
|
968 |
+
],
|
969 |
+
"responses": {
|
970 |
+
"200": {
|
971 |
+
"description": "Conversations",
|
972 |
+
"content": {
|
973 |
+
"application/json": {
|
974 |
+
"schema": {
|
975 |
+
"type": "object",
|
976 |
+
"properties": {
|
977 |
+
"results": {
|
978 |
+
"type": "array",
|
979 |
+
"items": {
|
980 |
+
"type": "object",
|
981 |
+
"properties": {
|
982 |
+
"conversation_id": {
|
983 |
+
"type": "string"
|
984 |
+
},
|
985 |
+
"title": {
|
986 |
+
"type": "string"
|
987 |
+
},
|
988 |
+
"last_updated_at": {
|
989 |
+
"type": "string",
|
990 |
+
"format": "date-time"
|
991 |
+
},
|
992 |
+
"created_at": {
|
993 |
+
"type": "string",
|
994 |
+
"format": "date-time"
|
995 |
+
},
|
996 |
+
"selected_repository": {
|
997 |
+
"type": "string",
|
998 |
+
"nullable": true
|
999 |
+
},
|
1000 |
+
"status": {
|
1001 |
+
"type": "string",
|
1002 |
+
"enum": ["RUNNING", "STOPPED"]
|
1003 |
+
},
|
1004 |
+
"trigger": {
|
1005 |
+
"type": "string",
|
1006 |
+
"enum": ["GUI", "API"]
|
1007 |
+
}
|
1008 |
+
}
|
1009 |
+
}
|
1010 |
+
},
|
1011 |
+
"next_page_id": {
|
1012 |
+
"type": "string",
|
1013 |
+
"nullable": true
|
1014 |
+
}
|
1015 |
+
}
|
1016 |
+
}
|
1017 |
+
}
|
1018 |
+
}
|
1019 |
+
}
|
1020 |
+
}
|
1021 |
+
}
|
1022 |
+
},
|
1023 |
+
"/api/conversations/{conversation_id}": {
|
1024 |
+
"get": {
|
1025 |
+
"summary": "Get conversation",
|
1026 |
+
"description": "Get conversation details",
|
1027 |
+
"operationId": "getConversation",
|
1028 |
+
"parameters": [
|
1029 |
+
{
|
1030 |
+
"name": "conversation_id",
|
1031 |
+
"in": "path",
|
1032 |
+
"required": true,
|
1033 |
+
"schema": {
|
1034 |
+
"type": "string"
|
1035 |
+
},
|
1036 |
+
"description": "Conversation ID"
|
1037 |
+
}
|
1038 |
+
],
|
1039 |
+
"responses": {
|
1040 |
+
"200": {
|
1041 |
+
"description": "Conversation details",
|
1042 |
+
"content": {
|
1043 |
+
"application/json": {
|
1044 |
+
"schema": {
|
1045 |
+
"type": "object",
|
1046 |
+
"properties": {
|
1047 |
+
"conversation_id": {
|
1048 |
+
"type": "string"
|
1049 |
+
},
|
1050 |
+
"title": {
|
1051 |
+
"type": "string"
|
1052 |
+
},
|
1053 |
+
"last_updated_at": {
|
1054 |
+
"type": "string",
|
1055 |
+
"format": "date-time"
|
1056 |
+
},
|
1057 |
+
"created_at": {
|
1058 |
+
"type": "string",
|
1059 |
+
"format": "date-time"
|
1060 |
+
},
|
1061 |
+
"selected_repository": {
|
1062 |
+
"type": "string",
|
1063 |
+
"nullable": true
|
1064 |
+
},
|
1065 |
+
"status": {
|
1066 |
+
"type": "string",
|
1067 |
+
"enum": ["RUNNING", "STOPPED"]
|
1068 |
+
},
|
1069 |
+
"trigger": {
|
1070 |
+
"type": "string",
|
1071 |
+
"enum": ["GUI", "API"]
|
1072 |
+
}
|
1073 |
+
}
|
1074 |
+
}
|
1075 |
+
}
|
1076 |
+
}
|
1077 |
+
},
|
1078 |
+
"404": {
|
1079 |
+
"description": "Conversation not found",
|
1080 |
+
"content": {
|
1081 |
+
"application/json": {
|
1082 |
+
"schema": {
|
1083 |
+
"type": "object",
|
1084 |
+
"nullable": true
|
1085 |
+
}
|
1086 |
+
}
|
1087 |
+
}
|
1088 |
+
}
|
1089 |
+
}
|
1090 |
+
},
|
1091 |
+
"patch": {
|
1092 |
+
"summary": "Update conversation",
|
1093 |
+
"description": "Update conversation details",
|
1094 |
+
"operationId": "updateConversation",
|
1095 |
+
"parameters": [
|
1096 |
+
{
|
1097 |
+
"name": "conversation_id",
|
1098 |
+
"in": "path",
|
1099 |
+
"required": true,
|
1100 |
+
"schema": {
|
1101 |
+
"type": "string"
|
1102 |
+
},
|
1103 |
+
"description": "Conversation ID"
|
1104 |
+
}
|
1105 |
+
],
|
1106 |
+
"requestBody": {
|
1107 |
+
"required": true,
|
1108 |
+
"content": {
|
1109 |
+
"application/json": {
|
1110 |
+
"schema": {
|
1111 |
+
"type": "object",
|
1112 |
+
"properties": {
|
1113 |
+
"title": {
|
1114 |
+
"type": "string"
|
1115 |
+
}
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
}
|
1119 |
+
}
|
1120 |
+
},
|
1121 |
+
"responses": {
|
1122 |
+
"200": {
|
1123 |
+
"description": "Conversation updated successfully",
|
1124 |
+
"content": {
|
1125 |
+
"application/json": {
|
1126 |
+
"schema": {
|
1127 |
+
"type": "boolean"
|
1128 |
+
}
|
1129 |
+
}
|
1130 |
+
}
|
1131 |
+
}
|
1132 |
+
}
|
1133 |
+
},
|
1134 |
+
"delete": {
|
1135 |
+
"summary": "Delete conversation",
|
1136 |
+
"description": "Delete a conversation",
|
1137 |
+
"operationId": "deleteConversation",
|
1138 |
+
"parameters": [
|
1139 |
+
{
|
1140 |
+
"name": "conversation_id",
|
1141 |
+
"in": "path",
|
1142 |
+
"required": true,
|
1143 |
+
"schema": {
|
1144 |
+
"type": "string"
|
1145 |
+
},
|
1146 |
+
"description": "Conversation ID"
|
1147 |
+
}
|
1148 |
+
],
|
1149 |
+
"responses": {
|
1150 |
+
"200": {
|
1151 |
+
"description": "Conversation deleted successfully",
|
1152 |
+
"content": {
|
1153 |
+
"application/json": {
|
1154 |
+
"schema": {
|
1155 |
+
"type": "boolean"
|
1156 |
+
}
|
1157 |
+
}
|
1158 |
+
}
|
1159 |
+
}
|
1160 |
+
}
|
1161 |
+
}
|
1162 |
+
},
|
1163 |
+
"/api/user/repositories": {
|
1164 |
+
"get": {
|
1165 |
+
"summary": "Get user repositories",
|
1166 |
+
"description": "Get repositories for the authenticated user",
|
1167 |
+
"operationId": "getUserRepositories",
|
1168 |
+
"parameters": [
|
1169 |
+
{
|
1170 |
+
"name": "sort",
|
1171 |
+
"in": "query",
|
1172 |
+
"required": false,
|
1173 |
+
"schema": {
|
1174 |
+
"type": "string",
|
1175 |
+
"default": "pushed"
|
1176 |
+
},
|
1177 |
+
"description": "Sort order for repositories"
|
1178 |
+
}
|
1179 |
+
],
|
1180 |
+
"responses": {
|
1181 |
+
"200": {
|
1182 |
+
"description": "User repositories",
|
1183 |
+
"content": {
|
1184 |
+
"application/json": {
|
1185 |
+
"schema": {
|
1186 |
+
"type": "array",
|
1187 |
+
"items": {
|
1188 |
+
"type": "object",
|
1189 |
+
"properties": {
|
1190 |
+
"full_name": {
|
1191 |
+
"type": "string"
|
1192 |
+
},
|
1193 |
+
"description": {
|
1194 |
+
"type": "string",
|
1195 |
+
"nullable": true
|
1196 |
+
},
|
1197 |
+
"html_url": {
|
1198 |
+
"type": "string"
|
1199 |
+
},
|
1200 |
+
"private": {
|
1201 |
+
"type": "boolean"
|
1202 |
+
},
|
1203 |
+
"fork": {
|
1204 |
+
"type": "boolean"
|
1205 |
+
},
|
1206 |
+
"updated_at": {
|
1207 |
+
"type": "string",
|
1208 |
+
"format": "date-time"
|
1209 |
+
}
|
1210 |
+
}
|
1211 |
+
}
|
1212 |
+
}
|
1213 |
+
}
|
1214 |
+
}
|
1215 |
+
},
|
1216 |
+
"401": {
|
1217 |
+
"description": "Authentication error",
|
1218 |
+
"content": {
|
1219 |
+
"application/json": {
|
1220 |
+
"schema": {
|
1221 |
+
"type": "string"
|
1222 |
+
}
|
1223 |
+
}
|
1224 |
+
}
|
1225 |
+
},
|
1226 |
+
"500": {
|
1227 |
+
"description": "Unknown error",
|
1228 |
+
"content": {
|
1229 |
+
"application/json": {
|
1230 |
+
"schema": {
|
1231 |
+
"type": "string"
|
1232 |
+
}
|
1233 |
+
}
|
1234 |
+
}
|
1235 |
+
}
|
1236 |
+
}
|
1237 |
+
}
|
1238 |
+
},
|
1239 |
+
"/api/user/info": {
|
1240 |
+
"get": {
|
1241 |
+
"summary": "Get user info",
|
1242 |
+
"description": "Get information about the authenticated user",
|
1243 |
+
"operationId": "getUser",
|
1244 |
+
"responses": {
|
1245 |
+
"200": {
|
1246 |
+
"description": "User information",
|
1247 |
+
"content": {
|
1248 |
+
"application/json": {
|
1249 |
+
"schema": {
|
1250 |
+
"type": "object",
|
1251 |
+
"properties": {
|
1252 |
+
"login": {
|
1253 |
+
"type": "string"
|
1254 |
+
},
|
1255 |
+
"name": {
|
1256 |
+
"type": "string",
|
1257 |
+
"nullable": true
|
1258 |
+
},
|
1259 |
+
"email": {
|
1260 |
+
"type": "string",
|
1261 |
+
"nullable": true
|
1262 |
+
},
|
1263 |
+
"avatar_url": {
|
1264 |
+
"type": "string",
|
1265 |
+
"nullable": true
|
1266 |
+
}
|
1267 |
+
}
|
1268 |
+
}
|
1269 |
+
}
|
1270 |
+
}
|
1271 |
+
},
|
1272 |
+
"401": {
|
1273 |
+
"description": "Authentication error",
|
1274 |
+
"content": {
|
1275 |
+
"application/json": {
|
1276 |
+
"schema": {
|
1277 |
+
"type": "string"
|
1278 |
+
}
|
1279 |
+
}
|
1280 |
+
}
|
1281 |
+
},
|
1282 |
+
"500": {
|
1283 |
+
"description": "Unknown error",
|
1284 |
+
"content": {
|
1285 |
+
"application/json": {
|
1286 |
+
"schema": {
|
1287 |
+
"type": "string"
|
1288 |
+
}
|
1289 |
+
}
|
1290 |
+
}
|
1291 |
+
}
|
1292 |
+
}
|
1293 |
+
}
|
1294 |
+
},
|
1295 |
+
"/api/user/search/repositories": {
|
1296 |
+
"get": {
|
1297 |
+
"summary": "Search repositories",
|
1298 |
+
"description": "Search for repositories",
|
1299 |
+
"operationId": "searchRepositories",
|
1300 |
+
"parameters": [
|
1301 |
+
{
|
1302 |
+
"name": "query",
|
1303 |
+
"in": "query",
|
1304 |
+
"required": true,
|
1305 |
+
"schema": {
|
1306 |
+
"type": "string"
|
1307 |
+
},
|
1308 |
+
"description": "Search query"
|
1309 |
+
},
|
1310 |
+
{
|
1311 |
+
"name": "per_page",
|
1312 |
+
"in": "query",
|
1313 |
+
"required": false,
|
1314 |
+
"schema": {
|
1315 |
+
"type": "integer",
|
1316 |
+
"default": 5
|
1317 |
+
},
|
1318 |
+
"description": "Number of repositories to return per page"
|
1319 |
+
},
|
1320 |
+
{
|
1321 |
+
"name": "sort",
|
1322 |
+
"in": "query",
|
1323 |
+
"required": false,
|
1324 |
+
"schema": {
|
1325 |
+
"type": "string",
|
1326 |
+
"default": "stars"
|
1327 |
+
},
|
1328 |
+
"description": "Sort order for repositories"
|
1329 |
+
},
|
1330 |
+
{
|
1331 |
+
"name": "order",
|
1332 |
+
"in": "query",
|
1333 |
+
"required": false,
|
1334 |
+
"schema": {
|
1335 |
+
"type": "string",
|
1336 |
+
"default": "desc"
|
1337 |
+
},
|
1338 |
+
"description": "Sort direction"
|
1339 |
+
}
|
1340 |
+
],
|
1341 |
+
"responses": {
|
1342 |
+
"200": {
|
1343 |
+
"description": "Search results",
|
1344 |
+
"content": {
|
1345 |
+
"application/json": {
|
1346 |
+
"schema": {
|
1347 |
+
"type": "array",
|
1348 |
+
"items": {
|
1349 |
+
"type": "object",
|
1350 |
+
"properties": {
|
1351 |
+
"full_name": {
|
1352 |
+
"type": "string"
|
1353 |
+
},
|
1354 |
+
"description": {
|
1355 |
+
"type": "string",
|
1356 |
+
"nullable": true
|
1357 |
+
},
|
1358 |
+
"html_url": {
|
1359 |
+
"type": "string"
|
1360 |
+
},
|
1361 |
+
"private": {
|
1362 |
+
"type": "boolean"
|
1363 |
+
},
|
1364 |
+
"fork": {
|
1365 |
+
"type": "boolean"
|
1366 |
+
},
|
1367 |
+
"updated_at": {
|
1368 |
+
"type": "string",
|
1369 |
+
"format": "date-time"
|
1370 |
+
}
|
1371 |
+
}
|
1372 |
+
}
|
1373 |
+
}
|
1374 |
+
}
|
1375 |
+
}
|
1376 |
+
},
|
1377 |
+
"401": {
|
1378 |
+
"description": "Authentication error",
|
1379 |
+
"content": {
|
1380 |
+
"application/json": {
|
1381 |
+
"schema": {
|
1382 |
+
"type": "string"
|
1383 |
+
}
|
1384 |
+
}
|
1385 |
+
}
|
1386 |
+
},
|
1387 |
+
"500": {
|
1388 |
+
"description": "Unknown error",
|
1389 |
+
"content": {
|
1390 |
+
"application/json": {
|
1391 |
+
"schema": {
|
1392 |
+
"type": "string"
|
1393 |
+
}
|
1394 |
+
}
|
1395 |
+
}
|
1396 |
+
}
|
1397 |
+
}
|
1398 |
+
}
|
1399 |
+
},
|
1400 |
+
"/api/user/suggested-tasks": {
|
1401 |
+
"get": {
|
1402 |
+
"summary": "Get suggested tasks",
|
1403 |
+
"description": "Get suggested tasks for the authenticated user across their most recently pushed repositories",
|
1404 |
+
"operationId": "getSuggestedTasks",
|
1405 |
+
"responses": {
|
1406 |
+
"200": {
|
1407 |
+
"description": "Suggested tasks",
|
1408 |
+
"content": {
|
1409 |
+
"application/json": {
|
1410 |
+
"schema": {
|
1411 |
+
"type": "array",
|
1412 |
+
"items": {
|
1413 |
+
"type": "object",
|
1414 |
+
"properties": {
|
1415 |
+
"title": {
|
1416 |
+
"type": "string"
|
1417 |
+
},
|
1418 |
+
"url": {
|
1419 |
+
"type": "string"
|
1420 |
+
},
|
1421 |
+
"repository": {
|
1422 |
+
"type": "string"
|
1423 |
+
},
|
1424 |
+
"type": {
|
1425 |
+
"type": "string"
|
1426 |
+
},
|
1427 |
+
"created_at": {
|
1428 |
+
"type": "string",
|
1429 |
+
"format": "date-time"
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
}
|
1433 |
+
}
|
1434 |
+
}
|
1435 |
+
}
|
1436 |
+
},
|
1437 |
+
"401": {
|
1438 |
+
"description": "Authentication error",
|
1439 |
+
"content": {
|
1440 |
+
"application/json": {
|
1441 |
+
"schema": {
|
1442 |
+
"type": "string"
|
1443 |
+
}
|
1444 |
+
}
|
1445 |
+
}
|
1446 |
+
},
|
1447 |
+
"500": {
|
1448 |
+
"description": "Unknown error",
|
1449 |
+
"content": {
|
1450 |
+
"application/json": {
|
1451 |
+
"schema": {
|
1452 |
+
"type": "string"
|
1453 |
+
}
|
1454 |
+
}
|
1455 |
+
}
|
1456 |
+
}
|
1457 |
+
}
|
1458 |
+
}
|
1459 |
+
},
|
1460 |
+
"/api/settings": {
|
1461 |
+
"get": {
|
1462 |
+
"summary": "Get settings",
|
1463 |
+
"description": "Get user settings",
|
1464 |
+
"operationId": "loadSettings",
|
1465 |
+
"responses": {
|
1466 |
+
"200": {
|
1467 |
+
"description": "User settings",
|
1468 |
+
"content": {
|
1469 |
+
"application/json": {
|
1470 |
+
"schema": {
|
1471 |
+
"type": "object",
|
1472 |
+
"properties": {
|
1473 |
+
"language": {
|
1474 |
+
"type": "string"
|
1475 |
+
},
|
1476 |
+
"agent": {
|
1477 |
+
"type": "string"
|
1478 |
+
},
|
1479 |
+
"security_analyzer": {
|
1480 |
+
"type": "string"
|
1481 |
+
},
|
1482 |
+
"confirmation_mode": {
|
1483 |
+
"type": "boolean"
|
1484 |
+
},
|
1485 |
+
"llm_model": {
|
1486 |
+
"type": "string"
|
1487 |
+
},
|
1488 |
+
"llm_api_key_set": {
|
1489 |
+
"type": "boolean"
|
1490 |
+
},
|
1491 |
+
"llm_base_url": {
|
1492 |
+
"type": "string",
|
1493 |
+
"nullable": true
|
1494 |
+
},
|
1495 |
+
"remote_runtime_resource_factor": {
|
1496 |
+
"type": "number"
|
1497 |
+
},
|
1498 |
+
"enable_default_condenser": {
|
1499 |
+
"type": "boolean"
|
1500 |
+
},
|
1501 |
+
"enable_sound_notifications": {
|
1502 |
+
"type": "boolean"
|
1503 |
+
},
|
1504 |
+
"user_consents_to_analytics": {
|
1505 |
+
"type": "boolean"
|
1506 |
+
},
|
1507 |
+
"provider_tokens_set": {
|
1508 |
+
"type": "object",
|
1509 |
+
"additionalProperties": {
|
1510 |
+
"type": "boolean"
|
1511 |
+
}
|
1512 |
+
}
|
1513 |
+
}
|
1514 |
+
}
|
1515 |
+
}
|
1516 |
+
}
|
1517 |
+
},
|
1518 |
+
"401": {
|
1519 |
+
"description": "Invalid token",
|
1520 |
+
"content": {
|
1521 |
+
"application/json": {
|
1522 |
+
"schema": {
|
1523 |
+
"type": "object",
|
1524 |
+
"properties": {
|
1525 |
+
"error": {
|
1526 |
+
"type": "string"
|
1527 |
+
}
|
1528 |
+
}
|
1529 |
+
}
|
1530 |
+
}
|
1531 |
+
}
|
1532 |
+
},
|
1533 |
+
"404": {
|
1534 |
+
"description": "Settings not found",
|
1535 |
+
"content": {
|
1536 |
+
"application/json": {
|
1537 |
+
"schema": {
|
1538 |
+
"type": "object",
|
1539 |
+
"properties": {
|
1540 |
+
"error": {
|
1541 |
+
"type": "string"
|
1542 |
+
}
|
1543 |
+
}
|
1544 |
+
}
|
1545 |
+
}
|
1546 |
+
}
|
1547 |
+
}
|
1548 |
+
}
|
1549 |
+
},
|
1550 |
+
"post": {
|
1551 |
+
"summary": "Store settings",
|
1552 |
+
"description": "Store user settings",
|
1553 |
+
"operationId": "storeSettings",
|
1554 |
+
"requestBody": {
|
1555 |
+
"required": true,
|
1556 |
+
"content": {
|
1557 |
+
"application/json": {
|
1558 |
+
"schema": {
|
1559 |
+
"type": "object",
|
1560 |
+
"properties": {
|
1561 |
+
"language": {
|
1562 |
+
"type": "string"
|
1563 |
+
},
|
1564 |
+
"agent": {
|
1565 |
+
"type": "string"
|
1566 |
+
},
|
1567 |
+
"security_analyzer": {
|
1568 |
+
"type": "string"
|
1569 |
+
},
|
1570 |
+
"confirmation_mode": {
|
1571 |
+
"type": "boolean"
|
1572 |
+
},
|
1573 |
+
"llm_model": {
|
1574 |
+
"type": "string"
|
1575 |
+
},
|
1576 |
+
"llm_api_key": {
|
1577 |
+
"type": "string"
|
1578 |
+
},
|
1579 |
+
"llm_base_url": {
|
1580 |
+
"type": "string",
|
1581 |
+
"nullable": true
|
1582 |
+
},
|
1583 |
+
"remote_runtime_resource_factor": {
|
1584 |
+
"type": "number"
|
1585 |
+
},
|
1586 |
+
"enable_default_condenser": {
|
1587 |
+
"type": "boolean"
|
1588 |
+
},
|
1589 |
+
"enable_sound_notifications": {
|
1590 |
+
"type": "boolean"
|
1591 |
+
},
|
1592 |
+
"user_consents_to_analytics": {
|
1593 |
+
"type": "boolean"
|
1594 |
+
},
|
1595 |
+
"provider_tokens": {
|
1596 |
+
"type": "object",
|
1597 |
+
"additionalProperties": {
|
1598 |
+
"type": "string"
|
1599 |
+
}
|
1600 |
+
}
|
1601 |
+
}
|
1602 |
+
}
|
1603 |
+
}
|
1604 |
+
}
|
1605 |
+
},
|
1606 |
+
"responses": {
|
1607 |
+
"200": {
|
1608 |
+
"description": "Settings stored successfully",
|
1609 |
+
"content": {
|
1610 |
+
"application/json": {
|
1611 |
+
"schema": {
|
1612 |
+
"type": "object",
|
1613 |
+
"properties": {
|
1614 |
+
"message": {
|
1615 |
+
"type": "string"
|
1616 |
+
}
|
1617 |
+
}
|
1618 |
+
}
|
1619 |
+
}
|
1620 |
+
}
|
1621 |
+
},
|
1622 |
+
"401": {
|
1623 |
+
"description": "Invalid token",
|
1624 |
+
"content": {
|
1625 |
+
"application/json": {
|
1626 |
+
"schema": {
|
1627 |
+
"type": "object",
|
1628 |
+
"properties": {
|
1629 |
+
"error": {
|
1630 |
+
"type": "string"
|
1631 |
+
}
|
1632 |
+
}
|
1633 |
+
}
|
1634 |
+
}
|
1635 |
+
}
|
1636 |
+
},
|
1637 |
+
"500": {
|
1638 |
+
"description": "Error storing settings",
|
1639 |
+
"content": {
|
1640 |
+
"application/json": {
|
1641 |
+
"schema": {
|
1642 |
+
"type": "object",
|
1643 |
+
"properties": {
|
1644 |
+
"error": {
|
1645 |
+
"type": "string"
|
1646 |
+
}
|
1647 |
+
}
|
1648 |
+
}
|
1649 |
+
}
|
1650 |
+
}
|
1651 |
+
}
|
1652 |
+
}
|
1653 |
+
}
|
1654 |
+
},
|
1655 |
+
"/api/reset-settings": {
|
1656 |
+
"post": {
|
1657 |
+
"summary": "Reset settings (Deprecated)",
|
1658 |
+
"description": "This endpoint is deprecated and will return a 410 Gone error. Reset functionality has been removed.",
|
1659 |
+
"operationId": "resetSettings",
|
1660 |
+
"deprecated": true,
|
1661 |
+
"responses": {
|
1662 |
+
"410": {
|
1663 |
+
"description": "Feature removed",
|
1664 |
+
"content": {
|
1665 |
+
"application/json": {
|
1666 |
+
"schema": {
|
1667 |
+
"type": "object",
|
1668 |
+
"properties": {
|
1669 |
+
"error": {
|
1670 |
+
"type": "string",
|
1671 |
+
"example": "Reset settings functionality has been removed."
|
1672 |
+
}
|
1673 |
+
}
|
1674 |
+
}
|
1675 |
+
}
|
1676 |
+
}
|
1677 |
+
}
|
1678 |
+
}
|
1679 |
+
}
|
1680 |
+
},
|
1681 |
+
"/api/unset-settings-tokens": {
|
1682 |
+
"post": {
|
1683 |
+
"summary": "Unset settings tokens",
|
1684 |
+
"description": "Unset provider tokens in settings",
|
1685 |
+
"operationId": "unsetSettingsTokens",
|
1686 |
+
"responses": {
|
1687 |
+
"200": {
|
1688 |
+
"description": "Tokens unset successfully",
|
1689 |
+
"content": {
|
1690 |
+
"application/json": {
|
1691 |
+
"schema": {
|
1692 |
+
"type": "object",
|
1693 |
+
"properties": {
|
1694 |
+
"message": {
|
1695 |
+
"type": "string"
|
1696 |
+
}
|
1697 |
+
}
|
1698 |
+
}
|
1699 |
+
}
|
1700 |
+
}
|
1701 |
+
},
|
1702 |
+
"500": {
|
1703 |
+
"description": "Error unsetting tokens",
|
1704 |
+
"content": {
|
1705 |
+
"application/json": {
|
1706 |
+
"schema": {
|
1707 |
+
"type": "object",
|
1708 |
+
"properties": {
|
1709 |
+
"error": {
|
1710 |
+
"type": "string"
|
1711 |
+
}
|
1712 |
+
}
|
1713 |
+
}
|
1714 |
+
}
|
1715 |
+
}
|
1716 |
+
}
|
1717 |
+
}
|
1718 |
+
}
|
1719 |
+
},
|
1720 |
+
"/api/options/models": {
|
1721 |
+
"get": {
|
1722 |
+
"summary": "Get models",
|
1723 |
+
"description": "Get all models supported by LiteLLM",
|
1724 |
+
"operationId": "getLitellmModels",
|
1725 |
+
"responses": {
|
1726 |
+
"200": {
|
1727 |
+
"description": "List of models",
|
1728 |
+
"content": {
|
1729 |
+
"application/json": {
|
1730 |
+
"schema": {
|
1731 |
+
"type": "array",
|
1732 |
+
"items": {
|
1733 |
+
"type": "string"
|
1734 |
+
}
|
1735 |
+
}
|
1736 |
+
}
|
1737 |
+
}
|
1738 |
+
}
|
1739 |
+
}
|
1740 |
+
}
|
1741 |
+
},
|
1742 |
+
"/api/options/agents": {
|
1743 |
+
"get": {
|
1744 |
+
"summary": "Get agents",
|
1745 |
+
"description": "Get all agents supported by OpenHands",
|
1746 |
+
"operationId": "getAgents",
|
1747 |
+
"responses": {
|
1748 |
+
"200": {
|
1749 |
+
"description": "List of agents",
|
1750 |
+
"content": {
|
1751 |
+
"application/json": {
|
1752 |
+
"schema": {
|
1753 |
+
"type": "array",
|
1754 |
+
"items": {
|
1755 |
+
"type": "string"
|
1756 |
+
}
|
1757 |
+
}
|
1758 |
+
}
|
1759 |
+
}
|
1760 |
+
}
|
1761 |
+
}
|
1762 |
+
}
|
1763 |
+
},
|
1764 |
+
"/api/options/security-analyzers": {
|
1765 |
+
"get": {
|
1766 |
+
"summary": "Get security analyzers",
|
1767 |
+
"description": "Get all supported security analyzers",
|
1768 |
+
"operationId": "getSecurityAnalyzers",
|
1769 |
+
"responses": {
|
1770 |
+
"200": {
|
1771 |
+
"description": "List of security analyzers",
|
1772 |
+
"content": {
|
1773 |
+
"application/json": {
|
1774 |
+
"schema": {
|
1775 |
+
"type": "array",
|
1776 |
+
"items": {
|
1777 |
+
"type": "string"
|
1778 |
+
}
|
1779 |
+
}
|
1780 |
+
}
|
1781 |
+
}
|
1782 |
+
}
|
1783 |
+
}
|
1784 |
+
}
|
1785 |
+
},
|
1786 |
+
"/api/options/config": {
|
1787 |
+
"get": {
|
1788 |
+
"summary": "Get config",
|
1789 |
+
"description": "Get current server configuration",
|
1790 |
+
"operationId": "getConfig",
|
1791 |
+
"responses": {
|
1792 |
+
"200": {
|
1793 |
+
"description": "Server configuration",
|
1794 |
+
"content": {
|
1795 |
+
"application/json": {
|
1796 |
+
"schema": {
|
1797 |
+
"type": "object"
|
1798 |
+
}
|
1799 |
+
}
|
1800 |
+
}
|
1801 |
+
}
|
1802 |
+
}
|
1803 |
+
}
|
1804 |
+
}
|
1805 |
+
},
|
1806 |
+
"components": {
|
1807 |
+
"schemas": {
|
1808 |
+
"Repository": {
|
1809 |
+
"type": "object",
|
1810 |
+
"properties": {
|
1811 |
+
"full_name": {
|
1812 |
+
"type": "string"
|
1813 |
+
},
|
1814 |
+
"description": {
|
1815 |
+
"type": "string",
|
1816 |
+
"nullable": true
|
1817 |
+
},
|
1818 |
+
"html_url": {
|
1819 |
+
"type": "string"
|
1820 |
+
},
|
1821 |
+
"private": {
|
1822 |
+
"type": "boolean"
|
1823 |
+
},
|
1824 |
+
"fork": {
|
1825 |
+
"type": "boolean"
|
1826 |
+
},
|
1827 |
+
"updated_at": {
|
1828 |
+
"type": "string",
|
1829 |
+
"format": "date-time"
|
1830 |
+
}
|
1831 |
+
}
|
1832 |
+
},
|
1833 |
+
"User": {
|
1834 |
+
"type": "object",
|
1835 |
+
"properties": {
|
1836 |
+
"login": {
|
1837 |
+
"type": "string"
|
1838 |
+
},
|
1839 |
+
"name": {
|
1840 |
+
"type": "string",
|
1841 |
+
"nullable": true
|
1842 |
+
},
|
1843 |
+
"email": {
|
1844 |
+
"type": "string",
|
1845 |
+
"nullable": true
|
1846 |
+
},
|
1847 |
+
"avatar_url": {
|
1848 |
+
"type": "string",
|
1849 |
+
"nullable": true
|
1850 |
+
}
|
1851 |
+
}
|
1852 |
+
},
|
1853 |
+
"SuggestedTask": {
|
1854 |
+
"type": "object",
|
1855 |
+
"properties": {
|
1856 |
+
"title": {
|
1857 |
+
"type": "string"
|
1858 |
+
},
|
1859 |
+
"url": {
|
1860 |
+
"type": "string"
|
1861 |
+
},
|
1862 |
+
"repository": {
|
1863 |
+
"type": "string"
|
1864 |
+
},
|
1865 |
+
"type": {
|
1866 |
+
"type": "string"
|
1867 |
+
},
|
1868 |
+
"created_at": {
|
1869 |
+
"type": "string",
|
1870 |
+
"format": "date-time"
|
1871 |
+
}
|
1872 |
+
}
|
1873 |
+
},
|
1874 |
+
"ConversationInfo": {
|
1875 |
+
"type": "object",
|
1876 |
+
"properties": {
|
1877 |
+
"conversation_id": {
|
1878 |
+
"type": "string"
|
1879 |
+
},
|
1880 |
+
"title": {
|
1881 |
+
"type": "string"
|
1882 |
+
},
|
1883 |
+
"last_updated_at": {
|
1884 |
+
"type": "string",
|
1885 |
+
"format": "date-time"
|
1886 |
+
},
|
1887 |
+
"created_at": {
|
1888 |
+
"type": "string",
|
1889 |
+
"format": "date-time"
|
1890 |
+
},
|
1891 |
+
"selected_repository": {
|
1892 |
+
"type": "string",
|
1893 |
+
"nullable": true
|
1894 |
+
},
|
1895 |
+
"status": {
|
1896 |
+
"type": "string",
|
1897 |
+
"enum": ["RUNNING", "STOPPED"]
|
1898 |
+
},
|
1899 |
+
"trigger": {
|
1900 |
+
"type": "string",
|
1901 |
+
"enum": ["GUI", "API"]
|
1902 |
+
}
|
1903 |
+
}
|
1904 |
+
},
|
1905 |
+
"ConversationInfoResultSet": {
|
1906 |
+
"type": "object",
|
1907 |
+
"properties": {
|
1908 |
+
"results": {
|
1909 |
+
"type": "array",
|
1910 |
+
"items": {
|
1911 |
+
"$ref": "#/components/schemas/ConversationInfo"
|
1912 |
+
}
|
1913 |
+
},
|
1914 |
+
"next_page_id": {
|
1915 |
+
"type": "string",
|
1916 |
+
"nullable": true
|
1917 |
+
}
|
1918 |
+
}
|
1919 |
+
},
|
1920 |
+
"FeedbackDataModel": {
|
1921 |
+
"type": "object",
|
1922 |
+
"properties": {
|
1923 |
+
"email": {
|
1924 |
+
"type": "string",
|
1925 |
+
"format": "email"
|
1926 |
+
},
|
1927 |
+
"version": {
|
1928 |
+
"type": "string"
|
1929 |
+
},
|
1930 |
+
"permissions": {
|
1931 |
+
"type": "string",
|
1932 |
+
"default": "private"
|
1933 |
+
},
|
1934 |
+
"polarity": {
|
1935 |
+
"type": "string"
|
1936 |
+
},
|
1937 |
+
"feedback": {
|
1938 |
+
"type": "string"
|
1939 |
+
},
|
1940 |
+
"trajectory": {
|
1941 |
+
"type": "array",
|
1942 |
+
"items": {
|
1943 |
+
"type": "object"
|
1944 |
+
}
|
1945 |
+
}
|
1946 |
+
}
|
1947 |
+
},
|
1948 |
+
"Settings": {
|
1949 |
+
"type": "object",
|
1950 |
+
"properties": {
|
1951 |
+
"language": {
|
1952 |
+
"type": "string"
|
1953 |
+
},
|
1954 |
+
"agent": {
|
1955 |
+
"type": "string"
|
1956 |
+
},
|
1957 |
+
"security_analyzer": {
|
1958 |
+
"type": "string"
|
1959 |
+
},
|
1960 |
+
"confirmation_mode": {
|
1961 |
+
"type": "boolean"
|
1962 |
+
},
|
1963 |
+
"llm_model": {
|
1964 |
+
"type": "string"
|
1965 |
+
},
|
1966 |
+
"llm_api_key": {
|
1967 |
+
"type": "string"
|
1968 |
+
},
|
1969 |
+
"llm_base_url": {
|
1970 |
+
"type": "string",
|
1971 |
+
"nullable": true
|
1972 |
+
},
|
1973 |
+
"remote_runtime_resource_factor": {
|
1974 |
+
"type": "number"
|
1975 |
+
},
|
1976 |
+
"enable_default_condenser": {
|
1977 |
+
"type": "boolean"
|
1978 |
+
},
|
1979 |
+
"enable_sound_notifications": {
|
1980 |
+
"type": "boolean"
|
1981 |
+
},
|
1982 |
+
"user_consents_to_analytics": {
|
1983 |
+
"type": "boolean"
|
1984 |
+
}
|
1985 |
+
}
|
1986 |
+
},
|
1987 |
+
"GETSettingsModel": {
|
1988 |
+
"type": "object",
|
1989 |
+
"properties": {
|
1990 |
+
"language": {
|
1991 |
+
"type": "string"
|
1992 |
+
},
|
1993 |
+
"agent": {
|
1994 |
+
"type": "string"
|
1995 |
+
},
|
1996 |
+
"security_analyzer": {
|
1997 |
+
"type": "string"
|
1998 |
+
},
|
1999 |
+
"confirmation_mode": {
|
2000 |
+
"type": "boolean"
|
2001 |
+
},
|
2002 |
+
"llm_model": {
|
2003 |
+
"type": "string"
|
2004 |
+
},
|
2005 |
+
"llm_api_key_set": {
|
2006 |
+
"type": "boolean"
|
2007 |
+
},
|
2008 |
+
"llm_base_url": {
|
2009 |
+
"type": "string",
|
2010 |
+
"nullable": true
|
2011 |
+
},
|
2012 |
+
"remote_runtime_resource_factor": {
|
2013 |
+
"type": "number"
|
2014 |
+
},
|
2015 |
+
"enable_default_condenser": {
|
2016 |
+
"type": "boolean"
|
2017 |
+
},
|
2018 |
+
"enable_sound_notifications": {
|
2019 |
+
"type": "boolean"
|
2020 |
+
},
|
2021 |
+
"user_consents_to_analytics": {
|
2022 |
+
"type": "boolean"
|
2023 |
+
},
|
2024 |
+
"provider_tokens_set": {
|
2025 |
+
"type": "object",
|
2026 |
+
"additionalProperties": {
|
2027 |
+
"type": "boolean"
|
2028 |
+
}
|
2029 |
+
}
|
2030 |
+
}
|
2031 |
+
},
|
2032 |
+
"POSTSettingsModel": {
|
2033 |
+
"type": "object",
|
2034 |
+
"properties": {
|
2035 |
+
"language": {
|
2036 |
+
"type": "string"
|
2037 |
+
},
|
2038 |
+
"agent": {
|
2039 |
+
"type": "string"
|
2040 |
+
},
|
2041 |
+
"security_analyzer": {
|
2042 |
+
"type": "string"
|
2043 |
+
},
|
2044 |
+
"confirmation_mode": {
|
2045 |
+
"type": "boolean"
|
2046 |
+
},
|
2047 |
+
"llm_model": {
|
2048 |
+
"type": "string"
|
2049 |
+
},
|
2050 |
+
"llm_api_key": {
|
2051 |
+
"type": "string"
|
2052 |
+
},
|
2053 |
+
"llm_base_url": {
|
2054 |
+
"type": "string",
|
2055 |
+
"nullable": true
|
2056 |
+
},
|
2057 |
+
"remote_runtime_resource_factor": {
|
2058 |
+
"type": "number"
|
2059 |
+
},
|
2060 |
+
"enable_default_condenser": {
|
2061 |
+
"type": "boolean"
|
2062 |
+
},
|
2063 |
+
"enable_sound_notifications": {
|
2064 |
+
"type": "boolean"
|
2065 |
+
},
|
2066 |
+
"user_consents_to_analytics": {
|
2067 |
+
"type": "boolean"
|
2068 |
+
},
|
2069 |
+
"provider_tokens": {
|
2070 |
+
"type": "object",
|
2071 |
+
"additionalProperties": {
|
2072 |
+
"type": "string"
|
2073 |
+
}
|
2074 |
+
}
|
2075 |
+
}
|
2076 |
+
}
|
2077 |
+
},
|
2078 |
+
"securitySchemes": {
|
2079 |
+
"bearerAuth": {
|
2080 |
+
"type": "http",
|
2081 |
+
"scheme": "bearer",
|
2082 |
+
"bearerFormat": "JWT"
|
2083 |
+
}
|
2084 |
+
}
|
2085 |
+
},
|
2086 |
+
"security": [
|
2087 |
+
{
|
2088 |
+
"bearerAuth": []
|
2089 |
+
}
|
2090 |
+
]
|
2091 |
+
}
|
docs/static/img/backend_architecture.png
ADDED
![]() |
Git LFS Details
|
docs/static/img/backend_architecture.puml
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@startuml openhands
|
2 |
+
!pragma useIntermediatePackages false
|
3 |
+
|
4 |
+
class openhands.action.agent.AgentEchoAction {
|
5 |
+
content: str
|
6 |
+
runnable: bool
|
7 |
+
action: str
|
8 |
+
}
|
9 |
+
class openhands.action.agent.AgentFinishAction {
|
10 |
+
runnable: bool
|
11 |
+
action: str
|
12 |
+
}
|
13 |
+
class openhands.observation.AgentMessageObservation {
|
14 |
+
role: str
|
15 |
+
observation: str
|
16 |
+
}
|
17 |
+
class openhands.action.agent.AgentSummarizeAction {
|
18 |
+
summary: str
|
19 |
+
action: str
|
20 |
+
}
|
21 |
+
class openhands.action.agent.AgentThinkAction {
|
22 |
+
thought: str
|
23 |
+
runnable: bool
|
24 |
+
action: str
|
25 |
+
}
|
26 |
+
class openhands.action.base.ExecutableAction {
|
27 |
+
}
|
28 |
+
class openhands.action.base.NotExecutableAction {
|
29 |
+
}
|
30 |
+
class openhands.observation.Observation {
|
31 |
+
content: str
|
32 |
+
}
|
33 |
+
class openhands.action.base.Action {
|
34 |
+
}
|
35 |
+
class openhands.action.base.NullAction {
|
36 |
+
action: str
|
37 |
+
}
|
38 |
+
class openhands.action.bash.CmdRunAction {
|
39 |
+
command: str
|
40 |
+
action: str
|
41 |
+
}
|
42 |
+
class openhands.action.browse.BrowseURLAction {
|
43 |
+
url: str
|
44 |
+
action: str
|
45 |
+
}
|
46 |
+
class openhands.observation.BrowserOutputObservation {
|
47 |
+
url: str
|
48 |
+
status_code: int
|
49 |
+
error: bool
|
50 |
+
observation: str
|
51 |
+
}
|
52 |
+
class openhands.action.fileop.FileReadAction {
|
53 |
+
path: str
|
54 |
+
action: str
|
55 |
+
}
|
56 |
+
class openhands.observation.FileReadObservation {
|
57 |
+
path: str
|
58 |
+
observation: str
|
59 |
+
}
|
60 |
+
class openhands.action.fileop.FileWriteAction {
|
61 |
+
path: str
|
62 |
+
contents: str
|
63 |
+
action: str
|
64 |
+
}
|
65 |
+
class openhands.observation.FileWriteObservation {
|
66 |
+
path: str
|
67 |
+
observation: str
|
68 |
+
}
|
69 |
+
class openhands.action.tasks.AddTaskAction {
|
70 |
+
parent: str
|
71 |
+
goal: str
|
72 |
+
subtasks: list
|
73 |
+
action: str
|
74 |
+
}
|
75 |
+
class openhands.action.tasks.ModifyTaskAction {
|
76 |
+
id: str
|
77 |
+
state: str
|
78 |
+
action: str
|
79 |
+
}
|
80 |
+
abstract class openhands.agent.Agent {
|
81 |
+
_registry: Dict[str, Type[Agent]] {static}
|
82 |
+
llm: LLM
|
83 |
+
_complete: None
|
84 |
+
}
|
85 |
+
class openhands.llm.llm.LLM {
|
86 |
+
model: None
|
87 |
+
api_key: None
|
88 |
+
base_url: None
|
89 |
+
_debug_dir: None
|
90 |
+
_debug_idx: None
|
91 |
+
_debug_id: None
|
92 |
+
_completion: None
|
93 |
+
}
|
94 |
+
class openhands.controller.agent_controller.AgentController {
|
95 |
+
agent: Agent
|
96 |
+
max_iterations: int
|
97 |
+
workdir: str
|
98 |
+
command_manager: CommandManager
|
99 |
+
state: State
|
100 |
+
plan: Plan
|
101 |
+
callbacks: List[Callable]
|
102 |
+
}
|
103 |
+
class openhands.observation.AgentErrorObservation {
|
104 |
+
observation: str
|
105 |
+
}
|
106 |
+
class openhands.controller.command_manager.CommandManager {
|
107 |
+
directory: None
|
108 |
+
shell: None
|
109 |
+
}
|
110 |
+
class openhands.observation.NullObservation {
|
111 |
+
observation: str
|
112 |
+
}
|
113 |
+
class openhands.plan.Plan {
|
114 |
+
main_goal: str {static}
|
115 |
+
task: Task {static}
|
116 |
+
main_goal: str
|
117 |
+
task: None
|
118 |
+
}
|
119 |
+
class openhands.state.State {
|
120 |
+
plan: Plan
|
121 |
+
iteration: int
|
122 |
+
history: List[Tuple[Action, Observation]]
|
123 |
+
updated_info: List[Tuple[Action, Observation]]
|
124 |
+
}
|
125 |
+
class openhands.observation.CmdOutputObservation {
|
126 |
+
command: str
|
127 |
+
exit_code: int
|
128 |
+
observation: str
|
129 |
+
}
|
130 |
+
class openhands.sandbox.sandbox.DockerInteractive {
|
131 |
+
instance_id: None
|
132 |
+
instance_id: None
|
133 |
+
workspace_dir: None
|
134 |
+
workspace_dir: None
|
135 |
+
workspace_dir: None
|
136 |
+
timeout: int
|
137 |
+
base_container_image: None
|
138 |
+
container_name: None
|
139 |
+
}
|
140 |
+
class openhands.observation.UserMessageObservation {
|
141 |
+
role: str
|
142 |
+
observation: str
|
143 |
+
}
|
144 |
+
class openhands.plan.Task {
|
145 |
+
id: str {static}
|
146 |
+
goal: str {static}
|
147 |
+
parent: Task | None {static}
|
148 |
+
subtasks: List[Task] {static}
|
149 |
+
id: None
|
150 |
+
id: None
|
151 |
+
parent: None
|
152 |
+
goal: str
|
153 |
+
subtasks: None
|
154 |
+
}
|
155 |
+
|
156 |
+
class openhands.server.session.Session {
|
157 |
+
websocket: None
|
158 |
+
controller: Optional[AgentController]
|
159 |
+
agent: Optional[Agent]
|
160 |
+
agent_task: None
|
161 |
+
}
|
162 |
+
|
163 |
+
openhands.action.base.ExecutableAction <|-- openhands.action.agent.AgentEchoAction
|
164 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.agent.AgentFinishAction
|
165 |
+
openhands.observation.Observation <|-- openhands.observation.AgentMessageObservation
|
166 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.agent.AgentSummarizeAction
|
167 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.agent.AgentThinkAction
|
168 |
+
openhands.action.base.Action <|-- openhands.action.base.ExecutableAction
|
169 |
+
openhands.action.base.Action <|-- openhands.action.base.NotExecutableAction
|
170 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.base.NullAction
|
171 |
+
openhands.action.base.ExecutableAction <|-- openhands.action.bash.CmdRunAction
|
172 |
+
openhands.action.base.ExecutableAction <|-- openhands.action.browse.BrowseURLAction
|
173 |
+
openhands.observation.Observation <|-- openhands.observation.BrowserOutputObservation
|
174 |
+
openhands.action.base.ExecutableAction <|-- openhands.action.fileop.FileReadAction
|
175 |
+
openhands.observation.Observation <|-- openhands.observation.FileReadObservation
|
176 |
+
openhands.action.base.ExecutableAction <|-- openhands.action.fileop.FileWriteAction
|
177 |
+
openhands.observation.Observation <|-- openhands.observation.FileWriteObservation
|
178 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.tasks.AddTaskAction
|
179 |
+
openhands.action.base.NotExecutableAction <|-- openhands.action.tasks.ModifyTaskAction
|
180 |
+
openhands.agent.Agent *-- openhands.agent.Agent
|
181 |
+
openhands.agent.Agent *-- openhands.llm.llm.LLM
|
182 |
+
openhands.controller.agent_controller.AgentController *-- openhands.agent.Agent
|
183 |
+
openhands.observation.Observation <|-- openhands.observation.AgentErrorObservation
|
184 |
+
openhands.observation.Observation <|-- openhands.observation.NullObservation
|
185 |
+
openhands.plan.Plan *-- openhands.plan.Task
|
186 |
+
openhands.state.State *-- openhands.plan.Plan
|
187 |
+
openhands.state.State *-- openhands.observation.CmdOutputObservation
|
188 |
+
openhands.state.State *-- openhands.action.base.Action
|
189 |
+
openhands.state.State *-- openhands.observation.Observation
|
190 |
+
openhands.observation.Observation <|-- openhands.observation.CmdOutputObservation
|
191 |
+
openhands.observation.Observation <|-- openhands.observation.UserMessageObservation
|
192 |
+
openhands.plan.Task *-- openhands.plan.Task
|
193 |
+
openhands.server.session.Session *-- openhands.controller.agent_controller.AgentController
|
194 |
+
openhands.server.session.Session *-- openhands.agent.Agent
|
195 |
+
openhands.controller.agent_controller.AgentController -> openhands.state.State
|
196 |
+
openhands.controller.agent_controller.AgentController -> openhands.plan.Plan
|
197 |
+
openhands.controller.agent_controller.AgentController -> openhands.controller.command_manager.CommandManager
|
198 |
+
openhands.controller.command_manager.CommandManager -> openhands.sandbox.sandbox.DockerInteractive
|
199 |
+
|
200 |
+
footer Based on f3fda42; Generated by //py2puml//
|
201 |
+
@enduml
|
docs/static/img/backend_architecture.svg
ADDED
|
docs/static/img/connect-repo.png
ADDED
![]() |
docs/static/img/docs/api-key-generation.png
ADDED
![]() |
docs/static/img/logo-square.png
ADDED
![]() |
Git LFS Details
|
docs/static/img/logo.png
ADDED
![]() |
docs/static/img/oh-features.png
ADDED
![]() |
Git LFS Details
|
docs/static/img/results.png
ADDED
![]() |
Git LFS Details
|
docs/static/img/screenshot.png
ADDED
![]() |
Git LFS Details
|