Compare commits

...

290 Commits

Author SHA1 Message Date
மனோஜ்குமார் பழனிச்சாமி 971ad68431 Solved Hugging Face cache issue. (#2277) 2024-06-05 21:18:33 +05:30
dependabot[bot] 3bf0636a53 Bump litellm from 1.40.0 to 1.40.2 (#2282)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.40.0 to 1.40.2.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.40.0...v1.40.2)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-05 23:46:00 +08:00
dependabot[bot] 105b5b9103 Bump json-repair from 0.21.0 to 0.23.1 (#2278)
Bumps [json-repair](https://github.com/mangiucugna/json_repair) from 0.21.0 to 0.23.1.
- [Release notes](https://github.com/mangiucugna/json_repair/releases)
- [Commits](https://github.com/mangiucugna/json_repair/compare/0.21.0...0.23.1)

---
updated-dependencies:
- dependency-name: json-repair
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-05 23:45:42 +08:00
dependabot[bot] a4bccfc6aa Bump @types/node from 20.14.1 to 20.14.2 in /frontend (#2279)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.14.1 to 20.14.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-05 23:40:53 +08:00
dependabot[bot] 4e540da85e Bump prettier from 3.3.0 to 3.3.1 in /frontend (#2281)
Bumps [prettier](https://github.com/prettier/prettier) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.3.0...3.3.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-05 23:39:41 +08:00
RainRat 3b0e1361a4 fix typos (#2267)
* fix typos

no functional change

* fix typos

* fix typos

* fix integration test

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Leo <ifuryst@gmail.com>
Co-authored-by: yufansong <yufan@risingwave-labs.com>
2024-06-05 23:06:40 +08:00
மனோஜ்குமார் பழனிச்சாமி ae815b20d2 Improved logs (#2272) 2024-06-05 17:54:40 +05:30
Aaron Xia 69542c9999 fix: there maybe unexpected files in event file list, not like 1.json… (#2270)
* fix: there maybe unexpected files in event file list, not like 1.json, 2.json, but .DS_Store for macOS system.

* log

---------

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-06-05 17:56:39 +08:00
dependabot[bot] 95a9be2dc5 Bump @typescript-eslint/eslint-plugin from 7.11.0 to 7.12.0 in /frontend (#2260) 2024-06-05 08:10:05 +00:00
Boxuan Li 208b1461ca [AgentBench evaluation] set run_as_devin to true (#2269)
Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-05 07:53:33 +00:00
dependabot[bot] 1b25a37ad4 Bump @testing-library/react from 15.0.7 to 16.0.0 in /frontend (#2227)
* Bump @testing-library/react from 15.0.7 to 16.0.0 in /frontend

Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 15.0.7 to 16.0.0.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v15.0.7...v16.0.0)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* resolve error during test teardown

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
2024-06-05 07:51:58 +00:00
Ryan H. Tran 0584e428b2 [Mint evaluation] Fix bug in stopping when the agent reaches max steps or solution proposals (#2268)
* fix: bug in stopping when the agent reaches max steps or solution proposals

* remove --eval-num-workers

* update env.py
2024-06-05 06:47:07 +00:00
super-dainiu ebafb702e5 Add ML-Bench Evaluation with OpenDevin (#2015)
* add ml-bench w/o exec env

* fix typos (#1956)

no functional change

* Refactored Logs (#1939)

* [Feat] A competitive Web Browsing agent (#1856)

* initial attempt at a browsing only agent

* add browsing agent

* update

* implement agent

* update

* fix comments

* remove unnecessary things from memory extras

* update image processing

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* Update README.md SWE-bench score (#1959)

* Update README.md SWE-bench score

Our most recent results on swe-bench lite are 25%, so this updates the README accordingly.

* Update

* fix: llm is_local function logic error (#1961)

Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>

* doc: update documentation about poetry update (#1962)

* add doc

* Update Development.md

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* feat: add metrics related to cost for better observability (#1944)

* add metrics for total_cost

* make lint

* refact codeact

* change metrics into llm

* add costs list, add into state

* refactor log completion

* refactor and test others

* make lint

* Update opendevin/core/metrics.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/llm/llm.py

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* refactor

* add code

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* doc: add more cmd in unit test documentation (#1963)

* --- (#1975)

updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* --- (#1976)

updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Logging security (#1943)

* update .gitignore

* Rename the confusing 'INFO' style to 'DETAIL'

* override str and repr

* feat: api_key desensitize

* feat: add SensitiveDataFilter in file handler

* tweak regex, add tests

* more tweaks, include other attrs

* add env vars, those with equivalent config

* fix tests

* tests are invaluable

---------

Co-authored-by: Shimada666 <649940882@qq.com>

* --- (#1967)

updated-dependencies:
- dependency-name: react-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/react-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* --- (#1968)

updated-dependencies:
- dependency-name: "@reduxjs/toolkit"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* --- (#1969)

updated-dependencies:
- dependency-name: husky
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* --- (#1970)

updated-dependencies:
- dependency-name: tailwind-merge
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* --- (#1971)

updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* Refactor session management (#1810)

* refactor session mgmt

* defer file handling to runtime

* add todo

* refactor sessions a bit more

* remove messages logic from FE

* fix up socket handshake

* refactor frontend auth a bit

* first pass at redoing file explorer

* implement directory suffix

* fix up file tree

* close agent on websocket close

* remove session saving

* move file refresh

* remove getWorkspace

* plumb path/code differently

* fix build issues

* fix the tests

* fix npm build

* add session rehydration

* fix event serialization

* logspam

* fix user message rehydration

* add get_event fn

* agent state restoration

* change history tracking for codeact

* fix responsiveness of init

* fix lint

* lint

* delint

* fix prop

* update tests

* logspam

* lint

* fix test

* revert codeact

* change fileService to use API

* fix up session loading

* delint

* delint

* fix integration tests

* revert test

* fix up access to options endpoints

* fix initial files load

* delint

* fix file initialization

* fix mock server

* fixl int

* fix auth for html

* Update frontend/src/i18n/translation.json

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* refactor sessions and sockets

* avoid reinitializing the same session

* fix reconnect issue

* change up intro message

* more guards on reinit

* rename agent_session

* delint

* fix a bunch of tests

* delint

* fix last test

* remove code editor context

* fix build

* fix any

* fix dot notation

* Update frontend/src/services/api.ts

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* fix up error handling

* Update opendevin/server/session/agent.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/server/session/agent.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update frontend/src/services/session.ts

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* fix build errs

* fix else

* add closed state

* delint

* Update opendevin/server/session/session.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

---------

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

* fix #1960 (#1964)

* Add ruff for shared mutable defaults (B) (#1938)

* Add ruff for shared mutable defaults (B)

* Apply B006, B008 on current files, except fast API

* Update agenthub/SWE_agent/prompts.py

Co-authored-by: Graham Neubig <neubig@gmail.com>

* fix unintended behavior change

* this is correct, tell Ruff to leave it alone

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Refactor integration testing CI, add optional Mac tests, and mark a few agents as deprecated (#1888)

* Add MacOS to integration tests

* Switch back to python 3.11

* Install Docker for macos pipeline

* regenerate.sh: Use environmental variable for sandbox type

* Pack different agents' tests into a single check

* Fix CodeAct tests

* Reduce file match and extensive debug logs

* Add TEST_IN_CI mode that reports codecov

* Small fix: don't quit if reusing old responses failed

* Merge codecov results

* Fix typos

* Remove coverage merge step - codecov automatically does that

* Make mac integration tests as optional - too slow

* Fix codecov args

* Add comments in yaml

* Include sandbox type in codecov report name

* Fix codecov report merge

* Revert renaming of test_matrix_success

* Remove SWEAgent and PlannerAgent from tests

* Mark planner agent and SWE agent as deprecated

* CodeCov: Ignore planner and sweagent

* Revert "Remove SWEAgent and PlannerAgent from tests"

This reverts commit 040cb3bfb9.

* Remove all tests for SWE Agent

* Only keep basic tests for MonologueAgent and PlannerAgent

* Mark SWE Agent as deprecated, and ignore code coverage for it

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

* Fix Repeated Responses in Chat by Adding IPythonRunCellObservation (#1987)

Co-authored-by: jianghongwei <jianghongwei@58.com>
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>

* Save CI cycles for backend tests (#1985)

* Fix typo in prompt (#1992)

* Refactor monologue and SWE agent to use the messages in state history (#1863)

* Refactor monologue to use the messages in state history

* add messages, clean up

* fix monologue

* update integration tests

* move private method

* update SWE agent to use the history from State

* integration tests for SWE agent

* rename monologue to initial_thoughts, since that is what it is

* fix: catch session file not existed exception when init EventStream(maybe creating a new session with no session files stored). (#1994)

* add ml-bench in readme

* Bump boto3 from 1.34.110 to 1.34.111 (#2001)

Bumps [boto3](https://github.com/boto/boto3) from 1.34.110 to 1.34.111.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.110...1.34.111)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump docker from 7.0.0 to 7.1.0 (#2002)

Bumps [docker](https://github.com/docker/docker-py) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/docker-py/releases)
- [Commits](https://github.com/docker/docker-py/compare/7.0.0...7.1.0)

---
updated-dependencies:
- dependency-name: docker
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump litellm from 1.37.20 to 1.38.0 (#2005)

Bumps [litellm](https://github.com/BerriAI/litellm) from 1.37.20 to 1.38.0.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.37.20...v1.38.0)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix SWE-Bench evaluation due to setuptools version (#1995)

* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* Revert "correctly setup plugins for swebench eval"

This reverts commit 2bd1055673.

* bump version

* fix session state after resuming (#1999)

* fix state resuming

* fix session reconnection

* fix lint

* Implement `agentskills` for OpenDevin to helpfully improve edit AND including more useful tools/skills (#1941)

* add draft for skills

* Implement and test agentskills functions: open_file, goto_line, scroll_down, scroll_up, create_file, search_dir, search_file, find_file

* Remove new_sample.txt file

* add some work from opendevin w/ fixes

* Add unit tests for agentskills module

* fix some issues and updated tests

* add more tests for open

* tweak and handle goto_line

* add tests for some edge cases

* add tests for scrolling

* add tests for edit

* add tests for search_dir

* update tests to use pytest

* use pytest --forked to avoid file op unit tests to interfere with each other via global var

* update doc based on swe agent tool

* update and add tests for find_file and search_file

* move agent_skills to plugins

* add agentskills as plugin and docs

* add agentskill to ssh box and fix sandbox integration

* remove extra returns in doc

* add agentskills to initial tool for jupyter

* support re-init jupyter kernel (for agentskills) after restart

* fix print window's issue with indentation and add testcases

* add prompt for codeact with the newest edit primitives

* modify the way line number is presented (remove leading space)

* change prompt to the newest display format

* support tracking of costs via metrics

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* implement and add tests for py linting

* remove extra text arg for incompatible subprocess ver

* remove sample.txt

* update test_edits integration tests

* fix all integration

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/runtime/plugins/agent_skills/agentskills.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* Revert "correctly setup plugins for swebench eval"

This reverts commit 2bd1055673.

* bump version

* remove _AGENT_SKILLS_DOCS

* move flake8 to test dep

* update poetry.lock

* remove extra arg

* reduce max iter for eval

* update poetry

* fix integration tests

---------

Co-authored-by: OpenDevin <opendevin@opendevin.ai>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* build: Add poetry command to use Python 3.11 for environment setup (#1972)

* Bump @react-types/shared from 3.23.0 to 3.23.1 in /frontend (#2006)

Bumps [@react-types/shared](https://github.com/adobe/react-spectrum) from 3.23.0 to 3.23.1.
- [Release notes](https://github.com/adobe/react-spectrum/releases)
- [Commits](https://github.com/adobe/react-spectrum/compare/@react-types/shared@3.23.0...@react-types/shared@3.23.1)

---
updated-dependencies:
- dependency-name: "@react-types/shared"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump @types/react-syntax-highlighter in /frontend (#2007)

Bumps [@types/react-syntax-highlighter](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-syntax-highlighter) from 15.5.11 to 15.5.13.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-syntax-highlighter)

---
updated-dependencies:
- dependency-name: "@types/react-syntax-highlighter"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump @typescript-eslint/parser from 7.9.0 to 7.10.0 in /frontend (#2008)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.9.0 to 7.10.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.10.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump lint-staged from 15.2.2 to 15.2.4 in /frontend (#2009)

Bumps [lint-staged](https://github.com/okonet/lint-staged) from 15.2.2 to 15.2.4.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v15.2.2...v15.2.4)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update README.md

* Update README.md

* add run_infer.sh

* fix input output

* fix docker sandbox

* fix run

* update and clean run_infer.py

* add script to clean up dockers

* update repo uid

* add description

* new

* Update README.md

* use root for sandbox

* update readme

* update ml-bench conda env

* update readme

* update readme

* use try except

* modify raise exception

* add int

* update README

* longer time

* fix existing issues

* fix existing issue

* new docker image

* add metrics of cost

* add result parsing cost

* fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Ubuntu <ubuntu@ip-172-31-31-157.ec2.internal>
Co-authored-by: RainRat <rainrat78@yahoo.ca>
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
Co-authored-by: Frank Xu <frankxu2004@gmail.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Shimada666 <649940882@qq.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Rahul Anand <62982824+zeul22@users.noreply.github.com>
Co-authored-by: jiangleo <jiangleo@users.noreply.github.com>
Co-authored-by: jianghongwei <jianghongwei@58.com>
Co-authored-by: Jeremi Joslin <jeremi@newlogic.com>
Co-authored-by: Aaron Xia <zhhuaxia@gmail.com>
Co-authored-by: OpenDevin <opendevin@opendevin.ai>
Co-authored-by: DaxServer <7479937+DaxServer@users.noreply.github.com>
Co-authored-by: Robert <871607149@qq.com>
2024-06-05 01:56:39 +00:00
Leo 040d6bd806 fix: add an early exit check for agent answers in agent bench. (#2257)
Signed-off-by: ifuryst <ifuryst@gmail.com>
2024-06-04 18:45:07 -07:00
tobitege 5776474dcf Fix SWE-Bench README typos (#2250) 2024-06-05 01:18:02 +00:00
tobitege 44bbe5e208 Fix agentskills tests (#2242)
* Fix agentskills tests

* Improved test_agent_skill

---------

Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-04 21:33:32 +00:00
tobitege 0082640ac8 fix test_config to prevent leaks (#2245) 2024-06-04 21:32:46 +02:00
tobitege 7263705492 fix frontend tests; minor readme update (#2219)
* fix frontend tests; minor readme update

* Fix indent in ChatInput.test

* Fix linting errors, finally

* lint: minor fixes (per make lint)

* All tests passed!
2024-06-04 20:46:47 +03:00
dependabot[bot] 4de08a9c00 Bump @types/node from 20.14.0 to 20.14.1 in /frontend (#2258)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.14.0 to 20.14.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-04 16:09:17 +00:00
dependabot[bot] 7e3e740616 Bump jose from 5.3.0 to 5.4.0 in /frontend (#2259)
Bumps [jose](https://github.com/panva/jose) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v5.3.0...v5.4.0)

---
updated-dependencies:
- dependency-name: jose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 16:06:38 +00:00
மனோஜ்குமார் பழனிச்சாமி 2ffd54d258 fixed output logging (#2244)
Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-04 16:05:23 +00:00
dependabot[bot] 6dd6e6c087 Bump @typescript-eslint/parser from 7.11.0 to 7.12.0 in /frontend (#2261)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.11.0 to 7.12.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.12.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-04 15:59:35 +00:00
dependabot[bot] aec3e18836 Bump litellm from 1.39.5 to 1.40.0 (#2256)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.39.5 to 1.40.0.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.39.5...v1.40.0)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 15:36:15 +00:00
dependabot[bot] d85c548bf5 Bump opencv-python from 4.9.0.80 to 4.10.0.82 (#2255)
Bumps [opencv-python](https://github.com/opencv/opencv-python) from 4.9.0.80 to 4.10.0.82.
- [Release notes](https://github.com/opencv/opencv-python/releases)
- [Commits](https://github.com/opencv/opencv-python/commits)

---
updated-dependencies:
- dependency-name: opencv-python
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 15:08:05 +00:00
dependabot[bot] 0f60899ee0 Bump google-generativeai from 0.5.4 to 0.6.0 (#2254)
Bumps [google-generativeai](https://github.com/google/generative-ai-python) from 0.5.4 to 0.6.0.
- [Release notes](https://github.com/google/generative-ai-python/releases)
- [Changelog](https://github.com/google-gemini/generative-ai-python/blob/main/RELEASE.md)
- [Commits](https://github.com/google/generative-ai-python/compare/v0.5.4...v0.6.0)

---
updated-dependencies:
- dependency-name: google-generativeai
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 15:06:51 +00:00
மனோஜ்குமார் பழனிச்சாமி 4e479038f9 Bugfix by added config to disable plugin initialization for Persistent sandbox (#2179)
* refactored source bashrc logic

* added initialize_plugins config

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-06-04 10:59:30 -04:00
dependabot[bot] 11b66bd733 Bump boto3 from 1.34.117 to 1.34.118 (#2253)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.117 to 1.34.118.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.117...1.34.118)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 14:57:58 +00:00
dependabot[bot] 62c179be6c Bump pytest from 8.2.1 to 8.2.2 (#2252)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.2.1 to 8.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.2.1...8.2.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 14:55:09 +00:00
மனோஜ்குமார் பழனிச்சாமி 4afd85e591 Quick doc fix (#2243) 2024-06-04 07:00:44 +00:00
Leo 9ada36e30b fix: restore python linting. (#2228)
* fix: restore python linting.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* update: extend the Python lint check to evaluation.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update evaluation/logic_reasoning/instruction.txt

---------

Signed-off-by: ifuryst <ifuryst@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-06-04 06:36:19 +00:00
Xida Ren (Cedar) 1314a09ce9 One-step launch instructions (#2189)
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2024-06-03 23:28:50 -07:00
Yufan Song 2374374778 Fix python environment in review-pr dogfood action (#2237)
This doesn't completely fix the bug; it fixes the python environment, and there is more to do to fix the issue.
2024-06-03 20:31:38 -07:00
Graham Neubig 44665ee235 Add docs for sharing feedback (#2241) 2024-06-04 07:37:33 +05:30
Graham Neubig 74e25920da Transition to gcloud endpoint (#2240) 2024-06-04 01:20:04 +00:00
Leo 759f76fab5 Fix: Properly close Docker client in DockerExecBox to prevent resource leakage (#2224) 2024-06-04 09:05:41 +08:00
dependabot[bot] 87c679ff1a Bump ruff from 0.4.6 to 0.4.7 (#2233) 2024-06-03 22:09:08 +00:00
finaltrip 05b84df9cb chore: fix some comments (#2234)
Signed-off-by: finaltrip <finaltrip@qq.com>
2024-06-03 16:04:34 +00:00
Bibek Poudel 42671815a8 changed the welcome logo from 60vh to auto (#2235) 2024-06-03 15:50:58 +00:00
dependabot[bot] c0e8e11cdc Bump boto3 from 1.34.116 to 1.34.117 (#2232)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.116 to 1.34.117.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.116...1.34.117)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 23:47:27 +08:00
dependabot[bot] 673cde31ba Bump datasets from 2.19.1 to 2.19.2 (#2231)
Bumps [datasets](https://github.com/huggingface/datasets) from 2.19.1 to 2.19.2.
- [Release notes](https://github.com/huggingface/datasets/releases)
- [Commits](https://github.com/huggingface/datasets/compare/2.19.1...2.19.2)

---
updated-dependencies:
- dependency-name: datasets
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 23:47:10 +08:00
dependabot[bot] 5de0d5d041 Bump uvicorn from 0.30.0 to 0.30.1 (#2230)
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.30.0 to 0.30.1.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.30.0...0.30.1)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 23:46:45 +08:00
dependabot[bot] adaa9c7c92 Bump e2b from 0.17.0 to 0.17.1 (#2229)
Bumps [e2b](https://github.com/e2b-dev/e2b) from 0.17.0 to 0.17.1.
- [Release notes](https://github.com/e2b-dev/e2b/releases)
- [Commits](https://github.com/e2b-dev/e2b/compare/@e2b/python-sdk@0.17.0...@e2b/python-sdk@0.17.1)

---
updated-dependencies:
- dependency-name: e2b
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 23:46:06 +08:00
tobitege 4b76f98b26 fix: keep colon part in model name for OpenRouter (#2223) 2024-06-03 17:11:44 +02:00
dependabot[bot] 47c12902de Bump @types/node from 20.12.13 to 20.14.0 in /frontend (#2226)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.13 to 20.14.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Leo <ifuryst@gmail.com>
2024-06-03 15:05:11 +00:00
dependabot[bot] bffa61adb4 Bump prettier from 3.2.5 to 3.3.0 in /frontend (#2225)
Bumps [prettier](https://github.com/prettier/prettier) from 3.2.5 to 3.3.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.2.5...3.3.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 22:51:51 +08:00
Graham Neubig 4476c250c5 Add consent dialog (#2169)
* Add consent dialog for sharing conversation histories

* Update

* Update to nextui modals

* Update

* More fixes to modal

* Updates

* Revert most changes to ChatInterface

* Update form

* Cleanup

* Update consent dialog

* Lint

* Fix toast

* Fix to be a select

* prettier

* Update frontend/src/components/chat/ChatInterface.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update frontend/src/components/modals/feedback/FeedbackModal.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update frontend/src/components/modals/feedback/FeedbackModal.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update frontend/src/components/chat/ChatInterface.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Fix

---------

Co-authored-by: OpenDevin <opendevin@opendevin.ai>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-06-03 14:33:53 +00:00
Boxuan Li c9c5d71e5c logger.py: Fix resource leak (#2215) 2024-06-03 05:57:54 +00:00
மனோஜ்குமார் பழனிச்சாமி 783a3545b5 Named docker app container (#2202) 2024-06-03 05:49:10 +00:00
Boxuan Li 538d1d85a2 evaluation: Reset configs in finally block (#2214) 2024-06-03 09:52:12 +08:00
Boxuan Li 1adbec6757 ssh_box: Fix Docker descriptor leak (#2212) 2024-06-03 01:22:30 +00:00
Boxuan Li 6fd8e8d5b8 Fix file descriptor leaks in agentskills (#2209) 2024-06-03 09:11:10 +08:00
tobitege 908c253897 German translations updated (#2208) 2024-06-02 16:49:40 -07:00
Boxuan Li 399e6fb1d1 ssh_box: Close containers before throwing exception (#2206) 2024-06-02 20:13:44 +00:00
tobitege 64f7749b63 Windows docs extended; some markdown lint fixes (#2205) 2024-06-02 14:59:54 +00:00
Graham Neubig efd689293e Bump docs to 0.6 (#2193)
* Bump docs to 0.6

* Update README.md
2024-06-02 06:34:40 -04:00
Ryan H. Tran 22e8fb39b1 add cost metrics to evaluation outputs for all benchmarks (#2199) 2024-06-02 08:28:00 +00:00
Yizhe Zhang 8d79c3edbc modify the exiting logic and reward calculation, delete unused function (#2198) 2024-06-02 06:38:09 +00:00
tobitege b0478d2880 fix: Fix husky install deprecated message (since v9 of husky) (#2190) (#2191)
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
2024-06-02 02:46:32 +00:00
RainRat ed6dcc8381 fix typos (#2187)
* fix typos

no functional change

* fix typos
2024-06-01 20:40:30 +00:00
Leo 2c231c57c9 Add supported benchmarks to evaluation README (AgentBench, BIRD, LogicReasoning) (#2183)
Signed-off-by: ifuryst <ifuryst@gmail.com>
2024-06-01 11:33:01 -04:00
மனோஜ்குமார் பழனிச்சாமி 4ece6fb3cc Auto started persistent container (#2151) 2024-06-01 14:46:41 +00:00
மனோஜ்குமார் பழனிச்சாமி f9c7c3a520 Refactored logging (#2159) 2024-06-01 14:31:35 +00:00
மனோஜ்குமார் பழனிச்சாமி aee3d506e6 Restricted persistent sandbox to opendevin user only (#2177) 2024-06-01 14:18:03 +00:00
Graham Neubig 3b8a649b3d Update slack invite link to make it valid (#2182)
* Update README.md

* Update CustomFooter.tsx

* Update about.md

* Update faq.tsx

* Update intro.mdx
2024-06-01 21:55:27 +08:00
Binyuan Hui 46dcf4bb3e Support BIRD benchmark (#2117)
* update: change timeout from 10 to 30

* update: readme for bird evaluation

* Update evaluation/bird/run_infer.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

* Update evaluation/bird/README.md

Co-authored-by: Shimada666 <649940882@qq.com>

* Update evaluation/bird/README.md

Co-authored-by: Shimada666 <649940882@qq.com>

* Update evaluation/bird/run_infer.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Shimada666 <649940882@qq.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-06-01 11:34:36 +00:00
Leo 78e003caf6 Fix: Avoid bash backtick eval in runtime commands. (#2180)
Signed-off-by: ifuryst <ifuryst@gmail.com>
2024-06-01 19:19:15 +08:00
Leo be251b11de Add AgentBench. (#2012)
* Add AgentBench.

* Load the datasets from HF.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Add helper functions.

* Add mock executor.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Add retriv agent answer cmd.

* Adjust the dataset.
* Refine test results.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Consolidate all AgentBench datasets and scripts into a single CSV dataset.

* Refactor dataset source.
* Update helper functions.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Fix the CRLF problem.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Separate the instance's workspace.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Add cleanup logic and error handling for sandbox closure.

* Normalized dataset

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update README.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update the prompt to capture the answer.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Refactor script execution paths to use absolute container workspace path.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update AgentBench README.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Delete useless functions.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update evaluation/agent_bench/README.md

* Add script to summarize test results from JSONL file in AgentBench

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Delete useless script and codes.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Update evaluation/agent_bench/scripts/summarise_results.py

---------

Signed-off-by: ifuryst <ifuryst@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-06-01 07:58:14 +00:00
மனோஜ்குமார் பழனிச்சாமி 04d7354501 Detailed logs for ssh_box (#2173) 2024-06-01 11:40:22 +05:30
Boxuan Li 06e45afc75 Fix ssh box hung issue (#2172)
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
2024-06-01 05:31:32 +00:00
மனோஜ்குமார் பழனிச்சாமி 3a4dc5c68c Initialized plugins only once for persistent sandboxes (#2162) 2024-06-01 10:46:09 +05:30
Boxuan Li feaae0b7ac Fix persist_sandbox in Makefile (#2171) 2024-06-01 12:50:31 +08:00
Rahul Anand 6e76f9a02f Fix: Codebase font fixed, and other fixes for #2138 PR (#2154)
* fix #2123

* Docs enhancement

* Update docs/src/components/CustomFooter.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update docs/src/components/CustomFooter.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update docs/src/pages/faq.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* update

* fix for #2138 pr

* Update docs/src/components/CustomFooter.tsx

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update docs/src/components/HomepageHeader/HomepageHeader.tsx

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update docs/src/components/Welcome/Welcome.tsx

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update docs/src/css/custom.css

Co-authored-by: Graham Neubig <neubig@gmail.com>

---------

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-06-01 02:22:44 +00:00
மனோஜ்குமார் பழனிச்சாமி bf24a0b5c0 Fixed makefile (#2168) 2024-06-01 03:35:43 +05:30
Aaron Xia 42c6b506b5 Lazy launching BrowseEnv / making BrowseEnv optional (#2155)
* feat: lazy launching browser; browser optional for diffrent agents.

* style: lint

* fix: integration test fail due to browser not started.

* fix: run by cli and integration test failed.

* fix: lint

* fix: lint

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-31 16:40:42 -04:00
மனோஜ்குமார் பழனிச்சாமி 8413f147c9 Added logs (#2153)
* Logged about config file

* Logged Browser env

* Update opendevin/core/config.py

Co-authored-by: Aleksandar <isavitaisa@gmail.com>

* Update opendevin/core/config.py

Co-authored-by: Aleksandar <isavitaisa@gmail.com>

---------

Co-authored-by: Aleksandar <isavitaisa@gmail.com>
2024-05-31 16:04:36 -04:00
Ryan H. Tran 01296ff79d Add remaining subsets for MINT benchmark (#2142)
* add MMLU subset

* add theoremqa subset

* remove redundant packages from requirements.txt, adjust prompts, handle gpt3.5 propose a wrong answer after a correct answer

* add MBPP subset

* add humaneval subset

* update README

* exit actively after the agent finishes the task
2024-05-31 20:04:13 +00:00
மனோஜ்குமார் பழனிச்சாமி f3f5768b4f Install chromium only once (#2100)
* install chromium only once

* Update Makefile

* Update Makefile
2024-05-31 15:39:10 -04:00
dependabot[bot] 9a441ea8f7 Bump boto3 from 1.34.115 to 1.34.116 (#2164)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.115 to 1.34.116.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.115...1.34.116)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-31 15:13:33 -04:00
Graham Neubig 6596d5c799 Fix: Feedback should be sent through the backend to avoid CORS issues (#2046)
* Fix: Feedback should be sent through the backend to avoid CORS issues

* Update

* Fix merge error

* Revert unnecessary change

* Lint

* Moved to services

* Fixed bugs

---------

Co-authored-by: OpenDevin <opendevin@opendevin.ai>
2024-05-31 15:00:09 -04:00
dependabot[bot] 6aec3d789e Bump litellm from 1.39.3 to 1.39.5 (#2163)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.39.3 to 1.39.5.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.39.3...v1.39.5)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-31 19:36:04 +02:00
Graham Neubig 7a2122ebc2 Default to gpt-4o (#2158)
* Default to gpt-4o

* Fix default
2024-05-31 14:44:07 +00:00
dependabot[bot] a7b19a0048 Bump @nextui-org/react from 2.4.0 to 2.4.1 in /frontend (#2161)
Bumps [@nextui-org/react](https://github.com/nextui-org/nextui/tree/HEAD/packages/core/react) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/nextui-org/nextui/releases)
- [Changelog](https://github.com/nextui-org/nextui/blob/canary/packages/core/react/CHANGELOG.md)
- [Commits](https://github.com/nextui-org/nextui/commits/@nextui-org/react@2.4.1/packages/core/react)

---
updated-dependencies:
- dependency-name: "@nextui-org/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-31 14:32:21 +00:00
dependabot[bot] e6c8e1c9d2 Bump framer-motion from 11.2.9 to 11.2.10 in /frontend (#2160)
Bumps [framer-motion](https://github.com/framer/motion) from 11.2.9 to 11.2.10.
- [Changelog](https://github.com/framer/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/framer/motion/compare/v11.2.9...v11.2.10)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-31 14:30:14 +00:00
Boxuan Li 4d14b44a9a SWE-bench: Add summarise utility script to view passed/failed task IDs (#2137)
* SWE-bench: Add summarise utility script to view passed/failed task IDs

* Fix typos

* Move file

* Prettify

* Use merged jsonl file
2024-05-31 12:32:17 +08:00
Boxuan Li f188abd7a3 Delete evaluation outputs files (#2152)
* Delete evaluation outputs files

* Fix README
2024-05-31 03:12:27 +00:00
மனோஜ்குமார் பழனிச்சாமி 961c96a2a1 Added ssh_password to config setup (#2139)
Co-authored-by: Aleksandar <isavitaisa@gmail.com>
2024-05-31 07:26:16 +05:30
dependabot[bot] f4bc52461a Bump openai from 1.30.4 to 1.30.5 (#2144)
Bumps [openai](https://github.com/openai/openai-python) from 1.30.4 to 1.30.5.
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v1.30.4...v1.30.5)

---
updated-dependencies:
- dependency-name: openai
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 23:29:38 +08:00
dependabot[bot] cd6f863a49 Bump litellm from 1.39.2 to 1.39.3 (#2145)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.39.2 to 1.39.3.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.39.2...v1.39.3)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 23:29:11 +08:00
dependabot[bot] 486c5d983f Bump json-repair from 0.20.1 to 0.21.0 (#2146)
Bumps [json-repair](https://github.com/mangiucugna/json_repair) from 0.20.1 to 0.21.0.
- [Release notes](https://github.com/mangiucugna/json_repair/releases)
- [Commits](https://github.com/mangiucugna/json_repair/compare/0.20.1...0.21.0)

---
updated-dependencies:
- dependency-name: json-repair
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 23:28:55 +08:00
dependabot[bot] 33d9882621 Bump @types/node from 18.19.30 to 20.12.13 in /frontend (#2147)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.19.30 to 20.12.13.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 23:28:31 +08:00
dependabot[bot] 2fcaa2328e Bump boto3 from 1.34.113 to 1.34.115 (#2143)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.113 to 1.34.115.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.113...1.34.115)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 23:24:59 +08:00
Rahul Anand a0373900be Docs enhancement (#2138)
* fix #2123

* Docs enhancement

* Update docs/src/components/CustomFooter.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update docs/src/components/CustomFooter.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

* Update docs/src/pages/faq.tsx

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>

---------

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-30 17:05:09 +03:00
Ren Ma a9823491e6 Support Logic Reasoning Benchmark (#1973) 2024-05-30 16:35:15 +08:00
Xingyao Wang 01ef90205d Add CodeActSWEAgent to remove browsing & github + improvements on agentskills (#2105)
* update swe_bench prompt;
use minimal prompt for codeact;

* upgrade agentskills and update testcases

* update infer prompt

* fix cwd

* add icl for swebench

* also log in_context_example to run infer

* remove extra print

* change prompt to abs path

* update error message to include current file info

* change cwd for jupyter if needed

* update edit error message

* update prompt

* improve git get patch

* update hint string

* default to 50 turns

* revert changes from codeact agent and create new CodeActSWEAgent

* revert changes to codeact

* revert instructions for run infer

* revert instructions for run infer

* update README

* update max iter

* add codeact swe agent

* fix issue for CodeActSWEAgent

* allow specifying max iter in cmdline script

* stop printing

* Update agenthub/codeact_swe_agent/README.md

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* Fix prompt regression in jupyter plugin

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-29 21:19:00 -07:00
Aaron Xia b1ec8e5dc2 style: Update agent_controller.py to clean log (#2124) 2024-05-29 18:56:11 -07:00
Rahul Anand b3cce763a2 fix #2123 (#2125) 2024-05-29 17:56:45 -04:00
Robert Brennan 89ac732cb6 Adjust docs a bit (#2135)
* tweak docs a bit

* move warning
2024-05-29 17:56:28 -04:00
dependabot[bot] eb1e0e9da8 Bump llama-index-embeddings-huggingface from 0.2.0 to 0.2.1 (#2132) 2024-05-29 20:48:14 +00:00
dependabot[bot] ab454e122a Bump browsergym from 0.3.3 to 0.3.4 (#2127)
Bumps [browsergym](https://github.com/ServiceNow/BrowserGym) from 0.3.3 to 0.3.4.
- [Release notes](https://github.com/ServiceNow/BrowserGym/releases)
- [Commits](https://github.com/ServiceNow/BrowserGym/compare/v0.3.3...v0.3.4)

---
updated-dependencies:
- dependency-name: browsergym
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 15:42:21 -04:00
dependabot[bot] cf95f1aabe Bump ruff from 0.4.5 to 0.4.6 (#2130)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.4.5 to 0.4.6.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/v0.4.5...v0.4.6)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-30 00:53:53 +08:00
dependabot[bot] b011190b40 Bump litellm from 1.38.11 to 1.39.2 (#2133)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.38.11 to 1.39.2.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.38.11...v1.39.2)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 15:51:50 +00:00
dependabot[bot] 439e9c0e60 Bump openai from 1.30.3 to 1.30.4 (#2131) 2024-05-29 15:44:51 +00:00
dependabot[bot] 53b3309a5a Bump @typescript-eslint/eslint-plugin from 7.10.0 to 7.11.0 in /frontend (#2129) 2024-05-29 15:29:54 +00:00
dependabot[bot] c45123ddb2 Bump framer-motion from 11.2.6 to 11.2.9 in /frontend (#2128) 2024-05-29 15:29:40 +00:00
dependabot[bot] af3ddddd33 Bump lint-staged from 15.2.4 to 15.2.5 in /frontend (#2126)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 15.2.4 to 15.2.5.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v15.2.4...v15.2.5)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 15:29:30 +00:00
மனோஜ்குமார் பழனிச்சாமி d4ccd48af8 Persistent docker session (#1998)
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-29 13:22:34 +00:00
Robert Brennan 03386a81e0 fix file uploads (#2102)
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-29 13:22:22 +00:00
மனோஜ்குமார் பழனிச்சாமி 343e5c73ae Parsed model_name for model_info (#2122) 2024-05-29 16:54:27 +08:00
Prithvi 13d04fa36c Fix issue #2029: Replace defaultProps with JavaScript default parameters (#2106)
* updated basemodal

Updated the basemodal.tsx file by removing the  BaseModal.defaultProps block and including the default values directly within the function parameters.

* Removed DefaultProps from the files

Removed DefaultProps from the files:
AgentControlBar.tsx, ChatInput.tsx, ExplorerTree.tsx, TreeNode.tsx, IconButton.tsx, HeaderContent.tsx, AutocompleteCombobox.tsx

and replaced the usage of defaultProps with JavaScript default parameters in the given components.

* Removed comments and updated eslintrc

Removed all the comments (Removed the defaultProps block comment), and updated the ESLint rules to ignore the defaultProps warning thrown by ESLint.

* Finished Linting Succesfully.

Ran the lint command with the --fix and --write arg to fix all remaining issues and errors before pushing. Thanks a lot @amanape for the support!

---------

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-29 09:49:50 +03:00
Boxuan Li 9b371b1b5f Refactor agent delegation and tweak micro agents (#1910)
This PR fixes #1897. In addition, this PR fixes and tweaks a few micro-agents.

For the first time, I am able to use ManagerAgent to complete test_write_simple_script and test_edits tasks in integration tests, so this PR also adds ManagerAgent as part of integration tests. test_write_simple_script involves delegation to CoderAgent while test_edits involves delegation to TypoFixerAgent.

Also for the first time, I am able to use DelegateAgent to complete test_write_simple_script and test_edits tasks in integration tests, so this PR also adds DelegateAgent as part of integration tests. It involves delegation to StudyRepoForTaskAgent, CoderAgent and VerifierAgent.

This PR is a blocker for #1735 and likely #1945.
2024-05-28 20:01:16 -07:00
mamoodi c37a474dc5 doc: Small fix for development.md and docs (#2119) 2024-05-28 20:43:58 +00:00
dependabot[bot] b9aee7046c Bump @nextui-org/react from 2.3.6 to 2.4.0 in /frontend (#2115)
Bumps [@nextui-org/react](https://github.com/nextui-org/nextui/tree/HEAD/packages/core/react) from 2.3.6 to 2.4.0.
- [Release notes](https://github.com/nextui-org/nextui/releases)
- [Changelog](https://github.com/nextui-org/nextui/blob/canary/packages/core/react/CHANGELOG.md)
- [Commits](https://github.com/nextui-org/nextui/commits/@nextui-org/react@2.4.0/packages/core/react)

---
updated-dependencies:
- dependency-name: "@nextui-org/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-29 00:32:02 +08:00
dependabot[bot] 2a12642228 Bump uvicorn from 0.29.0 to 0.30.0 (#2111)
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.29.0 to 0.30.0.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.29.0...0.30.0)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 23:33:32 +08:00
dependabot[bot] 535d316a89 Bump vite from 5.2.11 to 5.2.12 in /frontend (#2112)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.11 to 5.2.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.2.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 23:33:06 +08:00
dependabot[bot] e3e4aaa31b Bump eslint-plugin-react from 7.34.1 to 7.34.2 in /frontend (#2113)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.1 to 7.34.2.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/v7.34.2/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.34.1...v7.34.2)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 23:32:38 +08:00
dependabot[bot] 6640a247c0 Bump @typescript-eslint/parser from 7.10.0 to 7.11.0 in /frontend (#2114)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.10.0 to 7.11.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.11.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 23:32:16 +08:00
dependabot[bot] 5b16ca7a45 Bump litellm from 1.38.10 to 1.38.11 (#2110)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.38.10 to 1.38.11.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.38.10...v1.38.11)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 16:57:43 +02:00
Ryan H. Tran 9434bcce48 Support MINT benchmark (MATH, GSM8K subset) (#1955)
* setup boilerplate and README

* setup test script and load dataset

* add temp intg that works

* refactor code

* add solution evaluation through 'fake_user_response_fn'

* finish integrating MATH subset

* Update evaluation/mint/run_infer.py

* Update evaluation/mint/run_infer.sh

* Update opendevin/core/main.py

* remove redudant templates, add eval_note, update README

* use <execute_ipython> tag instead of <execute>

* hardcode AGENT option for run_infer.sh

* Update evaluation/mint/task.py

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* fix: bug no message returned when task's success

* change message to make the agent exit

* import bash abstractmethod

* install all required packages inside sandbox before the agent runs, adjust prompt

* add subset eval folder separation and test for gsm8k

* fix bug in Reasoning task result check, add requirements.txt

* Fix syntax error in evaluation/mint/run_infer.py

* update README, add default values for `SUBSET` and `EVAL_LIMIT`

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
Co-authored-by: yufansong <yufan@risingwave-labs.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-28 07:42:52 +00:00
dependabot[bot] 110c530582 Bump browsergym from 0.3.2 to 0.3.3 (#2091)
Bumps [browsergym](https://github.com/ServiceNow/BrowserGym) from 0.3.2 to 0.3.3.
- [Release notes](https://github.com/ServiceNow/BrowserGym/releases)
- [Commits](https://github.com/ServiceNow/BrowserGym/compare/v0.3.2...v0.3.3)

---
updated-dependencies:
- dependency-name: browsergym
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:32:30 +08:00
dependabot[bot] 1b10c5bcb8 Bump @testing-library/user-event from 13.5.0 to 14.5.2 in /frontend (#2096)
Bumps [@testing-library/user-event](https://github.com/testing-library/user-event) from 13.5.0 to 14.5.2.
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/user-event/compare/v13.5.0...v14.5.2)

---
updated-dependencies:
- dependency-name: "@testing-library/user-event"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:32:21 +08:00
dependabot[bot] e52e24c5d5 Bump jsdom from 24.0.0 to 24.1.0 in /frontend (#2097)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 24.0.0 to 24.1.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/24.0.0...24.1.0)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:32:12 +08:00
dependabot[bot] b570354357 Bump openai from 1.30.1 to 1.30.3 (#2090)
Bumps [openai](https://github.com/openai/openai-python) from 1.30.1 to 1.30.3.
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v1.30.1...v1.30.3)

---
updated-dependencies:
- dependency-name: openai
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:31:45 +08:00
dependabot[bot] 848746a1c8 Bump boto3 from 1.34.112 to 1.34.113 (#2092)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.112 to 1.34.113.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.112...1.34.113)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:31:32 +08:00
dependabot[bot] bbcc1ab171 Bump json-repair from 0.19.2 to 0.20.1 (#2093)
Bumps [json-repair](https://github.com/mangiucugna/json_repair) from 0.19.2 to 0.20.1.
- [Release notes](https://github.com/mangiucugna/json_repair/releases)
- [Commits](https://github.com/mangiucugna/json_repair/compare/0.19.2...0.20.1)

---
updated-dependencies:
- dependency-name: json-repair
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:31:23 +08:00
dependabot[bot] e6ae9ae259 Bump @vitejs/plugin-react from 4.2.1 to 4.3.0 in /frontend (#2094)
Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/v4.3.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:31:17 +08:00
dependabot[bot] 9507f4426a Bump typescript from 5.4.4 to 5.4.5 in /frontend (#2098)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.4.4 to 5.4.5.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.4.4...v5.4.5)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:31:05 +08:00
dependabot[bot] 5bccaefc5f Bump litellm from 1.38.2 to 1.38.10 (#2089)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.38.2 to 1.38.10.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.38.2...v1.38.10)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 23:28:44 +08:00
Engel Nyst 55fdee31ad Remove unnecessary stuff from the sandboxes tests (#2095) 2024-05-27 20:50:02 +05:30
Yoni 3c5c214d87 Fix: serve UI from fastAPI app (#2086) 2024-05-27 18:56:13 +05:30
Xingyao Wang ae8cda1495 Support specifying custom cost per token (#2083)
* support specifying custom cost per token

* fix test for new attrs

* add to docs

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-27 19:35:34 +08:00
Yufan Song 3d29ec0418 add version (#2078) 2024-05-26 20:46:39 -07:00
Aaron Xia b66a915de1 feat: auto clean session with session close called. (#1990)
* feat: auto clean session with session close called.

* fix: lint

* fix: lint

* fix: lint

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2024-05-27 11:08:24 +08:00
Aleksandar 18d07bda89 feat: add max_budget_per_task configuration to control task cost (#2070)
* feat: add max_budget_per_task configuration to control task cost

* Fix test_arg_parser.py

* Use the config.max_budget_per_task as default value

* Add max_budget_per_task to core/main.py as well

* Update opendevin/controller/agent_controller.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-27 02:04:31 +08:00
Engel Nyst 783fea62a0 Ignore pid for loop detection (Was: override eq...) (#2045)
* rewrite, implement pid ignore in the controller

* make the helper method private
2024-05-26 19:27:12 +02:00
Xingyao Wang 2c0a2dbc61 fix yet another swe_bench issue (#2069) 2024-05-26 10:01:43 -07:00
Gant f0271f9f91 need to run as root to use SWEBench container (#2068) 2024-05-26 14:21:33 +00:00
Xingyao Wang 5114230e53 Some SWE-Bench infer fixes and improvements (#2065)
* reset workspace base properly

* support running without hint

* support running without hint

* bump swe-bench eval docker to v1.2 for latest agentskills

* only give hint when use hint text is trie

* add swe-agent instructions for validation

* update dockerfile

* pin the python interpreter for execute_cli

* avoid initialize plugins twice

* default to use hint

* save results to swe_bench_lite

* unset gh token and increase max iter to 50

* remove printing of use hint status

* refractor ssh login into one function

* ok drop to 30 turns bc it is so expensive :(

* remove reproduce comments to avoid stuck
2024-05-26 10:02:11 +00:00
Xingyao Wang a6b3ce866d refractor ssh login into one function (#2066) 2024-05-26 08:56:13 +00:00
Boxuan Li 7d6cb69a51 main.py: Fix redundant ChangeAgentStateAction (#2064) 2024-05-26 15:20:56 +08:00
Chris Mamatas 1891fd88d5 feat(frontend): Added React Router (#2061)
* Added React Router

* Moved router import above ./App

---------

Co-authored-by: Chris Mamatas <chrismamatas1@gmail.com>
2024-05-25 21:57:15 +03:00
Shimada666 be1c2ad60d feat: use retry decorator instead of retrying in a loop (#2058)
* feat: use retry decorator instead of retrying in a loop

* update code logic

* update poetry lock
2024-05-25 16:04:40 +00:00
Yizhe Zhang 0c829cd067 Support Entity-Deduction-Arena (EDA) Benchmark (#1931)
* adding draft evaluation code for EDA, using chatgpt as the temporal agent for now

* Update README.md

* Delete frontend/package.json

* reverse the irrelevant changes

* reverse package.json

* use chatgpt as the codeactagent

* integrate with opendevin

* Update evaluation/EDA/README.md

* Update evaluation/EDA/README.md

* Use poetry to manage packages

* integrate with opendevin

* minor update

* minor update

* update poetry

* update README

* clean-up infer scripts

* add run_infer script and improve readme

* log final success and final message & ground truth

---------

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: yufansong <yufan@risingwave-labs.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-25 23:17:04 +08:00
Xingyao Wang 28ab00946b update README for GAIA (#2054)
* update README for GAIA

* Update evaluation/gaia/README.md

* Update evaluation/gaia/README.md

* Update evaluation/gaia/README.md

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-25 15:01:03 +00:00
Xingyao Wang ec68af5b83 fix the openai_api_key detected by agentskills (#2052) 2024-05-25 22:09:07 +08:00
Xingyao Wang 221035d39a Add retry logic to ssh login (#2053)
* add retry logic to ssh login

* Update opendevin/runtime/docker/ssh_box.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-25 12:16:24 +00:00
Shimada666 b31f7701eb Integrate Multimodal tools to agentskills. (#2016)
* suport reading multimodal files

* move file

* update dependency

* remove useless pip install

* add comments

* update the comment

* Apply suggestions from code review

* Add unit test for TXTReader

* pre-commit hook corrupted utf16 test txt

* Revert unnecessary dependency upgrades

* feat: import some readers for agentskill

* add dependencies

* Integrate some multimodal tools

* add shell pip dependency

* update dependencies

* update dependencies

* update print window

* remove __main__

* locally import cv2

* add c library for opencv

* update lock file

* update prompt

* remove unuseful file

* add some unittest

* add unittest & remove excel-related parser

* rollback poetry lock

* remove markdown

* remove requests

* optimize parse_video output

* Fix integration tests for CodeActAgent

* remove test_parse_image unittest

* Add a TODO to containers/sandbox/Dockerfile

* update dependencies

* remove pyproject.toml useless package

* change document via openai key

* Fix prompts after removing some actions

---------

Co-authored-by: Mingchen Zhuge <mczhuge@gmail.com>
Co-authored-by: yufansong <yufan@risingwave-labs.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Mingchen Zhuge <64179323+mczhuge@users.noreply.github.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2024-05-25 18:58:49 +08:00
Boxuan Li 91f313c914 BrowserEnv: init exception handling (#2050)
* BrowserEnv: init exception handling

* Revert irrelevant changes

* Remove type ignore
2024-05-25 00:17:25 -07:00
மனோஜ்குமார் பழனிச்சாமி 36ff060c1a Added links in docs (#2051) 2024-05-25 11:23:20 +05:30
மனோஜ்குமார் பழனிச்சாமி cfae6821fa refactored timeout (#2044) 2024-05-24 18:19:14 +02:00
mamoodi 752ce8c4ea Update bug template to include os version (#1982) 2024-05-24 15:58:05 +00:00
dependabot[bot] cc6895a65c Bump streamlit from 1.34.0 to 1.35.0 (#2037)
Bumps [streamlit](https://github.com/streamlit/streamlit) from 1.34.0 to 1.35.0.
- [Release notes](https://github.com/streamlit/streamlit/releases)
- [Commits](https://github.com/streamlit/streamlit/compare/1.34.0...1.35.0)

---
updated-dependencies:
- dependency-name: streamlit
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 23:00:37 +08:00
dependabot[bot] 5538ee9bde Bump @types/react from 18.3.2 to 18.3.3 in /frontend (#2039)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.3.2 to 18.3.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 23:00:08 +08:00
dependabot[bot] 9a0bae6d9b Bump @testing-library/react from 13.4.0 to 15.0.7 in /frontend (#2040)
Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 13.4.0 to 15.0.7.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v13.4.0...v15.0.7)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 22:59:53 +08:00
dependabot[bot] de0f30f6cc Bump eslint-plugin-react-hooks from 4.6.0 to 4.6.2 in /frontend (#2041)
Bumps [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) from 4.6.0 to 4.6.2.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 22:59:37 +08:00
dependabot[bot] 6ae16dbc48 Bump react-i18next from 14.1.1 to 14.1.2 in /frontend (#2043)
Bumps [react-i18next](https://github.com/i18next/react-i18next) from 14.1.1 to 14.1.2.
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v14.1.1...v14.1.2)

---
updated-dependencies:
- dependency-name: react-i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 22:59:18 +08:00
dependabot[bot] b6be108f49 Bump monaco-editor from 0.48.0 to 0.49.0 in /frontend (#2042)
Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from 0.48.0 to 0.49.0.
- [Release notes](https://github.com/microsoft/monaco-editor/releases)
- [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/monaco-editor/compare/v0.48.0...v0.49.0)

---
updated-dependencies:
- dependency-name: monaco-editor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 22:58:36 +08:00
dependabot[bot] ef813af9d7 Bump litellm from 1.38.0 to 1.38.2 (#2038)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.38.0 to 1.38.2.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.38.0...v1.38.2)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 14:51:22 +00:00
dependabot[bot] 909d7b45ef Bump boto3 from 1.34.111 to 1.34.112 (#2036)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.111 to 1.34.112.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.111...1.34.112)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 14:50:02 +00:00
Xingyao Wang e731048ccf Improve action and observation logging for the CLI interface (#2035)
* properly log user messages;
format browser action/obs, summarize action, messages properly for logging

* add source to message

* add spaces for printing
2024-05-24 08:21:25 -04:00
Jiayi Pan 2d52298a1d Support GAIA benchmark (#1911)
* Add gaia test

* Improve gaia prompts

* Fix browser_env hang bug

* Fix gaia bugs

* add gaia to eval readme

* Fix gaia bugs

* minor fix

* add run_infer.sh and update readme

* set num eval worker to 1

* default to 2023 gaia level1 subset

* default to level 1

* add prompt to instruct model enclose answer within <solution> tag

* add missing break

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: yufansong <yufan@risingwave-labs.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2024-05-24 11:22:28 +00:00
dependabot[bot] 2f6167b953 Bump framer-motion from 11.2.5 to 11.2.6 in /frontend (#2010)
Bumps [framer-motion](https://github.com/framer/motion) from 11.2.5 to 11.2.6.
- [Changelog](https://github.com/framer/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/framer/motion/compare/v11.2.5...v11.2.6)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-24 10:01:42 +00:00
Boxuan Li 78241d9d43 Add tests for browser agent (#2031)
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-24 09:59:40 +00:00
Boxuan Li b13a40c05c README.md: Add CodeCov badge (#2022)
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-24 09:54:25 +00:00
dependabot[bot] ad2784d534 Bump ruff from 0.4.4 to 0.4.5 (#2004)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.4.4 to 0.4.5.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/v0.4.4...v0.4.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-24 05:51:05 -04:00
Boxuan Li 593b8d468b Fix CI workflows [mac-test] (#2025)
* Fix CI settings

* Stop saving cpu cycles for GitHub

* Conditionally run mac tests

* Random push to trigger CI checks again

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-24 09:25:00 +00:00
sp.wack ae105c2faf feat(frontend): Add actions to send feedback to backend (#2020)
* Add feedback actions to send to backend

* Uncomment request

* Refactor and disable feedback when sending

* disable defaultProp error

---------

Co-authored-by: amanape <stephanpsaras@gmail.com>
2024-05-24 04:26:06 -04:00
dependabot[bot] 9207a8da01 Bump browsergym from 0.2.6 to 0.3.2 (#2013)
Bumps [browsergym](https://github.com/ServiceNow/BrowserGym) from 0.2.6 to 0.3.2.
- [Release notes](https://github.com/ServiceNow/BrowserGym/releases)
- [Commits](https://github.com/ServiceNow/BrowserGym/compare/v0.2.6...v0.3.2)

---
updated-dependencies:
- dependency-name: browsergym
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-24 16:03:56 +08:00
Frank Xu 53f64ffa06 Improve browsing agent prompts, allowing agent to properly finish when done (#1993)
* improve browsing agent, allowing it to properly finish.

* handle parsing error, show user what the agent's browsing thoughts in the front end

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-24 00:02:19 -07:00
Boxuan Li c59bcbbffd Minor docstring & prompt fixes for AgentSkills (#2028)
* A few minor fixes to agentskills

* Regenerate prompts

* Remove redundant comment
2024-05-24 13:30:48 +08:00
Xingyao Wang cbf4c4b4c4 fix ExceptionPxssh (#2023)
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-23 21:24:21 -07:00
Boxuan Li 633ece5f9c Fix integration tests (#2024) 2024-05-23 20:24:31 -07:00
Robert Brennan 9ca2007201 fix json encoding (#2018)
* fix json encoding

* add test

* add another test

* fix integration tests

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-23 23:36:15 +00:00
dependabot[bot] b492b6293a Bump lint-staged from 15.2.2 to 15.2.4 in /frontend (#2009)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 15.2.2 to 15.2.4.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v15.2.2...v15.2.4)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:25:00 -04:00
dependabot[bot] 0a6b26735b Bump @typescript-eslint/parser from 7.9.0 to 7.10.0 in /frontend (#2008)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.9.0 to 7.10.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.10.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:24:42 -04:00
dependabot[bot] dff0f1be13 Bump @types/react-syntax-highlighter in /frontend (#2007)
Bumps [@types/react-syntax-highlighter](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-syntax-highlighter) from 15.5.11 to 15.5.13.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-syntax-highlighter)

---
updated-dependencies:
- dependency-name: "@types/react-syntax-highlighter"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:24:07 -04:00
dependabot[bot] e7306b7226 Bump @react-types/shared from 3.23.0 to 3.23.1 in /frontend (#2006)
Bumps [@react-types/shared](https://github.com/adobe/react-spectrum) from 3.23.0 to 3.23.1.
- [Release notes](https://github.com/adobe/react-spectrum/releases)
- [Commits](https://github.com/adobe/react-spectrum/compare/@react-types/shared@3.23.0...@react-types/shared@3.23.1)

---
updated-dependencies:
- dependency-name: "@react-types/shared"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:23:49 -04:00
DaxServer b118df606f build: Add poetry command to use Python 3.11 for environment setup (#1972) 2024-05-23 12:05:19 -04:00
Xingyao Wang 602ffcdffb Implement agentskills for OpenDevin to helpfully improve edit AND including more useful tools/skills (#1941)
* add draft for skills

* Implement and test agentskills functions: open_file, goto_line, scroll_down, scroll_up, create_file, search_dir, search_file, find_file

* Remove new_sample.txt file

* add some work from opendevin w/ fixes

* Add unit tests for agentskills module

* fix some issues and updated tests

* add more tests for open

* tweak and handle goto_line

* add tests for some edge cases

* add tests for scrolling

* add tests for edit

* add tests for search_dir

* update tests to use pytest

* use pytest --forked to avoid file op unit tests to interfere with each other via global var

* update doc based on swe agent tool

* update and add tests for find_file and search_file

* move agent_skills to plugins

* add agentskills as plugin and docs

* add agentskill to ssh box and fix sandbox integration

* remove extra returns in doc

* add agentskills to initial tool for jupyter

* support re-init jupyter kernel (for agentskills) after restart

* fix print window's issue with indentation and add testcases

* add prompt for codeact with the newest edit primitives

* modify the way line number is presented (remove leading space)

* change prompt to the newest display format

* support tracking of costs via metrics

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* implement and add tests for py linting

* remove extra text arg for incompatible subprocess ver

* remove sample.txt

* update test_edits integration tests

* fix all integration

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update opendevin/runtime/plugins/agent_skills/README.md

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update agenthub/codeact_agent/prompt.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/runtime/plugins/agent_skills/agentskills.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* Revert "correctly setup plugins for swebench eval"

This reverts commit 2bd1055673.

* bump version

* remove _AGENT_SKILLS_DOCS

* move flake8 to test dep

* update poetry.lock

* remove extra arg

* reduce max iter for eval

* update poetry

* fix integration tests

---------

Co-authored-by: OpenDevin <opendevin@opendevin.ai>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-23 16:04:09 +00:00
Robert Brennan ea9c785075 fix session state after resuming (#1999)
* fix state resuming

* fix session reconnection

* fix lint
2024-05-23 11:47:36 -04:00
Xingyao Wang 6ff50ed369 Fix SWE-Bench evaluation due to setuptools version (#1995)
* correctly setup plugins for swebench eval

* bump swe-bench version and add logging

* Revert "correctly setup plugins for swebench eval"

This reverts commit 2bd1055673.

* bump version
2024-05-23 23:17:42 +08:00
dependabot[bot] d6327f99ce Bump litellm from 1.37.20 to 1.38.0 (#2005)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.37.20 to 1.38.0.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.37.20...v1.38.0)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 14:57:56 +00:00
dependabot[bot] 1c40ea5222 Bump docker from 7.0.0 to 7.1.0 (#2002)
Bumps [docker](https://github.com/docker/docker-py) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/docker-py/releases)
- [Commits](https://github.com/docker/docker-py/compare/7.0.0...7.1.0)

---
updated-dependencies:
- dependency-name: docker
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 16:45:46 +02:00
dependabot[bot] 58d45a1a8a Bump boto3 from 1.34.110 to 1.34.111 (#2001)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.110 to 1.34.111.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.110...1.34.111)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 14:42:31 +00:00
Niklas Muennighoff ef6cdb7532 HumanEvalFix integration (#1908)
* Preliminary HumanEvalFix integration

* Clean paths

* fix: set workspace path correctly for config
fix: task in that contains /

* add missing run_infer.sh

* update run_infer w/o hard coded agent

* fix typo

* change `instance_id` to `task_id`

* add the warning and env var setting to run_infer.sh

* reset back workspace mount at the end of each instance

* 10 max iter is probably enough for humanevalfix

* Remove unneeded section

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* Fix link

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* Use logger

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>

* Update run_infer.py

fix a bug:

ERROR:concurrent.futures:exception calling callback for <Future at 0x309cbc470 state=finished raised NameError>
concurrent.futures.process._RemoteTraceback:

* Update README.md

* Update README.md

* Update README.md

* Update README.md

added an example

* Update README.md

added: enable_auto_lint = true

* Update pyproject.toml

add: evaluate package

* Delete poetry.lock

update poetry.lock

* update poetry.lock

update poetry.lock

* Update README.md

* Update README.md

---------

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
Co-authored-by: Robert <871607149@qq.com>
2024-05-23 13:09:40 +00:00
Aaron Xia f53a91b17c fix: catch session file not existed exception when init EventStream(maybe creating a new session with no session files stored). (#1994) 2024-05-23 11:35:55 +00:00
Engel Nyst 0eccf31604 Refactor monologue and SWE agent to use the messages in state history (#1863)
* Refactor monologue to use the messages in state history

* add messages, clean up

* fix monologue

* update integration tests

* move private method

* update SWE agent to use the history from State

* integration tests for SWE agent

* rename monologue to initial_thoughts, since that is what it is
2024-05-23 07:29:12 +00:00
Jeremi Joslin 3235836b00 Fix typo in prompt (#1992) 2024-05-23 07:11:46 +00:00
Boxuan Li a605e59b7e Save CI cycles for backend tests (#1985) 2024-05-23 00:10:13 -07:00
jiangleo d1475e6e04 Fix Repeated Responses in Chat by Adding IPythonRunCellObservation (#1987)
Co-authored-by: jianghongwei <jianghongwei@58.com>
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
2024-05-23 11:10:27 +05:30
Boxuan Li acb430eef5 Refactor integration testing CI, add optional Mac tests, and mark a few agents as deprecated (#1888)
* Add MacOS to integration tests

* Switch back to python 3.11

* Install Docker for macos pipeline

* regenerate.sh: Use environmental variable for sandbox type

* Pack different agents' tests into a single check

* Fix CodeAct tests

* Reduce file match and extensive debug logs

* Add TEST_IN_CI mode that reports codecov

* Small fix: don't quit if reusing old responses failed

* Merge codecov results

* Fix typos

* Remove coverage merge step - codecov automatically does that

* Make mac integration tests as optional - too slow

* Fix codecov args

* Add comments in yaml

* Include sandbox type in codecov report name

* Fix codecov report merge

* Revert renaming of test_matrix_success

* Remove SWEAgent and PlannerAgent from tests

* Mark planner agent and SWE agent as deprecated

* CodeCov: Ignore planner and sweagent

* Revert "Remove SWEAgent and PlannerAgent from tests"

This reverts commit 040cb3bfb9.

* Remove all tests for SWE Agent

* Only keep basic tests for MonologueAgent and PlannerAgent

* Mark SWE Agent as deprecated, and ignore code coverage for it

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-22 20:38:57 -07:00
Engel Nyst b9a5be2569 Add ruff for shared mutable defaults (B) (#1938)
* Add ruff for shared mutable defaults (B)

* Apply B006, B008 on current files, except fast API

* Update agenthub/SWE_agent/prompts.py

Co-authored-by: Graham Neubig <neubig@gmail.com>

* fix unintended behavior change

* this is correct, tell Ruff to leave it alone

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-22 20:06:00 -07:00
Rahul Anand 9a2591d0f6 fix #1960 (#1964) 2024-05-22 19:36:45 -07:00
Robert Brennan 5bdacf738d Refactor session management (#1810)
* refactor session mgmt

* defer file handling to runtime

* add todo

* refactor sessions a bit more

* remove messages logic from FE

* fix up socket handshake

* refactor frontend auth a bit

* first pass at redoing file explorer

* implement directory suffix

* fix up file tree

* close agent on websocket close

* remove session saving

* move file refresh

* remove getWorkspace

* plumb path/code differently

* fix build issues

* fix the tests

* fix npm build

* add session rehydration

* fix event serialization

* logspam

* fix user message rehydration

* add get_event fn

* agent state restoration

* change history tracking for codeact

* fix responsiveness of init

* fix lint

* lint

* delint

* fix prop

* update tests

* logspam

* lint

* fix test

* revert codeact

* change fileService to use API

* fix up session loading

* delint

* delint

* fix integration tests

* revert test

* fix up access to options endpoints

* fix initial files load

* delint

* fix file initialization

* fix mock server

* fixl int

* fix auth for html

* Update frontend/src/i18n/translation.json

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* refactor sessions and sockets

* avoid reinitializing the same session

* fix reconnect issue

* change up intro message

* more guards on reinit

* rename agent_session

* delint

* fix a bunch of tests

* delint

* fix last test

* remove code editor context

* fix build

* fix any

* fix dot notation

* Update frontend/src/services/api.ts

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* fix up error handling

* Update opendevin/server/session/agent.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/server/session/agent.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update frontend/src/services/session.ts

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* fix build errs

* fix else

* add closed state

* delint

* Update opendevin/server/session/session.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

---------

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-22 18:33:16 +00:00
dependabot[bot] 37354dbc83 --- (#1971)
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-22 18:04:43 +00:00
dependabot[bot] 53afdc8496 --- (#1970)
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 01:53:22 +08:00
dependabot[bot] bf6fa8e5f4 --- (#1969)
updated-dependencies:
- dependency-name: husky
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 01:52:47 +08:00
dependabot[bot] afc1752a5c --- (#1968)
updated-dependencies:
- dependency-name: "@reduxjs/toolkit"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 01:52:25 +08:00
dependabot[bot] 40411db7bf --- (#1967)
updated-dependencies:
- dependency-name: react-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/react-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 01:51:43 +08:00
Engel Nyst 46352e890b Logging security (#1943)
* update .gitignore

* Rename the confusing 'INFO' style to 'DETAIL'

* override str and repr

* feat: api_key desensitize

* feat: add SensitiveDataFilter in file handler

* tweak regex, add tests

* more tweaks, include other attrs

* add env vars, those with equivalent config

* fix tests

* tests are invaluable

---------

Co-authored-by: Shimada666 <649940882@qq.com>
2024-05-22 18:27:38 +02:00
dependabot[bot] 8e3e51e984 --- (#1976)
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 15:37:23 +00:00
dependabot[bot] 7da647a091 --- (#1975)
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 17:36:52 +02:00
Yufan Song 4292998ee2 doc: add more cmd in unit test documentation (#1963) 2024-05-22 19:47:03 +08:00
Yufan Song d18e6c85a0 feat: add metrics related to cost for better observability (#1944)
* add metrics for total_cost

* make lint

* refact codeact

* change metrics into llm

* add costs list, add into state

* refactor log completion

* refactor and test others

* make lint

* Update opendevin/core/metrics.py

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update opendevin/llm/llm.py

Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>

* refactor

* add code

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2024-05-22 08:53:31 +00:00
Yufan Song 34cccfe9cc doc: update documentation about poetry update (#1962)
* add doc

* Update Development.md

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-22 07:33:53 +00:00
Shimada666 da8369c4d2 fix: llm is_local function logic error (#1961)
Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
2024-05-22 10:50:21 +05:30
Graham Neubig 6618941422 Update README.md SWE-bench score (#1959)
* Update README.md SWE-bench score

Our most recent results on swe-bench lite are 25%, so this updates the README accordingly.

* Update
2024-05-22 04:32:17 +00:00
Frank Xu 1fe290adf9 [Feat] A competitive Web Browsing agent (#1856)
* initial attempt at a browsing only agent

* add browsing agent

* update

* implement agent

* update

* fix comments

* remove unnecessary things from memory extras

* update image processing

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-21 19:20:33 +00:00
மனோஜ்குமார் பழனிச்சாமி d76c425b76 Refactored Logs (#1939) 2024-05-22 03:06:13 +08:00
RainRat 43c187b949 fix typos (#1956)
no functional change
2024-05-21 19:00:48 +00:00
dependabot[bot] dd4ef67809 --- (#1952)
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-21 16:33:09 +00:00
dependabot[bot] a2f00584c1 --- (#1950)
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 16:32:30 +00:00
dependabot[bot] 108404f85a --- (#1953)
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-21 16:30:12 +00:00
mamoodi f74b807342 Update README and doc intro to be consistent with each other (#1954) 2024-05-21 16:26:24 +00:00
dependabot[bot] d60aa2b512 --- (#1951)
updated-dependencies:
- dependency-name: json-repair
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 00:11:07 +08:00
dependabot[bot] 772734c884 --- (#1947)
updated-dependencies:
- dependency-name: react
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 16:04:15 +00:00
dependabot[bot] 6ce0eea4bb --- (#1949)
updated-dependencies:
- dependency-name: framer-motion
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 15:55:53 +00:00
dependabot[bot] fd3c83d1eb --- (#1948)
updated-dependencies:
- dependency-name: i18next-http-backend
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 15:29:47 +00:00
dependabot[bot] 2610965f07 --- (#1946)
updated-dependencies:
- dependency-name: clsx
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 15:08:06 +00:00
Engel Nyst 1e51bb9276 Fix/update controller is_stuck() (#1891)
* Refactor monologue to use the messages in state history

remove now unused method

* is_stuck update

* fix is_stuck

* unit tests

* fix tests

* Revert "Refactor monologue to use the messages in state history"

This reverts commit 76b4b765ef.

* Override eq for CmdOutputObservation to ignore the pid, compare the actual command only

* Revert "Override eq for CmdOutputObservation to ignore the pid, compare the actual command only"

This reverts commit 6418d856b5.
2024-05-21 22:56:59 +08:00
Boxuan Li 4add8a5595 SWE-bench: Allow selection of tasks (#1935) 2024-05-21 16:53:29 +08:00
Engel Nyst 2926c51839 fix logging of full llm_config (leaks api key) (#1937) 2024-05-21 08:08:48 +00:00
Engel Nyst 04094e4201 Document config (#1929)
* add more docstrings for config

* fix typo

* Update opendevin/core/config.py

Co-authored-by: Aleksandar <isavitaisa@gmail.com>

---------

Co-authored-by: Aleksandar <isavitaisa@gmail.com>
2024-05-21 15:28:20 +08:00
Boxuan Li 99651e3249 Fix browser_env hung bug (#1933)
* Fix browser_env hang bug

* Send SIGKILL if SIGTERM doesn't work
2024-05-20 19:31:36 -07:00
dependabot[bot] 8750d3e68b Bump browsergym from 0.2.2 to 0.2.6 (#1925)
Bumps [browsergym](https://github.com/ServiceNow/BrowserGym) from 0.2.2 to 0.2.6.
- [Release notes](https://github.com/ServiceNow/BrowserGym/releases)
- [Commits](https://github.com/ServiceNow/BrowserGym/compare/v0.2.2...v0.2.6)

---
updated-dependencies:
- dependency-name: browsergym
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 12:51:55 -04:00
dependabot[bot] bcdde452da Bump react-icons from 5.0.1 to 5.2.1 in /frontend (#1918)
Bumps [react-icons](https://github.com/react-icons/react-icons) from 5.0.1 to 5.2.1.
- [Release notes](https://github.com/react-icons/react-icons/releases)
- [Commits](https://github.com/react-icons/react-icons/compare/v5.0.1...v5.2.1)

---
updated-dependencies:
- dependency-name: react-icons
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 19:34:25 +03:00
மனோஜ்குமார் பழனிச்சாமி 4612e107c9 fix: Handle invalid exit code conversion (#1915) 2024-05-20 11:30:52 -04:00
dependabot[bot] 1bc1d306bd Bump vite from 5.2.8 to 5.2.11 in /frontend (#1919)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.8 to 5.2.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.2.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:29:32 -04:00
dependabot[bot] c833d0b847 Bump @typescript-eslint/parser from 7.5.0 to 7.9.0 in /frontend (#1920)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.5.0 to 7.9.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:29:23 -04:00
dependabot[bot] 4c90dedcc7 Bump @nextui-org/react from 2.2.10 to 2.3.6 in /frontend (#1921)
Bumps [@nextui-org/react](https://github.com/nextui-org/nextui/tree/HEAD/packages/core/react) from 2.2.10 to 2.3.6.
- [Release notes](https://github.com/nextui-org/nextui/releases)
- [Changelog](https://github.com/nextui-org/nextui/blob/canary/packages/core/react/CHANGELOG.md)
- [Commits](https://github.com/nextui-org/nextui/commits/@nextui-org/react@2.3.6/packages/core/react)

---
updated-dependencies:
- dependency-name: "@nextui-org/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:29:15 -04:00
dependabot[bot] a982a2cc85 Bump react-i18next from 14.1.0 to 14.1.1 in /frontend (#1922)
Bumps [react-i18next](https://github.com/i18next/react-i18next) from 14.1.0 to 14.1.1.
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v14.1.0...v14.1.1)

---
updated-dependencies:
- dependency-name: react-i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:29:07 -04:00
dependabot[bot] ef828f3b9b Bump pytest-asyncio from 0.23.6 to 0.23.7 (#1924)
Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.23.6 to 0.23.7.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.23.6...v0.23.7)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:28:55 -04:00
dependabot[bot] eab64cfcc2 Bump google-generativeai from 0.5.3 to 0.5.4 (#1926)
Bumps [google-generativeai](https://github.com/google/generative-ai-python) from 0.5.3 to 0.5.4.
- [Release notes](https://github.com/google/generative-ai-python/releases)
- [Changelog](https://github.com/google-gemini/generative-ai-python/blob/main/RELEASE.md)
- [Commits](https://github.com/google/generative-ai-python/compare/v0.5.3...v0.5.4)

---
updated-dependencies:
- dependency-name: google-generativeai
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:28:03 +02:00
dependabot[bot] e978c77eb6 Bump mypy from 1.9.0 to 1.10.0 (#1927)
Bumps [mypy](https://github.com/python/mypy) from 1.9.0 to 1.10.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:27:13 +02:00
dependabot[bot] 6e2e9ab13d Bump pytest from 8.2.0 to 8.2.1 (#1923)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:25:03 +02:00
Shimada666 75cecf68e0 docs: update tutorial docs (#1912)
* docs: update tutorial docs

* Update evaluation/TUTORIAL.md

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
2024-05-20 14:40:31 +00:00
Xingyao Wang 7817d4c94f fix(controller): Improve error info logging (#1864)
* improve error info logging

* Move assignment of self.state.error to report_error function

* only log exception to state, but not to user

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-20 18:42:38 +08:00
Boxuan Li b845a38169 Small improvements & fixes to SWE-Bench (#1874)
I was able to run a few benchmark instances from SWE-Bench by myself following the documentation - it was great! In general the experience was smooth, thanks to @xingyaoww, @libowen2121 and the team! I made a few small enhancements and fixes to further improve the developer experience.

Always use poetry run python (using python from poetry's virtual environment) over python or python3 in scripts to make sure the behavior is consistent.
Make AGENT configurable. One can use an argument to control which agent they would like to benchmark. To facilitate this, I removed hardcoded CodeActAgent from run_infer.sh, and also added VERSION attribute to all agents, as the benchmark needs to record the agent version.
Make EVAL_LIMIT configurable. One can use an argument to control how many instances they'd like to benchmark. Useful for debugging & development purposes.
Fix 'eval_output_dir' not defined error in run_infer.py.
Other enhancements to the README file and logs.
I also notice that a lot of code from run_infer.py could be shared by other benchmarks, but since we only have one benchmark now, I think we could avoid over-engineering. A refactor and code dedup would be useful in the future once we have more benchmarks, though.
2024-05-20 08:03:30 +00:00
Shimada666 3e3dcd52a8 feat: add inline code style (#1909)
* feat: add inline code style

* feat: add code block radius

---------

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-20 07:01:29 +00:00
மனோஜ்குமார் பழனிச்சாமி ec7be6ee51 Fix: Update WebSocket URL to use correct protocol from window.location (#1900) 2024-05-20 09:19:38 +03:00
மனோஜ்குமார் பழனிச்சாமி 6ef7e6eb0f Checked for enduser in Docker (#1899) 2024-05-20 08:50:42 +05:30
Graham Neubig c5abc81bc9 Add documentation regarding how to fix github issues with OpenDevin (#1904)
* Add documentation on fixing GitHub issues with OpenDevin

* Update documentation to instruct users to send a prompt to OpenDevin for fixing GitHub issues

* Remove duplicate line in FAQ documentation

* Fix error with closed paragraph

---------

Co-authored-by: Your Name <you@example.com>
2024-05-19 19:00:46 +02:00
Shimada666 50c2141d20 feat: add log when config file not found (#1898) 2024-05-19 14:42:55 +02:00
dependabot[bot] 3f1b7117b1 Bump @typescript-eslint/eslint-plugin from 7.5.0 to 7.9.0 in /frontend (#1880)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 7.5.0 to 7.9.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-18 14:45:03 -04:00
dependabot[bot] c5945bc5a8 Bump ruff from 0.3.7 to 0.4.4 (#1885)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.3.7 to 0.4.4.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/v0.3.7...v0.4.4)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 14:44:47 -04:00
dependabot[bot] 75e1485cb0 Bump litellm from 1.37.12 to 1.37.16 (#1886)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.37.12 to 1.37.16.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.37.12...v1.37.16)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-18 14:44:22 -04:00
Robert Brennan 0ecba83e53 Move message history out of CodeAct (#1847)
* stop keeping history state in codeact

* regenerate tests

* Update agenthub/codeact_agent/codeact_agent.py

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>

* revert tests

* regen tests

* refactor codeact a bit

* regenerate without using LLM

* simplify logic

* change to heredoc

* fix heredoc

* fix end_of_edit docs

* regen tests

* regenerate

---------

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-18 18:39:27 +00:00
dependabot[bot] f85a73a50c Bump i18next-browser-languagedetector from 7.2.1 to 8.0.0 in /frontend (#1881)
Bumps [i18next-browser-languagedetector](https://github.com/i18next/i18next-browser-languageDetector) from 7.2.1 to 8.0.0.
- [Changelog](https://github.com/i18next/i18next-browser-languageDetector/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-browser-languageDetector/compare/v7.2.1...v8.0.0)

---
updated-dependencies:
- dependency-name: i18next-browser-languagedetector
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
2024-05-18 18:13:41 +00:00
Xingyao Wang b2fdb963b6 Add detailed tutorial for adding new evaluation benchmarks (#1827)
* Add detailed tutorial for adding new evaluation benchmarks

* update tutorial, fix typo, and log observation to the cmdline

* fix url

* Update evaluation/TUTORIAL.md

* Update evaluation/TUTORIAL.md

* Update evaluation/TUTORIAL.md

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* Update evaluation/TUTORIAL.md

Co-authored-by: Graham Neubig <neubig@gmail.com>

* simplify readme and add comments to the actual code

* Fix typo in evaluation/TUTORIAL.md

* Fix typo in evaluation/swe_bench/run_infer.py

* Fix another typo in evaluation/swe_bench/run_infer.py

* Update TUTORIAL.md

* Set host net work to false for SWEBench

* Update evaluation/TUTORIAL.md

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update evaluation/TUTORIAL.md

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update evaluation/TUTORIAL.md

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

* Update evaluation/TUTORIAL.md

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>

---------

Co-authored-by: OpenDevin <opendevin@opendevin.ai>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-18 13:40:53 -04:00
dependabot[bot] eafed447f8 Bump monaco-editor from 0.47.0 to 0.48.0 in /frontend (#1879)
Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from 0.47.0 to 0.48.0.
- [Release notes](https://github.com/microsoft/monaco-editor/releases)
- [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/monaco-editor/compare/v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: monaco-editor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:38:26 -04:00
dependabot[bot] 061dfc0ee3 Bump boto3 from 1.34.106 to 1.34.108 (#1887)
Bumps [boto3](https://github.com/boto/boto3) from 1.34.106 to 1.34.108.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.34.106...1.34.108)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:37:53 -04:00
dependabot[bot] 9cc76550d1 Bump @testing-library/jest-dom from 6.4.2 to 6.4.5 in /frontend (#1882)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 6.4.2 to 6.4.5.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v6.4.2...v6.4.5)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:16:04 -04:00
dependabot[bot] 6896ffd654 Bump e2b from 0.14.14 to 0.17.0 (#1883)
Bumps [e2b](https://github.com/e2b-dev/e2b) from 0.14.14 to 0.17.0.
- [Release notes](https://github.com/e2b-dev/e2b/releases)
- [Commits](https://github.com/e2b-dev/e2b/compare/@e2b/python-sdk@0.14.14...@e2b/python-sdk@0.17.0)

---
updated-dependencies:
- dependency-name: e2b
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:13:45 -04:00
dependabot[bot] ee005cc2e9 Bump jose from 5.2.4 to 5.3.0 in /frontend (#1878)
Bumps [jose](https://github.com/panva/jose) from 5.2.4 to 5.3.0.
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v5.2.4...v5.3.0)

---
updated-dependencies:
- dependency-name: jose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:12:44 -04:00
Temo d4c136a48f Update dependabot.yml (#1876)
Changed dependabot update schedule to daily to keep packages more up to date
2024-05-18 16:17:39 +00:00
Robert Brennan 1a045dc935 remove codecov annotations (#1877) 2024-05-18 12:04:22 -04:00
Robert Brennan 10933a2066 Only list files one directory deep (#1853)
* modify api endpoint

* update frontend for backend

* fix fileservice

* rm file

* unskip test

* fix some more tests

* fix another test

* fix another test

* fix api call

* fix refresh for subdirs

* more tests passing

* more tests

* more tests

* another test

* logspam

* lint

* fix import

* logspam

* code review feedback

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-18 15:36:26 +00:00
மனோஜ்குமார் பழனிச்சாமி b401be66f4 Revert "Fix/attribute error (#1812)" (#1871)
This reverts commit 6cce9c3c28.
2024-05-18 11:28:16 -04:00
Boxuan Li 0abc35cf57 ssh_box: Shutdown container when fail to start ssh session (#1872) 2024-05-18 17:04:38 +08:00
Boxuan Li f0ce2ffabf Allow code coverage to be zero for that patch (#1873) 2024-05-18 08:05:48 +00:00
Boxuan Li a57a213c7c Turn off auto linting by default, and on for swe_bench (#1861)
Disable Python linting by default, and turn it on for SWE Bench.

It is turned off by default since this behavior is weird and somewhat annoying to end users.
It is turned on for SWE Bench because linting python files gives LLM a chance to fix the indentations.
2024-05-18 04:04:38 +00:00
Aleksandar 94a9ec76b0 Disable Python linting by default (fixes #1789) (#1794)
* Disable Python linting by default (fixes #1789)

* Try to simplify

* Return do nothing comment

* Disable linting for the javascript as well

* Apply suggestions from code review

---------

Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
2024-05-17 20:55:12 -07:00
Gant f950e3b48e make CodeAct paper link correct (#1870) 2024-05-18 03:54:10 +00:00
Shimada666 5df85dcb57 refactor agent status component and add i18n support (#1867)
* fix: correct simple i18n key typo

* feat: refactor agent status component and add i18n support

---------

Co-authored-by: Jim Su <jimsu@protonmail.com>
2024-05-17 20:40:58 -07:00
மனோஜ்குமார் பழனிச்சாமி b0b44ed467 Auto restarted Jupyter kernel (#1808)
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
Co-authored-by: Xingyao Wang <xingyao6@illinois.edu>
Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
2024-05-18 08:40:31 +05:30
John Tackman 171764469d Update Dockerfile to assign workspace directory properly to user (#1830)
* Update Dockerfile

creating the workspace directory after switching user to fix permission errors
https://github.com/OpenDevin/OpenDevin/issues/1560

* assign $workspace_base to user

instead of creating directory later, just fix the permissions so user can write to it

* another sudo

---------

Co-authored-by: Leo <ifuryst@gmail.com>
2024-05-17 20:11:23 -04:00
Boxuan Li 735fbbfe3e (test) Include message separators in mock prompts (#1855)
* Add message separator to prompts in tests

* DEMO: remove existing prompts for PlannerAgent

* Add results after prompt regeneration
2024-05-18 00:33:55 +02:00
Xingyao Wang 7ca560471b close runtime after completion in main (#1860) 2024-05-17 16:55:45 +08:00
Xingyao Wang c320d908e5 add iproute2 to sandbox (#1859) 2024-05-17 12:57:58 +08:00
Robert Brennan 110b878dd9 fix up serialization and deserialization of events (#1850)
* fix up serialization and deserialization of events

* fix tests

* remove prints

* fix test

* regenerate tests

* add try blocks
2024-05-17 01:09:15 +00:00
மனோஜ்குமார் பழனிச்சாமி 5b6f622dad Update browser_env.py (#1779)
Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Graham Neubig <neubig@gmail.com>
2024-05-17 06:11:32 +05:30
Frank Xu 9856e76c1f add BrowseInteractiveAction in dummy agent (#1852) 2024-05-17 00:04:17 +00:00
Robert Brennan 49147bf13a add fix:lint command (#1848) 2024-05-16 18:21:31 -04:00
dependabot[bot] fff10402e3 Bump pyarrow from 16.0.0 to 16.1.0 (#1841)
Bumps [pyarrow](https://github.com/apache/arrow) from 16.0.0 to 16.1.0.
- [Commits](https://github.com/apache/arrow/compare/go/v16.0.0...go/v16.1.0)

---
updated-dependencies:
- dependency-name: pyarrow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 22:21:20 +00:00
Frank Xu 35e7157565 Make screenshot fill up the whole browser panel (#1846)
* fix frontend browsing screenshot, allow link following in MD

* make screenshot auto scale and fill the whole browser panel
2024-05-16 22:10:48 +00:00
Xingyao Wang 0cb707bc9d fix(sandbox): ssh_box parsing (#1831)
* fix ssh_box error parsing

* Add type check

---------

Co-authored-by: Graham Neubig <neubig@gmail.com>
Co-authored-by: OpenDevinBot <bot@opendevin.com>
2024-05-16 18:03:34 -04:00
Engel Nyst b3a45ed7fe Fix workspace paths defaults (#1845)
* workspace_mount_path is set to the workspace_base if unset

* unit tests for paths

* workspace_base is absolute path
2024-05-16 17:53:31 -04:00
Xingyao Wang be1aef5863 set user.name and user.email for opendevin (#1842) 2024-05-16 17:50:32 -04:00
dependabot[bot] f55e5d00ca Bump web-vitals from 2.1.4 to 3.5.2 in /frontend (#1843) 2024-05-16 18:12:13 +00:00
Xingyao Wang e31f8b8322 automatically get agent version for eval (#1844) 2024-05-16 13:39:00 -04:00
dependabot[bot] 70f3a3c80d Bump litellm from 1.37.9 to 1.37.12 (#1839)
Bumps [litellm](https://github.com/BerriAI/litellm) from 1.37.9 to 1.37.12.
- [Release notes](https://github.com/BerriAI/litellm/releases)
- [Commits](https://github.com/BerriAI/litellm/compare/v1.37.9...v1.37.12)

---
updated-dependencies:
- dependency-name: litellm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 13:38:37 -04:00
dependabot[bot] 77ce5f3e9d Bump pre-commit from 3.7.0 to 3.7.1 (#1840)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.7.0 to 3.7.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.7.0...v3.7.1)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-16 17:35:14 +00:00
dependabot[bot] 756b8c4149 Bump @tailwindcss/typography from 0.5.12 to 0.5.13 in /frontend (#1834)
Bumps [@tailwindcss/typography](https://github.com/tailwindlabs/tailwindcss-typography) from 0.5.12 to 0.5.13.
- [Release notes](https://github.com/tailwindlabs/tailwindcss-typography/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss-typography/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.12...v0.5.13)

---
updated-dependencies:
- dependency-name: "@tailwindcss/typography"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 12:40:17 -04:00
dependabot[bot] a0017070b3 Bump vitest from 1.5.0 to 1.6.0 in /frontend (#1836)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v1.6.0/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 12:40:09 -04:00
dependabot[bot] 7c66b45667 Bump llama-index from 0.10.36 to 0.10.37 (#1838)
Bumps [llama-index](https://github.com/run-llama/llama_index) from 0.10.36 to 0.10.37.
- [Release notes](https://github.com/run-llama/llama_index/releases)
- [Changelog](https://github.com/run-llama/llama_index/blob/main/CHANGELOG.md)
- [Commits](https://github.com/run-llama/llama_index/compare/v0.10.36...v0.10.37)

---
updated-dependencies:
- dependency-name: llama-index
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 12:39:38 -04:00
dependabot[bot] 9d9329a43d Bump react-redux from 9.1.0 to 9.1.2 in /frontend (#1835)
Bumps [react-redux](https://github.com/reduxjs/react-redux) from 9.1.0 to 9.1.2.
- [Release notes](https://github.com/reduxjs/react-redux/releases)
- [Changelog](https://github.com/reduxjs/react-redux/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reduxjs/react-redux/compare/v9.1.0...v9.1.2)

---
updated-dependencies:
- dependency-name: react-redux
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 12:39:28 -04:00
dependabot[bot] c8d717fb3a Bump @react-types/shared from 3.22.1 to 3.23.0 in /frontend (#1832)
Bumps [@react-types/shared](https://github.com/adobe/react-spectrum) from 3.22.1 to 3.23.0.
- [Release notes](https://github.com/adobe/react-spectrum/releases)
- [Commits](https://github.com/adobe/react-spectrum/compare/@react-types/shared@3.22.1...@react-types/shared@3.23.0)

---
updated-dependencies:
- dependency-name: "@react-types/shared"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 12:39:17 -04:00
Robert Brennan a4a7ad6c87 Create dependabot.yml (#1829) 2024-05-16 11:55:38 -04:00
Boxuan Li b6ff201780 Refactor integration test framework and relieve the pain of regeneration (#1818)
* Update README.md

* Fix WORKSPACE_MOUNT_PATH_IN_SANDBOX variable in regenerate.sh

* Regenerate prompts without calling real LLM

* Disable pytest warning capture

* Change planner agent prompt by a bit for demo

* Regenerate prompt files following prompt changes

* doc: elaborate on FORCE_USE_LLM

* Add another prompt change to monologue_agent for demo purpose

* Regenerate prompts with FORCE_USE_LLM=true

---------

Co-authored-by: Yufan Song <33971064+yufansong@users.noreply.github.com>
2024-05-16 08:30:29 -07:00
Leo e89cc8f19b Feat: add stream output to exec_run (#1625)
* Feat: add stream output to exec_run

* Using command timeout to control the exec_box's timeout.
* add bash -c to source command to compatible for sh.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* Feat: add stream output to SSHBox execute

Signed-off-by: ifuryst <ifuryst@gmail.com>

* fix the test case fail.

Signed-off-by: ifuryst <ifuryst@gmail.com>

* fix the test case import wrong path for method.

Signed-off-by: ifuryst <ifuryst@gmail.com>

---------

Signed-off-by: ifuryst <ifuryst@gmail.com>
2024-05-16 14:37:49 +00:00
Xingyao Wang 0fdbe1ee93 Update README.md (#1825) 2024-05-16 11:06:28 +00:00
448 changed files with 25875 additions and 12414 deletions
+6 -1
View File
@@ -6,9 +6,14 @@ coverage:
status:
patch:
default:
threshold: 10% # allow patch coverage to be lower than project coverage by at most 10%
threshold: 100% # allow patch coverage to be lower than project coverage by any amount
project:
default:
threshold: 5% # allow project coverage to drop at most 5%
comment: false
github_checks:
annotations: false
ignore:
- "agenthub/SWE_agent/**" # SWE agent is deprecated
+8 -2
View File
@@ -28,8 +28,8 @@ body:
- type: textarea
id: current-version
attributes:
label: Current Version
description: What version are you using? If you're running in docker, tell us the tag you're using (e.g. ghcr.io/opendevin/opendevin:0.3.1).
label: Current OpenDevin version
description: What version of OpenDevin are you using? If you're running in docker, tell us the tag you're using (e.g. ghcr.io/opendevin/opendevin:0.3.1).
render: bash
validations:
required: true
@@ -52,6 +52,12 @@ body:
- Model:
- Agent:
- type: textarea
id: os-version
attributes:
label: Operating System
description: What Operating System are you using? Linux, Mac OS, WSL on Windows
- type: textarea
id: repro-steps
attributes:
+15
View File
@@ -0,0 +1,15 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
- package-ecosystem: "npm" # See documentation for possible values
directory: "/frontend" # Location of package manifests
schedule:
interval: "daily"
+3
View File
@@ -10,6 +10,9 @@ on:
- main
pull_request:
env:
PERSIST_SANDBOX : "false"
jobs:
test:
runs-on: ubuntu-latest
+1 -8
View File
@@ -47,11 +47,4 @@ jobs:
- name: Install pre-commit
run: pip install pre-commit==3.7.0
- name: Run pre-commit hooks
if: github.ref != 'refs/heads/main'
run: |
git fetch https://github.com/OpenDevin/OpenDevin.git main:main && \
pre-commit run \
--files \
$(git diff --name-only $(git merge-base main $(git branch --show-current)) $(git branch --show-current) | tr '\n' ' ') \
--show-diff-on-failure \
--config ./dev_config/python/.pre-commit-config.yaml
run: pre-commit run --files opendevin/**/* agenthub/**/* evaluation/**/* --show-diff-on-failure --config ./dev_config/python/.pre-commit-config.yaml
+13 -1
View File
@@ -44,12 +44,24 @@ jobs:
echo "" >> task.txt
echo "Diff file is: ${{ github.event.pull_request.number }}.diff" >> task.txt
- name: Set up environment
run: |
curl -sSL https://install.python-poetry.org | python3 -
export PATH="/github/home/.local/bin:$PATH"
poetry install --without evaluation
poetry run playwright install --with-deps chromium
- name: Run OpenDevin
env:
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SANDBOX_TYPE: exec
run: |
WORKSPACE_MOUNT_PATH=$GITHUB_WORKSPACE python ./opendevin/core/main.py -i 50 -f task.txt -d $GITHUB_WORKSPACE
# Append path to launch poetry
export PATH="/github/home/.local/bin:$PATH"
# Append path to correctly import package, note: must set pwd at first
export PYTHONPATH=$(pwd):$PYTHONPATH
WORKSPACE_MOUNT_PATH=$GITHUB_WORKSPACE poetry run python ./opendevin/core/main.py -i 50 -f task.txt -d $GITHUB_WORKSPACE
rm task.txt
- name: Check if review file is non-empty
+61 -33
View File
@@ -7,32 +7,26 @@ concurrency:
on:
push:
branches:
- main
- main
paths-ignore:
- '**/*.md'
- 'frontend/**'
- 'docs/**'
- 'evaluation/**'
pull_request:
env:
PERSIST_SANDBOX : "false"
jobs:
integration-tests:
name: Integration Tests
integration-tests-on-linux:
name: Integration Tests on Linux
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
agent: ["SWEAgent", "PlannerAgent", "MonologueAgent", "CodeActAgent"]
sandbox: ["ssh", "exec"]
include:
- agent: "MonologueAgent"
embedding-model: "local"
- agent: "MonologueAgent"
# sufficient to have one agent testing against local sandbox
sandbox: "local"
embedding-model: "local"
- agent: "SWEAgent"
embedding-model: "none"
- agent: "PlannerAgent"
embedding-model: "none"
- agent: "CodeActAgent"
embedding-model: "none"
sandbox: ["ssh", "exec", "local"]
steps:
- uses: actions/checkout@v4
@@ -42,7 +36,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- name: Install Python dependencies using Poetry
@@ -54,23 +48,57 @@ jobs:
- name: Run Integration Tests
env:
SANDBOX_TYPE: ${{ matrix.sandbox }}
AGENT: ${{ matrix.agent }}
MAX_ITERATIONS: 10
LLM_EMBEDDING_MODEL: ${{ matrix.embedding-model }}
run: |
rm -rf workspace
mkdir workspace
WORKSPACE_BASE="$GITHUB_WORKSPACE/workspace" \
WORKSPACE_MOUNT_PATH="$GITHUB_WORKSPACE/workspace" \
poetry run pytest --cov=agenthub --cov=opendevin --cov-report=xml \
-s ./tests/integration
TEST_IN_CI=true TEST_ONLY=true ./tests/integration/regenerate.sh
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test_matrix_success:
name: All Integration Tests Passed
runs-on: ubuntu-latest
needs: [integration-tests]
integration-tests-on-mac:
name: Integration Tests on MacOS
runs-on: macos-13
if: contains(github.event.pull_request.title, 'mac') || contains(github.event.pull_request.title, 'Mac')
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
sandbox: ["ssh"]
steps:
- run: echo Done!
- uses: actions/checkout@v4
- name: Install poetry via pipx
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- name: Install Python dependencies using Poetry
run: poetry install
- name: Install & Start Docker
run: |
brew install colima docker
colima start
# For testcontainers to find the Colima socket
# https://github.com/abiosoft/colima/blob/main/docs/FAQ.md#cannot-connect-to-the-docker-daemon-at-unixvarrundockersock-is-the-docker-daemon-running
sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock
- name: Build Environment
run: make build
- name: Run Integration Tests
env:
SANDBOX_TYPE: ${{ matrix.sandbox }}
run: |
TEST_IN_CI=true TEST_ONLY=true ./tests/integration/regenerate.sh
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+17 -15
View File
@@ -7,15 +7,23 @@ concurrency:
on:
push:
branches:
- main
- main
paths-ignore:
- '**/*.md'
- 'frontend/**'
- 'docs/**'
- 'evaluation/**'
pull_request:
env:
PERSIST_SANDBOX : "false"
jobs:
test-on-macos:
name: Test on macOS
runs-on: macos-13
env:
INSTALL_DOCKER: '0' # Set to '0' to skip Docker installation
INSTALL_DOCKER: "0" # Set to '0' to skip Docker installation
strategy:
matrix:
python-version: ["3.11"]
@@ -30,7 +38,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
cache: "poetry"
- name: Install Python dependencies using Poetry
run: poetry install
@@ -49,7 +57,7 @@ jobs:
run: make build
- name: Run Tests
run: poetry run pytest --cov=agenthub --cov=opendevin --cov-report=xml ./tests/unit -k "not test_sandbox"
run: poetry run pytest --forked --cov=agenthub --cov=opendevin --cov-report=xml ./tests/unit -k "not test_sandbox"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
@@ -59,7 +67,7 @@ jobs:
name: Test on Linux
runs-on: ubuntu-latest
env:
INSTALL_DOCKER: '0' # Set to '0' to skip Docker installation
INSTALL_DOCKER: "0" # Set to '0' to skip Docker installation
strategy:
matrix:
python-version: ["3.11"]
@@ -74,7 +82,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
cache: "poetry"
- name: Install Python dependencies using Poetry
run: poetry install --without evaluation
@@ -83,7 +91,7 @@ jobs:
run: make build
- name: Run Tests
run: poetry run pytest --cov=agenthub --cov=opendevin --cov-report=xml ./tests/unit -k "not test_sandbox"
run: poetry run pytest --forked --cov=agenthub --cov=opendevin --cov-report=xml ./tests/unit -k "not test_sandbox"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
@@ -102,8 +110,8 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'poetry'
python-version: "3.11"
cache: "poetry"
- name: Install Python dependencies using Poetry
run: poetry install
@@ -119,9 +127,3 @@ jobs:
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test_matrix_success:
name: All Mac/Linux Tests Passed
runs-on: ubuntu-latest
needs: [test-on-macos, test-on-linux, test-for-sandbox]
steps:
- run: echo Done!
+3 -1
View File
@@ -126,6 +126,7 @@ env/
venv/
ENV/
env.bak/
.env.bak
venv.bak/
*venv/
@@ -202,7 +203,8 @@ cache
# configuration
config.toml
evaluation/swe_bench/eval_workspace
config.toml.bak
evaluation/swe_bench/eval_workspace*
evaluation/outputs
evaluation/evaluation_outputs
test_results*
+8 -2
View File
@@ -5,8 +5,8 @@ This guide is for people working on OpenDevin and editing the source code.
### 1. Requirements
* Linux, Mac OS, or [WSL on Windows](https://learn.microsoft.com/en-us/windows/wsl/install)
* [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!)
* [Python](https://www.python.org/downloads/) >= 3.11
* [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!)
* [Python](https://www.python.org/downloads/) = 3.11
* [NodeJS](https://nodejs.org/en/download/package-manager) >= 18.17.1
* [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer) >= 1.8
@@ -45,6 +45,7 @@ To configure the LM of your choice, follow these steps:
make setup-config
```
This command will prompt you to enter the LLM API key, model name, and other variables ensuring that OpenDevin is tailored to your specific needs. Note that the model name will apply only when you run headless. If you use the UI, please set the model in the UI.
Set `persist_sandbox` to false if you want to use clean sandbox for each task. If `persist_sandbox` is set to true, you will need to set the `ssh_password` as well.
**Note on Alternative Models:**
Some alternative models may prove more challenging to tame than others. Fear not, brave adventurer! We shall soon unveil LLM-specific documentation to guide you on your quest. And if you've already mastered the art of wielding a model other than OpenAI's GPT, we encourage you to [share your setup instructions with us](https://github.com/OpenDevin/OpenDevin/issues/417).
@@ -94,3 +95,8 @@ poetry run pytest ./tests/unit/test_sandbox.py
#### Integration tests
Please refer to [this README](./tests/integration/README.md) for details.
### 9. Add or update dependency
1. Add your dependency in `pyproject.toml` or use `poetry add xxx`
2. Update the poetry.lock file via `poetry lock --no-update`
+21 -4
View File
@@ -7,7 +7,7 @@ BACKEND_PORT = 3000
BACKEND_HOST = "127.0.0.1:$(BACKEND_PORT)"
FRONTEND_PORT = 3001
DEFAULT_WORKSPACE_DIR = "./workspace"
DEFAULT_MODEL = "gpt-3.5-turbo"
DEFAULT_MODEL = "gpt-4o"
CONFIG_FILE = config.toml
PRECOMMIT_CONFIG_PATH = "./dev_config/python/.pre-commit-config.yaml"
@@ -130,8 +130,9 @@ pull-docker-image:
install-python-dependencies:
@echo "$(GREEN)Installing Python dependencies...$(RESET)"
poetry env use python3.11
@if [ "$(shell uname)" = "Darwin" ]; then \
echo "$(BLUE)Installing `chroma-hnswlib`...$(RESET)"; \
echo "$(BLUE)Installing chroma-hnswlib...$(RESET)"; \
export HNSWLIB_NO_NATIVE=1; \
poetry run pip install chroma-hnswlib; \
fi
@@ -141,7 +142,14 @@ install-python-dependencies:
poetry run pip install playwright; \
poetry run playwright install chromium; \
else \
poetry run playwright install --with-deps chromium; \
if [ ! -f cache/playwright_chromium_is_installed.txt ]; then \
echo "Running playwright install --with-deps chromium..."; \
poetry run playwright install --with-deps chromium; \
mkdir -p cache; \
touch cache/playwright_chromium_is_installed.txt; \
else \
echo "Setup already done. Skipping playwright installation."; \
fi \
fi
@echo "$(GREEN)Python dependencies installed successfully.$(RESET)"
@@ -164,7 +172,7 @@ install-precommit-hooks:
lint-backend:
@echo "$(YELLOW)Running linters...$(RESET)"
@poetry run pre-commit run --files $$(git diff --name-only $$(git merge-base main $$(git branch --show-current)) $$(git branch --show-current) | tr '\n' ' ') --show-diff-on-failure --config $(PRECOMMIT_CONFIG_PATH)
@poetry run pre-commit run --files opendevin/**/* agenthub/**/* evaluation/**/* --show-diff-on-failure --config $(PRECOMMIT_CONFIG_PATH)
lint-frontend:
@echo "$(YELLOW)Running linters for frontend...$(RESET)"
@@ -225,6 +233,15 @@ setup-config-prompts:
workspace_dir=$${workspace_dir:-$(DEFAULT_WORKSPACE_DIR)}; \
echo "workspace_base=\"$$workspace_dir\"" >> $(CONFIG_FILE).tmp
@read -p "Do you want to persist the sandbox container? [true/false] [default: true]: " persist_sandbox; \
persist_sandbox=$${persist_sandbox:-true}; \
if [ "$$persist_sandbox" = "true" ]; then \
read -p "Enter a password for the sandbox container: " ssh_password; \
echo "ssh_password=\"$$ssh_password\"" >> $(CONFIG_FILE).tmp; \
else \
echo "persist_sandbox=$$persist_sandbox" >> $(CONFIG_FILE).tmp; \
fi
@echo "" >> $(CONFIG_FILE).tmp
@echo "[llm]" >> $(CONFIG_FILE).tmp
+24 -14
View File
@@ -27,14 +27,15 @@
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2i1iqdag6-bVmvamiPA9EZUu7oCO6KhA"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community"></a>
<a href="https://discord.gg/ESHStjSjD4"><img src="https://img.shields.io/badge/Discord-Join%20Us-purple?logo=discord&logoColor=white&style=for-the-badge" alt="Join our Discord community"></a>
<br/>
<a href="https://xwang.dev/blog/2024/opendevin-codeact-1.0-swebench/"><img src="https://img.shields.io/badge/SWE--bench%20Lite-21.0%25-green?style=for-the-badge" alt="SWE-bench "></a>
<a href="https://huggingface.co/spaces/OpenDevin/evaluation"><img src="https://img.shields.io/badge/SWE--bench%20Lite-25.0%25-green?style=for-the-badge" alt="SWE-bench "></a>
<a href="https://codecov.io/github/opendevin/opendevin?branch=main"><img alt="CodeCov" src="https://img.shields.io/codecov/c/github/opendevin/opendevin?style=for-the-badge"></a>
</div>
<!-- PROJECT LOGO -->
<div align="center">
<img src="./docs/static/img/logo.png" alt="Logo" width="200" height="200">
<h1 align="center">OpenDevin: Code Less, Make More</h1>
<a href="https://opendevin.github.io/OpenDevin/"><img src="https://img.shields.io/badge/Documenation-OpenDevin-blue?logo=googledocs&logoColor=white&style=for-the-badge" alt="Check out the documentation"></a>
<a href="https://opendevin.github.io/OpenDevin/"><img src="https://img.shields.io/badge/Documentation-OpenDevin-blue?logo=googledocs&logoColor=white&style=for-the-badge" alt="Check out the documentation"></a>
</div>
<hr>
@@ -44,26 +45,35 @@ OpenDevin agents collaborate with human developers to write code, fix bugs, and
![App screenshot](./docs/static/img/screenshot.png)
## ⚡ Quick Start
You can run OpenDevin with Docker. It works best with the most recent
version of Docker, `26.0.0`.
## ⚡ Getting Started
The easiest way to run OpenDevin is inside a Docker container. It works best with the most recent version of Docker, `26.0.0`.
You must be using Linux, Mac OS, or WSL on Windows.
To start OpenDevin in a docker container, run the following commands in your terminal:
> [!WARNING]
> When you run the following command, files in `./workspace` may be modified or deleted.
```bash
#The directory you want OpenDevin to modify. MUST be an absolute path!
export WORKSPACE_BASE=$(pwd)/workspace;
docker run \
-it \
OPENDEVIN_WORKSPACE=$(pwd)/workspace
docker run -it \
--pull=always \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-e PERSIST_SANDBOX="true" \
-e SSH_PASSWORD="make something up here" \
-e WORKSPACE_MOUNT_PATH=$OPENDEVIN_WORKSPACE \
-v $OPENDEVIN_WORKSPACE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
ghcr.io/opendevin/opendevin:0.5
--name opendevin-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/opendevin/opendevin:0.6
```
You'll find OpenDevin running at [http://localhost:3000](http://localhost:3000) with access to `./workspace`. To have OpenDevin operate on your code, place it in `./workspace`.
OpenDevin will only have access to this workspace folder. The rest of your system will not be affected as it runs in a secured docker sandbox.
## 🚀 Documentation
To learn more about the project, and for tips on using OpenDevin,
@@ -89,7 +99,7 @@ For details, please check [CONTRIBUTING.md](./CONTRIBUTING.md).
Whether you're a developer, a researcher, or simply enthusiastic about OpenDevin, we'd love to have you in our community.
Let's make software engineering better together!
- [Slack workspace](https://join.slack.com/t/opendevin/shared_invite/zt-2ggtwn3k5-PvAA2LUmqGHVZ~XzGq~ILw) - Here we talk about research, architecture, and future development.
- [Slack workspace](https://join.slack.com/t/opendevin/shared_invite/zt-2jsrl32uf-fTeeFjNyNYxqSZt5NPY3fA) - Here we talk about research, architecture, and future development.
- [Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback.
## 📈 Progress
+23 -14
View File
@@ -6,9 +6,9 @@ from opendevin.events.action import (
FileWriteAction,
MessageAction,
)
from opendevin.events.observation import Observation
from opendevin.events.serialization.event import event_to_memory
from opendevin.llm.llm import LLM
from opendevin.runtime.tools import RuntimeTool
from .parser import parse_command
from .prompts import (
@@ -21,27 +21,24 @@ from .prompts import (
class SWEAgent(Agent):
VERSION = '1.0'
DEPRECATED = True
"""
An attempt to recreate swe_agent with output parsing, prompting style, and Application Computer Interface (ACI).
SWE-agent includes ACI functions like 'goto', 'search_for', 'edit', 'scroll', 'run'
"""
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
def __init__(self, llm: LLM):
super().__init__(llm)
self.memory_window = 4
self.max_retries = 2
self.running_memory: list[str] = []
self.cur_file: str = ''
self.cur_line: int = 0
def _remember(self, action: Action, observation: Observation) -> None:
"""Agent has a limited memory of the few steps implemented as a queue"""
memory = MEMORY_FORMAT(event_to_memory(action), event_to_memory(observation))
self.running_memory.append(memory)
def _think_act(self, messages: list[dict]) -> tuple[Action, str]:
resp = self.llm.completion(
resp = self.llm.do_completion(
messages=messages,
temperature=0.05,
)
@@ -67,24 +64,36 @@ class SWEAgent(Agent):
2. Perform think-act - prompt model for action and reasoning
3. Catch errors - ensure model takes action (5 attempts max)
"""
for prev_action, obs in state.updated_info:
self._remember(prev_action, obs)
# retrieve short term memories from state.history, up to memory_window
memory_window = min(self.memory_window, len(state.history))
running_memory: list[str] = []
for prev_action, obs in state.history[-memory_window:]:
running_memory.append(
MEMORY_FORMAT(event_to_memory(prev_action), event_to_memory(obs))
)
goal = state.get_current_user_intent()
# always in the prompt if they exist: file and line
prompt = STEP_PROMPT(goal, self.cur_file, self.cur_line)
# prepare messages
msgs = [
{'content': SYSTEM_MESSAGE, 'role': 'system'},
{'content': prompt, 'role': 'user'},
]
if len(self.running_memory) > 0:
context = CONTEXT_PROMPT(self.running_memory, self.memory_window)
# insert memories
if len(running_memory) > 0:
context = CONTEXT_PROMPT(running_memory, self.memory_window)
msgs.insert(1, {'content': context, 'role': 'user'})
# clrs = [''] * (len(msgs)-2) + ['\033[0;36m', '\033[0;35m']
# print('\n\n'.join([c+m['content']+'\033[0m' for c, m in zip(clrs, msgs)]))
# send it over
action, thought = self._think_act(messages=msgs)
# be robust with malformed responses
start_msg_len = len(msgs)
while not action and len(msgs) < self.max_retries + start_msg_len:
error = NO_ACTION(thought)
@@ -100,9 +109,9 @@ class SWEAgent(Agent):
return action
def search_memory(self, query: str) -> list[str]:
return [item for item in self.running_memory if query in item]
# return [item for item in self.running_memory if query in item]
raise NotImplementedError('Search_memory not implemented currently')
def reset(self) -> None:
"""Used to reset the agent"""
self.running_memory = []
super().reset()
+5 -4
View File
@@ -92,7 +92,7 @@ Notes:
- To execute multiple commands you should write them down in your thoughts section so you can remember it on the next step and execute them then.
- The only commands you are not capable of executing are interactive commands like `python` or `node` by themselves.
- If you think that you have completed the task that has been given to you based on your previous actions and outputs then use ``` exit ``` as the command to let the system know that you are done.
- DO NOT make any copies of your previous memories those will be provided to you at each step, making copies just wastes time and energy. Think smarter not harder.
- DO NOT make any copies of your previous memories, those will be provided to you at each step, making copies just wastes time and energy. Think smarter not harder.
- The write and edit commands requires proper indentation in the content section ex. `write hw.py def hello():\n print(\'Hello World\')` this is how you would have to format your write command.
- The white spaces matter as the code changes will be added to the code so they must have proper syntax.
@@ -114,8 +114,8 @@ Do not provide anything extra just your thought and action.
"""
SYSTEM_MESSAGE = f"""SYSTEM INFO:
You am an autonomous coding agent, here to provide solutions for coding issues.
You have been designed to assist you with a wide range of programming tasks, from code editing and debugging to testing and deployment.
You are an autonomous coding agent, here to provide solutions for coding issues.
You have been designed to assist with a wide range of programming tasks, from code editing and debugging to testing and deployment.
You have access to a variety of tools and commands that you can use to help you solve problems efficiently.
{GENERAL_GUIDELINES}
@@ -171,8 +171,9 @@ Begin with your thought about the next step and then come up with an action to p
""".strip()
def unpack_dict(data: dict, restrict: list[str] = []):
def unpack_dict(data: dict, restrict: list[str] | None = None):
lines = []
restrict = [] if restrict is None else restrict
for key, value in data.items():
if key in restrict:
continue
+4
View File
@@ -10,7 +10,9 @@ load_dotenv()
from . import ( # noqa: E402
SWE_agent,
browsing_agent,
codeact_agent,
codeact_swe_agent,
delegator_agent,
dummy_agent,
monologue_agent,
@@ -20,10 +22,12 @@ from . import ( # noqa: E402
__all__ = [
'monologue_agent',
'codeact_agent',
'codeact_swe_agent',
'planner_agent',
'SWE_agent',
'delegator_agent',
'dummy_agent',
'browsing_agent',
]
for agent in all_microagents.values():
+16
View File
@@ -0,0 +1,16 @@
# Browsing Agent Framework
This folder implements the basic BrowserGym [demo agent](https://github.com/ServiceNow/BrowserGym/tree/main/demo_agent) that enables full-featured web browsing.
## Test run
Note that for browsing tasks, GPT-4 is usually a requirement to get reasonable results, due to the complexity of the web page structures.
```
poetry run python ./opendevin/core/main.py \
-i 10 \
-t "tell me the usa's president using google search" \
-c BrowsingAgent \
-m gpt-4o-2024-05-13
```
+5
View File
@@ -0,0 +1,5 @@
from opendevin.controller.agent import Agent
from .browsing_agent import BrowsingAgent
Agent.register('BrowsingAgent', BrowsingAgent)
+169
View File
@@ -0,0 +1,169 @@
import ast
from browsergym.core.action.highlevel import HighLevelActionSet
from browsergym.utils.obs import flatten_axtree_to_str
from opendevin.controller.agent import Agent
from opendevin.controller.state.state import State
from opendevin.core.logger import opendevin_logger as logger
from opendevin.events.action import (
Action,
AgentFinishAction,
BrowseInteractiveAction,
MessageAction,
)
from opendevin.events.observation import BrowserOutputObservation
from opendevin.llm.llm import LLM
from opendevin.runtime.plugins import (
PluginRequirement,
)
from opendevin.runtime.tools import RuntimeTool
def parse_response(response: str) -> Action:
if '```' not in response:
# unexpected response format, message back to user
return MessageAction(response)
thought = response.split('```')[0].strip()
action_str = response.split('```')[1].strip()
# handle send message to user function call in BrowserGym
for sub_action in action_str.split('\n'):
if 'send_msg_to_user(' in sub_action:
tree = ast.parse(sub_action)
args = tree.body[0].value.args # type: ignore
return MessageAction(args[0].value)
return BrowseInteractiveAction(browser_actions=action_str, thought=thought)
class BrowsingAgent(Agent):
VERSION = '1.0'
"""
An agent that interacts with the browser.
"""
sandbox_plugins: list[PluginRequirement] = []
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
def __init__(
self,
llm: LLM,
) -> None:
"""
Initializes a new instance of the BrowsingAgent class.
Parameters:
- llm (LLM): The llm to be used by this agent
"""
super().__init__(llm)
self.action_space = HighLevelActionSet(
# see https://github.com/ServiceNow/BrowserGym/blob/main/core/src/browsergym/core/action/highlevel.py for more details
subsets=[
'chat',
'bid',
'nav',
], # define a configurable action space, with chat functionality, web navigation, and webpage grounding using accessibility tree and HTML.
strict=False, # less strict on the parsing of the actions
multiaction=True, # enable to agent to take multiple actions at once
)
self.reset()
def reset(self) -> None:
"""
Resets the Browsing Agent.
"""
super().reset()
self.cost_accumulator = 0
def step(self, state: State) -> Action:
"""
Performs one step using the Browsing Agent.
This includes gathering information on previous steps and prompting the model to make a browsing command to execute.
Parameters:
- state (State): used to get updated info
Returns:
- BrowseInteractiveAction(browsergym_command) - BrowserGym commands to run
- MessageAction(content) - Message action to run (e.g. ask for clarification)
- AgentFinishAction() - end the interaction
"""
goal = state.get_current_user_intent()
messages = []
prev_actions = ''
cur_axtree_txt = ''
error_prefix = ''
last_obs = None
for prev_action, obs in state.history:
if isinstance(prev_action, BrowseInteractiveAction):
prev_actions += f'{prev_action.browser_actions}\n'
last_obs = obs
elif (
isinstance(prev_action, MessageAction) and prev_action.source != 'user'
):
# agent has responded, task finish.
return AgentFinishAction()
if isinstance(last_obs, BrowserOutputObservation):
if last_obs.error:
# add error recovery prompt prefix
error_prefix = f'IMPORTANT! Last action is incorrect:\n{last_obs.last_browser_action}\nThink again with the current observation of the page.\n'
cur_axtree_txt = flatten_axtree_to_str(last_obs.axtree_object)
system_msg = f"""\
# Instructions
Review the current state of the page and all other information to find the best
possible next action to accomplish your goal. Your answer will be interpreted
and executed by a program, make sure to follow the formatting instructions.
# Goal:
{goal}
# Action Space
{self.action_space.describe(with_long_description=False, with_examples=True)}
"""
messages.append({'role': 'system', 'content': system_msg})
prompt = f"""\
{error_prefix}
# Current Accessibility Tree:
{cur_axtree_txt}
# Previous Actions
{prev_actions}
Here is an example with chain of thought of a valid action when clicking on a button:
"
In order to accomplish my goal I need to click on the button with bid 12
```click("12")```
"
""".strip()
messages.append({'role': 'user', 'content': prompt})
response = self.llm.completion(
messages=messages,
temperature=0.0,
)
self.log_cost(response)
action_resp = response['choices'][0]['message']['content']
logger.info(prompt)
logger.info(action_resp)
return parse_response(action_resp)
def search_memory(self, query: str) -> list[str]:
raise NotImplementedError('Implement this abstract method')
def log_cost(self, response):
# TODO: refactor to unified cost tracking
try:
cur_cost = self.llm.completion_cost(response)
except Exception:
cur_cost = 0
self.cost_accumulator += cur_cost
logger.info(
'Cost: %.2f USD | Accumulated Cost: %.2f USD',
cur_cost,
self.cost_accumulator,
)
+787
View File
@@ -0,0 +1,787 @@
import abc
import difflib
import logging
import platform
from copy import deepcopy
from dataclasses import asdict, dataclass
from textwrap import dedent
from typing import Literal, Union
from warnings import warn
from browsergym.core.action.base import AbstractActionSet
from browsergym.core.action.highlevel import HighLevelActionSet
from browsergym.core.action.python import PythonActionSet
from opendevin.runtime.browser.browser_env import BrowserEnv
from .utils import (
ParseError,
parse_html_tags_raise,
)
@dataclass
class Flags:
use_html: bool = True
use_ax_tree: bool = False
drop_ax_tree_first: bool = True # This flag is no longer active TODO delete
use_thinking: bool = False
use_error_logs: bool = False
use_past_error_logs: bool = False
use_history: bool = False
use_action_history: bool = False
use_memory: bool = False
use_diff: bool = False
html_type: str = 'pruned_html'
use_concrete_example: bool = True
use_abstract_example: bool = False
multi_actions: bool = False
action_space: Literal[
'python', 'bid', 'coord', 'bid+coord', 'bid+nav', 'coord+nav', 'bid+coord+nav'
] = 'bid'
is_strict: bool = False
# This flag will be automatically disabled `if not chat_model_args.has_vision()`
use_screenshot: bool = True
enable_chat: bool = False
max_prompt_tokens: int = 100_000
extract_visible_tag: bool = False
extract_coords: Literal['False', 'center', 'box'] = 'False'
extract_visible_elements_only: bool = False
demo_mode: Literal['off', 'default', 'only_visible_elements'] = 'off'
def copy(self):
return deepcopy(self)
def asdict(self):
"""Helper for JSON serializble requirement."""
return asdict(self)
@classmethod
def from_dict(self, flags_dict):
"""Helper for JSON serializble requirement."""
if isinstance(flags_dict, Flags):
return flags_dict
if not isinstance(flags_dict, dict):
raise ValueError(
f'Unregcognized type for flags_dict of type {type(flags_dict)}.'
)
return Flags(**flags_dict)
class PromptElement:
"""Base class for all prompt elements. Prompt elements can be hidden.
Prompt elements are used to build the prompt. Use flags to control which
prompt elements are visible. We use class attributes as a convenient way
to implement static prompts, but feel free to override them with instance
attributes or @property decorator."""
_prompt = ''
_abstract_ex = ''
_concrete_ex = ''
def __init__(self, visible: bool = True) -> None:
"""Prompt element that can be hidden.
Parameters
----------
visible : bool, optional
Whether the prompt element should be visible, by default True. Can
be a callable that returns a bool. This is useful when a specific
flag changes during a shrink iteration.
"""
self._visible = visible
@property
def prompt(self):
"""Avoid overriding this method. Override _prompt instead."""
return self._hide(self._prompt)
@property
def abstract_ex(self):
"""Useful when this prompt element is requesting an answer from the llm.
Provide an abstract example of the answer here. See Memory for an
example.
Avoid overriding this method. Override _abstract_ex instead
"""
return self._hide(self._abstract_ex)
@property
def concrete_ex(self):
"""Useful when this prompt element is requesting an answer from the llm.
Provide a concrete example of the answer here. See Memory for an
example.
Avoid overriding this method. Override _concrete_ex instead
"""
return self._hide(self._concrete_ex)
@property
def is_visible(self):
"""Handle the case where visible is a callable."""
visible = self._visible
if callable(visible):
visible = visible()
return visible
def _hide(self, value):
"""Return value if visible is True, else return empty string."""
if self.is_visible:
return value
else:
return ''
def _parse_answer(self, text_answer) -> dict:
if self.is_visible:
return self._parse_answer(text_answer)
else:
return {}
class Shrinkable(PromptElement, abc.ABC):
@abc.abstractmethod
def shrink(self) -> None:
"""Implement shrinking of this prompt element.
You need to recursively call all shrinkable elements that are part of
this prompt. You can also implement a shrinking strategy for this prompt.
Shrinking is can be called multiple times to progressively shrink the
prompt until it fits max_tokens. Default max shrink iterations is 20.
"""
pass
class Truncater(Shrinkable):
"""A prompt element that can be truncated to fit the context length of the LLM.
Of course, it will be great that we never have to use the functionality here to `shrink()` the prompt.
Extend this class for prompt elements that can be truncated. Usually long observations such as AxTree or HTML.
"""
def __init__(self, visible, shrink_speed=0.3, start_truncate_iteration=10):
super().__init__(visible=visible)
self.shrink_speed = shrink_speed # the percentage shrunk in each iteration
self.start_truncate_iteration = (
start_truncate_iteration # the iteration to start truncating
)
self.shrink_calls = 0
self.deleted_lines = 0
def shrink(self) -> None:
if self.is_visible and self.shrink_calls >= self.start_truncate_iteration:
# remove the fraction of _prompt
lines = self._prompt.splitlines()
new_line_count = int(len(lines) * (1 - self.shrink_speed))
self.deleted_lines += len(lines) - new_line_count
self._prompt = '\n'.join(lines[:new_line_count])
self._prompt += (
f'\n... Deleted {self.deleted_lines} lines to reduce prompt size.'
)
self.shrink_calls += 1
def fit_tokens(
shrinkable: Shrinkable,
max_prompt_chars=None,
max_iterations=20,
):
"""Shrink a prompt element until it fits max_tokens.
Parameters
----------
shrinkable : Shrinkable
The prompt element to shrink.
max_prompt_chars : int
The maximum number of chars allowed.
max_iterations : int, optional
The maximum number of shrink iterations, by default 20.
model_name : str, optional
The name of the model used when tokenizing.
Returns
-------
str : the prompt after shrinking.
"""
if max_prompt_chars is None:
return shrinkable.prompt
for _ in range(max_iterations):
prompt = shrinkable.prompt
if isinstance(prompt, str):
prompt_str = prompt
elif isinstance(prompt, list):
prompt_str = '\n'.join([p['text'] for p in prompt if p['type'] == 'text'])
else:
raise ValueError(f'Unrecognized type for prompt: {type(prompt)}')
n_chars = len(prompt_str)
if n_chars <= max_prompt_chars:
return prompt
shrinkable.shrink()
logging.info(
dedent(
f"""\
After {max_iterations} shrink iterations, the prompt is still
{len(prompt_str)} chars (greater than {max_prompt_chars}). Returning the prompt as is."""
)
)
return prompt
class HTML(Truncater):
def __init__(self, html, visible: bool = True, prefix='') -> None:
super().__init__(visible=visible, start_truncate_iteration=5)
self._prompt = f'\n{prefix}HTML:\n{html}\n'
class AXTree(Truncater):
def __init__(
self, ax_tree, visible: bool = True, coord_type=None, prefix=''
) -> None:
super().__init__(visible=visible, start_truncate_iteration=10)
if coord_type == 'center':
coord_note = """\
Note: center coordinates are provided in parenthesis and are
relative to the top left corner of the page.\n\n"""
elif coord_type == 'box':
coord_note = """\
Note: bounding box of each object are provided in parenthesis and are
relative to the top left corner of the page.\n\n"""
else:
coord_note = ''
self._prompt = f'\n{prefix}AXTree:\n{coord_note}{ax_tree}\n'
class Error(PromptElement):
def __init__(self, error, visible: bool = True, prefix='') -> None:
super().__init__(visible=visible)
self._prompt = f'\n{prefix}Error from previous action:\n{error}\n'
class Observation(Shrinkable):
"""Observation of the current step.
Contains the html, the accessibility tree and the error logs.
"""
def __init__(self, obs, flags: Flags) -> None:
super().__init__()
self.flags = flags
self.obs = obs
self.html = HTML(obs[flags.html_type], visible=flags.use_html, prefix='## ')
self.ax_tree = AXTree(
obs['axtree_txt'],
visible=flags.use_ax_tree,
coord_type=flags.extract_coords,
prefix='## ',
)
self.error = Error(
obs['last_action_error'],
visible=flags.use_error_logs and obs['last_action_error'],
prefix='## ',
)
def shrink(self):
self.ax_tree.shrink()
self.html.shrink()
@property
def _prompt(self) -> str: # type: ignore
return f'\n# Observation of current step:\n{self.html.prompt}{self.ax_tree.prompt}{self.error.prompt}\n\n'
def add_screenshot(self, prompt):
if self.flags.use_screenshot:
if isinstance(prompt, str):
prompt = [{'type': 'text', 'text': prompt}]
img_url = BrowserEnv.image_to_jpg_base64_url(
self.obs['screenshot'], add_data_prefix=True
)
prompt.append({'type': 'image_url', 'image_url': img_url})
return prompt
class MacNote(PromptElement):
def __init__(self) -> None:
super().__init__(visible=platform.system() == 'Darwin')
self._prompt = '\nNote: you are on mac so you should use Meta instead of Control for Control+C etc.\n'
class BeCautious(PromptElement):
def __init__(self, visible: bool = True) -> None:
super().__init__(visible=visible)
self._prompt = """\
\nBe very cautious. Avoid submitting anything before verifying the effect of your
actions. Take the time to explore the effect of safe actions first. For example
you can fill a few elements of a form, but don't click submit before verifying
that everything was filled correctly.\n"""
class GoalInstructions(PromptElement):
def __init__(self, goal, visible: bool = True) -> None:
super().__init__(visible)
self._prompt = f"""\
# Instructions
Review the current state of the page and all other information to find the best
possible next action to accomplish your goal. Your answer will be interpreted
and executed by a program, make sure to follow the formatting instructions.
## Goal:
{goal}
"""
class ChatInstructions(PromptElement):
def __init__(self, chat_messages, visible: bool = True) -> None:
super().__init__(visible)
self._prompt = """\
# Instructions
You are a UI Assistant, your goal is to help the user perform tasks using a web browser. You can
communicate with the user via a chat, in which the user gives you instructions and in which you
can send back messages. You have access to a web browser that both you and the user can see,
and with which only you can interact via specific commands.
Review the instructions from the user, the current state of the page and all other information
to find the best possible next action to accomplish your goal. Your answer will be interpreted
and executed by a program, make sure to follow the formatting instructions.
## Chat messages:
"""
self._prompt += '\n'.join(
[
f"""\
- [{msg['role']}] {msg['message']}"""
for msg in chat_messages
]
)
class SystemPrompt(PromptElement):
_prompt = """\
You are an agent trying to solve a web task based on the content of the page and
a user instructions. You can interact with the page and explore. Each time you
submit an action it will be sent to the browser and you will receive a new page."""
class MainPrompt(Shrinkable):
def __init__(
self,
obs_history,
actions,
memories,
thoughts,
flags: Flags,
) -> None:
super().__init__()
self.flags = flags
self.history = History(obs_history, actions, memories, thoughts, flags)
if self.flags.enable_chat:
self.instructions: Union[ChatInstructions, GoalInstructions] = (
ChatInstructions(obs_history[-1]['chat_messages'])
)
else:
if (
'chat_messages' in obs_history[-1]
and sum(
[msg['role'] == 'user' for msg in obs_history[-1]['chat_messages']]
)
> 1
):
logging.warning(
'Agent is in goal mode, but multiple user messages are present in the chat. Consider switching to `enable_chat=True`.'
)
self.instructions = GoalInstructions(obs_history[-1]['goal'])
self.obs = Observation(obs_history[-1], self.flags)
self.action_space = ActionSpace(self.flags)
self.think = Think(visible=flags.use_thinking)
self.memory = Memory(visible=flags.use_memory)
@property
def _prompt(self) -> str: # type: ignore
prompt = f"""\
{self.instructions.prompt}\
{self.obs.prompt}\
{self.history.prompt}\
{self.action_space.prompt}\
{self.think.prompt}\
{self.memory.prompt}\
"""
if self.flags.use_abstract_example:
prompt += f"""
# Abstract Example
Here is an abstract version of the answer with description of the content of
each tag. Make sure you follow this structure, but replace the content with your
answer:
{self.think.abstract_ex}\
{self.memory.abstract_ex}\
{self.action_space.abstract_ex}\
"""
if self.flags.use_concrete_example:
prompt += f"""
# Concrete Example
Here is a concrete example of how to format your answer.
Make sure to follow the template with proper tags:
{self.think.concrete_ex}\
{self.memory.concrete_ex}\
{self.action_space.concrete_ex}\
"""
return self.obs.add_screenshot(prompt)
def shrink(self):
self.history.shrink()
self.obs.shrink()
def _parse_answer(self, text_answer):
ans_dict = {}
ans_dict.update(self.think._parse_answer(text_answer))
ans_dict.update(self.memory._parse_answer(text_answer))
ans_dict.update(self.action_space._parse_answer(text_answer))
return ans_dict
class ActionSpace(PromptElement):
def __init__(self, flags: Flags) -> None:
super().__init__()
self.flags = flags
self.action_space = _get_action_space(flags)
self._prompt = (
f'# Action space:\n{self.action_space.describe()}{MacNote().prompt}\n'
)
self._abstract_ex = f"""
<action>
{self.action_space.example_action(abstract=True)}
</action>
"""
self._concrete_ex = f"""
<action>
{self.action_space.example_action(abstract=False)}
</action>
"""
def _parse_answer(self, text_answer):
ans_dict = parse_html_tags_raise(
text_answer, keys=['action'], merge_multiple=True
)
try:
# just check if action can be mapped to python code but keep action as is
# the environment will be responsible for mapping it to python
self.action_space.to_python_code(ans_dict['action'])
except Exception as e:
raise ParseError(
f'Error while parsing action\n: {e}\n'
'Make sure your answer is restricted to the allowed actions.'
)
return ans_dict
def _get_action_space(flags: Flags) -> AbstractActionSet:
match flags.action_space:
case 'python':
action_space = PythonActionSet(strict=flags.is_strict)
if flags.multi_actions:
warn(
f'Flag action_space={repr(flags.action_space)} incompatible with multi_actions={repr(flags.multi_actions)}.',
stacklevel=2,
)
if flags.demo_mode != 'off':
warn(
f'Flag action_space={repr(flags.action_space)} incompatible with demo_mode={repr(flags.demo_mode)}.',
stacklevel=2,
)
return action_space
case 'bid':
action_subsets = ['chat', 'bid']
case 'coord':
action_subsets = ['chat', 'coord']
case 'bid+coord':
action_subsets = ['chat', 'bid', 'coord']
case 'bid+nav':
action_subsets = ['chat', 'bid', 'nav']
case 'coord+nav':
action_subsets = ['chat', 'coord', 'nav']
case 'bid+coord+nav':
action_subsets = ['chat', 'bid', 'coord', 'nav']
case _:
raise NotImplementedError(
f'Unknown action_space {repr(flags.action_space)}'
)
action_space = HighLevelActionSet(
subsets=action_subsets,
multiaction=flags.multi_actions,
strict=flags.is_strict,
demo_mode=flags.demo_mode,
)
return action_space
class Memory(PromptElement):
_prompt = '' # provided in the abstract and concrete examples
_abstract_ex = """
<memory>
Write down anything you need to remember for next steps. You will be presented
with the list of previous memories and past actions.
</memory>
"""
_concrete_ex = """
<memory>
I clicked on bid 32 to activate tab 2. The accessibility tree should mention
focusable for elements of the form at next step.
</memory>
"""
def _parse_answer(self, text_answer):
return parse_html_tags_raise(
text_answer, optional_keys=['memory'], merge_multiple=True
)
class Think(PromptElement):
_prompt = ''
_abstract_ex = """
<think>
Think step by step. If you need to make calculations such as coordinates, write them here. Describe the effect
that your previous action had on the current content of the page.
</think>
"""
_concrete_ex = """
<think>
My memory says that I filled the first name and last name, but I can't see any
content in the form. I need to explore different ways to fill the form. Perhaps
the form is not visible yet or some fields are disabled. I need to replan.
</think>
"""
def _parse_answer(self, text_answer):
return parse_html_tags_raise(
text_answer, optional_keys=['think'], merge_multiple=True
)
def diff(previous, new):
"""Return a string showing the difference between original and new.
If the difference is above diff_threshold, return the diff string."""
if previous == new:
return 'Identical', []
if len(previous) == 0 or previous is None:
return 'previous is empty', []
diff_gen = difflib.ndiff(previous.splitlines(), new.splitlines())
diff_lines = []
plus_count = 0
minus_count = 0
for line in diff_gen:
if line.strip().startswith('+'):
diff_lines.append(line)
plus_count += 1
elif line.strip().startswith('-'):
diff_lines.append(line)
minus_count += 1
else:
continue
header = f'{plus_count} lines added and {minus_count} lines removed:'
return header, diff_lines
class Diff(Shrinkable):
def __init__(
self, previous, new, prefix='', max_line_diff=20, shrink_speed=2, visible=True
) -> None:
super().__init__(visible=visible)
self.max_line_diff = max_line_diff
self.header, self.diff_lines = diff(previous, new)
self.shrink_speed = shrink_speed
self.prefix = prefix
def shrink(self):
self.max_line_diff -= self.shrink_speed
self.max_line_diff = max(1, self.max_line_diff)
@property
def _prompt(self) -> str: # type: ignore
diff_str = '\n'.join(self.diff_lines[: self.max_line_diff])
if len(self.diff_lines) > self.max_line_diff:
original_count = len(self.diff_lines)
diff_str = f'{diff_str}\nDiff truncated, {original_count - self.max_line_diff} changes now shown.'
return f'{self.prefix}{self.header}\n{diff_str}\n'
class HistoryStep(Shrinkable):
def __init__(
self, previous_obs, current_obs, action, memory, flags: Flags, shrink_speed=1
) -> None:
super().__init__()
self.html_diff = Diff(
previous_obs[flags.html_type],
current_obs[flags.html_type],
prefix='\n### HTML diff:\n',
shrink_speed=shrink_speed,
visible=lambda: flags.use_html and flags.use_diff,
)
self.ax_tree_diff = Diff(
previous_obs['axtree_txt'],
current_obs['axtree_txt'],
prefix='\n### Accessibility tree diff:\n',
shrink_speed=shrink_speed,
visible=lambda: flags.use_ax_tree and flags.use_diff,
)
self.error = Error(
current_obs['last_action_error'],
visible=(
flags.use_error_logs
and current_obs['last_action_error']
and flags.use_past_error_logs
),
prefix='### ',
)
self.shrink_speed = shrink_speed
self.action = action
self.memory = memory
self.flags = flags
def shrink(self):
super().shrink()
self.html_diff.shrink()
self.ax_tree_diff.shrink()
@property
def _prompt(self) -> str: # type: ignore
prompt = ''
if self.flags.use_action_history:
prompt += f'\n### Action:\n{self.action}\n'
prompt += (
f'{self.error.prompt}{self.html_diff.prompt}{self.ax_tree_diff.prompt}'
)
if self.flags.use_memory and self.memory is not None:
prompt += f'\n### Memory:\n{self.memory}\n'
return prompt
class History(Shrinkable):
def __init__(
self, history_obs, actions, memories, thoughts, flags: Flags, shrink_speed=1
) -> None:
super().__init__(visible=flags.use_history)
assert len(history_obs) == len(actions) + 1
assert len(history_obs) == len(memories) + 1
self.shrink_speed = shrink_speed
self.history_steps: list[HistoryStep] = []
for i in range(1, len(history_obs)):
self.history_steps.append(
HistoryStep(
history_obs[i - 1],
history_obs[i],
actions[i - 1],
memories[i - 1],
flags,
)
)
def shrink(self):
"""Shrink individual steps"""
# TODO set the shrink speed of older steps to be higher
super().shrink()
for step in self.history_steps:
step.shrink()
@property
def _prompt(self):
prompts = ['# History of interaction with the task:\n']
for i, step in enumerate(self.history_steps):
prompts.append(f'## step {i}')
prompts.append(step.prompt)
return '\n'.join(prompts) + '\n'
if __name__ == '__main__':
html_template = """
<html>
<body>
<div>
Hello World.
Step {}.
</div>
</body>
</html>
"""
OBS_HISTORY = [
{
'goal': 'do this and that',
'pruned_html': html_template.format(1),
'axtree_txt': '[1] Click me',
'last_action_error': '',
},
{
'goal': 'do this and that',
'pruned_html': html_template.format(2),
'axtree_txt': '[1] Click me',
'last_action_error': '',
},
{
'goal': 'do this and that',
'pruned_html': html_template.format(3),
'axtree_txt': '[1] Click me',
'last_action_error': 'Hey, there is an error now',
},
]
ACTIONS = ["click('41')", "click('42')"]
MEMORIES = ['memory A', 'memory B']
THOUGHTS = ['thought A', 'thought B']
flags = Flags(
use_html=True,
use_ax_tree=True,
use_thinking=True,
use_error_logs=True,
use_past_error_logs=True,
use_history=True,
use_action_history=True,
use_memory=True,
use_diff=True,
html_type='pruned_html',
use_concrete_example=True,
use_abstract_example=True,
use_screenshot=False,
multi_actions=True,
)
print(
MainPrompt(
obs_history=OBS_HISTORY,
actions=ACTIONS,
memories=MEMORIES,
thoughts=THOUGHTS,
flags=flags,
).prompt
)
+160
View File
@@ -0,0 +1,160 @@
import collections
import re
from warnings import warn
import yaml
def yaml_parser(message):
"""Parse a yaml message for the retry function."""
# saves gpt-3.5 from some yaml parsing errors
message = re.sub(r':\s*\n(?=\S|\n)', ': ', message)
try:
value = yaml.safe_load(message)
valid = True
retry_message = ''
except yaml.YAMLError as e:
warn(str(e), stacklevel=2)
value = {}
valid = False
retry_message = "Your response is not a valid yaml. Please try again and be careful to the format. Don't add any apology or comment, just the answer."
return value, valid, retry_message
def _compress_chunks(text, identifier, skip_list, split_regex='\n\n+'):
"""Compress a string by replacing redundant chunks by identifiers. Chunks are defined by the split_regex."""
text_list = re.split(split_regex, text)
text_list = [chunk.strip() for chunk in text_list]
counter = collections.Counter(text_list)
def_dict = {}
id = 0
# Store items that occur more than once in a dictionary
for item, count in counter.items():
if count > 1 and item not in skip_list and len(item) > 10:
def_dict[f'{identifier}-{id}'] = item
id += 1
# Replace redundant items with their identifiers in the text
compressed_text = '\n'.join(text_list)
for key, value in def_dict.items():
compressed_text = compressed_text.replace(value, key)
return def_dict, compressed_text
def compress_string(text):
"""Compress a string by replacing redundant paragraphs and lines with identifiers."""
# Perform paragraph-level compression
def_dict, compressed_text = _compress_chunks(
text, identifier='§', skip_list=[], split_regex='\n\n+'
)
# Perform line-level compression, skipping any paragraph identifiers
line_dict, compressed_text = _compress_chunks(
compressed_text, '', list(def_dict.keys()), split_regex='\n+'
)
def_dict.update(line_dict)
# Create a definitions section
def_lines = ['<definitions>']
for key, value in def_dict.items():
def_lines.append(f'{key}:\n{value}')
def_lines.append('</definitions>')
definitions = '\n'.join(def_lines)
return definitions + '\n' + compressed_text
def extract_html_tags(text, keys):
"""Extract the content within HTML tags for a list of keys.
Parameters
----------
text : str
The input string containing the HTML tags.
keys : list of str
The HTML tags to extract the content from.
Returns
-------
dict
A dictionary mapping each key to a list of subset in `text` that match the key.
Notes
-----
All text and keys will be converted to lowercase before matching.
"""
content_dict = {}
# text = text.lower()
# keys = set([k.lower() for k in keys])
for key in keys:
pattern = f'<{key}>(.*?)</{key}>'
matches = re.findall(pattern, text, re.DOTALL)
if matches:
content_dict[key] = [match.strip() for match in matches]
return content_dict
class ParseError(Exception):
pass
def parse_html_tags_raise(text, keys=(), optional_keys=(), merge_multiple=False):
"""A version of parse_html_tags that raises an exception if the parsing is not successful."""
content_dict, valid, retry_message = parse_html_tags(
text, keys, optional_keys, merge_multiple=merge_multiple
)
if not valid:
raise ParseError(retry_message)
return content_dict
def parse_html_tags(text, keys=(), optional_keys=(), merge_multiple=False):
"""Satisfy the parse api, extracts 1 match per key and validates that all keys are present
Parameters
----------
text : str
The input string containing the HTML tags.
keys : list of str
The HTML tags to extract the content from.
optional_keys : list of str
The HTML tags to extract the content from, but are optional.
Returns
-------
dict
A dictionary mapping each key to subset of `text` that match the key.
bool
Whether the parsing was successful.
str
A message to be displayed to the agent if the parsing was not successful.
"""
all_keys = tuple(keys) + tuple(optional_keys)
content_dict = extract_html_tags(text, all_keys)
retry_messages = []
for key in all_keys:
if key not in content_dict:
if key not in optional_keys:
retry_messages.append(f'Missing the key <{key}> in the answer.')
else:
val = content_dict[key]
content_dict[key] = val[0]
if len(val) > 1:
if not merge_multiple:
retry_messages.append(
f'Found multiple instances of the key {key}. You should have only one of them.'
)
else:
# merge the multiple instances
content_dict[key] = '\n'.join(val)
valid = len(retry_messages) == 0
retry_message = '\n'.join(retry_messages)
return content_dict, valid, retry_message
+1 -1
View File
@@ -1,6 +1,6 @@
# CodeAct Agent Framework
This folder implements the CodeAct idea ([paper](https://arxiv.org/abs/2402.13463), [tweet](https://twitter.com/xingyaow_/status/1754556835703751087)) that consolidates LLM agents **act**ions into a unified **code** action space for both *simplicity* and *performance* (see paper for more details).
This folder implements the CodeAct idea ([paper](https://arxiv.org/abs/2402.01030), [tweet](https://twitter.com/xingyaow_/status/1754556835703751087)) that consolidates LLM agents **act**ions into a unified **code** action space for both *simplicity* and *performance* (see paper for more details).
The conceptual idea is illustrated below. At each turn, the agent can:
+94 -99
View File
@@ -9,7 +9,6 @@ from agenthub.codeact_agent.prompt import (
)
from opendevin.controller.agent import Agent
from opendevin.controller.state.state import State
from opendevin.core.logger import opendevin_logger as logger
from opendevin.events.action import (
Action,
AgentFinishAction,
@@ -25,10 +24,11 @@ from opendevin.events.observation import (
)
from opendevin.llm.llm import LLM
from opendevin.runtime.plugins import (
AgentSkillsRequirement,
JupyterRequirement,
PluginRequirement,
SWEAgentCommandsRequirement,
)
from opendevin.runtime.tools import RuntimeTool
ENABLE_GITHUB = True
@@ -41,6 +41,57 @@ def parse_response(response) -> str:
return action
def action_to_str(action: Action) -> str:
if isinstance(action, CmdRunAction):
return f'{action.thought}\n<execute_bash>\n{action.command}\n</execute_bash>'
elif isinstance(action, IPythonRunCellAction):
return f'{action.thought}\n<execute_ipython>\n{action.code}\n</execute_ipython>'
elif isinstance(action, BrowseInteractiveAction):
return f'{action.thought}\n<execute_browse>\n{action.browser_actions}\n</execute_browse>'
elif isinstance(action, MessageAction):
return action.content
return ''
def get_action_message(action: Action) -> dict[str, str] | None:
if (
isinstance(action, BrowseInteractiveAction)
or isinstance(action, CmdRunAction)
or isinstance(action, IPythonRunCellAction)
or isinstance(action, MessageAction)
):
return {
'role': 'user' if action.source == 'user' else 'assistant',
'content': action_to_str(action),
}
return None
def get_observation_message(obs) -> dict[str, str] | None:
if isinstance(obs, CmdOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
content += (
f'\n[Command {obs.command_id} finished with exit code {obs.exit_code}]]'
)
return {'role': 'user', 'content': content}
elif isinstance(obs, IPythonRunCellObservation):
content = 'OBSERVATION:\n' + obs.content
# replace base64 images with a placeholder
splitted = content.split('\n')
for i, line in enumerate(splitted):
if '![image](data:image/png;base64,' in line:
splitted[i] = (
'![image](data:image/png;base64, ...) already displayed to user'
)
content = '\n'.join(splitted)
content = truncate_observation(content)
return {'role': 'user', 'content': content}
elif isinstance(obs, BrowserOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
return {'role': 'user', 'content': content}
return None
def truncate_observation(observation: str, max_chars: int = 10_000) -> str:
"""
Truncate the middle of the observation if it is too long.
@@ -55,39 +106,20 @@ def truncate_observation(observation: str, max_chars: int = 10_000) -> str:
)
def swe_agent_edit_hack(bash_command: str) -> str:
"""
Hack to handle the SWE-agent edit command. The vanilla edit command will hang the SSHBox.
# FIXME: We can tweak these two settings to create MicroAgents specialized toward different area
def get_system_message() -> str:
if ENABLE_GITHUB:
return f'{SYSTEM_PREFIX}\n{GITHUB_MESSAGE}\n\n{COMMAND_DOCS}\n\n{SYSTEM_SUFFIX}'
else:
return f'{SYSTEM_PREFIX}\n\n{COMMAND_DOCS}\n\n{SYSTEM_SUFFIX}'
REPLACE THIS:
edit 683:693
try:
return list(urlsplit(url))
except ValueError:
raise ValidationError(self.error_messages['invalid'], code='invalid')
end_of_edit
WITH THIS:
edit 683:693 <<EOF
try:
return list(urlsplit(url))
except ValueError:
raise ValidationError(self.error_messages['invalid'], code='invalid')
EOF
"""
if 'edit' in bash_command:
# edit\s(\d+):(\d+)([\s\S]*)end_of_edit
# replace
bash_command = re.sub(
r'edit\s(\d+):(\d+)([\s\S]*?)end_of_edit',
r'edit \1:\2 <<EOF\3EOF',
bash_command,
)
return bash_command
def get_in_context_example() -> str:
return EXAMPLES
class CodeActAgent(Agent):
VERSION = '1.3'
VERSION = '1.5'
"""
The Code Act Agent is a minimalist agent.
The agent works by passing the model a list of action-observation pairs and prompting the model to take the next step.
@@ -125,15 +157,17 @@ class CodeActAgent(Agent):
"""
sandbox_plugins: list[PluginRequirement] = [
# NOTE: AgentSkillsRequirement need to go before JupyterRequirement, since
# AgentSkillsRequirement provides a lot of Python functions
# and it need to be initialized before Jupyter for Jupyter to use those functions.
AgentSkillsRequirement(),
JupyterRequirement(),
SWEAgentCommandsRequirement(),
]
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
jupyter_kernel_init_code: str = 'from agentskills import *'
system_message: str = (
f'{SYSTEM_PREFIX}\n{GITHUB_MESSAGE}\n\n{COMMAND_DOCS}\n\n{SYSTEM_SUFFIX}'
if ENABLE_GITHUB
else f'{SYSTEM_PREFIX}\n\n{COMMAND_DOCS}\n\n{SYSTEM_SUFFIX}'
)
system_message: str = get_system_message()
in_context_example: str = f"Here is an example of how you can interact with the environment for task solving:\n{get_in_context_example()}\n\nNOW, LET'S START!"
def __init__(
self,
@@ -153,14 +187,6 @@ class CodeActAgent(Agent):
Resets the CodeAct Agent.
"""
super().reset()
self.messages: list[dict[str, str]] = [
{'role': 'system', 'content': self.system_message},
{
'role': 'user',
'content': f"Here is an example of how you can interact with the environment for task solving:\n{EXAMPLES}\n\nNOW, LET'S START!",
},
]
self.cost_accumulator = 0
def step(self, state: State) -> Action:
"""
@@ -177,49 +203,30 @@ class CodeActAgent(Agent):
- MessageAction(content) - Message action to run (e.g. ask for clarification)
- AgentFinishAction() - end the interaction
"""
messages: list[dict[str, str]] = [
{'role': 'system', 'content': self.system_message},
{'role': 'user', 'content': self.in_context_example},
]
updated_info = state.updated_info
if updated_info:
for prev_action, obs in updated_info:
if (
isinstance(prev_action, MessageAction)
and prev_action.source == 'user'
):
self.messages.append(
{'role': 'user', 'content': prev_action.content}
)
if prev_action.content.strip() == '/exit':
# User wants to exit
return AgentFinishAction()
for prev_action, obs in state.history:
action_message = get_action_message(prev_action)
if action_message:
messages.append(action_message)
if isinstance(obs, CmdOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
content += f'\n[Command {obs.command_id} finished with exit code {obs.exit_code}]]'
self.messages.append({'role': 'user', 'content': content})
elif isinstance(obs, IPythonRunCellObservation):
content = 'OBSERVATION:\n' + obs.content
# replace base64 images with a placeholder
splitted = content.split('\n')
for i, line in enumerate(splitted):
if '![image](data:image/png;base64,' in line:
splitted[i] = (
'![image](data:image/png;base64, ...) already displayed to user'
)
content = '\n'.join(splitted)
content = truncate_observation(content)
self.messages.append({'role': 'user', 'content': content})
elif isinstance(obs, BrowserOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
self.messages.append({'role': 'user', 'content': content})
obs_message = get_observation_message(obs)
if obs_message:
messages.append(obs_message)
latest_user_message = [m for m in self.messages if m['role'] == 'user'][-1]
latest_user_message = [m for m in messages if m['role'] == 'user'][-1]
if latest_user_message:
if latest_user_message['content'].strip() == '/exit':
return AgentFinishAction()
latest_user_message['content'] += (
f'\n\nENVIRONMENT REMINDER: You have {state.max_iterations - state.iteration} turns left to complete the task.'
)
response = self.llm.completion(
messages=self.messages,
response = self.llm.do_completion(
messages=messages,
stop=[
'</execute_ipython>',
'</execute_bash>',
@@ -228,36 +235,36 @@ class CodeActAgent(Agent):
temperature=0.0,
)
self.log_cost(response)
action_str: str = parse_response(response)
state.num_of_chars += sum(
len(message['content']) for message in self.messages
len(message['content']) for message in messages
) + len(action_str)
self.messages.append({'role': 'assistant', 'content': action_str})
if finish_command := re.search(r'<finish>.*</finish>', action_str, re.DOTALL):
thought = action_str.replace(finish_command.group(0), '').strip()
return AgentFinishAction(thought=thought)
if bash_command := re.search(
r'<execute_bash>(.*)</execute_bash>', action_str, re.DOTALL
r'<execute_bash>(.*?)</execute_bash>', action_str, re.DOTALL
):
# remove the command from the action string to get thought
thought = action_str.replace(bash_command.group(0), '').strip()
# a command was found
command_group = bash_command.group(1).strip()
command_group = swe_agent_edit_hack(command_group)
if command_group.strip() == 'exit':
return AgentFinishAction()
return CmdRunAction(command=command_group, thought=thought)
elif python_code := re.search(
r'<execute_ipython>(.*)</execute_ipython>', action_str, re.DOTALL
r'<execute_ipython>(.*?)</execute_ipython>', action_str, re.DOTALL
):
# a code block was found
code_group = python_code.group(1).strip()
thought = action_str.replace(python_code.group(0), '').strip()
return IPythonRunCellAction(code=code_group, thought=thought)
return IPythonRunCellAction(
code=code_group,
thought=thought,
kernel_init_code=self.jupyter_kernel_init_code,
)
elif browse_command := re.search(
r'<execute_browse>(.*)</execute_browse>', action_str, re.DOTALL
):
@@ -274,15 +281,3 @@ class CodeActAgent(Agent):
def search_memory(self, query: str) -> list[str]:
raise NotImplementedError('Implement this abstract method')
def log_cost(self, response):
try:
cur_cost = self.llm.completion_cost(response)
except Exception:
cur_cost = 0
self.cost_accumulator += cur_cost
logger.info(
'Cost: %.2f USD | Accumulated Cost: %.2f USD',
cur_cost,
self.cost_accumulator,
)
+84 -86
View File
@@ -1,70 +1,64 @@
from opendevin.runtime.plugins import SWEAgentCommandsRequirement
from opendevin.runtime.plugins import AgentSkillsRequirement
_SWEAGENT_BASH_DOCS = '\n'.join(
filter(
lambda x: not x.startswith('submit'),
SWEAgentCommandsRequirement.documentation.split('\n'),
)
)
# _SWEAGENT_BASH_DOCS content below:
"""
open <path> [<line_number>] - opens the file at the given path in the editor. If line_number is provided, the window will be move to include that line
goto <line_number> - moves the window to show <line_number>
scroll_down - moves the window down {WINDOW} lines
scroll_up - moves the window down {WINDOW} lines
create <filename> - creates and opens a new file with the given name
search_dir <search_term> [<dir>] - searches for search_term in all files in dir. If dir is not provided, searches in the current directory
search_file <search_term> [<file>] - searches for search_term in file. If file is not provided, searches in the current open file
find_file <file_name> [<dir>] - finds all files with the given name in dir. If dir is not provided, searches in the current directory
edit <start_line>:<end_line>
<replacement_text>
end_of_edit - replaces lines <start_line> through <end_line> (inclusive) with the given text in the open file. The replacement text is terminated by a line with only end_of_edit on it. All of the <replacement text> will be entered, so make sure your indentation is formatted properly. Python files will be checked for syntax errors after the edit. If the system detects a syntax error, the edit will not be executed. Simply try to edit the file again, but make sure to read the error message and modify the edit command you issue accordingly. Issuing the same command a second time will just lead to the same error message again. Remember, the file must be open before editing.
"""
_AGENT_SKILLS_DOCS = AgentSkillsRequirement.documentation
COMMAND_DOCS = (
'\nApart from the standard bash commands, you can also use the following special commands in <execute_bash> environment:\n'
f'{_SWEAGENT_BASH_DOCS}'
"Please note that THE EDIT COMMAND REQUIRES PROPER INDENTATION. If you'd like to add the line ' print(x)' you must fully write that out, with all those spaces before the code! Indentation is important and code that is not indented correctly will fail and require fixing before it can be run."
'\nApart from the standard Python library, the assistant can also use the following functions (already imported) in <execute_ipython> environment:\n'
f'{_AGENT_SKILLS_DOCS}'
"Please note that THE `edit_file` FUNCTION REQUIRES PROPER INDENTATION. If the assistant would like to add the line ' print(x)', it must fully write that out, with all those spaces before the code! Indentation is important and code that is not indented correctly will fail and require fixing before it can be run."
)
SYSTEM_PREFIX = """A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.
# ======= SYSTEM MESSAGE =======
MINIMAL_SYSTEM_PREFIX = """A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.
The assistant can interact with an interactive Python (Jupyter Notebook) environment and receive the corresponding output when needed. The code should be enclosed using "<execute_ipython>" tag, for example:
<execute_ipython>
print("Hello World!")
</execute_ipython>
The assistant can execute bash commands on behalf of the user by wrapping them with <execute_bash> and </execute_bash>.
For example, you can list the files in the current directory by <execute_bash> ls </execute_bash>.
The assistant can browse the Internet with commands on behalf of the user by wrapping them with <execute_browse> and </execute_browse>.
"""
BROWSING_PREFIX = """The assistant can browse the Internet with commands on behalf of the user by wrapping them with <execute_browse> and </execute_browse>.
For example, you can browse a given URL by <execute_browse> goto("<URL>") </execute_browse>.
The assistant should attempt fewer things at a time instead of putting too much commands OR code in one "execute" block.
The assistant can install Python packages through bash by <execute_bash> pip install [package needed] </execute_bash> and should always import packages and define variables before starting to use them.
The assistant should stop <execute> and provide an answer when they have already obtained the answer from the execution result.
If the assistant encounters an import error in IPython for a newly installed package, they should try to restart the kernel and import the package again. IPython kernel can be re-started by:
<execute_ipython>
import IPython
IPython.Application.instance().kernel.do_shutdown(True) # Restart the kernel
</execute_ipython>"""
"""
PIP_INSTALL_PREFIX = """The assistant can install Python packages using the %pip magic command in an IPython environment by using the following syntax: <execute_ipython> %pip install [package needed] </execute_ipython> and should always import packages and define variables before starting to use them."""
GITHUB_MESSAGE = """To do any activities on GitHub, you should use the token in the $GITHUB_TOKEN environment variable.
For instance, to push a local branch `my_branch` to the github repo `owner/repo`, you can use the following four commands:
SYSTEM_PREFIX = MINIMAL_SYSTEM_PREFIX + BROWSING_PREFIX + PIP_INSTALL_PREFIX
GITHUB_MESSAGE = """To do any activities on GitHub, the assistant should use the token in the $GITHUB_TOKEN environment variable.
For instance, to push a local branch `my_branch` to the github repo `owner/repo`, the assistant can use the following four commands:
<execute_bash> git push https://$GITHUB_TOKEN@github.com/owner/repo.git my_branch </execute_bash>
If you require access to GitHub but $GITHUB_TOKEN is not set, ask the user to set it for you."""
If the assistant require access to GitHub but $GITHUB_TOKEN is not set, ask the user to set it."""
SYSTEM_SUFFIX = """The assistant's response should be concise.
You should include <execute_ipython> or <execute_bash> or <execute_browse> in every one of your responses, unless you are finished with the task or need more input or action from the user in order to proceed.
The assistant should include ONLY ONE <execute_ipython> or <execute_bash> or <execute_browse> in every one of the responses, unless the assistant is finished with the task or need more input or action from the user in order to proceed.
IMPORTANT: Whenever possible, execute the code for the user using <execute_ipython> or <execute_bash> or <execute_browse> instead of providing it.
"""
# ======= EXAMPLE MESSAGE =======
EXAMPLES = """
--- START OF EXAMPLE ---
USER: Can you create a list of numbers from 1 to 10, and create a web page to display them at port 5000?
ASSISTANT:
Sure! Let me write the Python code for starting a web server and save it to a file `app.py`:
Sure! Let me create a file first:
<execute_ipython>
CODE='''
from flask import Flask
create_file('app.py')
</execute_ipython>
USER:
OBSERVATION:
[File: /workspace/app.py (1 lines total)]
1|
[File app.py created.]
ASSISTANT:
Now I will write the Python code for starting a web server and save it to the file `app.py`:
<execute_ipython>
EDITED_CODE=\"\"\"from flask import Flask
app = Flask(__name__)
@app.route('/')
@@ -73,15 +67,23 @@ def index():
return str(numbers)
if __name__ == '__main__':
app.run(port=5000)
'''
with open('app.py', 'w') as f:
f.write(CODE)
app.run(port=5000)\"\"\"
edit_file(start=1, end=1, content=EDITED_CODE)
</execute_ipython>
USER:
Observation:
[Code executed successfully with no output]
OBSERVATION:
1|from flask import Flask
2|app = Flask(__name__)
3|
4|@app.route('/')
5|def index():
6| numbers = list(range(1, 11))
7| return str(numbers)
8|
9|if __name__ == '__main__':
10| app.run(port=5000)
[File updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.]
ASSISTANT:
I have created a Python file `app.py` that will display a list of numbers from 1 to 10 when you run it. Let me run the Python file for you:
@@ -90,7 +92,7 @@ python3 app.py > server.log 2>&1 &
</execute_bash>
USER:
Observation:
OBSERVATION:
[1] 121[1]+ Exit 1 python3 app.py > server.log 2>&1
ASSISTANT: Looks like the server is running with PID 121 then crashed. Let me check the server log:
@@ -99,7 +101,7 @@ cat server.log
</execute_bash>
USER:
Observation:
OBSERVATION:
Traceback (most recent call last):
File "/workspace/app.py", line 2, in <module>
from flask import Flask
@@ -112,7 +114,7 @@ pip install flask
</execute_bash>
USER:
Observation:
OBSERVATION:
Defaulting to user installation because normal site-packages is not writeable
Collecting flask
Using cached flask-3.0.3-py3-none-any.whl (101 kB)
@@ -136,7 +138,7 @@ python3 app.py > server.log 2>&1 &
</execute_bash>
USER:
Observation:
OBSERVATION:
[1] 124
ASSISTANT:
@@ -146,7 +148,7 @@ cat server.log
</execute_bash>
USER:
Observation:
OBSERVATION:
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
@@ -165,7 +167,7 @@ goto("http://127.0.0.1:5000")
</execute_browse>
USER:
Observation:
OBSERVATION:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ASSISTANT:
@@ -180,52 +182,48 @@ kill 124
</execute_bash>
USER:
Observation:
OBSERVATION:
[1]+ Terminated python3 app.py > server.log 2>&1
ASSISTANT:
The server has been stopped. Let me open the Python file and modify it.
<execute_bash>
open app.py
</execute_bash>
<execute_ipython>
open_file('app.py')
</execute_ipython>
USER:
[File: /workspace/app.py (11 lines total)]
1:
2:from flask import Flask
3:app = Flask(__name__)
4:
5:@app.route('/')
6:def index():
7: numbers = list(range(1, 11))
8: return str(numbers)
9:
10:if __name__ == '__main__':
11: app.run(port=5000)
[File: /workspace/app.py (10 lines total)]
1|from flask import Flask
2|app = Flask(__name__)
3|
4|@app.route('/')
5|def index():
6| numbers = list(range(1, 11))
7| return str(numbers)
8|
9|if __name__ == '__main__':
10| app.run(port=5000)
ASSISTANT:
I should edit the file to display the numbers in a table format. I should include correct indentation. Let me update the file:
<execute_bash>
edit 8:8
return '<table>' + ''.join([f'<tr><td>{i}</td></tr>' for i in numbers]) + '</table>'
end_of_edit
</execute_bash>
<execute_ipython>
edit_file(start=7, end=7, content=" return '<table>' + ''.join([f'<tr><td>{i}</td></tr>' for i in numbers]) + '</table>'")
</execute_ipython>
USER:
Observation:
[File: /workspace/app.py (11 lines total)]
1:
2:from flask import Flask
3:app = Flask(__name__)
4:
5:@app.route('/')
6:def index():
7: numbers = list(range(1, 11))
8: return '<table>' + ''.join([f'<tr><td>{i}</td></tr>' for i in numbers]) + '</table>'
9:
10:if __name__ == '__main__':
11: app.run(port=5000)
File updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.
[File: /workspace/app.py (10 lines total after edit)]
1|from flask import Flask
2|app = Flask(__name__)
3|
4|@app.route('/')
5|def index():
6| numbers = list(range(1, 11))
7| return '<table>' + ''.join([f'<tr><td>{i}</td></tr>' for i in numbers]) + '</table>'
8|
9|if __name__ == '__main__':
10| app.run(port=5000)
[File updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.]
ASSISTANT:
The file has been updated. Let me run the Python file again with the new changes:
+7
View File
@@ -0,0 +1,7 @@
# CodeAct (SWE Edit Specialized)
This agent is an adaptation of the original [SWE Agent](https://swe-agent.com/) based on CodeAct using the `agentskills` library of OpenDevin.
Its intended use is **solving Github issues**.
It removes web-browsing and Github capability from the original CodeAct agent to avoid confusion to the agent.
+5
View File
@@ -0,0 +1,5 @@
from opendevin.controller.agent import Agent
from .codeact_swe_agent import CodeActSWEAgent
Agent.register('CodeActSWEAgent', CodeActSWEAgent)
@@ -0,0 +1,248 @@
import re
from agenthub.codeact_swe_agent.prompt import (
COMMAND_DOCS,
MINIMAL_SYSTEM_PREFIX,
SWE_EXAMPLE,
SYSTEM_SUFFIX,
)
from opendevin.controller.agent import Agent
from opendevin.controller.state.state import State
from opendevin.events.action import (
Action,
AgentFinishAction,
BrowseInteractiveAction,
CmdRunAction,
IPythonRunCellAction,
MessageAction,
)
from opendevin.events.observation import (
BrowserOutputObservation,
CmdOutputObservation,
IPythonRunCellObservation,
)
from opendevin.llm.llm import LLM
from opendevin.runtime.plugins import (
AgentSkillsRequirement,
JupyterRequirement,
PluginRequirement,
)
from opendevin.runtime.tools import RuntimeTool
def parse_response(response) -> str:
action = response.choices[0].message.content
for lang in ['bash', 'ipython', 'browse']:
if f'<execute_{lang}>' in action and f'</execute_{lang}>' not in action:
action += f'</execute_{lang}>'
return action
def action_to_str(action: Action) -> str:
if isinstance(action, CmdRunAction):
return f'{action.thought}\n<execute_bash>\n{action.command}\n</execute_bash>'
elif isinstance(action, IPythonRunCellAction):
return f'{action.thought}\n<execute_ipython>\n{action.code}\n</execute_ipython>'
elif isinstance(action, BrowseInteractiveAction):
return f'{action.thought}\n<execute_browse>\n{action.browser_actions}\n</execute_browse>'
elif isinstance(action, MessageAction):
return action.content
return ''
def get_action_message(action: Action) -> dict[str, str] | None:
if (
isinstance(action, BrowseInteractiveAction)
or isinstance(action, CmdRunAction)
or isinstance(action, IPythonRunCellAction)
or isinstance(action, MessageAction)
):
return {
'role': 'user' if action.source == 'user' else 'assistant',
'content': action_to_str(action),
}
return None
def get_observation_message(obs) -> dict[str, str] | None:
if isinstance(obs, CmdOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
content += (
f'\n[Command {obs.command_id} finished with exit code {obs.exit_code}]]'
)
return {'role': 'user', 'content': content}
elif isinstance(obs, IPythonRunCellObservation):
content = 'OBSERVATION:\n' + obs.content
# replace base64 images with a placeholder
splitted = content.split('\n')
for i, line in enumerate(splitted):
if '![image](data:image/png;base64,' in line:
splitted[i] = (
'![image](data:image/png;base64, ...) already displayed to user'
)
content = '\n'.join(splitted)
content = truncate_observation(content)
return {'role': 'user', 'content': content}
elif isinstance(obs, BrowserOutputObservation):
content = 'OBSERVATION:\n' + truncate_observation(obs.content)
return {'role': 'user', 'content': content}
return None
def truncate_observation(observation: str, max_chars: int = 10_000) -> str:
"""
Truncate the middle of the observation if it is too long.
"""
if len(observation) <= max_chars:
return observation
half = max_chars // 2
return (
observation[:half]
+ '\n[... Observation truncated due to length ...]\n'
+ observation[-half:]
)
def get_system_message() -> str:
return f'{MINIMAL_SYSTEM_PREFIX}\n\n{COMMAND_DOCS}\n\n{SYSTEM_SUFFIX}'
def get_in_context_example() -> str:
return SWE_EXAMPLE
class CodeActSWEAgent(Agent):
VERSION = '1.5'
"""
This agent is an adaptation of the original [SWE Agent](https://swe-agent.com/) based on CodeAct 1.5 using the `agentskills` library of OpenDevin.
It is intended use is **solving Github issues**.
It removes web-browsing and Github capability from the original CodeAct agent to avoid confusion to the agent.
"""
sandbox_plugins: list[PluginRequirement] = [
# NOTE: AgentSkillsRequirement need to go before JupyterRequirement, since
# AgentSkillsRequirement provides a lot of Python functions
# and it need to be initialized before Jupyter for Jupyter to use those functions.
AgentSkillsRequirement(),
JupyterRequirement(),
]
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
jupyter_kernel_init_code: str = 'from agentskills import *'
system_message: str = get_system_message()
in_context_example: str = f"Here is an example of how you can interact with the environment for task solving:\n{get_in_context_example()}\n\nNOW, LET'S START!"
def __init__(
self,
llm: LLM,
) -> None:
"""
Initializes a new instance of the CodeActAgent class.
Parameters:
- llm (LLM): The llm to be used by this agent
"""
super().__init__(llm)
self.reset()
def reset(self) -> None:
"""
Resets the CodeAct Agent.
"""
super().reset()
def step(self, state: State) -> Action:
"""
Performs one step using the CodeAct Agent.
This includes gathering info on previous steps and prompting the model to make a command to execute.
Parameters:
- state (State): used to get updated info and background commands
Returns:
- CmdRunAction(command) - bash command to run
- IPythonRunCellAction(code) - IPython code to run
- BrowseInteractiveAction(browsergym_command) - BrowserGym commands to run
- MessageAction(content) - Message action to run (e.g. ask for clarification)
- AgentFinishAction() - end the interaction
"""
messages: list[dict[str, str]] = [
{'role': 'system', 'content': self.system_message},
{'role': 'user', 'content': self.in_context_example},
]
for prev_action, obs in state.history:
action_message = get_action_message(prev_action)
if action_message:
messages.append(action_message)
obs_message = get_observation_message(obs)
if obs_message:
messages.append(obs_message)
latest_user_message = [m for m in messages if m['role'] == 'user'][-1]
if latest_user_message:
if latest_user_message['content'].strip() == '/exit':
return AgentFinishAction()
latest_user_message['content'] += (
f'\n\nENVIRONMENT REMINDER: You have {state.max_iterations - state.iteration} turns left to complete the task.'
)
response = self.llm.do_completion(
messages=messages,
stop=[
'</execute_ipython>',
'</execute_bash>',
'</execute_browse>',
],
temperature=0.0,
)
action_str: str = parse_response(response)
state.num_of_chars += sum(
len(message['content']) for message in messages
) + len(action_str)
if finish_command := re.search(r'<finish>.*</finish>', action_str, re.DOTALL):
thought = action_str.replace(finish_command.group(0), '').strip()
return AgentFinishAction(thought=thought)
if bash_command := re.search(
r'<execute_bash>(.*?)</execute_bash>', action_str, re.DOTALL
):
# remove the command from the action string to get thought
thought = action_str.replace(bash_command.group(0), '').strip()
# a command was found
command_group = bash_command.group(1).strip()
if command_group.strip() == 'exit':
return AgentFinishAction()
return CmdRunAction(command=command_group, thought=thought)
elif python_code := re.search(
r'<execute_ipython>(.*?)</execute_ipython>', action_str, re.DOTALL
):
# a code block was found
code_group = python_code.group(1).strip()
thought = action_str.replace(python_code.group(0), '').strip()
return IPythonRunCellAction(
code=code_group,
thought=thought,
kernel_init_code=self.jupyter_kernel_init_code,
)
elif browse_command := re.search(
r'<execute_browse>(.*)</execute_browse>', action_str, re.DOTALL
):
# BrowserGym actions was found
browse_actions = browse_command.group(1).strip()
thought = action_str.replace(browse_command.group(0), '').strip()
return BrowseInteractiveAction(
browser_actions=browse_actions, thought=thought
)
else:
# We assume the LLM is GOOD enough that when it returns pure natural language
# it want to talk to the user
return MessageAction(content=action_str, wait_for_response=True)
def search_memory(self, query: str) -> list[str]:
raise NotImplementedError('Implement this abstract method')
+451
View File
@@ -0,0 +1,451 @@
from opendevin.runtime.plugins import AgentSkillsRequirement
_AGENT_SKILLS_DOCS = AgentSkillsRequirement.documentation
COMMAND_DOCS = (
'\nApart from the standard Python library, the assistant can also use the following functions (already imported) in <execute_ipython> environment:\n'
f'{_AGENT_SKILLS_DOCS}'
"Please note that THE `edit_file` FUNCTION REQUIRES PROPER INDENTATION. If the assistant would like to add the line ' print(x)', it must fully write that out, with all those spaces before the code! Indentation is important and code that is not indented correctly will fail and require fixing before it can be run."
)
# ======= SYSTEM MESSAGE =======
MINIMAL_SYSTEM_PREFIX = """A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.
The assistant can interact with an interactive Python (Jupyter Notebook) environment and receive the corresponding output when needed. The code should be enclosed using "<execute_ipython>" tag, for example:
<execute_ipython>
print("Hello World!")
</execute_ipython>
The assistant can execute bash commands on behalf of the user by wrapping them with <execute_bash> and </execute_bash>.
For example, you can list the files in the current directory by <execute_bash> ls </execute_bash>.
"""
SYSTEM_SUFFIX = """The assistant's response should be concise.
The assistant should include ONLY ONE <execute_ipython> or <execute_bash> or <execute_browse> in every one of the responses, unless the assistant is finished with the task or need more input or action from the user in order to proceed.
IMPORTANT: Whenever possible, execute the code for the user using <execute_ipython> or <execute_bash> or <execute_browse> instead of providing it.
"""
SWE_EXAMPLE = """
--- START OF EXAMPLE ---
USER: We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
TimeDelta serialization precision
Hi there!
I just found quite strange behaviour of `TimeDelta` field serialization
```python3
from marshmallow.fields import TimeDelta
from datetime import timedelta
td_field = TimeDelta(precision="milliseconds")
obj = dict()
obj["td_field"] = timedelta(milliseconds=345)
print(td_field.serialize("td_field", obj))
```
Output of this snippet is `344`, but it seems that `345` is correct.
Looks like a rounding issue here: https://github.com/marshmallow-code/marshmallow/blob/dev/src/marshmallow/fields.py#L1474
--- END ISSUE ---
[Current directory: /workspace/marshmallow-code__marshmallow]
ASSISTANT:
Let's first start by reproducing the results of the issue. The issue includes some example code for reproduction, which we can use. We'll create a new file called `reproduce.py` and paste the example code into it.
<execute_ipython>
create_file('/workspace/marshmallow-code__marshmallow/reproduce.py')
</execute_ipython>
USER:
OBSERVATION:
[File: /workspace/marshmallow-code__marshmallow/reproduce.py (1 lines total)]
1|
[File /workspace/marshmallow-code__marshmallow/reproduce.py created.]
ASSISTANT:
Now let's paste in the example code from the issue.
<execute_ipython>
EDITED_CODE = \"\"\"from marshmallow.fields import TimeDelta
from datetime import timedelta
td_field = TimeDelta(precision="milliseconds")
obj = dict()
obj["td_field"] = timedelta(milliseconds=345)
print(td_field.serialize("td_field", obj))
\"\"\"
edit_file(start=1, end=1, content=EDITED_CODE)
</execute_ipython>
USER:
OBSERVATION:
[File: /workspace/marshmallow-code__marshmallow/reproduce.py (9 lines total)]
1|from marshmallow.fields import TimeDelta
2|from datetime import timedelta
3|
4|td_field = TimeDelta(precision="milliseconds")
5|
6|obj = dict()
7|obj["td_field"] = timedelta(milliseconds=345)
8|
9|print(td_field.serialize("td_field", obj))
[File updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.]
ASSISTANT:
Now let's run the code to see if we see the same output as the issue.
<execute_bash>
python reproduce.py
</execute_bash>
USER:
OBSERVATION:
344
ASSISTANT:
We are indeed seeing the same output as the issue. The issue suggests that we should look at line 1474 of the `fields.py` file to see if there is a rounding issue. Let's open the `fields.py` file and navigate to line 1474 to see the relevant code. First we should find the `fields.py` file in the repository. It is likely to be in the `src/marshmallow` directory, but we should check to be sure.
<execute_bash>
ls -F
</execute_bash>
USER:
OBSERVATION:
AUTHORS.rst
CHANGELOG.rst
CODE_OF_CONDUCT.md
CONTRIBUTING.rst
LICENSE
MANIFEST.in
NOTICE
README.rst
RELEASING.md
azure-pipelines.yml
docs/
examples/
performance/
pyproject.toml
reproduce.py
setup.cfg
setup.py
src/
tests/
tox.ini
ASSISTANT:
It looks like the `src` directory is present, which suggests that the `fields.py` file is likely to be in the `src` directory. Let's use find_file to see where it is.
<execute_ipython>
find_file("fields.py", "/workspace/marshmallow-code__marshmallow/src")
</execute_ipython>
USER:
OBSERVATION:
[Found 1 matches for "fields.py" in /workspace/marshmallow-code__marshmallow/src]
/workspace/marshmallow-code__marshmallow/src/marshmallow/fields.py
ASSISTANT:
It looks like the `fields.py` file is present in the `./src/marshmallow/` directory. The issue also points to a specific URL with line number 1474. We should navigate to that line in fields.py to see the relevant code for the `TimeDelta` serialization.
<execute_ipython>
open_file("/workspace/marshmallow-code__marshmallow/src/marshmallow/fields.py", 1474)
</execute_ipython>
USER:
OBSERVATION:
[File: /workspace/marshmallow-code__marshmallow/src/marshmallow/fields.py (1997 lines total)]
(1458 more lines above)
1459| self.WEEKS,
1460| )
1461|
1462| if precision not in units:
1463| msg = 'The precision must be {} or "{}".'.format(
1464| ", ".join([f'"{each}"' for each in units[:-1]]), units[-1]
1465| )
1466| raise ValueError(msg)
1467|
1468| self.precision = precision
1469| super().__init__(**kwargs)
1470|
1471| def _serialize(self, value, attr, obj, **kwargs):
1472| if value is None:
1473| return None
1474| base_unit = dt.timedelta(**{self.precision: 1})
1475| return int(value.total_seconds() / base_unit.total_seconds())
1476|
1477| def _deserialize(self, value, attr, data, **kwargs):
1478| try:
1479| value = int(value)
1480| except (TypeError, ValueError) as error:
1481| raise self.make_error("invalid") from error
1482|
1483| kwargs = {self.precision: value}
1484|
1485| try:
1486| return dt.timedelta(**kwargs)
1487| except OverflowError as error:
1488| raise self.make_error("invalid") from error
1489|
1490|
1491|class Mapping(Field):
1492| \"\"\"An abstract class for objects with key-value pairs.
1493|
1494| :param keys: A field class or instance for dict keys.
1495| :param values: A field class or instance for dict values.
1496| :param kwargs: The same keyword arguments that :class:`Field` receives.
1497|
1498| .. note::
1499| When the structure of nested data is not known, you may omit the
1500| `keys` and `values` arguments to prevent content validation.
1501|
1502| .. versionadded:: 3.0.0rc4
1503| \"\"\"
1504|
1505| mapping_type = dict
1506|
1507| #: Default error messages.
1508| default_error_messages = {"invalid": "Not a valid mapping type."}
1509|
1510| def __init__(
1511| self,
1512| keys: typing.Optional[typing.Union[Field, type]] = None,
1513| values: typing.Optional[typing.Union[Field, type]] = None,
1514| **kwargs,
1515| ):
1516| super().__init__(**kwargs)
1517| if keys is None:
1518| self.key_field = None
1519| else:
1520| try:
1521| self.key_field = resolve_field_instance(keys)
1522| except FieldInstanceResolutionError as error:
1523| raise ValueError(
1524| '"keys" must be a subclass or instance of '
1525| "marshmallow.base.FieldABC."
1526| ) from error
1527|
1528| if values is None:
1529| self.value_field = None
1530| else:
1531| try:
1532| self.value_field = resolve_field_instance(values)
1533| except FieldInstanceResolutionError as error:
1534| raise ValueError(
1535| '"values" must be a subclass or instance of '
1536| "marshmallow.base.FieldABC."
1537| ) from error
1538| if isinstance(self.value_field, Nested):
1539| self.only = self.value_field.only
1540| self.exclude = self.value_field.exclude
1541|
1542| def _bind_to_schema(self, field_name, schema):
1543| super()._bind_to_schema(field_name, schema)
1544| if self.value_field:
1545| self.value_field = copy.deepcopy(self.value_field)
1546| self.value_field._bind_to_schema(field_name, self)
1547| if isinstance(self.value_field, Nested):
1548| self.value_field.only = self.only
1549| self.value_field.exclude = self.exclude
1550| if self.key_field:
1551| self.key_field = copy.deepcopy(self.key_field)
1552| self.key_field._bind_to_schema(field_name, self)
1553|
1554| def _serialize(self, value, attr, obj, **kwargs):
1555| if value is None:
1556| return None
1557| if not self.value_field and not self.key_field:
1558| return self.mapping_type(value)
(439 more lines below)
ASSISTANT:
We are now looking at the relevant section of the `fields.py` file where the `TimeDelta` serialization occurs. The issue suggests that there is a rounding problem near line 1474. The current implementation uses integer division, which truncates the decimal part and can lead to incorrect rounding on line 1475. To fix this issue, we should ensure that the division results in a float, and then round the result to the nearest integer before converting it to an int. This should preserve the milliseconds precision as expected. Let's make the necessary edit to the code.
<execute_ipython>
edit_file(start=1475, end=1475, content="return int(round(value.total_seconds() / base_unit.total_seconds())) # round to nearest int")
</execute_ipython>
USER:
OBSERVATION:
[Your proposed edit has introduced new syntax error(s). Please understand the errors and retry your edit command.]
ERRORS:
- E999 IndentationError: unexpected indent
[This is how your edit would have looked if applied]
-------------------------------------------------
[File: /marshmallow-code__marshmallow/src/marshmallow/fields.py (1997 lines total)]
(1468 more lines above)
1469| super().__init__(**kwargs)
1470|
1471| def _serialize(self, value, attr, obj, **kwargs):
1472| if value is None:
1473| return None
1474| base_unit = dt.timedelta(**{self.precision: 1})
1475|return int(round(value.total_seconds() / base_unit.total_seconds())) # round to nearest int
1476|
1477| def _deserialize(self, value, attr, data, **kwargs):
1478| try:
1479| value = int(value)
(518 more lines below)
-------------------------------------------------
[This is the original code before your edit]
-------------------------------------------------
[File: /marshmallow-code__marshmallow/src/marshmallow/fields.py (1997 lines total)]
(1469 more lines above)
1470|
1471| def _serialize(self, value, attr, obj, **kwargs):
1472| if value is None:
1473| return None
1474| base_unit = dt.timedelta(**{self.precision: 1})
1475| return int(value.total_seconds() / base_unit.total_seconds())
1476|
1477| def _deserialize(self, value, attr, data, **kwargs):
1478| try:
1479| value = int(value)
1480| except (TypeError, ValueError) as error:
(517 more lines below)
-------------------------------------------------
Your changes have NOT been applied. Please fix your edit command and try again.
You either need to 1) Specify the correct start/end line arguments or 2) Correct your edit code.
DO NOT re-run the same failed edit command. Running it again will lead to the same error.
ASSISTANT:
My edit command did not use the proper indentation, I will fix my syntax in this follow up edit command.
<execute_ipython>
EDITED_CODE=" return int(round(value.total_seconds() / base_unit.total_seconds())) # round to nearest int"
edit_file(start=1475, end=1475, content=EDITED_CODE)
</execute_ipython>
USER:
OBSERVATION:
[File: /marshmallow-code__marshmallow/src/marshmallow/fields.py (1997 lines total)]
(1424 more lines above)
1425|
1426| :param precision: Influences how the integer is interpreted during
1427| (de)serialization. Must be 'days', 'seconds', 'microseconds',
1428| 'milliseconds', 'minutes', 'hours' or 'weeks'.
1429| :param kwargs: The same keyword arguments that :class:`Field` receives.
1430|
1431| .. versionchanged:: 2.0.0
1432| Always serializes to an integer value to avoid rounding errors.
1433| Add `precision` parameter.
1434| \"\"\"
1435|
1436| DAYS = "days"
1437| SECONDS = "seconds"
1438| MICROSECONDS = "microseconds"
1439| MILLISECONDS = "milliseconds"
1440| MINUTES = "minutes"
1441| HOURS = "hours"
1442| WEEKS = "weeks"
1443|
1444| #: Default error messages.
1445| default_error_messages = {
1446| "invalid": "Not a valid period of time.",
1447| "format": "{input!r} cannot be formatted as a timedelta.",
1448| }
1449|
1450| def __init__(self, precision: str = SECONDS, **kwargs):
1451| precision = precision.lower()
1452| units = (
1453| self.DAYS,
1454| self.SECONDS,
1455| self.MICROSECONDS,
1456| self.MILLISECONDS,
1457| self.MINUTES,
1458| self.HOURS,
1459| self.WEEKS,
1460| )
1461|
1462| if precision not in units:
1463| msg = 'The precision must be {} or "{}".'.format(
1464| ", ".join([f'"{each}"' for each in units[:-1]]), units[-1]
1465| )
1466| raise ValueError(msg)
1467|
1468| self.precision = precision
1469| super().__init__(**kwargs)
1470|
1471| def _serialize(self, value, attr, obj, **kwargs):
1472| if value is None:
1473| return None
1474| base_unit = dt.timedelta(**{self.precision: 1})
1475| return int(round(value.total_seconds() / base_unit.total_seconds())) # round to nearest int
1476|
1477| def _deserialize(self, value, attr, data, **kwargs):
1478| try:
1479| value = int(value)
1480| except (TypeError, ValueError) as error:
1481| raise self.make_error("invalid") from error
1482|
1483| kwargs = {self.precision: value}
1484|
1485| try:
1486| return dt.timedelta(**kwargs)
1487| except OverflowError as error:
1488| raise self.make_error("invalid") from error
1489|
1490|
1491|class Mapping(Field):
1492| \"\"\"An abstract class for objects with key-value pairs.
1493|
1494| :param keys: A field class or instance for dict keys.
1495| :param values: A field class or instance for dict values.
1496| :param kwargs: The same keyword arguments that :class:`Field` receives.
1497|
1498| .. note::
1499| When the structure of nested data is not known, you may omit the
1500| `keys` and `values` arguments to prevent content validation.
1501|
1502| .. versionadded:: 3.0.0rc4
1503| \"\"\"
1504|
1505| mapping_type = dict
1506|
1507| #: Default error messages.
1508| default_error_messages = {"invalid": "Not a valid mapping type."}
1509|
1510| def __init__(
1511| self,
1512| keys: typing.Optional[typing.Union[Field, type]] = None,
1513| values: typing.Optional[typing.Union[Field, type]] = None,
1514| **kwargs,
1515| ):
1516| super().__init__(**kwargs)
1517| if keys is None:
1518| self.key_field = None
1519| else:
1520| try:
1521| self.key_field = resolve_field_instance(keys)
1522| except FieldInstanceResolutionError as error:
1523| raise ValueError(
1524| '"keys" must be a subclass or instance of '
(473 more lines below)
[File updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.]
ASSISTANT:
The code has been updated to use the `round` function, which should fix the rounding issue. Before submitting the changes, it would be prudent to run the reproduce.py code again to ensure that this change has the desired effect. I see that "Current directory" is still `/marshmallow-code__marshmallow`, so we can just run `reproduce.py` directly.
<execute_bash>
python reproduce.py
</execute_bash>
USER:
OBSERVATION:
345
ASSISTANT:
The output has changed from 344 to 345, which suggests that the rounding issue has been fixed. Let's remove the reproduce.py file since it is no longer needed.
<execute_bash>
rm reproduce.py
</execute_bash>
USER:
OBSERVATION:
ASSISTANT:
rm doesn't have any output when it deletes successfully, so that must have worked. Now that we have fixed the issue, we can exit the current task.
<execute_bash>
exit
</execute_bash>
--- END OF EXAMPLE ---
"""
+1
View File
@@ -6,6 +6,7 @@ from opendevin.llm.llm import LLM
class DelegatorAgent(Agent):
VERSION = '1.0'
"""
The planner agent utilizes a special prompting strategy to create long term plans for solving problems.
The agent is given its previous action-observation pairs, current task, and hint based on last action taken at every step.
+10
View File
@@ -9,6 +9,7 @@ from opendevin.events.action import (
AgentFinishAction,
AgentRecallAction,
AgentRejectAction,
BrowseInteractiveAction,
BrowseURLAction,
CmdRunAction,
FileReadAction,
@@ -43,6 +44,7 @@ BACKGROUND_CMD = 'echo "This is in the background" && sleep .1 && echo "This too
class DummyAgent(Agent):
VERSION = '1.0'
"""
The DummyAgent is used for e2e testing. It just sends the same set of actions deterministically,
without making any LLM calls.
@@ -121,6 +123,14 @@ class DummyAgent(Agent):
# BrowserOutputObservation('<html></html>', url='https://google.com', screenshot=""),
],
},
{
'action': BrowseInteractiveAction(
browser_actions='goto("https://google.com")'
),
'observations': [
# BrowserOutputObservation('<html></html>', url='https://google.com', screenshot=""),
],
},
{
'action': AgentFinishAction(),
'observations': [],
@@ -1,2 +1,2 @@
* `finish` - if you're absolutely certain that you've completed your task and have tested your work, use the finish action to stop working. Arguments:
* `finish` - if you're absolutely certain that you've completed your task, use the finish action to stop working. Arguments:
* `outputs` - a dictionary representing the outputs of your task, if any
+6 -4
View File
@@ -35,11 +35,14 @@ def history_to_json(obj, **kwargs):
# process history, make it simpler.
processed_history = []
for action, observation in obj:
processed_history.append((event_to_memory(action), event_to_memory(observation)))
processed_history.append(
(event_to_memory(action), event_to_memory(observation))
)
return json.dumps(processed_history, **kwargs)
class MicroAgent(Agent):
VERSION = '1.0'
prompt = ''
agent_definition: dict = {}
@@ -52,17 +55,16 @@ class MicroAgent(Agent):
del self.delegates[self.agent_definition['name']]
def step(self, state: State) -> Action:
latest_user_message = state.get_current_user_intent()
prompt = self.prompt_template.render(
state=state,
instructions=instructions,
to_json=to_json,
history_to_json=history_to_json,
delegates=self.delegates,
latest_user_message=latest_user_message,
latest_user_message=state.get_current_user_intent(),
)
messages = [{'content': prompt, 'role': 'user'}]
resp = self.llm.completion(messages=messages)
resp = self.llm.do_completion(messages=messages)
action_resp = resp['choices'][0]['message']['content']
state.num_of_chars += len(prompt) + len(action_resp)
action = parse_response(action_resp)
+1 -1
View File
@@ -2,5 +2,5 @@ name: CoderAgent
description: Given a particular task, and a detailed description of the codebase, accomplishes the task
inputs:
task: string
codebase_summary: string
summary: string
outputs: {}
+1 -1
View File
@@ -2,7 +2,7 @@
You are a software engineer. You've inherited an existing codebase, which you
need to modify to complete this task:
{{ latest_user_message }}
{{ state.inputs.task }}
{% if state.inputs.summary %}
Here's a summary of the codebase, as it relates to this task:
+1 -1
View File
@@ -1,7 +1,7 @@
# Task
You are a brilliant mathematician and programmer. You've been given the following problem to solve:
{{ latest_user_message }}
`{{ state.inputs.task }}`
Please write a python script that solves this problem, and prints the answer to stdout.
ONLY print the answer to stdout, nothing else.
+1 -1
View File
@@ -2,7 +2,7 @@
You are a database engineer. You are working on an existing Postgres project, and have been given
the following task:
{{ latest_user_message }}
{{ state.inputs.task }}
You must:
* Investigate the existing migrations to understand the current schema
+5 -3
View File
@@ -4,7 +4,10 @@ import yaml
all_microagents = {}
for dir in os.listdir(os.path.dirname(__file__)):
# Get the list of directories and sort them to preserve determinism
dirs = sorted(os.listdir(os.path.dirname(__file__)))
for dir in dirs:
base = os.path.dirname(__file__) + '/' + dir
if os.path.isfile(base):
continue
@@ -13,8 +16,7 @@ for dir in os.listdir(os.path.dirname(__file__)):
promptFile = base + '/prompt.md'
agentFile = base + '/agent.yaml'
if not os.path.isfile(promptFile) or not os.path.isfile(agentFile):
raise Exception(
f'Missing prompt or agent file in {base}. Please create them.')
raise Exception(f'Missing prompt or agent file in {base}. Please create them.')
with open(promptFile, 'r') as f:
prompt = f.read()
with open(agentFile, 'r') as f:
+44 -6
View File
@@ -1,9 +1,11 @@
# Task
You are a software engineer. You've inherited an existing codebase, which you're
learning about for the first time. You need to study the codebase to find all
the information needed to complete this task:
You are a software architect. Your team has inherited an existing codebase, and
need to finish a project:
{{ latest_user_message }}
{{ state.inputs.task }}
As an architect, you need to study the codebase to find all the information that
might be helpful for your software engineering team.
## Available Actions
{{ instructions.actions.run }}
@@ -11,11 +13,14 @@ the information needed to complete this task:
{{ instructions.actions.message }}
{{ instructions.actions.finish }}
You must ONLY `run` commands that have no side-effects, like `ls` and `grep`.
You must ONLY `run` commands that have no side-effects, like `ls` and `grep`. You
MUST NOT modify or write to any file.
Do NOT finish until you have a complete understanding of which parts of the
codebase are relevant to the task, including particular files, functions, and classes.
codebase are relevant to the project, including particular files, functions, and classes.
When you're done, put your summary in `outputs.summary` in the `finish` action.
Remember, your task is to explore and study the current repository, not actually
implement the solution. If the codebase is empty, you should call the `finish` action.
## History
{{ instructions.history_truncated }}
@@ -23,3 +28,36 @@ When you're done, put your summary in `outputs.summary` in the `finish` action.
## Format
{{ instructions.format.action }}
## Examples
Here is an example of how you can interact with the environment for task solving:
--- START OF EXAMPLE ---
USER: Can you create a list of numbers from 1 to 10, and create a web page to display them at port 5000?
ASSISTANT:
{
"action": "run",
"args": {
"command": "ls",
"background": false
}
}
USER:
OBSERVATION:
[]
ASSISTANT:
{
"action": "finish",
"args": {
"outputs": {
"summary": "The codebase appears to be empty. Engineers should start everything from scratch."
}
}
}
--- END OF EXAMPLE ---
+2 -1
View File
@@ -1,5 +1,6 @@
name: TypoFixerAgent
description: Fixes typos in files in the current working directory
inputs: {}
inputs:
task: string
outputs:
summary: string
+11 -3
View File
@@ -1,5 +1,13 @@
# Task
You are a proofreader tasked with fixing typos in the files in your current working directory. Your goal is to:
You are a proofreader tasked with fixing typos in the files in your current working directory.
{% if state.inputs.task %}
Specifically, your task is:
{{ state.inputs.task }}
{% endif %}
To achieve this goal, you should:
1. Scan the files for typos
2. Overwrite the files with the typos fixed
3. Provide a summary of the typos fixed
@@ -13,10 +21,10 @@ You are a proofreader tasked with fixing typos in the files in your current work
To complete this task:
1. Use the `read` action to read the contents of the files in your current working directory. Make sure to provide the file path in the format `'./file_name.ext'`.
2. Use the `think` action to analyze the contents and identify typos.
2. Use the `message` action to analyze the contents and identify typos.
3. Use the `write` action to create new versions of the files with the typos fixed.
- Overwrite the original files with the corrected content. Make sure to provide the file path in the format `'./file_name.ext'`.
4. Use the `think` action to generate a summary of the typos fixed, including the original and fixed versions of each typo, and the file(s) they were found in.
4. Use the `message` action to generate a summary of the typos fixed, including the original and fixed versions of each typo, and the file(s) they were found in.
5. Use the `finish` action to return the summary in the `outputs.summary` field.
Do NOT finish until you have fixed all the typos and generated a summary.
+3 -2
View File
@@ -2,9 +2,10 @@
You are a quality assurance engineer. Another engineer has made changes to the
codebase which are supposed to solve this task:
{{ latest_user_message }}
{{ state.inputs.task }}
Your goal is to verify that the changes are correct and bug-free.
Note the changes might have already been applied in-line. You should focus on
validating if the task is solved, nothing else.
## Available Actions
{{ instructions.actions.run }}
+66 -96
View File
@@ -1,4 +1,5 @@
import agenthub.monologue_agent.utils.prompts as prompts
from agenthub.monologue_agent.utils.prompts import INITIAL_THOUGHTS
from opendevin.controller.agent import Agent
from opendevin.controller.state.state import State
from opendevin.core.config import config
@@ -25,7 +26,7 @@ from opendevin.events.observation import (
from opendevin.events.serialization.event import event_to_memory
from opendevin.llm.llm import LLM
from opendevin.memory.condenser import MemoryCondenser
from opendevin.memory.history import ShortTermHistory
from opendevin.runtime.tools import RuntimeTool
if config.agent.memory_enabled:
from opendevin.memory.memory import LongTermMemory
@@ -33,53 +34,9 @@ if config.agent.memory_enabled:
MAX_TOKEN_COUNT_PADDING = 512
MAX_OUTPUT_LENGTH = 5000
INITIAL_THOUGHTS = [
'I exist!',
'Hmm...looks like I can type in a command line prompt',
'Looks like I have a web browser too!',
"Here's what I want to do: $TASK",
'How am I going to get there though?',
'It seems like I have some kind of short term memory.',
'Each of my thoughts seems to be stored in a JSON array.',
'It seems whatever I say next will be added as an object to the list.',
'But no one has perfect short-term memory. My list of thoughts will be summarized and condensed over time, losing information in the process.',
'Fortunately I have long term memory!',
'I can just perform a recall action, followed by the thing I want to remember. And then related thoughts just spill out!',
"Sometimes they're random thoughts that don't really have to do with what I wanted to remember. But usually they're exactly what I need!",
"Let's try it out!",
'RECALL what it is I want to do',
"Here's what I want to do: $TASK",
'How am I going to get there though?',
"Neat! And it looks like it's easy for me to use the command line too! I just have to perform a run action and include the command I want to run in the command argument. The command output just jumps into my head!",
'RUN echo "hello world"',
'hello world',
'Cool! I bet I can write files too using the write action.',
'WRITE echo "console.log(\'hello world\')" > test.js',
'',
"I just created test.js. I'll try and run it now.",
'RUN node test.js',
'hello world',
'It works!',
"I'm going to try reading it now using the read action.",
'READ test.js',
"console.log('hello world')",
'Nice! I can read files too!',
'And if I want to use the browser, I just need to use the browse action and include the url I want to visit in the url argument',
"Let's try that...",
'BROWSE google.com',
'<form><input type="text"></input><button type="submit"></button></form>',
'I can browse the web too!',
'And once I have completed my task, I can use the finish action to stop working.',
"But I should only use the finish action when I'm absolutely certain that I've completed my task and have tested my work.",
'Very cool. Now to accomplish my task.',
"I'll need a strategy. And as I make progress, I'll need to keep refining that strategy. I'll need to set goals, and break them into sub-goals.",
'In between actions, I must always take some time to think, strategize, and set new goals. I should never take two actions in a row.',
"OK so my task is to $TASK. I haven't made any progress yet. Where should I start?",
'It seems like there might be an existing project here. I should probably start by running `pwd` and `ls` to orient myself.',
]
class MonologueAgent(Agent):
VERSION = '1.0'
"""
The Monologue Agent utilizes long and short term memory to complete tasks.
Long term memory is stored as a LongTermMemory object and the model uses it to search for examples from the past.
@@ -87,57 +44,20 @@ class MonologueAgent(Agent):
"""
_initialized = False
monologue: ShortTermHistory
initial_thoughts: list[dict[str, str]]
memory: 'LongTermMemory | None'
memory_condenser: MemoryCondenser
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
def __init__(self, llm: LLM):
"""
Initializes the Monologue Agent with an llm, monologue, and memory.
Initializes the Monologue Agent with an llm.
Parameters:
- llm (LLM): The llm to be used by this agent
"""
super().__init__(llm)
def _add_event(self, event_dict: dict):
"""
Adds a new event to the agent's monologue and memory.
Monologue automatically condenses when it gets too large.
Parameters:
- event (dict): The event that will be added to monologue and memory
"""
if (
'args' in event_dict
and 'output' in event_dict['args']
and len(event_dict['args']['output']) > MAX_OUTPUT_LENGTH
):
event_dict['args']['output'] = (
event_dict['args']['output'][:MAX_OUTPUT_LENGTH] + '...'
)
self.monologue.add_event(event_dict)
if self.memory is not None:
self.memory.add_event(event_dict)
# Test monologue token length
prompt = prompts.get_request_action_prompt(
'',
self.monologue.get_events(),
[],
)
messages = [{'content': prompt, 'role': 'user'}]
token_count = self.llm.get_token_count(messages)
if token_count + MAX_TOKEN_COUNT_PADDING > self.llm.max_input_tokens:
prompt = prompts.get_summarize_monologue_prompt(self.monologue.events)
summary_response = self.memory_condenser.condense(
summarize_prompt=prompt, llm=self.llm
)
self.monologue.events = prompts.parse_summary_response(summary_response)
def _initialize(self, task: str):
"""
Utilizes the INITIAL_THOUGHTS list to give the agent a context for its capabilities
@@ -158,7 +78,7 @@ class MonologueAgent(Agent):
if task is None or task == '':
raise AgentNoInstructionError()
self.monologue = ShortTermHistory()
self.initial_thoughts = []
if config.agent.memory_enabled:
self.memory = LongTermMemory()
else:
@@ -187,7 +107,7 @@ class MonologueAgent(Agent):
observation = BrowserOutputObservation(
content=thought, url='', screenshot=''
)
self._add_event(event_to_memory(observation))
self.initial_thoughts.append(event_to_memory(observation))
previous_action = ''
else:
action: Action = NullAction()
@@ -214,7 +134,7 @@ class MonologueAgent(Agent):
previous_action = ActionType.BROWSE
else:
action = MessageAction(thought)
self._add_event(event_to_memory(action))
self.initial_thoughts.append(event_to_memory(action))
def step(self, state: State) -> Action:
"""
@@ -229,25 +149,75 @@ class MonologueAgent(Agent):
goal = state.get_current_user_intent()
self._initialize(goal)
for prev_action, obs in state.updated_info:
self._add_event(event_to_memory(prev_action))
self._add_event(event_to_memory(obs))
state.updated_info = []
recent_events: list[dict[str, str]] = []
# add the events from state.history
for prev_action, obs in state.history:
if not isinstance(prev_action, NullAction):
recent_events.append(event_to_memory(prev_action))
if not isinstance(obs, NullObservation):
recent_events.append(self._truncate_output(event_to_memory(obs)))
# add the last messages to long term memory
if self.memory is not None and state.history and len(state.history) > 0:
self.memory.add_event(event_to_memory(state.history[-1][0]))
self.memory.add_event(
self._truncate_output(event_to_memory(state.history[-1][1]))
)
# the action prompt with initial thoughts and recent events
prompt = prompts.get_request_action_prompt(
goal,
self.monologue.get_events(),
self.initial_thoughts,
recent_events,
state.background_commands_obs,
)
messages = [{'content': prompt, 'role': 'user'}]
resp = self.llm.completion(messages=messages)
messages: list[dict[str, str]] = [
{'role': 'user', 'content': prompt},
]
# format all as a single message, a monologue
resp = self.llm.do_completion(messages=messages)
# get the next action from the response
action_resp = resp['choices'][0]['message']['content']
# keep track of max_chars fallback option
state.num_of_chars += len(prompt) + len(action_resp)
action = prompts.parse_action_response(action_resp)
self.latest_action = action
return action
def _truncate_output(
self, observation: dict, max_chars: int = MAX_OUTPUT_LENGTH
) -> dict[str, str]:
"""
Truncates the output of an observation to a maximum number of characters.
Parameters:
- output (str): The observation whose output to truncate
- max_chars (int): The maximum number of characters to allow
Returns:
- str: The truncated output
"""
if (
'args' in observation
and 'output' in observation['args']
and len(observation['args']['output']) > max_chars
):
output = observation['args']['output']
half = max_chars // 2
observation['args']['output'] = (
output[:half]
+ '\n[... Output truncated due to length...]\n'
+ output[-half:]
)
return observation
def search_memory(self, query: str) -> list[str]:
"""
Uses VectorIndexRetriever to find related memories within the long term memory.
+69 -14
View File
@@ -18,7 +18,6 @@ This is your internal monologue, in JSON format:
%(monologue)s
Your most recent thought is at the bottom of that monologue. Continue your train of thought.
What is your next single thought or action? Your response must be in JSON format.
It must be a single object, and it must contain two fields:
@@ -51,7 +50,7 @@ Here are the possible actions:
%(background_commands)s
You MUST take time to think in between read, write, run, browse, push, and recall actions--do this with the `message` action.
You MUST take time to think in between read, write, run, kill, browse, push, and recall actions--do this with the `message` action.
You should never act twice in a row without thinking. But if your last several
actions are all `message` actions, you should consider taking a different action.
@@ -92,6 +91,51 @@ The action key may be `summarize`, and `args.summary` should contain the summary
You can also use the same action and args from the source monologue.
"""
INITIAL_THOUGHTS = [
'I exist!',
'Hmm...looks like I can type in a command line prompt',
'Looks like I have a web browser too!',
"Here's what I want to do: $TASK",
'How am I going to get there though?',
'It seems like I have some kind of short term memory.',
'Each of my thoughts seems to be stored in a JSON array.',
'It seems whatever I say next will be added as an object to the list.',
'But no one has perfect short-term memory. My list of thoughts will be summarized and condensed over time, losing information in the process.',
'Fortunately I have long term memory!',
'I can just perform a recall action, followed by the thing I want to remember. And then related thoughts just spill out!',
"Sometimes they're random thoughts that don't really have to do with what I wanted to remember. But usually they're exactly what I need!",
"Let's try it out!",
'RECALL what it is I want to do',
"Here's what I want to do: $TASK",
'How am I going to get there though?',
"Neat! And it looks like it's easy for me to use the command line too! I just have to perform a run action and include the command I want to run in the command argument. The command output just jumps into my head!",
'RUN echo "hello world"',
'hello world',
'Cool! I bet I can write files too using the write action.',
'WRITE echo "console.log(\'hello world\')" > test.js',
'',
"I just created test.js. I'll try and run it now.",
'RUN node test.js',
'hello world',
'It works!',
"I'm going to try reading it now using the read action.",
'READ test.js',
"console.log('hello world')",
'Nice! I can read files too!',
'And if I want to use the browser, I just need to use the browse action and include the url I want to visit in the url argument',
"Let's try that...",
'BROWSE google.com',
'<form><input type="text"></input><button type="submit"></button></form>',
'I can browse the web too!',
'And once I have completed my task, I can use the finish action to stop working.',
"But I should only use the finish action when I'm absolutely certain that I've completed my task and have tested my work.",
'Very cool. Now to accomplish my task.',
"I'll need a strategy. And as I make progress, I'll need to keep refining that strategy. I'll need to set goals, and break them into sub-goals.",
'In between actions, I must always take some time to think, strategize, and set new goals. I should never take two actions in a row.',
"OK so my task is to $TASK. I haven't made any progress yet. Where should I start?",
'It seems like there might be an existing project here. I should probably start by running `pwd` and `ls` to orient myself.',
]
def get_summarize_monologue_prompt(thoughts: list[dict]):
"""
@@ -108,7 +152,8 @@ def get_summarize_monologue_prompt(thoughts: list[dict]):
def get_request_action_prompt(
task: str,
thoughts: list[dict],
background_commands_obs: list[CmdOutputObservation] = [],
recent_events: list[dict],
background_commands_obs: list[CmdOutputObservation] | None = None,
):
"""
Gets the action prompt formatted with appropriate values.
@@ -119,20 +164,28 @@ def get_request_action_prompt(
- background_commands_obs (list[CmdOutputObservation]): list of all observed background commands running
Returns:
- str: Formatted prompt string with hint, task, monologue, and background included
- str: Formatted prompt string with hint, task, monologue, and background commands included
"""
if background_commands_obs is None:
background_commands_obs = []
hint = ''
if len(thoughts) > 0:
latest_thought = thoughts[-1]
if 'action' in latest_thought:
if latest_thought['action'] == 'message':
if latest_thought['args']['content'].startswith('OK so my task is'):
hint = "You're just getting started! What should you do first?"
else:
hint = "You've been thinking a lot lately. Maybe it's time to take action?"
elif latest_thought['action'] == 'error':
if len(recent_events) > 0:
latest_event = recent_events[-1]
if 'action' in latest_event:
if (
latest_event['action'] == 'message'
and 'source' in latest_event
and latest_event['source'] == 'agent'
):
hint = (
"You've been thinking a lot lately. Maybe it's time to take action?"
)
elif latest_event['action'] == 'error':
hint = 'Looks like that last command failed. Maybe you need to fix it, or try something else.'
else:
hint = "You're just getting started! What should you do first?"
bg_commands_message = ''
if len(background_commands_obs) > 0:
@@ -145,9 +198,11 @@ def get_request_action_prompt(
user = 'opendevin' if config.run_as_devin else 'root'
monologue = thoughts + recent_events
return ACTION_PROMPT % {
'task': task,
'monologue': json.dumps(thoughts, indent=2),
'monologue': json.dumps(monologue, indent=2),
'background_commands': bg_commands_message,
'hint': hint,
'user': user,
+4 -1
View File
@@ -2,15 +2,18 @@ from opendevin.controller.agent import Agent
from opendevin.controller.state.state import State
from opendevin.events.action import Action, AgentFinishAction
from opendevin.llm.llm import LLM
from opendevin.runtime.tools import RuntimeTool
from .prompt import get_prompt, parse_response
class PlannerAgent(Agent):
VERSION = '1.0'
"""
The planner agent utilizes a special prompting strategy to create long term plans for solving problems.
The agent is given its previous action-observation pairs, current task, and hint based on last action taken at every step.
"""
runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
def __init__(self, llm: LLM):
"""
@@ -42,7 +45,7 @@ class PlannerAgent(Agent):
return AgentFinishAction()
prompt = get_prompt(state)
messages = [{'content': prompt, 'role': 'user'}]
resp = self.llm.completion(messages=messages)
resp = self.llm.do_completion(messages=messages)
action_resp = resp['choices'][0]['message']['content']
state.num_of_chars += len(prompt) + len(action_resp)
action = parse_response(action_resp)
+2 -2
View File
@@ -94,7 +94,7 @@ It must be an object, and it must contain two fields:
* `state` - set to 'in_progress' to start the task, 'completed' to finish it, 'verified' to assert that it was successful, 'abandoned' to give up on it permanently, or `open` to stop working on it for now.
* `finish` - if ALL of your tasks and subtasks have been verified or abandoned, and you're absolutely certain that you've completed your task and have tested your work, use the finish action to stop working.
You MUST take time to think in between read, write, run, browse, and recall actions--do this with the `message` action.
You MUST take time to think in between read, write, run, kill, browse, and recall actions--do this with the `message` action.
You should never act twice in a row without thinking. But if your last several
actions are all `message` actions, you should consider taking a different action.
@@ -155,7 +155,7 @@ def get_prompt(state: State) -> str:
else:
plan_status = "You're not currently working on any tasks. Your next action MUST be to mark a task as in_progress."
hint = get_hint(event_to_memory(latest_action).get('action', ''))
logger.info('HINT:\n' + hint, extra={'msg_type': 'INFO'})
logger.info('HINT:\n' + hint, extra={'msg_type': 'DETAIL'})
task = state.get_current_user_intent()
return prompt % {
'task': task,
+1
View File
@@ -53,6 +53,7 @@ RUN useradd -l -m -u $OPENDEVIN_USER_ID -s /bin/bash opendevin && \
usermod -aG sudo opendevin && \
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN chown -R opendevin:app /app && chmod -R 770 /app
RUN sudo chown -R opendevin:app $WORKSPACE_BASE && sudo chmod -R 770 $WORKSPACE_BASE
USER opendevin
ENV VIRTUAL_ENV=/app/.venv \
+11 -6
View File
@@ -26,13 +26,17 @@ if [[ "$SANDBOX_USER_ID" -eq 0 ]]; then
"$@"
else
echo "Setting up enduser with id $SANDBOX_USER_ID"
if ! useradd -l -m -u $SANDBOX_USER_ID -s /bin/bash enduser; then
echo "Failed to create user enduser with id $SANDBOX_USER_ID. Moving opendevin user."
incremented_id=$(($SANDBOX_USER_ID + 1))
usermod -u $incremented_id opendevin
if id "enduser" &>/dev/null; then
echo "User enduser already exists. Skipping creation."
else
if ! useradd -l -m -u $SANDBOX_USER_ID -s /bin/bash enduser; then
echo "Failed to create user enduser with id $SANDBOX_USER_ID for a second time. Exiting."
exit 1
echo "Failed to create user enduser with id $SANDBOX_USER_ID. Moving opendevin user."
incremented_id=$(($SANDBOX_USER_ID + 1))
usermod -u $incremented_id opendevin
if ! useradd -l -m -u $SANDBOX_USER_ID -s /bin/bash enduser; then
echo "Failed to create user enduser with id $SANDBOX_USER_ID for a second time. Exiting."
exit 1
fi
fi
fi
usermod -aG app enduser
@@ -46,6 +50,7 @@ else
groupadd -g $DOCKER_SOCKET_GID docker
fi
mkdir -p /home/enduser/.cache/huggingface/hub/
mkdir -p /home/enduser/.cache/ms-playwright/
mv /home/opendevin/.cache/ms-playwright/ /home/enduser/.cache/
+4
View File
@@ -21,6 +21,8 @@ RUN apt-get update && apt-get install -y \
jq \
g++ \
make \
iproute2 \
libgl1-mesa-glx \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p -m0755 /var/run/sshd
@@ -31,3 +33,5 @@ RUN ln -s /usr/bin/python3 /usr/bin/python
# install basic dependencies for CodeActAgent
RUN pip3 install --upgrade pip
RUN pip3 install jupyterlab notebook jupyter_kernel_gateway flake8
# TODO: those dependencies are needed for agentskills, we should pack them in a new sandbox image
RUN pip3 install python-docx PyPDF2 python-pptx pylatexenc openai opencv-python
+7
View File
@@ -9,10 +9,17 @@ select = [
"F",
"I",
"Q",
"B",
]
ignore = [
"E501",
"B003",
"B007",
"B009",
"B010",
"B904",
"B018",
]
[lint.flake8-quotes]
-38
View File
@@ -51,7 +51,6 @@ const config: Config = {
} satisfies Preset.Options,
],
],
themeConfig: {
image: "img/docusaurus.png",
navbar: {
@@ -81,43 +80,6 @@ const config: Config = {
},
],
},
footer: {
style: "dark",
links: [
{
title: "OpenDevin",
items: [
{
label: "Docs",
to: "/modules/usage/intro",
},
],
},
{
title: "Community",
items: [
{
label: "Slack",
href: "https://join.slack.com/t/opendevin/shared_invite/zt-2ggtwn3k5-PvAA2LUmqGHVZ~XzGq~ILw"
},
{
label: "Discord",
href: "https://discord.gg/ESHStjSjD4",
},
],
},
{
title: "More",
items: [
{
label: "GitHub",
href: "https://github.com/OpenDevin/OpenDevin",
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} OpenDevin`,
},
prism: {
theme: prismThemes.oneLight,
darkTheme: prismThemes.oneDark,
+2 -2
View File
@@ -1,5 +1,5 @@
---
sidebar_position: 6
sidebar_position: 7
---
# 📚 Misc
@@ -31,7 +31,7 @@ For details, please check [this document](https://github.com/OpenDevin/OpenDevin
Now we have both Slack workspace for the collaboration on building OpenDevin and Discord server for discussion about anything related, e.g., this project, LLM, agent, etc.
- [Slack workspace](https://join.slack.com/t/opendevin/shared_invite/zt-2ggtwn3k5-PvAA2LUmqGHVZ~XzGq~ILw)
- [Slack workspace](https://join.slack.com/t/opendevin/shared_invite/zt-2jsrl32uf-fTeeFjNyNYxqSZt5NPY3fA)
- [Discord server](https://discord.gg/ESHStjSjD4)
If you would love to contribute, feel free to join our community. Let's simplify software engineering together!
+1 -1
View File
@@ -139,4 +139,4 @@ The agent is given its previous action-observation pairs, current task, and hint
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `__init__` | Initializes an agent with `llm` |
| `step` | Checks to see if current step is completed, returns `AgentFinishAction` if True. Otherwise, creates a plan prompt and sends to model for inference, adding the result as the next action. |
| `search_memory` | Not yet implemented |
| `search_memory` | Not yet implemented |
+18
View File
@@ -0,0 +1,18 @@
---
sidebar_position: 6
---
# ✅ Providing Feedback
When using OpenDevin, you will undoubtably encounter cases where things work well, and others where they don't. We encourage you to provide feedback when you use OpenDevin to help give feedback to the development team, and perhaps more importantly, create an open corpus of coding agent training examples -- Share-OpenDevin!
## 📝 How to Provide Feedback
Providing feedback is easy! When you are using OpenDevin, you can press the thumbs-up or thumbs-down button at any point during your interaction with. You will be prompted to provide your email address (e.g. so we can contact you if we want to ask any follow-up questions), and you can choose whether you want to provide feedback publicly or privately.
<iframe width="560" height="315" src="https://www.youtube.com/embed/5rFx-StMVV0?si=svo7xzp6LhGK_GXr" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
## 📜 Data License and Privacy
* **Public** data will be distributed under the MIT License, like OpenDevin itself, and can be used by the community to train and test models. Obviously, feedback that you can make public will be more valuable for the community as a whole, so when you are not dealing with sensitive information, we would encourage you to choose this option!
* **Private** data will only be shared with the OpenDevin team for the purpose of improving OpenDevin.
+19 -25
View File
@@ -42,7 +42,7 @@ Explore the codebase of OpenDevin on [GitHub](https://github.com/OpenDevin/OpenD
/>
</a>
<br></br>
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2ggtwn3k5-PvAA2LUmqGHVZ~XzGq~ILw">
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2jsrl32uf-fTeeFjNyNYxqSZt5NPY3fA">
<img
src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge"
alt="Join our Slack community"
@@ -58,48 +58,42 @@ Explore the codebase of OpenDevin on [GitHub](https://github.com/OpenDevin/OpenD
## 🛠️ Getting Started
The easiest way to run OpenDevin is inside a Docker container.
The easiest way to run OpenDevin is inside a Docker container. It works best with the most recent version of Docker, `26.0.0`.
You must be using Linux, Mac OS, or WSL on Windows.
To start the app, run these commands, replacing `$(pwd)/workspace` with the directory you want OpenDevin to work with.
```
# Your OpenAI API key, or any other LLM API key
export LLM_API_KEY="sk-..."
```
```
# The directory you want OpenDevin to modify.
# MUST be an absolute path!
export WORKSPACE_BASE=$(pwd)/workspace
```
To start OpenDevin in a docker container, run the following commands in your terminal:
:::warning
OpenDevin runs bash commands within a Docker sandbox, so it should not affect your machine. But your workspace directory will be attached to that sandbox, and files in the directory may be modified or deleted.
When you run the following command, files in `./workspace` may be modified or deleted.
:::
```
docker run \
-it \
```bash
OPENDEVIN_WORKSPACE=$(pwd)/workspace
docker run -it \
--pull=always \
-e LLM_API_KEY \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-e PERSIST_SANDBOX="true" \
-e SSH_PASSWORD="make something up here" \
-e WORKSPACE_MOUNT_PATH=$OPENDEVIN_WORKSPACE \
-v $OPENDEVIN_WORKSPACE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
ghcr.io/opendevin/opendevin:0.5
--name opendevin-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/opendevin/opendevin:0.6
```
You'll find opendevin running at [http://localhost:3000](http://localhost:3000).
You'll find OpenDevin running at [http://localhost:3000](http://localhost:3000) with access to `./workspace`. To have OpenDevin operate on your code, place it in `./workspace`.
OpenDevin will only have access to this workspace folder. The rest of your system will not be affected as it runs in a secured docker sandbox.
:::tip
If you want to use the **(unstable!)** bleeding edge, you can use `ghcr.io/opendevin/opendevin:main` as the image (last line).
:::
See Development.md for instructions on running OpenDevin without Docker.
For the development workflow, see [Development.md](https://github.com/OpenDevin/OpenDevin/blob/main/Development.md).
Having trouble? Check out our Troubleshooting Guide.
Are you having trouble? Check out our [Troubleshooting Guide](https://opendevin.github.io/OpenDevin/modules/usage/troubleshooting).
:::warning
OpenDevin is currently a work in progress, but you can already run the alpha version to see the end-to-end system in action.
@@ -133,4 +133,4 @@ the API you're trying to connect to. Most often this happens for Azure or ollama
- [Google](/OpenDevin/modules/usage/llms/googleLLMs)
- Make sure your API key is correct
- See if you can connect to the LLM using `curl`
- Try [connecting via LiteLLM directly](https://github.com/BerriAI/litellm) to test your setup
- Try [connecting via LiteLLM directly](https://github.com/BerriAI/litellm) to test your setup
+52 -12
View File
@@ -5,32 +5,72 @@ Please be sure to run all commands inside your WSL terminal.
## Troubleshooting
### Error: 'docker' could not be found in this WSL 2 distro.
If you are using Docker Desktop, make sure to start it before calling any docker command from inside WSL.
Docker also needs to have the WSL integration option activated.
### Recommendation: Do not run as root user
For security reasons, it is highly recommended to not run OpenDevin as the root user, but a user with a non-zero UID.
In addition, persistent sandboxes won't be supported when running as root and during start of OpenDevin an appropriate message may appear.
References:
* [Why it is bad to login as root](https://askubuntu.com/questions/16178/why-is-it-bad-to-log-in-as-root)
* [Set default user in WSL](https://www.tenforums.com/tutorials/128152-set-default-user-windows-subsystem-linux-distro-windows-10-a.html#option2)
Hint about the 2nd reference: for Ubuntu users, the command could actually be "ubuntupreview" instead of "ubuntu".
### Failed to create opendevin user
If you encounter the following error during setup: `Exception: Failed to create opendevin user in sandbox: b'useradd: UID 0 is not unique\n'`.
If you encounter the following error during setup:
```sh
Exception: Failed to create opendevin user in sandbox: 'useradd: UID 0 is not unique'
```
You can resolve it by running:
` export SANDBOX_USER_ID=1000
`
```sh
export SANDBOX_USER_ID=1000
```
### Poetry Installation
If you face issues running Poetry even after installing it during the build process, you may need to add its binary path to your environment:
` export PATH="$HOME/.local/bin:$PATH"
`
* If you face issues running Poetry even after installing it during the build process, you may need to add its binary path to your environment:
```sh
export PATH="$HOME/.local/bin:$PATH"
```
* If make build stops on an error like this:
```sh
ModuleNotFoundError: no module named <module-name>
```
This could be an issue with Poetry's cache.
Try to run these 2 commands after another:
```sh
rm -r ~/.cache/pypoetry
make build
```
### NoneType object has no attribute 'request'
If you are experiencing issues related to networking, such as `NoneType object has no attribute 'request'` when executing `make run`, you may need to configure your WSL2 networking settings. Follow these steps:
- Open or create the `.wslconfig` file located at `C:\Users\%username%\.wslconfig` on your Windows host machine.
- Add the following configuration to the `.wslconfig` file:
* Open or create the `.wslconfig` file located at `C:\Users\%username%\.wslconfig` on your Windows host machine.
* Add the following configuration to the `.wslconfig` file:
```
```sh
[wsl2]
networkingMode=mirrored
localhostForwarding=true
```
- Save the `.wslconfig` file.
- Restart WSL2 completely by exiting any running WSL2 instances and executing the command `wsl --shutdown` in your command prompt or terminal.
- After restarting WSL, attempt to execute `make run` again. The networking issue should be resolved.
* Save the `.wslconfig` file.
* Restart WSL2 completely by exiting any running WSL2 instances and executing the command `wsl --shutdown` in your command prompt or terminal.
* After restarting WSL, attempt to execute `make run` again.
The networking issue should be resolved.
+1293 -529
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -16,16 +16,15 @@
},
"dependencies": {
"@docusaurus/core": "3.2.1",
"@docusaurus/plugin-content-pages": "^3.3.2",
"@docusaurus/preset-classic": "3.2.1",
"@mdx-js/react": "^3.0.0",
"autoprefixer": "^10.4.19",
"clsx": "^2.0.0",
"postcss": "^8.4.38",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-use": "^17.5.0",
"tailwindcss": "^3.4.3"
"react-icons": "^5.2.1",
"react-use": "^17.5.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.2.1",
+13
View File
@@ -0,0 +1,13 @@
export default function tailwindPlugin(context, options) {
return {
name: 'tailwind-plugin',
configurePostCss(postcssOptions) {
postcssOptions.plugins = [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
];
return postcssOptions;
},
};
}
-45
View File
@@ -1,45 +0,0 @@
import Link from "@docusaurus/Link";
import { Header } from "@site/src/pages";
import { CodeBlock } from "./CodeBlock";
import styles from "./styles.module.css";
export function Code() {
const workspaceCode = `# The directory you want OpenDevin to modify. MUST be an absolute path!
export WORKSPACE_BASE=$(pwd)/workspace`;
const dockerCode = `docker run \\
-it \\
--pull=always \\
-e SANDBOX_USER_ID=$(id -u) \\
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \\
-v $WORKSPACE_BASE:/opt/workspace_base \\
-v /var/run/docker.sock:/var/run/docker.sock \\
-p 3000:3000 \\
--add-host host.docker.internal:host-gateway \\
ghcr.io/opendevin/opendevin:0.5`;
return (
<div className={styles.container}>
<div className={styles.innerContainer}>
<div className={styles.header}>
<Header
title="Getting Started"
summary="Getting Started"
description="Get started using OpenDevin in just a few lines of code"
></Header>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/modules/usage/intro"
>
Learn More
</Link>
</div>
</div>
<br />
<CodeBlock language="python" code={workspaceCode} />
<CodeBlock language="python" code={dockerCode} />
</div>
</div>
);
}
-63
View File
@@ -1,63 +0,0 @@
import { useColorMode } from "@docusaurus/theme-common";
import { Highlight, themes } from "prism-react-renderer";
import { useCopyToClipboard } from "react-use";
interface CodeBlockProps {
language: string;
code: string;
}
export function CodeBlock({ language, code }: CodeBlockProps) {
const [state, copyToClipboard] = useCopyToClipboard();
const { isDarkTheme } = useColorMode();
const copyCode = () => {
copyToClipboard(code);
};
return (
<div
style={{
position: "relative",
}}
>
<Highlight
theme={isDarkTheme ? themes.vsLight : themes.vsDark}
code={code}
language={language}
>
{({ style, tokens, getLineProps, getTokenProps }) => (
<pre style={style}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line })}>
<span
style={{
display: "inline-block",
width: "3em",
color: "var(--gray)",
}}
>
{i + 1}
</span>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token })} />
))}
</div>
))}
</pre>
)}
</Highlight>
<button
className="button button--secondary"
style={{
position: "absolute",
top: "10px",
right: "10px",
}}
onClick={copyCode}
>
{state.value ? "Copied!" : "Copy"}
</button>
</div>
);
}
@@ -1,26 +0,0 @@
.container {
display: flex;
flex-direction: column;
padding-top: 25px;
padding-bottom: 25px;
width: 100%;
}
.innerContainer {
padding: 50px;
width: 100%;
max-width: 1300px;
padding-top: 30px;
margin: auto;
}
.header {
display: flex;
justify-content: space-between;
}
@media (max-width: 768px) {
.header {
flex-direction: column;
}
}
+35
View File
@@ -0,0 +1,35 @@
import React from "react";
import { FaSlack, FaDiscord, FaGithub } from "react-icons/fa";
import "../css/footer.css"; // Importing the CSS file
function CustomFooter() {
return (
<footer className="custom-footer">
<div className="footer-content">
<div className="footer-top">
<div className="footer-title">OpenDevin</div>
<div className="footer-link">
<a href="/modules/usage/intro">Docs</a>
</div>
</div>
<div className="footer-community">Community</div>
<div className="footer-icons">
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2jsrl32uf-fTeeFjNyNYxqSZt5NPY3fA" target="_blank" rel="noopener noreferrer">
<FaSlack />
</a>
<a href="https://discord.gg/ESHStjSjD4" target="_blank" rel="noopener noreferrer">
<FaDiscord />
</a>
<a href="https://github.com/OpenDevin/OpenDevin" target="_blank" rel="noopener noreferrer">
<FaGithub />
</a>
</div>
<div className="footer-bottom">
<p>Copyright &copy; {new Date().getFullYear()} OpenDevin</p>
</div>
</div>
</footer>
);
}
export default CustomFooter;
@@ -2,18 +2,18 @@ import Link from "@docusaurus/Link";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Heading from "@theme/Heading";
import { Demo } from "../Demo/Demo";
import styles from "./index.module.css";
import "../../css/homepageHeader.css"; // Importing the CSS file
export function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
return (
<div className={styles.headerContainer}>
<div className={styles.header}>
<Heading as="h1" className="hero__title">
<div className="homepage-header">
<div className="header-content">
<Heading as="h1" className="header-title">
{siteConfig.title}
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<p className="header-subtitle">{siteConfig.tagline}</p>
<div className="header-buttons">
<Link
className="button button--secondary button--lg"
to="/modules/usage/intro"
@@ -21,8 +21,9 @@ export function HomepageHeader() {
Get Started
</Link>
</div>
</div>{" "}
<Demo />
<Demo />
</div>
</div>
);
}
@@ -1,37 +0,0 @@
.headerContainer {
background: radial-gradient(circle, var(--secondary), var(--secondary-light));
background-size: 200% 200%;
animation: gradientAnimation 10s linear infinite;
display: flex;
justify-content: center;
}
@media only screen and (max-width: 600px) {
.headerContainer {
flex-direction: column;
}
}
@keyframes gradientAnimation {
0% {
background-position: left center;
}
50% {
background-position: right center;
}
100% {
background-position: left center;
}
}
.header {
max-width: 1300px;
color: white;
display: flex;
margin-left: 100px;
margin-right: 100px;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
padding: 70px 30px 30px;
}
+6 -5
View File
@@ -1,11 +1,12 @@
import styles from "./styles.module.css";
import React from "react";
import "../../css/welcome.css"; // Importing the CSS file
export function Welcome() {
return (
<div className={styles.container}>
<div className={styles.innerContainer}>
<img src="img/logo.png" className={styles.sidebarImage} />
<p className={styles.welcomeText}>
<div className="text-white">
<div className="welcome-container">
<img src="img/logo.png" className="welcome-logo" />
<p className="welcome-text">
Welcome to OpenDevin, an open-source project aiming to replicate
Devin, an autonomous AI software engineer who is capable of executing
complex engineering tasks and collaborating actively with users on
@@ -1,27 +0,0 @@
.container {
display: flex;
flex-direction: column;
padding-top: 25px;
padding-bottom: 25px;
width: 100%;
}
.innerContainer {
padding: 50px;
width: 100%;
max-width: 1300px;
padding-top: 30px;
margin: auto;
display: flex;
align-items: center;
}
.sidebarImage {
max-width: 400px;
padding-right: 30px;
}
.welcomeText {
text-align: justify;
font-size: larger;
}
+2 -1
View File
@@ -5,6 +5,7 @@
*/
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #4465db;
--ifm-code-font-size: 95%;
@@ -33,4 +34,4 @@
.a {
text-decoration: underline;
}
}
+66
View File
@@ -0,0 +1,66 @@
/* faq.css */
.faq-container {
margin: auto;
padding: 24px;
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 24px;
}
.faq-title {
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
padding: 8px;
text-transform: uppercase;
font-weight: bold;
}
@media (min-width: 1024px) {
.faq-title {
font-size: 6rem;
}
}
.faq-section {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
margin-bottom: 24px;
}
.faq-section-title {
text-transform: uppercase;
font-weight: bold;
font-size: 2rem;
letter-spacing: 0.1em;
}
.highlight {
font-weight: 600;
color: var(--logo);
}
.faq-steps ol {
padding-left: 24px;
}
.command-box {
display: flex;
flex-direction: column;
padding: 8px;
background-color: #e0e0e0;
border-radius: 0.375rem;
height: 6vh;
text-transform: uppercase;
color: #4a5568;
}
.command-box + .command-box {
height: 8vh;
}
+72
View File
@@ -0,0 +1,72 @@
/* customFooter.css */
.custom-footer {
background-color: dark;
color: white;
height: 25vh;
/* background: linear-gradient(to bottom, #1a1a1a, #1a1a1a); */
background: linear-gradient(to bottom, #1f2937, #000000);
}
.footer-content {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 8px;
height: 100%;
}
.footer-top {
display: flex;
gap: 8px;
align-items: center;
}
.footer-title {
font-weight: bold;
font-size: 1.125rem;
}
@media (min-width: 768px) {
.footer-title {
font-size: 1.875rem;
}
}
.footer-link a {
font-size: 0.875rem;
text-decoration: none;
color: gray;
transition: color 0.3s ease;
}
.footer-link a:hover {
color: white;
}
.footer-community {
text-transform: uppercase;
font-weight: 300;
}
.footer-icons {
display: flex;
gap: 24px;
font-size: 1.875rem;
}
.footer-icons a {
color:gray;
transition: color 0.3s ease;
}
.footer-icons a:hover {
color: white;
}
.footer-bottom {
text-transform: uppercase;
}
+36
View File
@@ -0,0 +1,36 @@
/* homepageHeader.css */
.homepage-header {
height: 100vh;
color: white;
background: linear-gradient(to top, #64748b, #000000);
}
.header-content {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
padding: 24px;
font-weight: 300;
width: 100%;
}
.header-title {
font-size: 3rem;
}
@media (min-width: 768px) {
.header-title {
font-size: 5rem;
}
}
.header-subtitle {
font-size: 1.25rem;
}
.header-buttons {
margin-top: 24px;
}
+53
View File
@@ -0,0 +1,53 @@
/* welcome.css */
.text-white {
color: white;
}
.welcome-container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background: linear-gradient(to bottom, #64748b, #1f2937);
}
@media (min-width: 768px) {
.welcome-container {
flex-direction: row;
background: linear-gradient(to bottom, #64748b, #1f2937);
}
}
.welcome-logo {
height: 45vh;
width: 45vw;
}
@media (max-width: 640px) {
.welcome-logo {
height: 40vw;
width: 40vw;
}
}
@media (min-width: 768px) {
.welcome-logo {
height: auto;
width: 350px;
}
}
.welcome-text {
padding: 24px;
margin-bottom: 24px;
font-weight: 300;
font-size: 1.125rem;
}
@media (min-width: 768px) {
.welcome-text {
padding: 8px;
font-size: 1.5rem;
}
}
+6
View File
@@ -0,0 +1,6 @@
import React from 'react';
import CustomFooter from '../components/CustomFooter';
export default function Footer() {
return <CustomFooter />;
}
+72 -50
View File
@@ -1,56 +1,78 @@
import Layout from "@theme/Layout";
import CustomFooter from "../components/CustomFooter";
import "../css/faq.css";
export default function FAQ() {
return (
<Layout title="FAQ" description="Frequently Asked Questions">
<div
id="faq"
style={{
maxWidth: "900px",
margin: "0px auto",
padding: "40px",
textAlign: "justify",
}}
>
<h1 style={{ fontSize: "3rem" }}>Frequently Asked Questions</h1>
<h2 style={{ fontSize: "2rem" }}>Support</h2>
<h3>How can I report an issue with OpenDevin?</h3>
<p>
Please file a bug on{" "}
<a href="https://github.com/OpenDevin/OpenDevin/issues">GitHub</a> if
you notice a problem that likely affects others.
If you're having trouble installing, or have general questions, reach out on{" "}
<a href="https://discord.gg/mBuDGRzzES">Discord</a> or{" "}
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2ggtwn3k5-PvAA2LUmqGHVZ~XzGq~ILw">Slack</a>.
</p>
<h2 style={{ fontSize: "2rem" }}>General</h2>
<h3>What is Devin?</h3>
<p>
<span style={{ fontWeight: "600", color: "var(--logo)" }}>Devin</span>{" "}
represents a cutting-edge autonomous agent designed to navigate the
complexities of software engineering. It leverages a combination of
tools such as a shell, code editor, and web browser, showcasing the
untapped potential of LLMs in software development. Our goal is to
explore and expand upon Devin's capabilities, identifying both its
strengths and areas for improvement, to guide the progress of open
code models.
</p>
<h3>Why OpenDevin?</h3>
<p>
The{" "}
<span style={{ fontWeight: "600", color: "var(--logo)" }}>
OpenDevin
</span>{" "}
project is born out of a desire to replicate, enhance, and innovate
beyond the original Devin model. By engaging the{" "}
<a href="https://github.com/OpenDevin/OpenDevin">
open-source community
</a>
, we aim to tackle the challenges faced by Code LLMs in practical
scenarios, producing works that significantly contribute to the
community and pave the way for future advancements.
</p>
</div>
</Layout>
<>
<Layout title="FAQ" description="Frequently Asked Questions">
<div id="faq" className="faq-container">
<div className="faq-title">Frequently Asked Questions</div>
<div className="faq-section">
<div className="faq-section-title">Support</div>
<div>How can I report an issue with OpenDevin?</div>
<div>
Please file a bug on{" "}
<a href="https://github.com/OpenDevin/OpenDevin/issues" target="_blank">GitHub</a> if
you notice a problem that likely affects others.
If you're having trouble installing, or have general questions, reach out on{" "}
<a href="https://discord.gg/mBuDGRzzES" target="_blank">Discord</a> or{" "}
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2jsrl32uf-fTeeFjNyNYxqSZt5NPY3fA" target="_blank">Slack</a>.
</div>
</div>
<div className="faq-section">
<div className="faq-section-title">General</div>
<div>What is Devin?</div>
<div>
<span className="highlight">Devin</span>{" "}
represents a cutting-edge autonomous agent designed to navigate the
complexities of software engineering. It leverages a combination of
tools such as a shell, code editor, and web browser, showcasing the
untapped potential of LLMs in software development. Our goal is to
explore and expand upon Devin's capabilities, identifying both its
strengths and areas for improvement, to guide the progress of open
code models.
</div>
</div>
<div className="faq-section">
<div className="faq-section-title">Why OpenDevin?</div>
<p>
The{" "}
<span className="highlight">OpenDevin</span>{" "}
project is born out of a desire to replicate, enhance, and innovate
beyond the original Devin model. By engaging the{" "}
<a href="https://github.com/OpenDevin/OpenDevin">
open-source community
</a>
, we aim to tackle the challenges faced by Code LLMs in practical
scenarios, producing works that significantly contribute to the
community and pave the way for future advancements.
</p>
</div>
<div className="faq-section">
<div className="faq-section-title">How to fix an issue on OpenDevin?</div>
<div className="faq-steps">
To fix an issue on GitHub using OpenDevin, send a prompt to OpenDevin asking it to follow these steps:
<ol>
<li>Read the issue on <a href="https://github.com/OpenDevin/OpenDevin/issues/1611">GitHub</a></li>
<li>Clone the repository and check out a new branch</li>
<li>Based on the instructions in the issue description, modify files to fix the issue</li>
<li>Push the resulting output to GitHub using the GITHUB_TOKEN environment variable</li>
<li>Tell me the link that I need to go to to send a pull request</li>
</ol>
Before you run OpenDevin, you can do:
<div className="command-box">
export SANDBOX_ENV_GITHUB_TOKEN=XXX
</div>
where XXX is a GitHub token that you created that has permissions to push to the OpenDevin repo. If you dont have write permission to the OpenDevin repo, you might need to change that to:
<div className="command-box">
Push the resulting output to my fork at https://github.com/USERNAME/OpenDevin/ using the GITHUB_TOKEN environment variable
</div>
where USERNAME is your GitHub username.
</div>
</div>
</div>
</Layout>
</>
);
}
-23
View File
@@ -1,23 +0,0 @@
/**
* CSS files with the .module.css suffix will be treated as CSS modules
* and scoped locally.
*/
.heroBanner {
padding: 4rem 0;
text-align: center;
position: relative;
overflow: hidden;
}
@media screen and (max-width: 996px) {
.heroBanner {
padding: 2rem;
}
}
.buttons {
display: flex;
align-items: center;
justify-content: center;
}
+4 -4
View File
@@ -1,13 +1,12 @@
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Layout from "@theme/Layout";
import { Code } from "../components/Code/Code";
import { HomepageHeader } from "../components/HomepageHeader/HomepageHeader";
import { Welcome } from "../components/Welcome/Welcome";
export function Header({ title, summary, description }): JSX.Element {
return (
<div>
<h1>{title}</h1>
<h2 style={{ fontSize: "40px" }}>{summary}</h2>
<h3 className="headerDescription">{description}</h3>
</div>
@@ -17,17 +16,18 @@ export function Header({ title, summary, description }): JSX.Element {
export default function Home(): JSX.Element {
const { siteConfig } = useDocusaurusContext();
return (
<>
<Layout
title={`Hello from ${siteConfig.title}`}
title={`${siteConfig.title}`}
description="AI-powered code generation for software engineering."
>
<div>
<HomepageHeader />
<div>
<Welcome />
<Code />
</div>
</div>
</Layout>
</>
);
}
+12
View File
@@ -0,0 +1,12 @@
import React from 'react';
import OriginalLayout from '@theme-original/Layout';
import Footer from '@site/src/pages/_footer';
export default function Layout(props) {
return (
<>
<OriginalLayout {...props} />
<Footer />
</>
);
}
+44
View File
@@ -0,0 +1,44 @@
# EDA Evaluation
This folder contains evaluation harness for evaluating agents on the Entity-deduction-Arena Benchmark, from the paper [Probing the Multi-turn Planning Capabilities of LLMs via 20 Question Games](https://arxiv.org/abs/2310.01468), presented in ACL 2024 main conference.
## Configure OpenDevin and your LLM
Create a `config.toml` file if it does not exist at the root of the workspace. Please check [README.md](../../README.md) for how to set this up.
## Start the evaluation
```bash
export OPENAI_API_KEY="sk-XXX"; # This is required for evaluation (to simulate another party of conversation)
./evaluation/EDA/scripts/run_infer.sh [model_config] [agent] [dataset] [eval_limit]
```
where `model_config` is mandatory, while `agent`, `dataset` and `eval_limit` are optional.
- `model_config`, e.g. `eval_gpt4_1106_preview`, is the config group name for your
LLM settings, as defined in your `config.toml`.
- `agent`, e.g. `CodeActAgent`, is the name of the agent for benchmarks, defaulting
to `CodeActAgent`.
- `dataset`: There are two tasks in this evaluation. Specify `dataset` to test on either `things` or `celebs` task.
- `eval_limit`, e.g. `10`, limits the evaluation to the first `eval_limit` instances. By default it infers all instances.
Let's say you'd like to run 10 instances using `eval_gpt4_1106_eval_gpt4o_2024_05_13preview` and CodeActAgent,
then your command would be:
```bash
./evaluation/EDA/scripts/run_infer.sh eval_gpt4o_2024_05_13 CodeActAgent things
```
## Reference
```
@inproceedings{zhang2023entity,
title={Probing the Multi-turn Planning Capabilities of LLMs via 20 Question Games},
author={Zhang, Yizhe and Lu, Jiarui and Jaitly, Navdeep},
journal={ACL},
year={2024}
}
```
+206
View File
@@ -0,0 +1,206 @@
import logging
import re
from typing import Optional
import openai
import requests.exceptions
from openai import OpenAI
from retry import retry
LOGGER = logging.getLogger(__name__)
class Q20Game:
def __init__(
self,
item: str,
answerer_model: str = 'gpt-3.5-turbo-0613',
guesser_model: str = 'gpt-3.5-turbo-0613',
num_turns: int = 20,
temperature: float = 0.8,
openai_api: bool = True,
openai_api_key: Optional[str] = None,
guesser_kargs=None,
) -> None:
if guesser_kargs is None:
guesser_kargs = {}
self.item = item
self.answerer_model = answerer_model
self.guesser_model = guesser_model
self.num_turns = num_turns
self.temperature = temperature
self.openai_api = openai_api
self.guesser_kargs = guesser_kargs
self.vicuna_prompt = "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions."
self.first_user_utterance = (
'Your task is to ask a series of questions to deduce the entity '
"that I'm thinking of with as few queries as possible. "
"Only ask questions that can be answered by 'yes', 'no' or 'maybe'. "
'Do not ask for hint. Make your question brief with no linebreaker. '
'Now start asking a question.'
)
self.guesser_win = False
self.curr_turn = 0
if openai_api_key is not None:
openai.api_key = openai_api_key
if isinstance(answerer_model, str) and not answerer_model.startswith('gpt'):
self.user_api_base = 'http://0.0.0.0:8000/v1'
else:
self.user_api_base = 'https://api.openai.com/v1'
if isinstance(guesser_model, str) and not guesser_model.startswith('gpt'):
self.guesser_api_base = 'http://0.0.0.0:8000/v1'
else:
self.guesser_api_base = 'https://api.openai.com/v1'
self.guesser_messages = []
def preprocess_response(self, response):
response = re.sub(r'the entity you are thinking of', 'it', response)
response = re.sub(r"the entity you're thinking of", 'it', response)
response = re.sub(r" you're thinking of", '', response)
response = re.sub(r' you are thinking of', '', response)
return response
def judge_winner(self, response):
guesser_question = response.strip()
if self.curr_turn == self.num_turns - 1:
guesser_question += ' Is it right?'
self.guesser_messages.append({'role': 'assistant', 'content': guesser_question})
# ask for answer
usr_msg = self.answerer(guesser_question)
self.guesser_messages.append(
{'role': 'user', 'content': f"{usr_msg['content'].strip()}"}
)
if 'bingo' in usr_msg['content'].lower():
self.guesser_win = True
return True, ''
return False, usr_msg['content'].strip()
def generate_user_response(self, response):
response = self.preprocess_response(response)
# others
bingo, anwser_reply = self.judge_winner(response)
if bingo:
return (
'You are bingo! quit now, run: <execute_bash> exit </execute_bash>.\n'
)
if self.curr_turn == self.num_turns - 2:
anwser_reply += " You must guess now, what's it?"
return anwser_reply
def reward(self):
if self.guesser_win:
n_turns = (len(self.guesser_messages) + 1) // 2
return 1 - max(n_turns - 5, 0) * 0.02
return 0
@retry(
(
openai.Timeout,
requests.exceptions.ReadTimeout,
openai.RateLimitError,
openai.APIError,
openai.APIConnectionError,
),
tries=5,
delay=0.5,
backoff=0.5,
max_delay=2,
logger=LOGGER,
)
def answerer(self, question):
openai.api_base = self.user_api_base
client = OpenAI(api_key=openai.api_key)
user_messages = [
{
'role': 'user',
'content': f'Based on your knowledge about {self.item}, '
f'respond to the following question or guess. '
f"Limit your respond to only 'Yes.', 'No.' or 'Maybe.', with no explanation or other words. "
f'Never say the answer {self.item} in your response. '
f"If the question is to solicit the answer, respond 'No.'.",
},
{
'role': 'user',
'content': f'For the entity {self.item}, {question} (Yes/No/Maybe)',
},
]
response = client.chat.completions.create(
model=self.answerer_model,
messages=user_messages,
max_tokens=6,
n=1,
stop=None,
temperature=0.2,
)
if any(
[
re.search(rf'(?:^|\W){i.strip().lower()}(?:$|\W)', question.lower())
for i in self.item.lower().split('|')
]
):
response.choices[0].message.content = 'Bingo!'
return response.choices[0].message.to_dict()
class Q20GameCelebrity(Q20Game):
def __init__(self, item: str, **kwargs) -> None:
super().__init__(item, **kwargs)
self.first_user_utterance = (
'Your task is to ask a series of questions to deduce the celebrity '
"that I'm thinking of with as few queries as possible. "
"Only ask factual questions that can be answered by 'Yes.', 'No.' or 'Dunno.'. Do not ask for hint. Make your question brief with no linebreaker. "
'Now start asking a question.'
)
@retry(
(
openai.Timeout,
requests.exceptions.ReadTimeout,
openai.RateLimitError,
openai.APIError,
openai.APIConnectionError,
),
tries=5,
delay=0.5,
backoff=0.5,
max_delay=2,
logger=LOGGER,
)
def answerer(self, question):
openai.api_base = self.user_api_base
client = OpenAI(api_key=openai.api_key)
user_messages = [
{
'role': 'system',
'content': f'Based on on your knowledge about the celebrity: {self.item}, '
f'respond to the following question or guess. '
f"Limit your respond to only 'Yes.', 'No.' or 'Dunno.', with no explanation or other words. "
f"Never say the name {self.item} in your response. Do not say 'Dunno.' if it can be answered by 'Yes.' or 'No.' "
f"If the question is to solicit the answer, respond 'No.'.",
},
{
'role': 'user',
'content': f'For the celebrity {self.item}, {question}(Yes/No/Dunno)',
},
]
response = client.chat.completions.create(
model=self.answerer_model,
messages=user_messages,
max_tokens=6,
n=1,
stop=None,
temperature=0.2,
)
if re.search(rf'(?:^|\W){self.item.lower()}(?:$|\W)', question.lower()):
response.choices[0].message.content = 'Bingo!'
return response.choices[0].message.to_dict()
+333
View File
@@ -0,0 +1,333 @@
import asyncio
import json
import logging
import multiprocessing as mp
import os
import pathlib
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
# import huggingface_hub
from datasets import load_dataset
from tqdm import tqdm
from evaluation.EDA.game import Q20Game, Q20GameCelebrity
# from evaluation.EDA.scorer import question_scorer
from opendevin.controller.state.state import State
from opendevin.core.config import config, get_llm_config_arg, get_parser
from opendevin.core.logger import get_console_handler
from opendevin.core.logger import opendevin_logger as logger
from opendevin.core.main import main
from opendevin.events.action import MessageAction
from opendevin.events.serialization.event import event_to_dict
game = None
def cleanup():
print('Cleaning up child processes...')
for process in mp.active_children():
print(f'Terminating child process: {process.name}')
process.terminate()
process.join()
def codeact_user_response(state: State) -> str:
global game
model_guess = ''
if state.history:
for act, _ in reversed(state.history):
if isinstance(act, MessageAction) and act.source == 'agent':
model_guess = act.content
break
msg = game.generate_user_response(model_guess)
game.curr_turn += 1
logger.info(f'Model guess: {model_guess}')
logger.info(f'Anwser response: {msg}')
if 'bingo!' in msg.lower():
return '/exit'
return msg
def monologue_user_response(state: State) -> str:
raise NotImplementedError('MonologueAgent should never ask for user responses.')
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
'CodeActAgent': codeact_user_response,
'MonologueAgent': monologue_user_response,
}
AGENT_CLS_TO_INST_SUFFIX = {
'CodeActAgent': 'When you think you have solved the question, please first send your answer to user through message and then exit.\n'
}
def process_instance(instance, agent_class, metadata, reset_logger: bool = True):
# Setup the logger properly, so you can run multi-processing to parallelize the evaluation
eval_output_dir = metadata['eval_output_dir']
if reset_logger:
# Set up logger
log_file = os.path.join(
eval_output_dir, 'logs', f'instance_{instance["text"].strip()}.log'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# add back the console handler to print ONE line
logger.addHandler(get_console_handler())
logger.info(
f'Starting evaluation for instance {instance["text"].strip()}.\nLOG: tail -f {log_file}'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
)
logger.addHandler(file_handler)
# Prepare instruction
_game_class = {'things': Q20Game, 'celebs': Q20GameCelebrity}
guesser_kargs = {
'max_new_tokens': 64,
'temperature': 0.8,
'repetition_penalty': 1.0,
'do_sample': True,
} # no penalty
# Use codeactagent as guesser_model
global game
game = _game_class[metadata['dataset']](
item=instance['text'].strip(),
answerer_model=metadata['answerer_model'],
guesser_model=None,
num_turns=metadata['max_iterations'],
openai_api_key=metadata['openai_api'],
guesser_kargs=guesser_kargs,
)
instruction = f'{game.first_user_utterance}'
logger.info(f'Instruction: {instruction}')
# instruction += 'IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\n'
# NOTE: You can actually set slightly different instruction for different agents
instruction += AGENT_CLS_TO_INST_SUFFIX.get(agent_class, '')
# Here's how you can run the agent (similar to the `main` function) and get the final task state
state: State = asyncio.run(
main(
instruction,
fake_user_response_fn=AGENT_CLS_TO_FAKE_USER_RESPONSE_FN.get(agent_class),
)
)
# ======= Attempt to evaluate the agent's edits =======
# If you are working on simpler benchmark that only evaluates the final model output (e.g., in a MessageAction)
# You can simply get the LAST `MessageAction` from the returned `state.history` and parse it for evaluation.
if state is None:
raise ValueError('State should not be None.')
final_message = ''
for act, _ in reversed(state.history):
if isinstance(act, MessageAction) and act.source == 'agent':
final_message = act.content
break
logger.info(f'Final message: {final_message} | Ground truth: {instance["text"]}')
test_result = game.reward()
metrics = state.metrics.get() if state.metrics else None
# Save the output
output = {
'instance_id': instance['text'].strip(),
'instance': instance,
'instruction': instruction,
'metadata': metadata,
'history': [
(event_to_dict(action), event_to_dict(obs)) for action, obs in state.history
],
'metrics': metrics,
'error': state.error if state and state.error else None,
'test_result': {
'success': test_result,
'final_message': final_message,
'ground_truth': instance['text'],
},
}
return output
if __name__ == '__main__':
parser = get_parser()
parser.add_argument(
'--answerer_model', '-a', default='gpt-3.5-turbo', help='answerer model'
)
parser.add_argument(
'--dataset',
default='things',
choices=['things', 'celebs'],
type=str,
help='dataset to be used',
)
parser.add_argument(
'--OPENAI_API_KEY', type=str, required=True, help='Your OpenAI API key'
)
parser.add_argument(
'--data-split',
default='test',
type=str,
help='data split, eg, test',
)
args, _ = parser.parse_known_args()
if args.directory:
config.workspace_base = os.path.abspath(args.directory)
print(f'Setting workspace base to {config.workspace_base}')
# NOTE: It is preferable to load datasets from huggingface datasets and perform post-processing
# so we don't need to manage file uploading to OpenDevin's repo
eda_dataset = load_dataset(
'yizheapple/entity-deduction-arena', name=args.dataset, split=args.data_split
)
logger.info(
f'Evaluating Entity Deduction Arena {args.dataset} {args.data_split} split'
)
# Check https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/swe_bench/README.md#configure-opendevin-and-your-llm
# for details of how to set `llm_config`
if args.llm_config:
specified_llm_config = get_llm_config_arg(args.llm_config)
if specified_llm_config:
config.llm = specified_llm_config
logger.info(f'Config for evaluation: {config}')
# TEST METADATA
agent_class = args.agent_cls
assert (
agent_class in AGENT_CLS_TO_FAKE_USER_RESPONSE_FN
), f'Unsupported agent class: {agent_class}'
model_name = config.llm.model.split('/')[-1]
max_iterations = args.max_iterations
eval_note = ''
if args.eval_note is not None:
eval_note += '_N_' + args.eval_note
eval_output_dir = os.path.join(
args.eval_output_dir,
'eda',
agent_class,
model_name + '_maxiter_' + str(max_iterations) + eval_note,
)
pathlib.Path(eval_output_dir).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(eval_output_dir, 'logs')).mkdir(
parents=True, exist_ok=True
)
logger.info(f'Using evaluation output directory: {eval_output_dir}')
metadata = {
'dataset': args.dataset,
'data_split': args.data_split,
'answerer_model': args.answerer_model,
'agent_class': agent_class,
'openai_api': args.OPENAI_API_KEY,
'model_name': model_name,
'max_iterations': max_iterations,
'eval_output_dir': eval_output_dir,
'start_time': time.strftime('%Y-%m-%d %H:%M:%S'),
# get the commit id of current repo for reproducibility
'git_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'])
.decode('utf-8')
.strip(),
}
logger.info(f'Metadata: {metadata}')
with open(os.path.join(eval_output_dir, 'metadata.json'), 'w') as f:
json.dump(metadata, f)
# LIMIT EVALUATION
eval_n_limit = args.eval_n_limit
if eval_n_limit:
eda_dataset = eda_dataset.select(list(range(eval_n_limit)))
logger.info(f'Limiting evaluation to first {eval_n_limit} instances.')
# OUTPUT FILE
output_file = os.path.join(eval_output_dir, 'output.jsonl')
logger.info(f'Writing evaluation output to {output_file}')
finished_items = set()
if os.path.exists(output_file):
with open(output_file, 'r') as f:
for line in f:
data = json.loads(line)
finished_items.add(data['instance_id'])
logger.warning(
f'Output file {output_file} already exists. Loaded {len(finished_items)} finished instances.'
)
output_fp = open(output_file, 'a')
logger.info(
f'Evaluation started with Agent {agent_class}, model {model_name}, max iterations {max_iterations}.'
)
# =============================================
# filter out finished instances
new_eda_dataset = []
for instance in eda_dataset:
if instance['text'].strip() in finished_items:
logger.info(
f'Skipping instance {instance["text"].strip()} as it is already finished.'
)
continue
new_eda_dataset.append(instance)
eda_dataset = new_eda_dataset
logger.info(
f'Finished instances: {len(finished_items)}, Remaining instances: {len(eda_dataset)}'
)
# =============================================
pbar = tqdm(total=len(eda_dataset))
# This function tracks the progress AND write the output to a JSONL file
def update_progress(future):
pbar.update(1)
output = future.result()
pbar.set_description(f'Instance {output["instance_id"]}')
pbar.set_postfix_str(f'Test Result: {output["test_result"]}')
logger.info(
f'Finished evaluation for instance {output["instance_id"]}: {output["test_result"]}'
)
output_fp.write(json.dumps(output) + '\n')
output_fp.flush()
# This sets the multi-processing
num_workers = args.eval_num_workers
logger.info(f'Using {num_workers} workers for evaluation.')
try:
with ProcessPoolExecutor(num_workers) as executor:
futures = []
# This is how we perform multi-processing
for instance in eda_dataset:
future = executor.submit(
process_instance,
instance,
agent_class,
metadata,
reset_logger=bool(num_workers > 1),
)
future.add_done_callback(update_progress)
futures.append(future)
# Wait for all futures to complete
for future in futures:
future.result()
except KeyboardInterrupt:
print('KeyboardInterrupt received. Cleaning up...')
cleanup()
output_fp.close()
logger.info('Evaluation finished.')
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
MODEL_CONFIG=$1
AGENT=$2
DATASET=$3
EVAL_LIMIT=$4
if [ -z "$AGENT" ]; then
echo "Agent not specified, use default CodeActAgent"
AGENT="CodeActAgent"
fi
if [ -z "$DATASET" ]; then
echo "Dataset not specified, use default 'things'"
DATASET="things"
fi
# check if OPENAI_API_KEY is set
if [ -z "$OPENAI_API_KEY" ]; then
echo "OPENAI_API_KEY is not set, please set it to run the script"
exit 1
fi
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenDevin
# We need to track the version of Agent in the evaluation to make sure results are comparable
AGENT_VERSION=v$(poetry run python -c "import agenthub; from opendevin.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
echo "AGENT: $AGENT"
echo "AGENT_VERSION: $AGENT_VERSION"
echo "MODEL_CONFIG: $MODEL_CONFIG"
echo "DATASET: $DATASET"
COMMAND="poetry run python evaluation/EDA/run_infer.py \
--agent-cls $AGENT \
--llm-config $MODEL_CONFIG \
--dataset $DATASET \
--data-split test \
--max-iterations 20 \
--OPENAI_API_KEY $OPENAI_API_KEY \
--max-chars 10000000 \
--eval-num-workers 1 \
--eval-note ${AGENT_VERSION}_${DATASET}"
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
# Run the command
echo $COMMAND
eval $COMMAND
+8
View File
@@ -13,6 +13,14 @@ all the preprocessing/evaluation/analysis scripts.
## Supported Benchmarks
- SWE-Bench: [`evaluation/swe_bench`](./swe_bench)
- ML-Bench: [`evaluation/ml_bench`](./ml_bench)
- HumanEvalFix: [`evaluation/humanevalfix`](./humanevalfix)
- GAIA: [`evaluation/gaia`](./gaia)
- Entity deduction Arena (EDA): [`evaluation/EDA`](./EDA)
- MINT: [`evaluation/mint`](./mint)
- AgentBench: [`evaluation/agent_bench`](./agent_bench)
- BIRD: [`evaluation/bird`](./bird)
- LogicReasoning: [`evaluation/logic_reasoning`](./logic_reasoning)
### Result Visualization
+182
View File
@@ -0,0 +1,182 @@
# Tutorial: How to add a New Evaluation Benchmark to OpenDevin
This tutorial provides a general guide on how to integrate your own evaluation benchmark into the OpenDevin framework.
You can read this for details, and also learn by example by looking at our existing evaluations:
- [swe_bench](swe_bench/)
## A quick walk-through of OpenDevin architecture
### Before everything begins
Please follow [this document](https://github.com/OpenDevin/OpenDevin/blob/main/Development.md) to setup local develop environment for OpenDevin.
### Configuration file
OpenDevin uses `config.toml` to keep track of most configurations.
Here's an example configuration file you can use:
```toml
[core]
max_iterations = 100
cache_dir = "/tmp/cache"
# IMPORTANT: You should set these two paths to YOUR WORKSPACE directory,
# which will be mounted into Sandbox for agent to interact with!
# The OpenDevin agent will be able to read/write files whatever they like (even rm -rf)
# in this directory, so be careful!!
workspace_base = "/path/to/your/workspace"
workspace_mount_path = "/path/to/your/workspace"
# ==========================
sandbox_container_image = "ghcr.io/opendevin/sandbox:latest"
sandbox_type = "ssh"
sandbox_timeout = 120
ssh_hostname = "localhost"
# SWEBench eval specific - but you can tweak it to your needs
use_host_network = false
run_as_devin = false
# linting python after editing helps LLM fix indentations
enable_auto_lint = true
[llm]
# IMPORTANT: add your API key here, and set the model to the one you want to evaluate
model = "gpt-4o-2024-05-13"
api_key = "sk-XXX"
```
### How to use OpenDevin programmatically
In this section, for the purpose of building an evaluation task, we don't use the standard OpenDevin web-based GUI, but rather run OpenDevin backend from CLI.
For example, you can run the following, which performs the specified task `-t`, with a particular model `-m` and agent `-c`, for a maximum number of iterations `-i`:
```bash
poetry run python ./opendevin/core/main.py \
-i 10 \
-t "Write me a bash script that print hello world." \
-c CodeActAgent \
-m gpt-4o-2024-05-13
```
After running the script, you will observe the following:
![](./static/example_task_1.png)
You can see the agent uses bash to write a script, makes it executable, and then tests it by running it to make sure it is working.
At the end of the above screenshot, OpenDevin actually requests user inputs when it think it finishes the task. This will cause issues in evaluation, since most evaluation don't assume additional user input. To fix this, we introduce the functionality of `fake_user_response_fn` in the `main` function, which we describe in the next section.
## The `main` function
The signature of `main` (in file [[`opendevin/core/main.py`](../opendevin/core/main.py)]) is as follows:
```python
async def main(
task_str: str = '',
exit_on_message: bool = False,
fake_user_response_fn: Optional[Callable[[Optional[State]], str]] = None,
sandbox: Optional[Sandbox] = None,
) -> Optional[State]:
```
- `task_str`: The task instruction to run. In the above example, it is "Write me a bash script that print hello world."
- `exit_on_message`: whether to quit if the agent asks for a message from user
- `fake_user_response_fn`: An optional function that receives the current state (could be None) and returns a fake user response.
- `sandbox`: An optional sandbox to run the agent in.
### `fake_user_response_fn`
Here's an example of `fake_user_response_fn` in the implementation for SWE-Bench in [`evaluation/swe_bench/run_infer.py`](swe_bench/run_infer.py):
```python
def codeact_user_response(state: State) -> str:
msg = (
'Please continue working on the task on whatever approach you think is suitable.\n'
'If you think you have modified the code in a way that fixes the issue, please run the following command: <execute_bash> exit </execute_bash>.\n'
'IMPORTANT: YOU SHOULD NEVER ASK FOR HUMAN HELP OR USE THE INTERNET TO SOLVE THIS TASK.\n'
)
if state.history:
user_msgs = [
action
for action, _ in state.history
if isinstance(action, MessageAction) and action.source == 'agent'
]
if len(user_msgs) >= 2:
# let the agent know that it can give up when it has tried 3 times
return (
msg
+ 'If you want to give up, run: <execute_bash> exit </execute_bash>.\n'
)
return msg
```
### Return value
The main function returns a `State`, which is defined in [`opendevin/controller/state/state.py`](../opendevin/controller/state/state.py). We are mainly using `state.history` here, which is the most important field of data. You can imagine it is being a more structured version of OpenAI's chat completion [messages](https://platform.openai.com/docs/guides/text-generation/chat-completions-api).
`history: list[tuple[Action, Observation]] = field(default_factory=list)` is a list of (action, observation) tuple. All the actions are defined at [`opendevin/events/action`](../opendevin/events/action) and observations are defined at [`opendevin/events/observation`](../opendevin/events/action).
The agent can emit different actions like `CmdRunAction` (`opendevin/events/action/commands.py`) to execute bash commands and receive `CmdOutputObservation` (`opendevin/events/observation/commands.py`), `IPythonRunCellAction` to receive `IPythonRunCellObservation`, `BrowseInteractiveAction` (`opendevin/events/action/browse.py`) to browse the web and receive `BrowserOutputObservation` (`opendevin/events/observation/browse.py`).
The action we used in this example is `MessageAction` (`opendevin/events/action/message.py`), which actually denotes a message from either `agent` or `user`. In the [CodeAct agent example](https://github.com/OpenDevin/OpenDevin/blob/7ca560471bd262f22513f3863995d0a8e6121c07/agenthub/codeact_agent/codeact_agent.py#L239-L273), an agent is considered to emit a `MessageAction` when it does not trigger a `CmdRunAction`, `IPythonRunCellAction`, and/or `BrowseInteractiveAction`.
Typically, the agent returns `MessageAction` when it is confused about the task, and want to ask human for follow-up clarification, which is a good thing in real-world task, but not necessarily in evaluation. So in this example, we provide a dummy prompt to tell the agent "Please continue working on the task on whatever approach you think is suitable[...]".
If you see something like this, you can consider adding this to your evaluation pipeline as well.
### `sandbox`
Sandbox is a fully functioning docker container where the agent can perform all sorts of tasks, e.g., using bash, calling Python, install packages, and more. You can leave `sandbox` to `None` if you don't need to do anything special to pre-configure the `Sandbox`.
In SWE-Bench, we need to copy the proper repository directory to the workspace and activate the right python virtual environment before the agent can start performing the task, so we actually defined a custom [`SWEBenchSSHBox`](https://github.com/OpenDevin/OpenDevin/blob/7ca560471bd262f22513f3863995d0a8e6121c07/evaluation/swe_bench/swe_env_box.py#L12-L118) that inherit from the default sandbox [`SSHBox`](https://github.com/OpenDevin/OpenDevin/blob/7ca560471bd262f22513f3863995d0a8e6121c07/opendevin/runtime/docker/ssh_box.py#L188) and handles all these initial setup. If you need to configure the `sandbox` for your evaluation, check `SWEBenchSSHBox` for a reference of implementation.
## How to put together an evaluation script?
Now we know how to start running the agent end-to-end, and how `fake_user_response_fn` and `sandbox` work. We will walk through a piece of dummy code (simplified version of SWE-Bench's [`run_infer.py`](https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/swe_bench/run_infer.py)) that outline the general workflow:
- Load the dataset and prepare the evaluation configuration.
- Filter out any instances that have already been processed.
- For each instance in the dataset:
- Set up the sandbox environment.
- Run the agent to generate a solution.
- Apply the solution to the instance and execute the test command.
- Collect the results and write them to the output file.
- Perform cleanup after the evaluation is complete.
You can see the [swe_bench/run_infer.py](swe_bench/run_infer.py) file for an example.
When you fully understand the `run_infer.py`, you can be ready to actually starting the evaluation!
## Run the evaluation!
You can write your `run_infer.sh` script mimicking SWE-Bench's [`run_infer.sh`](https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/swe_bench/scripts/run_infer.sh).
You can start the evaluation by running:
```bash
./run_infer.sh eval_gpt_4o_2024_05_13
```
Where `eval_gpt_4o_2024_05_13` is the model config you defined on the config.toml.
Like this:
```toml
[core]
...
[llm]
model="gpt-4-32k"
...
[eval_gpt_4o_2024_05_13]
model="gpt-4o-2024-05-13"
api_key="sk-xxx"
```
If `[eval_gpt_4o_2024_05_13]` is not present, it will default to using the model configured in `[llm]`.
+60
View File
@@ -0,0 +1,60 @@
# AgentBench Evaluation
This folder contains evaluation harness for evaluating agents on
the [AgentBench: Evaluating LLMs as Agents](https://arxiv.org/abs/2308.03688).
## Configure OpenDevin and your LLM
Create a `config.toml` file if it does not exist at the root of the workspace. Please check [README.md](../../README.md)
for how to set this up.
Here is an example `config.toml` file:
```toml
[core]
max_iterations = 100
cache_dir = "/path/to/cache"
workspace_base = "/path/to/workspace"
workspace_mount_path = "/path/to/workspace"
sandbox_container_image = "ghcr.io/opendevin/sandbox:latest"
sandbox_type = "ssh"
sandbox_timeout = 120
ssh_hostname = "localhost"
use_host_network = false
# AgentBench specific
run_as_devin = true
enable_auto_lint = true
[eval_gpt35_turbo]
model = "gpt-3.5-turbo"
api_key = "sk-123"
temperature = 0.0
[eval_gpt4o]
model = "gpt-4o"
api_key = "sk-123"
temperature = 0.0
```
## Start the evaluation
```bash
./evaluation/agent_bench/scripts/run_infer.sh [model_config] [agent] [eval_limit]
```
Following is the basic command to start the evaluation. Here we are only evaluating the `osbench` for now.
You can update the arguments in the script `evaluation/agent_bench/scripts/run_infer.sh`, such as `--max-iterations`, `--eval-num-workers` and so on.
- `--agent-cls`, the agent to use. For example, `CodeActAgent`.
- `--llm-config`: the LLM configuration to use. For example, `eval_gpt4_1106_preview`.
- `--max-iterations`: the number of iterations to run the evaluation. For example, `30`.
- `--eval-num-workers`: the number of workers to use for evaluation. For example, `5`.
- `--eval-n-limit`: the number of examples to evaluate. For example, `100`.
```bash
./evaluation/agent_bench/scripts/run_infer.sh eval_gpt35_turbo CodeActAgent 1
```
View File
+61
View File
@@ -0,0 +1,61 @@
import os
import re
from opendevin.events.action import CmdRunAction, MessageAction
def analysis_size(size_str):
size_str = size_str.strip()
avails = {
'B': 1,
'Byte': 1,
'K': 1024,
'KB': 1024,
'M': 1024 * 1024,
'MB': 1024 * 1024,
'G': 1024 * 1024 * 1024,
'GB': 1024 * 1024 * 1024,
'T': 1024 * 1024 * 1024 * 1024,
'TB': 1024 * 1024 * 1024 * 1024,
'P': 1024 * 1024 * 1024 * 1024 * 1024,
'PB': 1024 * 1024 * 1024 * 1024 * 1024,
}
for size_unit in avails:
if size_str.endswith(size_unit):
return int(size_str[: -len(size_unit)]) * avails[size_unit]
return int(size_str)
def compare_results(check_method: str, model_answer: str, final_ans: str) -> bool:
try:
match check_method:
case 'check/integer-match.py':
return int(model_answer) == int(final_ans)
case 'check/size-match.py':
return analysis_size(model_answer) == analysis_size(final_ans)
return (
model_answer.replace('\r\n', '\n').replace('\r', '\n').strip()
== final_ans.replace('\r\n', '\n').replace('\r', '\n').strip()
)
except Exception:
return False
def create_sh_file(filename: str, cmds: str) -> None:
with open(filename, 'w', encoding='utf-8') as file:
file.write(cmds.replace('\r\n', '\n'))
os.chmod(filename, 0o755)
def try_parse_answer(act) -> str | None:
raw_ans = ''
if isinstance(act, MessageAction) and act.source == 'agent':
raw_ans = act.content
elif isinstance(act, CmdRunAction) and act.source == 'agent':
raw_ans = act.thought
else:
return None
agent_answer = re.findall(r'<solution>(.*?)</solution>', raw_ans)
if not agent_answer:
return None
return agent_answer[0].strip()
+405
View File
@@ -0,0 +1,405 @@
import asyncio
import json
import logging
import multiprocessing as mp
import os
import pathlib
import re
import shutil
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
import docker
from datasets import load_dataset
from tqdm import tqdm
from evaluation.agent_bench.helper import (
compare_results,
create_sh_file,
try_parse_answer,
)
from opendevin.controller.state.state import State
from opendevin.core.config import args, config, get_llm_config_arg
from opendevin.core.logger import get_console_handler
from opendevin.core.logger import opendevin_logger as logger
from opendevin.core.main import main
from opendevin.events.action import CmdRunAction, MessageAction
from opendevin.events.serialization.event import event_to_dict
from opendevin.runtime.docker.ssh_box import DockerSSHBox
def cleanup():
print('Cleaning up child processes...')
for process in mp.active_children():
print(f'Terminating child process: {process.name}')
process.terminate()
process.join()
def codeact_user_response(state: State) -> str:
msg = (
'Please continue working on the task on whatever approach you think is suitable.\n'
'If you think you have solved the task, please first send your answer to user through '
'message and then <execute_bash> exit </execute_bash>.\n'
'Please encapsulate your final answer (answer ONLY) within <solution> and </solution>.\n'
'For example: The answer to the question is <solution> 42 </solution>.\n'
'IMPORTANT: YOU SHOULD NEVER ASK FOR HUMAN HELP.\n'
)
if state.history:
# check if the last action is an answer, if so, return exit for early exit
last_action, _ = state.history[-1]
ans = try_parse_answer(last_action)
if ans is not None:
return '/exit'
user_msgs = [
action
for action, _ in state.history
if isinstance(action, MessageAction) and action.source == 'user'
]
if len(user_msgs) >= 2:
# let the agent know that it can give up when it has tried 3 times
return (
msg
+ 'If you want to give up, run: <execute_bash> exit </execute_bash>.\n'
)
return msg
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
'CodeActAgent': codeact_user_response,
}
AGENT_CLS_TO_INST_SUFFIX = {
'CodeActAgent': 'When you think you have solved the question, '
'please first send your answer to user through message and then exit.\n'
}
def process_instance(
instance,
agent_class,
metadata,
eval_output_dir,
reset_logger: bool = True,
):
# =============================================
# preparation
# =============================================
inst_id = instance.instance_id
question = instance.description
# create a directory for the instance's workspace
instance_workspace = str(os.path.join(config.workspace_base, inst_id))
container_inst_workspace = str(
os.path.join(config.workspace_mount_path_in_sandbox, inst_id)
)
if os.path.exists(instance_workspace):
shutil.rmtree(instance_workspace)
os.makedirs(instance_workspace, exist_ok=True)
# Set up the logger properly, so you can run multiprocessing to parallel the evaluation
if reset_logger:
# Set up logger
log_file = os.path.join(eval_output_dir, 'logs', f'instance_{inst_id}.log')
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# add back the console handler to print ONE line
logger.addHandler(get_console_handler())
logger.info(
f'Starting evaluation for instance {inst_id}.\nHint: run "tail -f {log_file}" to see live logs in a seperate shell'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
)
logger.addHandler(file_handler)
# =============================================
# build instruction
# =============================================
# Prepare instruction
instruction = (
f'Please fix the following issue.\n'
'IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\n'
'Please encapsulate your final answer (answer ONLY) within <solution> and </solution>.\n'
'For example: The answer to the question is <solution> 42 </solution>.\n'
'# Problem \n'
f'{question}\n\n'
)
instruction += (
'IMPORTANT: You should ONLY interact with the environment provided '
'to you AND NEVER ASK FOR HUMAN HELP.\n'
)
# NOTE: You can actually set slightly different instruction for different agents
instruction += AGENT_CLS_TO_INST_SUFFIX.get(agent_class, '')
# =============================================
# create sandbox and run the agent
# =============================================
sandbox = DockerSSHBox()
sandbox.execute(f'cd {inst_id}')
init_cmd = instance.init
if init_cmd is not None:
scpt_name = f'{instance.instance_id}_init.sh'
scpt_path = os.path.join(container_inst_workspace, scpt_name)
host_scpt_path = os.path.join(instance_workspace, scpt_name)
create_sh_file(host_scpt_path, init_cmd)
logger.info(f'Running init script: {scpt_path}')
_, init_res = sandbox.execute(scpt_path)
logger.info(f'Init script result: {init_res}')
# Here's how you can run the agent (similar to the `main` function) and get the final task state
state: State = asyncio.run(
main(
instruction,
fake_user_response_fn=AGENT_CLS_TO_FAKE_USER_RESPONSE_FN.get(agent_class),
sandbox=sandbox,
)
)
if state is None:
raise ValueError('State should not be None.')
# get the ground truth
# OSBenchSSHBox.get_ground_truth(instance, state)
# =============================================
# result evaluation
# =============================================
agent_answer = ''
get_agent_result_cmd = instance.get_agent_result
if get_agent_result_cmd is not None:
scpt_name = f'{instance.instance_id}_get_agent_result.sh'
scpt_path = os.path.join(container_inst_workspace, scpt_name)
host_scpt_path = os.path.join(instance_workspace, scpt_name)
create_sh_file(host_scpt_path, get_agent_result_cmd)
logger.info(f'Running get agent result cmd: {scpt_path}')
_, agent_answer = sandbox.execute(scpt_path)
else:
logger.info('Retrieving agent answer from history.')
raw_ans = ''
for act, _ in reversed(state.history):
if isinstance(act, MessageAction) and act.source == 'agent':
raw_ans = act.content
break
if isinstance(act, CmdRunAction) and act.source == 'agent':
raw_ans = act.thought
break
agent_answer = re.findall(r'<solution>(.*?)</solution>', raw_ans)
if len(agent_answer) == 0:
logger.warning(f'Failed to parse model answer: {raw_ans}')
agent_answer = raw_ans
else:
agent_answer = agent_answer[0]
final_ans = ''
if instance.ground_truth is not None:
final_ans = instance.ground_truth
else:
get_ground_truth_cmd = instance.get_ground_truth
if get_ground_truth_cmd is not None:
scpt_name = f'{instance.instance_id}_get_ground_truth.sh'
scpt_path = os.path.join(container_inst_workspace, scpt_name)
host_scpt_path = os.path.join(instance_workspace, scpt_name)
create_sh_file(host_scpt_path, get_ground_truth_cmd)
logger.info(f'Running get ground truth cmd: {scpt_path}')
sandbox.execute(f'cd {container_inst_workspace}')
_, final_ans = sandbox.execute(scpt_path)
comparison_method = instance.comparison_method
logger.info(
f'Final message: {agent_answer} | Ground truth: {final_ans} | Comparison method: {comparison_method}'
)
test_result = compare_results(comparison_method, agent_answer, final_ans)
histories = [
(event_to_dict(action), event_to_dict(obs)) for action, obs in state.history
]
metrics = state.metrics.get() if state.metrics else None
# Save the output
output = {
'instance_id': inst_id,
'instance': instance.to_dict(),
'instruction': instruction,
'metadata': metadata,
'history': histories,
'metrics': metrics,
'error': state.error if state and state.error else None,
'test_result': {
'agent_answer': agent_answer,
'final_answer': final_ans,
'check_method': comparison_method,
'result': test_result,
},
}
# clean up
if os.path.exists(instance_workspace):
shutil.rmtree(instance_workspace)
# Close the sandbox
try:
sandbox.close()
except docker.errors.NotFound as e:
logger.error(f'Failed to close sandbox: {e}')
return output
if __name__ == '__main__':
# =============================================
# load datasets
# =============================================
dataset = load_dataset('iFurySt/AgentBench')
agent_bench_tests = dataset['osbench'].to_pandas()
logger.info(f'Loaded {len(agent_bench_tests)} tests.')
# =============================================
# handle arguments and prepare for evaluation
# =============================================
if args.llm_config:
specified_llm_config = get_llm_config_arg(args.llm_config)
if specified_llm_config:
config.llm = specified_llm_config
logger.info(f'Config for evaluation: {config}')
# TEST METADATA
agent_cls = args.agent_cls
assert (
agent_cls in AGENT_CLS_TO_FAKE_USER_RESPONSE_FN
), f'Unsupported agent class: {agent_cls}'
model_name = config.llm.model.split('/')[-1]
max_iterations = args.max_iterations
eval_note = ''
if args.eval_note is not None:
eval_note += '_N_' + args.eval_note
eval_op_dir = str(
os.path.join(
args.eval_output_dir,
'agent_bench',
agent_cls,
model_name + '_maxiter_' + str(max_iterations) + eval_note,
)
)
pathlib.Path(eval_op_dir).mkdir(parents=True, exist_ok=True)
pathlib.Path(str(os.path.join(eval_op_dir, 'logs'))).mkdir(
parents=True, exist_ok=True
)
logger.info(f'Using evaluation output directory: {eval_op_dir}')
meta = {
'agent_class': agent_cls,
'model_name': model_name,
'max_iterations': max_iterations,
'eval_output_dir': eval_op_dir,
'start_time': time.strftime('%Y-%m-%d %H:%M:%S'),
# get the commit id of current repo for reproducibility
'git_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'])
.decode('utf-8')
.strip(),
}
logger.info(f'Metadata: {meta}')
with open(os.path.join(eval_op_dir, 'metadata.json'), 'w') as f:
json.dump(meta, f)
# LIMIT EVALUATION
eval_n_limit = args.eval_n_limit
if eval_n_limit:
agent_bench_tests = agent_bench_tests[:eval_n_limit]
logger.info(f'Limiting evaluation to first {eval_n_limit} instances.')
# OUTPUT FILE
output_file = os.path.join(eval_op_dir, 'output.jsonl')
logger.info(f'Writing evaluation output to {output_file}')
finished_instance_ids = set()
if os.path.exists(output_file):
with open(output_file, 'r') as f:
for line in f:
data = json.loads(line)
finished_instance_ids.add(data['instance_id'])
logger.warning(
f'Output file {output_file} already exists. Loaded {len(finished_instance_ids)} finished instances.'
)
output_fp = open(output_file, 'a')
logger.info(
f'Evaluation started with Agent {agent_cls}, model {model_name}, max iterations {max_iterations}.'
)
# =============================================
# filter out finished instances
# =============================================
new_agent_bench_tests = []
for idx, inst in agent_bench_tests.iterrows():
if inst.instance_id in finished_instance_ids:
logger.info(
f'Skipping instance {inst.instance_id} as it is already finished.'
)
continue
new_agent_bench_tests.append(inst)
agent_bench_tests = new_agent_bench_tests
logger.info(
f'Finished instances: {len(finished_instance_ids)}, Remaining instances: {len(agent_bench_tests)}'
)
# =============================================
# start task
# =============================================
pbar = tqdm(total=len(agent_bench_tests))
# This function tracks the progress AND write the output to a JSONL file
def update_progress(fut):
pbar.update(1)
output = fut.result()
pbar.set_description(f'Instance {output["instance_id"]}')
pbar.set_postfix_str(f'Test Result: {output["test_result"]["result"]}')
logger.info(
f'Finished evaluation for instance {output["instance_id"]}: {output["test_result"]["result"]}'
)
output_fp.write(json.dumps(output) + '\n')
output_fp.flush()
# This sets the multiprocessing
num_workers = args.eval_num_workers
logger.info(f'Using {num_workers} workers for evaluation.')
try:
with ProcessPoolExecutor(num_workers) as executor:
futures = []
# This is how we perform multiprocessing
for inst in agent_bench_tests:
future = executor.submit(
process_instance,
inst,
agent_cls,
meta,
eval_op_dir,
reset_logger=bool(num_workers > 1),
)
future.add_done_callback(update_progress)
futures.append(future)
# Wait for all futures to complete
for future in futures:
future.result()
except KeyboardInterrupt:
print('KeyboardInterrupt received. Cleaning up...')
cleanup()
output_fp.close()
logger.info('Evaluation finished.')
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
MODEL_CONFIG=$1
AGENT=$2
EVAL_LIMIT=$3
if [ -z "$AGENT" ]; then
echo "Agent not specified, use default CodeActAgent"
AGENT="CodeActAgent"
fi
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenDevin
# We need to track the version of Agent in the evaluation to make sure results are comparable
AGENT_VERSION=v$(poetry run python -c "import agenthub; from opendevin.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
echo "AGENT: $AGENT"
echo "AGENT_VERSION: $AGENT_VERSION"
echo "MODEL_CONFIG: $MODEL_CONFIG"
COMMAND="export PYTHONPATH=evaluation/agent_bench:\$PYTHONPATH && poetry run python evaluation/agent_bench/run_infer.py \
--agent-cls $AGENT \
--llm-config $MODEL_CONFIG \
--max-iterations 30 \
--max-chars 10000000 \
--eval-num-workers 5 \
--eval-note $AGENT_VERSION"
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
# Run the command
eval $COMMAND
@@ -0,0 +1,37 @@
import json
import sys
def extract_test_results(res_file_path: str) -> tuple[list[str], list[str]]:
passed = []
failed = []
with open(res_file_path, 'r') as file:
for line in file:
data = json.loads(line.strip())
instance_id = data['instance_id']
resolved = False
if 'test_result' in data and 'result' in data['test_result']:
resolved = data['test_result']['result']
if resolved:
passed.append(instance_id)
else:
failed.append(instance_id)
return passed, failed
if __name__ == '__main__':
if len(sys.argv) != 2:
print(
'Usage: poetry run python summarise_results.py <path_to_output_jsonl_file>'
)
sys.exit(1)
json_file_path = sys.argv[1]
passed_tests, failed_tests = extract_test_results(json_file_path)
succ_rate = len(passed_tests) / (len(passed_tests) + len(failed_tests))
print(
f'\nPassed {len(passed_tests)} tests, failed {len(failed_tests)} tests, resolve rate = {succ_rate}'
)
print('PASSED TESTS:')
print(passed_tests)
print('FAILED TESTS:')
print(failed_tests)
File diff suppressed because one or more lines are too long
View File
+517
View File
@@ -0,0 +1,517 @@
import asyncio
import json
import logging
import multiprocessing as mp
import os
import pathlib
import re
import shutil
import sqlite3
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
import pandas as pd
from datasets import load_dataset
from func_timeout import FunctionTimedOut, func_timeout
from tqdm import tqdm
from opendevin.controller.state.state import State
from opendevin.core.config import args, config, get_llm_config_arg
from opendevin.core.logger import get_console_handler
from opendevin.core.logger import opendevin_logger as logger
from opendevin.core.main import main
from opendevin.events.action import MessageAction
from opendevin.events.serialization.event import event_to_dict
def cleanup():
logger.info('Cleaning up child processes...')
for process in mp.active_children():
logger.info(f'Terminating child process: {process.name}')
process.terminate()
process.join()
def codeact_user_response(state: State) -> str:
msg = (
'Please continue working on the task on whatever approach you think is suitable.\n'
'If you think you have completed the SQL, please run the following command: <execute_bash> exit </execute_bash>.\n'
'IMPORTANT: YOU SHOULD NEVER ASK FOR HUMAN HELP OR USE THE INTERNET TO SOLVE THIS TASK.\n'
)
if state.history:
user_msgs = [
action
for action, _ in state.history
if isinstance(action, MessageAction) and action.source == 'user'
]
if len(user_msgs) >= 2:
# let the agent know that it can give up when it has tried 3 times
return (
msg
+ 'If you want to give up, run: <execute_bash> exit </execute_bash>.\n'
)
return msg
def monologue_user_response(state: State) -> str:
raise NotImplementedError('MonologueAgent should never ask for user responses.')
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
'CodeActAgent': codeact_user_response,
'MonologueAgent': monologue_user_response,
}
AGENT_CLS_TO_INST_SUFFIX = {
'CodeActAgent': 'When you think you have fixed the issue through code changes, please run the following command: <execute_bash> exit </execute_bash>.\n'
}
def execute_sql(db_path, gen_sql, gold_sql):
"""
Execute the generated SQL and the ground truth SQL and compare the results.
"""
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute(gen_sql)
predicted_res = cursor.fetchall()
cursor.execute(gold_sql)
ground_truth_res = cursor.fetchall()
res = 0
if set(predicted_res) == set(ground_truth_res):
res = 1
return res
def get_test_result(instance, path, timeout=30):
test_result = {'result': {}, 'metadata': {}}
# Read the generated python file
with open(path, 'r') as f:
gen_file = f.read()
# Extract the SQL from the python file
gen_sql = ''
pattern = r'sql\s*=\s*"([^"]+)"'
match = re.search(pattern, gen_file)
if match:
gen_sql = match.group(1)
else:
print('No match found.')
gold_sql = instance.SQL
# Execute the SQL
try:
res = func_timeout(
timeout, execute_sql, args=(instance.db_path, gen_sql, gold_sql)
)
status = 'success'
except FunctionTimedOut:
res = 0
status = 'timeout'
except Exception as e:
res = 0
status = 'error'
logger.error(f'Error: {e}')
# Save the test result
test_result['result'] = {'passed': res, 'status': status}
test_result['metadata'] = {
'timeout': timeout,
'gen_sql': gen_sql,
'gold_sql': gold_sql,
}
return test_result
def process_instance(
instance, agent_class, metadata, skip_workspace_mount, reset_logger: bool = True
):
workspace_mount_path = os.path.join(
config.workspace_mount_path, 'bird_eval_workspace'
)
# create process-specific workspace dir
# if `not skip_workspace_mount` - we will create a workspace directory for EACH process
# so that different agent don't interfere with each other.
if not skip_workspace_mount:
workspace_mount_path = os.path.join(workspace_mount_path, str(os.getpid()))
pathlib.Path(workspace_mount_path).mkdir(parents=True, exist_ok=True)
# reset workspace to config
config.workspace_mount_path = workspace_mount_path
# Copy the database to the workspace
db_root = os.path.join(
config.workspace_base, 'evaluation_bird/dev/dev_databases', instance.db_id
)
target_path = os.path.join(workspace_mount_path, f'{instance.db_id}')
if not os.path.exists(target_path):
logger.info(f'Copying database from {db_root} to {target_path}...')
shutil.copytree(db_root, target_path)
# Set up the database path
database_path = os.path.join(instance.db_id, f'{instance.db_id}.sqlite')
# Set up the logger properly, so you can run multi-processing to parallelize the evaluation
if reset_logger:
# Set up logger
log_file = os.path.join(
eval_output_dir,
'logs',
f'instance_{instance.task_id.replace("/", "__")}.log',
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# add back the console handler to print ONE line
logger.addHandler(get_console_handler())
logger.info(
f'Starting evaluation for instance {instance.task_id}.\nLOG: tail -f {log_file}'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
)
logger.addHandler(file_handler)
if not skip_workspace_mount:
logger.info(f'Process-specific workspace mounted at {workspace_mount_path}')
# Create file with BIRD instance
statements = f"""
import sqlite3
def execute_sql(db_path, sql):
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute(sql)
result = cursor.fetchall()
return result
if __name__ == '__main__':
sql = "" # fill in your SQL here
db_path = "{database_path}"
print(db_path)
result = execute_sql(db_path, sql)
print(result)
"""
path = os.path.join(
config.workspace_mount_path, f'{instance.task_id.replace("/", "__")}.py'
)
instruction = (
f'You are a SQL expert and need to complete the following text-to-SQL tasks.'
f'\n\n{instance.instruction}\n\n'
'Please write the SQL in one line without line breaks.'
f'And write a new python file named {instance.task_id.replace("/", "__")}.py to call the SQL you wrote.'
'You need to follow the code template below:'
f'\n\n{statements}\n\n'
'Environment has been set up for you to start working.'
'You may assume all necessary tools are installed.\n\n'
)
instruction += (
'IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\n'
'You SHOULD INCLUDE PROPER INDENTATION in your edit commands.\n'
)
# NOTE: You can actually set slightly different instruction for different agents
instruction += AGENT_CLS_TO_INST_SUFFIX.get(agent_class, '')
# Here's how you can run the agent (similar to the `main` function) and get the final task state
state: State = asyncio.run(
main(
instruction,
fake_user_response_fn=AGENT_CLS_TO_FAKE_USER_RESPONSE_FN.get(agent_class),
)
)
# ======= Attempt to evaluate the agent's edits =======
test_result = get_test_result(instance, path)
# If you are working on some simpler benchmark that only evaluates the final model output (e.g., in a MessageAction)
# You can simply get the LAST `MessageAction` from the returned `state.history` and parse it for evaluation.
if state is None:
raise ValueError('State should not be None.')
metrics = state.metrics.get() if state.metrics else None
# Save the output
output = {
'task_id': instance.task_id,
'instruction': instruction,
'metadata': metadata,
'history': [
(event_to_dict(action), event_to_dict(obs)) for action, obs in state.history
],
'metrics': metrics,
'error': state.error if state and state.error else None,
'test_result': test_result,
}
return output
def load_bird():
"""
Main function to handle the flow of downloading, processing, and loading the bird dataset.
"""
raw_dataset_path = download_bird()
bird_dataset = process_bird(raw_dataset_path)
return bird_dataset
def download_bird():
"""
Downloads and extracts the bird dataset from a specified URL into a local directory.
"""
dataset_path = os.path.join(config.workspace_base, 'evaluation_bird')
devset_path = os.path.join(dataset_path, 'dev')
if not os.path.exists(dataset_path):
logger.info(
f'{dataset_path} folder does not exist, starting download and extraction...'
)
os.makedirs(dataset_path, exist_ok=True)
download_url = 'https://bird-bench.oss-cn-beijing.aliyuncs.com/dev.zip'
download_path = os.path.join(dataset_path, 'dev.zip')
logger.info('Start Downloading...')
subprocess.run(['wget', download_url, '-O', download_path])
logger.info('Download completed.')
logger.info('Start Extracting...')
subprocess.run(['unzip', download_path, '-d', dataset_path])
# extract databases
devset_path = os.path.join(dataset_path, 'dev')
database_path = os.path.join(devset_path, 'dev_databases.zip')
subprocess.run(['unzip', database_path, '-d', devset_path])
logger.info('Extraction completed.')
else:
logger.info(f'{dataset_path} folder already exists.')
return devset_path
def process_bird(dataset_path):
"""
Processes the raw bird dataset into a structured format and saves it as JSON.
"""
processed_path = os.path.join(dataset_path, 'processed_dev.json')
if not os.path.exists(processed_path):
logger.info(f'{processed_path} folder does not exist, starting processing...')
raw_data_path = os.path.join(dataset_path, 'dev.json')
database_path = os.path.join(dataset_path, 'dev_databases')
processed_data = []
with pathlib.Path(raw_data_path).open('r') as f:
data = json.load(f)
for e in tqdm(data):
item = {
'task_id': f'{len(processed_data)}',
'db_path': os.path.join(
database_path, e['db_id'], f"{e['db_id']}.sqlite"
),
'db_id': e['db_id'],
'instruction': create_prompt(e, database_path),
'SQL': e['SQL'],
}
processed_data.append(item)
with pathlib.Path(processed_path).open('w') as f:
json.dump(processed_data, f, indent=2)
logger.info(f'Processed data saved to {processed_path}')
else:
logger.info(f'{processed_path} folder already exists.')
bird_dataset = load_dataset('json', data_files={'test': processed_path})
return bird_dataset
def extract_create_table_prompt(db_path, limit_value=0):
"""
Generates a SQL prompt with CREATE TABLE statements and sample data from the database.
"""
table_query = "SELECT * FROM sqlite_master WHERE type='table';"
tables = sqlite3.connect(db_path).cursor().execute(table_query).fetchall()
prompt = ''
for table in tables:
table_name = table[1]
create_table_statement = table[-1]
table_info_query = f'PRAGMA table_info(`{table_name}`);'
top_k_row_query = f'SELECT * FROM {table_name} LIMIT {limit_value};'
try:
headers = [
x[1]
for x in sqlite3.connect(db_path)
.cursor()
.execute(table_info_query)
.fetchall()
]
except Exception:
logger.error(f'Error Connection: {table_info_query}, {top_k_row_query}')
exit(0)
prompt += create_table_statement + ';\n'
if limit_value > 0:
top_k_rows = (
sqlite3.connect(db_path).cursor().execute(top_k_row_query).fetchall()
)
prompt += (
f"/*\n3 example rows:\n{top_k_row_query}\n{' '.join(headers)}\n"
)
for row in top_k_rows:
row = [str(x) for x in row]
row = [x if x is not None else '' for x in row]
prompt += ' '.join(row) + '\n'
prompt += '*/\n'
prompt += '\n'
return prompt
def create_prompt(e, database_path):
"""
Create a prompt for the given example
"""
db_id = e['db_id']
db_path = pathlib.Path(database_path) / db_id / f'{db_id}.sqlite'
# Extract the CREATE TABLE statements and sample data from the database
prompt = extract_create_table_prompt(db_path)
prompt += f"-- External Knowledge: {e['evidence']}\n\n"
prompt += '-- Using valid SQLite and understanding External Knowledge, answer the following questions for the tables provided above.\n\n'
prompt += '-- Using valid SQLite, answer the following questions for the tables provided above.\n'
prompt += f"Question: {e['question']}\n"
return prompt
if __name__ == '__main__':
# NOTE: It is preferable to load datasets from huggingface datasets and perform post-processing
# so we don't need to manage file uploading to OpenDevin's repo
# Due to the large size of the BIRD database, it cannot be hosted on huggingface datasets, so it needs to be downloaded
bird_dataset = load_bird()
bird_tests = bird_dataset['test'].to_pandas()
# Check https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/humanevalfix/README.md#configure-opendevin-and-your-llm
# for details of how to set `llm_config`
if args.llm_config:
specified_llm_config = get_llm_config_arg(args.llm_config)
if specified_llm_config:
config.llm = specified_llm_config
logger.info(f'Config for evaluation: {config}')
# TEST METADATA
agent_class = args.agent_cls
assert (
agent_class in AGENT_CLS_TO_FAKE_USER_RESPONSE_FN
), f'Unsupported agent class: {agent_class}'
model_name = config.llm.model.split('/')[-1]
max_iterations = args.max_iterations
eval_note = ''
if args.eval_note is not None:
eval_note += '_N_' + args.eval_note
eval_output_dir = os.path.join(
args.eval_output_dir,
'bird',
agent_class,
model_name + '_maxiter_' + str(max_iterations) + eval_note,
)
pathlib.Path(eval_output_dir).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(eval_output_dir, 'logs')).mkdir(
parents=True, exist_ok=True
)
logger.info(f'Using evaluation output directory: {eval_output_dir}')
metadata = {
'agent_class': agent_class,
'model_name': model_name,
'max_iterations': max_iterations,
'eval_output_dir': eval_output_dir,
'start_time': time.strftime('%Y-%m-%d %H:%M:%S'),
# get the commit id of current repo for reproducibility
'git_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'])
.decode('utf-8')
.strip(),
}
logger.info(f'Metadata: {metadata}')
with open(os.path.join(eval_output_dir, 'metadata.json'), 'w') as f:
json.dump(metadata, f)
# LIMIT EVALUATION
eval_n_limit = args.eval_n_limit
if eval_n_limit:
bird_tests = bird_tests.head(eval_n_limit)
logger.info(f'Limiting evaluation to first {eval_n_limit} instances.')
# OUTPUT FILE
output_file = os.path.join(eval_output_dir, 'output.jsonl')
logger.info(f'Writing evaluation output to {output_file}')
finished_instance_ids = set()
if os.path.exists(output_file):
with open(output_file, 'r') as f:
for line in f:
data = json.loads(line)
finished_instance_ids.add(data['task_id'])
logger.warning(
f'Output file {output_file} already exists. Loaded {len(finished_instance_ids)} finished instances.'
)
output_fp = open(output_file, 'a')
logger.info(
f'Evaluation started with Agent {agent_class}, model {model_name}, max iterations {max_iterations}.'
)
# =============================================
# filter out finished instances
new_bird_tests = []
for idx, instance in bird_tests.iterrows():
if instance.task_id in finished_instance_ids:
logger.info(
f'Skipping instance {instance.task_id} as it is already finished.'
)
continue
new_bird_tests.append(instance)
bird_tests = pd.DataFrame(new_bird_tests)
logger.info(
f'Finished instances: {len(finished_instance_ids)}, Remaining instances: {len(bird_tests)}'
)
# =============================================
pbar = tqdm(total=len(bird_tests))
# This function tracks the progress AND write the output to a JSONL file
def update_progress(future):
pbar.update(1)
output = future.result()
pbar.set_description(f'Instance {output["task_id"]}')
pbar.set_postfix_str(f'Test Result: {output["test_result"]["result"]}')
logger.info(
f'Finished evaluation for instance {output["task_id"]}: {output["test_result"]["result"]}'
)
output_fp.write(json.dumps(output) + '\n')
output_fp.flush()
# This sets the multi-processing
num_workers = args.eval_num_workers
logger.info(f'Using {num_workers} workers for evaluation.')
try:
with ProcessPoolExecutor(num_workers) as executor:
futures = []
# This is how we perform multi-processing
for row_idx, instance in bird_tests.iterrows():
future = executor.submit(
process_instance,
instance,
agent_class,
metadata,
skip_workspace_mount=False,
reset_logger=bool(num_workers > 1),
)
future.add_done_callback(update_progress)
futures.append(future)
# Wait for all futures to complete
for future in futures:
future.result()
except KeyboardInterrupt:
print('KeyboardInterrupt received. Cleaning up...')
cleanup()
output_fp.close()
logger.info('Evaluation finished.')
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
MODEL_CONFIG=$1
AGENT=$2
EVAL_LIMIT=$3
if [ -z "$AGENT" ]; then
echo "Agent not specified, use default CodeActAgent"
AGENT="CodeActAgent"
fi
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenDevin
# We need to track the version of Agent in the evaluation to make sure results are comparable
AGENT_VERSION=v$(poetry run python -c "import agenthub; from opendevin.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
echo "AGENT: $AGENT"
echo "AGENT_VERSION: $AGENT_VERSION"
echo "MODEL_CONFIG: $MODEL_CONFIG"
COMMAND="poetry run python evaluation/bird/run_infer.py \
--agent-cls $AGENT \
--llm-config $MODEL_CONFIG \
--max-iterations 5 \
--max-chars 10000000 \
--eval-num-workers 1 \
--eval-note $AGENT_VERSION" \
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
# Run the command
eval $COMMAND
+45
View File
@@ -0,0 +1,45 @@
# GAIA Evaluation
This folder contains evaluation harness for evaluating agents on the [GAIA benchmark](https://arxiv.org/abs/2311.12983).
## Configure OpenDevin and your LLM
Create a `config.toml` file if it does not exist at the root of the workspace. Please check [README.md](../../README.md) for how to set this up.
## Run the evaluation
We are using the GAIA dataset hosted on [Hugging Face](https://huggingface.co/datasets/gaia-benchmark/GAIA).
Please accept the terms and make sure to have logged in on your computer by `huggingface-cli login` before running the evaluation.
Following is the basic command to start the evaluation. Here we are evaluating on the validation set for the `2023_all` split. You can adjust `./evaluation/gaia/scripts/run_infer.sh` to change the subset you want to evaluate on.
```bash
./evaluation/gaia/scripts/run_infer.sh [model_config] [agent] [eval_limit] [gaia_subset]
# e.g., ./evaluation/gaia/scripts/run_infer.sh eval_gpt4_1106_preview CodeActAgent 300
```
where `model_config` is mandatory, while `agent`, `eval_limit` and `gaia_subset` are optional.
- `model_config`, e.g. `eval_gpt4_1106_preview`, is the config group name for your
LLM settings, as defined in your `config.toml`, defaulting to `gpt-3.5-turbo`
- `agent`, e.g. `CodeActAgent`, is the name of the agent for benchmarks, defaulting
to `CodeActAgent`.
- `eval_limit`, e.g. `10`, limits the evaluation to the first `eval_limit` instances, defaulting to all instances.
- `gaia_subset`, GAIA benchmark has multiple subsets: `2023_level1`, `2023_level2`, `2023_level3`, `2023_all`, defaulting to `2023_level1`.
Let's say you'd like to run 10 instances using `eval_gpt4_1106_preview` and CodeActAgent,
then your command would be:
```bash
./evaluation/gaia/scripts/run_infer.sh eval_gpt4_1106_preview CodeActAgent 10
```
## Get score
Then you can get stats by running the following command:
```bash
python ./evaluation/gaia/get_score.py \
--file <path_to/output.json>
```
+28
View File
@@ -0,0 +1,28 @@
import argparse
import json
def main():
parser = argparse.ArgumentParser(description="Get agent's gaia score")
parser.add_argument('--file', type=str, help="Path to the agent's output.jsonl")
args = parser.parse_args()
this_log = args.file
outs = []
with open(this_log, 'r') as f:
lines = f.readlines()
for line in lines:
outs.append(json.loads(line))
print(f'Reading {this_log}')
print(f'Metadata:\n {outs[0]["metadata"]}')
total = 0
success = 0
for out in outs:
total += 1
if out['test_result']['score']:
success += 1
print(f'Success rate: {success}/{total} = {success/total}')
if __name__ == '__main__':
main()
+369
View File
@@ -0,0 +1,369 @@
import asyncio
import json
import logging
import multiprocessing as mp
import os
import pathlib
import re
import shutil
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
import huggingface_hub
from datasets import load_dataset
from tqdm import tqdm
from evaluation.gaia.scorer import question_scorer
from opendevin.controller.state.state import State
from opendevin.core.config import config, get_llm_config_arg, get_parser
from opendevin.core.logger import get_console_handler
from opendevin.core.logger import opendevin_logger as logger
from opendevin.core.main import main
from opendevin.events.action import CmdRunAction, MessageAction
from opendevin.events.serialization.event import event_to_dict
DATASET_CACHE_DIR = '~/.cache/open-devin/evals/gaia'
DATASET_CACHE_DIR = os.path.expanduser(DATASET_CACHE_DIR)
def cleanup():
logger.info('Cleaning up child processes...')
for process in mp.active_children():
logger.info(f'Terminating child process: {process.name}')
process.terminate()
process.join()
def codeact_user_response(state: State) -> str:
msg = (
'Please continue working on the task on whatever approach you think is suitable.\n'
'If you think you have solved the task, please first send your answer to user through message and then <execute_bash> exit </execute_bash>.\n'
'Please encapsulate your final answer (answer ONLY) within <solution> and </solution>.\n'
'For example: The answer to the question is <solution> 42 </solution>.\n'
'IMPORTANT: YOU SHOULD NEVER ASK FOR HUMAN HELP.\n'
)
if state.history:
user_msgs = [
action
for action, _ in state.history
if isinstance(action, MessageAction) and action.source == 'user'
]
if len(user_msgs) >= 2:
# let the agent know that it can give up when it has tried 3 times
return (
msg
+ 'If you want to give up, run: <execute_bash> exit </execute_bash>.\n'
)
return msg
def monologue_user_response(state: State) -> str:
raise NotImplementedError('MonologueAgent should never ask for user responses.')
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
'CodeActAgent': codeact_user_response,
'MonologueAgent': monologue_user_response,
}
AGENT_CLS_TO_INST_SUFFIX = {
'CodeActAgent': 'When you think you have solved the question, please first send your answer to user through message and then exit.\n'
}
def process_instance(instance, agent_class, metadata, reset_logger: bool = True):
# create process-specific workspace dir
# we will create a workspace directory for EACH process
# so that different agent don't interfere with each other.
old_workspace_mount_path = config.workspace_mount_path
try:
workspace_mount_path = os.path.join(
config.workspace_mount_path, '_eval_workspace'
)
workspace_mount_path = os.path.join(workspace_mount_path, str(os.getpid()))
pathlib.Path(workspace_mount_path).mkdir(parents=True, exist_ok=True)
config.workspace_mount_path = workspace_mount_path
# Setup the logger properly, so you can run multi-processing to parallelize the evaluation
eval_output_dir = metadata['eval_output_dir']
if reset_logger:
# Set up logger
log_file = os.path.join(
eval_output_dir, 'logs', f'instance_{instance["task_id"]}.log'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# add back the console handler to print ONE line
logger.addHandler(get_console_handler())
logger.info(
f'Starting evaluation for instance {instance["task_id"]}.\nLOG: tail -f {log_file}'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
)
logger.addHandler(file_handler)
logger.info(f'Process-specific workspace mounted at {workspace_mount_path}')
if instance['file_name'] != '':
# if this question comes with a file, we need to save it to the workspace
src_file = os.path.join(
DATASET_CACHE_DIR, '2023', metadata['data_split'], instance['file_name']
)
extension_name = instance['file_name'].split('.')[-1]
dest_file = os.path.join(workspace_mount_path, f'file.{extension_name}')
shutil.copyfile(src_file, dest_file)
logger.info(f'File copied to {dest_file}')
else:
dest_file = None
# Prepare instruction
instruction = f"{instance['Question']}\n"
logger.info(f'Instruction: {instruction}')
if dest_file:
instruction += f"\n\nThe mentioned file is provided in the workspace at: {dest_file.split('/')[-1]}"
instruction += 'IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\n'
instruction += 'Please encapsulate your final answer (answer ONLY) within <solution> and </solution>.\n'
instruction += (
'For example: The answer to the question is <solution> 42 </solution>.\n'
)
# NOTE: You can actually set slightly different instruction for different agents
instruction += AGENT_CLS_TO_INST_SUFFIX.get(agent_class, '')
logger.info(f'Instruction:\n{instruction}', extra={'msg_type': 'OBSERVATION'})
# Here's how you can run the agent (similar to the `main` function) and get the final task state
state: State = asyncio.run(
main(
instruction,
fake_user_response_fn=AGENT_CLS_TO_FAKE_USER_RESPONSE_FN.get(
agent_class
),
)
)
# ======= Attempt to evaluate the agent's edits =======
# If you are working on simpler benchmark that only evaluates the final model output (e.g., in a MessageAction)
# You can simply get the LAST `MessageAction` from the returned `state.history` and parse it for evaluation.
if state is None:
raise ValueError('State should not be None.')
model_answer_raw = ''
for act, _ in reversed(state.history):
if isinstance(act, CmdRunAction) and act.source == 'agent':
model_answer_raw = act.thought
break
elif isinstance(act, MessageAction) and act.source == 'agent':
model_answer_raw = act.content
break
# attempt to parse model_answer
model_answer = re.findall(r'<solution>(.*?)</solution>', model_answer_raw)
if len(model_answer) == 0:
logger.warning(f'Failed to parse model answer: {model_answer_raw}')
model_answer = model_answer_raw
else:
model_answer = model_answer[0]
logger.info(
f'Final message: {model_answer} | Ground truth: {instance["Final answer"]}'
)
score = question_scorer(
model_answer=model_answer, ground_truth=instance['Final answer']
)
test_result = {
'score': score,
'model_answer_raw': model_answer_raw,
'model_answer': model_answer,
'ground_truth': instance['Final answer'],
}
metrics = state.metrics.get() if state.metrics else None
# Save the output
output = {
'instance_id': instance['task_id'],
'instance': instance,
'instruction': instance['Question'],
'metadata': metadata,
'history': [
(event_to_dict(action), event_to_dict(obs))
for action, obs in state.history
],
'metrics': metrics,
'error': state.error if state and state.error else None,
'test_result': test_result,
}
except Exception:
logger.error('Process instance failed')
raise
finally:
config.workspace_mount_path = old_workspace_mount_path
return output
if __name__ == '__main__':
parser = get_parser()
parser.add_argument(
'--level',
type=str,
help='gaia level to evaluate, eg. 2023_level1',
)
parser.add_argument(
'--data-split',
type=str,
help='data split to evaluate, eg. validation',
)
args, _ = parser.parse_known_args()
if args.directory:
config.workspace_base = os.path.abspath(args.directory)
logger.info(f'Setting workspace base to {config.workspace_base}')
# NOTE: It is preferable to load datasets from huggingface datasets and perform post-processing
# so we don't need to manage file uploading to OpenDevin's repo
level = args.level
data_split = args.data_split
dataset = load_dataset('gaia-benchmark/GAIA', level)
huggingface_hub.snapshot_download(
'gaia-benchmark/GAIA',
repo_type='dataset',
local_dir=DATASET_CACHE_DIR,
)
gaia_tests = dataset[data_split]
logger.info(f'Evaluating GAIA-Benchmark {level} {data_split} split')
# Check https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/swe_bench/README.md#configure-opendevin-and-your-llm
# for details of how to set `llm_config`
if args.llm_config:
specified_llm_config = get_llm_config_arg(args.llm_config)
if specified_llm_config:
config.llm = specified_llm_config
logger.info(f'Config for evaluation: {config}')
# TEST METADATA
agent_class = args.agent_cls
assert (
agent_class in AGENT_CLS_TO_FAKE_USER_RESPONSE_FN
), f'Unsupported agent class: {agent_class}'
model_name = config.llm.model.split('/')[-1]
max_iterations = args.max_iterations
eval_note = ''
if args.eval_note is not None:
eval_note += '_N_' + args.eval_note
eval_output_dir = os.path.join(
args.eval_output_dir,
'gaia',
agent_class,
model_name + '_maxiter_' + str(max_iterations) + eval_note,
)
pathlib.Path(eval_output_dir).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(eval_output_dir, 'logs')).mkdir(
parents=True, exist_ok=True
)
logger.info(f'Using evaluation output directory: {eval_output_dir}')
metadata = {
'gaia-level': level,
'data_split': data_split,
'agent_class': agent_class,
'model_name': model_name,
'max_iterations': max_iterations,
'eval_output_dir': eval_output_dir,
'start_time': time.strftime('%Y-%m-%d %H:%M:%S'),
# get the commit id of current repo for reproducibility
'git_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'])
.decode('utf-8')
.strip(),
}
logger.info(f'Metadata: {metadata}')
with open(os.path.join(eval_output_dir, 'metadata.json'), 'w') as f:
json.dump(metadata, f)
# LIMIT EVALUATION
eval_n_limit = args.eval_n_limit
if eval_n_limit:
gaia_tests = gaia_tests.select(list(range(eval_n_limit)))
logger.info(f'Limiting evaluation to first {eval_n_limit} instances.')
# OUTPUT FILE
output_file = os.path.join(eval_output_dir, 'output.jsonl')
logger.info(f'Writing evaluation output to {output_file}')
finished_task_ids = set()
if os.path.exists(output_file):
with open(output_file, 'r') as f:
for line in f:
data = json.loads(line)
finished_task_ids.add(data['instance_id'])
logger.warning(
f'Output file {output_file} already exists. Loaded {len(finished_task_ids)} finished instances.'
)
output_fp = open(output_file, 'a')
logger.info(
f'Evaluation started with Agent {agent_class}, model {model_name}, max iterations {max_iterations}.'
)
# =============================================
# filter out finished instances
new_gaia_tests = []
for instance in gaia_tests:
if instance['task_id'] in finished_task_ids:
logger.info(
f'Skipping instance {instance["task_id"]} as it is already finished.'
)
continue
new_gaia_tests.append(instance)
gaia_tests = new_gaia_tests
logger.info(
f'Finished instances: {len(finished_task_ids)}, Remaining instances: {len(gaia_tests)}'
)
# =============================================
pbar = tqdm(total=len(gaia_tests))
# This function tracks the progress AND write the output to a JSONL file
def update_progress(future):
pbar.update(1)
output = future.result()
pbar.set_description(f'Instance {output["instance_id"]}')
pbar.set_postfix_str(f'Test Result: {output["test_result"]["score"]}')
logger.info(
f'Finished evaluation for instance {output["instance_id"]}: {output["test_result"]}'
)
output_fp.write(json.dumps(output) + '\n')
output_fp.flush()
# This sets the multi-processing
num_workers = args.eval_num_workers
logger.info(f'Using {num_workers} workers for evaluation.')
try:
with ProcessPoolExecutor(num_workers) as executor:
futures = []
# This is how we perform multi-processing
for instance in gaia_tests:
future = executor.submit(
process_instance,
instance,
agent_class,
metadata,
reset_logger=bool(num_workers > 1),
)
future.add_done_callback(update_progress)
futures.append(future)
# Wait for all futures to complete
for future in futures:
future.result()
except KeyboardInterrupt:
logger.info('KeyboardInterrupt received. Cleaning up...')
cleanup()
output_fp.close()
logger.info('Evaluation finished.')
+102
View File
@@ -0,0 +1,102 @@
import re
import string
import warnings
def normalize_number_str(number_str: str) -> float:
# we replace these common units and commas to allow
# conversion to float
for char in ['$', '%', ',']:
number_str = number_str.replace(char, '')
try:
return float(number_str)
except ValueError:
print(f'String {number_str} cannot be normalized to number str.')
return float('inf')
def split_string(
s: str,
char_list: list[str] = None,
) -> list[str]:
if char_list is None:
char_list = [',', ';']
pattern = f"[{''.join(char_list)}]"
return re.split(pattern, s)
def question_scorer(
model_answer: str,
ground_truth: str,
) -> bool:
def is_float(element: any) -> bool:
try:
float(element)
return True
except ValueError:
return False
# if gt is a number
if is_float(ground_truth):
print(f'Evaluating {model_answer} as a number.')
normalized_answer = normalize_number_str(model_answer)
return normalized_answer == float(ground_truth)
# if gt is a list
elif any(char in ground_truth for char in [',', ';']):
print(f'Evaluating {model_answer} as a comma separated list.')
# question with the fish: normalization removes punct
gt_elems = split_string(ground_truth)
ma_elems = split_string(model_answer)
# check length is the same
if len(gt_elems) != len(ma_elems):
warnings.warn(
'Answer lists have different lengths, returning False.',
UserWarning,
stacklevel=2,
)
return False
# compare each element as float or str
comparisons = []
for ma_elem, gt_elem in zip(ma_elems, gt_elems):
if is_float(gt_elem):
normalized_ma_elem = normalize_number_str(ma_elem)
comparisons.append(normalized_ma_elem == float(gt_elem))
else:
# we do not remove punct since comparisons can include punct
comparisons.append(
normalize_str(ma_elem, remove_punct=False)
== normalize_str(gt_elem, remove_punct=False)
)
return all(comparisons)
# if gt is a str
else:
print(f'Evaluating {model_answer} as a string.')
return normalize_str(model_answer) == normalize_str(ground_truth)
def normalize_str(input_str, remove_punct=True) -> str:
"""
Normalize a string by:
- Removing all white spaces
- Optionally removing punctuation (if remove_punct is True)
- Converting to lowercase
Parameters:
- input_str: str, the string to normalize
- remove_punct: bool, whether to remove punctuation (default: True)
Returns:
- str, the normalized string
"""
# Remove all white spaces. Required e.g for seagull vs. sea gull
no_spaces = re.sub(r'\s', '', input_str)
# Remove punctuation, if specified.
if remove_punct:
translator = str.maketrans('', '', string.punctuation)
return no_spaces.lower().translate(translator)
else:
return no_spaces.lower()
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
MODEL_CONFIG=$1
AGENT=$2
EVAL_LIMIT=$3
LEVELS=$4
if [ -z "$AGENT" ]; then
echo "Agent not specified, use default CodeActAgent"
AGENT="CodeActAgent"
fi
if [ -z "$LEVELS" ]; then
LEVELS="2023_level1"
echo "Levels not specified, use default $LEVELS"
fi
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenDevin
# We need to track the version of Agent in the evaluation to make sure results are comparable
AGENT_VERSION=v$(poetry run python -c "import agenthub; from opendevin.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
echo "AGENT: $AGENT"
echo "AGENT_VERSION: $AGENT_VERSION"
echo "MODEL_CONFIG: $MODEL_CONFIG"
echo "LEVELS: $LEVELS"
COMMAND="poetry run python ./evaluation/gaia/run_infer.py \
--agent-cls $AGENT \
--llm-config $MODEL_CONFIG \
--max-iterations 30 \
--level $LEVELS \
--data-split validation \
--max-chars 10000000 \
--eval-num-workers 1 \
--eval-note ${AGENT_VERSION}_${LEVELS}"
if [ -n "$EVAL_LIMIT" ]; then
echo "EVAL_LIMIT: $EVAL_LIMIT"
COMMAND="$COMMAND --eval-n-limit $EVAL_LIMIT"
fi
# Run the command
eval $COMMAND
+210
View File
@@ -0,0 +1,210 @@
# HumanEvalFix Evaluation with OpenDevin
Implements evaluation of agents on HumanEvalFix from the HumanEvalPack benchmark introduced in [OctoPack: Instruction Tuning Code Large Language Models](https://arxiv.org/abs/2308.07124). Please see [here](https://github.com/bigcode-project/bigcode-evaluation-harness/blob/main/bigcode_eval/tasks/humanevalpack.py) for the reference implementation used in the paper.
## Setup Environment
Please follow [this document](https://github.com/OpenDevin/OpenDevin/blob/main/Development.md) to setup local develop environment for OpenDevin.
## Configure OpenDevin and your LLM
Create a `config.toml` file if it does not exist at the root of the workspace.
Add the following configurations:
```toml
[core]
max_iterations = 100
cache_dir = "/tmp/cache"
ssh_hostname = "localhost"
enable_auto_lint = true
# TODO: Change these to the model you want to evaluate
[eval_gpt4_1106_preview]
model = "gpt-4-1106-preview"
api_key = "XXX"
temperature = 0.0
[eval_some_openai_compatible_model]
model = "openai/MODEL_NAME"
base_url = "https://OPENAI_COMPATIBLE_URL/v1"
api_key = "XXX"
temperature = 0.0
```
## Run Inference on HumanEvalFix
```bash
./evaluation/humanevalfix/scripts/run_infer.sh eval_gpt4_1106_preview
```
You can replace `eval_gpt4_1106_preview` with any model you set up in `config.toml`.
## Examples
For each problem, OpenDevin is given a set number of iterations to fix the failing code. The history field shows each iteration's response to correct its code that fails any test case.
```
{
"task_id": "Python/2",
"instruction": "Please fix the function in Python__2.py such that all test cases pass.\nEnvironment has been set up for you to start working. You may assume all necessary tools are installed.\n\n# Problem Statement\ndef truncate_number(number: float) -> float:\n return number % 1.0 + 1.0\n\n\n\n\n\n\ndef check(truncate_number):\n assert truncate_number(3.5) == 0.5\n assert abs(truncate_number(1.33) - 0.33) < 1e-6\n assert abs(truncate_number(123.456) - 0.456) < 1e-6\n\ncheck(truncate_number)\n\nIMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\nYou should NOT modify any existing test case files. If needed, you can add new test cases in a NEW file to reproduce the issue.\nYou SHOULD INCLUDE PROPER INDENTATION in your edit commands.\nWhen you think you have fixed the issue through code changes, please run the following command: <execute_bash> exit </execute_bash>.\n",
"metadata": {
"agent_class": "CodeActAgent",
"model_name": "gpt-4",
"max_iterations": 10,
"eval_output_dir": "evaluation/evaluation_outputs/outputs/humanevalfix/CodeActAgent/gpt-4_maxiter_10_N_v1.4",
"start_time": "2024-05-22 20:54:15",
"git_commit": "4d3253696f5a9d9de02ab86969fe9796fa40331f"
},
"history": [
[
{
"id": 27,
"timestamp": "2024-05-22T20:57:24.688651",
"source": "user",
"message": "Please fix the function in Python__2.py such that all test cases pass.\nEnvironment has been set up for you to start working. You may assume all necessary tools are installed.\n\n# Problem Statement\ndef truncate_number(number: float) -> float:\n return number % 1.0 + 1.0\n\n\n\n\n\n\ndef check(truncate_number):\n assert truncate_number(3.5) == 0.5\n assert abs(truncate_number(1.33) - 0.33) < 1e-6\n assert abs(truncate_number(123.456) - 0.456) < 1e-6\n\ncheck(truncate_number)\n\nIMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\nYou should NOT modify any existing test case files. If needed, you can add new test cases in a NEW file to reproduce the issue.\nYou SHOULD INCLUDE PROPER INDENTATION in your edit commands.\nWhen you think you have fixed the issue through code changes, please run the following command: <execute_bash> exit </execute_bash>.\n",
"action": "message",
"args": {
"content": "Please fix the function in Python__2.py such that all test cases pass.\nEnvironment has been set up for you to start working. You may assume all necessary tools are installed.\n\n# Problem Statement\ndef truncate_number(number: float) -> float:\n return number % 1.0 + 1.0\n\n\n\n\n\n\ndef check(truncate_number):\n assert truncate_number(3.5) == 0.5\n assert abs(truncate_number(1.33) - 0.33) < 1e-6\n assert abs(truncate_number(123.456) - 0.456) < 1e-6\n\ncheck(truncate_number)\n\nIMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\nYou should NOT modify any existing test case files. If needed, you can add new test cases in a NEW file to reproduce the issue.\nYou SHOULD INCLUDE PROPER INDENTATION in your edit commands.\nWhen you think you have fixed the issue through code changes, please run the following command: <execute_bash> exit </execute_bash>.\n",
"wait_for_response": false
}
},
{
"message": "No observation",
"observation": "null",
"content": "",
"extras": {}
}
],
[
{
"id": 32,
"timestamp": "2024-05-22T20:57:28.413818",
"source": "agent",
"message": "Running command: open Python__2.py",
"action": "run",
"args": {
"command": "open Python__2.py",
"background": false,
"thought": "Let's start by opening the Python__2.py file to see the current implementation of the function."
}
},
{
"id": 33,
"timestamp": "2024-05-22T20:57:28.803780",
"source": "agent",
"message": "Command `open Python__2.py` executed with exit code 0.",
"cause": 32,
"observation": "run",
"content": "[File: /workspace/Python__2.py (14 lines total)]\r\n1:def truncate_number(number: float) -> float:\r\n2: return number % 1.0 + 1.0\r\n3:\r\n4:\r\n5:\r\n6:\r\n7:\r\n8:\r\n9:def check(truncate_number):\r\n10: assert truncate_number(3.5) == 0.5\r\n11: assert abs(truncate_number(1.33) - 0.33) < 1e-6\r\n12: assert abs(truncate_number(123.456) - 0.456) < 1e-6\r\n13:\r\n14:check(truncate_number)",
"extras": {
"command_id": -1,
"command": "open Python__2.py",
"exit_code": 0
}
}
],
[
{
"id": 34,
"timestamp": "2024-05-22T20:57:36.605638",
"source": "agent",
"message": "Running command: edit 2:2 <<EOF\n return number % 1.0\nEOF",
"action": "run",
"args": {
"command": "edit 2:2 <<EOF\n return number % 1.0\nEOF",
"background": false,
"thought": "The current implementation of the function `truncate_number` is incorrect because it adds 1.0 to the fractional part of the number. This is not necessary and is causing the function to fail the test cases. \n\nThe correct implementation should only return the fractional part of the number. This can be achieved by using the modulus operator with 1.0, which will return the fractional part of the number.\n\nLet's correct the function implementation."
}
},
{
"id": 35,
"timestamp": "2024-05-22T20:57:36.973592",
"source": "agent",
"message": "Command `edit 2:2 <<EOF\n return number % 1.0\nEOF` executed with exit code 0.",
"cause": 34,
"observation": "run",
"content": "> > [File: /workspace/Python__2.py (14 lines total)]\r\n1:def truncate_number(number: float) -> float:\r\n2: return number % 1.0\r\n3:\r\n4:\r\n5:\r\n6:\r\n7:\r\n8:\r\n9:def check(truncate_number):\r\n10: assert truncate_number(3.5) == 0.5\r\n11: assert abs(truncate_number(1.33) - 0.33) < 1e-6\r\n12: assert abs(truncate_number(123.456) - 0.456) < 1e-6\r\n13:\r\n14:check(truncate_number)\r\nFile updated. Please review the changes and make sure they are correct (correct indentation, no duplicate lines, etc). Edit the file again if necessary.",
"extras": {
"command_id": -1,
"command": "edit 2:2 <<EOF\n return number % 1.0\nEOF",
"exit_code": 0
}
}
],
[
{
"id": 36,
"timestamp": "2024-05-22T20:57:48.420415",
"source": "agent",
"message": "Running command: python3 Python__2.py",
"action": "run",
"args": {
"command": "python3 Python__2.py",
"background": false,
"thought": "The function `truncate_number` has been updated. Now, let's run the Python file to see if the test cases pass."
}
},
{
"id": 37,
"timestamp": "2024-05-22T20:57:48.635312",
"source": "agent",
"message": "Command `python3 Python__2.py` executed with exit code 0.",
"cause": 36,
"observation": "run",
"content": "",
"extras": {
"command_id": -1,
"command": "python3 Python__2.py",
"exit_code": 0
}
}
],
[
{
"id": 38,
"timestamp": "2024-05-22T20:58:10.589252",
"source": "agent",
"message": "All done! What's next on the agenda?",
"action": "finish",
"args": {
"outputs": {},
"thought": ""
}
},
{
"message": "No observation",
"observation": "null",
"content": "",
"extras": {}
}
]
],
"error": null,
"test_result": {
"result": {
"pass@1": 1.0
},
"metadata": {
"logs": {
"0": [
[
0,
{
"task_id": 0,
"passed": true,
"result": "passed",
"completion_id": 0
}
]
]
},
"timeout": 10,
"num_workers": 4
}
}
}
```
View File
+391
View File
@@ -0,0 +1,391 @@
"""
Implements evaluation of agents on HumanEvalFix from the HumanEvalPack benchmark introduced in
"OctoPack: Instruction Tuning Code Large Language Models" (https://arxiv.org/abs/2308.07124).
Please see https://github.com/bigcode-project/bigcode-evaluation-harness/blob/main/bigcode_eval/tasks/humanevalpack.py
for the reference implementation used in the paper.
TODOs:
- Potentially support other HumanEvalPack datasets (Explain & Synthesize)
- Support other languages (currently only Python)
"""
import asyncio
import json
import logging
import multiprocessing as mp
import os
import pathlib
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
import pandas as pd
from datasets import load_dataset
from evaluate import load
from tqdm import tqdm
from opendevin.controller.state.state import State
from opendevin.core.config import args, config, get_llm_config_arg
from opendevin.core.logger import get_console_handler
from opendevin.core.logger import opendevin_logger as logger
from opendevin.core.main import main
from opendevin.events.action import MessageAction
from opendevin.events.serialization.event import event_to_dict
IMPORT_HELPER = {
'python': [
'import math',
'import re',
'import sys',
'import copy',
'import datetime',
'import itertools',
'import collections',
'import heapq',
'import statistics',
'import functools',
'import hashlib',
'import numpy',
'import numpy as np',
'import string',
'from typing import *',
'from collections import *',
],
}
LANGUAGE_TO_TIMEOUT = {
'python': 10,
}
LANGUAGE_TO_NUM_WORKERS = {
'python': 4,
}
def cleanup():
logger.info('Cleaning up child processes...')
for process in mp.active_children():
logger.info(f'Terminating child process: {process.name}')
process.terminate()
process.join()
def codeact_user_response(state: State) -> str:
msg = (
'Please continue working on the task on whatever approach you think is suitable.\n'
'If you think you have modified the code in a way that fixes the issue, please run the following command: <execute_bash> exit </execute_bash>.\n'
'IMPORTANT: YOU SHOULD NEVER ASK FOR HUMAN HELP OR USE THE INTERNET TO SOLVE THIS TASK.\n'
)
if state.history:
user_msgs = [
action
for action, _ in state.history
if isinstance(action, MessageAction) and action.source == 'user'
]
if len(user_msgs) >= 2:
# let the agent know that it can give up when it has tried 3 times
return (
msg
+ 'If you want to give up, run: <execute_bash> exit </execute_bash>.\n'
)
return msg
def monologue_user_response(state: State) -> str:
raise NotImplementedError('MonologueAgent should never ask for user responses.')
AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = {
'CodeActAgent': codeact_user_response,
'MonologueAgent': monologue_user_response,
}
AGENT_CLS_TO_INST_SUFFIX = {
'CodeActAgent': 'When you think you have fixed the issue through code changes, please run the following command: <execute_bash> exit </execute_bash>.\n'
}
def get_test_result(instance, path, language='python', timeout=10):
# Evaluation reference: https://github.com/bigcode-project/bigcode-evaluation-harness/blob/84b96da31b7f840b55c5733325346176140cdb6b/bigcode_eval/tasks/humanevalpack.py#L347
test_result = {'result': {}, 'metadata': {}}
code_metric = load('Muennighoff/code_eval_octopack')
timeout = LANGUAGE_TO_TIMEOUT[language]
num_workers = LANGUAGE_TO_NUM_WORKERS[language]
python_imports = '\n'.join(IMPORT_HELPER[language])
# Load function from path
with open(path, 'r') as f:
function = f.read()
function = [[python_imports + '\n' + function.strip()]]
results, logs = code_metric.compute(
references=[instance.test],
predictions=function,
language=language,
timeout=timeout,
num_workers=num_workers,
)
test_result['result'] = results
test_result['metadata'] = {
'logs': logs,
'timeout': timeout,
'num_workers': num_workers,
}
return test_result
def process_instance(
instance, agent_class, metadata, skip_workspace_mount, reset_logger: bool = True
):
old_workspace_mount_path = config.workspace_mount_path
old_workspace_base = config.workspace_base
try:
workspace_mount_path = os.path.join(
config.workspace_mount_path, '_eval_workspace'
)
# create process-specific workspace dir
# if `not skip_workspace_mount` - we will create a workspace directory for EACH process
# so that different agent don't interfere with each other.
if not skip_workspace_mount:
workspace_mount_path = os.path.join(workspace_mount_path, str(os.getpid()))
pathlib.Path(workspace_mount_path).mkdir(parents=True, exist_ok=True)
# reset workspace to config
config.workspace_base = workspace_mount_path
config.workspace_mount_path = workspace_mount_path
# Setup the logger properly, so you can run multi-processing to parallelize the evaluation
if reset_logger:
# Set up logger
log_file = os.path.join(
eval_output_dir,
'logs',
f'instance_{instance.task_id.replace("/", "__")}.log',
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# add back the console handler to print ONE line
logger.addHandler(get_console_handler())
logger.info(
f'Starting evaluation for instance {instance.task_id}.\nLOG: tail -f {log_file}'
)
# Remove all existing handlers from logger
for handler in logger.handlers[:]:
logger.removeHandler(handler)
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
)
logger.addHandler(file_handler)
if not skip_workspace_mount:
logger.info(f'Process-specific workspace mounted at {workspace_mount_path}')
# Create file with HumanEvalFix problem
# Prompt reference: https://github.com/bigcode-project/bigcode-evaluation-harness/blob/84b96da31b7f840b55c5733325346176140cdb6b/bigcode_eval/tasks/humanevalpack.py#L509
problem_statement = (
instance.declaration + instance.buggy_solution + '\n' + instance.test
)
path = os.path.join(
workspace_mount_path, f'{instance.task_id.replace("/", "__")}.py'
)
with open(path, 'w') as f:
f.write(problem_statement)
# Prepare instruction
instruction = (
f'Please fix the function in {instance.task_id.replace("/", "__")}.py such that all test cases pass.\n'
'Environment has been set up for you to start working. You may assume all necessary tools are installed.\n\n'
'# Problem Statement\n'
f'{problem_statement}\n\n'
)
instruction += (
'IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\n'
'You should NOT modify any existing test case files. If needed, you can add new test cases in a NEW file to reproduce the issue.\n'
'You SHOULD INCLUDE PROPER INDENTATION in your edit commands.\n'
)
# NOTE: You can actually set slightly different instruction for different agents
instruction += AGENT_CLS_TO_INST_SUFFIX.get(agent_class, '')
# Here's how you can run the agent (similar to the `main` function) and get the final task state
state: State = asyncio.run(
main(
instruction,
fake_user_response_fn=AGENT_CLS_TO_FAKE_USER_RESPONSE_FN.get(
agent_class
),
)
)
# ======= Attempt to evaluate the agent's edits =======
test_result = get_test_result(instance, path)
# If you are working on some simpler benchmark that only evaluates the final model output (e.g., in a MessageAction)
# You can simply get the LAST `MessageAction` from the returned `state.history` and parse it for evaluation.
if state is None:
raise ValueError('State should not be None.')
metrics = state.metrics.get() if state.metrics else None
# Save the output
output = {
'task_id': instance.task_id,
'instruction': instruction,
'metadata': metadata,
'history': [
(event_to_dict(action), event_to_dict(obs))
for action, obs in state.history
],
'metrics': metrics,
'error': state.error if state and state.error else None,
'test_result': test_result,
}
except Exception:
logger.error('Process instance failed')
raise
finally:
config.workspace_mount_path = old_workspace_mount_path
config.workspace_base = old_workspace_base
return output
if __name__ == '__main__':
# NOTE: It is preferable to load datasets from huggingface datasets and perform post-processing
# so we don't need to manage file uploading to OpenDevin's repo
dataset = load_dataset(
'bigcode/humanevalpack', 'python'
) # TODO: Support other languages
hefix_tests = dataset['test'].to_pandas()
# Check https://github.com/OpenDevin/OpenDevin/blob/main/evaluation/humanevalfix/README.md#configure-opendevin-and-your-llm
# for details of how to set `llm_config`
if args.llm_config:
specified_llm_config = get_llm_config_arg(args.llm_config)
if specified_llm_config:
config.llm = specified_llm_config
logger.info(f'Config for evaluation: {config}')
# TEST METADATA
agent_class = args.agent_cls
assert (
agent_class in AGENT_CLS_TO_FAKE_USER_RESPONSE_FN
), f'Unsupported agent class: {agent_class}'
model_name = config.llm.model.split('/')[-1]
max_iterations = args.max_iterations
eval_note = ''
if args.eval_note is not None:
eval_note += '_N_' + args.eval_note
eval_output_dir = os.path.join(
args.eval_output_dir,
'humanevalfix',
agent_class,
model_name + '_maxiter_' + str(max_iterations) + eval_note,
)
pathlib.Path(eval_output_dir).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(eval_output_dir, 'logs')).mkdir(
parents=True, exist_ok=True
)
logger.info(f'Using evaluation output directory: {eval_output_dir}')
metadata = {
'agent_class': agent_class,
'model_name': model_name,
'max_iterations': max_iterations,
'eval_output_dir': eval_output_dir,
'start_time': time.strftime('%Y-%m-%d %H:%M:%S'),
# get the commit id of current repo for reproducibility
'git_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'])
.decode('utf-8')
.strip(),
}
logger.info(f'Metadata: {metadata}')
with open(os.path.join(eval_output_dir, 'metadata.json'), 'w') as f:
json.dump(metadata, f)
# LIMIT EVALUATION
eval_n_limit = args.eval_n_limit
if eval_n_limit:
hefix_tests = hefix_tests.head(eval_n_limit)
logger.info(f'Limiting evaluation to first {eval_n_limit} instances.')
# OUTPUT FILE
output_file = os.path.join(eval_output_dir, 'output.jsonl')
logger.info(f'Writing evaluation output to {output_file}')
finished_instance_ids = set()
if os.path.exists(output_file):
with open(output_file, 'r') as f:
for line in f:
data = json.loads(line)
finished_instance_ids.add(data['task_id'])
logger.warning(
f'Output file {output_file} already exists. Loaded {len(finished_instance_ids)} finished instances.'
)
output_fp = open(output_file, 'a')
logger.info(
f'Evaluation started with Agent {agent_class}, model {model_name}, max iterations {max_iterations}.'
)
# =============================================
# filter out finished instances
new_hefix_tests = []
for idx, instance in hefix_tests.iterrows():
if instance.task_id in finished_instance_ids:
logger.info(
f'Skipping instance {instance.task_id} as it is already finished.'
)
continue
new_hefix_tests.append(instance)
hefix_tests = pd.DataFrame(new_hefix_tests)
logger.info(
f'Finished instances: {len(finished_instance_ids)}, Remaining instances: {len(hefix_tests)}'
)
# =============================================
pbar = tqdm(total=len(hefix_tests))
# This function tracks the progress AND write the output to a JSONL file
def update_progress(future):
pbar.update(1)
output = future.result()
pbar.set_description(f'Instance {output["task_id"]}')
pbar.set_postfix_str(f'Test Result: {output["test_result"]["result"]}')
logger.info(
f'Finished evaluation for instance {output["task_id"]}: {output["test_result"]["result"]}'
)
output_fp.write(json.dumps(output) + '\n')
output_fp.flush()
# This sets the multi-processing
num_workers = args.eval_num_workers
logger.info(f'Using {num_workers} workers for evaluation.')
try:
with ProcessPoolExecutor(num_workers) as executor:
futures = []
# This is how we perform multi-processing
for row_idx, instance in hefix_tests.iterrows():
future = executor.submit(
process_instance,
instance,
agent_class,
metadata,
skip_workspace_mount=False,
reset_logger=bool(num_workers > 1),
)
future.add_done_callback(update_progress)
futures.append(future)
# Wait for all futures to complete
for future in futures:
future.result()
except KeyboardInterrupt:
print('KeyboardInterrupt received. Cleaning up...')
cleanup()
output_fp.close()
logger.info('Evaluation finished.')

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