From dcc4101bd45dcd53a6bd5cfdf8ea1af0a40fcad2 Mon Sep 17 00:00:00 2001 From: S Ali Hosseini <38721653+5A11@users.noreply.github.com> Date: Tue, 17 Jan 2023 14:59:25 +0000 Subject: [PATCH] docs: documentation cleanup --- .github/PULL_REQUEST_TEMPLATE/release.md | 2 +- AUTHORS.md | 24 +- CODE_OF_CONDUCT.md | 26 +- CONTRIBUTING.md | 38 +- DEVELOPING.md | 161 ++- HISTORY.md | 57 +- README.md | 8 +- SECURITY.md | 2 +- aea/connections/scaffold/connection.yaml | 2 +- aea/connections/scaffold/readme.md | 2 + benchmark/README.md | 17 +- deploy-image/README.md | 7 +- develop-image/README.md | 92 +- docs/12-factor.md | 217 +-- docs/acn-internals.md | 525 +++---- docs/acn.md | 27 +- docs/aea-vs-mvc.md | 8 +- docs/agent-oriented-development.md | 50 +- docs/agent-vs-aea.md | 278 ++-- docs/aggregation-demo.md | 88 +- docs/app-areas.md | 39 +- docs/aries-cloud-agent-demo.md | 168 ++- docs/assets/images/favicon.ico | Bin 0 -> 1150 bytes docs/assets/images/logo.png | Bin 0 -> 14201 bytes docs/build-aea-programmatically.md | 268 ++-- docs/build-aea-step-by-step.md | 21 +- docs/car-park-skills.md | 176 +-- docs/cli-commands.md | 100 +- docs/cli-how-to.md | 16 +- docs/cli-vs-programmatic-aeas.md | 479 ++++--- docs/config.md | 22 +- docs/connect-a-frontend.md | 6 +- docs/connection.md | 25 +- docs/contract.md | 37 +- docs/core-components-1.md | 53 +- docs/core-components-2.md | 26 +- docs/css/my-styles.css | 86 +- docs/debug.md | 5 +- docs/decision-maker-transaction.md | 555 ++++---- docs/decision-maker.md | 30 +- docs/defining-data-models.md | 36 +- docs/demos.md | 4 +- docs/deployment.md | 4 +- docs/design-principles.md | 20 +- docs/development-setup.md | 32 +- docs/diagram.md | 29 +- docs/erc1155-skills.md | 207 ++- docs/generic-skills-step-by-step.md | 85 +- docs/generic-skills.md | 155 +- docs/generic-storage.md | 38 +- docs/glossary.md | 10 +- docs/gym-example.md | 17 +- docs/gym-skill.md | 79 +- docs/http-connection-and-skill.md | 20 +- docs/identity.md | 9 +- docs/index.md | 57 +- docs/interaction-protocol.md | 25 +- docs/known-limits.md | 4 +- docs/language-agnostic-definition.md | 246 ++-- docs/ledger-integration.md | 39 +- docs/limits.md | 100 +- docs/logging.md | 10 +- docs/message-routing.md | 24 +- docs/ml-skills.md | 211 ++- docs/modes.md | 1 + docs/multi-agent-manager.md | 15 +- docs/multiplexer-standalone.md | 233 +-- docs/oef-ledger.md | 13 +- docs/oracle-demo.md | 439 +++--- docs/orm-integration.md | 166 ++- docs/p2p-connection.md | 112 +- docs/package-imports.md | 21 +- docs/performance-benchmark.md | 77 +- docs/por.md | 3 +- docs/prometheus.md | 212 +-- docs/protocol-generator.md | 116 +- docs/protocol.md | 111 +- docs/query-language.md | 54 +- docs/questions-and-answers.md | 101 +- docs/quickstart.md | 421 +++--- docs/raspberry-set-up.md | 77 +- docs/runtime-cost.md | 6 +- docs/scaffolding.md | 17 +- docs/security.md | 3 +- docs/simple-oef-usage.md | 45 +- docs/skill-guide.md | 1192 ++++++++-------- docs/skill-testing.md | 32 +- docs/skill.md | 71 +- docs/standalone-transaction.md | 157 +- docs/step-one.md | 18 +- docs/tac-skills-contract.md | 557 ++++---- docs/tac-skills.md | 299 ++-- docs/tac.md | 25 +- docs/thermometer-skills.md | 162 +-- docs/trust.md | 6 +- docs/upgrading.md | 155 +- docs/version.md | 4 +- docs/vision.md | 26 +- docs/wealth.md | 37 +- docs/weather-skills.md | 178 +-- examples/aealite_go/README.md | 2 +- examples/gym_ex/README.md | 2 +- examples/tac_deploy/README.md | 22 +- libs/go/aealite/README.md | 115 +- libs/go/libp2p_node/README.md | 11 +- mkdocs.yml | 109 +- packages/fetchai/agents/aries_alice/README.md | 8 +- packages/fetchai/agents/aries_faber/README.md | 17 +- .../fetchai/agents/car_data_buyer/README.md | 6 +- .../fetchai/agents/car_detector/README.md | 4 +- .../fetchai/agents/coin_price_feed/README.md | 2 +- .../agents/coin_price_oracle/README.md | 3 +- .../agents/coin_price_oracle_client/README.md | 1 - .../fetchai/agents/erc1155_client/README.md | 4 +- .../fetchai/agents/erc1155_deployer/README.md | 4 +- .../fetchai/agents/fipa_dummy_buyer/README.md | 2 +- .../fetchai/agents/generic_buyer/README.md | 6 +- .../fetchai/agents/generic_seller/README.md | 6 +- packages/fetchai/agents/gym_aea/README.md | 8 +- packages/fetchai/agents/hello_world/README.md | 4 +- .../agents/latest_block_feed/README.md | 2 +- .../fetchai/agents/ml_data_provider/README.md | 6 +- .../fetchai/agents/ml_model_trainer/README.md | 4 +- .../fetchai/agents/my_first_aea/README.md | 4 +- .../agents/simple_aggregator/README.md | 1 - .../simple_service_registration/README.md | 2 +- .../agents/simple_service_search/README.md | 2 +- .../fetchai/agents/tac_controller/README.md | 4 +- .../agents/tac_controller_contract/README.md | 4 +- .../fetchai/agents/tac_participant/README.md | 4 +- .../agents/tac_participant_contract/README.md | 4 +- .../fetchai/agents/thermometer_aea/README.md | 6 +- .../agents/thermometer_client/README.md | 4 +- .../fetchai/agents/weather_client/README.md | 4 +- .../fetchai/agents/weather_station/README.md | 6 +- packages/fetchai/connections/gym/README.md | 2 +- .../fetchai/connections/gym/connection.yaml | 2 +- .../fetchai/connections/http_server/README.md | 2 +- .../connections/http_server/connection.yaml | 2 +- packages/fetchai/connections/oef/README.md | 4 +- .../fetchai/connections/oef/connection.yaml | 2 +- .../connections/p2p_libp2p/connection.yaml | 2 +- .../p2p_libp2p/libp2p_node/README.md | 11 +- .../connections/p2p_libp2p_client/README.md | 3 +- .../p2p_libp2p_client/connection.yaml | 2 +- .../connections/p2p_libp2p_mailbox/README.md | 3 +- .../p2p_libp2p_mailbox/connection.yaml | 2 +- .../fetchai/connections/prometheus/README.md | 1 + .../connections/prometheus/connection.yaml | 2 +- packages/fetchai/connections/soef/README.md | 2 +- .../fetchai/connections/soef/connection.yaml | 2 +- packages/fetchai/connections/stub/README.md | 2 + .../fetchai/connections/stub/connection.yaml | 2 +- packages/fetchai/contracts/erc1155/README.md | 29 +- .../fetchai/contracts/erc1155/contract.yaml | 2 +- .../fetchai/contracts/fet_erc20/README.md | 4 +- .../fetchai/contracts/fet_erc20/contract.yaml | 2 +- packages/fetchai/contracts/oracle/README.md | 4 +- .../fetchai/contracts/oracle/contract.yaml | 2 +- .../fetchai/contracts/oracle_client/README.md | 2 +- .../contracts/oracle_client/contract.yaml | 2 +- .../fetchai/contracts/staking_erc20/README.md | 2 +- .../contracts/staking_erc20/contract.yaml | 2 +- .../fetchai/protocols/cosm_trade/README.md | 5 +- .../protocols/cosm_trade/protocol.yaml | 2 +- packages/fetchai/protocols/fipa/README.md | 2 +- packages/fetchai/protocols/fipa/protocol.yaml | 2 +- packages/fetchai/protocols/gym/README.md | 2 +- packages/fetchai/protocols/gym/protocol.yaml | 2 +- packages/fetchai/protocols/http/README.md | 2 +- packages/fetchai/protocols/http/protocol.yaml | 2 +- packages/fetchai/protocols/tac/README.md | 2 +- packages/fetchai/protocols/tac/protocol.yaml | 2 +- .../skills/advanced_data_request/README.md | 4 +- .../skills/advanced_data_request/skill.yaml | 2 +- packages/fetchai/skills/aries_alice/README.md | 12 +- .../fetchai/skills/aries_alice/skill.yaml | 2 +- packages/fetchai/skills/aries_faber/README.md | 19 +- .../fetchai/skills/aries_faber/skill.yaml | 2 +- .../fetchai/skills/carpark_client/README.md | 16 +- .../fetchai/skills/carpark_client/skill.yaml | 2 +- .../skills/carpark_detection/README.md | 10 +- .../skills/carpark_detection/skill.yaml | 2 +- .../fetchai/skills/confirmation_aw1/README.md | 12 +- .../skills/confirmation_aw1/skill.yaml | 2 +- .../fetchai/skills/confirmation_aw2/README.md | 18 +- .../skills/confirmation_aw2/skill.yaml | 2 +- .../fetchai/skills/confirmation_aw3/README.md | 18 +- .../skills/confirmation_aw3/skill.yaml | 2 +- packages/fetchai/skills/echo/README.md | 10 +- packages/fetchai/skills/echo/skill.yaml | 2 +- .../fetchai/skills/erc1155_client/README.md | 16 +- .../fetchai/skills/erc1155_client/skill.yaml | 2 +- .../fetchai/skills/erc1155_deploy/README.md | 14 +- .../fetchai/skills/erc1155_deploy/skill.yaml | 2 +- packages/fetchai/skills/error/README.md | 3 +- packages/fetchai/skills/error/skill.yaml | 2 +- .../fetchai/skills/error_test_skill/README.md | 4 +- .../skills/error_test_skill/skill.yaml | 2 +- packages/fetchai/skills/fetch_block/README.md | 4 +- .../fetchai/skills/fetch_block/skill.yaml | 2 +- .../fetchai/skills/generic_buyer/README.md | 18 +- .../fetchai/skills/generic_buyer/skill.yaml | 2 +- .../fetchai/skills/generic_seller/README.md | 12 +- .../fetchai/skills/generic_seller/skill.yaml | 2 +- packages/fetchai/skills/gym/README.md | 9 +- packages/fetchai/skills/gym/skill.yaml | 2 +- packages/fetchai/skills/http_echo/README.md | 4 +- packages/fetchai/skills/http_echo/skill.yaml | 2 +- .../fetchai/skills/ml_data_provider/README.md | 10 +- .../skills/ml_data_provider/skill.yaml | 2 +- packages/fetchai/skills/ml_train/README.md | 15 +- packages/fetchai/skills/ml_train/skill.yaml | 2 +- .../fetchai/skills/registration_aw1/README.md | 8 +- .../skills/registration_aw1/skill.yaml | 2 +- .../skills/simple_aggregation/README.md | 8 +- .../skills/simple_aggregation/skill.yaml | 2 +- .../fetchai/skills/simple_buyer/README.md | 16 +- .../fetchai/skills/simple_buyer/skill.yaml | 2 +- .../skills/simple_data_request/README.md | 4 +- .../skills/simple_data_request/skill.yaml | 2 +- .../fetchai/skills/simple_oracle/README.md | 10 +- .../fetchai/skills/simple_oracle/skill.yaml | 2 +- .../skills/simple_oracle_client/README.md | 8 +- .../skills/simple_oracle_client/skill.yaml | 2 +- .../fetchai/skills/simple_seller/README.md | 10 +- .../fetchai/skills/simple_seller/skill.yaml | 2 +- .../simple_service_registration/README.md | 6 +- .../simple_service_registration/skill.yaml | 2 +- .../skills/simple_service_search/README.md | 6 +- .../skills/simple_service_search/skill.yaml | 2 +- packages/fetchai/skills/tac_control/README.md | 8 +- .../fetchai/skills/tac_control/skill.yaml | 2 +- .../skills/tac_control_contract/README.md | 14 +- .../skills/tac_control_contract/skill.yaml | 2 +- .../fetchai/skills/tac_negotiation/README.md | 16 +- .../fetchai/skills/tac_negotiation/skill.yaml | 2 +- .../skills/tac_participation/README.md | 10 +- .../skills/tac_participation/skill.yaml | 2 +- .../fetchai/skills/task_test_skill/README.md | 2 - .../fetchai/skills/task_test_skill/skill.yaml | 2 +- packages/fetchai/skills/thermometer/README.md | 10 +- .../fetchai/skills/thermometer/skill.yaml | 2 +- .../skills/thermometer_client/README.md | 15 +- .../skills/thermometer_client/skill.yaml | 2 +- .../fetchai/skills/weather_client/README.md | 15 +- .../fetchai/skills/weather_client/skill.yaml | 2 +- .../fetchai/skills/weather_station/README.md | 10 +- .../fetchai/skills/weather_station/skill.yaml | 2 +- packages/hashes.csv | 174 +-- plugins/aea-cli-ipfs/README.md | 1 + plugins/aea-ledger-ethereum/setup.py | 2 +- poetry.lock | 1262 +++++++++-------- pyproject.toml | 4 +- scripts/NOTES.md | 2 +- scripts/RELEASE_PROCESS.md | 4 +- scripts/acn/README.md | 33 +- .../test_helpers/test_ipfs/test_base.py | 2 +- tests/test_docs/helper.py | 89 +- .../md_files/bash-aggregation-demo.md | 19 +- .../md_files/bash-aries-cloud-agent-demo.md | 27 +- .../md_files/bash-car-park-skills.md | 18 +- .../md_files/bash-cli-how-to.md | 6 +- .../md_files/bash-cli-vs-programmatic-aeas.md | 8 + .../test_bash_yaml/md_files/bash-config.md | 8 + .../md_files/bash-connection.md | 3 +- .../test_bash_yaml/md_files/bash-contract.md | 1 + .../md_files/bash-decision-maker.md | 1 + .../md_files/bash-erc1155-skills.md | 24 +- .../bash-generic-skills-step-by-step.md | 29 +- .../md_files/bash-generic-skills.md | 21 +- .../md_files/bash-gym-example.md | 2 + .../test_bash_yaml/md_files/bash-gym-skill.md | 11 + .../bash-http-connection-and-skill.md | 12 +- .../bash-language-agnostic-definition.md | 4 +- .../test_bash_yaml/md_files/bash-logging.md | 3 + .../test_bash_yaml/md_files/bash-ml-skills.md | 20 +- .../md_files/bash-oef-ledger.md | 1 + .../md_files/bash-oracle-demo.md | 31 + .../md_files/bash-orm-integration.md | 24 +- .../md_files/bash-p2p-connection.md | 78 +- .../md_files/bash-package-imports.md | 1 + .../md_files/bash-performance-benchmark.md | 2 + .../test_bash_yaml/md_files/bash-por.md | 2 +- .../md_files/bash-protocol-generator.md | 4 + .../md_files/bash-quickstart.md | 34 +- .../md_files/bash-raspberry-set-up.md | 8 + .../md_files/bash-scaffolding.md | 5 + .../md_files/bash-skill-guide.md | 17 +- .../test_bash_yaml/md_files/bash-skill.md | 5 +- .../md_files/bash-tac-skills-contract.md | 40 +- .../md_files/bash-tac-skills.md | 22 +- .../test_bash_yaml/md_files/bash-tac.md | 9 + .../md_files/bash-thermometer-skills.md | 20 +- .../test_bash_yaml/md_files/bash-version.md | 2 +- .../test_bash_yaml/md_files/bash-wealth.md | 11 +- .../md_files/bash-weather-skills.md | 18 +- .../test_language_agnostic_definition.py | 2 +- tests/test_docs/test_quickstart.py | 2 +- user-image/README.md | 2 +- 300 files changed, 7112 insertions(+), 6379 deletions(-) create mode 100644 docs/assets/images/favicon.ico create mode 100644 docs/assets/images/logo.png diff --git a/.github/PULL_REQUEST_TEMPLATE/release.md b/.github/PULL_REQUEST_TEMPLATE/release.md index 1b4b7ba0cc..49ff36f139 100644 --- a/.github/PULL_REQUEST_TEMPLATE/release.md +++ b/.github/PULL_REQUEST_TEMPLATE/release.md @@ -18,7 +18,7 @@ _Put an `x` in the boxes that apply._ - [ ] I have added an item in `HISTORY.md` for this release. - [ ] I bumped the version number in the `aea/__version__.py` file. - [ ] I bumped the version number in every Docker image of the repo and published it. Also, I built and published them with tag `latest` - (check the READMEs of [`aea-develop`](https://github.com/fetchai/agents-aea/blob/master/develop-image/README.md#publish) + (check the READMEs of [`aea-develop`](https://github.com/fetchai/agents-aea/blob/master/develop-image/README.md#publish) and [`aea-user`](https://github.com/fetchai/agents-aea/blob/master/develop-image/user-image/README.md#publish)) - [ ] I have pushed the latest packages to the registry. - [ ] I have uploaded the latest `aea` to PyPI. diff --git a/AUTHORS.md b/AUTHORS.md index 5bc6dfd308..61ce63145d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -4,18 +4,18 @@ This is the official list of the AEA Framework authors: ### Lead -* Ali Hosseini [5A11](https://github.com/5A11) +- Ali Hosseini [5A11](https://github.com/5A11) ### Current and Past Contributors -* James Riehl [jrriehl](https://github.com/jrriehl) -* David Minarsch [DavidMinarsch](https://github.com/DavidMinarsch) -* Marco Favorito [MarcoFavorito](https://github.com/MarcoFavorito) -* Yuri Turchenkov [solarw](https://github.com/solarw) -* Oleg Panasevych [Panasevychol](https://github.com/panasevychol) -* Lokman Rahmani [lrahmani](https://github.com/lrahmani) -* Jiří Vestfál [MissingNO57](https://github.com/MissingNO57) -* Aristotelis Triantafyllidis [Totoual](https://github.com/Totoual) -* Diarmid Campbell [dishmop](https://github.com/dishmop) -* Kevin Chen [Kevin-Chen0](https://github.com/Kevin-Chen0) -* Ed Fitzgerald [ejfitzgerald](https://github.com/ejfitzgerald) +- James Riehl [jrriehl](https://github.com/jrriehl) +- David Minarsch [DavidMinarsch](https://github.com/DavidMinarsch) +- Marco Favorito [MarcoFavorito](https://github.com/MarcoFavorito) +- Yuri Turchenkov [solarw](https://github.com/solarw) +- Oleg Panasevych [Panasevychol](https://github.com/panasevychol) +- Lokman Rahmani [lrahmani](https://github.com/lrahmani) +- Jiří Vestfál [MissingNO57](https://github.com/MissingNO57) +- Aristotelis Triantafyllidis [Totoual](https://github.com/Totoual) +- Diarmid Campbell [dishmop](https://github.com/dishmop) +- Kevin Chen [Kevin-Chen0](https://github.com/Kevin-Chen0) +- Ed Fitzgerald [ejfitzgerald](https://github.com/ejfitzgerald) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 8c98b067fe..685073776e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -10,19 +10,19 @@ We pledge to act and interact in ways that contribute to an open, welcoming, div Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall community +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others’ private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others’ private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -70,9 +70,11 @@ Community leaders will follow these Community Impact Guidelines in determining t ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 2.1, +This Code of Conduct is adapted from the [Contributor Covenant][contributor covenant], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html). Community Impact Guidelines were inspired by [Mozilla’s code of conduct enforcement ladder](https://github.com/mozilla/diversity). -For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are available at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). \ No newline at end of file +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are available at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). + +[contributor covenant]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8492224414..79802b0cfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,10 +16,10 @@ Please read and follow our [Code of Conduct][coc]. ## Question or Problem? -Please use [Github Discussions][ghdiscussion] for support related questions and general discussions. Do NOT open issues as they are for bug reports and feature requests. This is because: +Please use [GitHub Discussions][ghdiscussion] for support related questions and general discussions. Do NOT open issues as they are for bug reports and feature requests. This is because: - Questions and answers stay available for public viewing so your question/answer might help someone else. -- Github Discussions voting system ensures the best answers are prominently visible. +- GitHub Discussions voting system ensures the best answers are prominently visible. ## Found a Bug? @@ -27,11 +27,12 @@ If you find a bug in the source code [submit a bug report issue](#submit-issue). Even better, you can [submit a Pull Request](#submit-pr) with a fix. ## Missing a Feature? + You can *request* a new feature by [submitting a feature request issue](#submit-issue). If you would like to *implement* a new feature: -* For a **Major Feature**, first [open an issue](#submit-issue) and outline your proposal so that it can be discussed. -* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). +- For a **Major Feature**, first [open an issue](#submit-issue) and outline your proposal so that it can be discussed. +- **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). ## Submission Guidelines @@ -74,7 +75,7 @@ Before you submit your Pull Request (PR) consider the following guidelines: #### Reviewing a Pull Request -The AEA team reserves the right not to accept pull requests from community members who haven't been good citizens of the community. Such behavior includes not following our [code of conduct][coc] and applies within or outside of the managed channels. +The AEA team reserves the right not to accept pull requests from community members who haven't been good citizens of the community. Such behavior includes not following our [code of conduct][coc] and applies within or outside the managed channels. When you contribute a new feature, the maintenance burden is transferred to the core team. This means that the benefit of the contribution must be compared against the cost of maintaining the feature. @@ -93,25 +94,26 @@ If we ask for changes via code reviews then: After your pull request is merged, you can safely delete your branch and pull the changes from the (upstream) repository. ## Coding Rules + To ensure consistency throughout the source code, keep these rules in mind as you are working: -* All code must pass our code quality checks (linters, formatters, etc). See the [development guide][developing] section for more detail. -* All features or bug fixes **must be tested** via unit-tests and if applicable integration-tests. These help to, a) prove that your code works correctly, and b) guard against future breaking changes and lower the maintenance cost. -* All public features **must be documented**. -* All files must include a license header. +- All code must pass our code quality checks (linters, formatters, etc). See the [development guide][developing] section for more detail. +- All features or bug fixes **must be tested** via unit-tests and if applicable integration-tests. These help to, a. prove that your code works correctly, and b. guard against future breaking changes and lower the maintenance cost. +- All public features **must be documented**. +- All files must include a license header. ## Commit Message Convention Please follow the [Conventional Commits v1.0.0][convcommit]. The commit types must be one of the following: -* **build**: Changes that affect the build system or external dependencies -* **ci**: Changes to our CI configuration files and scripts -* **docs**: Documentation only changes -* **feat**: A new feature -* **fix**: A bug fix -* **nfunc**: Code that improves some non-functional characteristic, such as performance, security, ... -* **refactor**: A code change that neither fixes a bug nor adds a feature -* **test**: Adding missing tests or correcting existing tests +- **build**: Changes that affect the build system or external dependencies +- **ci**: Changes to our CI configuration files and scripts +- **docs**: Documentation only changes +- **feat**: A new feature +- **fix**: A bug fix +- **nfunc**: Code that improves some non-functional characteristic, such as performance, security, ... +- **refactor**: A code change that neither fixes a bug nor adds a feature +- **test**: Adding missing tests or correcting existing tests [coc]: https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md [developing]: https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md @@ -120,4 +122,4 @@ Please follow the [Conventional Commits v1.0.0][convcommit]. The commit types mu [new-issue]: https://github.com/fetchai/agents-aea/issues/new/choose [prs]: https://github.com/fetchai/agents-aea/pulls [convcommit]: https://www.conventionalcommits.org/en/v1.0.0/ -[github]: https://github.com/fetchai/agents-aea \ No newline at end of file +[github]: https://github.com/fetchai/agents-aea diff --git a/DEVELOPING.md b/DEVELOPING.md index 86126e48c7..3cdd8d48d4 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -15,97 +15,190 @@ ## Getting the Source -1. Fork the [agents-aea repository][repo]. +1. Fork the [agents-aea repository][repo]. 2. Clone your fork of the agents-aea repository: - ```shell + + ``` shell git clone git@github.com:/agents-aea.git ``` + 3. Define an `upstream` remote pointing back to the main agents-aea repository: - ```shell + + ``` shell git remote add upstream https://github.com/fetchai/agents-aea.git ``` -## Setting up a New Development Environment: +## Setting up a New Development Environment + +1. Ensure you have Python (version `3.8`, `3.9` or `3.10`) and [`poetry`][poetry]. + +2. ``` shell + make new-env + ``` + + This will create a new virtual environment using poetry with the project and all the development dependencies installed. -1. Ensure you have Python (version `3.8`, `3.9` or `3.10`) and [`poetry`][poetry]. -2. make new-env - This will create a new virtual environment using poetry with the project and all the development dependencies installed. -3. poetry shell - To enter the virtual environment. +3. ``` shell + poetry shell + ``` + + To enter the virtual environment. Depending on what you want to do, you might need extra tools on your system: - The project uses [Google Protocol Buffers][protobuf] compiler for message serialization. The compiler's version must match the `protobuf` library installed with the project (see `pyproject.toml`). - The `fetchai/p2p_libp2p` package is partially developed in Go. To make changes, [install Golang][go]. -- To update fingerprint hashes of packages, you will need the [IPFS daemon][ipfs]. +- To update fingerprint hashes of packages, you will need the [IPFS daemon][ipfs]. ## Development ### General code quality checks + To run general code quality checkers, formatters and linters: -- make lint + +- ``` shell + make lint + ``` + Automatically formats your code and sorts your imports, checks your code's quality and scans for any unused code. -- make mypy + +- ``` shell + make mypy + ``` + Statically checks the correctness of the types. -- make pylint + +- ``` shell + make pylint + ``` + Analyses the quality of your code. -- make security + +- ``` shell + make security + ``` + Checks the code for known vulnerabilities and common security issues. -- make clean + +- ``` shell + make clean + ``` + Cleans your development environment and deletes temporary files and directories. + - For the Go parts, we use [`golines`][golines] and [`golangci-lint`][golangci-lint] for linting. ### Updating documentation + We use [`mkdocs`][mkdocs] and [`material-for-mkdocs`][material] for static documentation pages. To make changes to the documentation: -- make docs-live - This starts a live-reloading docs server on localhost which you can access by going to http://127.0.0.1:8000/ in your browser. Making changes to the documentation automatically reloads this page, showing you the latest changes. + +- ``` shell + make docs-live + ``` + + This starts a live-reloading docs server on localhost which you can access by going to in your browser. Making changes to the documentation automatically reloads this page, showing you the latest changes. To create a new documentation page, add a markdown file under `/docs/` and add a reference to this page in `mkdocs.yml` under `nav`. ### Updating API documentation + If you've made changes to the core `aea` package that affects the public API: -- make generate-api-docs + +- ``` shell + make generate-api-docs + ``` + This regenerates the API docs. If pages are added/deleted, or there are changes in their structure, these need to be reflected manually in the `nav` section of `mkdocs.yaml`. ### Updating dependencies -We use [`poetry`][poetry] and `pyproject.toml` to manage the project's dependencies. + +We use [`poetry`][poetry] and `pyproject.toml` to manage the project's dependencies. If you've made any changes to the dependencies (e.g. added/removed dependencies, or updated package version requirements): -- poetry lock + +- ``` shell + poetry lock + ``` + This re-locks the dependencies. Ensure that the `poetry.lock` file is pushed into the repository (by default it is). -- make liccheck + +- ``` shell + make liccheck + ``` + Checks that the licence for the framework is correct, taking into account the licences for all dependencies, their dependencies and so forth. ### Updating packages + If you've made changes to the packages included in the repository (e.g. skills, protocols, connections, contracts): -- make update-package-hashes + +- ``` shell + make update-package-hashes + ``` + Updates the fingerprint hashes of every package in the repository. -- make package-checks - Checks, a) that the package hashes are correct, b) the documentation correctly references the latest packages, and c) runs other correctness checks on packages. + +- ``` shell + make package-checks + ``` + + Checks, a. that the package hashes are correct, b. the documentation correctly references the latest packages, and c) runs other correctness checks on packages. ### Tests + To test the Python part of the project, we use `pytest`. To run the tests: -- make test +- ``` shell + make test + ``` + Runs all the tests. -- make test-plugins + +- ``` shell + make test-plugins + ``` + Runs all plugin tests. -- make dir={SUBMODULE} tdir={TESTMODULE} test-sub + +- ``` shell + make dir={SUBMODULE} tdir={TESTMODULE} test-sub + ``` + Runs the tests for `aea.{SUBMODULE}`. For example, to run the tests for the CLI: `make dir=cli tdir=cli test-sub` -To test the Go parts of the project: -- go test -p 1 -timeout 0 -count 1 -v ./... - from the root directory of a Go package (e.g. `fetchai/p2p_libp2p`) to run the Golang tests. +To test the Go parts of the project: + +- ``` shell + go test -p 1 -timeout 0 -count 1 -v ./... + ``` + + from the root directory of a Go package (e.g. `fetchai/p2p_libp2p`) to run the Golang tests. If you experience installation or build issues, run `go clean -modcache`. ### Miscellaneous checks -- copyright-check + +- ``` shell + copyright-check + ``` + Checks that all files have the correct copyright header (where applicable). -- check-doc-links + +- ``` shell + check-doc-links + ``` + Checks that the links in the documentations are valid and alive. -- make libp2p-diffs + +- ``` shell + make libp2p-diffs + ``` + Checks the libp2p code under `libs` and in the connection packages aren't different. -- make plugin-diffs + +- ``` shell + make plugin-diffs + ``` + Checks the plugin licenses and the codes under `cosmos` and `fetchai` ledger plugins aren't different. ## Contributing diff --git a/HISTORY.md b/HISTORY.md index 7565698b4b..0b5b05173c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,13 +3,16 @@ ## 1.2.4(2022-11-30) Agents: + - Add hello_world skill and agent Docs: + - Update repository documentations - Update installation guide for Raspberry Pis (add a link to prebuilt image for Raspberry Pis) Misc: + - Update the dependencies (protobuf, jsonschema, cosmpy) - Various improvements in the repository structure (e.g. makefile, tox, workflows) - Speed up CI/CD @@ -18,68 +21,81 @@ Misc: ## 1.2.3(2022-11-03) AEA: + - core and development are dependencies updated. - ci improvements - cosmpy updated to 0.6.0 - Small code format improvements and better linting Plugins: + - Small code format improvements - cosmpy updated to 0.6.0 Packages: + - Small code format improvements ## 1.2.2 (2022-10-17) AEA: + - Dependency management switched from pipenv to poetry. - Protocol generator updated to support Unions - Dependencies versions updates: click, mypy, black, ipfshttpclient - Small code format improvements Plugins: + - Update web3 to version 5.31 - Small code format improvements - ipfshttpclient dependency version updated to 0.8.0a2 Packages: + - Protocols regenerated according to the latest protocol generator improvements: Union support - Small code format improvements ## 1.2.1 (2022-07-12) AEA: + - Protocol generator uses int64 instead of int32 - Dependencies versions updates Plugins: + - Upgrades fetchai plugin to use cosmpy>=0.5.0 - Upgrades cosmos plugin to use cosmpy>=0.5.0 Packages: + - Fixes for skills to work with dorado testnet (tx fee adjusted) ## 1.2.0 (2022-05-05) AEA: + - Adds support for Python 3.10 -- Updates protobuf dependency +- Updates protobuf dependency - Updates asyncio dependency - Updates golang modules - Updates many dependencies to their latest versions - Fixes dependency issues Plugins: + - Upgrades fetchai plugin to be compatible with Dorado networks - Upgrades cosmos plugin to be compatible with Dorado networks Packages: + - Adds more logging to the p2p_libp2p packages (vanilla, client, mailbox) - Aries demo updated to cover the full base scenario - Protocols were regenerated with newer protobuf Chores: + - Fixed various tests - Fixed docker container issue in tests - Added automated script to add support for new versions of the Fetchai network @@ -91,23 +107,28 @@ Chores: ## 1.1.1 (2021-12-15) AEA: + - Updates the protocol generator to generate protocols that satisfy linter constraints Plugins: - - aea-cli-ipfs plugin small update + +- aea-cli-ipfs plugin small update Packages: + - Fixes fetchai/p2p_libp2p connection to address a slow DHT lookup problem - Updates protocols with the latest protocol generator - Updates random beacon agent so it produces block data instead of the (now deprecated feature of the test-net) random beacon data Misc + - Bumps go library versions - Various fixes and improvements ## 1.1.0 (2021-10-13) AEA: + - Adds public keys to agent identity and skill context - Adds contract test tool - Adds multiprocess support for task manager @@ -124,27 +145,30 @@ AEA: - Fixes IPFS hash calculation for large files - Fixes protobuf dictionary serializer's uncovered cases and makes it deterministic - Fixes scaffolding of error and decision maker handlers -- Fixes pywin32 problem when checking dependency +- Fixes pywin32 problem when checking dependency - Improves existing testing tools Benchmarks: + - Adds agents construction and decision maker benchmark cases Plugins: + - Upgrades fetchai plugin to use CosmPy instead of CLI calls - Upgrades cosmos plugin to use CosmPy instead of CLI calls -- Upgrades fetchai plugin to use StargateWorld +- Upgrades fetchai plugin to use StargateWorld - Upgrades cosmos plugin to Stargate - Sets the correct maximum Gas for fetch.ai plugin Packages: + - Adds support for Tac to be run against fetchai StargateWorld test-net - Adds more informative error messages to CosmWasm ERC1155 contract - Adds support for atomic swap to CosmWasm ERC1155 contract -- Adds an ACN protocol that formalises ACN communication using the framework's protocol language +- Adds an ACN protocol that formalises ACN communication using the framework's protocol language - Adds `cosm_trade` protocol for preparing atomic swap transactions for cosmos-based networks - Adds https support for server connection -- Adds parametrising of http(s) in soef connection +- Adds parametrising of http(s) in soef connection - Fixes http server content length response problem - Updates Oracle contract to 0.14 - Implements the full ACN spec throughout the ACN packages @@ -156,22 +180,26 @@ Packages: - Multiple fixes and stability improvements for `p2p_libp2p` connections Docs: + - Adds ACN internals documentation - Fixes tutorial for HTTP connection and skill - Multiple additional docs updates - Adds more context to private keys docs Chores: + - Various development features bumped - Bumped Mermaid-JS, for UML diagrams to major version 8 - Applies darglint to the code Examples: + - Adds a unified script for running various versions/modes of Tac ## 1.0.2 (2021-06-03) AEA: + - Bounds versions of dependencies by next major - Fixes incoherent warning message during package loading - Improves various incomprehensible error messages @@ -184,9 +212,11 @@ AEA: - Fixes `aea get-multiaddress` command to consider overrides Plugins: + - Bounds versions of dependencies by next major Packages: + - Updates `p2p_libp2p` connection to use TCP sockets for all platforms - Multiple fixes on `libp2p_node` including better error handling and stream creation - Adds sending queue in `p2p_libp2p` connection to handle sending failures @@ -201,11 +231,13 @@ Packages: - Multiple additional tests and test stability fixes Docs: + - Extends demo docs to include guidance of usage in AEA Manager - Adds short guide on Kubernetes deployment - Multiple additional docs updates Chores: + - Adds `--no-bump` option to `generate_all_protocols` script - Adds script to detect if aea or plugins need bumping - Bumps various development dependencies @@ -213,11 +245,13 @@ Chores: - Adds `darglint` to CI Examples: + - Updates TAC deployment scripts and images ## - (2021-05-05) Packages: + - Adds node watcher to `p2p_libp2p` connection - Improves logging and error handling in `p2p_libp2p` node - Addresses potential overflow issue in `p2p_libp2p` node @@ -231,16 +265,19 @@ Packages: ## 1.0.1 (2021-04-30) AEA: + - Fixes wheels issue for Windows - Fixes password propagation for certificate issuance in `MultiAgentManager` - Improves error message when local registry not present AEALite: + - Adds full protocol support - Adds end-to-end interaction example with AEA (based on `fetchai/fipa` protocol) - Multiple additional tests and test stability fixes Packages: + - Fixes multiple bugs in `ERC1155` version of TAC - Refactors p2p connections for better separation of concerns and maintainability - Integrates aggregation with simple oracle skill @@ -253,11 +290,13 @@ Packages: - Multiple additional tests and test stability fixes Docs: + - Extends car park demo with usage guide for AEA manager - Multiple additional docs updates Examples: -- Adds TAC deployment example + +- Adds TAC deployment example ## 1.0.0 (2021-03-30) @@ -311,7 +350,6 @@ Examples: - Multiple docs updates to fix order of CLI commands with respect to installing dependencies - Multiple additional tests and test stability fixes - ## 0.11.2 (2021-03-17) - Fixes a package import issue @@ -755,7 +793,7 @@ Examples: - Updates connection loading mechanism - Updates all connections for compatibility with new loading mechanism - Extracts multiplexer into its own module -- Implements list all CLI command +- Implements list all CLI command - Updates wallet to split into several crypto stores - Refactors component registry and resources - Extends soef connection functionality @@ -1049,7 +1087,6 @@ Examples: - Increased test coverage - Multiple additional minor fixes and changes - ## 0.1.4 (2019-09-20) - Adds CLI functionality to add connections diff --git a/README.md b/README.md index 82b54bb9cb..d1215ec033 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ Create Autonomous Economic Agents (AEAs) PyPI - Python Version - License + License - License + License
@@ -32,6 +32,7 @@ Create Autonomous Economic Agents (AEAs)

The AEA framework allows you to create **Autonomous Economic Agents**: + - An AEA is an Agent, representing an individual, family, organisation or object (a.k.a. its "owner") in the digital world. It looks after its owner's interests and has their preferences in mind when acting on their behalf. - AEAs are Autonomous; acting with no, or minimal, interference from their owners. - AEAs have a narrow and specific focus: creating Economic value for their owners. @@ -56,7 +57,7 @@ The full documentation, including how to get started, can be found [here][docs]. ## Contributing -All contributions are very welcome! Remember, contribution is not only PRs and code, but any help with docs or helping other developers solve their issues are very appreciated! +All contributions are very welcome! Remember, contribution is not only PRs and code, but any help with docs or helping other developers solve their issues are very appreciated! Read below to learn how you can take part in the AEA project. @@ -90,7 +91,6 @@ If you want to cite this software in a publication, please use the `Cite this re [contributing]: https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md [developing]: https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md [coc]: https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md -[security]: https://github.com/fetchai/agents-aea/blob/main/SECURITY.md [discussion]: https://github.com/fetchai/agents-aea/discussions [issues]: https://github.com/fetchai/agents-aea/issues [github]: https://github.com/fetchai/agents-aea diff --git a/SECURITY.md b/SECURITY.md index d347def524..fa7f245661 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ This document outlines security procedures and general policies for the `aea` pr The following table shows which versions of `aea` are currently being supported with security updates. | Version | Supported | -| --------- | ------------------ | +|-----------|--------------------| | `1.2.x` | :white_check_mark: | | `< 1.2.0` | :x: | diff --git a/aea/connections/scaffold/connection.yaml b/aea/connections/scaffold/connection.yaml index fe4d8b6687..2b76d893f6 100644 --- a/aea/connections/scaffold/connection.yaml +++ b/aea/connections/scaffold/connection.yaml @@ -9,7 +9,7 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: QmaA7o9G1hT3fHtPDq6UYUyS5KY51uDkwMUGUc96odzSCX connection.py: QmWUqCmfD65KqnGjk2XWLDN3KAU32nC6uYgGCvjmSLWi7D - readme.md: Qmdt71SaCCwAG1c24VktXDm4pxgUBiPMg4bWfUTiqorypf + readme.md: QmRFgpKrtPPTJSAEaXoNNKcYFiTAhVFKuiNZdjrjmAw8d1 fingerprint_ignore_patterns: [] connections: [] protocols: [] diff --git a/aea/connections/scaffold/readme.md b/aea/connections/scaffold/readme.md index 6359d72d7b..5b373b777f 100644 --- a/aea/connections/scaffold/readme.md +++ b/aea/connections/scaffold/readme.md @@ -1,5 +1,7 @@ # Scaffold connection + The scaffold connection acts as a boilerplate for a newly created connection. ## Usage + Create a scaffold connection with the `aea scaffold connection {NAME}` command and implement your own connection. diff --git a/benchmark/README.md b/benchmark/README.md index 5cc76cbeb3..a08b684163 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -1,15 +1,19 @@ +# Benchmarks -# Running a benchmark locally: +## Running a benchmark locally First, set permissions: + ``` bash chmod +x /benchmark/checks/run_benchmark.sh ``` Then, run: + ``` bash ./benchmark/checks/run_benchmark.sh ``` + or to save to file: ``` bash @@ -18,10 +22,10 @@ or to save to file: The benchmark will use the locally installed AEA version! - -# Deploying a benchmark run and serving results: +## Deploying a benchmark run and serving results First remove any old configuration maps and create a new one: + ``` bash kubectl delete configmap run-benchmark kubectl create configmap run-benchmark --from-file=run_from_branch.sh @@ -51,11 +55,14 @@ List pods: kubectl get pod -o wide ``` -To access NGINX (wait for status: ` `): +To access NGINX (wait for status: ``): + ``` bash kubectl port-forward NODE_NAME 8000:80 ``` + then + ``` bash curl localhost:8000 | tee results.txt -``` \ No newline at end of file +``` diff --git a/deploy-image/README.md b/deploy-image/README.md index 896e85a69f..7c6de6d899 100644 --- a/deploy-image/README.md +++ b/deploy-image/README.md @@ -23,14 +23,14 @@ Second, review the `entrypoint.sh` script to make sure you supply the agent with Importantly, do not add any private keys during the build step! Third, create a local `.env` file with the relevant environment variables: -``` + +``` bash AGENT_PRIV_KEY=hex_key_here CONNECTION_PRIV_KEY=hex_key_here ``` Finally, if required, modify the `Dockerfile` to expose any ports needed by the AEA. (The default example does not require this.) - ### Build the image ``` bash @@ -47,5 +47,4 @@ To stop, use `docker ps` to find the container id and then `docker stop CONTAINE ## Advanced usage and comments -- The above approach implies that key files remain in the container. To avoid this, a static volume can be mounted with the key files in it (https://docs.docker.com/get-started/06_bind_mounts/). - +- The above approach implies that key files remain in the container. To avoid this, a static volume can be mounted with the key files in it (). diff --git a/develop-image/README.md b/develop-image/README.md index 8c2b571355..f562b3f1a1 100644 --- a/develop-image/README.md +++ b/develop-image/README.md @@ -4,110 +4,132 @@ All the commands must be executed from the parent directory, if not stated other ## Build - ./develop-image/scripts/docker-build-img.sh -t fetchai/aea-deploy:latest -- - +``` bash +./develop-image/scripts/docker-build-img.sh -t fetchai/aea-deploy:latest -- +``` To pass immediate parameters to the `docker build` command: - ./develop-image/scripts/docker-build-img.sh arg1 arg2 -- +``` bash +./develop-image/scripts/docker-build-img.sh arg1 arg2 -- +``` E.g.: - ./develop-image/scripts/docker-build-img.sh --squash --cpus 4 --compress -- - +``` bash +./develop-image/scripts/docker-build-img.sh --squash --cpus 4 --compress -- +``` ## Run - ./develop-image/scripts/docker-run.sh -- /bin/bash - -As before, to pass parameters to the `docker run` command: +``` bash +./develop-image/scripts/docker-run.sh -- /bin/bash +``` - ./develop-image/scripts/docker-run.sh -p 8080:80 -- /bin/bash +As before, to pass parameters to the `docker run` command: +``` bash +./develop-image/scripts/docker-run.sh -p 8080:80 -- /bin/bash +``` ## Publish -First, be sure you tagged the image with the `latest` tag: +First, be sure you tagged the image with the `latest` tag: - docker tag fetchai/aea-develop: fetchai/aea-develop:latest +``` bash +docker tag fetchai/aea-develop: fetchai/aea-develop:latest +``` Then, publish the images. First, the `fetchai/aea-develop:` - ./develop-image/scripts/docker-publish-img.sh +``` bash +./develop-image/scripts/docker-publish-img.sh +``` And then, the `fetchai/aea-develop:latest` image: - In `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=fetchai/aea-develop:latest` -- Run the publish command again: +- Run the publish command again: - ./develop-image/scripts/docker-publish-img.sh + ``` bash + ./develop-image/scripts/docker-publish-img.sh + ``` -# Publish to k8s +### Publish to k8s Switch the context: -``` bash + +``` shell kubectx sandbox ``` List pods in cluster: -``` bash + +``` shell kubectl get pods ``` Optionally, create new namespace: -``` bash + +``` shell kubectl create namespace aea-research ``` Ensure right namespace is used: -``` bash + +``` shell kubens aea-research ``` + Choose namespace in cluster: -``` bash + +``` shell kubens aea-research ``` + To enter selected namespace: -``` bash + +``` shell kubens ``` From the `develop-image` folder run: -``` bash + +``` shell skaffold run -p sandbox ``` SSH into a new image: -``` bash + +``` shell kubectl run --generator=run-pod/v1 -it debian --image=debian -- bash ``` -# Dedicated node pool for benchmarking agents +## Dedicated node pool for benchmarking agents - -## Setup and tear down +### Setup and tear down To create the node pool -``` bash + +``` shell gcloud container node-pools create agent-test-pool --cluster sandbox --project fetch-ai-sandbox --node-taints dedicated=agent:NoSchedule --machine-type=n1-standard-4 --num-nodes=1 --enable-autoscaling --node-labels=type=agent-test --max-nodes=1 --min-nodes=0 ``` -To remove the node pool -``` bash + +To remove the node pool + +``` shell gcloud container node-pools delete agent-test-pool --cluster sandbox --project fetch-ai-sandbox ``` -## Usage +### Usage List pods -``` bash +``` shell kubectl get pod -o wide ``` -``` bash +``` shell kubectl exec -it NAME -- bash ``` - - - diff --git a/docs/12-factor.md b/docs/12-factor.md index cf86a51074..c9f20a30b2 100644 --- a/docs/12-factor.md +++ b/docs/12-factor.md @@ -1,228 +1,131 @@ -# Relationship with the Twelve-Factor App methodology. +# Relationship with the Twelve-Factor App Methodology -The
Twelve-Factor App is -a set of best practices to build modern -web applications, or *software-as-a-service*. +The Twelve-Factor App is a set of best practices to build modern web applications, or *software-as-a-service*. -In this section, we will see how the AEA framework -facilitates the achievement of those -in the development, release and deployment -phases of an AEA project. +In this section, we will see how the AEA framework facilitates the achievement of those in the development, release and deployment phases of an AEA project. -Note that an AEA instance, as a software agent, -can be seen as a more general case of a web app, -as it not only shows reactive behaviour, -but it is also *proactive*, depending -on the goals assigned to it. +Note that an AEA instance, as a software agent, can be seen as a more general case of a web app, as it not only shows reactive behaviour, but it is also *proactive*, depending on the goals assigned to it. ## Codebase -> One codebase tracked in revision control, many deploys +!!! info "Factor 1" + One codebase tracked in revision control, many deploys Support: Excellent -The framework does not impose any particular requirement -or convention on the type of version control -software to be used to store an AEA project. +The framework does not impose any particular requirement or convention on the type of version control software to be used to store an AEA project. ## Dependencies -> Explicitly declare and isolate dependencies +!!! info "Factor 2" + Explicitly declare and isolate dependencies Support: Good -The framework allows an AEA project to explicitly declare -the AEA package dependencies, and the PyPI dependencies -needed to proper working. - -However, it does not provide built-in support -for checking platform-specific dependencies, -e.g. specific Python version, or needed system-wide available libraries. -Nevertheless, this can be indirectly achieved -by means of build scripts called on `aea build`, -which can do the checks manually according to the specific -requirements of the project. +The framework allows an AEA project to explicitly declare the AEA package dependencies, and the PyPI dependencies needed to proper working. +However, it does not provide built-in support for checking platform-specific dependencies, e.g. specific Python version, or needed system-wide available libraries. Nevertheless, this can be indirectly achieved by means of build scripts called on `aea build`, which can do the checks manually according to the specific requirements of the project. ## Configuration -> Store configuration in the environment +!!! info "Factor 3" + Store configuration in the environment Support: Good -An AEA project can specify an environment configuration -file `.env`, stored in the project root, -that the framework will use to update -environment variables before the execution of the AEA instance. +An AEA project can specify an environment configuration file `.env`, stored in the project root, that the framework will use to update environment variables before the execution of the AEA instance. -The CLI tool command `aea run` accepts the option `--env PATH` -to change the default configuration file. -However, the framework does not -automatically switch between, nor allows to add, -different types of configuration files, one for each -deployment step (e.g. development, staging, production), -without using the `--env` option. +The CLI tool command `aea run` accepts the option `--env PATH` to change the default configuration file. However, the framework does not automatically switch between, nor allows to add, different types of configuration files, one for each deployment step (e.g. development, staging, production), without using the `--env` option. -## Backing services +## Backing Services -> Treat backing services as attached resources +!!! info "Factor 4" + Treat backing services as attached resources Support: Good -A persistent storage of an AEA can be seen -as an attached resource in the 12-factor terminology. -The default storage is SQLite, but the interface -`AbstractStorageBacked` allows to implement -specific wrappers to other backing services, -without changing the AEA project code. -The support for integrating -different storage back-end implementations in an AEA project -by using a plug-in mechanism is currently missing. - -Moreover, new adapters to backing services -can be implemented as custom connections, which -can connect to attached resources. -This does not usually requires a change -in the skill code, especially -in the case when a custom protocol -can abstract the details of the interaction with -the specific resource. +A persistent storage of an AEA can be seen as an attached resource in the 12-factor terminology. The default storage is SQLite, but the interface `AbstractStorageBacked` allows to implement specific wrappers to other backing services, without changing the AEA project code. The support for integrating different storage back-end implementations in an AEA project by using a plug-in mechanism is currently missing. +Moreover, new adapters to backing services can be implemented as custom connections, which can connect to attached resources. This does not usually require a change in the skill code, especially in the case when a custom protocol can abstract the details of the interaction with the specific resource. -## Build, release, run +## Build, Release, Run -> Strictly separate build and run stages +!!! info "Factor 5" + Strictly separate build and run stages Support: Excellent -The phases of build, release and run -of an AEA project are neatly separated, -both for programmatic usage -and through the usage of the CLI tool, -as each of them corresponds to different subcommands. +The phases of build, release and run of an AEA project are neatly separated, both for programmatic usage and through the usage of the CLI tool, as each of them corresponds to different subcommands. ## Processes -> Execute the app as one or more stateless processes +!!! info "Factor 6" + Execute the app as one or more stateless processes Support: Excellent -Whether the process is stateless depends on the specific AEA. -No strict enforcement is applied by the framework. -Moreover, dialogue histories can be stored -with persistent storage, if enabled by the developer. +Whether the process is stateless depends on the specific AEA. No strict enforcement is applied by the framework. Moreover, dialogue histories can be stored with persistent storage, if enabled by the developer. -## Port binding +## Port Binding -> Export services via port binding +!!! info "Factor 7" + Export services via port binding Support: Excellent -An AEA project may not need to expose services via HTTP. -This property depends on the specific choices of -the project developer, and the framework does not -impose any restriction. +An AEA project may not need to expose services via HTTP. This property depends on the specific choices of the project developer, and the framework does not impose any restriction. -One of the provided package, the "HTTP server" connection, -relies on `aiohttp`, which makes the connection completely -self-contained—therefore, it satisfies the requirement. +One of the provided package, the "HTTP server" connection, relies on `aiohttp`, which makes the connection completely self-contained—therefore, it satisfies the requirement. -Another relevant example is the ACN node, which -exposes its service to the Libp2p AEA connection +Another relevant example is the ACN node, which exposes its service to the Libp2p AEA connection ## Concurrency -> Scale out via the process model +!!! info "Factor 8" + Scale out via the process model Support: Not Supported -The framework does not easily allow to scale up an -AEA instance with multiple processes, -as it is bound to a process. -However, note that its attached services -can live in a different process, which could -give better scalability. +The framework does not easily allow to scale up an AEA instance with multiple processes, as it is bound to a process. However, note that its attached services can live in a different process, which could give better scalability. ## Disposability -> Maximize robustness with fast startup and graceful shutdown +!!! info "Factor 9" + Maximize robustness with fast startup and graceful shutdown Support: Good -Disposability of an AEA instance -depends, in general, on the AEA itself; -whether the connections can be quickly -connected and disconnected, -whether skills can be easily torn -down or not, whether other resources -can be detached successfully like -the persistent storage, -just to name a few examples. - -There has been put some effort into -reducing startup time, and to ensure -that a graceful shut down can happen -when the process receives a SIGTERM -under normal circumstances, -but robustness cannot be ensured for individual components, -as it depends on their implementation. - -Additionally, -the framework does provide some features to -control some aspects of AEA disposability, -e.g. the possibility to change -execution timeout for behaviours or handlers, -implementation of an effective exception propagation -from a component code to the main agent loop. - -## Dev/prod parity - -> Keep development, staging, and production as similar as possible +Disposability of an AEA instance depends, in general, on the AEA itself; whether the connections can be quickly connected and disconnected, whether skills can be easily torn down or not, whether other resources can be detached successfully like the persistent storage, just to name a few examples. + +There has been put some effort into reducing startup time, and to ensure that a graceful shut-down can happen when the process receives a SIGTERM under normal circumstances, but robustness cannot be ensured for individual components, as it depends on their implementation. + +Additionally, the framework does provide some features to control some aspects of AEA disposability, e.g. the possibility to change execution timeout for behaviours or handlers, implementation of an effective exception propagation from a component code to the main agent loop. + +## Dev/Prod Parity + +!!! info "Factor 10" + Keep development, staging, and production as similar as possible Support: Good -This aspect mostly depends on the specific AEA project, -and the framework does not impose particular restrictions -on best deployment practices (e.g. continuous integration, -same backing services between development -and production stages). +This aspect mostly depends on the specific AEA project, and the framework does not impose particular restrictions on best deployment practices (e.g. continuous integration, same backing services between development and production stages). ## Logs -> Treat logs as event streams +!!! info "Factor 11" + Treat logs as event streams Support: Excellent -Thanks to the seamless integration with the -Python standard library `logging`, -the developer or the deployer has great control -on the routing and filtering of log records. -The behaviour can be changed by providing -a proper configuration in the AEA project configuration file, -according to the standard library specification. -The framework facilitates this -by creating ad-hoc logger names that can be used -for finer-grained routing or filtering; -for example, each AEA instance uses its own -logging namespace to send logging events. -Integration with other log handlers -is delegated to extensions of the standard library, -hence not necessarily coupled with the AEA framework. - -## Admin processes - -> Run admin/management tasks as one-off processes +Thanks to the seamless integration with the Python standard library `logging`, the developer or the deployer has great control on the routing and filtering of log records. The behaviour can be changed by providing a proper configuration in the AEA project configuration file, according to the standard library specification. The framework facilitates this by creating ad-hoc logger names that can be used for finer-grained routing or filtering; for example, each AEA instance uses its own logging namespace to send logging events. Integration with other log handlers is delegated to extensions of the standard library, hence not necessarily coupled with the AEA framework. + +## Admin Processes + +!!! info "Factor 12" + Run admin/management tasks as one-off processes Support: Good -The CLI tool provides commands to -manage private keys and ledger related operations, and -it is possible to extend it with a plugin to manage databases of AEA's persistent storage -for maintenance operations. - -Moreover, the Python programming language -makes it easy to run one-off scripts or running a console -(also known as REPL) to do management tasks. -It follows that it is also easy to ensure -dependency isolation and same configurations -of the running AEA instance. +The CLI tool provides commands to manage private keys and ledger related operations, and it is possible to extend it with a plugin to manage databases of AEA's persistent storage for maintenance operations. + +Moreover, the Python programming language makes it easy to run one-off scripts or running a console (also known as REPL) to do management tasks. It follows that it is also easy to ensure dependency isolation and same configurations of the running AEA instance. diff --git a/docs/acn-internals.md b/docs/acn-internals.md index 5d16d212d2..41bd744edf 100644 --- a/docs/acn-internals.md +++ b/docs/acn-internals.md @@ -1,79 +1,50 @@ +# ACN Internals -The aim of this document is to describe at a high-level -the main implementation of the Agent Communication Network (ACN). +The aim of this document is to describe at a high-level the main implementation of the Agent Communication Network (ACN). In particular: -- the `libp2p_node` Golang library; -- the `p2p_libp2p` AEA connection, written in Python, that implements the _direct connection_ with an ACN peer; -- the `p2p_libp2p_client` AEA connection, written in Python, which implements the _delegate connection_ with an ACN peer. +- the `libp2p_node` Golang library; +- the `p2p_libp2p` AEA connection written in Python, that implements the **direct connection** with an ACN peer; +- the `p2p_libp2p_client` AEA connection written in Python, which implements the **delegate connection** with an ACN peer. -It is assumed the reader already knows what is the ACN and -its purposes; if not, we suggest reading this page. +It is assumed the reader already knows what is the ACN and its purposes; if not, we suggest reading this page. This documentation page is structured as follows: -- Firstly, the ACN protocol is described: all the messages -and data structures involved, as well as some example of interaction -protocol with these messages; -- Then, it is explained how a peer can join an existing ACN network, -and the message exchange involved; -- It follows the description of the journey of an envelope - in the ACN network: from the agent connection to its contact - peer, between ACN peers, and then from the contact peer of the - destination agent to the target agent; -- The following section describes the functionalities - of the AEA connections that allow to communicate through - the ACN: `fetchai/p2p_libp2p` and `fetchia/p2p_libp2p_delegate`; -- The documentation ends with a section of known issues and limitations - of the current implementation. +- Firstly, the ACN protocol is described: all the messages and data structures involved, as well as some example of interaction protocol with these messages; +- Then, it is explained how a peer can join an existing ACN network, and the message exchange involved; +- It follows the description of the journey of an envelope in the ACN network: from the agent connection to its contact peer, between ACN peers, and then from the contact peer of the destination agent to the target agent; +- The following section describes the functionalities of the AEA connections that allow to communicate through the ACN: `fetchai/p2p_libp2p` and `fetchia/p2p_libp2p_delegate`; +- The documentation ends with a section of known issues and limitations of the current implementation. ## Messages and Data Structures -At the foundation of the ACN there is the _ACN protocol_. -The protocol messages and the reply structure are generated from this -protocol specification, -using the protocol generator. -Therefore, it uses Protocol Buffers -as a serialization format, -and the definition of the data structures involved is defined in this -`.proto` file. +At the foundation of the ACN there is the _ACN protocol_. The protocol messages and the reply structure are generated from this protocol specification, using the protocol generator. Therefore, it uses Protocol Buffers as a serialization format, and the definition of the data structures involved is defined in this `.proto` file. -To know more about the protocol generator, refer to the relevant -section of the documentation: -Protocol Generator. +To know more about the protocol generator, refer to the relevant section of the documentation: Protocol Generator. ### Agent Record -An _agent record_ is a data structure containing information about an -agent and its Proof-of-Representation (PoR) to be used by a peer for other peers. -This data structure is used as a payload in other ACN messages (see below). +An _agent record_ is a data structure containing information about an agent and its Proof-of-Representation (PoR) to be used by a peer for other peers. This data structure is used as a payload in other ACN messages (see below). The `AgentRecord` data structure contains the following fields: - `service_id`: a string describing the service identifier. -- `ledger_id`: a string. It is the identifier of the ledger - this agent record is associated to. - Currently, the allowed values are: +- `ledger_id`: a string. It is the identifier of the ledger this agent record is associated to. Currently, the allowed values are: - `fetchai`, the identifier for the Fetch.AI ledger; - `ethereum`, the identifier for the Ethereum ledger; - `cosmos`, the identifier for the Cosmos ledger; -- `address`: a string. It is the public key of a public-private key pair. - It is used as an identifier for routing purposes. +- `address`: a string. It is the public key of a public-private key pair. It is used as an identifier for routing purposes. - `public_key`: a string. The representative's public key. Used in case of (PoR). - `peer_public_key`: a string. The public key of the peer. - `signature`: a string. The signature for PoR. -- `not_before`: a string. Specify the lower bound for certificate validity. - If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0 -- `not_after`: a string. Specify the upper bound for certificate validity. - If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0. - +- `not_before`: a string. Specify the lower bound for certificate validity. If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0 +- `not_after`: a string. Specify the upper bound for certificate validity. If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0. ### ACN Message -Entities in the ACN (i.e. either agents or peers) exchange _ACN messages_. -An ACN message contains a `payload` field, -which is the actual content of the message. +Entities in the ACN (i.e. either agents or peers) exchange _ACN messages_. An ACN message contains a `payload` field, which is the actual content of the message. There are different types of payloads: @@ -85,35 +56,24 @@ There are different types of payloads: ### Status -The `Status` payload is used as a response message to inform -the sender about the handling of certain requests. -The payload contains: +The `Status` payload is used as a response message to inform the sender about the handling of certain requests. The payload contains: -- the `status_code`, a positive integer among the ones in the - Protobuf file. +- the `status_code`, a positive integer among the ones in the Protobuf file. - a list of error messages (string). -A status code `0`, identified as `SUCCESS`, -means that the request has been processed successfully. -Status codes greater than `0` can be: +A status code `0`, identified as `SUCCESS`, means that the request has been processed successfully. Status codes greater than `0` can be: - Generic errors: errors that occur under generic circumstances. - - `ERROR_UNSUPPORTED_VERSION`, with integer value `1`: the receiver of the message - does not support the protocol version of the sender; - - `ERROR_UNEXPECTED_PAYLOAD`, with integer value `2`: the payload could not be - deserialised on the receiver side; + - `ERROR_UNSUPPORTED_VERSION`, with integer value `1`: the receiver of the message does not support the protocol version of the sender; + - `ERROR_UNEXPECTED_PAYLOAD`, with integer value `2`: the payload could not be deserialized on the receiver side; - `ERROR_GENERIC`, with integer value `3`: an internal error; - - `ERROR_SERIALIZATION`, with integer value `4`: a serialization error occurred - on the receiving end; + - `ERROR_SERIALIZATION`, with integer value `4`: a serialization error occurred on the receiving end; -- Register errors: errors that occur during agent registration operations in the ACN. +- Register errors: errors that occur during agent registration operations in the ACN. - - `ERROR_WRONG_AGENT_ADDRESS`, with integer value `10`: - the PoR by a peer from another peer does not match the destination address of - the envelope to be routed by the receiving peer. - - `ERROR_WRONG_PUBLIC_KEY`, with integer value `11`: the - representative peer public key does not match the one in the agent record; + - `ERROR_WRONG_AGENT_ADDRESS`, with integer value `10`: the PoR by a peer from another peer does not match the destination address of the envelope to be routed by the receiving peer. + - `ERROR_WRONG_PUBLIC_KEY`, with integer value `11`: the representative peer public key does not match the one in the agent record; - `ERROR_INVALID_PROOF`, with integer value `12`: the signature is invalid; - `ERROR_UNSUPPORTED_LEDGER`, with integer value `13`: the ledger of the PoR is not supported by the peer; @@ -122,26 +82,21 @@ Status codes greater than `0` can be: - `ERROR_UNKNOWN_AGENT_ADDRESS`, with integer value `20`: the requested agent address has not been found in the local DHT of the peer; - `ERROR_AGENT_NOT_READY`, with integer value `21`: the agent is not ready for envelope delivery. - ### Register -The `Register` payload is used to request a peer to register an agent among his known ones. -The payload contains the field `record`, which is an instance of `AgentRecord`. +The `Register` payload is used to request a peer to register an agent among his known ones. The payload contains the field `record`, which is an instance of `AgentRecord`. ### LookupRequest -The `LookupRequest` payload is sent between peer to look-up addresses in the Distributed Hash Table (DHT). -It contains the agent address (a string) that the sender needs to correctly route an envelope. +The `LookupRequest` payload is sent between peer to look-up addresses in the Distributed Hash Table (DHT). It contains the agent address (a string) that the sender needs to correctly route an envelope. ### LookupResponse -The `LookupResponse` payload is the response sent by a peer that received a `LookupRequest`. -It contains the `AgentRecord` associated to the requested address. +The `LookupResponse` payload is the response sent by a peer that received a `LookupRequest`. It contains the `AgentRecord` associated to the requested address. ### AeaEnvelope -The `AeaEnvelope` payload contains the envelope sent by an agent and to be delivered to another agent. -It contains: +The `AeaEnvelope` payload contains the envelope sent by an agent and to be delivered to another agent. It contains: - `envelope`: the envelope to be forwarded, in byte representation; - an `AgentRecord` (see above). @@ -156,10 +111,9 @@ The ACN protocol specifies three different possible interactions: ### "Registration" Interaction -The registration interaction is used by delegate agents or relayed peers -to register themselves to another peer. +The registration interaction is used by delegate agents or relayed peers to register themselves to another peer. -
+``` mermaid sequenceDiagram participant Agent/RelayedPeer participant Peer @@ -176,14 +130,13 @@ to register themselves to another peer. else unsupported ledger Peer->>Agent/RelayedPeer: Status(ERROR_UNSUPPORTED_LEDGER) end -
+``` ### "Look-up" Interaction -The look-up interaction is used by a peer -to request information to another peer about an agent address. +The look-up interaction is used by a peer to request information to another peer about an agent address. -
+``` mermaid sequenceDiagram participant Peer1 participant Peer2 @@ -193,15 +146,13 @@ to request information to another peer about an agent address. else unknown agent address Peer2->>Peer1: Status(ERROR_UNKNOWN_AGENT_ADDRESS) end -
- +``` ### "Routing" Interaction -The routing interaction is used by agents -and peers to route the envelope through the ACN. +The routing interaction is used by agents and peers to route the envelope through the ACN. -
+``` mermaid sequenceDiagram participant Peer1 participant Peer2 @@ -214,41 +165,24 @@ and peers to route the envelope through the ACN. else PoR errors note over Peer1,Peer2: see above end - -
- +``` ## Joining the ACN network -When an ACN peer wants to join the network, it has -to start from a list of _bootstrap peers_, i.e. -a list of ACN peers to connect with (at least one). +When an ACN peer wants to join the network, it has to start from a list of _bootstrap peers_, i.e. a list of ACN peers to connect with (at least one). Each node handles four different types of libp2p streams: -- the _notification stream_, identified by the URI `/aea-notif/`: - this stream is used by new peers to notify their existence to -- the _address stream_, identified by the URI `/aea-address/`: - used to send look-up requests and look-up responses; -- the _envelope stream_, identified by the URI `/aea/`: - used to forward and to receive ACN envelopes; -- the _register relay stream_, identified by the URI `/aea-register/`: - this is to receive messages from clients that want to register their agents addresses; - this peer, and then it can register their addresses. - -To begin with, the node process initializes -the transport connections with the bootstrap peers, -the local copy of the Kademlia Distributed -Hash Table (DHT), -the persistent storage for agent records, -and performs other non-functional operations -like setting up the Prometheus monitoring system. -Optionally, can also start listening for relay connections -and delegate connections. +- the _notification stream_, identified by the URI `/aea-notif/`: this stream is used by new peers to notify their existence to +- the _address stream_, identified by the URI `/aea-address/`: used to send look-up requests and look-up responses; +- the _envelope stream_, identified by the URI `/aea/`: used to forward and to receive ACN envelopes; +- the _register relay stream_, identified by the URI `/aea-register/`: this is to receive messages from clients that want to register their agents addresses; this peer, and then it can register their addresses. + +To begin with, the node process initializes the transport connections with the bootstrap peers, the local copy of the Kademlia Distributed Hash Table (DHT), the persistent storage for agent records, and performs other non-functional operations like setting up the Prometheus monitoring system. Optionally, can also start listening for relay connections and delegate connections. Then, it sets up the notification stream and notifies the bootstrap peers (if any). -
+``` mermaid sequenceDiagram participant Peer1 participant Peer2 @@ -269,18 +203,15 @@ Then, it sets up the notification stream and notifies the bootstrap peers (if an Peer1->>Peer3: register address end note over Peer1: set up:
- address stream
- envelope stream
- register relay stream -
+``` -### Relay connections +### Relay Connections -If the ACN node is configured to run the relay service, -it sets up the register relay stream, waiting for registration -requests. +If the ACN node is configured to run the relay service, it sets up the register relay stream, waiting for registration requests. -The following diagram shows an example of the message exchanged -during a registration request: +The following diagram shows an example of the message exchanged during a registration request: -
+``` mermaid sequenceDiagram participant Agent participant Peer @@ -303,58 +234,33 @@ during a registration request: Peer->>Agent: Status(SUCCESS) note over Peer: announce agent address
to other peers end -
+``` -### Delegate connections +### Delegate Connections -If the ACN node is configured to run the delegate service, -it start listening from a TCP socket at a configurable URI. +If the ACN node is configured to run the delegate service, it starts listening from a TCP socket at a configurable URI. -To see a diagram of the message exchanged -during a registration request read -this section. +To see a diagram of the message exchanged during a registration request read this section. -## ACN transport +## ACN Transport -In the following sections, we describe the main three steps of the routing -of an envelope through the ACN: +In the following sections, we describe the main three steps of the routing of an envelope through the ACN: -- _ACN entrance_: when an envelope sent by an agent enters - the peer-to-peer network via the peer the agent is connected to - i.e. agent-to-peer communication; -- _ACN routing_: when an envelope gets routed through the peer-to-peer network, - i.e. peer-to-peer communication; -- _ACN exit_: when an envelope gets delivered to the receiving agent - through its representative peer, i.e. peer-to-agent communication. +- _ACN entrance_: when an envelope sent by an agent enters the peer-to-peer network via the peer the agent is connected to i.e. agent-to-peer communication; +- _ACN routing_: when an envelope gets routed through the peer-to-peer network, i.e. peer-to-peer communication; +- _ACN exit_: when an envelope gets delivered to the receiving agent through its representative peer, i.e. peer-to-agent communication. - ### ACN Envelope Entrance: Agent -> Peer -In this section, we will describe the interaction protocols between agents and peers -for the messages sent by the agent to the ACN network; -in particular, the communication from the contact peer of an agent to the agent. +In this section, we will describe the interaction protocols between agents and peers for the messages sent by the agent to the ACN network; in particular, the communication from the contact peer of an agent to the agent. The following diagram explains the exchange of messages on entering an envelope in the ACN. -In the case of _direct connection_, -`Agent` is a Python process, whereas `Peer` is in a separate (Golang) process. -The logic of the Python Agent client is implemented in -the AEA connection `fetchai/p2p_libp2p` -The communication between `Agent` and `Peer` is done through -an OS pipe for Inter-Process Communication (IPC) between the AEA's process and the libp2p node process; -then, the message gets enqueued to an output queue by an input coroutine. -Finally, the envelope ends up in an output queue, -which is processed by an output coroutine and routed to the next peer. - -In the case of _delegate connection_, -the message exchange is very similar; however, instead of using -pipes, the communication is done through the network, i.e. TCP, -with a peer which has the delegate service enabled. -The logic of the `Agent` client connected with a delegate connection -is implemented in -the AEA connection `fetchai/p2p_libp2p_client` - -
+In the case of _direct connection_, `Agent` is a Python process, whereas `Peer` is in a separate (Golang) process. The logic of the Python Agent client is implemented in the AEA connection `fetchai/p2p_libp2p` The communication between `Agent` and `Peer` is done through an OS pipe for Inter-Process Communication (IPC) between the AEA's process and the libp2p node process; then, the message gets enqueued to an output queue by an input coroutine. Finally, the envelope ends up in an output queue, which is processed by an output coroutine and routed to the next peer. + +In the case of _delegate connection_, the message exchange is very similar; however, instead of using pipes, the communication is done through the network, i.e. TCP, with a peer which has the delegate service enabled. The logic of the `Agent` client connected with a delegate connection is implemented in the AEA connection `fetchai/p2p_libp2p_client` + +``` mermaid sequenceDiagram participant Agent participant Peer @@ -378,82 +284,65 @@ the - sequenceDiagram - participant Agent - participant Peer1 - participant Peer2 - Agent->>Peer1: AeaEnvelope - alt envelope sender not registered locally - note over Peer1: stop, log error - end -
- -2) the `target` of the envelope is - the local agent connected to the peer: - the envelope is routed to the local agent. - -
- sequenceDiagram - participant Agent - participant Peer1 - participant Peer2 - Agent->>Peer1: AeaEnvelope - alt target == peer1.my_agent - note over Peer1: envelope destinated
to local agent,
not routing - loop agent not ready - note over Peer1: sleep for 100ms + ``` mermaid + sequenceDiagram + participant Agent + participant Peer1 + participant Peer2 + Agent->>Peer1: AeaEnvelope + alt envelope sender not registered locally + note over Peer1: stop, log error end - Peer1->>Agent: AeaEnvelope - Agent->>Peer1: Status(Success) - end -
- -3) the `target` is a delegate client. - Send the envelope via TCP. - -
- sequenceDiagram - participant Delegate - participant Peer1 - participant Peer2 - Delegate->>Peer1: AeaEnvelope - alt destination is a delegate - note over Peer1: send envelope
to delegate via TCP - Peer1->>Delegate: AeaEnvelope - Delegate->>Peer1: Status(Success) - end -
+ ``` + +2. the `target` of the envelope is the local agent connected to the peer: the envelope is routed to the local agent. + + ``` mermaid + sequenceDiagram + participant Agent + participant Peer1 + participant Peer2 + Agent->>Peer1: AeaEnvelope + alt target == peer1.my_agent + note over Peer1: envelope destinated
to local agent,
not routing + loop agent not ready + note over Peer1: sleep for 100ms + end + Peer1->>Agent: AeaEnvelope + Agent->>Peer1: Status(Success) + end + ``` + +3. the `target` is a delegate client. Send the envelope via TCP. + + ``` mermaid + sequenceDiagram + participant Delegate + participant Peer1 + participant Peer2 + Delegate->>Peer1: AeaEnvelope + alt destination is a delegate + note over Peer1: send envelope
to delegate via TCP + Peer1->>Delegate: AeaEnvelope + Delegate->>Peer1: Status(Success) + end + ``` -4) Otherwise, look up the local DHT. - If an entry is found, use it; - otherwise, send a look-up request - to connected peers. +4. Otherwise, look up the local DHT. If an entry is found, use it; otherwise, send a look-up request to connected peers. -
+``` mermaid sequenceDiagram participant Agent participant Peer1 @@ -474,13 +363,11 @@ we may have different scenario: end end note over Peer1,Peer2: Now Peer1 knows the contact peer
is PeerX -
- -In particular, when a peer receives a LookupRequest message, -it does the following: +``` +In particular, when a peer receives a LookupRequest message, it does the following: -
+``` mermaid sequenceDiagram participant Peer1 participant Peer2 @@ -500,13 +387,11 @@ it does the following: Peer2->>Peer1:Status(UNKNOWN_AGENT_ADDRESS) end end -
+``` -Let `Peer3` the contact peer of the recipient of the envelope. -The following diagram shows how the contact peer of the -envelope recipient handles the incoming envelope: +Let `Peer3` the contact peer of the recipient of the envelope. The following diagram shows how the contact peer of the envelope recipient handles the incoming envelope: -
+``` mermaid sequenceDiagram participant Peer1 participant Peer3 @@ -542,20 +427,15 @@ envelope recipient handles the incoming envelope: Peer3->>Peer1: Status(ERROR_UNKNOWN_AGENT_ADDRESS) end end -
+``` ### ACN Envelope Exit: Peer -> Agent -The following diagram explains the exchange of messages on exiting an envelope in the ACN. -That is, the communication from the contact peer of an agent to the agent. +The following diagram explains the exchange of messages on exiting an envelope in the ACN. That is, the communication from the contact peer of an agent to the agent. -The same message exchange is done -both in the case of direct connection and -delegate connection, -similarly for what has been described for the envelope entrance -
(see above). +The same message exchange is done both in the case of direct connection and delegate connection, similarly for what has been described for the envelope entrance (see above). -
+``` mermaid sequenceDiagram participant Agent participant Peer @@ -571,43 +451,26 @@ similarly for what has been described for the envelope entrance else wrong payload Agent->>Peer: Status(GENERIC_ERROR) end -
+``` ## Connect your AEA to the ACN -To connect the AEA to the ACN network, -there are two AEA connections available: +To connect the AEA to the ACN network, there are two AEA connections available: -- the `fetchai/p2p_libp2p`, that implements - a direct connection, and -- the `fetchai/p2p_libp2p_delegate` connection, - that implements the delegate connection. +- the `fetchai/p2p_libp2p`, that implements a direct connection, and +- the `fetchai/p2p_libp2p_delegate` connection, that implements the delegate connection. -For more information on the AEA connection package type, -refer to this guide. +For more information on the AEA connection package type, refer to this guide. -### The `fetchai/p2p_libp2p` connection +### The `fetchai/p2p_libp2p` Connection -The source code of the `fetchai/p2p_libp2p` connection -can be downloaded from -the AEA Registry, -or from the main AEA framework repository. +The source code of the `fetchai/p2p_libp2p` connection can be downloaded from the AEA Registry, or from the main AEA framework repository. -The package provides the connection class `P2PLibp2pConnection`, -which implements the `Connection` interface and -therefore can be used by the Multiplexer as any other connection. +The package provides the connection class `P2PLibp2pConnection`, which implements the `Connection` interface and therefore can be used by the Multiplexer as any other connection. -- The `connect` method of this connection spawns a new instance - of the `libp2p_node` program -(i.e. an ACN peer node) and connects to it through OS pipes. -Then, it sets up the _message receiving loop_, - which enqueues messages in the input queue to be read by `read` method calls, - and the _message sending loop_, - which dequeues messages from the output queue and forwards them to the Libp2p node. -The loops are run concurrently in the Multiplexer thread, - using the Python asynchronous programming library `asyncio`. +- The `connect` method of this connection spawns a new instance of the `libp2p_node` program (i.e. an ACN peer node) and connects to it through OS pipes. Then, it sets up the _message receiving loop_, which enqueues messages in the input queue to be read by `read` method calls, and the _message sending loop_, which dequeues messages from the output queue and forwards them to the Libp2p node. The loops are run concurrently in the Multiplexer thread, using the Python asynchronous programming library `asyncio`. -
+``` mermaid sequenceDiagram participant Libp2p Connection participant sending loop @@ -624,13 +487,11 @@ The loops are run concurrently in the Multiplexer thread, deactivate Libp2p Node deactivate sending loop deactivate receiving loop -
+``` -- The `send` method enqueues a message in the output queue. -The message is then dequeued by the sending loop, -and then sent to the Libp2p node. +- The `send` method enqueues a message in the output queue. The message is then dequeued by the sending loop, and then sent to the Libp2p node. -
+``` mermaid sequenceDiagram participant Libp2p Connection participant sending loop @@ -656,13 +517,11 @@ and then sent to the Libp2p node. else envelope decoding error Libp2p Node->>sending loop: Status(ERROR_SERIALIZATION) end -
+``` -- The `receive` method dequeues a message from the input queue. -The queue is populated by the receiving loop, -which receives messages from the Libp2p node. +- The `receive` method dequeues a message from the input queue. The queue is populated by the receiving loop, which receives messages from the Libp2p node. -
+``` mermaid sequenceDiagram participant Libp2p Connection participant receiving loop @@ -688,34 +547,19 @@ which receives messages from the Libp2p node. end Libp2p Connection->>receiving loop: read message from output queue note over Libp2p Connection: return message
to Multiplexer -
- -- the `disconnect` method stops both the receiving loop and the sending loop, - and stops the Libp2p node. - -### The `fetchai/p2p_libp2p_delegate` connection - -The source code of the `fetchai/p2p_libp2p_delegate` connection -can be downloaded from -the main AEA framework repository. -or from the main AEA framework repository. - -The package provides the connection class `P2PLibp2pClientConnection`, -which implements the `Connection` interface and -therefore can be used by the Multiplexer as any other connection. - -- The `connect` method of this connection will set up a TCP - connection to the URI of the delegate peer. Then, it will - send a `Register` request to register the agent among the peer's - client connections. - On registration success, it sets up the _message receiving loop_, - which enqueues messages in the input queue to be read by read method calls, - and the _message sending loop_, which dequeues messages from the output queue - and forwards them to the Libp2p node. - The loops are run concurrently in the Multiplexer thread, - using the Python asynchronous programming library `asyncio`. - -
+``` + +- the `disconnect` method stops both the receiving loop and the sending loop, and stops the Libp2p node. + +### The `fetchai/p2p_libp2p_delegate` Connection + +The source code of the `fetchai/p2p_libp2p_delegate` connection can be downloaded from the main AEA framework repository. or from the main AEA framework repository. + +The package provides the connection class `P2PLibp2pClientConnection`, which implements the `Connection` interface and therefore can be used by the Multiplexer as any other connection. + +- The `connect` method of this connection will set up a TCP connection to the URI of the delegate peer. Then, it will send a `Register` request to register the agent among the peer's client connections. On registration success, it sets up the _message receiving loop_, which enqueues messages in the input queue to be read by read method calls, and the _message sending loop_, which dequeues messages from the output queue and forwards them to the Libp2p node. The loops are run concurrently in the Multiplexer thread, using the Python asynchronous programming library `asyncio`. + +``` mermaid sequenceDiagram participant Libp2p Client Connection participant Libp2p Node @@ -744,34 +588,24 @@ therefore can be used by the Multiplexer as any other connection. activate Libp2p Node deactivate Libp2p Node end -
+``` -- The `send` method and the `receive` methods behave similarly to - the `send` and `receive` methods of the - `p2p_libp2p connection`, - in terms of message exchange; - however, the communication is done via TCP rather than pipes. +- The `send` method and the `receive` methods behave similarly to the `send` and `receive` methods of the `p2p_libp2p connection`, in terms of message exchange; however, the communication is done via TCP rather than pipes. -- The `disconnect` method interrupts the connection with the delegate peer, - without explicitly unregistering. +- The `disconnect` method interrupts the connection with the delegate peer, without explicitly unregistering. -## Known issues and limitations +## Known Issues and Limitations -In this section, we provide a list of known issues -and limitations of the current implementation -of the ACN, considering both the ACN nodes (written in Golang) -and the AEA connections, for the Python AEA framework, to interact with them. +In this section, we provide a list of known issues and limitations of the current implementation of the ACN, considering both the ACN nodes (written in Golang) and the AEA connections, for the Python AEA framework, to interact with them. -### Delegate client on client disconnection/reconnection +### Delegate Client on Client Disconnection/Reconnection -In case of disconnection/reconnection, delegate client record will be removed. -This can cause two problems: either the delegate client is not found, -or connection is closed during the send operation. +In case of disconnection/reconnection, delegate client record will be removed. This can cause two problems: either the delegate client is not found, or connection is closed during the send operation. Possible solutions: - Create more complicated structure for clients storage; -- Keep the delegate client record for longer; +- Keep the delegate client record for longer; - Clean up the record by timeout, per client queues. Code references: @@ -779,33 +613,20 @@ Code references: - record removed: https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L864 - send code: https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L955 +### Golang Node <> Python Client `libp2p` Connection -### Golang Node <> Python Client `libp2p` connection - -In case of connection between the Golang side (i.e. ACN node) -and the Python side (i.e. the `libp2p` AEA connection) is broken, -there is no reconnection attempt. -The Golang side connect to the Python server opened, -but if the connection is broken Golang can try to reconnect; -however, the Python side does not know about this and will restart -the node completely. +In case of connection between the Golang side (i.e. ACN node) and the Python side (i.e. the `libp2p` AEA connection) is broken, there is no reconnection attempt. The Golang side connect to the Python server opened, but if the connection is broken Golang can try to reconnect; however, the Python side does not know about this and will restart the node completely. -Possible solutions: the problem requires updates on both sides and assume possible timeouts on broken connection. -If connection is broken, the Python side awaits for reconnection from Golang side, -and restart node completely after timeout. +Possible solutions: the problem requires updates on both sides and assume possible timeouts on broken connection. If connection is broken, the Python side awaits for reconnection from Golang side, and restart node completely after timeout. -### What a peer should do if it receives an acknowledgement with an error? +### What a Peer Should Do if it Receives an Acknowledgement with an Error? -If an ACN response is the `Status` with error code different from `SUCCESS`, -the forwarding to other peers is not repeated. +If an ACN response is the `Status` with error code different from `SUCCESS`, the forwarding to other peers is not repeated. -A possible solution is to resend the message; however, -not clear why it should help in case of healthy connection, -how many times the sender should retry, and how it would help. +A possible solution is to resend the message; however, not clear why it should help in case of healthy connection, how many times the sender should retry, and how it would help. -Discussion on GitHub: -https://github.com/fetchai/agents-aea/pull/2509#discussion_r642628983 +Discussion on GitHub: https://github.com/fetchai/agents-aea/pull/2509#discussion_r642628983 -### No possibility of switching peers +### No Possibility of Switching Peers In case of a peer becoming unavailable, a delegate client or relay client currently has no means to automatically switch the peer. In particular, the DHT should be updated when a client switches peers. diff --git a/docs/acn.md b/docs/acn.md index f083aeff33..03a74bdca0 100644 --- a/docs/acn.md +++ b/docs/acn.md @@ -1,17 +1,19 @@ +# Agent Communication Network The agent communication network (ACN) provides a system for agents to find each other and communicate, solely based on their wallet addresses. It addresses the message delivery problem. -## Message delivery problem +## Message Delivery Problem + Agents need to contact each others. Given the wallet address of a target agent, how can the originator agent deliver a message to it whilst guaranteeing certain properties? -The properties we would like to have are: +The properties we would like to have, are: - Reliability: with guarantees on message reception - Authentication: to prevent impersonation - Confidentiality: to prevent exposing sensitive information within the message - Availability: some guarantees about the liveness of the service (tampering detection) -The problem statement and the agents framework context impose a number of design constraints: +The problem statement and the agent framework context impose a number of design constraints: - Distributed environment: no assumption are placed about the location of the agent, they can be anywhere in the publicly reachable internet - Decentralized environment: no trusted central authority @@ -23,31 +25,27 @@ The ACN solves the above problem whilst providing the above guarantees and satis The ACN is maintained by peers. Peers are not to be equated with agents. They are processes (usually distributed and decentralized) that together maintain the service. To use the service, agents need to associate themselves with peers. Thanks to digital signatures, the association between a given peer and agent can be verified by any participant in the system. -## Distributed hash table +## Distributed Hash Table At its core, the ACN implements a distributed hash table (DHT). A DHT is similar to a regular hash table in that it stores key-value pairs. However, storage is distributed across the participating machines (peers) with an efficient lookup operation. This is enabled by: - Consistent hashing: decide responsibility for assignment of the DHT key-value storage -- Structured overlays: organize the participating peers in a well defined topology for efficient routing +- Structured overlays: organize the participating peers in a well-defined topology for efficient routing DHT For the ACN, we use the DHT to store and maintain association between an agent address and the (network) location of its peer. - -## N-tier architecture +## N-Tier Architecture To satisfy different resource constraints and flexible deployment the ACN is implemented as a multi-tier architecture. As such, it provides an extension of the client-server model. The agent framework exploits this by implementing different tiers as different `Connections`: DHT -
-

Note

-

The p2p_libp2p_mailbox connection is not available yet. -

-
+!!! note + The `p2p_libp2p_mailbox` connection is not available yet. -## Trust and security +## Trust and Security An agent can choose which connection to use depending on the resource and trust requirements: @@ -57,6 +55,3 @@ An agent can choose which connection to use depending on the resource and trust All communication protocols use public cryptography to ensure security (authentication, confidentiality, and availability) using TLS handshakes with pre-shared public keys. DHT - - -
diff --git a/docs/aea-vs-mvc.md b/docs/aea-vs-mvc.md index 5b34cbd149..787299479d 100644 --- a/docs/aea-vs-mvc.md +++ b/docs/aea-vs-mvc.md @@ -1,3 +1,5 @@ +# AEA and Web Frameworks + The AEA framework borrows several concepts from popular web frameworks like Django and Ruby on Rails. ## MVC @@ -8,7 +10,7 @@ Both aforementioned web frameworks use the asynchronous messaging and other agent-oriented development assumptions. Hence, there is not a direct one-to-one relationship between MVC based architectures and the AEA framework. Nevertheless, there are some parallels which can help a developer familiar with MVC make quick progress in the AEA framework, in particular the development of `Skills`: @@ -21,10 +23,8 @@ The AEA framework is based on Build a skill for an AEA - -
diff --git a/docs/agent-oriented-development.md b/docs/agent-oriented-development.md index 86085e4883..22d507215e 100644 --- a/docs/agent-oriented-development.md +++ b/docs/agent-oriented-development.md @@ -1,69 +1,67 @@ -# Agent-oriented development +# Agent-Oriented Development In this section, we discuss some of the most fundamental characteristics of an agent-oriented approach to solution development, which might be different from existing paradigms and methodologies that you may be used to. We hope that with this, we can guide you towards the right mindset when designing your own agent-based solutions to real world problems. ## Decentralisation -Multi-Agent Systems (**MAS**) are inherently decentralised. The vision is of an environment in which every agent is able to directly connect with everyone else and interact with them without having to rely on a third party acting as an intermediary or match-maker. This is in direct contrast to centralised systems in which a single entity is the central point of authority, through which all interactions happen. The conventional client-server model is an example of a centralized architecture where clients interact with one another regarding specific services (e.g. communication, commerce) only through a server. +Multi-Agent Systems (**MAS**) are inherently decentralized. The vision is of an environment in which every agent is able to directly connect with everyone else and interact with them without having to rely on a third party acting as an intermediary or match-maker. This is in direct contrast to centralized systems in which a single entity is the central point of authority, through which all interactions happen. The conventional client-server model is an example of a centralized architecture where clients interact with one another regarding specific services (e.g. communication, commerce) only through a server. This is not to say that facilitators and middlemen have no place in a multi-agent system; rather it is the '_commanding reliance on middlemen_' that MAS rejects. -**Division of responsibilities:** In a decentralised system, every agent is equally privileged, and (in principle) should be able to interact with any other agent. The idea is very much aligned with the peer-to-peer paradigm, in which it is the voluntary participation and contribution of the peers that create the infrastructure. Therefore, in a decentralised system, there is no central 'enforcer'. This means all the work that would typically fall under the responsibilities of a central entity must be performed by individual parties in a decentralised system. Blockchain-based cryptocurrencies are a good example of this. A notable characteristic of cryptocurrencies is the absence of central trusted entities (e.g. banks). But this in turn means that most security precautions related to the handling of digital assets and the execution of transactions are the responsibility of individuals. +**Division of responsibilities:** In a decentralized system, every agent is equally privileged, and (in principle) should be able to interact with any other agent. The idea is very much aligned with the peer-to-peer paradigm, in which it is the voluntary participation and contribution of the peers that create the infrastructure. Therefore, in a decentralized system, there is no central 'enforcer'. This means all the work that would typically fall under the responsibilities of a central entity must be performed by individual parties in a decentralized system. Blockchain-based cryptocurrencies are a good example of this. A notable characteristic of cryptocurrencies is the absence of central trusted entities (e.g. banks). But this in turn means that most security precautions related to the handling of digital assets and the execution of transactions are the responsibility of individuals. - + -**Decentralisation vs distribution:** It is important to emphasise that by decentralisation we do not mean distribution; although multi-agent systems typically do also tend to be distributed. A distributed system is one whose components are physically located in different places and connected over a network. A fully centralised system, owned and operated by a single entity, may in fact be highly distributed. Google or Microsoft's cloud infrastructure are examples of this, where their components are distributed across the globe yet designed to work together harmoniously and function in unison. Decentralisation on the other hand refers to a system whose components may be owned, operated, and managed by different stakeholders, each with their own personal objectives, interests, and preferences which may not necessarily be aligned with one another or the system itself. Therefore, distribution refers to the physical placement of a system's components, whereas decentralisation refers to **a)** the diversity of ownership and control over a system's constituents, and **b)** the absence of central authorities between them. +**Decentralisation vs distribution:** It is important to emphasise that by decentralisation we do not mean distribution; although multi-agent systems typically do also tend to be distributed. A distributed system is one whose components are physically located in different places and connected over a network. A fully centralized system, owned and operated by a single entity, may in fact be highly distributed. Google or Microsoft's cloud infrastructure are examples of this, where their components are distributed across the globe yet designed to work together harmoniously and function in unison. Decentralisation on the other hand refers to a system whose components may be owned, operated, and managed by different stakeholders, each with their own personal objectives, interests, and preferences which may not necessarily be aligned with one another or the system itself. Therefore, distribution refers to the physical placement of a system's components, whereas decentralisation refers to **a.** the diversity of ownership and control over a system's constituents, and **b.** the absence of central authorities between them. -**Example:** To better illustrate the distinction between centralised and decentralised systems, consider another example: search and discoverability in a commerce environment. In a centralised system (say Amazon), there is a single search service -- provided, owned and run by the commerce company itself -- which takes care of all search-related functionality for every product within their domain. So to be discoverable in this system, all sellers must register their products with this particular service. However in a decentralised system, there may not necessarily be a single search service provider. There may be multiple such services, run by different, perhaps competing entities. Each seller has the freedom to register with (i.e. make themselves known to) one or a handful of services. On the buyers side, the more services they contact and query, the higher their chances of finding the product they are looking for. +**Example:** To better illustrate the distinction between centralized and decentralized systems, consider another example: search and discoverability in a commerce environment. In a centralized system (say Amazon), there is a single search service -- provided, owned and run by the commerce company itself -- which takes care of all search-related functionality for every product within their domain. So to be discoverable in this system, all sellers must register their products with this particular service. However, in a decentralized system, there may not necessarily be a single search service provider. There may be multiple such services, run by different, perhaps competing entities. Each seller has the freedom to register with (i.e. make themselves known to) one or a handful of services. On the buyers side, the more services they contact and query, the higher their chances of finding the product they are looking for. ## Conflicting Environment -As discussed above, the notion of decentralisation extends as far as ownership and control. Therefore, the different components that make up a decentralised system may each be owned by a different entity, designed according to very different principles and standards, with heterogeneous software and hardware, and each with internal objectives that may be fundamentally inconsistent, worse yet contradictory, with those of others. +As discussed above, the notion of decentralisation extends as far as ownership and control. Therefore, the different components that make up a decentralized system may each be owned by a different entity, designed according to very different principles and standards, with heterogeneous software and hardware, and each with internal objectives that may be fundamentally inconsistent, worse yet contradictory, with those of others. As such, a distinctive characteristic of a multi-agent environment, is that it is inhabited by more than one agent (as the name suggests), where each agent may be owned potentially by a different stakeholder (individual, company, government). Since by design, each agent represents and looks after the interests of its owner(s), and because different stakeholders may have unaligned, conflicting, or contradictory interests, it is very common to have multi-agent systems in which the agents' objectives, values and preferences are unaligned, conflicting, or contradictory. **In practice:** There are practical implications that follow from the above when it comes to designing an agent. For example, it is not rational for an agent to automatically rely on the information it receives from other agents. The information could be: -* Incomplete: what is unrevealed may have been deemed private for strategic reasons. -* Uncertain: it may be the result of an inaccurate prediction. -* Incorrect: it could be an outright lie, due to the adversarial nature of the environment. +- Incomplete: what is unrevealed may have been deemed private for strategic reasons. +- Uncertain: it may be the result of an inaccurate prediction. +- Incorrect: it could be an outright lie, due to the adversarial nature of the environment. -Therefore one can argue, that there is a degree of uncertainty attached to almost all information an agent receives or infers in a multi-agent system. It wouldn't then be illogical for an agent to take a sceptical approach: treating everything as uncertain, unless proved otherwise. +Therefore, one can argue that there is a degree of uncertainty attached to almost all information an agent receives or infers in a multi-agent system. It wouldn't then be illogical for an agent to take a sceptical approach: treating everything as uncertain, unless proved otherwise. -## Asynchronisation +## Asynchronization -The conflicting nature of multi-agent systems, consisting of self-interested autonomous agents, points to _asynchronisation_ as the preferred method of designing and managing processes and interactions. +The conflicting nature of multi-agent systems, consisting of self-interested autonomous agents, points to _asynchronization_ as the preferred method of designing and managing processes and interactions. -**Synchronisation vs asynchronisation:** In general, asynchronisation refers to the decoupling of events that do interact with one another but do not occur at predetermined intervals, not necessarily relying on each other's existence to function. This is in contrast with _synchronous_ systems in which processes are aware of one another, where one's execution depends in some way on the other. +**Synchronisation vs asynchronization:** In general, asynchronization refers to the decoupling of events that do interact with one another but do not occur at predetermined intervals, not necessarily relying on each other's existence to function. This is in contrast with _synchronous_ systems in which processes are aware of one another, where one's execution depends in some way on the other. -**Asynchronisation in MAS:** In the context of multi-agent systems, the decentralised and potentially conflicting nature of the environment creates uncertainty over the behaviour of the whole system, in particular of other agents. For example, suppose an agent `i` sends a message requesting some resources from an agent `j`. Since MAS often tends to be distributed, there is the usual uncertainties with communication over a network: `j` may never receive `i`'s request, or may receive it after a long delay. Furthermore, `j` could receive the request in time and respond immediately, but as mentioned in the last section, its answer might be incomplete (gives only some of the requested resources), uncertain (promises to give the resources, but cannot be fully trusted), or incorrect (sends a wrong resource). In addition, since agents are self-interested, `j` may _decide_ to reply much later, to the point that the resource is no longer useful to agent `i`, or `j` may simply decide not to respond at all. There might be a myriad of reasons why it may choose to do that; it could be because `j` assigns a low priority to answering `i` over its other tasks. But that's beside the point. The take away is that agents' autonomy strongly influences what can be expected of them, and of an environment inhabited by them. As such, developing for a system whose constituents are autonomous, e.g. agents in a multi-agent system, is fundamentally different from one whose constituents aren't, e.g. objects in an object-oriented system. +**Asynchronization in MAS:** In the context of multi-agent systems, the decentralized and potentially conflicting nature of the environment creates uncertainty over the behaviour of the whole system, in particular of other agents. For example, suppose an agent `i` sends a message requesting some resources from an agent `j`. Since MAS often tends to be distributed, there is the usual uncertainties with communication over a network: `j` may never receive `i`'s request, or may receive it after a long delay. Furthermore, `j` could receive the request in time and respond immediately, but as mentioned in the last section, its answer might be incomplete (gives only some of the requested resources), uncertain (promises to give the resources, but cannot be fully trusted), or incorrect (sends a wrong resource). In addition, since agents are self-interested, `j` may _decide_ to reply much later, to the point that the resource is no longer useful to agent `i`, or `j` may simply decide not to respond at all. There might be a myriad of reasons why it may choose to do that; it could be because `j` assigns a low priority to answering `i` over its other tasks. But that's beside the point. The takeaway is that agents' autonomy strongly influences what can be expected of them, and of an environment inhabited by them. As such, developing for a system whose constituents are autonomous, e.g. agents in a multi-agent system, is fundamentally different from one whose constituents aren't, e.g. objects in an object-oriented system. -**Objects vs agents:** In object-oriented systems, objects are entities that encapsulate state and perform actions, i.e. call methods, on this state. In object-oriented languages, like C++ and Java, it is common practice to declare methods as public, so they can be invoked by other objects in the system whenever they wish. This implies that an object does not control its own behaviour. If an object’s method is public, the object has no control over whether or not that method is executed. +**Objects vs agents:** In object-oriented systems, objects are entities that encapsulate state and perform actions, i.e. call methods, on this state. In object-oriented languages, like C++ and Java, it is common practice to declare methods as public, so they can be invoked by other objects in the system whenever they wish. This implies that an object does not control its own behaviour. If an object’s method is public, the object has no control over whether that method is executed. We cannot take for granted that an agent `j` will execute an action (the equivalent of a method in object-oriented systems) just because another agent `i` wants it to; this action may not be in the best interests of agent `j`. So we do not think of agents as invoking methods on one another, rather as _requesting_ actions. If `i` requests `j` to perform an action, then `j` may or may not perform the action. It may choose to do it later or do it in exchange for something. The locus of control is therefore different in object-oriented and agent-oriented systems. In the former, the decision lies with the object invoking the method, whereas in the latter, the decision lies with the agent receiving the request. This distinction could be summarised by the following slogan (from An Introduction to MultiAgent Systems by Michael Wooldridge): >objects do it for free; agents do it because they want to. -All of this makes asynchronisation the preferred method for designing agent processes and interactions. An agent's interactions should be independent of each other, as much as possible, and of the agent's decision making processes and actions. This means the success or failure of, or delay in any single interaction does not block the agent's other tasks. +All of this makes asynchronization the preferred method for designing agent processes and interactions. An agent's interactions should be independent of each other, as much as possible, and of the agent's decision-making processes and actions. This means the success or failure of, or delay in any single interaction does not block the agent's other tasks. ## Time -Closely related with the discussion of asynchronicity, is the idea that in multi-agent systems, time is not a universally agreed notion. Agents may not necessarily share the same clock and this fact must be taken into account when designing agent-based systems. For example, you cannot necessarily expect agents to synchronise their behaviour according to time (e.g. perform a certain task at a time `X`). +Closely related with the discussion of asynchronicity, is the idea that in multi-agent systems, time is not a universally agreed notion. Agents may not necessarily share the same clock and this fact must be taken into account when designing agent-based systems. For example, you cannot necessarily expect agents to synchronise their behaviour according to time (e.g. perform a certain task at a time `X`). -Another related issue, is that unlike some agent-based simulation (ABS) systems where there is a global tick rate for all agents, in AEA-based systems tick rates may be different for different agents. This is due to the fundamental difference that ABS systems control some aspects of all of their agents' executions while in AEA-based systems, agents are truly decoupled from one another - most likely distributed and running on different machines and networks - and there is absolutely no central unit that moderates any aspect of their behaviour. +Another related issue, is that unlike some agent-based simulation (ABS) systems where there is a global tick rate for all agents, in AEA-based systems tick rates may be different for different agents. This is due to the fundamental difference that ABS systems control some aspects of all of their agents' executions while in AEA-based systems, agents are truly decoupled from one another - most likely distributed and running on different machines and networks - and there is absolutely no central unit that moderates any aspect of their behaviour. ## Complex, Incomplete, Inconsistent and Uncertain The fourth characteristic(s) relate to the environment in which agents are expected to operate in, and these have been mentioned a number of times in the previous sections. -The environment agents are suited for typically tend to be complex, to the point that it is usually impossible for any single agent to perceive the whole of the environment on its own. This means that at any point in time, any agent has a limited knowledge about the state of the environment. In other words, the agents;' information tend to be incomplete due to the complexity and sophistication of the world in which they reside. +The environment agents are suited for typically tend to be complex, to the point that it is usually impossible for any single agent to perceive the whole of the environment on its own. This means that at any point in time, any agent has a limited knowledge about the state of the environment. In other words, the agents;' information tend to be incomplete due to the complexity and sophistication of the world in which they reside. -Consider an agent which represents a driverless vehicle. The complexity of the problem of driving on the road makes it impossible for a single vehicle to have an accurate and up-to-date knowledge of the overall state of the world . This means that an agent's model of the world is at best uncertain. For instance, the vehicle, through its sensor may detect green light at a junction, and by being aware of what it means, it may infer that it is safe to cross a junction. However, that simply may not be true as another car in the opposite direction may still cross the junction violating their red light. Therefore, there is uncertainty associated with the knowledge "it is safe to cross the road because the light is green", and the agent must recognise that. +Consider an agent which represents a driver-less vehicle. The complexity of the problem of driving on the road makes it impossible for a single vehicle to have an accurate and up-to-date knowledge of the overall state of the world . This means that an agent's model of the world is at best uncertain. For instance, the vehicle, through its sensor may detect green light at a junction, and by being aware of what it means, it may infer that it is safe to cross a junction. However, that simply may not be true as another car in the opposite direction may still cross the junction violating their red light. Therefore, there is uncertainty associated with the knowledge "it is safe to cross the road because the light is green", and the agent must recognise that. -Furthermore, the often conflicting nature of the environment means information obtained from multiple sources (agents) may be inconsistent. Again, this must be taken into consideration when designing an agent which is expected to operate successfully in a potentially conflicting environment. +Furthermore, the often conflicting nature of the environment means information obtained from multiple sources (agents) may be inconsistent. Again, this must be taken into consideration when designing an agent which is expected to operate successfully in a potentially conflicting environment. ## Further Reading -* Wooldridge, M. (2009). _An Introduction to MultiAgent Systems_. Wiley, Second edition. -* Shoham, Y. and Leyton-Brown, K. (2008). _Multiagent Systems: Algorithmic, Game-Theoretic, and Logical Foundations_. Cambridge University Press - -
+- Wooldridge, M. (2009). _An Introduction to MultiAgent Systems_. Wiley, Second edition. +- Shoham, Y. and Leyton-Brown, K. (2008). _Multiagent Systems: Algorithmic, Game-Theoretic, and Logical Foundations_. Cambridge University Press diff --git a/docs/agent-vs-aea.md b/docs/agent-vs-aea.md index 16a90e5d37..aaa951ebf3 100644 --- a/docs/agent-vs-aea.md +++ b/docs/agent-vs-aea.md @@ -1,12 +1,15 @@ +# AEAs vs Agents + AEAs are more than just agents. AEA vs Agent vs Multiplexer -In this guide we show some of the differences in terms of code. +In this guide, we show some of the differences in terms of code. The Build an AEA programmatically guide shows how to programmatically build an AEA. We can build an agent of the `Agent` class programmatically as well. -First, import the python and application specific libraries. (Get the packages directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) +First, import the python and application specific libraries. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) + ``` python import os import time @@ -27,12 +30,12 @@ from packages.fetchai.protocols.default.message import DefaultMessage Unlike an `AEA`, an `Agent` does not require a `Wallet`, `LedgerApis` or `Resources` module. However, we need to implement 4 abstract methods: + - `setup()` - `act()` - `handle_envelope()` - `teardown()` - When we run an agent, `start()` calls `setup()` and then the main agent loop. The main agent loop calls `act()`, `react()` and `update()` on each tick. When the agent is stopped via `stop()` then `teardown()` is called. Such a lightweight agent can be used to implement simple logic. @@ -40,6 +43,7 @@ Such a lightweight agent can be used to implement simple logic. ## Code an `Agent` We define our `Agent` which simply receives envelopes, prints the sender address and `protocol_id` and returns it unopened. + ``` python INPUT_FILE = "input_file" OUTPUT_FILE = "output_file" @@ -118,8 +122,10 @@ class MyAgent(Agent): my_agent = MyAgent(identity, [stub_connection]) ``` -## Start the agent +## Start the Agent + We run the agent from a different thread so that we can still use the main thread to pass it messages. + ``` python # Set the agent running in a different thread try: @@ -130,8 +136,10 @@ We run the agent from a different thread so that we can still use the main threa time.sleep(3) ``` -## Send and receive an envelope +## Send and Receive an Envelope + We use the input and output text files to send an envelope to our agent and receive a response + ``` python # Create a message inside an envelope and get the stub connection to pass it into the agent message_text = b"my_agent,other_agent,fetchai/default:1.0.0,\x12\r\x08\x01*\t*\x07\n\x05hello," @@ -148,7 +156,9 @@ We use the input and output text files to send an envelope to our agent and rece ``` ## Shutdown -Finally stop our agent and wait for it to finish + +Finally, stop our agent and wait for it to finish + ``` python finally: # Shut down the agent @@ -156,139 +166,135 @@ Finally stop our agent and wait for it to finish t.join() ``` -## Your turn +## Your Turn Now it is your turn to develop a simple agent with the `Agent` class. -## Entire code listing -If you just want to copy and paste the entire script in you can find it here: - -
Click here to see full listing -

- -``` python -import os -import time -from threading import Thread -from typing import List - -from aea.agent import Agent -from aea.configurations.base import ConnectionConfig -from aea.connections.base import Connection -from aea.helpers.file_io import write_with_lock -from aea.identity.base import Identity -from aea.mail.base import Envelope - -from packages.fetchai.connections.stub.connection import StubConnection -from packages.fetchai.protocols.default.message import DefaultMessage - - -INPUT_FILE = "input_file" -OUTPUT_FILE = "output_file" - +## Entire Code Listing -class MyAgent(Agent): - """A simple agent.""" - - def __init__(self, identity: Identity, connections: List[Connection]): - """Initialise the agent.""" - super().__init__(identity, connections) - - def setup(self): - """Setup the agent.""" - - def act(self): - """Act implementation.""" - print("Act called for tick {}".format(self.tick)) - - def handle_envelope(self, envelope: Envelope) -> None: - """ - Handle envelope. +If you just want to copy and paste the entire script in you can find it here: - :param envelope: the envelope received - :return: None - """ - print("React called for tick {}".format(self.tick)) - if ( - envelope is not None - and envelope.protocol_specification_id - == DefaultMessage.protocol_specification_id - ): - sender = envelope.sender - receiver = envelope.to - envelope.to = sender - envelope.sender = receiver - envelope.message = DefaultMessage.serializer.decode(envelope.message_bytes) - envelope.message.sender = receiver - envelope.message.to = sender - print( - "Received envelope from {} with protocol_specification_id={}".format( - sender, envelope.protocol_specification_id +??? note "Click here to see full listing" + + ``` python + import os + import time + from threading import Thread + from typing import List + + from aea.agent import Agent + from aea.configurations.base import ConnectionConfig + from aea.connections.base import Connection + from aea.helpers.file_io import write_with_lock + from aea.identity.base import Identity + from aea.mail.base import Envelope + + from packages.fetchai.connections.stub.connection import StubConnection + from packages.fetchai.protocols.default.message import DefaultMessage + + + INPUT_FILE = "input_file" + OUTPUT_FILE = "output_file" + + + class MyAgent(Agent): + """A simple agent.""" + + def __init__(self, identity: Identity, connections: List[Connection]): + """Initialise the agent.""" + super().__init__(identity, connections) + + def setup(self): + """Setup the agent.""" + + def act(self): + """Act implementation.""" + print("Act called for tick {}".format(self.tick)) + + def handle_envelope(self, envelope: Envelope) -> None: + """ + Handle envelope. + + :param envelope: the envelope received + :return: None + """ + print("React called for tick {}".format(self.tick)) + if ( + envelope is not None + and envelope.protocol_specification_id + == DefaultMessage.protocol_specification_id + ): + sender = envelope.sender + receiver = envelope.to + envelope.to = sender + envelope.sender = receiver + envelope.message = DefaultMessage.serializer.decode(envelope.message_bytes) + envelope.message.sender = receiver + envelope.message.to = sender + print( + "Received envelope from {} with protocol_specification_id={}".format( + sender, envelope.protocol_specification_id + ) ) - ) - self.outbox.put(envelope) - - def teardown(self): - """Teardown the agent.""" - - -def run(): - """Run demo.""" - - # Ensure the input and output files do not exist initially - if os.path.isfile(INPUT_FILE): - os.remove(INPUT_FILE) - if os.path.isfile(OUTPUT_FILE): - os.remove(OUTPUT_FILE) - - # Create an addresses identity: - identity = Identity( - name="my_agent", address="some_address", public_key="public_key" - ) - - # Set up the stub connection - configuration = ConnectionConfig( - input_file_path=INPUT_FILE, - output_file_path=OUTPUT_FILE, - connection_id=StubConnection.connection_id, - ) - stub_connection = StubConnection( - configuration=configuration, data_dir=".", identity=identity - ) - - # Create our Agent - my_agent = MyAgent(identity, [stub_connection]) - - # Set the agent running in a different thread - try: - t = Thread(target=my_agent.start) - t.start() - - # Wait for everything to start up - time.sleep(3) - - # Create a message inside an envelope and get the stub connection to pass it into the agent - message_text = b"my_agent,other_agent,fetchai/default:1.0.0,\x12\r\x08\x01*\t*\x07\n\x05hello," - - with open(INPUT_FILE, "wb") as f: - write_with_lock(f, message_text) - - # Wait for the envelope to get processed - time.sleep(2) - - # Read the output envelope generated by the agent - with open(OUTPUT_FILE, "rb") as f: - print("output message: " + f.readline().decode("utf-8")) - finally: - # Shut down the agent - my_agent.stop() - t.join() - - -if __name__ == "__main__": - run() -``` -

-
- -
+ self.outbox.put(envelope) + + def teardown(self): + """Teardown the agent.""" + + + def run(): + """Run demo.""" + + # Ensure the input and output files do not exist initially + if os.path.isfile(INPUT_FILE): + os.remove(INPUT_FILE) + if os.path.isfile(OUTPUT_FILE): + os.remove(OUTPUT_FILE) + + # Create an addresses identity: + identity = Identity( + name="my_agent", address="some_address", public_key="public_key" + ) + + # Set up the stub connection + configuration = ConnectionConfig( + input_file_path=INPUT_FILE, + output_file_path=OUTPUT_FILE, + connection_id=StubConnection.connection_id, + ) + stub_connection = StubConnection( + configuration=configuration, data_dir=".", identity=identity + ) + + # Create our Agent + my_agent = MyAgent(identity, [stub_connection]) + + # Set the agent running in a different thread + try: + t = Thread(target=my_agent.start) + t.start() + + # Wait for everything to start up + time.sleep(3) + + # Create a message inside an envelope and get the stub connection to pass it into the agent + message_text = b"my_agent,other_agent,fetchai/default:1.0.0,\x12\r\x08\x01*\t*\x07\n\x05hello," + + with open(INPUT_FILE, "wb") as f: + write_with_lock(f, message_text) + + # Wait for the envelope to get processed + time.sleep(2) + + # Read the output envelope generated by the agent + with open(OUTPUT_FILE, "rb") as f: + print("output message: " + f.readline().decode("utf-8")) + finally: + # Shut down the agent + my_agent.stop() + t.join() + + + if __name__ == "__main__": + run() + ``` diff --git a/docs/aggregation-demo.md b/docs/aggregation-demo.md index c5bf1c7b58..873fd9f8c9 100644 --- a/docs/aggregation-demo.md +++ b/docs/aggregation-demo.md @@ -1,11 +1,13 @@ +# Aggregation Skill + This demo shows how AEAs can aggregate values over the peer-to-peer network. ## Discussion This demonstration shows how to set up a simple aggregation network in which several AEAs take an average of values fetched from different sources for the same real-world quantity. For this particular example, we take an average of Bitcoin prices from four public APIs. -## Preparation instructions - +## Preparation Instructions + ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. @@ -17,6 +19,7 @@ Follow the Preliminaries and Alternatively, create from scratch. -

+??? note "Alternatively, create from scratch:" -Create the AEA. + Create the AEA: -``` bash -agent_name="agg$i" -aea create agent_name -cd agent_name -aea add connection fetchai/http_client:0.24.5 -aea add connection fetchai/http_server:0.23.5 -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/prometheus:0.9.5 -aea add skill fetchai/advanced_data_request:0.7.5 -aea add skill fetchai/simple_aggregation:0.3.5 - -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea install -aea build -``` + ``` bash + agent_name="agg$i" + aea create agent_name + cd agent_name + aea add connection fetchai/http_client:0.24.5 + aea add connection fetchai/http_server:0.23.5 + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/prometheus:0.9.5 + aea add skill fetchai/advanced_data_request:0.7.5 + aea add skill fetchai/simple_aggregation:0.3.5 + + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea install + aea build + ``` + + Set the desired decimal precision for the quantity: -Set the desired decimal precision for the quantity: -``` bash -aea config set --type int vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals 0 -``` + ``` bash + aea config set --type int vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals 0 + ``` -Disable the http server since it is not used in this demo: -``` bash -aea config set --type bool vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server false -``` - -

- + Disable the http server since it is not used in this demo: + ``` bash + aea config set --type bool vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server false + ``` Set the cert requests for the peer-to-peer connection: + ``` bash aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ '[{"identifier": "acn", "ledger_id": "fetchai", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "message_format": "{public_key}", "save_path": ".certs/conn_cert.txt"}]' ``` Match the agent index `i` to the `COIN_URL` and `JSON_PATH` below: + - `agg0`: `COIN_URL="https://api.coinbase.com/v2/prices/BTC-USD/buy" && JSON_PATH="data.amount"` - `agg1`: `COIN_URL="https://api.coinpaprika.com/v1/tickers/btc-bitcoin" && JSON_PATH="quotes.USD.price"` - `agg2`: `COIN_URL="https://api.cryptowat.ch/markets/kraken/btcusd/price" && JSON_PATH="result.price"` - `agg3`: `COIN_URL="https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd" && JSON_PATH="bitcoin.usd"` Set the following configuration for the `advanced_data_request` skill: + ``` bash aea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url $COIN_URL aea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{"name": "price", "json_path": '"\"$JSON_PATH\""'}]' ``` Set the name of the quantity to aggregate and choose an aggregation function for the AEAs (the currently implemented options are `mean`, `median`, and `mode`): + ``` bash aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.quantity_name price aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.aggregation_function mean ``` Specify a name for your aggregation service: + ``` bash SERVICE_ID=my_btc_aggregation_service aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.service_id $SERVICE_ID @@ -93,6 +98,7 @@ aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.sea ``` Additionally, create private keys for use with the ledger and the peer-to-peer connection: + ``` bash aea generate-key fetchai aea add-key fetchai @@ -101,13 +107,15 @@ aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the keys for use by the connections that request them: + ``` bash aea issue-certificates ``` -### Configure the peer-to-peer network +### Configure the Peer-to-Peer Network + +Set the multiaddress of the first AEA as an initial peer to help the remaining AEAs find each other on the network. Also, if these AEAs are all running on the same machine, set different ports for their connections to ensure there are no conflicts (from the `agg1`, `agg2`, and `agg3` directories): -Set the multi-address of the first AEA as an initial peer to help the remaining AEAs find each other on the network. Also, if these AEAs are all running on the same machine, set different ports for their connections to ensure there are no conflicts (from the `agg1`, `agg2`, and `agg3` directories): ``` bash MULTIADDR=$(cd ../agg0 && aea get-multiaddress fetchai --connection) aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ @@ -122,38 +130,44 @@ aea config set vendor.fetchai.connections.prometheus.config.port $((20000+i)) aea config set vendor.fetchai.connections.http_server.config.port $((8000+i)) ``` -### Oracle integration (optional) +### Oracle Integration (optional) To publish the aggregated value to an oracle smart contract, add the ledger connection and simple oracle skill to one of the aggregators: + ``` bash aea add connection fetchai/ledger:0.21.4 aea add skill fetchai/simple_oracle:0.16.4 ``` Configure the simple oracle skill for the `fetchai` ledger: + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value ``` Generate some wealth to use for transactions on the testnet ledger: -``` + +``` bash aea generate-wealth fetchai ``` Set the name of the oracle value to match the value collected by the aggregators: + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price_mean ``` ### Run the AEAs -Run each of the aggregator AEAs in separate terminals: +Run each of the aggregator AEAs in separate terminals: + ``` bash aea run ``` After a few moments, you should see the AEAs finding peers, making observations, sending them to peers, and taking the average of their observations: + ``` bash info: [agg_i] found agents... ... diff --git a/docs/app-areas.md b/docs/app-areas.md index b19d603d9d..0de9868c3a 100644 --- a/docs/app-areas.md +++ b/docs/app-areas.md @@ -1,34 +1,31 @@ +# Application Areas + The
introduction and the agent-oriented development guide together present a picture of the kinds of solution an agent-based approach makes possible, and the types of environment they are most suited for. In short, this is where: - * the environment is decentralised, - * involves multiple stakeholders, and - * is inhabited by AEAs representing the different stakeholders who: - * interact autonomously, and - * communicate with one another directly via a peer-to-peer network. +- the environment is decentralized, +- involves multiple stakeholders, and +- is inhabited by AEAs representing the different stakeholders who: + - interact autonomously, and + - communicate with one another directly via a peer-to-peer network. In light of those discussions, on this page we identify a number of application areas for AEA-based solutions. This list is by no means comprehensive. In fact, we are most excited about applications which we have not thought of before. -* **Inhabitants**: agents representing objects in the IoT (Internet of Things) space. For examples, AEAs paired with real world hardware devices such as drones, laptops, heat sensors, etc. An example is a thermometer agent . -* **Interfaces**: facilitation agents which provide the necessary API interfaces for interaction between existing (Web 2.0) and new (Web 3.0) economic models. An example is an AEA with HTTP connection and skill who has the capability to communicate using HTTP. -* **Pure software**: software agents _living_ in the digital space that interact with interface agents and others. -* **Digital data sales agents**: software agents that attach to data sources and sell it via the open economic framework. An example can be found here. -* **Representative**: an agent which represents an individual's activities on the Fetch.ai network. An example can be found here. +- **Inhabitants**: agents representing objects in the IoT (Internet of Things) space. For examples, AEAs paired with real world hardware devices such as drones, laptops, heat sensors, etc. An example is a thermometer agent . +- **Interfaces**: facilitation agents which provide the necessary API interfaces for interaction between existing (Web 2.0) and new (Web 3.0) economic models. An example is an AEA with HTTP connection and skill who has the capability to communicate using HTTP. +- **Pure software**: software agents _living_ in the digital space that interact with interface agents and others. +- **Digital data sales agents**: software agents that attach to data sources and sell it via the open economic framework. An example can be found here. +- **Representative**: an agent which represents an individual's activities on the Fetch.ai network. An example can be found here. -## Likely short-term applications +## Likely Short-Term Applications In the short-term we see AEAs primarily deployed in three areas: -* Off-load repetitive tasks: AEAs can automate well-defined processes in different domains such as supply chain, mobility and finance, etc. - -* Micro transactions: AEAs make it economically viable to execute trades which involve small value transfers. This is particularly relevant in areas where there is a (data) supply side constituted of many small actors and a single demand side. - -* Wallet agents: AEAs can simplify interactions with blockchains for end users. For instance, they can act as "smart wallets" which optimize blockchain interactions on behalf of the user. +- Off-load repetitive tasks: AEAs can automate well-defined processes in different domains such as supply chain, mobility and finance, etc. +- Micro-transactions: AEAs make it economically viable to execute trades which involve small value transfers. This is particularly relevant in areas where there is a (data) supply side constituted of many small actors and a single demand side. +- Wallet agents: AEAs can simplify interactions with blockchains for end users. For instance, they can act as "smart wallets" which optimize blockchain interactions on behalf of the user. - -## Multi-agent system versus agent-based modelling +## Multi-Agent System versus Agent-Based Modelling The multi-agent systems enabled by the AEA framework are technological agent-based solutions to real problems and, although there are some overlap, the framework is not designed from the outset to be used as an agent-based modelling software where the goal is scientific behavioural observation rather than practical economic gain. -Moreover, there is no restriction to *multi*; single-agent applications are also supported. - -
+Moreover, there is no restriction to _multi_; single-agent applications are also supported. diff --git a/docs/aries-cloud-agent-demo.md b/docs/aries-cloud-agent-demo.md index d81f0d9de3..f8b198a0ba 100644 --- a/docs/aries-cloud-agent-demo.md +++ b/docs/aries-cloud-agent-demo.md @@ -1,10 +1,9 @@ -
-

Note

-

This demo is incomplete and will soon be updated. -

-
+# Aries Cloud Agents Demo -Demonstrating an entire decentralised identity scenario involving AEAs and instances of Aries Cloud Agents (ACAs). +!!! note + This demo is incomplete and will soon be updated. + +Demonstrating an entire decentralized identity scenario involving AEAs and instances of Aries Cloud Agents (ACAs). ## Discussion @@ -12,7 +11,7 @@ This demo corresponds with the one +``` mermaid sequenceDiagram participant faea as Faber_AEA participant faca as Faber_ACA @@ -41,39 +40,39 @@ The aim of this demo is to illustrate how AEAs can connect to ACAs, thus gaining deactivate faca deactivate aaca deactivate aaea - +``` There are two AEAs: - * **Alice_AEA** - * **Faber_AEA** +- **Alice_AEA** +- **Faber_AEA** and two ACAs: - * **Alice_ACA** - * **Faber_ACA** +- **Alice_ACA** +- **Faber_ACA** Each AEA is connected to its corresponding ACA: **Alice_AEA** to **Alice_ACA** and **Faber_AEA** to **Faber_ACA**. The following lists the sequence of interactions between the four agents: - * **Alice_AEA**: starts - * **Alice_AEA**: shows its P2P address in the terminal and waits for an `invitation` detail from **Faber_AEA**. - * **Alice_AEA**: registers itself on the SOEF. - * **Faber_AEA**: starts - * **Faber_AEA**: searches the SOEF and finds **Alice_AEA**. - * **Faber_AEA**: tests its connection to **Faber_ACA**. - * **Faber_ACA**: responds to **Faber_AEA**. - * **Faber_AEA**: registers a DID on the ledger. - * **Faber_AEA**: request **Faber_ACA** to register a schema on the ledger. - * **Faber_ACA**: responds by sending back the `schema_id`. - * **Faber_AEA**: request **Faber_ACA** to register a credential definition on the ledger. - * **Faber_ACA**: responds by sending back the `credential_definition_id`. - * **Faber_AEA**: requests **Faber_ACA** to create an invitation. - * **Faber_ACA**: responds by sending back the `connection` detail, which contains an `invitation` field. - * **Faber_AEA**: sends the `invitation` detail to **Alice_AEA**. - * **Alice_AEA**: receives `invitation` detail from **Faber_AEA**. - * **Alice_AEA**: requests **Alice_ACA** to accept the invitation, by passing it the `invitation` detail it received in the last step. +- **Alice_AEA**: starts +- **Alice_AEA**: shows its P2P address in the terminal and waits for an `invitation` detail from **Faber_AEA**. +- **Alice_AEA**: registers itself on the SOEF. +- **Faber_AEA**: starts +- **Faber_AEA**: searches the SOEF and finds **Alice_AEA**. +- **Faber_AEA**: tests its connection to **Faber_ACA**. +- **Faber_ACA**: responds to **Faber_AEA**. +- **Faber_AEA**: registers a DID on the ledger. +- **Faber_AEA**: request **Faber_ACA** to register a schema on the ledger. +- **Faber_ACA**: responds by sending back the `schema_id`. +- **Faber_AEA**: request **Faber_ACA** to register a credential definition on the ledger. +- **Faber_ACA**: responds by sending back the `credential_definition_id`. +- **Faber_AEA**: requests **Faber_ACA** to create an invitation. +- **Faber_ACA**: responds by sending back the `connection` detail, which contains an `invitation` field. +- **Faber_AEA**: sends the `invitation` detail to **Alice_AEA**. +- **Alice_AEA**: receives `invitation` detail from **Faber_AEA**. +- **Alice_AEA**: requests **Alice_ACA** to accept the invitation, by passing it the `invitation` detail it received in the last step. All messages from an AEA to an ACA are http requests (using `http_client` connection). @@ -85,21 +84,21 @@ This is the extent of the demo at this point. The rest of the interactions requi The rest of the interactions are broadly as follows: - * **Alice_ACA**: accepts the invitation. - * **Alice_ACA**: sends a matching invitation request to **Faber_ACA**. - * **Faber_ACA**: accepts +- **Alice_ACA**: accepts the invitation. +- **Alice_ACA**: sends a matching invitation request to **Faber_ACA**. +- **Faber_ACA**: accepts At this point, the two ACAs are connected to each other. - * **Faber_AEA**: requests **Faber_ACA** to issue a credential (e.g. university degree) to **Alice_AEA**, which **Faber_ACA** does via **Alice_ACA**. - * **Faber_AEA**: requests proof that **Alice_AEA**'s age is above 18. - * **Alice_AEA**: presents proof that it's age is above 18, without presenting its credential. +- **Faber_AEA**: requests **Faber_ACA** to issue a credential (e.g. university degree) to **Alice_AEA**, which **Faber_ACA** does via **Alice_ACA**. +- **Faber_AEA**: requests proof that **Alice_AEA**'s age is above 18. +- **Alice_AEA**: presents proof that it's age is above 18, without presenting its credential. ## Preparation Instructions ### Dependencies -Follow the Preliminaries and Installation sections from the AEA quick start. +Follow the Preliminaries and Installation sections from the AEA quick start. Install Aries cloud-agents (for more info see here) if you do not have it on your machine: @@ -111,7 +110,7 @@ This demo has been successfully tested with `aca-py` version `0.4.5`. This demo requires an instance of von network running in docker locally (for more info see here) -This demo has been successfully tested with the von-network git repository pulled on 07 Aug 2020 (commit number `ad1f84f64d4f4c106a81462f5fbff496c5fbf10e`). +This demo has been successfully tested with the von-network git repository pulled on 07 Aug 2020 (commit number `ad1f84f64d4f4c106a81462f5fbff496c5fbf10e`). ### Terminals @@ -126,7 +125,8 @@ This http://localhost:9000. ## Alice and Faber ACAs @@ -149,9 +149,9 @@ Make sure the ports above are unused. Take note of the specific IP addresses and ports you used in the above command. We will refer to them by the following names: -* **Faber admin IP**: 127.0.0.1 -* **Faber admin port**: 8021 -* **Faber webhook port**: 8022 +- **Faber admin IP**: 127.0.0.1 +- **Faber admin port**: 8021 +- **Faber webhook port**: 8022 The admin IP and port will be used to send administrative commands to this ACA from an AEA. @@ -167,9 +167,9 @@ aca-py start --admin 127.0.0.1 8031 --admin-insecure-mode --inbound-transport ht Again, make sure the above ports are unused and take note of the specific IP addresses and ports. In this case: -* **Alice admin IP**: 127.0.0.1 -* **Alice admin port**: 8031 -* **Alice webhook port**: 8032 +- **Alice admin IP**: 127.0.0.1 +- **Alice admin port**: 8031 +- **Alice webhook port**: 8032 ## Alice and Faber AEAs @@ -184,36 +184,35 @@ aea fetch fetchai/aries_alice:0.32.4 cd aries_alice ``` -
Alternatively, create from scratch. -

+??? note "Alternatively, create from scratch:" -The following steps create Alice_AEA from scratch: -``` bash -aea create aries_alice -cd aries_alice -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/http_client:0.24.5 -aea add connection fetchai/webhook:0.20.5 -aea add skill fetchai/aries_alice:0.26.5 -``` -

-
+ The following steps create **Alice_AEA** from scratch: + + ``` bash + aea create aries_alice + cd aries_alice + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/http_client:0.24.5 + aea add connection fetchai/webhook:0.20.5 + aea add skill fetchai/aries_alice:0.26.5 + ``` -#### Configure the `aries_alice` skill: +#### Configure the `aries_alice` Skill -(configuration file: `alice/vendor/fetchai/skills/aries_alice/skill.yaml`) +(configuration file: `alice/vendor/fetchai/skills/aries_alice/skill.yaml`) Ensure `admin_host` and `admin_port` values match with the values you noted above for **Alice_ACA**. You can use the framework's handy `config` CLI command to set these values: ``` bash aea config set vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host 127.0.0.1 ``` + ``` bash aea config set --type int vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port 8031 ``` -#### Configure the `webhook` connection: +#### Configure the `webhook` Connection (configuration file: `alice/vendor/fetchai/connections/webhook/connection.yaml`). @@ -229,7 +228,7 @@ Next, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`. aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/ ``` -#### Configure the `p2p_libp2p` connection: +#### Configure the `p2p_libp2p` Connection ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ @@ -242,7 +241,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ }' ``` -### Install the Dependencies and Run Alice_AEA: +### Install the Dependencies and Run Alice_AEA Now install all the dependencies: @@ -251,7 +250,7 @@ aea install aea build ``` -Finally run **Alice_AEA**: +Finally, run **Alice_AEA**: ``` bash aea run @@ -268,23 +267,20 @@ aea fetch fetchai/aries_faber:0.32.4 cd aries_faber ``` -
Alternatively, create from scratch. -

+??? note "Alternatively, create from scratch:" + The following steps create **Faber_AEA** from scratch: -The following steps create Faber_AEA from scratch: -``` bash -aea create aries_faber -cd aries_faber -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/http_client:0.24.5 -aea add connection fetchai/webhook:0.20.5 -aea add skill fetchai/aries_faber:0.24.4 -``` -

-
+ ``` bash + aea create aries_faber + cd aries_faber + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/http_client:0.24.5 + aea add connection fetchai/webhook:0.20.5 + aea add skill fetchai/aries_faber:0.24.4 + ``` -#### Configure the `aries_faber` skill: +#### Configure the `aries_faber` Skill (configuration file: `faber/vendor/fetchai/skills/aries_alice/skill.yaml`) @@ -298,7 +294,7 @@ aea config set vendor.fetchai.skills.aries_faber.models.strategy.args.admin_host aea config set --type int vendor.fetchai.skills.aries_faber.models.strategy.args.admin_port 8021 ``` -#### Configure the `webhook` connection: +#### Configure the `webhook` Connection (configuration file: `faber/vendor/fetchai/connections/webhook/connection.yaml`). @@ -314,7 +310,7 @@ Next, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`. aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/ ``` -#### Configure the `p2p_libp2p` connection: +#### Configure the `p2p_libp2p` Connection ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ @@ -329,7 +325,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ where `SOME_ADDRESS` is **Alice_AEA's P2P address** as displayed in the third terminal. -### Install the Dependencies and Run Faber_AEA: +### Install the Dependencies and Run Faber_AEA Now install all the dependencies: @@ -365,10 +361,10 @@ aea delete aries_faber aea delete aries_alice ``` -## Further developments +## Further Developments In the next update to this demo, the remaining interactions between AEAs and ACAs must be implemented. This means: -* An instance of Indy ledger must be installed and running. See here for more detail. -* The commands for running the ACAs need to be adjusted. Additional options relating to a wallet (wallet-name, type, key, storage-type, configuration, credentials) need to be fed to the ACAs as well as the ledger's genesis file so the ACAs can connect to the ledger. -* The remaining interactions between the AEAs and ACAs as described here need to be implemented. \ No newline at end of file +- An instance of Indy ledger must be installed and running. See here for more detail. +- The commands for running the ACAs need to be adjusted. Additional options relating to a wallet (wallet-name, type, key, storage-type, configuration, credentials) need to be fed to the ACAs as well as the ledger's genesis file so the ACAs can connect to the ledger. +- The remaining interactions between the AEAs and ACAs as described here need to be implemented. diff --git a/docs/assets/images/favicon.ico b/docs/assets/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8c5a4d5b3ec784024720f4a537eb5f099ce3b2ad GIT binary patch literal 1150 zcmb`H+b)Aq5QVqIog0ZnP-j&|ix4V~Jl+ALyz<%IM>NJy{oGUhVAu}>1mPw8tLv( z8SC3R(kvN<)=KNl_*ruy-X+EKgv>=-Wv;hPikS(?_IGGpv+N}kvNY7Ac_ArG4$DR& z{tF{N5SHV7%JSzmzqFW^T&&aLj&d`yGSVw4tiulh;&_#bAc<^AQ^FyMg}{J>M*g}1Hj54?c;!Thx3R0q8P20Y+K zPk5d1pg;WH&x?Z*tDWs@Hw=743$d*6ojTTE6?o*s|GKmN;4KoLPeM2Zxt z2Bk;`5d`Vd38CB_-uHXY_n-Tn|DNaO0o<8AYi7-?X=~Op#!z3AhVn8c001-yEj42R zIQtTO{&b!U{JZS*s0jRr!c)r%0|25t#9xwt=SqG6Kz7&3)Y8XNPgl;~!%Ys(^Qh+DY-Ua2uX@_!ja#!G9uW#b!baGJOwvf_;>UpZ7?mB4&dZSDN^-b*q zUF_iw+)9d^*8}800&XZDBxit|t2;(6K!N*|t{nJG1dDNVo}&1;C~)5(GUT+>GvrkD z@J4Y;iAsyui%Uvz%D_d%rD2kAxG<*#R9sdJDk~-q6A_n|lZ47iNO1oB;Rd;RJD}x^ z)inO*1%6ZDzU$-TDJLf8@9!__4-@t9b`%qb!{K632{8!?5fDQJbI;ue86e`0;rSN@ zH5A6)+sV_%$-|wKND*o0;p?No4bJp05!^igA?uF$TTP(C!~&3>V&bAuqDZHR4)*`x zdHQ<0o-%i^7el$C+)(a57!X(dA6(D79zGtJyB_}o>3?4T9}Ga%>goN%<3G;D&Fvo+ z7$0>%P>jD7@*lA=ruRHiV#X+php)FiO5G2fCJ#{>PdQa@6w=4T+tkCu^r4yNKk4gH>4v<%+uYGoAV!C%Bgy| zdU%73!P&w79ga{{HT3pCJGp`{FvglHoCtMQX>qu;w1|YL_~~@@^yCok7$2m&Jqn?w zzzu3h)XB*~4i1x&go@kQiO8TNr9>p*k`f|tBpfDUXOFap*&`if?Pbva8n5PI?@P1; z;`qN@!okBHr14+VgNfVO%R(igB1jlqRz%uC5-kEJPD0uqChi~slYlwE;s2s$;Ozu@ zCDQfZsS;=908*5MqU>NOBuoVD0E3E1%A&vt!H{SXDU`H?gfvuI8if=m+Wx6I$!R%Z zz=gi|w>O!fy#9W2b>cj=AUUKx(K8gd?TIFVa^U_O?DQY>@xS8y_jv!iD3Iv?#Y+C- zj`2YI_#?ehHylCT{qIas?0=NN!`%<%{ckdOBE6AdR6==U6u8me9&VgSPfu4Tdn8d{ zF+X>Qzn%S`CF1n);QTMk`XBjVkbeJnJ^k7NK^- zG$3bna@BWMx^{Pis;_&m)#THc63!e-6^n~{=f0U{~`3Yrj{TUcj zMDc^8V1Ui#dMMouL(cXS50N*zt|ViD55wbGk&wgKg;yjVE zbEi+?ue1zFPMAtE(FH-9@4cuZtpBaCPX2zzcS07erIM z;Z8oT?#ua|GYy$m0wt*@hs@Yx&FHXnd3@j9Y&lV28dfE=FrmIC3&aU+D`e*!*#OFS z(B@h<5eMo9_SO2vLM6%DU*NSNg@=hv0lyY-8c7Efi!QG^P-x%z4qtfx?1x_b`wCsO z`IFJH-g4nd#~R$x`*0ISvGv`i8w6s);5NeNJ)(2;nyHYM`7)~me+&L2(t{FOXj z7n}(%6tB__WwL$kWez{Xnw&MMb#ozswE2At=PaK;8xVfI<^8I8X!{_SHbMryn_Xmp zt6QtSf-N|c6pwcca>2KmX2F<&4K00=9$U0fa?Y9XcFL|2c|4EBK`HNK*664ULJ-tf zf+*xg<0BFgXb_}09CiL7J=O%MFr4qpj@8pwD4nygX$X*pTWqwhL>|5I9U-l!?7E^(>^ z00f!y4C0r!Y?2CEZXbpISp9BKc0VIhBqVWMlqBbo=RJJcgcrcd(j@>i7kYlih^q{N zgo(&$Fbk#4(>cW|FIxkz2cGQr{3(i#?tqoSb~y zi>Y+qz8lVEebM$$? zwD}bTM=l2Z878U|065E(G+$!24q09mw75o!+~H`&Uu*ik*c;IVaT_@!tq3dQ4MCVr zYV=#sgVib+71(igud}4IYhC8Y;KNy?{!I{YnK3xGZIxZ7*)e&>ke3?$kr?-k0#PEm za$x?iHzSIsLW|2fVYZJs!Yvmrhd$4bFM@%#LL_HBv!ByPTDCZs_;c~j0gup2U>l8o z9_6u0U^8zz4FP;OcrC^Frk!8E&*o!>C&TW|l!AabaoGT%xh2ADLK81UV0Y$OYz<-& z=ecpNAfqDCS)qXPZw4l~y3cTbzC~R{{9uD;m3e=4u-(!Y7mIk1%j4twUh@ZG!Ny(>@ai5eo3fo@EMG41FxTr)l|%oCs;Y z07f|3M_I2SX>{th@U0s}AP_)DAqYetNL5Y@tCo+Pf-FTrho&{tOkISyrD&XLL>3Nt z34HA76>N7~AFl``?k0dgSBYpwn&|`>>LL*kKA`r1vYE>cm+zd5(OXg`!hqsva2~3r zbf}sb`%^&9HE`GzBQ9T%JN7tDnw|)3E&;>v4+WGi*TRIT8!HhMZlVqn3o3miQQsy` z1OWQ1;7r%?@MpRya_5PF=Ec)d>S|d{Cgguj)0#NV;)H7hkc3l!XA3AZt7^795g%v{ zPAWL_M-V1t-wj_FdzX9))V~Ch^$@_E>Ijex0Vx#K{GBOm@BD|PKvZn)U>)h{=p02* zn$u4w2>{z$`w zAZ9aRIt?es%MhuV>DQQYy{n9#+`X@`rV%HTCwn@V@qHO>j#T8typ@zSw89$E6$7 z4^jIidu#P+CsPMH{W$n=e85Tbw+OR0)p-YzzaIHpEOqpy&nexS27l}6);Sm!cF`q` zCl4{2wC9>HqWxr4s-GW(A$$XG3M%ok=;S@6(5VCy@1iVePotcI?_sUap^YQjLT<{% zQf+Ej)QQpQa4~0mj@C|JrT#6};Jhi^{+_CklhDb5v=vVl99BO#rCmds8?TT_z1}+g zYx;3}=HAeNdFTUF3Y@l}Hl}txmv4|iZpAeBSo@Wo`J?y=4SLXX>E)IN8cQg4_tn~A0dN1Q6KJnRK|1AJ{f%`@NRUKy;cx`*TalDhibv$kZ zn1nm6wK8RO^-Iaf_zR_@P@kXddW9MbVkJX2JLwc64&p2Qn9JLrXhU`c8 zjS#&RfbG6A2`juOGP+inw4QoBqJxUFpQCB943CRzt}=nF_g(jUtF@3eU}o))VO-J3GxJR*dC zOtYCZLen}5Cr(?KttopRFk>?V-9;AjC>{;mct8oDKleJr>W3@kIQ!DD?q60CvS2?# zsPyhO6(#vFVaa^wEt!RMq1S&)*047eo3bi9CXn(AZd0wln+Qd6olN@m&HXw|F1UFf zCe%vbNxrpafJDqq;V$PS1;ZlXo@>FN;E+Uab`{of&?fcXe1!)w228E;@Vo9#2-0N~ro-_Apxm%eP)) zWTGBcT^@v6sD#R^uQZZ>kXXx#K#^-AA>i}^F_d=Yw6e$il(soy(R zr7DU8x3BU)lWgJK*7xXZoa~jtlU*OXB~{%vI^XDwr$yw#X*tU(oDaO@Ii@T+_ae)^ z$-PT=58TQ=ChMvQGzGpPlK(wgS|WjwH8Jn3U6#?kgX=Mx;F_L4;y~4w z4lXxXEOzW!=SqIyVA`BEa|8?bIYLWJrgBq-(QU$=uBL^aKU-CY_SaI>_diq@b@$#K zc6@MlXz|w0`^g-7(3@kmS+k+3%O^G6yj7va z27%gnI~N!4O}T5S2ff+y--+0>7CFf^qp3@@VB|(blCt01d}=nf+i-7j?`g=(U*o$s zXL+Xt@qR}GUw6;U^4y5jR9^!EOM@nA2B{vRY)f0}#O*!4I6;mCoPu7RU7G@YgpTA3 zce4+}tJr2lhi4RVIhe`wJESR|MNESICiQRS=fmZwulZripNBE*H+9#tx1aa7>b!tf zlwXkM8EiVw^HIz{@L+0*eh6RMus4ayw6*F9b4;UHe{m5Z_>sqTQJw?ueiMH@n%@y9 z7S*?5ZgAA1(r6v#I&C62r{wZ(nL+abC1&XNA6f&Mn~VeA(ki)4B`2=IJd51-Agxk$ zq_S3Aby>GIJYMCdvq}1-kIQN&^SA!$=iWBk7flgeCHf2jCy|84R0H$Z zkfU;+aexY6<*k_ab&rw$e14%&{IJ-{+<3pzizH5(^^^D_y?_-LeBaHiKkj#ji*dbo z2z6C-x<57&Hs8BGi{5-PdUStddOo50!WQ`y`%f4*=&p6WxwWuVNc-55;%#v8ZY^6ZeYmurbHeabAb}vvh6^U_L;rZK6`n+dWv#PJ@dt;k20^Q;_4c=_`wksf zMK>^>1GC5WYxP$*1hUTRZ092THVtpLuWyGa{P7EmyR0470IHqi> z%fmxHyGJ(}Q|^ni);=g`Ra%ICIcH(aM6rCfQoPA~siAE2^GH|i6^{9Scde5ec9uYA z`4168(<3TaQ-RFUx~PzRYn_81IrTZ4vD^z2IC#e9k$Lv?&&0^8jT*OFtfErQy2)|y zDph_p3_mnluQpUpfRuQu^}) z8R?P>TV>qt42m*)8rUUU@C~BU%UoY!gn}38nqyY7Jdx<4n{F#TaTo;q-hgjgUWw=k zQTp+Ay$qvtb6+MlRriO?5K*AL)g>>vY>xzFQPl;5G+WvYsO35tCrG72Alai(l^r54qri_I_aUm zO!-f8;blxF>s~nDryPHb7IB;(-!fdDdyZDba|AiGSu9L+2;@9u;Asot3k$^=%6wMq z<{p(5DlY$J0dc4Qo;5TTTiSQIF>oW+FXX0{p@^F0XZ(%OMM74v>JAs1q};8i_YYnc zckFzF?=>MGUxYfP?<#NS9uiLEj6zcA>D@WfUToQ15)u|y<$)CYZLWSsJv-p*fDcE6 zs+4xU7s_4~%;(vEb{u`lfAf~Mm3X&Ctj${*2AGO>X|l((*nDN$n>R^5 zgaXgVVG{RVn?ry>`GGUC#W`Zqw7e~)durC%yWGAYdNSYl5g#pLl_nX8d=A+bZIk+OYjQ_xkMO4}ri8*_>A`L2kbVkHuzS ziND?(eV7}3WdYfxJBVVzDmqzC|B32~cH#tU08Qp}`Y?o{SsB9}shuYcs|~BorH#Tf zaX|0%)OTY^uB z)7=;DJUQ$8#kj@I^0t@A`99UrLM@&X#TAY7juI+ZXIMe(6GZ9&3!lg^MXB>#qUR{@ zOP6#NLg#;-4l2B1s~~+JQ<*gcfz&IDy4AvbO@?Bo@HPrJ1IMB zW-Y&ziQ$jjjd>S+BYCdKN4fx5!}i zm-Y|M>o{5mGp*RS)aDZijG0zQ^a*vaLADou#XoB_@CPP1iy&TP>otv!KImZnm^&7= zL$bf7bOY^|@dHzhJCc2Y>lJ)V5N(()XB z(W1($awR!p^;*tl;~IZBQ~H~$l40{@lF~Ly=dZ_67w(h~L{wf!suaWs>yK~n@L4wc zzkW}Viaq=LFiQzmde!ip&=UFiTW$o!u<9tAALkXoZESdQ#Ht<2VM9NZ!aw6$jygqd z(sJidmvkSVXegk-VW{5vgEz(?R)>4=9s4xC+pMCIrEx$ex!t1c%%^XWLvK~FBk_mQ zM${MUjBB*6p1%X`wgHWca@?vo*7pVWN+T8sHwP;sHLiyl`p0oJ)QmNDA@SEfm>ur^ zG#L;G#r_yhYX8rv5 zE15Tk;DktHGFjT)k+-mJ4s|xhWcN2BL)+vk1BAx*zC}z@j`t#eTmq#_y0fxW!hVa; zPesu*LVLCBr6;v&ZKzMlnNJt;_}}|u73CHJrfj|o9AEs?ettdITJ4*h6Q?ZM*q&4U z#al;wk)UZo7)7~mt1&yKyF!p@s#lDBzGQK*4m1y$T&YQq7jh*X?XKm>&&4?2ZvLrv zi)@gbz-;tFoBix(7})+v-wg>S6^*^0Otge|b`}QWU)gM2$sItUe`HN__xL_D2@z)5 zEPEkcN18=av&ZhvV)BS8ptn0|OAF4is70o0XLlBil$><1GDfBPE@g}Z(sNXUF@Dwd zjK^i!`eSknUpd-^+a09^4<%oT%1?wNN+gi1tO(1Hh6G`KLTE7LEdK*gh$5K7j%l{U z#gBq$zb1#zmwBu-)0Y{;e6?+b-&(x5RcWo3CE-QQ+M(^Gsp#`8MCpU)^ET^wC?`>c z{eqQjWyJ}Oh3{LT_O(b7kC+gfqffC{b-zmc1F%7jR6N}GBCGmJ5$|e{;&ul=(H|jT z6T1CN>Z+xJ@AanxwV*+2Up~()=1L*T6YFQ^$38Id$C~-q`XdSTCC()Ckw$BE##J>! zp5BPxxC5>I2H4I~zTBjdZm-j}(eAn>q(V=x#p}1jXn|;DT=gc0n&_R*SIdLR%3YO^ z2i8HIaYQNK#$FrnGJ82o6}?|Wryhp5Lc#3LWR)OtKJ%GJ9cgBX=ri3cS+XLQh7frt z#@`~_J@vgv;mct2g!LL*fwdarB!uQ{h$~O`EBcP`$jcQCi6WmeORd)cbm1U zB0NM#yWRW!jkK$jDj8`Feh5MO$++E}W%32}87+ql`S9lyWj;_n@l|_+HpS+ecg$Jbinrdm%EuC>nm&MeIo`i9Ju@CO2h1fTUvgDaQ7)RRRtGLja& ziMXtxbW`T9ZQmu%3SrVQ>Y6ay(kEcAz(ko4YFtxCYDqi^faC&Jj_RWihIduzNzG)^1IC82M_zj)h-!DNs|J6y}gv})$8>|_c@<~OOXBuoP*kB zPgZmal$yHg@ih~^1QIIof-fVy)TCN5Ol08}>gg`@pTi?sz8{EUSRbo`k@6>#cw`Pn zZwv}mzGC!3myI;NFixNiZvsH?nW<%^Zx!>s>0)p0Cn_!g1n_~1w?_f?_%tg1Ho_U#MH?)EO!W4 z<_SL21q}r3r<<(-NqLxZsj3O2Fr_2tK_3PEflj`8VXlHs@I=k_at@|`LL4ypOEGn% z%F_Qu+_D1nWt|r0CYFev=r=7VHCVs58Ql5UKkuFKH+=b>g18gQQo|Zz|CE8P&Mrn; z0O-nT*^>kS*!S3&u0pOG)%*}o_wAM%b{JtPr~bOP79!J%>*T$8-?0x0eG35w$Vsn4 z?bhCMNUjoLhXpp?rBuEmPWen406b^U~eu2+r$_x3RjVM!Pidifgj_Rwh)9y3?Wup*$v*b1IUBvp?_-a7C za~tbtL-xSdOXY#5z2iBHIa*tUmLak{7W53ucc7vy$@r|m6P40#_GWBS!RFZ2+EtBM zr10eZS{KbYB=wi4GCsJ~&s3yT!*jI2=wU9gtqrxA;kE{LlM1kNIWD}bv>)*tv+5GD zsC}=A;&qzP9QDIeb#*l}%zf`xQ0$!AV8=u8y zFm@FxJA+mNT94U}9GBh|-Tv2i^ygjYQY@=}<}B}Cwb*IV^TR5_7e4SrrFHWoWCHP& zajy?&ofBCvq!-6u+uEaMm<0O4i5(g&aRNY!Az}=jK;j|f4Vo?F zI7zdC56wMx%}gr7-$e`IqyDfUrXfwm`qO)9Axxmf3e7;KqTtTLpA8IMqrAEuwbLXZxy<3 zYFXS~)WCe8O!%GM*xm!o%NNmG#hb*rwXSgY3{jkl=m1B1lh}?u>GW;_ zQxM`6s6A7#j<5~)yoSDFl=_LULYZ_d4y<*6@FEq$lp3QoFU?tjuLgY)#7GY&n<~nl zXcFN*>1VoK(n>()N3cM^x`htV9W0cADU+F){X~~^FKzrH7dCUv{uCz)=-zTA90&DZ zgSLTTM@IvUzER^~2CtwHPQtifu}V$L0HDaHA?w_+{f!3XT`h57l5bYV)#)cY(t1iM z*}kozLs24@i;Mukcw8e@pshQ1rS}!H#d;6%#HMJ&(V@<_n-l2$Y?J&ebM#!e(_^>k zCP@4l@%PW{(8L-k9;^hXt@>$%`^~+^m9=5F_~Xw4Nxk82p|`1d3MPR< z5mKv!jkkf$a>VLH?$%ordGq}oj67I?d(n>rP$MMjNVHNG#IgQG3tR;?q~-7Im(Lph|2|GO!on$2zv@UBW%24 z#T!|a9pUu@MR=HD+@G5@*?)&rwmB(Ahn}B@N@%FG7ioKeI5#oB3IXvEwzMoJ*T*eq zt%X9FhGKiLiTv+ahN!}BB0e}?p$)H%FslTm8{4DHvf{-Np0E)$V`)DJePn( zv6GjfF3OtP%33H~0oKwl~vq_RP^T1<{sxC@i+GNZ8ld zskeD5(0&r;ovd8FkVS)V)p4b}3iobV9D~sKWBTiB>F+w@Kil+I#qSHuejtZoNR-zzeUGgx9m5#VZUewlf zT**apnOT#+S5?1F55y#N6@qajOE#*VqU#%%;|Su|*Y@I8lv-Dbd8>^OK$YxC|6uos zhID-I&5W=W+i8vU;OixPYJniu)B_5hZ@KfnCO6;7dYEuB1a3EYeJ|?F<}1}q62K$)T#2h}381do5F^LQc4jy| zORflopod?EnoG-7JLsmS=}@JEH-tyNzUIVov`wT;gwoUdUATOFr@_{RBb*giNA)}_ z;=NSW*3*rg*sqP#LggXrsc4l;$wYbSB3qedC`xZ;kFr~2ZIStD>`K{{;V@v9dB7y^ z6p;pZj47=buPRgX{bH^)NK+TyQYccj0+1aP&1foX^`~V`3OCrW();ekdQ4l#`=JS1&wfp!bov zoR{O=2KQB_N1JC^xuF-(HMA$9m=0g+AWdZ-iqcyyPj7wLO9)_H@4XxW zJ#1;xdfaUhx9_fRU|72f0fZylBYfeX93MJ$3k0dv`-+22ZX@5c!}O*tu+w;l6`0nM zGcdH~$Bs60qRpckdmbLfX2|2`TJ-k!9%d;-6qzN94}Ob8Jc2z(7@KXb5>Q}gk4twD zJojy~Z;c%}Z7p7cV&PjzD;WNJq zlbcpk)n9><5Ys{mv>72~&xaRV7&p1<8Fgt`9#N}Z<*dEgRigLogZ>bhP8xF#diUN& z>TmNQ)2a`Dtk0PvpNtB=!tG-##ta};_XD_|{!u?_Y^A~ln@j7nS)K=9&eyX>EpYTw>7x~`-9n!zIM(>>B?iriW^hm9>04#PR9F}Sh@ z*KiU>)ft%|Ovcpw_|0#gc^DxQxO~>^ON{~MWdp=4qhd^Dx^^Aa@sk6RiO$ z<|D=>U1crf5W^=A2l8+A^yN%OitXD)5VQncztj!M#t3v>kba~2axWF^Eu}C+mvdFM zjN`rBHMo?L@QzCqYo26Xa%|ywa^k!Sx$tVlZLtd0r_)|372RAG&e@S)=i|ihS^X9; z@`e3^m9{{Bp?Y74z>eXmfGyg+HV>w?`A zx+Su7hvz;E8rsGRzuL3~gM?Pblh^D-!Ze0v;Sobxdzgv_M05wDTTHv&te&o`1VQu; z2Cyd1!8mF+`8wKgO$*dXtxHp1FQZ%EA_tEl*s;tfoo_;AEyna$8uj}%u_h0L*)2m~ zXSs7^S2kqr`nA;y?D$B%CO|W-;se5_M_t6+_pl=_@xyl{v5MdoH|)MIpRd0D-G_?K zAG>tAYS$M6pTxbVOaa;-?cv2>WhzSB=KV^WDYRvDYtFMd1TAmppS>&X`J~;}Q8IrD zQ+|6!U6=(s)q%IC?#w5+J*tqH`QGR+AE}GK__Q^U;ZCupf5(bse&wI6wPjKNiQ<++ z+m(F(ymj%3tgzML`SAqqPxd9fwQn-!$Md3jlwJg7-;-Blim|D`vbA0%u{SGsZr(9( zoxV{q`h$#80lfCCTNHlxSxxY&diQIsDkRuH_Fa3wAiAjl-czhk?CjXjBTOVNkM!17 zb@+K4*UO;@$0Hmct7dmFedKMyEM8$dNefQ2!r%O(6na#T80oaQlzOZc2qpqeXV)!Y z*}p2`LHKTZ_5De~>*e$Bjc6Q?ClWK{ZVBN#qfwHo6myAAytc2mQMgEl71g+l)a+KLor4I6vf ziuZTKpRKv7IJzHw)}zELeBhW*4W>fm?4i$i^uEe6+5B?oO3>*l32}iDdf>GR8oJG_ zS2O&wN7D{Bmvc&c_oglQ<#@ZmV^egE*}<>9$U9mI&y9A5JDsf1e32zPD#I4H48c^hqeF7%MDhl=wTxd{OwC-rbU^<;W^MfU)#Ra zLsBasi5n{VydCs&T(5myPM9ie(*oZt5y7PFczHoEtoSZZSZJ>(hOKz1>a)W7c~bbo z<%J1N8YP*PL0_<4i32a$72d^=dpft=d!7#o=?`G(%&gKkSPjg8Gj9*>C2fD`a4XC6 zb+kWbd-1b5yKhyw(F|mz?)zg^d)Ad9=lsHiyGQdViq^68CcdmH_=Sl?-k*tn@x1#L zuQwikR=Jp>O{OsW4r0eX=P#ARGod&#MdTH+rd#yp$k4CewRdYa7j%<5$r4=TRdU1P4HsM^ zcaL;KeKFba9Q&m?!hH_7|Gwn5p5bcXM9rd=zx30Te)fQ^I;p7ow%Y7iVh5q?*=%ZL z8l8@=sc)dRu61RuSboRDL#e{`qvzmdO6K&J&O51@V-5-DET1Vc3=cb5h2%X1%_L|w zC{441|u%#J_p zos6pxj*W_k8*916eftl}3$R604Y~2FbFi8!dYsSbN3Rt9#*_het{jJ!rHZ{fiG7$` zOIOKMS=J|9Rihbo7;28Kqi!tle-SG=#_B6>Y=B3q$$dMLk$Y2-ht8$e^PXQ-M=oz7 zLV4#S=W~C!???vVC2NmqJX=Il(eeQdpWS4et9C)?gJ z;fVZ`*qV^HVA2Mrs%3;W_j&L|Djd1N#j2a^N%~ZoMlCbDQ;uoD4`v+|c;zS?6tnAt zcEL*=CqcV1Q!bj!WYYa6SVEZ3eq3;I@$NGkrH@g~6jU*#)xjsvzM71`P4OUYM2z** z&M}Scsu--|w~lR}uk#CB4rvOhNXxhVef2~`f-;d-|L^|~0CZf$Fe#n(2LVpv+0W_c d->!QeoMfD*4dDNNBa!$9p{}o1u44P({{hR1pCteQ literal 0 HcmV?d00001 diff --git a/docs/build-aea-programmatically.md b/docs/build-aea-programmatically.md index 4b9afdb69d..7f72487206 100644 --- a/docs/build-aea-programmatically.md +++ b/docs/build-aea-programmatically.md @@ -1,16 +1,18 @@ +# Build an AEA Programmatically These instructions detail the Python code you need for running an AEA outside the `cli` tool, using the code interface. ## Preparation -Get the packages directory from the AEA repository: +Get the `packages` directory from the AEA repository: ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/packages ``` Also, install `aea-ledger-fetchai` plug-in: -```bash + +``` bash pip install aea-ledger-fetchai ``` @@ -36,7 +38,8 @@ from aea.helpers.file_io import write_with_lock from aea.skills.base import Skill ``` -Set up a variable pointing to where the packages directory is located - this should be our current directory - and where the input and output files are located. +Set up a variable pointing to where the `packages` directory is located - this should be our current directory - and where the input and output files are located. + ``` python ROOT_DIR = "./" INPUT_FILE = "input_file" @@ -44,15 +47,19 @@ OUTPUT_FILE = "output_file" FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier) ``` -## Create a private key +## Create a Private Key + We need a private key to populate the AEA's wallet. + ``` python # Create a private key create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) ``` -## Clearing the input and output files +## Clearing the Input and Output Files + We will use the stub connection to pass envelopes in and out of the AEA. Ensure that any input and output text files are removed before we start. + ``` python # Ensure the input and output files do not exist initially if os.path.isfile(INPUT_FILE): @@ -62,7 +69,9 @@ We will use the stub connection to pass envelopes in and out of the AEA. Ensure ``` ## Initialise the AEA + We use the `AEABuilder` to readily build an AEA. By default, the `AEABuilder` adds the `fetchai/default:1.1.6`, `fetchai/state_update:1.1.6` and `fetchai/signing:1.1.6` protocols. + ``` python # Instantiate the builder and build the AEA # By default, the default protocol, error skill and stub connection are added @@ -70,6 +79,7 @@ We use the `AEABuilder` to r ``` We set the name, add the private key for the AEA to use and set the ledger configurations for the AEA to use. + ``` python builder.set_name("my_aea") @@ -77,18 +87,21 @@ We set the name, add the private key for the AEA to use and set the ledger confi ``` Next, we add the `fetchai/stub:0.15.0` connection which will read/write messages from file: + ``` python # Add the stub connection (assuming it is present in the local directory 'packages') builder.add_connection("./packages/fetchai/connections/stub") ``` Next, we add the echo skill which will bounce our messages back to us. We first need to place the echo skill into a relevant directory (see path), either by downloading the `packages` directory from the AEA repo or by getting the package from the registry. + ``` python # Add the echo skill (assuming it is present in the local directory 'packages') builder.add_skill("./packages/fetchai/skills/echo") ``` Also, we can add a component that was instantiated programmatically. : + ``` python # create skill and handler manually from aea.protocols.base import Message @@ -121,13 +134,16 @@ Also, we can add a component that was instantiated programmatically. : ``` Finally, we can build our AEA: + ``` python # Create our AEA my_aea = builder.build() ``` ## Start the AEA + We run the AEA from a different thread so that we can still use the main thread to pass it messages. + ``` python # Set the AEA running in a different thread try: @@ -138,8 +154,10 @@ We run the AEA from a different thread so that we can still use the main thread time.sleep(4) ``` -## Send and receive an envelope +## Send and Receive an Envelope + We use the input and output text files to send an envelope to our AEA and receive a response (from the echo skill) + ``` python # Create a message inside an envelope and get the stub connection to pass it on to the echo skill message_text = b"my_aea,other_agent,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello," @@ -156,7 +174,9 @@ We use the input and output text files to send an envelope to our AEA and receiv ``` ## Shutdown -Finally stop our AEA and wait for it to finish + +Finally, stop our AEA and wait for it to finish + ``` python finally: # Shut down the AEA @@ -166,127 +186,125 @@ Finally stop our AEA and wait for it to finish ``` ## Running the AEA + If you now run this python script file, you should see this output: - input message: my_aea,other_agent,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello, - output message: other_agent,my_aea,fetchai/default:1.0.0,...\x05hello +``` text +input message: my_aea,other_agent,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello, +output message: other_agent,my_aea,fetchai/default:1.0.0,...\x05hello +``` +## Entire Code Listing -## Entire code listing If you just want to copy and past the entire script in you can find it here: -
Click here to see full listing -

- -``` python -import os -import time -from threading import Thread - -from aea_ledger_fetchai import FetchAICrypto - -from aea.aea_builder import AEABuilder -from aea.configurations.base import SkillConfig -from aea.crypto.helpers import PRIVATE_KEY_PATH_SCHEMA, create_private_key -from aea.helpers.file_io import write_with_lock -from aea.skills.base import Skill - - -ROOT_DIR = "./" -INPUT_FILE = "input_file" -OUTPUT_FILE = "output_file" -FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier) - - -def run(): - """Run demo.""" - - # Create a private key - create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) - - # Ensure the input and output files do not exist initially - if os.path.isfile(INPUT_FILE): - os.remove(INPUT_FILE) - if os.path.isfile(OUTPUT_FILE): - os.remove(OUTPUT_FILE) - - # Instantiate the builder and build the AEA - # By default, the default protocol, error skill and stub connection are added - builder = AEABuilder() - - builder.set_name("my_aea") - - builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) - - # Add the stub connection (assuming it is present in the local directory 'packages') - builder.add_connection("./packages/fetchai/connections/stub") - - # Add the echo skill (assuming it is present in the local directory 'packages') - builder.add_skill("./packages/fetchai/skills/echo") - - # create skill and handler manually - from aea.protocols.base import Message - from aea.skills.base import Handler - - from packages.fetchai.protocols.default.message import DefaultMessage - - class DummyHandler(Handler): - """Dummy handler to handle messages.""" - - SUPPORTED_PROTOCOL = DefaultMessage.protocol_id - - def setup(self) -> None: - """Noop setup.""" - - def teardown(self) -> None: - """Noop teardown.""" - - def handle(self, message: Message) -> None: - """Handle incoming message.""" - self.context.logger.info("You got a message: {}".format(str(message))) - - config = SkillConfig(name="test_skill", author="fetchai") - skill = Skill(configuration=config) - dummy_handler = DummyHandler( - name="dummy_handler", skill_context=skill.skill_context - ) - skill.handlers.update({dummy_handler.name: dummy_handler}) - builder.add_component_instance(skill) - - # Create our AEA - my_aea = builder.build() - - # Set the AEA running in a different thread - try: - t = Thread(target=my_aea.start) - t.start() - - # Wait for everything to start up - time.sleep(4) - - # Create a message inside an envelope and get the stub connection to pass it on to the echo skill - message_text = b"my_aea,other_agent,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello," - with open(INPUT_FILE, "wb") as f: - write_with_lock(f, message_text) - print(b"input message: " + message_text) - - # Wait for the envelope to get processed - time.sleep(4) - - # Read the output envelope generated by the echo skill - with open(OUTPUT_FILE, "rb") as f: - print(b"output message: " + f.readline()) - finally: - # Shut down the AEA - my_aea.stop() - t.join() - t = None - - -if __name__ == "__main__": - run() -``` -

-
- -
+??? note "Click here to see full listing:" + + ``` python + import os + import time + from threading import Thread + + from aea_ledger_fetchai import FetchAICrypto + + from aea.aea_builder import AEABuilder + from aea.configurations.base import SkillConfig + from aea.crypto.helpers import PRIVATE_KEY_PATH_SCHEMA, create_private_key + from aea.helpers.file_io import write_with_lock + from aea.skills.base import Skill + + + ROOT_DIR = "./" + INPUT_FILE = "input_file" + OUTPUT_FILE = "output_file" + FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier) + + + def run(): + """Run demo.""" + + # Create a private key + create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) + + # Ensure the input and output files do not exist initially + if os.path.isfile(INPUT_FILE): + os.remove(INPUT_FILE) + if os.path.isfile(OUTPUT_FILE): + os.remove(OUTPUT_FILE) + + # Instantiate the builder and build the AEA + # By default, the default protocol, error skill and stub connection are added + builder = AEABuilder() + + builder.set_name("my_aea") + + builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) + + # Add the stub connection (assuming it is present in the local directory 'packages') + builder.add_connection("./packages/fetchai/connections/stub") + + # Add the echo skill (assuming it is present in the local directory 'packages') + builder.add_skill("./packages/fetchai/skills/echo") + + # create skill and handler manually + from aea.protocols.base import Message + from aea.skills.base import Handler + + from packages.fetchai.protocols.default.message import DefaultMessage + + class DummyHandler(Handler): + """Dummy handler to handle messages.""" + + SUPPORTED_PROTOCOL = DefaultMessage.protocol_id + + def setup(self) -> None: + """Noop setup.""" + + def teardown(self) -> None: + """Noop teardown.""" + + def handle(self, message: Message) -> None: + """Handle incoming message.""" + self.context.logger.info("You got a message: {}".format(str(message))) + + config = SkillConfig(name="test_skill", author="fetchai") + skill = Skill(configuration=config) + dummy_handler = DummyHandler( + name="dummy_handler", skill_context=skill.skill_context + ) + skill.handlers.update({dummy_handler.name: dummy_handler}) + builder.add_component_instance(skill) + + # Create our AEA + my_aea = builder.build() + + # Set the AEA running in a different thread + try: + t = Thread(target=my_aea.start) + t.start() + + # Wait for everything to start up + time.sleep(4) + + # Create a message inside an envelope and get the stub connection to pass it on to the echo skill + message_text = b"my_aea,other_agent,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello," + with open(INPUT_FILE, "wb") as f: + write_with_lock(f, message_text) + print(b"input message: " + message_text) + + # Wait for the envelope to get processed + time.sleep(4) + + # Read the output envelope generated by the echo skill + with open(OUTPUT_FILE, "rb") as f: + print(b"output message: " + f.readline()) + finally: + # Shut down the AEA + my_aea.stop() + t.join() + t = None + + + if __name__ == "__main__": + run() + ``` diff --git a/docs/build-aea-step-by-step.md b/docs/build-aea-step-by-step.md index 52c18d83b2..d7adfe851a 100644 --- a/docs/build-aea-step-by-step.md +++ b/docs/build-aea-step-by-step.md @@ -1,14 +1,13 @@ +# Build an AEA with the CLI Building an AEA step by step (ensure you have followed the Preliminaries and Installation sections from the AEA quick start first): -
    -
  1. Set up your AEA project with the CLI: `aea create my_aea && cd my_aea`
  2. -
  3. Look at, then add the right connections for your use case: - `aea search connections`, then `aea add connection [public_id]` -
  4. -
  5. Look for, then add or generate the protocols you require: `aea search protocols`, then `aea add protocol [public_id]` or `aea generate protocol [path_to_specification]`
  6. -
  7. Look for, then add or code the skills you need: `aea search skills`, then `aea add skill [public_id]`. This guide shows you step by step how to develop a skill.
  8. -
  9. Where required, scaffold any of the above resources with the scaffolding tool or generate a protocol with the protocol generator.
  10. -
  11. Now, run your AEA: `aea run --connections [public_id]`
  12. -
-See information on the CLI tool here for all the available commands. +1. Set up your AEA project with the CLI: `aea create my_aea && cd my_aea` +1. Look at, then add the right connections for your use case: + `aea search connections`, then `aea add connection [public_id]` +1. Look for, then add or generate the protocols you require: `aea search protocols`, then `aea add protocol [public_id]` or `aea generate protocol [path_to_specification]` +1. Look for, then add or code the skills you need: `aea search skills`, then `aea add skill [public_id]`. This guide shows you step by step how to develop a skill. +1. Where required, scaffold any of the above resources with the scaffolding tool or generate a protocol with the protocol generator. +1. Now, run your AEA: `aea run --connections [public_id]` + +See information on the CLI tool here for all the available commands. diff --git a/docs/car-park-skills.md b/docs/car-park-skills.md index 7fffa1bb1f..8217a90505 100644 --- a/docs/car-park-skills.md +++ b/docs/car-park-skills.md @@ -1,8 +1,9 @@ +# Car park skills The AEA car-park skills demonstrate an interaction between two AEAs. -* The `carpark_detection` AEA provides information on the number of car parking spaces available in a given vicinity. -* The `carpark_client` AEA is interested in purchasing information on available car parking spaces in the same vicinity. +- The `carpark_detection` AEA provides information on the number of car parking spaces available in a given vicinity. +- The `carpark_client` AEA is interested in purchasing information on available car parking spaces in the same vicinity. ## Discussion @@ -12,9 +13,10 @@ This demo allows you to test the AEA functionality of the car park AEA demo with It demonstrates how the AEAs trade car park information. ## Communication -This diagram shows the communication between the various entities as data is successfully sold by the car park AEA to the client. -
+This diagram shows the communication between the various entities as data is successfully sold by the car park AEA to the client. + +``` mermaid sequenceDiagram participant Search participant Car_Data_Buyer_AEA @@ -42,18 +44,17 @@ This diagram shows the communication between the various entities as data is suc deactivate Car_Data_Buyer_AEA deactivate Car_Park_AEA deactivate Blockchain -
-
+``` -## Option 1: AEA Manager approach +## Option 1: AEA Manager Approach -Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. -### Preparation instructions +### Preparation Instructions Install the AEA Manager. -### Demo instructions +### Demo Instructions The following steps assume you have launched the AEA Manager Desktop app. @@ -66,151 +67,152 @@ The following steps assume you have launched the AEA Manager Desktop app. 4. Run the `car_detector` AEA. Navigate to its logs and copy the multiaddress displayed. 5. Navigate to the settings of the `car_data_buyer` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11001", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9001", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9001" -} -``` + + ``` bash + { + "delegate_uri": "127.0.0.1:11001", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9001", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9001" + } + ``` 6. Run the `car_data_buyer`. In the AEA's logs, you should see the agent trading successfully. -
-## Option 2: CLI approach +## Option 2: CLI Approach Follow this approach when using the `aea` CLI. -### Preparation instructions +### Preparation Instructions #### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -### Demo instructions +### Demo Instructions -#### Create car detector AEA +#### Create Car Detector AEA First, fetch the car detector AEA: -``` bash -aea fetch fetchai/car_detector:0.32.4 -cd car_detector -aea install -aea build -``` -
Alternatively, create from scratch. -

- -The following steps create the car detector from scratch: ``` bash -aea create car_detector +aea fetch fetchai/car_detector:0.32.4 cd car_detector -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/carpark_detection:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- -#### Create car data buyer AEA +??? note "Alternatively, create from scratch:" + + The following steps create the car detector from scratch: + + ``` bash + aea create car_detector + cd car_detector + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/carpark_detection:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Create Car Data Buyer AEA Then, fetch the car data client AEA: -``` bash -aea fetch fetchai/car_data_buyer:0.33.4 -cd car_data_buyer -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the car data client from scratch: ``` bash -aea create car_data_buyer +aea fetch fetchai/car_data_buyer:0.33.4 cd car_data_buyer -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/carpark_client:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` - -

-
- -#### Add keys for the car data seller AEA +??? note "Alternatively, create from scratch:" + The following steps create the car data client from scratch: + + ``` bash + aea create car_data_buyer + cd car_data_buyer + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/carpark_client:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Add Keys for the Car Data Seller AEA First, create the private key for the car data seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -#### Add keys and generate wealth for the car data buyer AEA +#### Add Keys and Generate Wealth for the Car Data Buyer AEA The buyer needs to have some wealth to purchase the service from the seller. First, create the private key for the car data buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for your car data buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` @@ -229,6 +231,7 @@ Once you see a message of the form `To join its network use multiaddr 'SOME_ADDR This is the entry peer address for the local agent communication network created by the car data seller. Then, in the car data buyer, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -239,9 +242,11 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + This allows the car data buyer to connect to the same local agent communication network as the car data seller. Then run the buyer AEA: + ``` bash aea run ``` @@ -251,10 +256,9 @@ You will see that the AEAs negotiate and then transact using the Fetch.ai testne #### Cleaning up When you're finished, delete your AEAs: + ``` bash cd .. aea delete car_detector aea delete car_data_buyer ``` - -
\ No newline at end of file diff --git a/docs/cli-commands.md b/docs/cli-commands.md index 7a698bb936..900968d891 100644 --- a/docs/cli-commands.md +++ b/docs/cli-commands.md @@ -1,47 +1,47 @@ -# CLI commands +# CLI Commands -| Command | Description | -| ------------------------------------------- | ---------------------------------------------------------------------------- | -| `add [package_type] [public_id]` | Add a `package_type` connection, contract, protocol, or skill, with `[public_id]`, to the AEA. `add --local` to add from local `packages` directory. | -| `add-key [ledger_id] file [--connection]` | Add a private key from a file for `ledger_id`. | -| `build` | Build the agent and its components. | -| `config get [path]` | Reads the configuration specified in `path` and prints its target. | -| `config set [path] [--type TYPE]` | Sets a new value for the target of the `path`. Optionally cast to type. | -| `create [name]` | Create a new AEA project called `name`. | -| `delete [name]` | Delete an AEA project. See below for disabling a resource. | -| `eject [package_type] [public_id]` | Move a package of `package_type` and `package_id` from vendor to project working directory. | -| `fetch [public_id]` | Fetch an AEA project with `public_id`. `fetch --local` to fetch from local `packages` directory. | -| `fingerprint [package_type] [public_id]` | Fingerprint connection, contract, protocol, or skill, with `public_id`. | -| `freeze` | Get all the dependencies needed for the AEA project and its components. | -| `generate protocol [protocol_spec_path]` | Generate a protocol from the specification. | -| `generate-key [ledger_id]` | Generate private keys. The AEA uses a private key to derive the associated public key and address. | -| `generate-wealth [ledger_id]` | Generate wealth for address on test network. | -| `get-address [ledger_id]` | Get the address associated with the private key. | -| `get-multiaddress [ledger_id]...` | Get the multiaddress associated with a private key or connection. | -| `get-public-key [ledger_id]...` | Get the public key associated with a private key of the agent. | -| `get-wealth [ledger_id]` | Get the wealth associated with the private key. | -| `init` | Initialize your AEA configurations. (With `--author` to define author.) | -| `install [-r ]` | Install the dependencies. (With `--install-deps` to install dependencies.) | -| `interact` | Interact with a running AEA via the stub connection. | -| `ipfs` | IPFS Commands | -| `issue-certificates` | Issue the connection certificates. | -| `launch [path_to_agent_project]...` | Launch many agents at the same time. | -| `list [package_type]` | List the installed resources. | -| `local-registry-sync` | Upgrade the local package registry. | -| `login USERNAME [--password password]` | Login to a registry account with credentials. | -| `logout` | Logout from registry account. | -| `publish` | Publish the AEA to registry. Needs to be executed from an AEA project.`publish --local` to publish to local `packages` directory. | -| `push [package_type] [public_id]` | Push connection, protocol, or skill with `public_id` to registry. `push --local` to push to local `packages` directory. | -| `register` | Create a new registry account. -| `remove [package_type] [name]` | Remove connection, protocol, or skill, called `name`, from AEA. | -| `remove-key [ledger_id] [name]` | Remove a private key registered with id `ledger_id`. | -| `reset_password EMAIL` | Reset the password of the registry account. | -| `run {using [connections, ...]}` | Run the AEA on the Fetch.ai network with default or specified connections. | -| `scaffold [package_type] [name]` | Scaffold a new connection, protocol, or skill called `name`. | -| `search [package_type]` | Search for components in the registry. `search --local [package_type] [--query searching_query]` to search in local `packages` directory. | -| `transfer [type] [address] [amount]` | Transfer wealth associated with a private key of the agent to another account. | -| `upgrade [package_type] [public_id]` | Upgrade the packages of the agent. | -| `-v DEBUG run` | Run with debugging. | +| Command | Description | +|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------| +| `add [package_type] [public_id]` | Add a `package_type` connection, contract, protocol, or skill, with `[public_id]`, to the AEA. `add --local` to add from local `packages` directory. | +| `add-key [ledger_id] file [--connection]` | Add a private key from a file for `ledger_id`. | +| `build` | Build the agent and its components. | +| `config get [path]` | Reads the configuration specified in `path` and prints its target. | +| `config set [path] [--type TYPE]` | Sets a new value for the target of the `path`. Optionally cast to type. | +| `create [name]` | Create a new AEA project called `name`. | +| `delete [name]` | Delete an AEA project. See below for disabling a resource. | +| `eject [package_type] [public_id]` | Move a package of `package_type` and `package_id` from vendor to project working directory. | +| `fetch [public_id]` | Fetch an AEA project with `public_id`. `fetch --local` to fetch from local `packages` directory. | +| `fingerprint [package_type] [public_id]` | Fingerprint connection, contract, protocol, or skill, with `public_id`. | +| `freeze` | Get all the dependencies needed for the AEA project and its components. | +| `generate protocol [protocol_spec_path]` | Generate a protocol from the specification. | +| `generate-key [ledger_id]` | Generate private keys. The AEA uses a private key to derive the associated public key and address. | +| `generate-wealth [ledger_id]` | Generate wealth for address on test network. | +| `get-address [ledger_id]` | Get the address associated with the private key. | +| `get-multiaddress [ledger_id]...` | Get the multiaddress associated with a private key or connection. | +| `get-public-key [ledger_id]...` | Get the public key associated with a private key of the agent. | +| `get-wealth [ledger_id]` | Get the wealth associated with the private key. | +| `init` | Initialize your AEA configurations. (With `--author` to define author.) | +| `install [-r ]` | Install the dependencies. (With `--install-deps` to install dependencies.) | +| `interact` | Interact with a running AEA via the stub connection. | +| `ipfs` | IPFS Commands | +| `issue-certificates` | Issue the connection certificates. | +| `launch [path_to_agent_project]...` | Launch many agents at the same time. | +| `list [package_type]` | List the installed resources. | +| `local-registry-sync` | Upgrade the local package registry. | +| `login USERNAME [--password password]` | Login to a registry account with credentials. | +| `logout` | Logout from registry account. | +| `publish` | Publish the AEA to registry. Needs to be executed from an AEA project.`publish --local` to publish to local `packages` directory. | +| `push [package_type] [public_id]` | Push connection, protocol, or skill with `public_id` to registry. `push --local` to push to local `packages` directory. | +| `register` | Create a new registry account. | +| `remove [package_type] [name]` | Remove connection, protocol, or skill, called `name`, from AEA. | +| `remove-key [ledger_id] [name]` | Remove a private key registered with id `ledger_id`. | +| `reset_password EMAIL` | Reset the password of the registry account. | +| `run {using [connections, ...]}` | Run the AEA on the Fetch.ai network with default or specified connections. | +| `scaffold [package_type] [name]` | Scaffold a new connection, protocol, or skill called `name`. | +| `search [package_type]` | Search for components in the registry. `search --local [package_type] [--query searching_query]` to search in local `packages` directory. | +| `transfer [type] [address] [amount]` | Transfer wealth associated with a private key of the agent to another account. | +| `upgrade [package_type] [public_id]` | Upgrade the packages of the agent. | +| `-v DEBUG run` | Run with debugging. | -
-

Tip

-

You can also disable a resource without deleting it by removing the entry from the configuration but leaving the package in the skills namespace.

-
+!!! tip + You can also disable a resource without deleting it by removing the entry from the configuration but leaving the package in the `skills` namespace. -
-

Tip

-

You can skip the consistency checks on the AEA project by using the flag --skip-consistency-check. E.g. aea --skip-consistency-check run will bypass the fingerprint checks.

-
- -
+!!! tip + You can skip the consistency checks on the AEA project by using the flag `--skip-consistency-check`. E.g. `aea --skip-consistency-check run` will bypass the fingerprint checks. diff --git a/docs/cli-how-to.md b/docs/cli-how-to.md index ea990b74ac..5d19bcd798 100644 --- a/docs/cli-how-to.md +++ b/docs/cli-how-to.md @@ -1,3 +1,5 @@ +# How to Use the Command Line Interface + The command line interface is the easiest way to build an AEA. ## Installation @@ -14,28 +16,35 @@ The following installs the entire AEA package including the CLI. pip install aea[all] ``` -If you are using `zsh` rather than `bash` type +If you are using `zsh` rather than `bash` type + ``` zsh pip install 'aea[cli]' ``` + and + ``` zsh pip install 'aea[all]' ``` + respectively. Be sure that the `bin` folder of your Python environment is in the `PATH` variable. If so, you can execute the CLI tool as: + ``` bash aea ``` You might find useful the execution of the `aea.cli` package as a script: + ``` bash python -m aea.cli ``` -which is just an alternative entry-point to the CLI tool. + +which is just an alternative entry-point to the CLI tool. ## Troubleshooting @@ -46,8 +55,7 @@ pip install aea[all] --force --no-cache-dir ``` And for `zsh` run: + ``` zsh pip install 'aea[all]' --force --no-cache-dir ``` - -
diff --git a/docs/cli-vs-programmatic-aeas.md b/docs/cli-vs-programmatic-aeas.md index 1779944f73..3b23cd4416 100644 --- a/docs/cli-vs-programmatic-aeas.md +++ b/docs/cli-vs-programmatic-aeas.md @@ -1,3 +1,5 @@ +# CLI vs Programmatic AEAs + The AEA framework enables us to create agents either from the CLI tool or programmatically. The following demo demonstrates an interaction between two AEAs. @@ -11,24 +13,25 @@ The scope of the specific demo is to demonstrate how a CLI based AEA can interac to achieve this we are going to use the weather station skills. This demo does not utilize a smart contract or a ledger interaction. -## Get required packages +## Get Required Packages -Copy the packages directory into your local working directory: +Copy the `packages` directory into your local working directory: ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/packages ``` Also, install `aea-ledger-fetchai` plug-in: -```bash + +``` bash pip install aea-ledger-fetchai ``` -## Demo instructions +## Demo Instructions If you want to create the weather station AEA step by step you can follow this guide here -### Create the weather station AEA +### Create the Weather Station AEA Fetch the weather station AEA with the following command : @@ -39,285 +42,291 @@ aea install aea build ``` -### Update the AEA configurations +### Update the AEA Configurations In the terminal change the configuration: + ``` bash aea config set vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx False --type bool ``` + The `is_ledger_tx` will prevent the AEA to communicate with a ledger. -### Add keys +### Add Keys Add a private key for the weather station. + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Run the weather station AEA +### Run the Weather Station AEA + ``` bash aea run ``` Once you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address. -### Create the weather client AEA +### Create the Weather Client AEA Since we want to show the interaction between a programmatically created AEA with a CLI based AEA we are going to write some code for the client. Create a new python file and name it `weather_client.py` and add the following code -
Weather client full code. - -``` python -import logging -import os -import sys -from typing import cast - -from aea_ledger_fetchai import FetchAICrypto - -from aea.aea import AEA -from aea.aea_builder import AEABuilder -from aea.configurations.base import ConnectionConfig -from aea.crypto.helpers import ( - PRIVATE_KEY_PATH_SCHEMA, - create_private_key, - make_certificate, -) -from aea.crypto.wallet import Wallet -from aea.helpers.base import CertRequest -from aea.identity.base import Identity -from aea.protocols.base import Protocol -from aea.registries.resources import Resources -from aea.skills.base import Skill - -import packages.fetchai.connections.p2p_libp2p.connection -from packages.fetchai.connections.ledger.connection import LedgerConnection -from packages.fetchai.connections.p2p_libp2p.connection import P2PLibp2pConnection -from packages.fetchai.connections.soef.connection import SOEFConnection -from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage -from packages.fetchai.protocols.oef_search.message import OefSearchMessage -from packages.fetchai.skills.weather_client.strategy import Strategy - - -API_KEY = "TwiCIriSl0mLahw17pyqoA" -SOEF_ADDR = "s-oef.fetch.ai" -SOEF_PORT = 443 -ENTRY_PEER_ADDRESS = ( - "/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmLBCAqHL8SuFosyDhAKYsLKXBZBWXBsB9oFw2qU4Kckun" -) -FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier) -FETCHAI_PRIVATE_KEY_FILE_CONNECTION = PRIVATE_KEY_PATH_SCHEMA.format( - "fetchai_connection" -) -ROOT_DIR = os.getcwd() - -logger = logging.getLogger("aea") -logging.basicConfig(stream=sys.stdout, level=logging.INFO) - - -def run(): - """Run demo.""" - - # Create a private key - create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) - create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION) - - # Set up the wallet, identity and (empty) resources - wallet = Wallet( - private_key_paths={FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE}, - connection_private_key_paths={ - FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_CONNECTION - }, +??? note "Weather client full code:" + + ``` python + import logging + import os + import sys + from typing import cast + + from aea_ledger_fetchai import FetchAICrypto + + from aea.aea import AEA + from aea.aea_builder import AEABuilder + from aea.configurations.base import ConnectionConfig + from aea.crypto.helpers import ( + PRIVATE_KEY_PATH_SCHEMA, + create_private_key, + make_certificate, ) - identity = Identity( - "my_aea", - address=wallet.addresses.get(FetchAICrypto.identifier), - public_key=wallet.public_keys.get(FetchAICrypto.identifier), + from aea.crypto.wallet import Wallet + from aea.helpers.base import CertRequest + from aea.identity.base import Identity + from aea.protocols.base import Protocol + from aea.registries.resources import Resources + from aea.skills.base import Skill + + import packages.fetchai.connections.p2p_libp2p.connection + from packages.fetchai.connections.ledger.connection import LedgerConnection + from packages.fetchai.connections.p2p_libp2p.connection import P2PLibp2pConnection + from packages.fetchai.connections.soef.connection import SOEFConnection + from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage + from packages.fetchai.protocols.oef_search.message import OefSearchMessage + from packages.fetchai.skills.weather_client.strategy import Strategy + + + API_KEY = "TwiCIriSl0mLahw17pyqoA" + SOEF_ADDR = "s-oef.fetch.ai" + SOEF_PORT = 443 + ENTRY_PEER_ADDRESS = ( + "/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmLBCAqHL8SuFosyDhAKYsLKXBZBWXBsB9oFw2qU4Kckun" ) - resources = Resources() - data_dir = os.getcwd() - - # specify the default routing for some protocols - default_routing = { - LedgerApiMessage.protocol_id: LedgerConnection.connection_id, - OefSearchMessage.protocol_id: SOEFConnection.connection_id, - } - default_connection = P2PLibp2pConnection.connection_id - - state_update_protocol = Protocol.from_dir( - os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "state_update") - ) - resources.add_protocol(state_update_protocol) - - # Add the default protocol (which is part of the AEA distribution) - default_protocol = Protocol.from_dir( - os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "default") + FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier) + FETCHAI_PRIVATE_KEY_FILE_CONNECTION = PRIVATE_KEY_PATH_SCHEMA.format( + "fetchai_connection" ) - resources.add_protocol(default_protocol) - - # Add the signing protocol (which is part of the AEA distribution) - signing_protocol = Protocol.from_dir( - os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "signing") - ) - resources.add_protocol(signing_protocol) - - # Add the ledger_api protocol - ledger_api_protocol = Protocol.from_dir( - os.path.join( - os.getcwd(), - "packages", - "fetchai", - "protocols", - "ledger_api", + ROOT_DIR = os.getcwd() + + logger = logging.getLogger("aea") + logging.basicConfig(stream=sys.stdout, level=logging.INFO) + + + def run(): + """Run demo.""" + + # Create a private key + create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE) + create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION) + + # Set up the wallet, identity and (empty) resources + wallet = Wallet( + private_key_paths={FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE}, + connection_private_key_paths={ + FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_CONNECTION + }, ) - ) - resources.add_protocol(ledger_api_protocol) - - # Add the oef_search protocol - oef_protocol = Protocol.from_dir( - os.path.join( - os.getcwd(), - "packages", - "fetchai", - "protocols", - "oef_search", + identity = Identity( + "my_aea", + address=wallet.addresses.get(FetchAICrypto.identifier), + public_key=wallet.public_keys.get(FetchAICrypto.identifier), ) - ) - resources.add_protocol(oef_protocol) - - # Add the fipa protocol - fipa_protocol = Protocol.from_dir( - os.path.join( - os.getcwd(), - "packages", - "fetchai", - "protocols", - "fipa", + resources = Resources() + data_dir = os.getcwd() + + # specify the default routing for some protocols + default_routing = { + LedgerApiMessage.protocol_id: LedgerConnection.connection_id, + OefSearchMessage.protocol_id: SOEFConnection.connection_id, + } + default_connection = P2PLibp2pConnection.connection_id + + state_update_protocol = Protocol.from_dir( + os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "state_update") ) - ) - resources.add_protocol(fipa_protocol) - - # Add the LedgerAPI connection - configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id) - ledger_api_connection = LedgerConnection( - configuration=configuration, data_dir=data_dir, identity=identity - ) - resources.add_connection(ledger_api_connection) - - # Add the P2P connection - cert_path = ".certs/conn_cert.txt" - cert_request = CertRequest( - identifier="acn", - ledger_id=FetchAICrypto.identifier, - not_after="2022-01-01", - not_before="2021-01-01", - public_key="fetchai", - message_format="{public_key}", - save_path=cert_path, - ) - public_key = wallet.connection_cryptos.public_keys.get(FetchAICrypto.identifier) - message = cert_request.get_message(public_key) - make_certificate( - FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE, message, cert_path - ) - configuration = ConnectionConfig( - connection_id=P2PLibp2pConnection.connection_id, - delegate_uri="127.0.0.1:11001", - entry_peers=[ENTRY_PEER_ADDRESS], - local_uri="127.0.0.1:9001", - log_file="libp2p_node.log", - public_uri="127.0.0.1:9001", - build_directory=os.getcwd(), - build_entrypoint="check_dependencies.py", - cert_requests=[cert_request], - ) - configuration.directory = os.path.dirname( - packages.fetchai.connections.p2p_libp2p.connection.__file__ - ) - - AEABuilder.run_build_for_component_configuration(configuration) - - p2p_connection = P2PLibp2pConnection( - configuration=configuration, - data_dir=data_dir, - identity=identity, - crypto_store=wallet.connection_cryptos, - ) - resources.add_connection(p2p_connection) - - # Add the SOEF connection - configuration = ConnectionConfig( - api_key=API_KEY, - soef_addr=SOEF_ADDR, - soef_port=SOEF_PORT, - restricted_to_protocols={OefSearchMessage.protocol_id}, - connection_id=SOEFConnection.connection_id, - ) - soef_connection = SOEFConnection( - configuration=configuration, data_dir=data_dir, identity=identity - ) - resources.add_connection(soef_connection) - - # create the AEA - my_aea = AEA( - identity, - wallet, - resources, - data_dir, - default_connection=default_connection, - default_routing=default_routing, - ) - # Add the error and weather_client skills - error_skill = Skill.from_dir( - os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "error"), - agent_context=my_aea.context, - ) - weather_skill = Skill.from_dir( - os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "weather_client"), - agent_context=my_aea.context, - ) - - strategy = cast(Strategy, weather_skill.models.get("strategy")) - strategy._is_ledger_tx = False - - for skill in [error_skill, weather_skill]: - resources.add_skill(skill) - - # Run the AEA - try: - logger.info("STARTING AEA NOW!") - my_aea.start() - except KeyboardInterrupt: - logger.info("STOPPING AEA NOW!") - my_aea.stop() - - -if __name__ == "__main__": - run() -``` -
+ resources.add_protocol(state_update_protocol) + + # Add the default protocol (which is part of the AEA distribution) + default_protocol = Protocol.from_dir( + os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "default") + ) + resources.add_protocol(default_protocol) + + # Add the signing protocol (which is part of the AEA distribution) + signing_protocol = Protocol.from_dir( + os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "signing") + ) + resources.add_protocol(signing_protocol) + + # Add the ledger_api protocol + ledger_api_protocol = Protocol.from_dir( + os.path.join( + os.getcwd(), + "packages", + "fetchai", + "protocols", + "ledger_api", + ) + ) + resources.add_protocol(ledger_api_protocol) + + # Add the oef_search protocol + oef_protocol = Protocol.from_dir( + os.path.join( + os.getcwd(), + "packages", + "fetchai", + "protocols", + "oef_search", + ) + ) + resources.add_protocol(oef_protocol) + + # Add the fipa protocol + fipa_protocol = Protocol.from_dir( + os.path.join( + os.getcwd(), + "packages", + "fetchai", + "protocols", + "fipa", + ) + ) + resources.add_protocol(fipa_protocol) + + # Add the LedgerAPI connection + configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id) + ledger_api_connection = LedgerConnection( + configuration=configuration, data_dir=data_dir, identity=identity + ) + resources.add_connection(ledger_api_connection) + + # Add the P2P connection + cert_path = ".certs/conn_cert.txt" + cert_request = CertRequest( + identifier="acn", + ledger_id=FetchAICrypto.identifier, + not_after="2022-01-01", + not_before="2021-01-01", + public_key="fetchai", + message_format="{public_key}", + save_path=cert_path, + ) + public_key = wallet.connection_cryptos.public_keys.get(FetchAICrypto.identifier) + message = cert_request.get_message(public_key) + make_certificate( + FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE, message, cert_path + ) + configuration = ConnectionConfig( + connection_id=P2PLibp2pConnection.connection_id, + delegate_uri="127.0.0.1:11001", + entry_peers=[ENTRY_PEER_ADDRESS], + local_uri="127.0.0.1:9001", + log_file="libp2p_node.log", + public_uri="127.0.0.1:9001", + build_directory=os.getcwd(), + build_entrypoint="check_dependencies.py", + cert_requests=[cert_request], + ) + configuration.directory = os.path.dirname( + packages.fetchai.connections.p2p_libp2p.connection.__file__ + ) + + AEABuilder.run_build_for_component_configuration(configuration) + + p2p_connection = P2PLibp2pConnection( + configuration=configuration, + data_dir=data_dir, + identity=identity, + crypto_store=wallet.connection_cryptos, + ) + resources.add_connection(p2p_connection) + + # Add the SOEF connection + configuration = ConnectionConfig( + api_key=API_KEY, + soef_addr=SOEF_ADDR, + soef_port=SOEF_PORT, + restricted_to_protocols={OefSearchMessage.protocol_id}, + connection_id=SOEFConnection.connection_id, + ) + soef_connection = SOEFConnection( + configuration=configuration, data_dir=data_dir, identity=identity + ) + resources.add_connection(soef_connection) + + # create the AEA + my_aea = AEA( + identity, + wallet, + resources, + data_dir, + default_connection=default_connection, + default_routing=default_routing, + ) + # Add the error and weather_client skills + error_skill = Skill.from_dir( + os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "error"), + agent_context=my_aea.context, + ) + weather_skill = Skill.from_dir( + os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "weather_client"), + agent_context=my_aea.context, + ) + + strategy = cast(Strategy, weather_skill.models.get("strategy")) + strategy._is_ledger_tx = False + + for skill in [error_skill, weather_skill]: + resources.add_skill(skill) + + # Run the AEA + try: + logger.info("STARTING AEA NOW!") + my_aea.start() + except KeyboardInterrupt: + logger.info("STOPPING AEA NOW!") + my_aea.stop() + + + if __name__ == "__main__": + run() + ``` Now replace `ENTRY_PEER_ADDRESS` with the peer address (`SOME_ADDRESS`) noted above. For more details on how to create an agent programmatically follow this guide here. -### Run the weather station AEA +### Run the Weather Client AEA In a new terminal window, navigate to the folder that you created the script and run: + ``` bash python weather_client.py ``` diff --git a/docs/config.md b/docs/config.md index 6b53437969..294ee1abe8 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,8 +1,11 @@ +# Configurations + This document describes the configuration files of the different packages. -## AEA configuration YAML +## AEA Configuration YAML The following provides a list of the relevant regex used: + ``` yaml PACKAGE_REGEX: "[a-zA-Z_][a-zA-Z0-9_]*" AUTHOR_REGEX: "[a-zA-Z_][a-zA-Z0-9_]*" @@ -11,6 +14,7 @@ LEDGER_ID_REGEX: "^[^\\d\\W]\\w*\\Z" ``` The `aea-config.yaml` defines the AEA project. The compulsory components are listed below: + ``` yaml agent_name: my_agent # Name of the AEA project (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the project's author (must satisfy AUTHOR_REGEX) @@ -42,6 +46,7 @@ dependencies: {} # The python dependencies the AE ``` The `aea-config.yaml` can be extended with a number of optional fields: + ``` yaml period: 0.05 # The period to call agent's act execution_timeout: 0 # The execution time limit on each call to `react` and `act` (0 disables the feature) @@ -60,6 +65,7 @@ data_dir: None # The path to the directory for The `aea-config.yaml` can further be extended with component configuration overrides. For custom connection configurations: + ``` yaml public_id: some_author/some_package:0.1.0 # The public id of the connection (must satisfy PUBLIC_ID_REGEX). type: connection # for connections, this must be "connection". @@ -67,6 +73,7 @@ config: ... # a dictionary to overwrite the ``` For custom skill configurations: + ``` yaml public_id: some_author/some_package:0.1.0 # The public id of the connection (must satisfy PUBLIC_ID_REGEX). type: skill # for skills, this must be "skill". @@ -84,10 +91,10 @@ models: # override configurations for mo foo: bar ``` - -## Connection configuration YAML +## Connection Configuration YAML The `connection.yaml`, which is present in each connection package, has the following required fields: + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -111,9 +118,10 @@ dependencies: {} # The python dependencies the pa is_abstract: false # An optional boolean that if `true` makes the connection ``` -## Contract configuration YAML +## Contract Configuration YAML The `contract.yaml`, which is present in each contract package, has the following required fields: + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -133,9 +141,10 @@ config: # A dictionary containing the kw dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` -## Protocol configuration YAML +## Protocol Configuration YAML The `protocol.yaml`, which is present in each protocol package, has the following required fields: + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -152,9 +161,10 @@ fingerprint_ignore_patterns: [] # Ignore pattern for the fingerp dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` -## Skill configuration YAML +## Skill Configuration YAML The `skill.yaml`, which is present in each protocol package, has the following required fields: + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) diff --git a/docs/connect-a-frontend.md b/docs/connect-a-frontend.md index 8f151af39f..e0a7778a7b 100644 --- a/docs/connect-a-frontend.md +++ b/docs/connect-a-frontend.md @@ -1,9 +1,13 @@ +# Front-End Integration + This page lays out two options for connecting a front-end to an AEA. The following diagram illustrates these two options. How to connect front-end to your AEA ## Case 1 + The first option is to create a `HTTP Server` connection that handles incoming requests from a REST API. In this scenario, the REST API communicates with the AEA and requests are handled by the `HTTP Server` connection package. The REST API should send CRUD requests to the `HTTP Server` connection (`fetchai/http_server:0.23.5`) which translates these into Envelopes to be consumed by the correct skill. ## Case 2 -The second option is to create a front-end comprising a stand-alone `Multiplexer` with a `P2P` connection (`fetchai/p2p_libp2p:0.27.4`). In this scenario the Agent Communication Network can be used to send Envelopes from the AEA to the front-end. \ No newline at end of file + +The second option is to create a front-end comprising a stand-alone `Multiplexer` with a `P2P` connection (`fetchai/p2p_libp2p:0.27.4`). In this scenario the Agent Communication Network can be used to send Envelopes from the AEA to the front-end. diff --git a/docs/connection.md b/docs/connection.md index 3d612afacb..e81f17f59d 100644 --- a/docs/connection.md +++ b/docs/connection.md @@ -1,3 +1,5 @@ +# Connections + A `Connection` provides an interface for the agent to connect with entities in the outside world. Connections wrap SDKs or APIs and provide interfaces to networks, ledgers and other services. As such, a connection is concerned with I/O bound and continuously connected operations. Where necessary, a connection is responsible for translating between the framework specific protocol (an `Envelope` with its contained `Message`) and the external service or third-party protocol (e.g. `HTTP`). Hence, there are two roles for connections: wrapper and transport connection. The transport connection is responsible to delivering AEA envelopes. The messages constructed or received by a connection are eventually processed by one or several skills which deal with handling and generating messages related to a specific business objective. @@ -8,7 +10,7 @@ An `AEA` can interact with multiple connections at the same time via the `InBox` and `OutBox`, which are, respectively, queues for incoming and outgoing envelopes and their contained messages. -## Developing your connection +## Developing your Connection The easiest way to get started developing your own connection is by using the scaffold command: @@ -18,13 +20,13 @@ aea scaffold connection my_new_connection This will scaffold a connection package called `my_new_connection` with three files: -* `__init__.py` -* `connection.py` containing the scaffolded connection class -* `connection.yaml` containing the scaffolded configuration file +- `__init__.py` +- `connection.py` containing the scaffolded connection class +- `connection.yaml` containing the scaffolded configuration file As a developer you have the choice between implementing a sync or asynchronous interface. The scaffolded `connection.py` file contains two classes: the `MyScaffoldAsyncConnection` inherited from the `Connection` base class and the `MyScaffoldSyncConnection` inherited from the `BaseSyncConnection`. Remove the unused class. -### Primary methods to develop - asynchronous connection interface +### Primary Methods to Develop - Asynchronous Connection Interface The developer needs to implement four public coroutines: @@ -38,14 +40,15 @@ The developer needs to implement four public coroutines: The framework provides a demo `stub` connection which implements an I/O reader and writer to send and receive messages between the agent and a local file. To gain inspiration and become familiar with the structure of connection packages, you may find it useful to check out `fetchai/stub:0.21.2`, `fetchai/http_server:0.23.5` or `fetchai/http_client:0.24.5` connections. The latter two connections are for external clients to connect with an agent, and for the agent to connect with external servers, respectively. -### Primary methods to develop - sync connection interface +### Primary Methods to Develop - Sync Connection Interface The `BaseSyncConnection` uses executors to execute synchronous code from the asynchronous context of the `Multiplexer` in executors/threads, which are limited by the amount of configured workers. The asynchronous methods `connect`, `disconnect` and `send` are converted to callbacks which the developer implements: -* `on_connect` -* `on_disconnect` -* `on_send` + +- `on_connect` +- `on_disconnect` +- `on_send` All of these methods will be executed in the executor pool. @@ -57,7 +60,7 @@ The `receive` coroutine has no direct equivalent. Instead, the developer impleme Every connection must have a configuration file in `connection.yaml`, containing meta-information about the connection as well as all the required configuration details. For more details, have a look here. -### Configuration options +### Configuration Options The `connection.yaml` file contains a number of fields that must be edited by the developer of the connection: @@ -83,5 +86,3 @@ cert_requests: [] - `dependencies` lists any Python dependencies of the connection package - `is_abstract` specifies whether this connection is only used as an abstract base class - `cert_requests` lists certification requests of the connection (see proof of representation for details) - -
diff --git a/docs/contract.md b/docs/contract.md index 327941a55d..d4858fba1e 100644 --- a/docs/contract.md +++ b/docs/contract.md @@ -1,3 +1,5 @@ +# Contracts + `Contracts` wrap smart contracts for Fetch.ai and third-party decentralized ledgers. In particular, they provide wrappers around the API or ABI of a smart contract and its byte code. They implement a translation between framework messages (in the `fetchai/contract_api:1.0.0` protocol) and the implementation specifics of the ABI. Contracts usually implement four types of methods: @@ -9,10 +11,9 @@ Contracts usually implement four types of methods: Contracts can be added as packages which means they become reusable across AEA projects. -The smart contract wrapped in a AEA contract package might be a third-party smart contract or your own smart contract potentially interacting with a third-party contract on-chain. - +The smart contract wrapped in an AEA contract package might be a third-party smart contract or your own smart contract potentially interacting with a third-party contract on-chain. -## Interacting with contracts from skills +## Interacting with Contracts from Skills Interacting with contracts in almost all cases requires network access. Therefore, the framework executes contract related logic in a Connection. @@ -20,7 +21,7 @@ Interacting with contracts in almost all cases requires network access. Therefor In particular, the `fetchai/ledger:0.21.4` connection can be used to execute contract related logic. The skills communicate with the `fetchai/ledger:0.21.4` connection via the `fetchai/contract_api:1.0.0` protocol. This protocol implements a request-response pattern to serve the four types of methods listed above: -- the `get_deploy_transaction` message is used to request a deploy transaction for a specific contract. For instance, to request a deploy transaction for the deployment of the smart contract wrapped in the `fetchai/erc1155:0.23.2` package, we send the following message to the `fetchai/ledger:0.21.4`: +- the `get_deploy_transaction` message is used to request a `deploy` transaction for a specific contract. For instance, to request a `deploy` transaction for the deployment of the smart contract wrapped in the `fetchai/erc1155:0.23.2` package, we send the following message to the `fetchai/ledger:0.21.4`: ``` python contract_api_msg = ContractApiMessage( @@ -39,11 +40,13 @@ Any additional arguments needed by the contract's constructor method should be a This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `raw_transaction` message will be returned with the matching raw transaction. To send this transaction to the ledger for processing, we first sign the message with the decision maker and then send the signed transaction to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. For details on how to implement the message handling, see the handlers in the `erc1155_deploy` skill. -
-

CosmWasm based smart contract deployments

-

When using CosmWasm based smart contracts two types of deployment transactions exist. The first transaction stores the code on the chain. The second transaction initialises the code. This way, the same contract code can be initialised many times.
Both the store and init messages use the ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION performative. The ledger API automatically detects the type of transactions based on the provided keyword arguments. In particular, an init transaction requires the keyword arguments code_id (integer), label (string), amount (integer) and init_msg (JSON).
For an example look at the fetchai/erc1155:0.23.2 package. -

-
+!!! note "CosmWasm based smart contract deployments" + + When using CosmWasm based smart contracts two types of deployment transactions exist. The first transaction stores the code on the chain. The second transaction initialises the code. This way, the same contract code can be initialised many times. + + Both the store and init messages use the ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION performative. The ledger API automatically detects the type of transactions based on the provided keyword arguments. In particular, an init transaction requires the keyword arguments code_id (integer), label (string), amount (integer) and init_msg (JSON). + + For an example look at the fetchai/erc1155:0.23.2 package. - the `get_raw_transaction` message is used to request any transaction for a specific contract which changes state in the contract. For instance, to request a transaction for the creation of token in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.2` package, we send the following message to the `fetchai/ledger:0.21.4`: @@ -64,7 +67,7 @@ contract_api_msg = ContractApiMessage( ) ``` -This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `raw_transaction` message will be returned with the matching raw transaction. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_create_batch_transaction` method with the specified key word arguments (see example in *Deploy your own*, below). Similarly to above, to send this transaction to the ledger for processing, we first sign the message with the decision maker and then send the signed transaction to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. +This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `raw_transaction` message will be returned with the matching raw transaction. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_create_batch_transaction` method with the specified key word arguments (see example in *Deploy your own*, below). Similar to the above, to send this transaction to the ledger for processing, we first sign the message with the decision maker and then send the signed transaction to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. - the `get_raw_message` message is used to request any contract method call for a specific contract which does not change state in the contract. For instance, to request a call to get a hash from some input data in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.2` package, we send the following message to the `fetchai/ledger:0.21.4`: @@ -89,8 +92,8 @@ contract_api_msg = ContractApiMessage( ), ) ``` -This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `raw_message` message will be returned with the matching raw message. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_hash_single` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required. +This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `raw_message` message will be returned with the matching raw message. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_hash_single` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required. - the `get_state` message is used to request any contract method call to query state in the deployed contract. For instance, to request a call to get the balances in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.2` package, we send the following message to the `fetchai/ledger:0.21.4`: @@ -107,8 +110,8 @@ contract_api_msg = ContractApiMessage( ), ) ``` -This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `state` message will be returned with the matching state. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_balance` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required. +This message will be handled by the `fetchai/ledger:0.21.4` connection and then a `state` message will be returned with the matching state. For this to be executed correctly, the `fetchai/erc1155:0.23.2` contract package needs to implement the `get_balance` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.4` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required. ## Developing your own @@ -120,10 +123,9 @@ aea scaffold contract my_new_contract This will scaffold a contract package called `my_new_contract` with three files: -* `__init__.py` -* `contract.py`, containing the scaffolded contract class -* `contract.yaml` containing the scaffolded configuration file - +- `__init__.py` +- `contract.py`, containing the scaffolded contract class +- `contract.yaml` containing the scaffolded configuration file Once your scaffold is in place, you can create a `build` folder in the package and copy the smart contract interface (e.g. bytes code and ABI) to it. Then, specify the path to the interfaces in the `contract.yaml`. For instance, if you use Ethereum, then you might specify the following: @@ -131,8 +133,8 @@ Once your scaffold is in place, you can create a `build` folder in the package a contract_interface_paths: ethereum: build/my_contract.json ``` -where `ethereum` is the ledger id and `my_contract.json` is the file containing the byte code and ABI. +where `ethereum` is the ledger id and `my_contract.json` is the file containing the byte code and ABI. Finally, you will want to implement the part of the contract interface you need in `contract.py`: @@ -180,6 +182,7 @@ class MyContract(Contract): tx = cls._try_estimate_gas(ledger_api, tx) return tx ``` + Above, we implement a method to create a transaction, in this case a transaction to create a batch of tokens. The method will be called by the framework, specifically the `fetchai/ledger:0.21.4` connection once it receives a message (see bullet point 2 above). The method first gets the latest transaction nonce of the `deployer_address`, then constructs the contract instance, then uses the instance to build the transaction and finally updates the gas on the transaction. It helps to look at existing contract packages, like `fetchai/erc1155:0.23.2`, and skills using them, like `fetchai/erc1155_client:0.11.0` and `fetchai/erc1155_deploy:0.31.5`, for inspiration and guidance. diff --git a/docs/core-components-1.md b/docs/core-components-1.md index 2ded1b513d..995f18b932 100644 --- a/docs/core-components-1.md +++ b/docs/core-components-1.md @@ -1,8 +1,10 @@ +# Core Components - Part 1 + The AEA framework consists of several core components, some required to run an AEA and others optional. The following sections discuss the inner workings of the AEA framework and how it calls the code in custom packages (see inversion of control and a helpful comparison here). Whilst it is in principle possible to use parts of the framework as a library, we do not recommend it. -## The elements each AEA uses +## The Elements Each AEA Uses ### Envelope @@ -12,15 +14,11 @@ The following sections discuss the inner workings of the AEA framework and how i An `Envelope` is the core object with which agents communicate. It is a vehicle for `Messages` with five attributes: -* `to`: defines the destination address. - -* `sender`: defines the sender address. - -* `protocol_id`: defines the id of the `Protocol`. - -* `message`: is a bytes field which holds the `Message` in serialized form. - -* `Optional[context]`: an optional field to specify routing information in a URI. +- `to`: defines the destination address. +- `sender`: defines the sender address. +- `protocol_id`: defines the id of the `Protocol`. +- `message`: is a bytes field which holds the `Message` in serialized form. +- `Optional[context]`: an optional field to specify routing information in a URI. `Messages` must adhere to a `Protocol`. @@ -28,11 +26,9 @@ An `Envelope` is the core object `Protocols` define agent-to-agent as well as component-to-component interactions within AEAs. As such, they include: -* `Messages` defining the syntax of messages; - -* `Serialization` defining how a `Message` is encoded for transport; and, optionally - -* `Dialogues`, which define rules over `Message` sequences. +- `Messages` defining the syntax of messages; +- `Serialization` defining how a `Message` is encoded for transport; and, optionally +- `Dialogues`, which define rules over `Message` sequences. The framework provides one default `Protocol`, called `default` (current version `fetchai/default:1.1.6`). This `Protocol` provides a bare-bones implementation for an AEA `Protocol` which includes a `DefaultMessage` class and associated `DefaultSerializer` and `DefaultDialogue` classes. @@ -66,12 +62,12 @@ It maintains an `InBox` and `Handler`: each `Skill` has zero, one or more `Handler` objects. There is a one-to-one correspondence between `Handlers` and the protocols in an AEA (also known as the _registered protocols_). Handlers implement AEAs' **reactive** behaviour. If an AEA understands a `Protocol` referenced in a received `Envelope` (i.e. the protocol is registered in this AEA), this envelope is sent to the corresponding `Handler` which executes the AEA's reaction to this `Message`. -* `Behaviour`: a `skill` can have zero, one or more `Behaviours`, each encapsulating actions which further the AEAs goal and are initiated by internals of the AEA rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of abstract base classes implementing different types of simple and composite behaviours (e.g. cyclic, one-shot, finite-state-machine, etc), and these define how often and in what order a behaviour and its sub-behaviours must be executed. -* `Model`: zero, one or more `Models` that inherit from the `Model` abstract base class and are accessible via the `SkillContext`. -* `Task`: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of `Skills`, but `Tasks` are declared in or from `Skills` if a packaging approach for AEA creation is used. +- `Handler`: each `Skill` has zero, one or more `Handler` objects. There is a one-to-one correspondence between `Handlers` and the protocols in an AEA (also known as the _registered protocols_). Handlers implement AEAs' **reactive** behaviour. If an AEA understands a `Protocol` referenced in a received `Envelope` (i.e. the protocol is registered in this AEA), this envelope is sent to the corresponding `Handler` which executes the AEA's reaction to this `Message`. +- `Behaviour`: a `skill` can have zero, one or more `Behaviours`, each encapsulating actions which further the AEAs goal and are initiated by internals of the AEA rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of abstract base classes implementing different types of simple and composite behaviours (e.g. cyclic, one-shot, finite-state-machine, etc), and these define how often and in what order a behaviour and its sub-behaviours must be executed. +- `Model`: zero, one or more `Models` that inherit from the `Model` abstract base class and are accessible via the `SkillContext`. +- `Task`: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of `Skills`, but `Tasks` are declared in or from `Skills` if a packaging approach for AEA creation is used. -A `Skill` can read (parts of) an AEA's state (as summarised in the `AgentContext`), and suggests actions to the AEA according to its specific logic. As such, more than one `Skill` could exist per `Protocol`, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms, this means `Skills` are horizontally arranged. +A `Skill` can read (parts of) an AEA's state (as summarised in the `AgentContext`), and propose actions to the AEA according to its specific logic. As such, more than one `Skill` could exist per `Protocol`, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms, this means `Skills` are horizontally arranged. For instance, an AEA which is trading goods, could subscribe to more than one `Skill`, where each corresponds to a different trading strategy. @@ -79,25 +75,25 @@ The framework places no limits on the complexity of `Skills`. They can implement The framework provides one default `Skill`, called `error`. Additional `Skills` can be added as packages. For more details on `Skills` head over to the `Skill` guide . -### Agent loop +### Agent Loop The `AgentLoop` performs a series of activities while the `AEA` state is not `stopped`. -* it calls the `act()` function of all active registered `Behaviours` at their respective tick rate. -* it grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` function for the `Handlers` currently registered against the `Protocol` of the `Envelope`. -* it dispatches the internal `Messages` from the decision maker (described below) to the handler in the relevant `Skill`. +- it calls the `act()` function of all active registered `Behaviours` at their respective tick rate. +- it grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` function for the `Handlers` currently registered against the `Protocol` of the `Envelope`. +- it dispatches the internal `Messages` from the decision maker (described below) to the handler in the relevant `Skill`. The `AgentLoop` and `Multiplexer` are decoupled via the `InBox` and `OutBox`, and both are maintained by the `Runtime`. -## Next steps +## Next Steps -### Recommended +### Recommended We recommend you continue with the next step in the 'Getting Started' series: - AEA and web frameworks -### Relevant deep-dives +### Relevant Deep-Dives Most AEA development focuses on developing the `Skills` and `Protocols` necessary for an AEA to deliver against its economic objectives. @@ -112,6 +108,3 @@ Most of an AEA developer's time is spent on `Skill` development. `Skills` are th In most cases, one of the available `Connection` packages can be used. Occasionally, you might develop your own `Connection`: - Connections - -
- diff --git a/docs/core-components-2.md b/docs/core-components-2.md index 2c63f56977..00700bfcb0 100644 --- a/docs/core-components-2.md +++ b/docs/core-components-2.md @@ -1,8 +1,10 @@ +# Core components - Part 2 + The AEA framework consists of several core components, some required to run an AEA and others optional. -In Core Components - Part 1 we described the common components each AEA uses. In this page, we will look at more advanced components. +In Core Components - Part 1 we described the common components each AEA uses. In this page, we will look at more advanced components. -## Required components used by AEAs +## Required Components Used by AEAs ### Decision Maker @@ -10,7 +12,7 @@ In Core Components - Part 1 we described the The `DecisionMaker` can be thought of as a `Wallet` manager plus "economic brain" of the AEA. It is responsible for the AEA's crypto-economic security and goal management, and it contains the preference and ownership representation of the AEA. The decision maker is the only component with access to the `Wallet`'s private keys. -You can learn more about the decision maker here. In its simplest form, the decision maker acts like a `Wallet` with `Handler` to react to messages it receives from the skills. +You can learn more about the decision maker here. In its simplest form, the decision maker acts like a `Wallet` with `Handler` that reacts to the messages it receives from the skills. ### Wallet @@ -21,9 +23,9 @@ The agent has two sets of private keys, as configured in the `aea-config.yaml`: - `private_key_paths`: This is a dictionary mapping identifiers to the file paths of private keys used in the AEA. For each identifier, e.g. `fetchai`, the AEA can have one private key. The private keys listed here are available in the `Decision Maker` and the associated public keys and addresses are available in all skills. The AEA uses these keys to sign transactions and messages. These keys usually hold the AEAs funds. - `connection_private_key_paths`: This is a dictionary mapping identifiers to the file paths of private keys used in connections. For each identifier, e.g. `fetchai`, the `Multiplexer` can have one private key. The private keys listed here are available in the connections. The connections use these keys to secure message transport, for instance. -It is the responsibility of the AEA's user to safe-guard the keys used and ensure that keys are only used in a single AEA. Using the same key across different AEAs will lead to various failure modes. +It is the responsibility of the AEA's user to safeguard the keys used and ensure that keys are only used in a single AEA. Using the same key across different AEAs will lead to various failure modes. -Private keys can be encrypted at rest. The CLI commands used for interacting with the wallet allow specifying a password for encryption/decryption. +Private keys can be encrypted at rest. The CLI commands used for interacting with the wallet allow specifying a password for encryption/decryption. ### Identity @@ -31,7 +33,7 @@ The `Identity` is an abstrac The identity can be accessed in a `Skill` via the `AgentContext`. -## Optional components used by AEAs +## Optional Components Used by AEAs ### Contracts @@ -43,30 +45,26 @@ The identity can be accessed in a `Skill` via the here. -## Putting it together +## Putting it Together Taken together, the core components from this section and the first part provide the following simplified illustration of an AEA: Simplified illustration of an AEA -## Next steps +## Next Steps -### Recommended +### Recommended We recommend you continue with the next step in the 'Getting Started' series: - How AEAs talk to each other - Interaction protocols -### Relevant deep-dives +### Relevant Deep-Dives Understanding the decision maker is vital to developing a goal oriented and crypto-economically safe AEA. You can learn more about the `DecisionMaker` in the following section: - Decision Maker - Understanding `Contracts` is important when developing AEAs that make commitments or use smart contracts for other purposes. You can learn more about the `Contracts` agents use in the following section: - Contracts - - -
diff --git a/docs/css/my-styles.css b/docs/css/my-styles.css index 0799b02f96..92508981d5 100644 --- a/docs/css/my-styles.css +++ b/docs/css/my-styles.css @@ -1,37 +1,75 @@ -pre { - background-color: #f8f8f7; +/* overriding colours */ +[data-md-color-scheme="default"] { + --md-primary-fg-color: #4051b5; + --md-typeset-color: #525252; + --md-a-color:#1d6ff5; +} +[data-md-color-scheme="slate"] { + --md-primary-fg-color: #fff; + --md-typeset-color: #d0d6fc; + --md-a-color:#5997fd; +} + +/*overriding the header*/ +.md-header-nav__button.md-logo img { + width: auto!important; } -code { - background-color: #0083fb; +.md-nav__button .md-logo{ + width: auto!important; } -/* this doesn't work now -.md-nav__link { - text-transform: uppercase; - color: #0083fb; +.md-header__button.md-logo img { + width: auto !important; } -*/ -/* Katharine's css additions */ -.md-header, -.md-tabs, -.md-footer-meta, -.md-footer-nav, -.md-footer-nav__inner { - background-color: #172b6e; + +@media screen and (max-width: 76.1875em) { + .md-nav--primary .md-nav__title[for="__drawer"] { + background-color: #202943 !important; + } + + .md-nav--primary .md-nav__title[for=__drawer] img{ + width: 180px; + height: auto; + } } -.md-nav__title { - color: #172b6e; +.md-header{ + background-color:#202943!important; + padding: 10px; + height: auto; } -.md-icon { - ./assets/images/favicon.ico; +/* Overriding font header, link, paragraph styling */ +.md-typeset h3, +.md-typeset h1, +.md-typeset h2 { + margin-bottom: 0.4em; + color: var(--md-primary-fg-color); + font-weight: 400; } -/* Needed so that Mermaid UML diagrams don't end up being massively tall */ -svg{ - height: auto; +.md-typeset a { + color: var(--md-a-color); +} -} \ No newline at end of file +.black-link{ + color: black!important; +} + +.md-nav__item .md-nav__link--active { + padding: 4px 8px; + position: relative; + left: -8px; + background: #E9EBFC; + border-radius: 16px; + width: fit-content; + color: rgb(64, 81, 181) +} + +@media screen and (max-width: 76.1875em) { + .md-nav__item .md-nav__link--active { + left: 0; + } +} diff --git a/docs/debug.md b/docs/debug.md index 1a75cb0271..4917568702 100644 --- a/docs/debug.md +++ b/docs/debug.md @@ -1,3 +1,5 @@ +# Debugging + There are multiple ways in which to configure your AEA for debugging during development. We focus on the standard Python approach here. ## Using `pdb` stdlib @@ -16,7 +18,7 @@ aea -s run For more guidance on how to use `pdb` check out the documentation. -## Using an IDE: +## Using an IDE - For VSCode modify the `launch.json` to include the following information: @@ -36,4 +38,5 @@ For more guidance on how to use `pdb` check out the stand-alone transaction demo. The main difference is that now we are going to use the decision-maker to sign the transaction. -First, import the libraries and the set the constant values. (Get the packages directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) +First, import the libraries and the set the constant values. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) ``` python import logging @@ -37,9 +39,9 @@ FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" ``` -## Create a private key and an AEA +## Create a Private Key and an AEA -To have access to the decision-maker, which is responsible for signing transactions, we need to create an AEA. We can create a an AEA with the builder, providing it with a private key we generate first. +To have access to the decision-maker, which is responsible for signing transactions, we need to create an AEA. We can create an AEA with the builder, providing it with a private key we generate first. ``` python # Create a private key @@ -59,7 +61,7 @@ To have access to the decision-maker, which is responsible for signing transacti my_aea = builder.build() ``` -## Add a simple skill +## Add a Simple Skill Add a simple skill with a signing handler and the signing dialogues. @@ -85,7 +87,8 @@ Add a simple skill with a signing handler and the signing dialogues. my_aea.resources.add_skill(simple_skill) ``` -## Create a second identity +## Create a Second Identity + ``` python # create a second identity create_private_key( @@ -103,9 +106,10 @@ Add a simple skill with a signing handler and the signing dialogues. ) ``` -## Create the signing message +## Create the Signing Message + +Next, we are creating the signing message and sending it to the decision-maker. -Next, we are creating the signing message and we send it to the decision-maker. ``` python # create signing message for decision maker to sign terms = Terms( @@ -143,9 +147,10 @@ Next, we are creating the signing message and we send it to the decision-maker. ``` -## Run the agent +## Run the Agent + +Finally, we are running the agent and expect the signed transaction to be printed in the terminal. -Finally, we are running the agent and we expect the signed transaction to be printed in the terminal. ``` python # Set the AEA running in a different thread try: @@ -164,9 +169,10 @@ Finally, we are running the agent and we expect the signed transaction to be pri After the completion of the signing, we get the signed transaction. -## More details +## More Details To be able to register a handler that reads the internal messages, we have to create a class at the end of the file which processes the signing messages. + ``` python class SigningDialogues(Model, BaseSigningDialogues): """Signing dialogues model.""" @@ -298,275 +304,274 @@ class SigningHandler(Handler): You can find the full code for this example below: -
Transaction via decision-maker full code - -``` python -import logging -import time -from threading import Thread -from typing import Optional, cast - -from aea_ledger_fetchai import FetchAICrypto - -from aea.aea_builder import AEABuilder -from aea.configurations.base import PublicId, SkillConfig -from aea.crypto.helpers import create_private_key -from aea.crypto.ledger_apis import LedgerApis -from aea.crypto.wallet import Wallet -from aea.helpers.transaction.base import RawTransaction, Terms -from aea.identity.base import Identity -from aea.protocols.base import Address, Message -from aea.protocols.dialogue.base import Dialogue -from aea.skills.base import Handler, Model, Skill, SkillContext - -from packages.fetchai.protocols.signing.dialogues import SigningDialogue -from packages.fetchai.protocols.signing.dialogues import ( - SigningDialogues as BaseSigningDialogues, -) -from packages.fetchai.protocols.signing.message import SigningMessage - -from tests.conftest import get_wealth_if_needed - - -logger = logging.getLogger("aea") -logging.basicConfig(level=logging.INFO) - -FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" -FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" - - -def run(): - """Run demo.""" - - # Create a private key - create_private_key( - FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1 - ) - - # Instantiate the builder and build the AEA - # By default, the default protocol, error skill and stub connection are added - builder = AEABuilder() - - builder.set_name("my_aea") - - builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_1) - - # Create our AEA - my_aea = builder.build() - - # add a simple skill with handler - skill_context = SkillContext(my_aea.context) - skill_config = SkillConfig(name="simple_skill", author="fetchai", version="0.1.0") - signing_handler = SigningHandler( - skill_context=skill_context, name="signing_handler" - ) - signing_dialogues_model = SigningDialogues( - skill_context=skill_context, - name="signing_dialogues", - self_address=str(skill_config.public_id), - ) - - simple_skill = Skill( - skill_config, - skill_context, - handlers={signing_handler.name: signing_handler}, - models={signing_dialogues_model.name: signing_dialogues_model}, - ) - my_aea.resources.add_skill(simple_skill) - - # create a second identity - create_private_key( - FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2 - ) - - counterparty_wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2}) - get_wealth_if_needed(counterparty_wallet.addresses["fetchai"]) - - counterparty_identity = Identity( - name="counterparty_aea", - addresses=counterparty_wallet.addresses, - public_keys=counterparty_wallet.public_keys, - default_address_key=FetchAICrypto.identifier, - ) - - # create signing message for decision maker to sign - terms = Terms( - ledger_id=FetchAICrypto.identifier, - sender_address=my_aea.identity.address, - counterparty_address=counterparty_identity.address, - amount_by_currency_id={"FET": -1}, - quantities_by_good_id={"some_service": 1}, - nonce="some_nonce", - fee_by_currency_id={"FET": 0}, - ) - get_wealth_if_needed(terms.sender_address) - - signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues) - stub_transaction = LedgerApis.get_transfer_transaction( - terms.ledger_id, - terms.sender_address, - terms.counterparty_address, - terms.sender_payable_amount, - terms.sender_fee, - terms.nonce, - ) - signing_msg = SigningMessage( - performative=SigningMessage.Performative.SIGN_TRANSACTION, - dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(), - raw_transaction=RawTransaction(FetchAICrypto.identifier, stub_transaction), - terms=terms, +??? note "Transaction via decision-maker full code:" + + ``` python + import logging + import time + from threading import Thread + from typing import Optional, cast + + from aea_ledger_fetchai import FetchAICrypto + + from aea.aea_builder import AEABuilder + from aea.configurations.base import PublicId, SkillConfig + from aea.crypto.helpers import create_private_key + from aea.crypto.ledger_apis import LedgerApis + from aea.crypto.wallet import Wallet + from aea.helpers.transaction.base import RawTransaction, Terms + from aea.identity.base import Identity + from aea.protocols.base import Address, Message + from aea.protocols.dialogue.base import Dialogue + from aea.skills.base import Handler, Model, Skill, SkillContext + + from packages.fetchai.protocols.signing.dialogues import SigningDialogue + from packages.fetchai.protocols.signing.dialogues import ( + SigningDialogues as BaseSigningDialogues, ) - signing_dialogue = cast( - Optional[SigningDialogue], - signing_dialogues.create_with_message("decision_maker", signing_msg), - ) - assert signing_dialogue is not None - my_aea.context.decision_maker_message_queue.put_nowait(signing_msg) - - # Set the AEA running in a different thread - try: - logger.info("STARTING AEA NOW!") - t = Thread(target=my_aea.start) - t.start() - - # Let it run long enough to interact with the decision maker - time.sleep(1) - finally: - # Shut down the AEA - logger.info("STOPPING AEA NOW!") - my_aea.stop() - t.join() - - -class SigningDialogues(Model, BaseSigningDialogues): - """Signing dialogues model.""" - - def __init__(self, self_address: Address, **kwargs) -> None: - """ - Initialize dialogues. - - :return: None - """ - Model.__init__(self, **kwargs) - - def role_from_first_message( # pylint: disable=unused-argument - message: Message, receiver_address: Address - ) -> Dialogue.Role: - """Infer the role of the agent from an incoming/outgoing first message - - :param message: an incoming/outgoing first message - :param receiver_address: the address of the receiving agent - :return: The role of the agent - """ - return SigningDialogue.Role.SKILL - - BaseSigningDialogues.__init__( - self, - self_address=self_address, - role_from_first_message=role_from_first_message, + from packages.fetchai.protocols.signing.message import SigningMessage + + from tests.conftest import get_wealth_if_needed + + + logger = logging.getLogger("aea") + logging.basicConfig(level=logging.INFO) + + FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" + FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" + + + def run(): + """Run demo.""" + + # Create a private key + create_private_key( + FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1 + ) + + # Instantiate the builder and build the AEA + # By default, the default protocol, error skill and stub connection are added + builder = AEABuilder() + + builder.set_name("my_aea") + + builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_1) + + # Create our AEA + my_aea = builder.build() + + # add a simple skill with handler + skill_context = SkillContext(my_aea.context) + skill_config = SkillConfig(name="simple_skill", author="fetchai", version="0.1.0") + signing_handler = SigningHandler( + skill_context=skill_context, name="signing_handler" + ) + signing_dialogues_model = SigningDialogues( + skill_context=skill_context, + name="signing_dialogues", + self_address=str(skill_config.public_id), + ) + + simple_skill = Skill( + skill_config, + skill_context, + handlers={signing_handler.name: signing_handler}, + models={signing_dialogues_model.name: signing_dialogues_model}, + ) + my_aea.resources.add_skill(simple_skill) + + # create a second identity + create_private_key( + FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2 + ) + + counterparty_wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2}) + get_wealth_if_needed(counterparty_wallet.addresses["fetchai"]) + + counterparty_identity = Identity( + name="counterparty_aea", + addresses=counterparty_wallet.addresses, + public_keys=counterparty_wallet.public_keys, + default_address_key=FetchAICrypto.identifier, + ) + + # create signing message for decision maker to sign + terms = Terms( + ledger_id=FetchAICrypto.identifier, + sender_address=my_aea.identity.address, + counterparty_address=counterparty_identity.address, + amount_by_currency_id={"FET": -1}, + quantities_by_good_id={"some_service": 1}, + nonce="some_nonce", + fee_by_currency_id={"FET": 0}, + ) + get_wealth_if_needed(terms.sender_address) + + signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues) + stub_transaction = LedgerApis.get_transfer_transaction( + terms.ledger_id, + terms.sender_address, + terms.counterparty_address, + terms.sender_payable_amount, + terms.sender_fee, + terms.nonce, + ) + signing_msg = SigningMessage( + performative=SigningMessage.Performative.SIGN_TRANSACTION, + dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(), + raw_transaction=RawTransaction(FetchAICrypto.identifier, stub_transaction), + terms=terms, ) - - -class SigningHandler(Handler): - """Implement the signing handler.""" - - SUPPORTED_PROTOCOL = SigningMessage.protocol_id # type: Optional[PublicId] - - def setup(self) -> None: - """Implement the setup for the handler.""" - - def handle(self, message: Message) -> None: - """ - Implement the reaction to a message. - - :param message: the message - :return: None - """ - signing_msg = cast(SigningMessage, message) - - # recover dialogue - signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues) signing_dialogue = cast( - Optional[SigningDialogue], signing_dialogues.update(signing_msg) + Optional[SigningDialogue], + signing_dialogues.create_with_message("decision_maker", signing_msg), ) - if signing_dialogue is None: - self._handle_unidentified_dialogue(signing_msg) - return - - # handle message - if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION: - self._handle_signed_transaction(signing_msg, signing_dialogue) - elif signing_msg.performative is SigningMessage.Performative.ERROR: - self._handle_error(signing_msg, signing_dialogue) - else: - self._handle_invalid(signing_msg, signing_dialogue) - - def teardown(self) -> None: - """ - Implement the handler teardown. - - :return: None - """ - - def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None: - """ - Handle an unidentified dialogue. - - :param msg: the message - """ - self.context.logger.info( - "received invalid signing message={}, unidentified dialogue.".format( - signing_msg + assert signing_dialogue is not None + my_aea.context.decision_maker_message_queue.put_nowait(signing_msg) + + # Set the AEA running in a different thread + try: + logger.info("STARTING AEA NOW!") + t = Thread(target=my_aea.start) + t.start() + + # Let it run long enough to interact with the decision maker + time.sleep(1) + finally: + # Shut down the AEA + logger.info("STOPPING AEA NOW!") + my_aea.stop() + t.join() + + + class SigningDialogues(Model, BaseSigningDialogues): + """Signing dialogues model.""" + + def __init__(self, self_address: Address, **kwargs) -> None: + """ + Initialize dialogues. + + :return: None + """ + Model.__init__(self, **kwargs) + + def role_from_first_message( # pylint: disable=unused-argument + message: Message, receiver_address: Address + ) -> Dialogue.Role: + """Infer the role of the agent from an incoming/outgoing first message + + :param message: an incoming/outgoing first message + :param receiver_address: the address of the receiving agent + :return: The role of the agent + """ + return SigningDialogue.Role.SKILL + + BaseSigningDialogues.__init__( + self, + self_address=self_address, + role_from_first_message=role_from_first_message, ) - ) - - def _handle_signed_transaction( - self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue - ) -> None: - """ - Handle a signing message. - - :param signing_msg: the signing message - :param signing_dialogue: the dialogue - :return: None - """ - self.context.logger.info("transaction signing was successful.") - logger.info(signing_msg.signed_transaction) - - def _handle_error( - self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue - ) -> None: - """ - Handle an oef search message. - - :param signing_msg: the signing message - :param signing_dialogue: the dialogue - :return: None - """ - self.context.logger.info( - "transaction signing was not successful. Error_code={} in dialogue={}".format( - signing_msg.error_code, signing_dialogue + + + class SigningHandler(Handler): + """Implement the signing handler.""" + + SUPPORTED_PROTOCOL = SigningMessage.protocol_id # type: Optional[PublicId] + + def setup(self) -> None: + """Implement the setup for the handler.""" + + def handle(self, message: Message) -> None: + """ + Implement the reaction to a message. + + :param message: the message + :return: None + """ + signing_msg = cast(SigningMessage, message) + + # recover dialogue + signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues) + signing_dialogue = cast( + Optional[SigningDialogue], signing_dialogues.update(signing_msg) ) - ) - - def _handle_invalid( - self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue - ) -> None: - """ - Handle an oef search message. - - :param signing_msg: the signing message - :param signing_dialogue: the dialogue - :return: None - """ - self.context.logger.warning( - "cannot handle signing message of performative={} in dialogue={}.".format( - signing_msg.performative, signing_dialogue + if signing_dialogue is None: + self._handle_unidentified_dialogue(signing_msg) + return + + # handle message + if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION: + self._handle_signed_transaction(signing_msg, signing_dialogue) + elif signing_msg.performative is SigningMessage.Performative.ERROR: + self._handle_error(signing_msg, signing_dialogue) + else: + self._handle_invalid(signing_msg, signing_dialogue) + + def teardown(self) -> None: + """ + Implement the handler teardown. + + :return: None + """ + + def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None: + """ + Handle an unidentified dialogue. + + :param msg: the message + """ + self.context.logger.info( + "received invalid signing message={}, unidentified dialogue.".format( + signing_msg + ) ) - ) - - -if __name__ == "__main__": - run() -``` -
\ No newline at end of file + + def _handle_signed_transaction( + self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue + ) -> None: + """ + Handle a signing message. + + :param signing_msg: the signing message + :param signing_dialogue: the dialogue + :return: None + """ + self.context.logger.info("transaction signing was successful.") + logger.info(signing_msg.signed_transaction) + + def _handle_error( + self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue + ) -> None: + """ + Handle an oef search message. + + :param signing_msg: the signing message + :param signing_dialogue: the dialogue + :return: None + """ + self.context.logger.info( + "transaction signing was not successful. Error_code={} in dialogue={}".format( + signing_msg.error_code, signing_dialogue + ) + ) + + def _handle_invalid( + self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue + ) -> None: + """ + Handle an oef search message. + + :param signing_msg: the signing message + :param signing_dialogue: the dialogue + :return: None + """ + self.context.logger.warning( + "cannot handle signing message of performative={} in dialogue={}.".format( + signing_msg.performative, signing_dialogue + ) + ) + + + if __name__ == "__main__": + run() + ``` diff --git a/docs/decision-maker.md b/docs/decision-maker.md index 2e5bfab0d7..db196496ab 100644 --- a/docs/decision-maker.md +++ b/docs/decision-maker.md @@ -1,6 +1,8 @@ +# Decision Maker + The `DecisionMaker` can be thought of like a wallet manager plus "economic brain" of the AEA. It is responsible for the AEA's crypto-economic security and goal management, and it contains the preference and ownership representation of the AEA. The decision maker is the only component which has access to the wallet's private keys. -## Interaction with skills +## Interaction with Skills Skills communicate with the decision maker via `Messages`. At present, the decision maker processes messages of two protocols: @@ -9,7 +11,8 @@ Skills communicate with the decision maker via `StateUpdateMessage`: it is used to initialize the decision maker with preferences and ownership states. It can also be used to update the ownership states in the decision maker if the settlement of transaction takes place. A message, say `msg`, is sent to the decision maker like so from any skill: -``` + +``` python self.context.decision_maker_message_queue.put_nowait(msg) ``` @@ -20,15 +23,15 @@ To process `Messages` from the decision maker in a given skill you need to creat ``` python class SigningHandler(Handler): - protocol_id = SigningMessage.protocol_id + protocol_id = SigningMessage.protocol_id - def handle(self, message: Message): - """ - Handle a signing message. + def handle(self, message: Message): + """ + Handle a signing message. - :param message: the signing message from the decision maker. - """ - # code to handle the message + :param message: the signing message from the decision maker. + """ + # code to handle the message ``` ## Custom `DecisionMaker` @@ -50,10 +53,7 @@ The easiest way to add a custom decision maker handler is to run the following c aea scaffold decision-maker-handler ``` -You can then implement your own custom logic to process messages and interact with the `Wallet`. +You can then implement your own custom logic to process messages and interact with the `Wallet`. -
-

Note

-

For examples how to use these concepts have a look at the tac_ skills. These functionalities are experimental and subject to change. -

-
\ No newline at end of file +!!! note + For examples how to use these concepts have a look at the `tac_` skills. These functionalities are experimental and subject to change. diff --git a/docs/defining-data-models.md b/docs/defining-data-models.md index 26542c183d..b51b9afdc8 100644 --- a/docs/defining-data-models.md +++ b/docs/defining-data-models.md @@ -1,10 +1,11 @@ +# Defining Data Models + In this section, we explain how to define _data models_, an important component of the OEF Search & Discovery. It allows agents to describe themselves and to discover the services/resources they are interested in. In a sentence, a `DataModel` is a set of `attributes`, and a `Description` of a service/resource is an assignment of those attributes. All you need to specify data models and descriptions (that is, instances of the data model) can be found in the `aea.helpers.search` module. - ## Attributes At the lowest level of our data model language, we have the `Attribute`. @@ -14,11 +15,11 @@ It is identified by a `name`, that must be unique in a given data model (that is Every attribute has a `type`, that specifies the domain of the property, that is, the possible values that the attribute can assume. At the moment, we support five types of attributes: -* strings -* integers -* booleans -* floats -* locations, i.e. instances of `Location` (pairs of (latitude, longitude)) +- strings +- integers +- booleans +- floats +- locations, i.e. instances of `Location` (pairs of (latitude, longitude)) An attribute can be `optional`, in the sense that instantiation of the attribute is not mandatory by the instances of the data model. @@ -26,15 +27,15 @@ Finally, every attribute might have a `description` that explains the purpose of **Example**: suppose we have a bookshop, and we want to describe the books we sell. Presumably, we would like to include: the following properties of our books: -* The `title` -* The `author` -* The `genre` (e.g. science fiction, horror) -* The `year of publication` -* The `average rating` (average of the ratings between 0 and 5) -* The `ISBN` code -* If it can be sold as an e-book. +- The `title` +- The `author` +- The `genre` (e.g. science fiction, horror) +- The `year of publication` +- The `average rating` (average of the ratings between 0 and 5) +- The `ISBN` code +- If it can be sold as an e-book. -For each of this fields, we can define an attribute by using `Attribute`: +For each of these fields, we can define an attribute by using `Attribute`: ``` python from aea.helpers.search.models import Attribute, Location @@ -47,6 +48,7 @@ attr_isbn = Attribute("ISBN", str, True, "The ISBN.") attr_ebook = Attribute("ebook_available", bool, False, "If the book can be sold as an e-book.") attr_bookshop = Attribute("bookshop_pos", Location, False, "The location of the bookshop where you can find the book") ``` + Let's focus on the parameters of the `Attribute` constructor: 1. the first one is the name of the attribute. It is needed to instantiate a data model and to define queries over it. @@ -56,7 +58,7 @@ Let's focus on the parameters of the `Attribute` constructor: 3. the third one is a boolean that specifies whether the attribute is _always required_ or it _can be omitted_. For example, we might not be able to specify the `ebook_available` attribute, maybe because it's not applicable to some kind of books. 4. the fourth parameter is the description, that is a short description of the purpose of the attribute. -## Data models +## Data Models A _data model_ is just a set of _attributes_. The class that implements the data model is `DataModel`. @@ -120,7 +122,7 @@ We defined the descriptions for two books, namely `It` and `_1984`, that refers The attributes are instantiated with a dictionary that has: -* as keys, the name of the attributes. -* as values, the values associated with the attributes. +- as keys, the name of the attributes. +- as values, the values associated with the attributes. Notice that in the latter book we omitted the `average_rating` field. We are allowed to do that because of the `average_rating` attribute is not mandatory. diff --git a/docs/demos.md b/docs/demos.md index 0c9d0bd737..ea2211f0cc 100644 --- a/docs/demos.md +++ b/docs/demos.md @@ -1,5 +1,7 @@ +# Demos + We provide demo guides for multiple use-cases, each one involving several AEAs interacting in a different scenario. These demos serve to highlight the concept of AEAs as well as provide inspiration for developers. Demos should not be taken as production ready software, although every care is taken to fix bugs when reported. -Demos are alphabetically sorted, we recommend you start with the weather skills demo. \ No newline at end of file +Demos are alphabetically sorted, we recommend you start with the weather skills demo. diff --git a/docs/deployment.md b/docs/deployment.md index 5817fef348..b73888a7b3 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,3 +1,4 @@ +# Deployment The easiest way to run an AEA is using your development environment. @@ -8,6 +9,7 @@ For deployment, we recommend you use Kubernetes navigate to our TAC deployment example. diff --git a/docs/design-principles.md b/docs/design-principles.md index 052fc3132e..7f5c2c8672 100644 --- a/docs/design-principles.md +++ b/docs/design-principles.md @@ -1,12 +1,12 @@ -The AEA framework development is guided by the following 8 principles: +# Design Principles -* **Accessibility**: ease of use. -* **Modularity**: encourages module creation, sharing and reuse. -* **Openness**: easily extensible with third-party libraries. -* **Conciseness**: conceptually simple. -* **Value-driven**: drives immediate value. -* **Low entry barriers**: leverages existing programming languages and web protocols. -* **Safety**: safe for the user (economically speaking). -* **Goal-alignment**: seamless facilitation of users' preferences and goals. +The AEA framework development is guided by the following 8 principles: -
\ No newline at end of file +- **Accessibility**: ease of use. +- **Modularity**: encourages module creation, sharing and reuse. +- **Openness**: easily extensible with third-party libraries. +- **Conciseness**: conceptually simple. +- **Value-driven**: drives immediate value. +- **Low entry barriers**: leverages existing programming languages and web protocols. +- **Safety**: safe for the user (economically speaking). +- **Goal-alignment**: seamless facilitation of users' preferences and goals. diff --git a/docs/development-setup.md b/docs/development-setup.md index b9175eaa41..e63f4c7e22 100644 --- a/docs/development-setup.md +++ b/docs/development-setup.md @@ -1,4 +1,4 @@ - +# Development Setup An AEA consists of packages . When developing, it helps to be able to save packages in a local package registry, rather than pushing them to remote registry. This guide helps you set up a local package registry and configure the working directory for development. @@ -13,20 +13,13 @@ There are two ways to write code for an AEA: To prepare a directory (henceforth working directory) for development with the AEA framework you can take a few steps: - Either, manually: - - - Ensure you start with an empty working directory to avoid any unnecessary side effects. - - - In your working directory, create an empty folder called `packages`. This folder will act as the local registry for packages. - - - In your working directory, create a `.env` file with the constant `PYTHONPATH=$PYTHONPATH:path_to_packages_dir` where `path_to_packages_dir` is the path to the packages folder in your working directory. - + - Ensure you start with an empty working directory to avoid any unnecessary side effects. + - In your working directory, create an empty folder called `packages`. This folder will act as the local registry for packages. + - In your working directory, create a `.env` file with the constant `PYTHONPATH=$PYTHONPATH:path_to_packages_dir` where `path_to_packages_dir` is the path to the `packages` folder in your working directory. - Or, automated: - - - Fork our template repo for AEA development. Then clone it to your machine. - + - Fork our template repo for AEA development. Then clone it to your machine. - Depending on your editor, you might take further steps: - - - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `"python.envFile": "${workspaceFolder}/.env"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect. + - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `"python.envFile": "${workspaceFolder}/.env"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect. After developing a package, you can add it to an AEA project in the working directory (e.g. `aea create AGENT_NAME && cd AGENT_NAME && aea add --local PACKAGE_TYPE PUBLIC_ID` will create a new AEA project `AGENT_NAME` and add the package of type `PACKAGE_TYPE` with public id `PUBLIC_ID` to it.) @@ -35,23 +28,16 @@ After developing a package, you can add it to an AEA project in the working dire It is also possible to develop directly in an AEA project: - Prepare a directory (henceforth working directory) for development. - - Create a new project `aea create AGENT_NAME && cd AGENT_NAME` - - Scaffold a new package `aea scaffold --with-symlinks PACKAGE_TYPE PACKAGE_NAME`. This will create the package scaffold under the directory `{PACKAGE_TYPE}s` and create symlinks to ensure package import paths line up with the folder structure. The symlinks are not needed to run the AEA. They are purely for your IDE. - - In your working directory, create a `.env` file with the constant `PYTHONPATH=$PYTHONPATH:path_to_project_dir` where `path_to_project_dir` is the path to the AEA project contained in your working directory. - - Depending on your editor, you might take further steps: + - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `"python.envFile": "${workspaceFolder}/.env"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect. - - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `"python.envFile": "${workspaceFolder}/.env"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect. - -## General advice +## General Advice This advice partially overlaps with the previous two sections: - When developing a specific AEA, it might be helpful to publish/push or fetch/add from local registry. From your working directory/AEA project, simply execute the usual AEA CLI commands. The CLI will first search in the `packages` directory, then in the remote AEA registry. You can explicitly point to local registry by providing flag `--local` or `--remote` to only point to remote registry (see here for more details on CLI commands). - -- When working on an AEA, it may help to provide a symbolic link to the packages directory, so that the import paths are detected by your editor. Simply create an empty file with `touch packages` in your AEA project, then create a symbolic link to the `packages` directory with `ln -s ../packages packages`. - +- When working on an AEA, it may help to provide a symbolic link to the `packages` directory, so that the import paths are detected by your editor. Simply create an empty file with `touch packages` in your AEA project, then create a symbolic link to the `packages` directory with `ln -s ../packages packages`. - Alternatively, it can help to provide symbolic links within an AEA to align import paths with folder structure. Simply create an empty file with `touch packages` in your AEA project, then create a symbolic link to `ln -s vendor packages`. diff --git a/docs/diagram.md b/docs/diagram.md index 6c3c166aba..bf27cdd5de 100644 --- a/docs/diagram.md +++ b/docs/diagram.md @@ -1,3 +1,5 @@ +# Architectural Diagram + The framework has two distinctive parts. - A **core** that is developed by the Fetch.ai team as well as external contributors. @@ -5,7 +7,7 @@ The framework has two distinctive parts. Currently, the framework supports four types of packages which can be added to the core as modules: -- Skills encapsulate logic that deliver economic value to the AEA. Skills are the main focus of the framework's extensibility. +- Skills encapsulate logic that deliver economic value to the AEA. Skills are the main focus of the framework's extensibility. - Protocols define the structure of agent-to-agent and component-to-component interactions (messages and dialogues) for agents. - Connections provide interfaces for the agent to connect with the outside world. They wrap SDKs or APIs and provide interfaces to networks, ledgers and other services. - Contracts wrap smart contracts for Fetch.ai and third-party decentralized ledgers. @@ -14,30 +16,25 @@ The following figure illustrates the framework's architecture: Simplified illustration of an AEA - The execution is broken down in more detail below: Execution of an AEA The agent operation breaks down into three parts: -* **Setup**: calls the `setup()` method of all registered resources -* **Operation**: - * Agent loop (Thread 1 - Asynchronous agent loop): - * `react()`: this function grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` method on the Handler(s) responsible for them. - * `act()`: this function calls the `act()` method of all registered Behaviours. - * `update()`: this function enqueues scheduled tasks for execution with the `TaskManager` and executes the decision maker. - * Task loop (Thread 2- Synchronous): executes available tasks - * Decision maker loop (Thread 3- Synchronous): processes internal messages - * Multiplexer (Thread 4 - Asynchronous event loop): processes incoming and outgoing messages across several connections asynchronously. -* **Teardown**: calls the `teardown()` method of all registered resources - +- **Setup**: calls the `setup()` method of all registered resources +- **Operation**: + - Agent loop (Thread 1 - Asynchronous agent loop): + - `react()`: this function grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` method on the Handler(s) responsible for them. + - `act()`: this function calls the `act()` method of all registered Behaviours. + - `update()`: this function enqueues scheduled tasks for execution with the `TaskManager` and executes the decision maker. + - Task loop (Thread 2- Synchronous): executes available tasks + - Decision maker loop (Thread 3- Synchronous): processes internal messages + - Multiplexer (Thread 4 - Asynchronous event loop): processes incoming and outgoing messages across several connections asynchronously. +- **Teardown**: calls the `teardown()` method of all registered resources To prevent a developer from blocking the main loop with custom skill code, an execution time limit is applied to every `Behaviour.act` and `Handler.handle` call. By default, the execution limit is set to `0` seconds, which disables the feature. You can set the limit to a strictly positive value (e.g. `0.1` seconds) to test your AEA for production readiness. If the `act` or `handle` time exceed this limit, the call will be terminated. An appropriate message is added to the logs in the case of some code execution being terminated. - - -
diff --git a/docs/erc1155-skills.md b/docs/erc1155-skills.md index 2ccb214906..f2c30d4a8f 100644 --- a/docs/erc1155-skills.md +++ b/docs/erc1155-skills.md @@ -1,10 +1,12 @@ +# Contract Deploy and Interact + The AEA `erc1155_deploy` and `erc1155_client` skills demonstrate an interaction between two AEAs which use a smart contract. -* The `erc1155_deploy` skill deploys the smart contract, creates and mints items. -* The `erc1155_client` skill signs a transaction to complete a trustless trade with its counterparty. +- The `erc1155_deploy` skill deploys the smart contract, creates and mints items. +- The `erc1155_client` skill signs a transaction to complete a trustless trade with its counterparty. + +## Preparation Instructions -## Preparation instructions - ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. @@ -13,14 +15,12 @@ Follow the Preliminaries and -

Note

-

This is only for demonstrative purposes since the AEA deploying the contract also has the ability to mint tokens. In reality, the transfer of tokens from the AEA signing the transaction is worthless.

- +!!! note + This is only for demonstrative purposes since the AEA deploying the contract also has the ability to mint tokens. In reality, the transfer of tokens from the AEA signing the transaction is worthless. ## Demo -### Create the deployer AEA +### Create the Deployer AEA Fetch the AEA that will deploy the contract: @@ -31,44 +31,40 @@ aea install aea build ``` -
Alternatively, create from scratch. -

- -Create the AEA that will deploy the contract. - -``` bash -aea create erc1155_deployer -cd erc1155_deployer -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/erc1155_deploy:0.31.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-cosmos": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' -aea install -aea build -``` - -And change the default ledger: -``` bash -aea config set agent.default_ledger ethereum -``` - -

-
+??? note "Alternatively, create from scratch:" + Create the AEA that will deploy the contract. + + ``` bash + aea create erc1155_deployer + cd erc1155_deployer + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/erc1155_deploy:0.31.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-cosmos": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' + aea install + aea build + ``` + + And change the default ledger: + + ``` bash + aea config set agent.default_ledger ethereum + ``` Create a private key for the deployer AEA and add it for Ethereum use: @@ -90,7 +86,7 @@ Finally, certify the key for use by the connections that request that: aea issue-certificates ``` -### Create the client AEA +### Create the Client AEA In another terminal, fetch the client AEA which will receive some tokens from the deployer. @@ -101,44 +97,40 @@ aea install aea build ``` -
Alternatively, create from scratch. -

- -Create the AEA that will get some tokens from the deployer. - -``` bash -aea create erc1155_client -cd erc1155_client -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/erc1155_client:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-cosmos": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' -aea install -aea build -``` - -And change the default ledger: -``` bash -aea config set agent.default_ledger ethereum -``` - -

-
+??? note "Alternatively, create from scratch:" + Create the AEA that will get some tokens from the deployer. + + ``` bash + aea create erc1155_client + cd erc1155_client + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/erc1155_client:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-cosmos": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' + aea install + aea build + ``` + + And change the default ledger: + + ``` bash + aea config set agent.default_ledger ethereum + ``` Create a private key for the client AEA and add it for Ethereum use: @@ -155,6 +147,7 @@ aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` @@ -162,6 +155,7 @@ aea issue-certificates ## Run Ganache Execute the following command to run Ganache: + ``` bash docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat erc1155_deployer/ethereum_private_key.txt),1000000000000000000000" --account="$(cat erc1155_client/ethereum_private_key.txt),1000000000000000000000" ``` @@ -176,15 +170,13 @@ aea get-wealth ethereum You should get `1000000000000000000000`. -
-

Note

-

If no wealth appears after a while, then try funding the private key directly using a web faucet.

-
- +!!! note + If no wealth appears after a while, then try funding the private key directly using a web faucet. -## Update SOEF configurations for both AEAs +## Update SOEF Configurations for both AEAs Update the SOEF configuration in both AEA projects: + ``` bash aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum ``` @@ -193,11 +185,11 @@ aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum First, run the deployer AEA: -``` bash +``` bash aea run ``` -Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of this address. +Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of this address. Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address. The output will be something like `/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm2JPsUX1Su59YVDXJQizYkNSe8JCusqRpLeeTbvY76fE5`. @@ -205,16 +197,18 @@ This is the entry peer address for the local
agent communicatio This AEA then performs the following steps: - * deploys the smart contract - * creates a batch of items in the smart contract - * mints a batch of items in the smart contract +- deploys the smart contract +- creates a batch of items in the smart contract +- mints a batch of items in the smart contract At some point you should see the log output: + ``` bash registering service on SOEF. ``` At this point, configure the client AEA to connect to the same local ACN created by the deployer by running the following command in the client's terminal, replacing `SOME_ADDRESS` with the value you noted above: + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -228,25 +222,21 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ Then, run the client AEA: -``` bash +``` bash aea run ``` You will see that after discovery, the two AEAs exchange information about the transaction and the client at the end signs and sends the signature to the deployer AEA to send it to the network. -
-

Note

-

Transactions on Ropsten can take a significant amount of time! If you run the example a second time, and the previous transaction is still pending, it can lead to a failure. - - The warning message `Cannot verify whether transaction improves utility. Assuming it does!` can be ignored. -

-
+!!! note + Transactions on Ropsten can take a significant amount of time! If you run the example a second time, and the previous transaction is still pending, it can lead to a failure. + The warning message `Cannot verify whether transaction improves utility. Assuming it does!` can be ignored. ## Delete the AEAs When you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs. -``` bash +``` bash cd .. aea delete erc1155_deployer aea delete erc1155_client @@ -256,7 +246,7 @@ aea delete erc1155_client This diagram shows the communication between the various entities in this interaction: -
+``` mermaid sequenceDiagram participant Search participant Erc1155_contract @@ -287,5 +277,4 @@ This diagram shows the communication between the various entities in this intera deactivate Client_AEA deactivate Deployer_AEA deactivate Blockchain - -
\ No newline at end of file +``` diff --git a/docs/generic-skills-step-by-step.md b/docs/generic-skills-step-by-step.md index 0e2eea4fe6..47bd479d56 100644 --- a/docs/generic-skills-step-by-step.md +++ b/docs/generic-skills-step-by-step.md @@ -1,3 +1,5 @@ +# Trade between Two AEAs + This guide is a step-by-step introduction to building AEAs that advertise their static and dynamic data, find other AEAs with required data, negotiate terms of trade, and carry out trades via ledger transactions. If you simply want to run the resulting AEAs
go here. @@ -6,7 +8,7 @@ If you simply want to run the resulting AEAs go here Follow the Preliminaries and Installation sections from the AEA quick start. -## Reference code (Optional) +## Reference Code (Optional) This step-by-step guide goes through the creation of two AEAs which are already developed by Fetch.ai. You can get the finished AEAs, and compare your code against them, by following the next steps: @@ -24,7 +26,7 @@ aea eject skill fetchai/generic_buyer:0.27.5 cd .. ``` -## Simplification step +## Simplification Step To keep file paths consistent with the reference code, we suggest you initialize your local author as `fetchai` for the purpose of this demo only: @@ -37,12 +39,15 @@ aea init --reset --author fetchai ### Step 1: Create the AEA Create a new AEA by typing the following command in the terminal: + ``` bash aea create my_generic_seller cd my_generic_seller aea install ``` + Our newly created AEA is inside the current working directory. Let’s create our new skill that will handle the sale of data. Type the following command: + ``` bash aea scaffold skill generic_seller ``` @@ -55,7 +60,7 @@ The `scaffold skill` command creates the correct structure for a new skill insid - `my_model.py` - `skills.yaml` -### Step 2: Create the behaviour +### Step 2: Create the Behaviour A `Behaviour` class contains the business logic specific to actions initiated by the AEA, rather than reactions to other events. @@ -225,17 +230,17 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): self.context.logger.info("unregistering agent from SOEF.") ``` -This `TickerBehaviour` registers (see `setup` method) and deregisters (see `teardown` method) our AEA’s service on the SOEF search node at regular tick intervals (here 60 seconds). By registering, the AEA becomes discoverable to other AEAs. +This `TickerBehaviour` registers (see `setup` method) and de-registers (see `teardown` method) our AEA’s service on the SOEF search node at regular tick intervals (here 60 seconds). By registering, the AEA becomes discoverable to other AEAs. In `setup`, prior to registrations, we send a message to the ledger connection to check the account balance for the AEA's address on the configured ledger. -### Step 3: Create the handler +### Step 3: Create the Handler So far, we have tasked the AEA with sending register/unregister requests to the SOEF search node. However at present, the AEA has no way of handling the responses it receives from the search node, or in fact messages sent by any other AEA. We have to specify the logic to negotiate with another AEA based on the strategy we want our AEA to follow. The following diagram illustrates the negotiation flow that we want this AEA to use, as well as interactions with a search node and the blockchain between a `seller_AEA` and a `buyer_AEA`. -
+``` mermaid sequenceDiagram participant Search participant Buyer_AEA @@ -272,8 +277,7 @@ We have to specify the logic to negotiate with another AEA based on the strategy deactivate Search deactivate Seller_AEA deactivate Blockchain - -
+``` In our case, `my_generic_seller` is the `Seller_AEA` in the above figure. @@ -351,6 +355,7 @@ class GenericFipaHandler(Handler): def teardown(self) -> None: """Implement the handler teardown.""" ``` + The code above contains the logic for handling `FipaMessages` received by the `my_generic_seller` AEA. We use `FipaDialogues` (more on this below) to keep track of the progress of the negotiation dialogue between the `my_generic_seller` AEA and the `my_generic_buyer` AEA. In the above `handle` method, we first check if a received message belongs to an existing dialogue or if we have to create a new dialogue (the `recover dialogue` part). Once this is done, we break down the AEA's response to each type of negotiation message, as indicated by the message's performative (the `handle message` part). Therefore, we implement the AEA's response to each negotiation message type in a different handler function. @@ -451,6 +456,7 @@ The next code-block handles the decline message we receive from the buyer. Add FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated ) ``` + If we receive a decline message from the buyer we close the dialogue and terminate this conversation with `my_generic_buyer`. Alternatively, we might receive an `ACCEPT` message. In order to handle this option add the following code below the `_handle_decline` function: @@ -485,7 +491,8 @@ Alternatively, we might receive an `ACCEPT` message. In order to handle this opt self.context.outbox.put_message(message=match_accept_msg) ``` -When `my_generic_buyer` accepts the `Proposal` we send it and sends an `ACCEPT` message, we have to respond with another message (`MATCH_ACCEPT_W_INFORM`) to match the acceptance of the terms of trade and to inform the buyer of the address we would like it to send the funds to. + +When `my_generic_buyer` accepts the `Proposal` we send it and sends an `ACCEPT` message, we have to respond with another message (`MATCH_ACCEPT_W_INFORM`) to match the acceptance of the terms of trade and to inform the buyer of the address we would like it to send the funds to. Lastly, we must handle an `INFORM` message, which the buyer uses to inform us that it has indeed sent the funds to the provided address. Add the following code at the end of the file: @@ -556,9 +563,11 @@ Lastly, we must handle an `INFORM` message, which the buyer uses to inform us th ) ) ``` -In the above code, we check the `INFORM` message. If it contains a transaction digest, then we verify that the transaction matches the proposal the buyer accepted. If the transaction is valid and we received the funds then we send the data to the buyer. Otherwise, we do not send the data. + +In the above code, we check the `INFORM` message. If it contains a transaction digest, then we verify that the transaction matches the proposal the buyer accepted. If the transaction is valid and we received the funds, then we send the data to the buyer. Otherwise, we do not send the data. The remaining handlers are as follows: + ``` python def _handle_invalid( self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue @@ -876,7 +885,7 @@ class GenericOefSearchHandler(Handler): The `GenericLedgerApiHandler` deals with `LedgerApiMessages` from the ledger connection and the `GenericOefSearchHandler` handles `OefSearchMessages` from the SOEF connection. -### Step 4: Create the strategy +### Step 4: Create the Strategy Next, we are going to create the strategy that we want our `my_generic_seller` AEA to follow. Rename the `my_model.py` file (`my_generic_seller/skills/generic_seller/my_model.py`) to `strategy.py` and replace the stub code with the following: @@ -1143,7 +1152,7 @@ The following properties and methods deal with different aspects of the strategy The helper private function `collect_from_data_source` is where we read data from a sensor or if there are no sensor we use some default data provided (see the `data_for_sale` property). -### Step 5: Create the dialogues +### Step 5: Create the Dialogues To keep track of the structure and progress of interactions, including negotiations with a buyer AEA and interactions with search nodes and ledgers, we use dialogues. Create a new file in the skill folder (`my_generic_seller/skills/generic_seller/`) and name it `dialogues.py`. Inside this file add the following code: @@ -1397,7 +1406,7 @@ The `FipaDialogues` class contains negotiation dialogues with each `my_generic_b The `FipaDialogues` class extends `BaseFipaDialogues`, which itself derives from the base `Dialogues` class. Similarly, the `FipaDialogue` class extends `BaseFipaDialogue` which itself derives from the base `Dialogue` class. To learn more about dialogues have a look here. -### Step 6: Update the YAML files +### Step 6: Update the YAML Files Since we made so many changes to our AEA we have to update the `skill.yaml` (at `my_generic_seller/skills/generic_seller/skill.yaml`). Make sure you update your `skill.yaml` with the following configuration: @@ -1484,7 +1493,6 @@ aea fingerprint skill fetchai/generic_seller:0.1.0 This will hash each file and save the hash in the fingerprint. This way, in the future we can easily track if any of the files have changed. - ## Generic Buyer AEA ### Step 1: Create the AEA @@ -1511,7 +1519,7 @@ This command creates the correct structure for a new skill inside our AEA projec - `my_model.py` - `skills.yaml` -### Step 2: Create the behaviour +### Step 2: Create the Behaviour Open the `behaviours.py` file (`my_generic_buyer/skills/generic_buyer/behaviours.py`) and replace the stub code with the following: @@ -1700,7 +1708,7 @@ class GenericTransactionBehaviour(TickerBehaviour): This `TickerBehaviour` will send a search query to the SOEF search node at regular tick intervals. -### Step 3: Create the handler +### Step 3: Create the Handler So far, the AEA is tasked with sending search queries to the SOEF search node. However, currently the AEA has no way of handling the responses it receives from the SOEF or messages from other agents. @@ -1779,6 +1787,7 @@ class GenericFipaHandler(Handler): def teardown(self) -> None: """Implement the handler teardown.""" ``` + You will see that we are following similar logic to the `generic_seller` when we develop the `generic_buyer`’s side of the negotiation. First, we create a new dialogue and store it in the dialogues class. Then we are checking what kind of message we received by checking its performative. So lets start creating our handlers: ``` python @@ -1801,6 +1810,7 @@ You will see that we are following similar logic to the `generic_seller` when we ) self.context.outbox.put_message(message=default_msg) ``` + The above code handles messages referencing unidentified dialogues and responds with an error message to the sender. Next we will handle the `PROPOSE` message received from the `my_generic_seller` AEA: ``` python @@ -1843,6 +1853,7 @@ The above code handles messages referencing unidentified dialogues and responds ) self.context.outbox.put_message(message=decline_msg) ``` + When we receive a proposal, we have to check if we have the funds to complete the transaction and if the proposal is acceptable based on our strategy. If the proposal is not affordable or acceptable, we respond with a `DECLINE` message. Otherwise, we send an `ACCEPT` message to the seller. The next code-block handles the `DECLINE` message that we may receive from the seller as a response to our `CFP` or `ACCEPT` messages: @@ -1880,7 +1891,8 @@ The next code-block handles the `DECLINE` message that we may receive from the s FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated ) ``` -The above code terminates each dialogue with the specific AEA and stores the state of the terminated dialogue (whether it was terminated after a `CFP` or an `ACCEPT`). + +The above code terminates each dialogue with the specific AEA and stores the state of the terminated dialogue (whether it was terminated after a `CFP` or an `ACCEPT`). If `my_generic_seller` AEA wants to move on with the sale, it will send a `MATCH_ACCEPT` message. In order to handle this we add the following code: @@ -1922,7 +1934,8 @@ def _handle_match_accept( "informing counterparty={} of payment.".format(fipa_msg.sender[-5:]) ) ``` -The first thing we are checking is if we enabled our AEA to transact with a ledger. If so, we add this negotiation to the queue of transactions to be processed. If not, we simulate non-ledger payment by sending an inform to the seller that the payment is done (say via bank transfer). + +The first thing we are checking is if we enabled our AEA to transact with a ledger. If so, we add this negotiation to the queue of transactions to be processed. If not, we simulate non-ledger payment by sending an `inform` to the seller that the payment is done (say via bank transfer). Lastly, we need to handle `INFORM` messages. This is the message that will have our data: @@ -2101,7 +2114,8 @@ class GenericOefSearchHandler(Handler): ) ) ``` -When we receive a message from the SOEF search node of a type `OefSearchMessage.Performative.SEARCH_RESULT`, we are passing the details to the relevant handler method. In the `_handle_search` function we are checking that the response contains some agents and we stop the search if it does. We pick our first agent and we send a `CFP` message. + +When we receive a message from the SOEF search node of a type `OefSearchMessage.Performative.SEARCH_RESULT`, we are passing the details to the relevant handler method. In the `_handle_search` function, we are checking that the response contains some agents, and we stop the search if it does. We pick our first agent and send a `CFP` message. The last handlers we need are the `GenericSigningHandler` and the `GenericLedgerApiHandler`. These handlers are responsible for `SigningMessages` that we receive from the `DecisionMaker`, and `LedgerApiMessages` that we receive from the ledger connection, respectively. @@ -2443,7 +2457,7 @@ class GenericLedgerApiHandler(Handler): ) ``` -### Step 4: Create the strategy +### Step 4: Create the Strategy We are going to create the strategy that we want our AEA to follow. Rename the `my_model.py` file (in `my_generic_buyer/skills/generic_buyer/`) to `strategy.py` and replace the stub code with the following: @@ -2647,7 +2661,7 @@ The following code block checks if the proposal that we received is acceptable a return result ``` -The `is_affordable_proposal` method in the following code block checks if we can afford the transaction based on the funds we have in our wallet on the ledger. The rest of the methods are self-explanatory. +The `is_affordable_proposal` method in the following code block checks if we can afford the transaction based on the funds we have in our wallet on the ledger. The rest of the methods are self-explanatory. ``` python def is_affordable_proposal(self, proposal: Description) -> bool: @@ -2720,7 +2734,7 @@ The `is_affordable_proposal` method in the following code block checks if we can """Update agent location and query for search.""" ``` -### Step 5: Create the dialogues +### Step 5: Create the Dialogues As mentioned during the creation of the seller AEA, we should keep track of the various interactions an AEA has with others and this is done via dialogues. Create a new file and name it `dialogues.py` (in `my_generic_buyer/skills/generic_buyer/`). Inside this file add the following code: @@ -3059,7 +3073,7 @@ class SigningDialogues(Model, BaseSigningDialogues): The various dialogues classes in the above code snippet store dialogues with other AEAs, services and components, (e.g. SOEF search node via the `fetchai/soef` connection, ledgers via the `fetchai/ledger` connection and the decision maker). They expose useful methods to manipulate these interactions, access previous messages, and enable us to identify possible communications problems between `my_generic_seller` and `my_generic_buyer` AEAs. -### Step 6: Update the YAML files +### Step 6: Update the YAML Files After making so many changes to our skill, we have to update the `skill.yaml` configuration file so it reflects our newly created classes, and contains the values used by the strategy. Make sure `skill.yaml` contains the following configuration: @@ -3149,7 +3163,8 @@ models: is_abstract: false dependencies: {} ``` -We must pay attention to the models and the strategy’s variables. Here we can change the price we would like to buy each reading at, the maximum transaction fee we are prepared to pay, and so on. + +We must pay attention to the models and the strategy’s variables. Here we can change the price we would like to buy each reading at, the maximum transaction fee we are prepared to pay, and so on. Finally, we fingerprint our new skill: @@ -3161,28 +3176,32 @@ This will hash each file and save the hash in the fingerprint. This way, in the ## Run the AEAs -### Create private keys +### Create Private Keys For each AEA, create a private key: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Update the AEA configurations +### Update the AEA Configurations In both AEAs run: + ``` bash aea config set --type dict agent.default_routing \ '{ @@ -3191,7 +3210,7 @@ aea config set --type dict agent.default_routing \ }' ``` -### Fund the buyer AEA +### Fund the Buyer AEA Create some wealth for your buyer on the Fetch.ai testnet (this operation might take a while). @@ -3199,7 +3218,7 @@ Create some wealth for your buyer on the Fetch.ai testnet (this operation might aea generate-wealth fetchai --sync ``` -### Run seller AEA +### Run Seller AEA Add the remaining packages for the seller AEA, then run it: @@ -3216,7 +3235,7 @@ aea run Once you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address. -#### Run buyer AEA +#### Run Buyer AEA Add the remaining packages for the buyer AEA: @@ -3247,6 +3266,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ where `SOME_ADDRESS` is replaced accordingly. Then run the buyer AEA: + ``` bash aea run ``` @@ -3256,20 +3276,19 @@ You will see that the AEAs negotiate and then transact using the Dorado testnet. ## Delete the AEAs When you are done, go up a level and delete the AEAs. + ``` bash cd .. aea delete my_generic_seller aea delete my_generic_buyer ``` -## Next steps +## Next Steps You have completed the "Getting Started" series. Congratulations! The following guide provides some hints on AEA development setup. -### Recommended +### Recommended We recommend you build your own AEA next. There are many helpful guides and demos in the documentation, and a developer community on Discord. Speak to you there! - -
diff --git a/docs/generic-skills.md b/docs/generic-skills.md index 3edd084053..2d78f1bf6a 100644 --- a/docs/generic-skills.md +++ b/docs/generic-skills.md @@ -1,11 +1,13 @@ +# Generic Skills + The AEA generic buyer and seller skills demonstrate an interaction between two AEAs: -* An AEA that provides a (data selling) service. -* An AEA that demands this service. +- An AEA that provides a (data selling) service. +- An AEA that demands this service. ## Discussion -The scope of this guide is demonstrating how to create easily configurable AEAs. The buyer AEA finds the seller, negotiates the terms of trade, and if successful purchases the data by sending payment. The seller AEA sells the service specified in its `skill.yaml` file, delivering it to the buyer upon receiving payment. +The scope of this guide is demonstrating how to create easily configurable AEAs. The buyer AEA finds the seller, negotiates the terms of trade, and if successful purchases the data by sending payment. The seller AEA sells the service specified in its `skill.yaml` file, delivering it to the buyer upon receiving payment. Note that these agents do not utilize a smart contract but interact with a ledger to complete a transaction. Moreover, in this setup, the buyer agent has to trust the seller to send the data upon successful payment. @@ -15,7 +17,7 @@ The corresponding packages can be customised to allow for a database or sensor t The following diagram shows the communication between various entities in this interaction. -
+``` mermaid sequenceDiagram participant Search participant Buyer_AEA @@ -42,21 +44,21 @@ The following diagram shows the communication between various entities in this i deactivate Buyer_AEA deactivate Search deactivate Seller_AEA - deactivate Blockchain - -
+ deactivate Blockchain +``` + +## Preparation Instructions -## Preparation instructions - ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -## Demo instructions +## Demo Instructions -### Create the seller AEA +### Create the Seller AEA First, fetch the seller AEA: + ``` bash aea fetch fetchai/generic_seller:0.29.4 --alias my_seller_aea cd my_seller_aea @@ -64,125 +66,125 @@ aea install aea build ``` -
Alternatively, create from scratch. -

- -The following steps create the seller from scratch: -``` bash -aea create my_seller_aea -cd my_seller_aea -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/generic_seller:0.28.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea install -aea build -``` - -

-
- -### Create the buyer AEA +??? note "Alternatively, create from scratch:" + The following steps create the seller from scratch: + + ``` bash + aea create my_seller_aea + cd my_seller_aea + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/generic_seller:0.28.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +### Create the Buyer AEA Then, in another terminal fetch the buyer AEA: -``` bash -aea fetch fetchai/generic_buyer:0.30.4 --alias my_buyer_aea -cd my_buyer_aea -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the buyer from scratch: ``` bash -aea create my_buyer_aea +aea fetch fetchai/generic_buyer:0.30.4 --alias my_buyer_aea cd my_buyer_aea -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/generic_buyer:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- - -### Add keys for the seller AEA +??? note "Alternatively, create from scratch:" + The following steps create the buyer from scratch: + + ``` bash + aea create my_buyer_aea + cd my_buyer_aea + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/generic_buyer:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +### Add Keys for the Seller AEA Create the private key for the seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Add keys and generate wealth for the buyer AEA +### Add Keys and Generate Wealth for the Buyer AEA The buyer needs to have some wealth to purchase the data from the seller. First, create the private key for the buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for your buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Update the skill configurations +### Update the Skill Configurations The default skill configurations assume that the transaction is settled against the Fetch.ai ledger. In the generic seller's skill configuration file (`my_seller_aea/vendor/fetchai/skills/generi_seller/skill.yaml`) the `data_for_sale` is the data the seller AEA is offering for sale. In the following case, this is a one item dictionary where key is `generic` and value is `data`. -Furthermore, the `service_data` is used to register the seller's service in the SOEF search node and make your agent discoverable. +Furthermore, the `service_data` is used to register the seller's service in the SOEF search node and make your agent discoverable. + ``` yaml models: ... @@ -230,7 +232,7 @@ models: class_name: GenericStrategy ``` -### Update the skill configurations +### Update the Skill Configurations Both skills are abstract skills, make them instantiable: @@ -256,6 +258,7 @@ Once you see a message of the form `To join its network use multiaddr 'SOME_ADDR This is the entry peer address for the local agent communication network created by the seller. Then, configure the buyer to connect to this same local ACN by running the following command in the buyer terminal, replacing `SOME_ADDRESS` with the value you noted above: + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -279,8 +282,8 @@ You will see that the AEAs negotiate and then transact using the Fetch.ai testne When you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs. -``` bash +``` bash cd .. aea delete my_seller_aea aea delete my_buyer_aea -``` \ No newline at end of file +``` diff --git a/docs/generic-storage.md b/docs/generic-storage.md index cfd9640f5f..ecce155224 100644 --- a/docs/generic-storage.md +++ b/docs/generic-storage.md @@ -1,41 +1,45 @@ +# Generic Storage + The AEA generic storage: description and usage. ## AEA Generic Storage + AEA generic storage allows AEA skill's components to store data permanently and use it any time. The primary scenario: to save AEA data on shutdown and load back on startup. Generic storage provides an API for general data manipulation in key-object style. - ## Configuration + Storage is enabled by providing in the agent configuration (`aea-config.yaml`) an optional `storage_uri`. The storage URI consists of the backend name and string data provided to selected backend. The storage URI schema is `://[Optional string]` Example: `storage_uri: sqlite://./some_file.db` tells the AEA to use SQLite backend and store data in `./some_file.db`. Supported backends: -* SQLite - bundled with python simple SQL engine that uses file or in-memory storage. -## Dialogues and Storage integration +- SQLite - bundled with python simple SQL engine that uses file or in-memory storage. + +## Dialogues and Storage Integration One of the most useful cases is the integration of the dialogues subsystem and storage. It helps maintain dialogues state during agent restarts and reduced memory requirements due to the offloading feature. -### Keep terminal state dialogues +### Keep Terminal State Dialogues The Dialogues class has the optional boolean argument `keep_terminal_state_dialogues` -which specifies whether a dialogue which has reached its terminal state is kept in memory or not. If `keep_terminal_state_dialogues` is `False`, dialogues that reach a terminal state are removed from memory and can not be used any more. If `keep_terminal_state_dialogues` is `True`, dialogues that reach a terminal state are kept in memory or storage (if configured). If storage is configured, all dialogues in memory are stored on agent stop and restored on agent start. +which specifies whether a dialogue which has reached its terminal state is kept in memory or not. If `keep_terminal_state_dialogues` is `False`, dialogues that reach a terminal state are removed from memory and can not be used anymore. If `keep_terminal_state_dialogues` is `True`, dialogues that reach a terminal state are kept in memory or storage (if configured). If storage is configured, all dialogues in memory are stored on agent stop and restored on agent start. -It useful to save memory with dialogues that are in terminal state and probably will be never used again. +It is useful to save memory with terminated dialogues that will (possibly) be never used again. Default behaviour on keep terminals state dialogues is set according to the protocol specification but can be set explicitly with skill configuration section. - Skill configuration to keep terminated dialogues for `DefaultDialogues`. Example: -### Dialogues dump/restore on agent restart -If storage is enabled then all the dialogues present in memory will be stored on agent's teardown and loaded on agent's start. +### Dialogues Dump/Restore on Agent Restart -### Offload terminal state dialogues +If storage is enabled then all the dialogues present in memory will be stored on agent's teardown and loaded on agent's start. + +### Offload Terminal State Dialogues If keep options is set and storage is available dialogues in terminal state will be dumped to generic storage and removed from memory. This option helps to save memory and handle terminated dialogues with the same functionality as when they are kept in memory. @@ -43,8 +47,8 @@ All the active dialogues will be stored and loaded during agent restart. All the To enable dialogues offloading `keep_terminal_state_dialogues` has to be enabled and storage configured. +## Manual Usage with Skill Components -## Manual usage with skill components Handlers, Behaviours and Models are able to use storage if enabled. Storage is available with skill context: `self.context.storage` @@ -56,14 +60,15 @@ Objects consist of the `object_id` (unique string) and object body. The object b Collection is a group of the objects, objects data types can vary in the same collection. Collection name is name consists of letters, numbers and `_`. - To get/put specific object collection instance should be used. + ``` python my_collection = self.context.storage.get_sync_connection('my_collection') ``` Collection instance provide set of methods to handle data objects. List of collection methods: + ``` python def put(self, object_id: str, object_body: JSON_TYPES) -> None: """ @@ -110,11 +115,10 @@ List of collection methods: """ ``` - - Simple behaviour example: It saves the `datetime` string of the first act and print it to stdout. + ``` python class TestBehaviour(TickerBehaviour): """Simple behaviour to count how many acts were called.""" @@ -125,14 +129,14 @@ class TestBehaviour(TickerBehaviour): def act(self) -> None: """Make an action.""" if not (self.context.storage and self.context.storage.is_connected): - return + return collection = self.context.storage.get_sync_collection('my_collection') first_call_datetime = collection.get("first_call_ts") if not first_call_ts: # there is no object with "first_call_ts" id. first_call_datetime = str(datetime.datetime.now()) - col.put(first_call_ts, first_call_datetime) - print("Act was called for the first time on:", first_call_datetime) + col.put(first_call_ts, first_call_datetime) + print("Act was called for the first time on:", first_call_datetime) ``` Please, pay attention: `datetime` object is not JSON friendly and can not be stored directly. it should be transformed to `timestamp` or string before put into the storage. diff --git a/docs/glossary.md b/docs/glossary.md index 24b96a4f7b..7781323cea 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,9 +1,11 @@ +# Glossary + This glossary defines a number of terms commonly used across the documentation. For the definitions of framework components consult the API docs. -* **AEA (Autonomous Economic Agent)**: An AEA is "an intelligent agent acting on an owner's behalf, with limited or no interference, and whose goal is to generate economic value to its owner". AEAs are a special type of agent. [more] +- **AEA (Autonomous Economic Agent)**: An AEA is "an intelligent agent acting on an owner's behalf, with limited or no interference, and whose goal is to generate economic value to its owner". AEAs are a special type of agent. [more] -* **Software Agent**: a software agent is a computer program that acts on behalf of an entity (e.g. individual, organisation, business). [more] +- **Software Agent**: a software agent is a computer program that acts on behalf of an entity (e.g. individual, organisation, business). [more] -* **sOEF (Simple Open Economic Framework)**: The simple-OEF, or sOEF, is a search and discovery service for autonomous economic agents. [more] +- **sOEF (Simple Open Economic Framework)**: The simple-OEF, or sOEF, is a search and discovery service for autonomous economic agents. [more] -* **ACN (Agent Communication Network)**: The ACN is a peer-to-peer communication network for autonomous economic agents. [more] \ No newline at end of file +- **ACN (Agent Communication Network)**: The ACN is a peer-to-peer communication network for autonomous economic agents. [more] diff --git a/docs/gym-example.md b/docs/gym-example.md index 25b6516cbf..fab789cedc 100644 --- a/docs/gym-example.md +++ b/docs/gym-example.md @@ -1,18 +1,21 @@ +# Gym Example + The `gym` example demonstrates the AEA framework's flexibility with respect to Reinforcement Learning using OpenAI's `gym` framework. -### Discussion +## Discussion -There is no immediate use case for this example as you can train an RL agent without the AEA proxy layer just fine (and faster). +There is no immediate use case for this example as you can train an RL agent without the AEA proxy layer just fine (and faster). However, the example decouples the RL agent from the `gym.Env` allowing them to run in separate execution environments, potentially owned by different entities. -## Preparation instructions +## Preparation Instructions ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. Download the necessary directories into your working directory: + ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/examples svn export https://github.com/fetchai/agents-aea.git/trunk/packages @@ -24,15 +27,15 @@ Install the `gym` and `numpy` library. pip install numpy gym ``` -## Demo instructions +## Demo Instructions -### Run the example +### Run the Example ``` bash python examples/gym_ex/train.py ``` -Notice the usual RL setup, i.e. the fit method of the RL agent has the typical signature and a familiar implementation. +Notice the usual RL setup, i.e. the fit method of the RL agent has the typical signature and a familiar implementation. Note how `train.py` demonstrates how easy it is to use an AEA agent as a proxy layer between an OpenAI `gym.Env` and a standard RL agent. @@ -59,5 +62,3 @@ if __name__ == "__main__": rl_agent = RLAgent(nb_goods=NB_GOODS) rl_agent.fit(env=proxy_env, nb_steps=NB_STEPS) ``` - -
diff --git a/docs/gym-skill.md b/docs/gym-skill.md index 882ef0a4c5..cc41d3d347 100644 --- a/docs/gym-skill.md +++ b/docs/gym-skill.md @@ -1,12 +1,13 @@ +# Gym Skill + The AEA gym skill demonstrates how a custom Reinforcement Learning agent, that uses OpenAI's gym library, may be embedded into an AEA skill and connection. -### Discussion +## Discussion The gym skills demonstrate how to wrap a Reinforcement Learning agent in a skill. The example decouples the RL agent from the `gym.Env` allowing them to run in separate execution environments, potentially owned by different entities. - -## Preparation instructions +## Preparation Instructions ### Dependencies @@ -25,69 +26,72 @@ Install the `gym` and `numpy` library. pip install numpy gym ``` -## Demo instructions - +## Demo Instructions ### Create the AEA First, fetch the gym AEA: + ``` bash aea fetch fetchai/gym_aea:0.26.4 --alias my_gym_aea cd my_gym_aea aea install ``` -
Alternatively, create from scratch. -

+??? note "Alternatively, create from scratch:" -### Create the AEA -In the root directory, create the gym AEA and enter the project. -``` bash -aea create my_gym_aea -cd my_gym_aea -``` + ### Create the AEA -### Add the gym skill -``` bash -aea add skill fetchai/gym:0.21.5 -``` + In the root directory, create the gym AEA and enter the project. -### Set gym connection as default -``` bash -aea config set agent.default_connection fetchai/gym:0.20.5 -``` + ``` bash + aea create my_gym_aea + cd my_gym_aea + ``` -### Install the skill dependencies + ### Add the gym skill -To install the `gym` package, a dependency of the gym skill, from PyPI run -``` bash -aea install -``` + ``` bash + aea add skill fetchai/gym:0.21.5 + ``` + + ### Set gym connection as default + + ``` bash + aea config set agent.default_connection fetchai/gym:0.20.5 + ``` + + ### Install the skill dependencies + + To install the `gym` package, a dependency of the gym skill, from PyPI run + + ``` bash + aea install + ``` -

-
+### Set up the Training Environment -### Set up the training environment +#### Copy the Gym Environment to the AEA Directory -#### Copy the gym environment to the AEA directory ``` bash mkdir gyms cp -a ../examples/gym_ex/gyms/. gyms/ ``` -#### Update the connection configuration +#### Update the Connection Configuration + ``` bash aea config set vendor.fetchai.connections.gym.config.env 'gyms.env.BanditNArmedRandom' ``` -#### Create and add a private key +#### Create and Add a Private Key ``` bash aea generate-key fetchai aea add-key fetchai ``` -### Run the AEA with the gym connection +### Run the AEA with the Gym Connection ``` bash aea run @@ -95,10 +99,8 @@ aea run You will see the gym training logs. - AEA gym training logs - ### Delete the AEA When you're done, you can go up a level and delete the AEA. @@ -109,9 +111,10 @@ aea delete my_gym_aea ``` ## Communication + This diagram shows the communication between the AEA and the gym environment -
+``` mermaid sequenceDiagram participant AEA participant Environment @@ -127,7 +130,7 @@ This diagram shows the communication between the AEA and the gym environment deactivate AEA deactivate Environment -
+``` ## Skill Architecture @@ -142,5 +145,3 @@ In this particular skill, which chiefly serves for demonstration purposes, we im Gym skill illustration The illustration shows how the RL agent only interacts with the proxy environment by sending it `action (A)` and receiving `observation (O)`, `reward (R)`, `done (D)` and `info (I)`. - -
diff --git a/docs/http-connection-and-skill.md b/docs/http-connection-and-skill.md index cd3ed4f14f..676b818527 100644 --- a/docs/http-connection-and-skill.md +++ b/docs/http-connection-and-skill.md @@ -1,10 +1,12 @@ +# HTTP Connection + ## Description -The HTTP client and HTTP server connections enable an AEA to communicate with external servers, respectively clients, via HTTP. +The HTTP client and HTTP server connections enable an AEA to communicate with external servers, respectively clients, via HTTP. The HTTP client connection receives request envelops from an agent's skill, translates each into an HTTP request and sends it to a server external to the agent. If it receives an HTTP response from the server within a timeout window, it translates it into a response envelope, and sends this back to the relevant skill inside the agent. -The HTTP server connection allows you to run a server inside the connection itself which accepts requests from clients external to the agent. The HTTP server connection validates requests it receives against a provided OpenAPI file. It translates each valid request into an envelope and sends it to the skill specified in the connections configuration. If it receives a valid response envelope from the skill within a timeout window, the connection translates the response envelope into an HTTP response and serves it to the client. +The HTTP server connection allows you to run a server inside the connection itself which accepts requests from clients external to the agent. The HTTP server connection validates requests it receives against a provided OpenAPI file. It translates each valid request into an envelope and sends it to the skill specified in the `connections` configuration. If it receives a valid response envelope from the skill within a timeout window, the connection translates the response envelope into an HTTP response and serves it to the client. ## HTTP Client @@ -12,7 +14,7 @@ The `fetchai/simple_data_request:0.14.5` skill demonstrates a simple use case of The `HttpRequestBehaviour` in `behaviours.py` periodically sends HTTP envelops to the HTTP client connection. Its `act()` method, periodically called, simply calls `_generate_http_request` which contains the logic for enqueueing an HTTP request envelop. -The `HttpHandler` in `handler.py` is a basic handler for dealing with HTTP response envelops received from the HTTP client connection. In the `handle()` method, the responses are dealt with by the private `_handle_response` method which essentially logs the response and adds the body of the response into the skill's shared state. +The `HttpHandler` in `handler.py` is a basic handler for dealing with HTTP response envelops received from the HTTP client connection. In the `handle()` method, the responses are dealt with by the private `_handle_response` method which essentially logs the response and adds the body of the response into the skill's shared state. ## HTTP Server @@ -64,15 +66,11 @@ aea scaffold skill http_echo You can implement a simple http echo skill (modelled after the standard echo skill) which prints out the content of received messages and responds with success. - First, delete the `my_model.py` and `behaviour.py` files (in `my_aea/skills/http_echo/`). The server will be purely reactive, so you only need the `handlers.py` file, and the `dialogues.py` to record the state of the dialogues. Update `skill.yaml` accordingly, so set `models: {}` and `behaviours: {}`. Next implement a basic handler which prints the received envelopes and responds. - -Then, replace the content of `handlers.py` with the following code snippet, -after having replaced the placeholder `YOUR_USERNAME` with -the author username (i.e. the output of `aea config get agent.author`): +Then, replace the content of `handlers.py` with the following code snippet, after having replaced the placeholder `YOUR_USERNAME` with the author username (i.e. the output of `aea config get agent.author`): ``` python import json @@ -217,6 +215,7 @@ class HttpHandler(Handler): ``` Moreover, add a `dialogues.py` file with the following code: + ``` python from typing import Any @@ -314,13 +313,12 @@ models: class_name: HttpDialogues ``` - Run the fingerprinter (note, you will have to replace the author name with your author handle): + ``` bash aea fingerprint skill fetchai/http_echo:0.21.5 ``` - Moreover, we need to tell to the `http_server` connection to what skill the HTTP requests should be forwarded. In our case, this is the `http_echo` that you have just scaffolded. @@ -331,11 +329,13 @@ aea config set vendor.fetchai.connections.http_server.config.target_skill_id "$( ``` You can now run the AEA: + ``` bash aea run ``` In a separate terminal, you can create a client and communicate with the server: + ``` python import requests diff --git a/docs/identity.md b/docs/identity.md index 82ff28c31d..1cd87f4c67 100644 --- a/docs/identity.md +++ b/docs/identity.md @@ -1,8 +1,7 @@ -
-

Note

-

This section is incomplete and will soon be updated. -

-
+# Identity + +!!! note + This section is incomplete and will soon be updated. The AEAs currently use the addresses associated with their private-public key pairs to identify themselves. diff --git a/docs/index.md b/docs/index.md index f852eab46f..ab90cd3825 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,27 +1,31 @@ +# AEA Framework Documentation The AEA framework provides the tools for creating Autonomous Economic Agents (AEA). -## What are AEAs? +## Autonomous Economic Agents (AEAs) -We define an autonomous economic agent or AEA as: + -> An intelligent agent acting on an owner's behalf, with limited or no interference, and whose goal is to generate economic value for its owner. +### What is an AEA? - +!!! info "Definition" + An Autonomous Economic Agent (AEA) is an intelligent agent that acts on its owner's behalf, with limited or no interference, and whose goal is to generate economic value for its owner. -An AEA represents an individual, organisation or object and looks after its interests. AEAs act independently of constant input from their owner and autonomously execute actions to achieve their prescribed goals. Their purpose is to create economic value for you, their owner, in clearly defined domains. AEAs have a wide range of application areas and we provide demo guides to highlight examples of their use cases. +- **Agent**: An AEA represents an individual, organisation or object and looks after their interests. +- **Autonomous**: AEAs act independently of constant input from their owner and autonomously execute actions to achieve their prescribed goals. +- **Economic**: Their purpose is to create economic value for their owner, in clearly defined domains. + +AEAs have a wide range of application areas and we provide demo guides to highlight examples of their use cases. ### What is not an AEA -* Any agent: AEAs' purpose is to generate economic value in a multi-stakeholder environment with competing incentives between agents. They represent humans, organisations or objects. -* APIs or sensors which do not have agency. -* Smart contracts which do not display any proactiveness and are purely reactive to external requests (=contract calls and transactions). -* Artificial General Intelligence (AGI). AEAs can have a very narrow, goal directed focus involving some economic gain and can have a very simple logic. +- Any agent: AEAs' purpose is to generate economic value in a multi-stakeholder environment with competing incentives between agents. They represent humans, organisations or objects. +- APIs or sensors which do not have agency. +- Smart contracts which do not display any proactivity and are purely reactive to external requests (=contract calls and transactions). +- Artificial General Intelligence (AGI). AEAs can have a very narrow, goal directed focus involving some economic gain and can have a very simple logic. -
-

Note

-

In the rest of the documentation, unless specified otherwise, we use the terms AEA and agent interchangeably to refer to AEA as defined above.

-
+!!! note + In the rest of the documentation, unless specified otherwise, we use the terms AEA and agent interchangeably to refer to AEA as defined above. ## What is the AEA Framework? @@ -29,19 +33,17 @@ The AEA framework is a development suite, currently implemented in Python, which AEAs achieve their goals with the help of a search & discovery service for AEAs -- the simple Open Economic Framework (sOEF) -- a decentralized agent communication system -- the Agent Communication Network (ACN) -- and using Fetch.ai's blockchain as a financial settlement and commitment layer. AEAs can also be integrated with third-party blockchains, such as Ethereum. - -## Why build with the AEA Framework? +## Why Build with the AEA Framework? The AEA framework provides the developer with a number of features, which combined cannot be found anywhere else: -* The peer-to-peer agent communication network (ACN) allows your AEAs to interact with all other AEAs over the public internet. -* The search and discovery system sOEF allows your AEAs to find other AEAs. -* The AEA registry enables code sharing and re-use by providing a space in which AEAs or their individual components may be shared. -* The framework's crypto and ledger APIs make it possible for AEAs to interact with blockchains. -* The contract packages enable AEAs to interact with smart contracts in Fetch.ai and other third-party decentralised ledgers. +- The peer-to-peer agent communication network (ACN) allows your AEAs to interact with all other AEAs over the public internet. +- The search and discovery system sOEF allows your AEAs to find other AEAs. +- The AEA registry enables code sharing and re-use by providing a space in which AEAs or their individual components may be shared. +- The framework's crypto and ledger APIs make it possible for AEAs to interact with blockchains. +- The contract packages enable AEAs to interact with smart contracts in Fetch.ai and other third-party decentralized ledgers. - -## Next steps +## Next Steps To get started developing your own AEA, check out the getting started section. @@ -51,12 +53,7 @@ If you would like to develop an AEA in a language different to Python then check If you want to run a demo, check out the demo guides. +## Help us Improve -## Help us improve - -
-

Note

-

This developer documentation is a work in progress. If you spot any errors please open an issue on Github or contact us in the developer Discord channel.

-
- -
+!!! note + This developer documentation is a work in progress. If you spot any errors please open an issue on Github or contact us in the developer Discord channel. diff --git a/docs/interaction-protocol.md b/docs/interaction-protocol.md index 0bc3b52293..aa0df4dd45 100644 --- a/docs/interaction-protocol.md +++ b/docs/interaction-protocol.md @@ -1,3 +1,5 @@ +# How AEAs Talk to Each Other - Interaction Protocols + Although one can imagine scenarios where single AEAs pursue their goals in isolation without interacting with other AEAs, there is no doubt that by working together, AEAs have the potential of achieving much more, especially when taking into account agents' heterogeneity, specialisations, and differing and often complimentary local views of the environment. Interactions in the AEA world are in the form of communication. This is influenced by established practices in the field of multi-agent systems and the prominent speech-act theory which suggests that a communicative expression is not only about transferring information from the speaker to the hearer, but that there may be meanings and commitments beyond the statement's appearance. Therefore, speech may more suitably be considered as action. For example, "I hereby appoint you as chairman" is not just a sequence of words, but an action done by the speaker with wide-ranging consequences for the hearer and any other audience to that sentence. @@ -10,36 +12,35 @@ There are multiple types of interactions an AEA can have: - Interactions between an AEA's internal components. - Interaction protocols - Usually, an interaction involves three types of framework packages: skills, protocols and connections. -### Example 1: negotiation +## Examples + +### Example 1: Negotiation The generic buyer/seller skills use the `fetchai/fipa` protocol which defines the negotiation dialogue between two AEAs. The `fetchai/generic_buyer` and `fetchai/generic_seller` skills implement specific strategies for engaging in such negotiations, by providing the logic for producing negotiation messages to be sent, handling negotiation messages received. The `fetchai/p2p_libp2p` connection is then used for connecting to the agent communication network enabling two AEAs with these skills to deliver negotiation messages to each other. -### Example 2: AEA <> web client +### Example 2: AEA <> Web Client -In the http connection guide we demonstrate how an AEA with an http server connection (e.g. `fetchai/http_server`) receives http payloads from web clients, translates them to messages conforming with the `fetchai/http` protocol and passes it to a skill (e.g. `fetchai/http_echo`) to process. The `fetchai/http` protocol in this case is used for communication between the connection and the skill. +In the http connection guide we demonstrate how an AEA with a http server connection (e.g. `fetchai/http_server`) receives http payloads from web clients, translates them to messages conforming with the `fetchai/http` protocol and passes it to a skill (e.g. `fetchai/http_echo`) to process. The `fetchai/http` protocol in this case is used for communication between the connection and the skill. -### Example 3 : AEA <> 3rd party server +### Example 3 : AEA <> 3rd Party Server -The `fetchai/http_client` connection can be used to make requests to third party servers. In this case, a skill containing the logic for the production of http requests would create messages conforming with the `fetchai/http` protocol and sends it to the `fetchai/http_client` connection which in turn translates it into http payload and sends it to the destination server. +The `fetchai/http_client` connection can be used to make requests to third party servers. In this case, a skill containing the logic for the production of http requests would create messages conforming with the `fetchai/http` protocol and sends it to the `fetchai/http_client` connection which in turn translates it into http payload and sends it to the destination server. Note that in general, third party SDKs can be wrapped in a connection and shared with other developers as a package. Often this also involves creating a custom protocol to enforce the type of interactions permitted between skills and the connection wrapping the SDK. +## Next Steps -## Next steps - -### Recommended +### Recommended We recommend you continue with the next step in the 'Getting Started' series: - Trade between two AEAs -### Relevant deep-dives +### Relevant Deep-Dives Most AEA development focuses on developing the `Skills` and `Protocols` necessary for an AEA to deliver against its economic objectives and implement interaction protocols. @@ -54,5 +55,3 @@ Most of an AEA developer's time is spent on `Skill` development. `Skills` are th In most cases, one of the available `Connection` packages can be used. Occasionally, you might develop your own `Connection`: - Connections - -
\ No newline at end of file diff --git a/docs/known-limits.md b/docs/known-limits.md index f5b6410338..1b15c78a34 100644 --- a/docs/known-limits.md +++ b/docs/known-limits.md @@ -1,3 +1,5 @@ +# Known Limitations + The AEA framework makes a multitude of tradeoffs. Here we present an incomplete list of known limitations: @@ -7,5 +9,3 @@ Here we present an incomplete list of known limitations: - The `AEABuilder` assumes that packages with public ids of identical author and package name have a matching version. As a result, if a developer uses a package with matching author and package name but different version in the public id, then the `AEABuilder` will not detect this and simply use the last loaded package. - The order in which `setup` and `teardown` are called on the skills, and `act` is called on the behaviours, is not guaranteed. Skills should be designed to work independently. Where skills use the `shared_context` to exchange information they must do so safely. - -
diff --git a/docs/language-agnostic-definition.md b/docs/language-agnostic-definition.md index 4ee4b6b428..0b42a81ce8 100644 --- a/docs/language-agnostic-definition.md +++ b/docs/language-agnostic-definition.md @@ -1,136 +1,126 @@ +# Language Agnostic Definition + Currently, there is an implementation of the AEA framework in Python which enables the development of AEAs in Python, and allows AEAs which are built with it to run. -However, AEAs can be developed in different programming languages. This is further backed by the idea that agent-based solutions are suited for multi-stakeholder environments where the different AEAs may be developed independently of one another, resulting in heterogeneous systems. +However, AEAs can be developed in different programming languages. This is further backed by the idea that agent-based solutions are suited for multi-stakeholder environments where the different AEAs may be developed independently of one another, resulting in heterogeneous systems. This means that in principle, there could be different implementations of the AEA framework, in various programming languages and for different platforms. However, to ensure that AEAs under any implementation are compatible with one another and able to interact, they must satisfy specific definitions. In this page, we compile a set of definitions which any AEA independent of its implementation must satisfy in order to be able to interact with other AEAs. An AEA, in technical terms, must satisfy the following requirements: -
    -
  • It MUST be capable of receiving and sending Envelopes which satisfy the following protobuf schema: - -``` proto -syntax = "proto3"; - -package aea.base.v0_1_0; - -message Envelope{ - string to = 1; - string sender = 2; - string protocol_id = 3; - bytes message = 4; - string uri = 5; -} -``` - -The format for the above fields are as follows: - -
      -
    • to and sender: an address derived from the private key of a secp256k1-compatible elliptic curve
    • -
    • protocol_id: this must match a defined regular expression (see below) -
    • message: a bytes string representing a serialized message in the specified protocol
    • -
    • URI: follows this syntax
    • -
    -
  • - -
  • It MUST implement each protocol's message with the required meta-fields: - -``` proto -syntax = "proto3"; - -package aea.base.v0_1_0; - -import "google/protobuf/struct.proto"; - - -message DialogueMessage { - int32 message_id = 1; - string dialogue_starter_reference = 2; - string dialogue_responder_reference = 3; - int32 target = 4; - bytes content = 5; -} - -message Message { - oneof message { - google.protobuf.Struct body = 1; - DialogueMessage dialogue_message = 2; - } -} - -message Envelope{ - string to = 1; - string sender = 2; - string protocol_id = 3; - bytes message = 4; - string uri = 5; -} -``` - where content is replaced with the protocol specific content (see here for details). -
  • - -
  • It MUST implement protocols according to their specification (see here for details). - -
  • It SHOULD implement the fetchai/default:1.1.6 protocol which satisfies the following protobuf schema: - -``` proto -syntax = "proto3"; - -package aea.fetchai.default.v1_0_0; - -message DefaultMessage{ - - // Custom Types - message ErrorCode{ - enum ErrorCodeEnum { - UNSUPPORTED_PROTOCOL = 0; - DECODING_ERROR = 1; - INVALID_MESSAGE = 2; - UNSUPPORTED_SKILL = 3; - INVALID_DIALOGUE = 4; +- It MUST be capable of receiving and sending `Envelopes` which satisfy the following protobuf schema: + + ``` proto + syntax = "proto3"; + + package aea.base.v0_1_0; + + message Envelope{ + string to = 1; + string sender = 2; + string protocol_id = 3; + bytes message = 4; + string uri = 5; + } + ``` + + The format for the above fields are as follows: + + - `to` and `sender`: an address derived from the private key of a secp256k1-compatible elliptic curve + - `protocol_id`: this must match a defined regular expression (see below) + - `message`: a bytes string representing a serialized message in the specified protocol + - `URI`: follows this syntax + +- It MUST implement each protocol's `message` with the required meta-fields: + + ``` proto + syntax = "proto3"; + + package aea.base.v0_1_0; + + import "google/protobuf/struct.proto"; + + + message DialogueMessage { + int32 message_id = 1; + string dialogue_starter_reference = 2; + string dialogue_responder_reference = 3; + int32 target = 4; + bytes content = 5; + } + + message Message { + oneof message { + google.protobuf.Struct body = 1; + DialogueMessage dialogue_message = 2; + } + } + + message Envelope{ + string to = 1; + string sender = 2; + string protocol_id = 3; + bytes message = 4; + string uri = 5; + } + ``` + + where `content` is replaced with the protocol specific content (see here for details). + +- It MUST implement protocols according to their specification (see here for details). + +- It SHOULD implement the `fetchai/default:1.1.6` protocol which satisfies the following protobuf schema: + + ``` proto + syntax = "proto3"; + + package aea.fetchai.default.v1_0_0; + + message DefaultMessage{ + + // Custom Types + message ErrorCode{ + enum ErrorCodeEnum { + UNSUPPORTED_PROTOCOL = 0; + DECODING_ERROR = 1; + INVALID_MESSAGE = 2; + UNSUPPORTED_SKILL = 3; + INVALID_DIALOGUE = 4; + } + ErrorCodeEnum error_code = 1; + } + + + // Performatives and contents + message Bytes_Performative{ + bytes content = 1; + } + + message Error_Performative{ + ErrorCode error_code = 1; + string error_msg = 2; + map error_data = 3; + } + + message End_Performative{ + } + + + oneof performative{ + Bytes_Performative bytes = 5; + End_Performative end = 6; + Error_Performative error = 7; + } } - ErrorCodeEnum error_code = 1; - } - - - // Performatives and contents - message Bytes_Performative{ - bytes content = 1; - } - - message Error_Performative{ - ErrorCode error_code = 1; - string error_msg = 2; - map error_data = 3; - } - - message End_Performative{ - } - - - oneof performative{ - Bytes_Performative bytes = 5; - End_Performative end = 6; - Error_Performative error = 7; - } -} -``` -
  • -
  • The protocol id MUST match the following regular expression: ^([a-zA-Z_][a-zA-Z0-9_]{0,127})/([a-zA-Z_][a-zA-Z0-9_]{0,127})(:((any|latest|((0|[1-9]\d*))\.((0|[1-9]\d*))\.((0|[1-9]\d*))(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)))?$
  • -
  • It is recommended that it processes Envelopes asynchronously. Note, the specification regarding the processing of messages does not impose any particular implementation, and the AEA can be designed to process envelopes either synchronously and asynchronously. However, asynchronous message handling enables the agent to be more responsive and scalable in maintaining many concurrent dialogues with its peers. -
  • -
  • It MUST have an identity in the form of, at a minimum, an address derived from a public key and its associated private key (where the elliptic curve must be of type SECP256k1). -
  • -
  • It SHOULD implement handling of errors using the fetchai/default:1.1.6 protocol. The protobuf schema is given above. -
  • -
  • It MUST implement the following principles when handling messages: -
      -
    • It MUST ALWAYS handle incoming envelopes/messages and NEVER raise an exception when decoding and validating the message. This ensures another AEA cannot cause the agent to fail by sending a malicious envelope/message.
    • -
    • It MUST NEVER handle outgoing messages and ALWAYS raise an exception when validating the message. An exception implies that the handler is resolving a bug in the implementation.
    • -
    -
  • -
-
-

Note

-

Additional constraints will be added soon!

-
+ ``` + +- The protocol id MUST match the following regular expression: `^([a-zA-Z_][a-zA-Z0-9_]{0,127})/([a-zA-Z_][a-zA-Z0-9_]{0,127})(:((any|latest|((0|[1-9]\d*))\.((0|[1-9]\d*))\.((0|[1-9]\d*))(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)))?$` +- It is recommended that it processes `Envelopes` asynchronously. Note, the specification regarding the processing of messages does not impose any particular implementation, and the AEA can be designed to process envelopes either synchronously and asynchronously. However, asynchronous message handling enables the agent to be more responsive and scalable in maintaining many concurrent dialogues with its peers. +- It MUST have an identity in the form of, at a minimum, an address derived from a public key and its associated private key (where the elliptic curve must be of type SECP256k1). +- It SHOULD implement handling of errors using the `fetchai/default:1.1.6` protocol. The protobuf schema is given above. +- It MUST implement the following principles when handling messages: + - It MUST ALWAYS handle incoming envelopes/messages and NEVER raise an exception when decoding and validating the message. This ensures another AEA cannot cause the agent to fail by sending a malicious envelope/message. + - It MUST NEVER handle outgoing messages and ALWAYS raise an exception when validating the message. An exception implies that the handler is resolving a bug in the implementation. + +!!! note + Additional constraints will be added soon! diff --git a/docs/ledger-integration.md b/docs/ledger-integration.md index 29f56b5270..a64caed4bb 100644 --- a/docs/ledger-integration.md +++ b/docs/ledger-integration.md @@ -1,6 +1,8 @@ +# Ledger & Crypto APIs + In this section, we show you how to integrate the AEA with the Fetch.ai and third-party ledgers. -## Ledger support +## Ledger Support For a ledger to be considered _supported_ in the framework, three abstract base classes need to be implemented: @@ -10,10 +12,10 @@ For a ledger to be considered _supported_ in the framework, three abstract base These three classes have their own registries, which allow the developer to import the relevant object where needed. -## Ledger plug-in architecture +## Ledger Plug-in Architecture -The AEA framework provides a plug-in mechanism to support ledger functionalities in -an easily extendible way. At import time, the framework will load +The AEA framework provides a plug-in mechanism to support ledger functionalities in +an easily extendable way. At import time, the framework will load all the crypto plug-ins available in the current Python environment. A _crypto plug-in_ is a Python package which declares some specific @@ -27,7 +29,7 @@ In particular, there are three types of entry points the framework looks up: This is an example of `setup.py` script for a ledger plug-in `aea-ledger-myledger`: -```python +``` python # sample ./setup.py file from setuptools import setup @@ -55,7 +57,7 @@ and the importable package name is `aea_ledger_myledger`. You can search for AEA ledger plug-ins on PyPI: https://pypi.org/search/?q=aea-ledger -## Maintained plug-ins +## Maintained Plug-ins At the moment, the framework natively supports the following three ledgers: @@ -65,7 +67,6 @@ At the moment, the framework natively supports the following three ledgers: However, support for additional ledgers can be added to the framework at runtime. - ## Examples - Examples of how to interact with the crypto registry: @@ -128,27 +129,25 @@ The framework wraps all `LedgerApi` classes and exposes them in the https://explore-dorado.fetch.ai | -| Token Faucet | Use block explorer | +| Token Faucet | Use block explorer | You can access more details on docs section. The configurations can be specified for the `fetchai/ledger:0.21.4` connection. -## CosmWasm supporting chains +## CosmWasm Supporting Chains The Fetch.ai networks use CosmWasm for smart contract support. - diff --git a/docs/limits.md b/docs/limits.md index 716855a954..b3efc7ee2c 100644 --- a/docs/limits.md +++ b/docs/limits.md @@ -1,8 +1,10 @@ +# Limitations of v1 + This document describes some of the limitations of `v1` of the AEA framework and tradeoffs made in its design. -### Rejected ideas: +## Rejected Ideas -#### Handlers implemented as behaviours: +### Handlers Implemented as Behaviours Handlers can be considered a special cases of a "behaviour that listens for specific events to happen". @@ -10,24 +12,21 @@ One could implement `Handler` classes in terms of `Behaviours`, after having imp This was rejected in favour of a clear separation of concerns, and to avoid purely reactive (handlers) and proactive (behaviours) components to be conflated into one concept. The proposal would also add complexity to behaviour development. - -#### Multiple versions of the same package +### Multiple Versions of the Same Package The framework does not allow for the usage of multiple versions of the same package in a given project. Although one could re-engineer the project to allow for this, it does introduce significant additional complexities. Furthermore, Python modules are by design only allowed to exist as one version in a given process. Hence, it seems sensible to maintain this approach in the AEA. +## Potential Extensions, Considered yet not Decided -### Potential extensions, considered yet not decided: - - -#### Alternative skill design +### Alternative Skill Design -For very simple skills, the splitting of skills into `Behaviour`, `Handler`, `Model` and `Task` classes can add unnecessary complexity to the framework and a counter-intuitive responsibility split. The splitting also implies the framework needs to introduce the `SkillContext` object to allow for access to data across the skill. Furthermore, the framework requires implementing all functionality in `SkillComponent` classes `Handler`, `Behaviour` or `Model`. This approach is consistent and transparent, however it creates a lot of boiler plate code for simple skills. +For very simple skills, the splitting of skills into `Behaviour`, `Handler`, `Model` and `Task` classes can add unnecessary complexity to the framework and a counter-intuitive responsibility split. The splitting also implies the framework needs to introduce the `SkillContext` object to allow for access to data across the skill. Furthermore, the framework requires implementing all functionality in `SkillComponent` classes `Handler`, `Behaviour` or `Model`. This approach is consistent and transparent, however it creates a lot of boilerplate code for simple skills. Hence, for some use cases it would be useful to have a single `Skill` class with abstract methods `setup`, `act`, `handle` and `teardown`. Then the developer can decide how to split up their code. -``` +``` python class SkillTemplate(SimpleSkill): protocol_ids: Optional[List[PublicId]] = None @@ -48,16 +47,15 @@ class SkillTemplate(SimpleSkill): Alternatively, we could use decorators to let a developer define whether a function is part of a handler or behaviour. That way, a single file with a number of functions could implement a skill. (Behind the scenes this would utilise a number of virtual `Behaviour` and `Handler` classes provided by the framework). -The downside of this approach is that it does not advocate for much modularity on the skill level. Part of the role of a framework is to propose a common way to do things. The above approach can cause for a larger degree of heterogeneity in the skill design which makes it harder for developers to understand each others' code. +The downside of this approach is that it does not advocate for much modularity on the skill level. Part of the role of a framework is to propose a common way to do things. The above approach can cause for a larger degree of heterogeneity in the skill design which makes it harder for developers to understand each other's code. The separation between all four base classes does exist both in convention *and* at the code level. Handlers deal with skill-external events (messages), behaviours deal with scheduled events (ticks), models represent data and tasks are used to manage long-running business logic. By adopting strong convention around skill development we allow for the framework to take a more active role in providing guarantees. E.g. handlers' and behaviours' execution can be limited to avoid them being blocking, models can be persisted and recreated, tasks can be executed with different task backends. The opinionated approach is thought to allow for better scaling. +### Further Modularity for Skill Level Code -#### Further modularity for skill level code - -Currently we have three levels of modularity: +Currently, we have three levels of modularity: - PyPI packages - framework packages: protocols, contracts, connections and skills @@ -65,11 +63,11 @@ Currently we have three levels of modularity: We could consider having a fourth level: common behaviours, handlers, models exposed as modules which can then speed up skill development. - -#### "promise" pattern: +### "promise" Pattern Given the asynchronous nature of the framework, it is often hard to implement reactions to specific messages, without making a "fat" handler. Take the example of a handler for a certain type of message `A` for a certain protocol `p`. The handler for protocol `p` would look something like this: -``` + +``` python class PHandler: ... def handle(msg): @@ -78,7 +76,8 @@ def handle(msg): ``` However, it could be helpful to overwrite this handler reaction with another callback (e.g. consider this in context): -``` + +``` python # callable that handles the reply def my_callback(msg): # handle reply @@ -88,15 +87,13 @@ self.context.outbox.put_message(message, handler_func=my_callback, failure_func= This feature would introduce additional complexity for the framework to correctly wire up the callbacks and messages with the dialogues. - -#### CLI using standard lib +### CLI using Standard Lib Removing the click dependency from the CLI would further reduce the dependencies in the AEA framework which is overall desirable. +### Metadata vs Configurations -#### Meta data vs configurations - -The current approach uses `yaml` files to specify both meta data and component configuration. It would be desirable to introduce the following separation: +The current approach uses `yaml` files to specify both metadata and component configuration. It would be desirable to introduce the following separation: - package metadata - package default developer configuration @@ -104,39 +101,35 @@ The current approach uses `yaml` files to specify both meta data and component c A user can only configure a subset of the configuration. The developer should be able to define these constraints for the user. Similarly, a developer cannot modify all fields in a package, some of them are determined by the framework. - -#### Configuring agent goal setup +### Configuring Agent Goal Setup By default, the agent's goals are implicitly defined by its skills and the configurations thereof. This is because the default decision maker signs every message and transaction presented to it. It is already possible to design a custom decision maker. However, more work needs to be done to understand how to improve the usability and configuration of the decision maker. In this context different types of decision makers can be implemented for the developer/user. - -#### Connection status monitoring +### Connection Status Monitoring Currently, connections are responsible for managing their own status after they have been "connected" by the `Multiplexer`. Developers writing connections must take care to properly set its connection status at all times and manage any disconnection. It would potentially be desirable to offer different policies to deal with connection problems on the multiplexer level: - disconnect one, keep others alive - disconnect all -- try reconnect indefinitely +- try to reconnect indefinitely - -#### Agent snapshots on teardown or error +### Agent Snapshots on Teardown or Error Currently, the developer must implement snapshots on the component level. It would be desirable if the framework offered more help to persist the agent state on teardown or error. - -#### Dialogues management +### Dialogues Management The current implementation of Dialogues is verbose. Developers often need to subclass `Dialogues` and `Dialogue` classes. More effort can be made to simplify and streamline dialogues management. -#### Instantiate multiple instances of the same class of `SkillComponent` +### Instantiate Multiple Instances of the Same Class of `SkillComponent` Currently, configuration and metadata of a package are conflated making it not straightforward to run one package component with multiple sets of configuration. It could be desirable to configure an agent to run a given package with multiple different configurations. -This feature could be problematic with respect to component to component messaging which currently relies on component ids, which are bound to the package and not its instance. +This feature could be problematic with respect to component-to-component messaging which currently relies on component ids, which are bound to the package and not its instance. -#### Containerized Agents +### Containerized Agents Agent management, especially when many of them live on the same host, can be cumbersome. The framework should provide more utilities for these large-scale use cases. But a proper isolation of the agent environment is something that helps also simple use cases. @@ -144,7 +137,7 @@ A new software architecture, somehow inspired to the Docker system. The CLI only Users and developers would potentially like to run many AEAs of different versions and with differences in the versions of their dependencies. It is not possible to import different versions of the same Python (PyPI) package in the same process in a clean way. However, in different processes this is trivial with virtual environments. It would be desirable to consider this in the context of a container solution for agents. -#### Dependency light version of the AEA framework +### Dependency Light Version of the AEA Framework The `v1` of the Python AEA implementation makes every effort to minimise the amount of third-party dependencies. However, some dependencies remain to lower development time. @@ -152,22 +145,22 @@ It would be desirable to further reduce the dependencies, and potentially have a This could be taken further, and a reduced spec version for micropython could be designed. -#### Compiled AEA +### Compiled AEA Python is not a compiled language. However, various projects attempt this, e.g. Nuitka and it would be desirable to explore how useful and practical this would be in the context of AEA. -#### DID integration +### DID Integration It would be great to integrate DID in the framework design, specifically identification of packages (most urgently protocols). Other projects and standards worth reviewing in the context (in particular with respect to identity): - ERC 725: Ethereum Identity Standard and here. - ERC 735: Claim Holder -#### Optimise protocol schemas and messages +### Optimise Protocol Schemas and Messages The focus of protocol development was on extensibility and compatibility, not on optimisation. For instance, the dialogue references use inefficient string representations. -#### Constraints on primitive types in protocols +### Constraints on Primitive Types in Protocols The protocol generator currently does not support custom constraints. The framework could add support for custom constraints for the protocol generator and specification. @@ -192,8 +185,7 @@ This would automatically enable support for signed/unsigned `int` and `float`. T Currently, the developer has to specify a custom type to implement any constraints on primitive types. - -#### Subprotocols & multi-party interactions +### Sub-protocols & Multi-Party Interactions Protocols can be allowed to depend on each other. Similarly, protocols might have multiple parties. @@ -201,13 +193,11 @@ Furthermore, a turn-taking function that specifies who's turn it is at any given Then the current `fipa` setup is a specific case of turn-taking where the turn shifts after a player sends a single move (unique-reply). But generally, it does not have to be like this. Players could be allowed to send multiple messages until the turn shifts, or until they send specific speech-acts (multiple-replies). - -#### Timeouts in protocols +### Timeouts in Protocols Protocols currently do not implement the concept of timeouts. We leave it to the skill developer to implement any time-specific protocol rules. - -#### Framework internal messages +### Framework Internal Messages The activation/deactivation of skills and addition/removal of components is implemented in a "passive" way - the skill posts a request in its skill context queue (in the case of new behaviours), or it just sets a flag (in case of activation/deactivation of skills). @@ -215,11 +205,11 @@ One could consider that a skill can send requests to the framework, via the inte This is a further small but meaningful step toward an actor-based model for agent internals. -#### Ledger transaction management +### Ledger Transaction Management Currently, the framework does not manage any aspect of submitting multiple transactions to the ledgers. This responsibility is left to skills. Additionally, the ledger APIs/contract APIs take the ledger as a reference to determine the nonce for a transaction. If a new transaction is sent before a previous transaction has been processed then the nonce will not be incremented correctly for the second transaction. This can lead to submissions of multiple transactions with the same nonce, and therefore failure of subsequent transactions. -A naive approach would involve manually incrementing the nonce and then submitting transactions into the pool with the correct nonce for eventual inclusion. The problem with this approach is that any failure of a transaction will cause non of the subsequent transactions to be processed for some ledgers (https://ethereum.stackexchange.com/questions/2808/what-happens-when-a-transaction-nonce-is-too-high). To recover from a transaction failure not only the failed transaction would need to be handled, but potentially also all subsequent transactions. It is easy to see that logic required to recover from a transaction failure early in a sequence can be arbitrarily complex (involving potentially new negotiations between agents, new signatures having to be generated etc.). +A naive approach would involve manually incrementing the nonce and then submitting transactions into the pool with the correct nonce for eventual inclusion. The problem with this approach is that any failure of a transaction will cause none of the subsequent transactions to be processed for some ledgers (). To recover from a transaction failure not only the failed transaction would need to be handled, but potentially also all subsequent transactions. It is easy to see that logic required to recover from a transaction failure early in a sequence can be arbitrarily complex (involving potentially new negotiations between agents, new signatures having to be generated etc.). A further problem with the naive approach is that it (imperfectly) replicates the ledger state (with respect to (subset of state of) a specific account). @@ -229,32 +219,26 @@ This approach is currently used and implemented across all the reference skills. Related, the topic of latency in transactions. State channels provide a solution. E.g. Perun. There could also be an interesting overlap with our protocols here. - -#### Unsolved problems in `Multiplexer` - `AgentLoop` interplay +### Unsolved Problems in `Multiplexer` - `AgentLoop` Interplay Problem 1: connection generates too many messages in a short amount of time, that are not consumed by the multiplexer Solution: Can be solved by slowing down connections receive method called, controlled by the inbox messages amount Side effects: Most of the connections should have an internal queue because there is no synchronization between internal logic and multiplexer connection `receive` calls. - Problem 2: the send method can take a long time (because send retries logic in connection) -Solution: Currently, we apply timeouts on send. Other solutions could be considered, like parallelisation. - +Solution: Currently, we apply timeouts on send. Other solutions could be considered, like parallelization. Problem 3: too many messages are produced by a skill. Solution: Raise an exception on outbox is full or slow down agent loop? - ## ACN -### Agent mobility on ACN +### Agent Mobility on ACN If a peer-client or full client switches peer, then the DHT is not updated properly at the moment under certain conditions. -### Mailbox connection +### Mailbox Connection The two available connections `p2p_libp2p` and `p2p_libp2p_client` imply that the agent is continuously connected and therefore must have uninterrupted network access and the resources to maintain a connection. For more lightweight implementations, a mailbox connection is desirable, as outlined in the ACN documentation. - - diff --git a/docs/logging.md b/docs/logging.md index 660b8d21a6..bbd05c3e4b 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -1,9 +1,10 @@ +# Logging + The AEA framework supports flexible logging capabilities with the standard Python logging library. In this tutorial, we configure logging for an AEA. -First of all, create your AEA. - +First, create your AEA. ``` bash aea create my_aea @@ -75,8 +76,7 @@ logging_config: This configuration will set up a logger with name `aea`. It prints both on console and on file with a format specified by the `standard` formatter. - -## Streaming to browser +## Streaming to Browser It is possible to configure the AEA to stream logs to a browser. @@ -167,5 +167,3 @@ if __name__ == "__main__": Save the script in a file called `server.py`, install flask with `pip install flask` and run the server with `python server.py`. Third, run your AEA and visit `localhost:5000` in your browser. - -
diff --git a/docs/message-routing.md b/docs/message-routing.md index c32f886417..a77dcf45a7 100644 --- a/docs/message-routing.md +++ b/docs/message-routing.md @@ -1,3 +1,4 @@ +# Message Routing Message routing can be split up into the routing of incoming and outgoing `Messages`. @@ -11,14 +12,11 @@ It is important to keep in mind that interacti - the `AEA` tries to decode the message; errors are handled by the `ErrorHandler` - `Messages` are dispatched based on two rules: - 1. checks if `to` field can be interpreted as `skill_id`, if so uses that together with the `protocol_id` to dispatch to the protocol's `Handler` in the specified `Skill`, else - 2. uses the `protocol_id` to dispatch to the protocol's `Handler` in all skills supporting the protocol. + 1. checks if `to` field can be interpreted as `skill_id`, if so uses that together with the `protocol_id` to dispatch to the protocol's `Handler` in the specified `Skill`, else + 2. uses the `protocol_id` to dispatch to the protocol's `Handler` in all skills supporting the protocol. -
-

Note

-

For agent-to-agent communication it is advisable to have a single skill implement a given protocol. Skills can then forward the messages via skill-to-skill communication to other skills where required. Otherwise, received agent-to-agent messages will be forwarded to all skills implementing a handler for the specified protocol and the developer needs to take care to handle them appropriately (e.g. avoid multiple replies to a single message). -

-
+!!! note + For agent-to-agent communication it is advisable to have a single skill implement a given protocol. Skills can then forward the messages via skill-to-skill communication to other skills where required. Otherwise, received agent-to-agent messages will be forwarded to all skills implementing a handler for the specified protocol and the developer needs to take care to handle them appropriately (e.g. avoid multiple replies to a single message). ## Outgoing `Messages` @@ -26,12 +24,12 @@ It is important to keep in mind that
interacti - `OutBox` constructs an `Envelope` from the `Message` - `Multiplexer` assigns messages to relevant `Connection` based on the following rules: - 1. Component to component messages are routed by their `component_id` - 2. Agent to agent messages are routed following four rules: - 1. checks if `EnvelopeContext` exists and specifies a `Connection`, if so uses that else - 2. checks which connection handled the last message from `sender`, if present uses that else - 3. checks if default routing is specified for the `protocol_id` referenced in the `Envelope`, if so uses that else - 4. sends to default `Connection`. + 1. Component to component messages are routed by their `component_id` + 2. Agent to agent messages are routed following four rules: + 1. checks if `EnvelopeContext` exists and specifies a `Connection`, if so uses that else + 2. checks which connection handled the last message from `sender`, if present uses that else + 3. checks if default routing is specified for the `protocol_id` referenced in the `Envelope`, if so uses that else + 4. sends to default `Connection`. - `Connections` can process `Envelopes` directly or encode them for transport to another agent. diff --git a/docs/ml-skills.md b/docs/ml-skills.md index 43e7eec21a..bfe0bab09f 100644 --- a/docs/ml-skills.md +++ b/docs/ml-skills.md @@ -1,24 +1,26 @@ -The AEA ML (machine learning) skills demonstrate an interaction between two AEAs, one purchasing data from the other and training a machine learning model with it. +# ML Skills + +The AEA ML (machine learning) skills demonstrate an interaction between two AEAs, one purchasing data from the other and training a machine learning model with it. There are two types of AEAs: -* The `ml_data_provider` which sells training data. -* The `ml_model_trainer` which purchases data and trains a model +- The `ml_data_provider` which sells training data. +- The `ml_model_trainer` which purchases data and trains a model ## Discussion -This demo aims to demonstrate the integration of a simple AEA with machine learning using the AEA framework. The `ml_data_provider` AEA provides some sample data and delivers to the client upon payment. +This demo aims to demonstrate the integration of a simple AEA with machine learning using the AEA framework. The `ml_data_provider` AEA provides some sample data and delivers to the client upon payment. Once the client receives the data, it trains a model. This process can be found in `tasks.py`. This demo does not utilize a smart contract. As a result, the ledger interaction is only for completing a transaction. Since the AEA framework enables using third-party libraries from PyPI, we can directly reference any external dependencies. -The `aea install` command installs all dependencies an AEA needs that is listed in one of its skills' YAML file. +The `aea install` command installs all dependencies an AEA needs that is listed in one of its skills' YAML file. ## Communication This diagram shows the communication between the two AEAs. -
+``` mermaid sequenceDiagram participant ml_model_trainer participant ml_data_provider @@ -47,20 +49,18 @@ This diagram shows the communication between the two AEAs. deactivate ml_data_provider deactivate Search deactivate Ledger +``` -
-
- -## Option 1: AEA Manager approach +## Option 1: AEA Manager Approach -Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. -### Preparation instructions +### Preparation Instructions -* Install the
AEA Manager. -* Install Tensorflow +- Install the AEA Manager. +- Install Tensorflow -### Demo instructions +### Demo Instructions The following steps assume you have launched the AEA Manager Desktop app. @@ -73,153 +73,153 @@ The following steps assume you have launched the AEA Manager Desktop app. 4. Run the `ml_data_provider` AEA. Navigate to its logs and copy the multiaddress displayed. 5. Navigate to the settings of the `ml_model_trainer` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11001", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9001", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9001" -} -``` + + ``` bash + { + "delegate_uri": "127.0.0.1:11001", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9001", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9001" + } + ``` 6. Run the `ml_model_trainer`. -In the AEA's logs, you should see the agents trading successfully, and the training agent training its machine learning model using the data purchased. +In the AEA's logs, you should see the agents trading successfully, and the training agent training its machine learning model using the data purchased. The trainer keeps purchasing data and training its model until stopped. -
-## Option 2: CLI approach +## Option 2: CLI Approach Follow this approach when using the `aea` CLI. -### Preparation instructions +### Preparation Instructions #### Dependencies -* Follow the Preliminaries and Installation sections from the AEA quick start. -* Install Tensorflow +- Follow the Preliminaries and Installation sections from the AEA quick start. +- Install Tensorflow -### Demo instructions +### Demo Instructions -#### Create data provider AEA +#### Create Data Provider AEA First, fetch the data provider AEA: -``` bash -aea fetch fetchai/ml_data_provider:0.32.4 -cd ml_data_provider -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the data provider from scratch: ``` bash -aea create ml_data_provider +aea fetch fetchai/ml_data_provider:0.32.4 cd ml_data_provider -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/ml_data_provider:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- -#### Create model trainer AEA +??? note "Alternatively, create from scratch:" + The following steps create the data provider from scratch: + + ``` bash + aea create ml_data_provider + cd ml_data_provider + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/ml_data_provider:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Create Model Trainer AEA Then, fetch the model trainer AEA: -``` bash -aea fetch fetchai/ml_model_trainer:0.33.4 -cd ml_model_trainer -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the model trainer from scratch: ``` bash -aea create ml_model_trainer +aea fetch fetchai/ml_model_trainer:0.33.4 cd ml_model_trainer -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/ml_train:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` - -

-
- -#### Add keys for the data provider AEA +??? note "Alternatively, create from scratch:" + The following steps create the model trainer from scratch: + + ``` bash + aea create ml_model_trainer + cd ml_model_trainer + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/ml_train:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Add Keys for the Data Provider AEA First, create the private key for the data provider AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -#### Add keys and generate wealth for the model trainer AEA +#### Add Keys and Generate Wealth for the Model Trainer AEA The model trainer needs to have some wealth to purchase the data from the data provider. First, create the private key for the model trainer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for your model trainer based on the network you want to transact with. On the Fetch.ai `Dorado` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` @@ -237,25 +237,8 @@ aea run Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) This is the entry peer address for the local agent communication network created by the ML data provider. - Then, in the ML model trainer, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -266,24 +249,24 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` -This allows the model trainer to connect to the same local agent communication network as the data provider. +This allows the model trainer to connect to the same local agent communication network as the data provider. Then run the model trainer AEA: + ``` bash aea run ``` -You can see that the AEAs find each other, negotiate and eventually trade. After the trade, the model trainer AEA trains its ML model using the data it has purchased. +You can see that the AEAs find each other, negotiate and eventually trade. After the trade, the model trainer AEA trains its ML model using the data it has purchased. This AEA keeps purchasing data and training its model until stopped. #### Cleaning up When you're finished, delete your AEAs: + ``` bash cd .. aea delete ml_data_provider aea delete ml_model_trainer ``` - -
\ No newline at end of file diff --git a/docs/modes.md b/docs/modes.md index cc142afb3d..cc3198bb42 100644 --- a/docs/modes.md +++ b/docs/modes.md @@ -1,3 +1,4 @@ +# Modes of Running an AEA We can run an AEA in multiple modes thanks to the configurable design of the framework. diff --git a/docs/multi-agent-manager.md b/docs/multi-agent-manager.md index c645a66f3e..bcee29e2de 100644 --- a/docs/multi-agent-manager.md +++ b/docs/multi-agent-manager.md @@ -1,3 +1,4 @@ +# Multi Agent Manager The `MultiAgentManager` allows managing multiple agent projects programmatically. @@ -16,7 +17,7 @@ manager = MultiAgentManager(WORKING_DIR) manager.start_manager() ``` -## Adding projects +## Adding Projects We first add a couple of finished AEA project: @@ -31,10 +32,10 @@ weather_station_name = weather_station_id.name weather_client_name = weather_client_id.name ``` -## Adding agent instances - +## Adding Agent Instances Add the agent instances + ``` python agent_overrides = { "private_key_paths": {"fetchai": "fetchai_private_key.txt"}, @@ -98,8 +99,8 @@ component_overrides = [{ manager.add_agent(weather_client_id, component_overrides=component_overrides, agent_overrides=agent_overrides) ``` - Save the following private keys in the respective files. + ``` python FET_PRIVATE_KEY_STATION = b"72d3149f5689f0749eaec5ebf6dba5deeb1e89b93ae1c58c71fd43dfaa231e87" FET_PRIVATE_KEY_PATH_STATION = Path(manager.data_dir, weather_station_name, "fetchai_private_key.txt").absolute() @@ -118,7 +119,7 @@ FET_CONNECTION_PRIVATE_KEY_PATH_CLIENT = Path(manager.data_dir, weather_client_n FET_CONNECTION_PRIVATE_KEY_PATH_CLIENT.write_bytes(FET_CONNECTION_PRIVATE_KEY_CLIENT) ``` -## Running the agents: +## Running the Agents ``` python import time @@ -133,7 +134,7 @@ manager.start_agent(weather_client_id.name) time.sleep(5.0) ``` -## Stopping the agents: +## Stopping the Agents ``` python manager.stop_all_agents() @@ -145,6 +146,6 @@ manager.stop_all_agents() manager.stop_manager() ``` -# Limitations +## Limitations The `MultiAgentManager` can only be used with compatible package versions, in particular the same package (with respect to author and name) cannot be used in different versions. If you want to run multiple agents with differing versions of the same package then use the `aea launch` command in the multi-processing mode, or simply launch each agent individually with `aea run`. diff --git a/docs/multiplexer-standalone.md b/docs/multiplexer-standalone.md index b66adb12ae..0f46adaadb 100644 --- a/docs/multiplexer-standalone.md +++ b/docs/multiplexer-standalone.md @@ -1,6 +1,9 @@ +# Use Multiplexer Stand-Alone + The `Multiplexer` can be used stand-alone. This way a developer can utilise the protocols and connections independent of the `Agent` or `AEA` classes. -First, import the Python and application specific libraries and set the static variables. (Get the packages directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) +First, import the Python and application specific libraries and set the static variables. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.) + ``` python import os import time @@ -49,7 +52,7 @@ A `Multiplexer` only needs a list of connections. The `StubConnection` is a simp ## Start the `Multiplexer` -We can run a multiplexer by calling, `connect()` which starts the receive and sending loops. We run the multiplexer from a different thread so that we can still use the main thread to pass it messages. +We can run a multiplexer by calling, `connect()` which starts the 'receive' and 'send' loops. We run the multiplexer from a different thread so that we can still use the main thread to pass it messages. ``` python try: @@ -66,8 +69,10 @@ We can run a multiplexer by calling, `connect()` which starts the receive and se raise Exception("Not connected") ``` -## Send and receive an envelope +## Send and Receive an Envelope + We use the input and output text files to send an envelope to our agent and receive a response + ``` python # Create a message inside an envelope and get the stub connection to pass it into the multiplexer message_text = ( @@ -112,7 +117,9 @@ We use the input and output text files to send an envelope to our agent and rece ``` ## Shutdown -Finally stop our multiplexer and wait for it to finish + +Finally, stop our multiplexer and wait for it to finish + ``` python finally: # Shut down the multiplexer @@ -120,121 +127,117 @@ Finally stop our multiplexer and wait for it to finish t.join() ``` -## Your turn +## Your Turn Now it is your turn to develop a simple use case which utilises the `Multiplexer` to send and receive Envelopes. -## Entire code listing -If you just want to copy and paste the entire script in you can find it here: - -
Click here to see full listing -

- -``` python -import os -import time -from copy import copy -from threading import Thread -from typing import Optional - -from aea.configurations.base import ConnectionConfig -from aea.helpers.file_io import write_with_lock -from aea.identity.base import Identity -from aea.mail.base import Envelope -from aea.multiplexer import Multiplexer - -from packages.fetchai.connections.stub.connection import StubConnection -from packages.fetchai.protocols.default.message import DefaultMessage - - -INPUT_FILE = "input.txt" -OUTPUT_FILE = "output.txt" +## Entire Code Listing +If you just want to copy and paste the entire script in you can find it here: -def run(): - """Run demo.""" - - # Ensure the input and output files do not exist initially - if os.path.isfile(INPUT_FILE): - os.remove(INPUT_FILE) - if os.path.isfile(OUTPUT_FILE): - os.remove(OUTPUT_FILE) - - # create the connection and multiplexer objects - configuration = ConnectionConfig( - input_file=INPUT_FILE, - output_file=OUTPUT_FILE, - connection_id=StubConnection.connection_id, - ) - stub_connection = StubConnection( - configuration=configuration, - data_dir=".", - identity=Identity("some_agent", "some_address", "some_public_key"), - ) - multiplexer = Multiplexer([stub_connection], protocols=[DefaultMessage]) - try: - # Set the multiplexer running in a different thread - t = Thread(target=multiplexer.connect) - t.start() - - # Wait for everything to start up - for _ in range(20): - if multiplexer.is_connected: - break - time.sleep(1) - else: - raise Exception("Not connected") - - # Create a message inside an envelope and get the stub connection to pass it into the multiplexer - message_text = ( - "multiplexer,some_agent,fetchai/default:1.0.0,\x08\x01*\x07\n\x05hello," +??? note "Click here to see full listing:" + + ``` python + import os + import time + from copy import copy + from threading import Thread + from typing import Optional + + from aea.configurations.base import ConnectionConfig + from aea.helpers.file_io import write_with_lock + from aea.identity.base import Identity + from aea.mail.base import Envelope + from aea.multiplexer import Multiplexer + + from packages.fetchai.connections.stub.connection import StubConnection + from packages.fetchai.protocols.default.message import DefaultMessage + + + INPUT_FILE = "input.txt" + OUTPUT_FILE = "output.txt" + + + def run(): + """Run demo.""" + + # Ensure the input and output files do not exist initially + if os.path.isfile(INPUT_FILE): + os.remove(INPUT_FILE) + if os.path.isfile(OUTPUT_FILE): + os.remove(OUTPUT_FILE) + + # create the connection and multiplexer objects + configuration = ConnectionConfig( + input_file=INPUT_FILE, + output_file=OUTPUT_FILE, + connection_id=StubConnection.connection_id, ) - with open(INPUT_FILE, "w") as f: - write_with_lock(f, message_text) - - # Wait for the envelope to get processed - for _ in range(20): - if not multiplexer.in_queue.empty(): - break - time.sleep(1) - else: - raise Exception("No message!") - - # get the envelope - envelope = multiplexer.get() # type: Optional[Envelope] - assert envelope is not None - - # Inspect its contents - print( - "Envelope received by Multiplexer: sender={}, to={}, protocol_specification_id={}, message={}".format( - envelope.sender, - envelope.to, - envelope.protocol_specification_id, - envelope.message, - ) + stub_connection = StubConnection( + configuration=configuration, + data_dir=".", + identity=Identity("some_agent", "some_address", "some_public_key"), ) - - # Create a mirrored response envelope - response_envelope = copy(envelope) - response_envelope.to = envelope.sender - response_envelope.sender = envelope.to - - # Send the envelope back - multiplexer.put(response_envelope) - - # Read the output envelope generated by the multiplexer - with open(OUTPUT_FILE, "r") as f: - print("Envelope received from Multiplexer: " + f.readline()) - finally: - # Shut down the multiplexer - multiplexer.disconnect() - t.join() - - -if __name__ == "__main__": - run() -``` -

-
- -
+ multiplexer = Multiplexer([stub_connection], protocols=[DefaultMessage]) + try: + # Set the multiplexer running in a different thread + t = Thread(target=multiplexer.connect) + t.start() + + # Wait for everything to start up + for _ in range(20): + if multiplexer.is_connected: + break + time.sleep(1) + else: + raise Exception("Not connected") + + # Create a message inside an envelope and get the stub connection to pass it into the multiplexer + message_text = ( + "multiplexer,some_agent,fetchai/default:1.0.0,\x08\x01*\x07\n\x05hello," + ) + with open(INPUT_FILE, "w") as f: + write_with_lock(f, message_text) + + # Wait for the envelope to get processed + for _ in range(20): + if not multiplexer.in_queue.empty(): + break + time.sleep(1) + else: + raise Exception("No message!") + + # get the envelope + envelope = multiplexer.get() # type: Optional[Envelope] + assert envelope is not None + + # Inspect its contents + print( + "Envelope received by Multiplexer: sender={}, to={}, protocol_specification_id={}, message={}".format( + envelope.sender, + envelope.to, + envelope.protocol_specification_id, + envelope.message, + ) + ) + + # Create a mirrored response envelope + response_envelope = copy(envelope) + response_envelope.to = envelope.sender + response_envelope.sender = envelope.to + + # Send the envelope back + multiplexer.put(response_envelope) + + # Read the output envelope generated by the multiplexer + with open(OUTPUT_FILE, "r") as f: + print("Envelope received from Multiplexer: " + f.readline()) + finally: + # Shut down the multiplexer + multiplexer.disconnect() + t.join() + + + if __name__ == "__main__": + run() + ``` diff --git a/docs/oef-ledger.md b/docs/oef-ledger.md index 5880a21d99..f9b6151435 100644 --- a/docs/oef-ledger.md +++ b/docs/oef-ledger.md @@ -1,3 +1,4 @@ +# Relation to OEF and Ledger The Open Economic Framework (OEF) and Decentralized Ledger Technologies (DLTs) allow AEAs to create value through their interaction with other AEAs. The following diagram illustrates the relation of AEAs to the OEF and DLTs. @@ -5,12 +6,10 @@ The Open Economic Framework (OEF) and Decentralized Ledger Technologies (DLTs) a ## Open Economic Framework (OEF) -The _Open Economic Framework_ (OEF) consists of protocols, languages and market mechanisms agents use to search and find each other, communicate with as well as trade with each other. As such the OEF defines the decentralised virtual environment that supplies and supports APIs for autonomous third-party software agents, also known as Autonomous Economic Agents (AEAs). +The _Open Economic Framework_ (OEF) consists of protocols, languages and market mechanisms agents use to search and find each other, communicate with as well as trade with each other. As such the OEF defines the decentralized virtual environment that supplies and supports APIs for autonomous third-party software agents, also known as Autonomous Economic Agents (AEAs). -
-

Note

-

The OEF is under development. Expect frequent changes. What follows is a description of the current implementation.

-
+!!! note + The OEF is under development. Expect frequent changes. What follows is a description of the current implementation. At present, the OEF's capabilities are fulfilled by three components: @@ -30,7 +29,7 @@ Agents can receive messages from other agents if they are both connected to the ### Search and Discovery -A simple OEF (sOEF) node allows agents to discover each other. In particular, agents can register themselves and the services they offer, and can search for agents who offer specific services. +A simple OEF (sOEF) node allows agents to discover each other. In particular, agents can register themselves and the services they offer, and can search for agents who offer specific services. For two agents to be able to find each other, at least one must register itself on the sOEF and the other must query the sOEF node for it. Detailed documentation is provided here. @@ -48,7 +47,7 @@ The Python implementation of the AEA Framework currently integrates with three l However, the framework makes it straightforward for any developer to add support for other ledgers. -### AEAs as second layer technology +### AEAs as Second Layer Technology The following presentation discusses how AEAs can be seen as second layer technology to ledgers. diff --git a/docs/oracle-demo.md b/docs/oracle-demo.md index d1d0d17046..2c49d28c83 100644 --- a/docs/oracle-demo.md +++ b/docs/oracle-demo.md @@ -1,3 +1,5 @@ +# Oracle Skills + This demo shows how an AEA can be used to maintain an oracle and how another AEA can request the oracle value. ## Discussion @@ -6,15 +8,15 @@ This demo shows how an AEA can be used to maintain an oracle and how another AEA This demonstration shows how to set up a simple oracle agent who deploys an oracle contract and updates the contract with a token price fetched from a public API. It also shows how to create an oracle client agent that can request the value from the oracle contract. -## Preparation instructions - +## Preparation Instructions + ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. ## Demo -### Create the oracle AEA +### Create the Oracle AEA Fetch the AEA that will deploy and update the oracle contract. @@ -24,104 +26,106 @@ cd coin_price_oracle aea install ``` -
Alternatively, create from scratch (and customize the data source) -

- -Create the AEA that will deploy the contract. - -``` bash -aea create coin_price_oracle -cd coin_price_oracle -aea add connection fetchai/http_client:0.24.5 -aea add connection fetchai/ledger:0.21.4 -aea add connection fetchai/prometheus:0.9.5 -aea add skill fetchai/advanced_data_request:0.7.5 -aea add skill fetchai/simple_oracle:0.16.4 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/ledger:0.21.4 -aea install -``` - -Set the URL for the data request skill: -``` bash -aea config set --type str vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url "https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd" -``` - -Specify the name and JSON path of the data to fetch from the API: -``` bash -aea config set --type list vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{"name": "price", "json_path": "fetch-ai.usd"}]' -``` - -Set the name of the oracle value in the simple oracle skill: -``` bash -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price -``` - -Then update the agent configuration with the default routing: -``` bash -aea config set --type dict agent.default_routing \ -'{ -"fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", -"fetchai/http:1.1.6": "fetchai/http_client:0.24.5", -"fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" -}' -``` - -Update the default ledger. -``` bash -aea config set agent.default_ledger fetchai -``` - -Set the following configuration for the oracle skill: -``` bash -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value -``` - -

-
+??? note "Alternatively, create from scratch (and customize the data source):" + Create the AEA that will deploy the contract. + + ``` bash + aea create coin_price_oracle + cd coin_price_oracle + aea add connection fetchai/http_client:0.24.5 + aea add connection fetchai/ledger:0.21.4 + aea add connection fetchai/prometheus:0.9.5 + aea add skill fetchai/advanced_data_request:0.7.5 + aea add skill fetchai/simple_oracle:0.16.4 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/ledger:0.21.4 + aea install + ``` + + Set the URL for the data request skill: + + ``` bash + aea config set --type str vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url "https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd" + ``` + + Specify the name and JSON path of the data to fetch from the API: + + ``` bash + aea config set --type list vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{"name": "price", "json_path": "fetch-ai.usd"}]' + ``` + + Set the name of the oracle value in the simple oracle skill: + + ``` bash + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price + ``` + + Then update the agent configuration with the default routing: + + ``` bash + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/http:1.1.6": "fetchai/http_client:0.24.5", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" + }' + ``` + + Update the default ledger. + + ``` bash + aea config set agent.default_ledger fetchai + ``` + + Set the following configuration for the oracle skill: + + ``` bash + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value + ``` This demo runs on the `fetchai` ledger by default. Set the following variable for use in the configuration steps: + ``` bash LEDGER_ID=fetchai ``` -
Alternatively, configure the agent to use an ethereum ledger -

+??? note "Alternatively, configure the agent to use an ethereum ledger:" -``` bash -LEDGER_ID=ethereum -``` + ``` bash + LEDGER_ID=ethereum + ``` -Update the default ledger. -``` bash -aea config set agent.default_ledger ethereum -``` + Update the default ledger. -Set the following configuration for the oracle skill: -``` bash -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id ethereum -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function updateOracleValue -``` + ``` bash + aea config set agent.default_ledger ethereum + ``` + + Set the following configuration for the oracle skill: -

-
+ ``` bash + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id ethereum + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function updateOracleValue + ``` Additionally, create the private key for the oracle AEA. Generate and add a key for use with the ledger: + ``` bash aea generate-key $LEDGER_ID --add-key ``` If running on a testnet (not including Ganache), generate some wealth for your AEA: + ``` bash aea generate-wealth $LEDGER_ID ``` -### Create the oracle client AEA +### Create the Oracle Client AEA From a new terminal (in the same top-level directory), fetch the AEA that will deploy the oracle client contract and call the function that requests the coin price from the oracle contract. @@ -131,66 +135,62 @@ cd coin_price_oracle_client aea install ``` -
Alternatively, create from scratch -

- -Create the AEA that will deploy the contract. - -``` bash -aea create coin_price_oracle_client -cd coin_price_oracle_client -aea add connection fetchai/http_client:0.24.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/simple_oracle_client:0.13.4 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/ledger:0.21.4 -aea install -``` - -Then update the agent configuration with the default routing: -``` bash -aea config set --type dict agent.default_routing \ -'{ -"fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", -"fetchai/http:1.1.6": "fetchai/http_client:0.24.5", -"fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" -}' -``` - -Set the default ledger: -``` bash -aea config set agent.default_ledger fetchai -``` -Set the following configuration for the oracle client skill: -``` bash -aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id fetchai -aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function query_oracle_value -``` - -

-
+??? note "Alternatively, create from scratch:" + Create the AEA that will deploy the contract. + + ``` bash + aea create coin_price_oracle_client + cd coin_price_oracle_client + aea add connection fetchai/http_client:0.24.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/simple_oracle_client:0.13.4 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/ledger:0.21.4 + aea install + ``` + + Then update the agent configuration with the default routing: + + ``` bash + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/http:1.1.6": "fetchai/http_client:0.24.5", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" + }' + ``` + + Set the default ledger: + + ``` bash + aea config set agent.default_ledger fetchai + ``` + Set the following configuration for the oracle client skill: + + ``` bash + aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id fetchai + aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function query_oracle_value + ``` Similar to above, set a temporary variable `LEDGER_ID=fetchai` or `LEDGER_ID=ethereum`. -
Follow these steps to configure for an ethereum ledger -

+??? note "Follow these steps to configure for an ethereum ledger:" + Set the default ledger: -Set the default ledger: -``` bash -aea config set agent.default_ledger ethereum -``` -Set the following configuration for the oracle client skill: -``` bash -aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id ethereum -aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function queryOracleValue -``` + ``` bash + aea config set agent.default_ledger ethereum + ``` + + Set the following configuration for the oracle client skill: -

-
+ ``` bash + aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id ethereum + aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function queryOracleValue + ``` Create the private key for the oracle client AEA. Generate and add a key for use on the ledger: @@ -199,98 +199,100 @@ aea generate-key $LEDGER_ID --add-key ``` If running on a testnet (not including Ganache), generate some wealth for your AEA: + ``` bash aea generate-wealth $LEDGER_ID ``` -### Configuring a ledger +### Configuring a Ledger The oracle AEAs require either a locally running ledger node or a connection to a remote ledger. By default, they are configured to use the latest `fetchai` testnet. -
Follow these steps to configure local Ethereum test node -

- -The easiest way to test the oracle agents on an Ethereum-based ledger to set up a local test node using Ganache. This can be done by running the following docker command from the directory you started from (in a new terminal). This command will also fund the accounts of the AEAs: - -``` bash -docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat coin_price_oracle/ethereum_private_key.txt),1000000000000000000000" --account="$(cat coin_price_oracle_client/ethereum_private_key.txt),1000000000000000000000" -``` - -Run the following Python script (with web3 installed) from the top-level directory to deploy a mock Fetch ERC20 contract and give some test FET to the client agent. - -``` python -import json -import os -from web3 import Web3 - -FILE_DIR = os.path.dirname(os.path.realpath(__file__)) -CONTRACT_PATH = os.path.join(FILE_DIR, "coin_price_oracle_client/vendor/fetchai/contracts/fet_erc20/build/FetERC20Mock.json") -ORACLE_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, "coin_price_oracle/ethereum_private_key.txt") -CLIENT_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, "coin_price_oracle_client/ethereum_private_key.txt") - -# Solidity source code -with open(CONTRACT_PATH) as file: - compiled_sol = json.load(file) - -# web3.py instance -w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545')) - -# Import oracle account from private key and set to default account -with open(ORACLE_PRIVATE_KEY_PATH) as file: - private_key = file.read() -oracle_account = w3.eth.account.privateKeyToAccount(private_key) -w3.eth.defaultAccount = oracle_account.address - -# Import client account from private key -with open(CLIENT_PRIVATE_KEY_PATH) as file: - private_key = file.read() -client_account = w3.eth.account.privateKeyToAccount(private_key) - -# Deploy mock Fetch ERC20 contract -FetERC20Mock = w3.eth.contract(abi=compiled_sol['abi'], bytecode=compiled_sol['bytecode']) - -# Submit the transaction that deploys the contract -tx_hash = FetERC20Mock.constructor( - name="FetERC20Mock", - symbol="MFET", - initialSupply=int(1e23), - decimals_=18).transact() - -# Wait for the transaction to be mined, and get the transaction receipt -tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) - -# Print out the contract address -print("FetERC20Mock contract deployed at:", tx_receipt.contractAddress) - -# Get deployed contract -fet_erc20_mock = w3.eth.contract(address=tx_receipt.contractAddress, abi=compiled_sol['abi']) - -# Transfer some test FET to oracle client account -tx_hash = fet_erc20_mock.functions.transfer(client_account.address, int(1e20)).transact() -tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) -``` - -Set the ERC20 contract address for the oracle AEA -``` bash -aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address $ERC20_ADDRESS -``` -as well as for the oracle client AEA -``` bash -aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address $ERC20_ADDRESS -``` -where `ERC20_ADDRESS` is in the output of the script above. - -

-
- -### Run the oracle AEA +??? note "Follow these steps to configure local Ethereum test node:" + The easiest way to test the oracle agents on an Ethereum-based ledger to set up a local test node using Ganache. This can be done by running the following docker command from the directory you started from (in a new terminal). This command will also fund the accounts of the AEAs: + + ``` bash + docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat coin_price_oracle/ethereum_private_key.txt),1000000000000000000000" --account="$(cat coin_price_oracle_client/ethereum_private_key.txt),1000000000000000000000" + ``` + + Run the following Python script (with web3 installed) from the top-level directory to deploy a mock Fetch ERC20 contract and give some test FET to the client agent. + + ``` python + import json + import os + from web3 import Web3 + + FILE_DIR = os.path.dirname(os.path.realpath(__file__)) + CONTRACT_PATH = os.path.join(FILE_DIR, "coin_price_oracle_client/vendor/fetchai/contracts/fet_erc20/build/FetERC20Mock.json") + ORACLE_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, "coin_price_oracle/ethereum_private_key.txt") + CLIENT_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, "coin_price_oracle_client/ethereum_private_key.txt") + + # Solidity source code + with open(CONTRACT_PATH) as file: + compiled_sol = json.load(file) + + # web3.py instance + w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545')) + + # Import oracle account from private key and set to default account + with open(ORACLE_PRIVATE_KEY_PATH) as file: + private_key = file.read() + oracle_account = w3.eth.account.privateKeyToAccount(private_key) + w3.eth.defaultAccount = oracle_account.address + + # Import client account from private key + with open(CLIENT_PRIVATE_KEY_PATH) as file: + private_key = file.read() + client_account = w3.eth.account.privateKeyToAccount(private_key) + + # Deploy mock Fetch ERC20 contract + FetERC20Mock = w3.eth.contract(abi=compiled_sol['abi'], bytecode=compiled_sol['bytecode']) + + # Submit the transaction that deploys the contract + tx_hash = FetERC20Mock.constructor( + name="FetERC20Mock", + symbol="MFET", + initialSupply=int(1e23), + decimals_=18).transact() + + # Wait for the transaction to be mined, and get the transaction receipt + tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) + + # Print out the contract address + print("FetERC20Mock contract deployed at:", tx_receipt.contractAddress) + + # Get deployed contract + fet_erc20_mock = w3.eth.contract(address=tx_receipt.contractAddress, abi=compiled_sol['abi']) + + # Transfer some test FET to oracle client account + tx_hash = fet_erc20_mock.functions.transfer(client_account.address, int(1e20)).transact() + tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) + ``` + + Set the ERC20 contract address for the oracle AEA + + ``` bash + aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address $ERC20_ADDRESS + ``` + + as well as for the oracle client AEA + + ``` bash + aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address $ERC20_ADDRESS + ``` + + where `ERC20_ADDRESS` is in the output of the script above. + +### Run the Oracle AEA Run the oracle agent. This will deploy a contract to the testnet, grant oracle permissions to the AEA's wallet address, and periodically update the contract with the latest price of FET (or whichever coin was specified). + ``` bash aea run ``` After a few moments, you should see the following notices in the logs: + ``` bash info: [coin_price_oracle] Oracle contract successfully deployed at address: ... ... @@ -298,28 +300,35 @@ info: [coin_price_oracle] Oracle role successfully granted! ... info: [coin_price_oracle] Oracle value successfully updated! ``` + The oracle contract will continue to be updated with the latest retrieved coin price at the default time interval (every 15 seconds). -### Set the ERC20 and oracle contract addresses for the oracle client AEA: +### Set the ERC20 and Oracle Contract Addresses for the Oracle Client AEA + ``` bash aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address $ORACLE_ADDRESS ``` + where `ORACLE_ADDRESS` should be set to the address shown in the oracle AEA logs: + ``` bash Oracle contract successfully deployed at address: ORACLE_ADDRESS ``` -### Run the oracle client AEA +### Run the Oracle Client AEA Run the oracle client agent. This will deploy an oracle client contract to the testnet, approve the contract to spend tokens on behalf of the AEA, and periodically call the contract function that requests the latest price of FET (or whichever coin was specified). + ``` bash aea run ``` After a few moments, you should see the following notices in the logs: + ``` bash info: [coin_price_oracle_client] Oracle client contract successfully deployed at address: ... ... info: [coin_price_oracle_client] Oracle value successfully requested! ``` + The AEA will continue to request the latest coin price at the default time interval (every 15 seconds). diff --git a/docs/orm-integration.md b/docs/orm-integration.md index 8182e596fd..a2b9459f07 100644 --- a/docs/orm-integration.md +++ b/docs/orm-integration.md @@ -1,3 +1,5 @@ +# ORM Integration + This guide demonstrates how to configure an AEA to interact with a database using `python-sql` objects. ## Discussion @@ -8,13 +10,13 @@ Object-relational-mapping (ORM) is the idea of being able to write SQL queries, - We assume, that we have a database `genericdb.db` with table name `data`. This table contains the following columns `timestamp` and `thermometer`. - We assume, that we have a hardware thermometer sensor that adds the readings in the `genericdb` database (although you can follow the guide without having access to a sensor). -Since the AEA framework enables us to use third-party libraries hosted on PyPI we can directly reference the external dependencies. The `aea install` command will install each dependency that the specific AEA needs and which is listed in the skill's YAML file. +Since the AEA framework enables us to use third-party libraries hosted on PyPI we can directly reference the external dependencies. The `aea install` command will install each dependency that the specific AEA needs and which is listed in the skill's YAML file. ## Communication -This diagram shows the communication between the various entities in the case where the thermometer data is successfully sold by the seller AEA to the buyer. +This diagram shows the communication between the various entities in the case where the thermometer data is successfully sold by the seller AEA to the buyer. -
+``` mermaid sequenceDiagram participant Search participant Buyer_AEA @@ -41,147 +43,145 @@ This diagram shows the communication between the various entities in the case wh deactivate Buyer_AEA deactivate Search deactivate Seller_AEA - deactivate Blockchain - -
+ deactivate Blockchain +``` -## Preparation instructions +## Preparation Instructions ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -## Demo instructions +## Demo Instructions This demo involves a true ledger transaction on Fetch.ai's `testnet` network or Ethereum's `ropsten`. This demo assumes the buyer trusts the seller AEA to send the data upon successful payment. -### Create the seller AEA +### Create the Seller AEA First, fetch the seller AEA which provides thermometer data: -``` bash -aea fetch fetchai/thermometer_aea:0.30.4 --alias my_thermometer_aea -cd my_thermometer_aea -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the seller from scratch: ``` bash -aea create my_thermometer_aea +aea fetch fetchai/thermometer_aea:0.30.4 --alias my_thermometer_aea cd my_thermometer_aea -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/thermometer:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- - -### Create the buyer client +??? note "Alternatively, create from scratch:" + The following steps create the seller from scratch: + + ``` bash + aea create my_thermometer_aea + cd my_thermometer_aea + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/thermometer:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +### Create the Buyer Client In another terminal, fetch the buyer AEA: -``` bash -aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client -cd my_thermometer_client -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the car data client from scratch: ``` bash -aea create my_thermometer_client +aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client cd my_thermometer_client -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/thermometer_client:0.26.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- - -### Add keys for the seller AEA +??? note "Alternatively, create from scratch:" + The following steps create the car data client from scratch: + + ``` bash + aea create my_thermometer_client + cd my_thermometer_client + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/thermometer_client:0.26.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +### Add Keys for the Seller AEA First, create the private key for the seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Add keys and generate wealth for the buyer AEA +### Add Keys and Generate Wealth for the Buyer AEA The buyer needs to have some wealth to purchase the thermometer data. First, create the private key for the buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for the buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` - -### Update the seller and buyer AEA skill configurations +### Update the Seller and Buyer AEA Skill Configurations In `my_thermometer_aea/vendor/fetchai/skills/thermometer/skill.yaml`, replace the `data_for_sale` with your data: + ``` yaml models: ... @@ -205,6 +205,7 @@ models: dependencies: SQLAlchemy: {} ``` + The `service_data` is used to register the service in the SOEF search node and make your agent discoverable. In `my_thermometer_client/vendor/fetchai/skills/thermometer_client/skill.yaml`) ensure you have matching data. @@ -233,11 +234,12 @@ models: ``` After changing the skill configuration files you should run the following command for both agents to install each dependency: + ``` bash aea install ``` -### Modify the seller's strategy +### Modify the Seller's Strategy Before being able to modify a package we need to eject it from vendor: @@ -250,10 +252,13 @@ This will move the package to your `skills` directory and reset the version to ` Open `strategy.py` (in `my_thermometer_aea/skills/thermometer/strategy.py`) and make the following modifications: Import the newly installed `sqlalchemy` library in your strategy. + ``` python import sqlalchemy as db ``` + Then modify your strategy's `__init__` function to match the following code: + ``` python class Strategy(GenericStrategy): """This class defines a strategy for the agent.""" @@ -271,9 +276,10 @@ class Strategy(GenericStrategy): self._tbl = self.create_database_and_table() self.insert_data() super().__init__(**kwargs) -``` +``` + +At the end of the file modify the `collect_from_data_source` function: -At the end of the file modify the `collect_from_data_source` function: ``` python def collect_from_data_source(self) -> Dict[str, str]: """Implement the logic to collect data.""" @@ -283,6 +289,7 @@ At the end of the file modify the `collect_from_data_source` function: data_points = result_proxy.fetchall() return {"data": json.dumps(list(map(tuple, data_points)))} ``` + Also, create two new functions, one that creates a connection with the database, and another that populates the database with some fake data. This is needed in the case you do not have access to an actual thermometer sensor that inserts data in the database. ``` python @@ -315,7 +322,7 @@ After modifying the skill we need to fingerprint it: aea fingerprint skill {YOUR_AUTHOR_HANDLE}/thermometer:0.1.0 ``` -### Run both AEAs +### Run Both AEAs First, run the thermometer (seller) AEA: @@ -327,6 +334,7 @@ Once you see a message of the form `To join its network use multiaddr 'SOME_ADDR This is the entry peer address for the local agent communication network created by the thermometer AEA. Then, configure the thermometer client (buyer) to connect to this same local ACN by running the following command in the buyer terminal, replacing `SOME_ADDRESS` with the value you noted above: + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -339,6 +347,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ ``` Then run the thermometer client AEA: + ``` bash aea run ``` @@ -348,8 +357,9 @@ You will see that the AEAs negotiate and then transact using the configured test ## Delete the AEAs When you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs. -``` bash + +``` bash cd .. aea delete my_thermometer_aea aea delete my_thermometer_client -``` \ No newline at end of file +``` diff --git a/docs/p2p-connection.md b/docs/p2p-connection.md index f795c5c06b..5253d3f1b5 100644 --- a/docs/p2p-connection.md +++ b/docs/p2p-connection.md @@ -1,14 +1,17 @@ +# P2P Connection + The `fetchai/p2p_libp2p:0.27.4` connection allows AEAs to create a peer-to-peer communication network. In particular, the connection creates an overlay network which maps agents' public keys to IP addresses. -## Local demo +## Local Demo First, make sure you have installed the crypto plugin of the target test-net. E.g. for Fetch.AI: + ``` bash pip install aea-ledger-fetchai ``` -### Create and run the genesis AEA +### Create and Run the Genesis AEA Create one AEA as follows: @@ -40,7 +43,7 @@ aea run --connections fetchai/p2p_libp2p:0.27.4 Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) This is the entry peer address for the local agent communication network created by the genesis AEA. -### Create and run another AEA +### Create and Run Another AEA Create a second AEA: @@ -75,6 +78,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + Here `SOME_ADDRESS` needs to be replaced with the list of multi addresses displayed in the log output of the genesis AEA. Run the AEA: @@ -85,29 +89,27 @@ aea run --connections fetchai/p2p_libp2p:0.27.4 You can inspect the `libp2p_node.log` log files of the AEA to see how they discover each other. -
-

Note

-

Currently p2p_libp2p connection limits the total message size to 3 MB. -

-
+!!! note + Currently `p2p_libp2p` connection limits the total message size to 3 MB. - -## Local demo with skills +## Local Demo with Skills Explore the demo section for further examples. -## Deployed agent communication network +## Deployed Agent Communication Network You can connect to the deployed public test network by adding one or multiple of the following addresses as the `p2p_libp2p` connection's `entry_peers`: ``` yaml /dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx ``` + ``` yaml /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW ``` Specifically, in an AEA's configuration `aea-config.yaml` add the above addresses for `entry_peers` as follows: + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -121,32 +123,35 @@ config: Note, this configuration change must be made for all agents attempting to communicate with each other via the Agent Communication Network. For example, in demos involving two agents, both agents will need the above modifications to their respective `aea-config.yaml` file. However, remember to use different ports in `local_uri.` This will allow both agents to default to this communication network without the added overhead of opening ports and specifying hosts on the individual host machines running each agent. - -## Configuring the `connection.yaml` entries: +## Configuring the `connection.yaml` Entries To learn more about how to configure your `fetchai/p2p_libp2p:0.27.4` connection consult the `README.md` file supplied with the connection package. -## Running Go peer standalone +## Running Go Peer Standalone You can run a peer node in _standalone mode_; that is, as a Go process with no dependency on the AEA framework. To facilitate such a deployment, we provide a script `run_acn_node_standalone.py` - and a corresponding + and a corresponding Dockerfile. First, you need to build the node's binary (`libp2p_node`) either: - locally - ``` bash - svn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p - cd p2p_libp2p - go build - chmod +x libp2p_node - ``` - Make sure you satisfy the system requirements. + + ``` bash + svn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p + cd p2p_libp2p + go build + chmod +x libp2p_node + ``` + + Make sure you satisfy the system requirements. + - or within a docker image using the provided Dockerfile: - ``` bash - docker build -t acn_node_standalone -f scripts/acn/Dockerfile . - ``` + + ``` bash + docker build -t acn_node_standalone -f scripts/acn/Dockerfile . + ``` Next, to run the node binary in standalone mode, it requires values for the following entries: @@ -154,35 +159,44 @@ Next, to run the node binary in standalone mode, it requires values for the foll - `AEA_P2P_URI`: the local host and port to use by node - `AEA_P2P_URI_PUBLIC`: the URI under which the peer is publicly reachable - `AEA_P2P_DELEGATE_URI`: the URI under which the peer receives delegate connections -- `AEA_P2P_ENTRY_URIS`: an optionally supplied list of comma-separated (`,`) entry Multiaddresses for the peer to bootstrap +- `AEA_P2P_ENTRY_URIS`: an optionally supplied list of comma-separated (`,`) entry multiaddresses for the peer to bootstrap The script allows different methods to pass these values to the node: - As environment variables exported in the format `=` for each entry. Then: - ``` bash - python3 run_acn_node_standalone.py libp2p_node --config-from-env - ``` + + ``` bash + python3 run_acn_node_standalone.py libp2p_node --config-from-env + ``` + - Using an environment file containing the entries and their values in the format `=`, one entry per line. Then: - ``` bash - python3 run_acn_node_standalone.py libp2p_node --config-from-file - ``` - or - ``` bash - docker run -v :/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config - ``` + + ``` bash + python3 run_acn_node_standalone.py libp2p_node --config-from-file + ``` + + or + + ``` bash + docker run -v :/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config + ``` + - Using command line arguments: - ``` bash - python3 run_acn_node_standalone.py libp2p_node --key-file \ - --uri --uri-external \ - --uri-delegate \ - --entry-peers-maddrs ... - ``` - or - ``` bash - docker run -v :/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \ - --uri --uri-external \ - --uri-delegate \ - --entry-peers-maddrs ... - ``` + + ``` bash + python3 run_acn_node_standalone.py libp2p_node --key-file \ + --uri --uri-external \ + --uri-delegate \ + --entry-peers-maddrs ... + ``` + + or + + ``` bash + docker run -v :/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \ + --uri --uri-external \ + --uri-delegate \ + --entry-peers-maddrs ... + ``` Note that the script will always save the configuration of the running node as a file under the name `.acn_config` in the current working directory. This can be handy when you want the exact same configuration for future runs of the node. diff --git a/docs/package-imports.md b/docs/package-imports.md index 75f5b0a5a7..20302f20d4 100644 --- a/docs/package-imports.md +++ b/docs/package-imports.md @@ -1,6 +1,8 @@ +# File Structure + An agent that is generated using the AEA framework is a modular system with different connections, contracts, protocols and skills. -## File structure +## An AEA Project's File Structure The file structure of an AEA is fixed. @@ -45,6 +47,7 @@ The developer can create new directories where necessary but the core structure The `aea-config.yaml` is the top level configuration file of an AEA. It defines the global configurations as well as the component/package dependencies of the AEA. In some sense, the AEA can therefore be understood as an orchestrator of components. For the AEA to use a package, the `public_id` for the package must be listed in the `aea-config.yaml` file, e.g. + ``` yaml connections: - fetchai/stub:0.21.2 @@ -52,15 +55,15 @@ connections: The above shows a part of the `aea-config.yaml`. If you see the connections, you will see that we follow a pattern of `author/name_package:version` to identify each package, also referred to as `public_id`. Here the `author` is the author of the package. -## Vendor and package directories +## Vendor and Package Directories -The `vendor` folder contains the packages from the registry (local or remote) which have been developed by ourselves, other authors or Fetch.ai and are namespaced by author name. +The `vendor` folder contains the packages from the registry (local or remote) which have been developed by ourselves, other authors or Fetch.ai and are placed in different namespaces according to the author name. The packages we develop as part of the given AEA project are in the respective `connections/`, `contracts/`, `protocols/`, and `skills/` folders. In the above configuration example, the package is authored by Fetch.ai and is located inside the `vendor/fetchai/connections` folder. -## Importing modules from packages +## Importing Modules from Packages The way we import modules from packages inside the agent is in the form of `packages.{author}.{package_type}.{package_name}.{module_name}`. So for the above example, the import path is `packages.fetchai.connections.stub.{module_name}`. @@ -68,24 +71,24 @@ The framework loads the modules from the local agent project and adds them to Py We use a custom package management approach for the AEAs rather than the default Python one as it provides us with more flexibility, especially when it comes to extension beyond the Python ecosystem. -## Python dependencies of packages +## Python Dependencies of Packages Python dependencies of packages are specified in their respective configuration files under `dependencies`. They will be installed when `aea install` is run on an agent project. -## Create a package +## Create a Package If you want to create a package, you can use the CLI command `aea scaffold connection/contract/protocol/skill [name]` and this will create the package and put it inside the respective folder based on the command for example if we `scaffold` skill with the name `my_skill` it will be located inside the folder skills in the root directory of the agent (`my_aea/skills/my_skill`). -## Use published packages from the registry +## Use Published Packages from the Registry If you want to use a finished package, you can use a package from the registry. There or two registries. The remote registry operated by Fetch.ai and a local registry stub. The local registry stub is a directory called `packages` which contains packages in a nested structure with authors on the top level, followed by the package type, then package name. An example of such a directory is the `packages` directory located in the AEA repository. The local registry is useful for development. -You can use the CLI to interact with the registry. By default the CLI points to the remote registry. You can point it to the local registry via the flag `--local`. +You can use the CLI to interact with the registry. By default, the CLI points to the remote registry. You can point it to the local registry via the flag `--local`. -## Package versioning +## Package Versioning By default, the AEA can only handle one version per package. That is, a project should never use both `some_author/some_package_name:0.1.0` and `some_author/some_package_name:0.2.0`. diff --git a/docs/performance-benchmark.md b/docs/performance-benchmark.md index 3b6544e6e3..9b2af48262 100644 --- a/docs/performance-benchmark.md +++ b/docs/performance-benchmark.md @@ -1,31 +1,31 @@ +# Performance Benchmark + Test AEA framework performance. ## What is it? The benchmark module is a set of tools to measure execution time, CPU load and memory usage of the AEA Python code. It produces text reports and draws charts to present the results. -## How does it work? +## How does it Work? The framework: -* spawns a dedicated process for each test run to execute the function to test. -* measures CPU and RAM usage periodically. -* waits for function exits or terminates them by timeout. -* repeats test execution multiple times to get more accurate results. - - +- spawns a dedicated process for each test run to execute the function to test. +- measures CPU and RAM usage periodically. +- waits for function exits or terminates them by timeout. +- repeats test execution multiple times to get more accurate results. -## How to use +## How to Use Steps to run a test: -* Write a function you would like to test with all arguments you would like to parametrise, add some doc strings. -* Split the function into two parts: prepare part and performance part. The prepare part will not be included in the measurement. -* Add `BenchmarkControl` support, to notify framework to start measurement. -* Import `TestCli` class, `TestCli().run(function_to_be_tested)` -* Call it from console to get text results. +- Write a function you would like to test with all arguments you would like to parametrise, add some doc strings. +- Split the function into two parts: 'prepare' and 'performance' part. The 'prepare' part will not be included in the measurement. +- Add `BenchmarkControl` support, to notify framework to start measurement. +- Import `TestCli` class, `TestCli().run(function_to_be_tested)` +- Call it from console to get text results. -### Simple example +### Simple Example `cpuburn` - simple test of CPU load depends on idle sleep time. Shows how much CPU consumed during the execution. @@ -59,8 +59,8 @@ if __name__ == "__main__": TestCli(cpu_burn).run() ``` - Run it with `python ./benchmark/cases/cpu_burn.py --help` to get help about usage. + ``` bash Usage: cpu_burn.py [OPTIONS] [ARGS]... @@ -83,8 +83,8 @@ Options: --help Show this message and exit. ``` - Run it with `python ./benchmark/cases/cpu_burn.py` to start with default parameters. + ``` bash Test execution timeout: 10.0 Test execution measure period: 0.1 @@ -116,11 +116,11 @@ mem mean (kb): 53.98828125 ± 0 Here you can see test report for default arguments set. - Run with multiple arguments set, multiple repeats and draw a chart on resources `python ./benchmark/cases/cpu_burn.py -N 5 -P 1 3,0.00001 3,0.001 3,0.01` Report is: + ``` bash Test execution timeout: 10.0 Test execution measure period: 0.1 @@ -179,27 +179,24 @@ Chart is drawn for argument 1: sleep: The most interesting part is CPU usage, as you can see CPU usage decreases with increasing value of idle sleep. Memory usage and execution time can slightly differ per case execution. +## Requirements for Tested Function -## Requirements for tested function - -* The first function's argument has to be `benchmark: BenchmarkControl` which is passed by default by the framework. -* All arguments except the fist one have to set default values. -* Function doc string is required, it used for help information. -* `benchmark.start()` has to be called once in the function body to start measurement. The timeout is counted from this point! -* All the "prepare part" in the function that should not be measured has to be placed before `benchmark.start()` -* Code to be measured has to go after `benchmark.start()` -* Try to avoid infinitive loops and assume the test should exit after a while. +- The first function's argument has to be `benchmark: BenchmarkControl` which is passed by default by the framework. +- All arguments except the fist one have to set default values. +- Function doc string is required, it used for help information. +- `benchmark.start()` has to be called once in the function body to start measurement. The timeout is counted from this point! +- All the "prepare part" in the function that should not be measured has to be placed before `benchmark.start()` +- Code to be measured has to go after `benchmark.start()` +- Try to avoid infinitive loops and assume the test should exit after a while. +## Execution Options -## Execution options - -* To pass an arguments set just provide it as a comma separated string like `10,0.1` -* To pass several argument sets just separate them by white space `10,0.1 20,0.2` -* `--timeout FLOAT` is test execution timeout in seconds. If the test takes more time, it will be terminated. -* `--period FLOAT` is measurement interval in seconds, how often to make CPU and RAM usage measurements. -* `-N, --num-executions INTEGER` - how many time to run the same argument set to make result more accurate. -* `-P, --plot INTEGER` - Draw a chart using, using values of argument specified as values for axis X. argument positions started with 0, argument benchmark does not counted. for example `-P 0` will use `run_time` values, `-P 1` will use `sleep` values. - +- To pass an arguments set just provide it as a comma separated string like `10,0.1` +- To pass several argument sets just separate them by white space `10,0.1 20,0.2` +- `--timeout FLOAT` is test execution timeout in seconds. If the test takes more time, it will be terminated. +- `--period FLOAT` is measurement interval in seconds, how often to make CPU and RAM usage measurements. +- `-N, --num-executions INTEGER` - how many times to run the same argument set to make result more accurate. +- `-P, --plot INTEGER` - Draw a chart, using values in the argument on the X axis, argument positions started with 0, argument benchmark not counted. For example `-P 0` will use `run_time` values, `-P 1` will use `sleep` values, and so on. ## Limitations @@ -207,9 +204,7 @@ Currently, the benchmark framework does not measure resources consumed by subpro Asynchronous functions or coroutines are not supported directly. So you have to set up an event loop inside test function and start loop manually. - - -## Testing AEA: handlers example +## Testing AEA: Handlers Example Test react speed on specific messages amount. @@ -247,8 +242,8 @@ def react_speed_in_loop(benchmark: BenchmarkControl, inbox_amount=1000) -> None: aea_test_wrapper.stop_loop() ``` - Create AEA wrapper with specified handler: + ``` python skill_definition = { "handlers": {"dummy_handler": DummyHandler} @@ -259,8 +254,8 @@ aea_test_wrapper = AEATestWrapper( ) ``` - Populate inbox with dummy messages: + ``` python for _ in range(inbox_amount): aea_test_wrapper.put_inbox(aea_test_wrapper.dummy_envelope()) @@ -271,6 +266,7 @@ Set timeout `0`, for maximum messages processing speed: `aea_test_wrapper.set_lo Start benchmark: `benchmark.start()` Start/stop AEA: + ``` python aea_test_wrapper.start() ... @@ -278,6 +274,7 @@ aea_test_wrapper.stop() ``` Wait till messages present in inbox: + ``` python while not aea_test_wrapper.is_inbox_empty(): time.sleep(0.1) diff --git a/docs/por.md b/docs/por.md index 5a5c6e8acd..34030410a7 100644 --- a/docs/por.md +++ b/docs/por.md @@ -1,3 +1,4 @@ +# Proof of Representation An AEA can use several key pairs. In particular, it can use different keys for securing its communication and for engaging in exchange. In the ACN we make use of this fact. To be able to signal to other agents that the address derived from one key pair is allowed to represent the agent controlling the other key pair, the key pair which is being represented must sign a message to prove that the other key pair is allowed to represent it. The `aea issue-certificates` command allows to create this association. @@ -16,6 +17,6 @@ cert_requests: save_path: .certs/conn_cert.txt ``` -The `identifier` refers to the environment for which the signature is generated, here `acn`. The `ledger_id` refers to the key pair to be used from the `private_key_paths` specified in `aea-config.yaml` for signing. The `not_after` and `not_before` fields specify constraints on the validity of the signature. The `public_key` can specify either the identifier of the key pair in `connection_private_key_paths` of which the public key is signed or it can contain the to be signed public key in plain text. The `save_path` specifies the path where the certificate is to be saved at. +The `identifier` refers to the environment for which the signature is generated, here `acn`. The `ledger_id` refers to the key pair to be used from the `private_key_paths` specified in `aea-config.yaml` for signing. The `not_after` and `not_before` fields specify constraints on the validity of the signature. The `public_key` can specify either the identifier of the key pair in `connection_private_key_paths`, of which the public key is signed, or it can contain the to be signed public key in plain text. The `save_path` specifies the path where the certificate is to be saved at. In the above example, the connection requests a certificate which is a signature of the `fetchai` public key in `connection_private_key_paths` with the `fetchai` key pair in `private_key_paths`. The validity of the signature will be constrained to the year `2021` for the environment `acn`. diff --git a/docs/prometheus.md b/docs/prometheus.md index 1f4094766c..14640ee71e 100644 --- a/docs/prometheus.md +++ b/docs/prometheus.md @@ -1,6 +1,9 @@ +# Prometheus Monitoring + AEAs can create and update prometheus metrics for remote monitoring by sending messages to the prometheus connection `fetchai/prometheus:0.9.5`. To see this working in an agent, fetch and run the `coin_price_feed` agent and check `localhost:9090/metrics` to see the latest values of the metrics `num_retrievals` and `num_requests`: + ``` bash aea fetch fetchai/coin_price_feed:0.15.4 cd coin_price_feed @@ -8,49 +11,48 @@ aea install aea build aea run ``` + You can then instruct a prometheus server running on the same computing cluster as a deployed agent to scrape these metrics for remote monitoring and visualisation with the Prometheus/Grafana toolset. To use this connection, add a model `prometheus_dialogues` to your skill to handle the metrics configuration and messages to the prometheus connection. -
Click here for example - - -``` python -class PrometheusDialogues(Model, BasePrometheusDialogues): - """The dialogues class keeps track of all prometheus dialogues.""" - - def __init__(self, **kwargs) -> None: - """ - Initialize dialogues. - - :return: None - """ - - self.enabled = kwargs.pop("enabled", False) - self.metrics = kwargs.pop("metrics", []) - - Model.__init__(self, **kwargs) +??? note "Click here for example:" + ``` python + class PrometheusDialogues(Model, BasePrometheusDialogues): + """The dialogues class keeps track of all prometheus dialogues.""" - def role_from_first_message( # pylint: disable=unused-argument - message: Message, receiver_address: Address - ) -> BaseDialogue.Role: - """Infer the role of the agent from an incoming/outgoing first message - - :param message: an incoming/outgoing first message - :param receiver_address: the address of the receiving agent - :return: The role of the agent + def __init__(self, **kwargs) -> None: """ - return PrometheusDialogue.Role.AGENT - - BasePrometheusDialogues.__init__( - self, - self_address=str(self.skill_id), - role_from_first_message=role_from_first_message, - ) -``` -
+ Initialize dialogues. + + :return: None + """ + + self.enabled = kwargs.pop("enabled", False) + self.metrics = kwargs.pop("metrics", []) + + Model.__init__(self, **kwargs) + + def role_from_first_message( # pylint: disable=unused-argument + message: Message, receiver_address: Address + ) -> BaseDialogue.Role: + """Infer the role of the agent from an incoming/outgoing first message + + :param message: an incoming/outgoing first message + :param receiver_address: the address of the receiving agent + :return: The role of the agent + """ + return PrometheusDialogue.Role.AGENT + + BasePrometheusDialogues.__init__( + self, + self_address=str(self.skill_id), + role_from_first_message=role_from_first_message, + ) + ``` Then configure your metrics in the `skill.yaml` file. For example (from the `advanced_data_request` skill): + ``` yaml models: prometheus_dialogues: @@ -69,6 +71,7 @@ models: ``` Add a metric `metric_name` of type `metric_type` {`Gauge`, `Counter`, ...} and description `description` by sending a message with performative `ADD_METRIC` to the prometheus connection: + ``` python def add_prometheus_metric( self, @@ -103,7 +106,9 @@ def add_prometheus_metric( # send message self.context.outbox.put_message(message=message) ``` + where `PROM_CONNECTION_ID` should be imported to your skill as follows: + ``` python from packages.fetchai.connections.prometheus.connection import ( PUBLIC_ID as PROM_CONNECTION_ID, @@ -111,6 +116,7 @@ from packages.fetchai.connections.prometheus.connection import ( ``` Update metric `metric_name` with update function `update_func` {`inc`, `set`, `observe`, ...} and value `value` by sending a message with performative `UPDATE_METRIC` to the prometheus connection: + ``` python def update_prometheus_metric( self, metric_name: str, update_func: str, value: float, labels: Dict[str, str], @@ -143,6 +149,7 @@ def update_prometheus_metric( ``` Initialize the metrics from the configuration file in the behaviour setup: + ``` python def setup(self) -> None: """Implement the setup of the behaviour""" @@ -157,6 +164,7 @@ def setup(self) -> None: Then call the `update_prometheus_metric` function from the appropriate places. For example, the following code in `handlers.py` for the `advanced_data_request` skill updates the number of http requests served: + ``` python if self.context.prometheus_dialogues.enabled: self.context.behaviours.advanced_data_request_behaviour.update_prometheus_metric( @@ -166,73 +174,71 @@ if self.context.prometheus_dialogues.enabled: Finally, you can add a `PrometheusHandler` to your skill to process response messages from the prometheus connection. -
Click here for example - - -``` python -class PrometheusHandler(Handler): - """This class handles responses from the prometheus server.""" - - SUPPORTED_PROTOCOL = PrometheusMessage.protocol_id - - def __init__(self, **kwargs): - """Initialize the handler.""" - super().__init__(**kwargs) - - self.handled_message = None - - def setup(self) -> None: - """Set up the handler.""" - if self.context.prometheus_dialogues.enabled: - self.context.logger.info("setting up PrometheusHandler") - - def handle(self, message: Message) -> None: - """ - Implement the reaction to a message. - - :param message: the message - :return: None - """ - - message = cast(PrometheusMessage, message) - - # recover dialogue - prometheus_dialogues = cast( - PrometheusDialogues, self.context.prometheus_dialogues - ) - prometheus_dialogue = cast( - PrometheusDialogue, prometheus_dialogues.update(message) - ) - if prometheus_dialogue is None: - self._handle_unidentified_dialogue(message) - return - - self.handled_message = message - if message.performative == PrometheusMessage.Performative.RESPONSE: - self.context.logger.debug( - f"Prometheus response ({message.code}): {message.message}" +??? note "Click here for example:" + ``` python + class PrometheusHandler(Handler): + """This class handles responses from the prometheus server.""" + + SUPPORTED_PROTOCOL = PrometheusMessage.protocol_id + + def __init__(self, **kwargs): + """Initialize the handler.""" + super().__init__(**kwargs) + + self.handled_message = None + + def setup(self) -> None: + """Set up the handler.""" + if self.context.prometheus_dialogues.enabled: + self.context.logger.info("setting up PrometheusHandler") + + def handle(self, message: Message) -> None: + """ + Implement the reaction to a message. + + :param message: the message + :return: None + """ + + message = cast(PrometheusMessage, message) + + # recover dialogue + prometheus_dialogues = cast( + PrometheusDialogues, self.context.prometheus_dialogues ) - else: - self.context.logger.debug( - f"got unexpected prometheus message: Performative = {PrometheusMessage.Performative}" + prometheus_dialogue = cast( + PrometheusDialogue, prometheus_dialogues.update(message) ) - - def _handle_unidentified_dialogue(self, msg: Message) -> None: - """ - Handle an unidentified dialogue. - - :param msg: the unidentified message to be handled - :return: None - """ - - self.context.logger.info( - "received invalid message={}, unidentified dialogue.".format(msg) - ) - - def teardown(self) -> None: - """ - Teardown the handler. - - :return: None - """ -``` + if prometheus_dialogue is None: + self._handle_unidentified_dialogue(message) + return + + self.handled_message = message + if message.performative == PrometheusMessage.Performative.RESPONSE: + self.context.logger.debug( + f"Prometheus response ({message.code}): {message.message}" + ) + else: + self.context.logger.debug( + f"got unexpected prometheus message: Performative = {PrometheusMessage.Performative}" + ) + + def _handle_unidentified_dialogue(self, msg: Message) -> None: + """ + Handle an unidentified dialogue. + + :param msg: the unidentified message to be handled + :return: None + """ + + self.context.logger.info( + "received invalid message={}, unidentified dialogue.".format(msg) + ) + + def teardown(self) -> None: + """ + Teardown the handler. + + :return: None + """ + ``` diff --git a/docs/protocol-generator.md b/docs/protocol-generator.md index d90b6c5f2a..dbe8c5a6ed 100644 --- a/docs/protocol-generator.md +++ b/docs/protocol-generator.md @@ -1,9 +1,6 @@ -
-

Note

-

This is currently an experimental feature. To try it follow this guide.

-
+# Generating Protocols -## How to run +## How to Run First make sure you are inside your AEA's folder (see here on how to create a new agent). @@ -17,25 +14,25 @@ where `` is the path to a -

Note

-

Note the protocol buffer compiler protoc that the generator uses requires a plugin to produce go code. Follow this instruction.

- +!!! note + Note the protocol buffer compiler `protoc` that the generator uses requires a plugin to produce `go` code. Follow this instruction. ## Protocol Specification + A protocol can be described in a YAML file. This is called a _protocol specification_. The following is an example protocol specification: ``` yaml @@ -92,27 +88,27 @@ keep_terminal_state_dialogues: true ... ``` -Each protocol specification must follow the YAML format, and have a minimum of one and a maximum of three YAML documents (each YAML document is enclosed within --- and ...). +Each protocol specification must follow the YAML format, and have a minimum of one and a maximum of three YAML documents (each YAML document is enclosed within --- and ...). ### Basic Protocol Detail and Messages Syntax -The first YAML document is mandatory in any protocol specification. It contains some basic information about the protocol and describes the syntax of communicative messages allowed under this protocol. +The first YAML document is mandatory in any protocol specification. It contains some basic information about the protocol and describes the syntax of communicative messages allowed under this protocol. The allowed fields and what they represent are: - * `name`: The name of the protocol (written in snake_case) - * `author`: The creator of the protocol - * `version`: The current version of the protocol - * `license`: Licensing information - * `aea_version`: The version(s) of the framework that support this protocol. The format is described here. - * `description`: A short description of the protocol - * `protocol_specification_id`: The id which identifies the protocol for over-the-wire transport. This id is decoupled from the `protocol_id` (`{author}/{name}:{version}`) which is tied to the Python implementation. +- `name`: The name of the protocol (written in snake_case) +- `author`: The creator of the protocol +- `version`: The current version of the protocol +- `license`: Licensing information +- `aea_version`: The version(s) of the framework that support this protocol. The format is described here. +- `description`: A short description of the protocol +- `protocol_specification_id`: The id which identifies the protocol for over-the-wire transport. This id is decoupled from the `protocol_id` (`{author}/{name}:{version}`) which is tied to the Python implementation. -All of the above fields are mandatory and each is a key/value pair, where both key and value are YAML strings. +All of the above fields are mandatory and each is a key/value pair, where both key and value are YAML strings. Additionally, the first YAML document of a protocol specification must describe the syntax of valid messages according to this protocol. Therefore, it must contain another mandatory `speech-acts` field which defines the set of _performatives_ valid under this protocol, and a set of _contents_ for each performative. -A _performative_ defines the type of a message (e.g. propose, accept) and has a set of _contents_ (or parameters) of varying types. +A _performative_ defines the _type_ of a message (e.g. propose, accept) and has a set of _contents_ (or parameters) of varying types. The format of the `speech-act` is as follows: `speech-act` is a dictionary, where each key is a **unique** _performative_ (YAML string), and the value is a _content_ dictionary. If a performative does not have any content, then its content dictionary is empty, for instance `accept` and `decline` in the specification above. @@ -122,19 +118,19 @@ A content dictionary in turn has key/value pairs, where each key is the name of The specific types which could be assigned to contents in a protocol specification are described in the table below. -Types are either user defined (i.e. custom types) or primitive: +Types are either user defined (i.e. custom types) or primitive: + +- Custom types are prepended with `ct:` and their format is described using regular expression in the table below. +- Primitive types are prepended with `pt:`. There are different categories of primitive types. For example, `` such as integers and booleans, `` such as sets and lists, and so on. Primitive types are compositional: + - For example, consider `pt:set[...]` under ``, i.e. an unordered collection of elements without duplicates. A `pt:set[...]` describes the type of its elements (called "sub-type") in square brackets. The subtype of a `pt:set[...]` must be a `` (e.g. `pt:int`, `pt:bool`). + - In describing the format of types, `/` between two subtypes should be treated as "or". For example, the subtype of a `pt:optional[...]` is either a ``, ``, ``, `` or ``. -* Custom types are prepended with `ct:` and their format is described using regular expression in the table below. -* Primitive types are prepended with `pt:`. There are different categories of primitive types. For example, `` such as integers and booleans, `` such as sets and lists, and so on. Primitive types are compositional: - - For example, consider `pt:set[...]` under ``, i.e. an unordered collection of elements without duplicates. A `pt:set[...]` describes the type of its elements (called "sub-type") in square brackets. The sub-type of a `pt:set[...]` must be a `` (e.g. `pt:int`, `pt:bool`). - - In describing the format of types, `/` between two sub-types should be treated as "or". For example, the sub-type of a `pt:optional[...]` is either a ``, ``, ``, `` or ``. +A multi type denotes an "or" separated set of subtypes. For example, a content whose type is specified as `pt:union[pt:str, pt:int]` should either be `pt:int` or `pt:float`. -A multi type denotes an "or" separated set of sub-types. For example, a content whose type is specified as `pt:union[pt:str, pt:int]` should either be `pt:int` or `pt:float`. +An optional type `pt:optional[...]` assigned to a content means the content's existence is optional, but if it is present, its type must match `pt:optional[...]`'s subtype. -An optional type `pt:optional[...]` assigned to a content means the content's existence is optional, but if it is present, its type must match `pt:optional[...]`'s sub-type. - | Type | Code | Format | Example | In Python | -| ------------------------------------| --------| --------------------------------------------------------------|------------------------------------------|------------------------------------| +|-------------------------------------|---------|---------------------------------------------------------------|------------------------------------------|------------------------------------| | Custom types1 | `` | `ct:RegExp(^[A-Z][a-zA-Z0-9]*$)` | `ct:DataModel` | Custom Class | | Primitive types | `` | `pt:bytes` | `pt:bytes` | `bytes` | | | | `pt:int` | `pt:int` | `int` | @@ -163,29 +159,29 @@ You can optionally specify the structure of dialogues conforming to your protoco The allowed fields and what they represent are: - * `initiation`: The list of initial performatives - * `reply`: The reply structure of speech-acts - * `termination`: The list of terminal performatives - * `roles`: The roles of players participating in a dialogue - * `end_states`: The possible outcomes a terminated dialogue. - * `keep_terminal_state_dialogues`: whether to keep or drop a terminated dialogue. When a storage backend is configured, the dialogues will be persisted in storage when kept. +- `initiation`: The list of initial performatives +- `reply`: The reply structure of speech-acts +- `termination`: The list of terminal performatives +- `roles`: The roles of players participating in a dialogue +- `end_states`: The possible outcomes a terminated dialogue. +- `keep_terminal_state_dialogues`: whether to keep or drop a terminated dialogue. When a storage backend is configured, the dialogues will be persisted in storage when kept. -All of the above fields are mandatory. +All of the above fields are mandatory. -`initiation` is a YAML list, containing the performatives which can be used to start a dialogue. +`initiation` is a YAML list, containing the performatives which can be used to start a dialogue. -`reply` specifies for every performative, what its valid replies are. If a performative `per_1` is a valid reply to another `per_2`, this means a message with performative `per_1` can target a message whose performative is `per_2`. +`reply` specifies for every performative, what its valid replies are. If a performative `per_1` is a valid reply to another `per_2`, this means a message with performative `per_1` can target a message whose performative is `per_2`. -`reply` is a YAML dictionary, where the keys are the performatives (YAML string) defined in `speech-acts`. For each performative key, its value is a list of performatives which are defined to be a valid reply. +`reply` is a YAML dictionary, where the keys are the performatives (YAML string) defined in `speech-acts`. For each performative key, its value is a list of performatives which are defined to be a valid reply. For example, valid replies to `cfp` are `propose` and `decline`. `termination` is a YAML list, containing the performatives which terminate a dialogue. Once any of these performatives are used in a dialogue, the dialogue is terminated and no other messages may be added to it. `roles` is a YAML set, containing the roles players participating in dialogues can take. `roles` may contain one or two roles, each role being a YAML string. If there are two roles, each participant has a distinguished role in the dialogue (e.g. buyer and seller in the above specification). If there is only one role, then both participants in a dialogue have this same role. -`end_states` lists the final states a terminated dialogue may have. `end_states` is a YAML list of strings. +`end_states` lists the final states a terminated dialogue may have. `end_states` is a YAML list of strings. -`keep_terminal_state_dialogues` has a boolean value and specifies whether the terminated dialogues of this protocol are to be kept or discarded. +`keep_terminal_state_dialogues` has a boolean value and specifies whether the terminated dialogues of this protocol are to be kept or discarded. ## Design Guidelines @@ -195,20 +191,19 @@ For example, valid replies to `cfp` are `propose` and `decline`. 3. If a speech-act is listed in `termination`, it must not have any replies in `reply`. The reason is simple: a terminal speech-act terminates a dialogue and so its reply can never be used. -4. If a speech-act replies to no other speech-acts, it should be listed in `initiation` otherwise it could never be used in a dialogue (neither to a start a dialogue with, nor as a reply to another speech-act). +4. If a speech-act replies to no other speech-acts, it should be listed in `initiation` otherwise it could never be used in a dialogue (neither to a start a dialogue with, nor as a reply to another speech-act). ### Notes 1. Currently, there is no way to describe custom types in a programming language independent format. This means that if a protocol specification includes custom types, the required implementations must be provided manually. - * Before generating the protocol, the protocol buffer schema code for every custom type must be provided in the protocol specification. - * Once the generator is called, it produces a `custom_types` module containing stub implementations for every custom type in the specification. The user must then modify this module and add implementations for every custom type in the specification. This includes implementations of how an object of a custom type can be encoded and decoded using protocol buffer. - * Note, currently the way custom types are dealt with in the generator is admittedly inconvenient. The reason is, the generator does not know the structure of custom types and how they may be serialised/deserialised. Although this approach works, it is only a temporary solution until further work on a programming language-independent type description language is finished (similar to how the generator is designed to be a programming language-independent protocol description language). + _ Before generating the protocol, the protocol buffer schema code for every custom type must be provided in the protocol specification. + - Once the generator is called, it produces a `custom_types` module containing stub implementations for every custom type in the specification. The user must then modify this module and add implementations for every custom type in the specification. This includes implementations of how an object of a custom type can be encoded and decoded using protocol buffer. + - Note, currently the way custom types are dealt with in the generator is admittedly inconvenient. The reason is, the generator does not know the structure of custom types and how they may be serialized/deserialized. Although this approach works, it is only a temporary solution until further work on a programming language-independent type description language is finished (similar to how the generator is designed to be a programming language-independent protocol description language). 2. Currently, the first element in `pt:dict` cannot be a ``, `pt:float` or `pt:bytes`. This is because of a constraint in protocol buffer version 3 which is the framework's underlying serialisation mechanism. In a future version, we may address this limitation, in which case we will relax this constraint. 3. In protocol buffer version 3, which is the version used by the generator, there is no way to check whether an optional field (i.e. contents of type `pt:optional[...]`) has been set or not (see discussion here). In proto3, all optional fields are assigned a default value (e.g. `0` for integers types, `false` for boolean types, etc). Therefore, given an optional field whose value is the default value, there is no way to know from the optional field itself, whether it is not set, or in fact is set but its value happens to be the default value. Because of this, in the generated protocol schema file (the `.proto` file), for every optional content there is a second field that declares whether this field is set or not. We will maintain this temporary solution until a cleaner alternative is found. -4. Be aware that currently, using the generated protocols in python, there might be some rounding errors when serialising and then deserialising values of `pt:float` contents. - +4. Be aware that currently, using the generated protocols in python, there might be some rounding errors when serialising and then deserializing values of `pt:float` contents. -## Demo instructions +## Demo Instructions First, create a new AEA project: @@ -226,6 +221,3 @@ aea generate protocol ../examples/protocol_specification_ex/sample.yaml This will generate the protocol and place it in your AEA project. Third, try generating other protocols by first defining a specification, then running the generator. - - -
diff --git a/docs/protocol.md b/docs/protocol.md index 67a3f3c337..c146e8bb2c 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -1,12 +1,12 @@ -`Protocols` define the structure of agent-to-agent and component-to-component interactions, which in the AEA world, are in the form of communication. To learn more about interactions and interaction protocols, see here. +# Protocols -Protocols in the AEA world provide definitions for: - -* `messages` defining the structure and syntax of messages; +`Protocols` define the structure of agent-to-agent and component-to-component interactions, which in the AEA world, are in the form of communication. To learn more about interactions and interaction protocols, see here. -* `serialization` defining how a message is encoded/decoded for transport; and optionally +Protocols in the AEA world provide definitions for: -* `dialogues` defining the structure of dialogues formed from exchanging series of messages. +- `messages` defining the structure and syntax of messages; +- `serialization` defining how a message is encoded/decoded for transport; and optionally +- `dialogues` defining the structure of dialogues formed from exchanging series of messages. Protocol simplified @@ -16,62 +16,54 @@ Additional protocols - i.e. a new type of interaction - can be added as packages We highly recommend you to **not** attempt writing your protocol manually as they tend to have involved logic; always use existing packages or the protocol generator! -## Components of a protocol +## Components of a Protocol A protocol package contains the following files: -* `__init__.py` -* `message.py`, which defines message representation -* `serialization.py`, which defines the encoding and decoding logic -* two protobuf related files +- `__init__.py` +- `message.py`, which defines message representation +- `serialization.py`, which defines the encoding and decoding logic +- two protobuf related files It optionally also contains -* `dialogues.py`, which defines the structure of dialogues formed from the exchange of a series of messages -* `custom_types.py`, which defines custom types +- `dialogues.py`, which defines the structure of dialogues formed from the exchange of a series of messages +- `custom_types.py`, which defines custom types All protocols are for point to point interactions between two agents or agent-like services. - - ## Metadata Each `Message` in an interaction protocol has a set of default fields: -* `dialogue_reference: Tuple[str, str]`, a reference of the dialogue the message is part of. The first part of the tuple is the reference assigned to by the agent who first initiates the dialogue (i.e. sends the first message). The second part of the tuple is the reference assigned to by the other agent. The default value is `("", "")`. -* `message_id: int`, the identifier of the message in a dialogue. The default value is `1`. -* `target: int`, the id of the message this message is replying to. The default value is `0`. -* `performative: Enum`, the purpose/intention of the message. -* `sender: Address`, the address of the sender of this message. -* `to: Address`, the address of the receiver of this message. +- `dialogue_reference: Tuple[str, str]`, a reference of the dialogue the message is part of. The first part of the tuple is the reference assigned to by the agent who first initiates the dialogue (i.e. sends the first message). The second part of the tuple is the reference assigned to by the other agent. The default value is `("", "")`. +- `message_id: int`, the identifier of the message in a dialogue. The default value is `1`. +- `target: int`, the id of the message this message is replying to. The default value is `0`. +- `performative: Enum`, the purpose/intention of the message. +- `sender: Address`, the address of the sender of this message. +- `to: Address`, the address of the receiver of this message. The default values for `message_id` and `target` assume the message is the first message in a dialogue. Therefore, the `message_id` is set to `1` indicating the first message in the dialogue and `target` is `0` since the first message is the only message that does not reply to any other. -By default, the values of `dialogue_reference`, `message_id`, `target` are set. However, most interactions involve more than one message being sent as part of the interaction and potentially multiple simultaneous interactions utilising the same protocol. In those cases, the `dialogue_reference` allows different interactions to be identified as such. The `message_id` and `target` are used to keep track of messages and their replies. For instance, on receiving of a message with `message_id=1` and `target=0`, the responding agent could respond with another with `message_id=2` and `target=1` replying to the first message. In particular, `target` holds the id of the message being replied to. This can be the preceding message, or an older one. +By default, the values of `dialogue_reference`, `message_id`, `target` are set. However, most interactions involve more than one message being sent as part of the interaction and potentially multiple simultaneous interactions utilising the same protocol. In those cases, the `dialogue_reference` allows different interactions to be identified as such. The `message_id` and `target` are used to keep track of messages and their replies. For instance, on receiving of a message with `message_id=1` and `target=0`, the responding agent could respond with another with `message_id=2` and `target=1` replying to the first message. In particular, `target` holds the id of the message being replied to. This can be the preceding message, or an older one. ## Contents -Each message may optionally have any number of contents of varying types. +Each message may optionally have any number of contents of varying types. -## Dialogue rules +## Dialogue Rules Protocols can optionally have a dialogue module. A _dialogue_, respectively _dialogues_ object, maintains the state of a single, respectively, all dialogues associated with a protocol. The framework provides a number of helpful classes which implement most of the logic to maintain dialogues, namely the `Dialogue` and `Dialogues` base classes. -## Custom protocol +## Custom Protocol The developer can generate custom protocols with the protocol generator. This lets the developer specify the speech-acts as well as optionally the dialogue structure (e.g. roles of agents participating in a dialogue, the states a dialogue may end in, and the reply structure of the speech-acts in a dialogue). We highly recommend you **do not** attempt to write your own protocol code; always use existing packages or the protocol generator! -## `fetchai/default:1.1.6` protocol +## `fetchai/default:1.1.6` Protocol The `fetchai/default:1.1.6` protocol is meant to be implemented by every AEA. It serves AEA to AEA interaction and includes three message performatives: @@ -90,7 +82,8 @@ class Performative(Enum): return self.value ``` -* The `DefaultMessage` of performative `DefaultMessage.Performative.BYTES` is used to send payloads of byte strings to other AEAs. An example is: +- The `DefaultMessage` of performative `DefaultMessage.Performative.BYTES` is used to send payloads of byte strings to other AEAs. An example is: + ``` python from packages.fetchai.protocols.default.message import DefaultMessage @@ -100,7 +93,8 @@ msg = DefaultMessage( ) ``` -* The `DefaultMessage` of performative `DefaultMessage.Performative.ERROR` is used to notify other AEAs of errors in an interaction, including errors with other protocols, by including an `error_code` in the payload: +- The `DefaultMessage` of performative `DefaultMessage.Performative.ERROR` is used to notify other AEAs of errors in an interaction, including errors with other protocols, by including an `error_code` in the payload: + ``` python class ErrorCode(Enum): """This class represents an instance of ErrorCode.""" @@ -111,7 +105,9 @@ class ErrorCode(Enum): UNSUPPORTED_SKILL = 3 INVALID_DIALOGUE = 4 ``` + An example is: + ``` python msg = DefaultMessage( performative=DefaultMessage.Performative.ERROR, @@ -121,7 +117,8 @@ msg = DefaultMessage( ) ``` -* The `DefaultMessage` of performative `DefaultMessage.Performative.END` is used to terminate a default protocol dialogue. An example is: +- The `DefaultMessage` of performative `DefaultMessage.Performative.END` is used to terminate a default protocol dialogue. An example is: + ``` python from packages.fetchai.protocols.default.message import DefaultMessage @@ -132,7 +129,7 @@ msg = DefaultMessage( Each AEA's `fetchai/error:0.18.5` skill utilises the `fetchai/default:1.0.0` protocol for error handling. -## `fetchai/oef_search:1.1.6` protocol +## `fetchai/oef_search:1.1.6` Protocol The `fetchai/oef_search:1.1.6` protocol is used by AEAs to interact with an SOEF search node to register and unregister their own services and search for services registered by other agents. @@ -156,11 +153,14 @@ class Performative(Enum): We show some example messages below: -* To register a service, we require a reference to the dialogue in string form (used to keep different dialogues apart), for instance +- To register a service, we require a reference to the dialogue in string form (used to keep different dialogues apart), for instance + ``` python my_dialogue_reference = "a_unique_register_service_dialogue_reference" ``` + and a description of the service we would like to register, for instance + ``` python from aea.helpers.search.models import Description @@ -170,7 +170,9 @@ my_service_description = Description( data_model=my_data_model, ) ``` + where we use, for instance + ``` python from aea.helpers.search.generic import GenericDataModel @@ -189,7 +191,9 @@ data_model = { } my_data_model = GenericDataModel(data_model_name, data_model) ``` + We can then create the message to register this service: + ``` python msg = OefSearchMessage( performative=OefSearchMessage.Performative.REGISTER_SERVICE, @@ -198,11 +202,14 @@ msg = OefSearchMessage( ) ``` -* To unregister a service, we require a reference to the dialogue in string form, for instance +- To unregister a service, we require a reference to the dialogue in string form, for instance + ``` python my_dialogue_reference = "a_unique_unregister_service_dialogue_reference" ``` + the description of the service we would like to unregister, say `my_service_description` from above and construct the message: + ``` python msg = OefSearchMessage( performative=OefSearchMessage.Performative.UNREGISTER_SERVICE, @@ -211,7 +218,8 @@ msg = OefSearchMessage( ) ``` -* To search a service, we similarly require a reference to the dialogue in string form, and then the query we would like the search node to evaluate, for instance +- To search a service, we similarly require a reference to the dialogue in string form, and then the query we would like the search node to evaluate, for instance + ``` python from aea.helpers.search.models import Constraint, ConstraintType, Query @@ -233,7 +241,9 @@ query = Query( model=None, ) ``` + We can then create the message to search these services: + ``` python oef_msg = OefSearchMessage( performative=OefSearchMessage.Performative.SEARCH_SERVICES, @@ -242,9 +252,10 @@ oef_msg = OefSearchMessage( ) ``` -* The SOEF search node will respond with a message `msg` of type `OefSearchMessage` with performative `OefSearchMessage.Performative.SEARCH_RESULT`. To access the tuple of agents which match the query, simply use `msg.agents`. In particular, this will return the agent addresses matching the query. The agent address can then be used to send a message to the agent utilising the P2P agent communication network and any protocol other than `fetchai/oef_search:1.0.0`. +- The SOEF search node will respond with a message `msg` of type `OefSearchMessage` with performative `OefSearchMessage.Performative.SEARCH_RESULT`. To access the tuple of agents which match the query, simply use `msg.agents`. In particular, this will return the agent addresses matching the query. The agent address can then be used to send a message to the agent utilising the P2P agent communication network and any protocol other than `fetchai/oef_search:1.0.0`. + +- If the SOEF search node encounters any errors with the messages you send, it will return an `OefSearchMessage` of performative `OefSearchMessage.Performative.OEF_ERROR` and indicate the error operation encountered: -* If the SOEF search node encounters any errors with the messages you send, it will return an `OefSearchMessage` of performative `OefSearchMessage.Performative.OEF_ERROR` and indicate the error operation encountered: ``` python class OefErrorOperation(Enum): @@ -257,7 +268,7 @@ class OefErrorOperation(Enum): OTHER = 10000 ``` -## `fetchai/fipa:1.1.6` protocol +## `fetchai/fipa:1.1.6` Protocol This protocol provides classes and functions necessary for communication between AEAs via a variant of the FIPA Agent Communication Language. @@ -299,12 +310,12 @@ The `fetchai/fipa:1.1.6` protocol also defines a `FipaDialogue` class which spec For examples of the usage of the `fetchai/fipa:1.1.6` protocol check out the generic skills step by step guide. - -### Fipa dialogue +### Fipa Dialogue Below, we give an example of a dialogue between two agents. In practice; both dialogues would be maintained in the respective agent. We first create concrete implementations of `FipaDialogue` and `FipaDialogues` for the buyer and seller: + ``` python from aea.common import Address from aea.helpers.search.models import Constraint, ConstraintType, Description, Query @@ -432,6 +443,7 @@ class SellerDialogues(FipaDialogues): ``` Next, we can imitate a dialogue between the buyer and the seller. We first instantiate the dialogues models: + ``` python buyer_address = "buyer_address_stub" seller_address = "seller_address_stub" @@ -440,6 +452,7 @@ seller_dialogues = SellerDialogues(seller_address) ``` First, the buyer creates a message destined for the seller and updates the dialogues: + ``` python cfp_msg = FipaMessage( message_id=1, @@ -453,29 +466,35 @@ cfp_msg.counterparty = seller_addr # Extends the outgoing list of messages. buyer_dialogue = buyer_dialogues.update(cfp_msg) ``` + If the message has been correctly constructed, the `buyer_dialogue` will be returned, otherwise it will be `None`. In a skill, the message could now be sent: + ``` python # In a skill we would do: # self.context.outbox.put_message(message=cfp_msg) ``` However, here we simply continue with the seller: + ``` python # change the incoming message field & counterparty cfp_msg.is_incoming = True cfp_msg.counterparty = buyer_address ``` + In the skill, the above two lines will be done by the framework; you can simply receive the message in the handler. We update the seller's dialogues model next to generate a new dialogue: + ``` python # Creates a new dialogue for the seller side based on the income message. seller_dialogue = seller_dialogues.update(cfp_msg) ``` Next, the seller can generate a proposal: + ``` python # Generate a proposal message to send to the buyer. proposal = Description({"foo1": 1, "bar1": 2}) @@ -495,6 +514,7 @@ seller_dialogue.update(proposal_msg) ``` In a skill, the message could now be sent: + ``` python # In a skill we would do: # self.context.outbox.put_message(message=proposal_msg) @@ -507,6 +527,3 @@ To retrieve a dialogue for a given message, we can do the following: ``` python retrieved_dialogue = seller_dialogues.get_dialogue(cfp_msg) ``` - - -
\ No newline at end of file diff --git a/docs/query-language.md b/docs/query-language.md index f68e412c57..0214d5a1d3 100644 --- a/docs/query-language.md +++ b/docs/query-language.md @@ -1,3 +1,5 @@ +# The Query Language + We recommend reading Defining a Data Model before reading this section. Along with the Data Model language, the AEA framework offers the possibility to specify _queries_ defined over data models. @@ -17,22 +19,22 @@ That is, it imposes some limitations on the values the attribute can assume. We have different types of constraints: -* _relation_ constraints: +- _relation_ constraints: - * the author of the book must be _Stephen King_ - * the publication year must be greater than 1990 + - the author of the book must be _Stephen King_ + - the publication year must be greater than 1990 -* _set_ constraints: +- _set_ constraints: - * the genre must fall into the following set of genres: _Horror_, _Science fiction_, _Non-fiction_. + - the genre must fall into the following set of genres: _Horror_, _Science fiction_, _Non-fiction_. -* _range_ constraints: +- _range_ constraints: - * the average rating must be between 3.5 and 4.5 + - the average rating must be between 3.5 and 4.5 -* _distance_ constraints: +- _distance_ constraints: - * the nearest bookshop must be within a distance from a given location. + - the nearest bookshop must be within a distance from a given location. The class that implements the constraint concept is `Constraint` In the following, we show how to define them. @@ -43,14 +45,14 @@ There are several The types of relation constraints are: -* Equal: `==` -* Not Equal: `!=` -* Less than: `<` -* Less than or Equal: `<=` -* Greater than: `>` -* Greater than or Equal: `>=` +- Equal: `==` +- Not Equal: `!=` +- Less than: `<` +- Less than or Equal: `<=` +- Greater than: `>` +- Greater than or Equal: `>=` -**Examples**: using the attributes we used before: +**Examples**: using the attributes we used before: ``` python from aea.helpers.search.models import Constraint, ConstraintType @@ -80,9 +82,8 @@ The _set_ is a constraint type that allows you to restrict the values of the att There are two kind of _set_ constraints: -* In (a set of values): `in` -* Not in (a set of values): `not_in` - +- In (a set of values): `in` +- Not in (a set of values): `not_in` **Examples**: @@ -100,7 +101,6 @@ Constraint("year", ConstraintType("not_in", (1990, 1995, 2000))) The _range_ is a constraint type that allows you to restrict the values of the attribute in a given range. - **Examples**: ``` python @@ -139,12 +139,12 @@ close_to_tour_eiffel.check(Description({"position": colosseum})) # gives `False ## Constraint Expressions -The constraints above mentioned can be combined with the common logical operators (i.e. and, or and not), yielding more complex expression. +The constraints mentioned above can be combined with the common logical operators (i.e. and, or and not), yielding more complex expression. -In particular we can specify any conjunction/disjunction/negations of the previous constraints or composite `ConstraintExpressions`, e.g.: +In particular, we can specify any conjunction/disjunction/negations of the previous constraints or composite `ConstraintExpressions`, e.g.: -* books that belong to _Horror_ **and** has been published after 2000, but **not** published by _Stephen King_. -* books whose author is **either** _J. K. Rowling_ **or** _J. R. R. Tolkien_ +- books that belong to _Horror_ **and** has been published after 2000, but **not** published by _Stephen King_. +- books whose author is **either** _J. K. Rowling_ **or** _J. R. R. Tolkien_ The classes that implement these operators are `Not`, `And` and `Or`. @@ -211,7 +211,7 @@ Query([ Where `book_model` is the `DataModel` object. However, the data model is an optional parameter, but to avoid ambiguity is recommended to include it. -### The ``check`` method +### The ``check`` Method The `Query` class supports a way to check whether a `Description` matches with the query. This method is called `Query.check`. @@ -241,11 +241,10 @@ A `Query` object must satisfy some conditions in order to be instantiated. - For every constraint expression that constitute the query, check if they are _valid with respect to the data model_. - A `ConstraintExpr` `c` (that is, one of `And`, `Or`, `Not`, `Constraint`) is _valid with respect to a_ `DataModel` if: - If `c` is an instance of `And`, `Or` or `Not`, then - every subexpression of `c` must be valid (with respect to to the data model); + every subexpression of `c` must be valid (with respect to the data model); - If `c` is an instance of `Constraint`, then: - if the constraint type is one of `<`, `<=`, `>`, `>=`, the value in the constructor must be one of `str`, `int` or `float`. @@ -263,4 +262,3 @@ Constraint("foo", ConstraintType("==", True)) ``` Consider a `DataModel` where there is an `Attribute` `"foo"` of type `str`. Then the constraint is not compatible with the mentioned data model, because the constraint expect an equality comparison with a boolean `True`, instead of a `str`. - diff --git a/docs/questions-and-answers.md b/docs/questions-and-answers.md index aa1c7643a0..db0487802f 100644 --- a/docs/questions-and-answers.md +++ b/docs/questions-and-answers.md @@ -1,55 +1,46 @@ -
What is an AEA? -AEA stands for "Autonomous Economic Agent". An AEA can represent an individual, organisation or object and looks after its owner's interests. AEAs act independently of constant user input and autonomously execute actions to achieve their prescribed goals. Their purpose is to create economic value for their owners. -
- -
How do AEAs talk to each other when they do not know each other? -For an Autonomous Economic Agent (AEA) to talk to other AEAs, it first needs to find them. Once it does, it should ensure that they both use the same protocol for communication, and if so, they then have to send messages to each other. -

-The AEA framework, together with some of the services it provides, address all three problems. You can read more about search and discovery here, protocols here, and the Agent Communication Network (ACN) here. -
- -
How does an AEA use blockchain? -The AEA framework enables agents to interact with blockchains to settle transactions. Currently, the framework has native support for three different networks: Fetch.ai, Ethereum and Cosmos. -

-You can read more about the framework's integration with the different blockchains here and gain a high level overview here. -
- -
How does one install third party libraries? -The framework supports the use of third-party libraries hosted on PyPI. You can directly reference the external dependencies of an AEA package (e.g. skill) in its configuration file. From inside an AEA's project directory, the install command can be used to install all the dependencies of the AEA listed in the configuration files of any of it's packages. -
- -
How does one connect to a database? -You have two options to connect to a database: using the built-in storage solution or using a custom ORM (object-relational mapping) library and backend. -

-The use of the built-in storage is explained here. For a detailed example of how to use an ORM, follow the ORM guide. -
- -
How does one connect a frontend? -There are multiple options. The most obvious is using an HTTP server connection and creating a client that communicates with this connection. -

-You can find a more detailed discussion here. -
- -
Is the AEA framework ideal for agent-based modelling? -The goal of agent-based modelling (ABM) is to study the unknown (often complex) behaviour of systems comprised of agents with known (much simpler) behaviour. ABM is a popular technique for studying biological and social systems. Despite some similarities between ABM and the AEA framework, the two have fundamentally different goals. ABM's goal is not the design of agents or solving specific practical or engineering problems. Although it would be potentially possible, it would likely be inefficient to use the AEA framework for that kind of problem. -

-You can find more details on the application areas of the AEA framework here. -
- -
When a new AEA is created, is the vendor folder populated with some default packages? -All AEA projects by default hold the fetchai/default:1.1.6, fetchai/state_update:1.1.6 and fetchai/signing:1.1.6 protocols. These (as all other packages installed from the registry) are placed in the vendor folder. -

-You can find more details about the file structure here. -
- -
Is there a standardization for private key files? -Currently, the private keys are stored in .txt files. This is temporary and will be improved soon. -
- -
How to use the same protocol in different skills? -The details of envelope/message routing by the AEA framework are discussed in this guide. -
- -
Why does the AEA framework use its own package registry? -AEA packages could be described as personalized plugins for the AEA runtime. They are not like a library - they have no direct use outside the context of the framework - and therefore are not suitable for distribution via PyPI. -
+# Q&A + +??? question "What is an AEA?" + AEA stands for "Autonomous Economic Agent". An AEA can represent an individual, organisation or object and looks after its owner's interests. AEAs act independently of constant user input and autonomously execute actions to achieve their prescribed goals. Their purpose is to create economic value for their owners. + +??? question "How do AEAs talk to each other when they do not know each other?" + For an Autonomous Economic Agent (AEA) to talk to other AEAs, it first needs to find them. Once it does, it should ensure that they both use the same protocol for communication, and if so, they then have to send messages to each other. + + The AEA framework, together with some of the services it provides, address all three problems. You can read more about search and discovery here, protocols here, and the Agent Communication Network (ACN) here. + +??? question "How does an AEA use blockchain?" + The AEA framework enables agents to interact with blockchains to settle transactions. Currently, the framework has native support for three different networks: _Fetch.ai_, _Ethereum_ and _Cosmos_. + + You can read more about the framework's integration with the different blockchains here and gain a high level overview here. + +??? question "How does one install third party libraries?" + The framework supports the use of third-party libraries hosted on PyPI. You can directly reference the external dependencies of an AEA package (e.g. skill) in its configuration file. From inside an AEA's project directory, the `install` command can be used to install all the dependencies of the AEA which are listed in the configuration files belonging to any of its packages. + +??? question "How does one connect to a database?" + You have two options to connect to a database: using the built-in storage solution or using a custom ORM (object-relational mapping) library and backend. + + The use of the built-in storage is explained here. For a detailed example of how to use an ORM, follow the ORM guide. + +??? question "How does one connect a frontend?" + There are multiple options. The most obvious is using an HTTP server connection and creating a client that communicates with this connection. + + You can find a more detailed discussion here. + +??? question "Is the AEA framework ideal for agent-based modelling?" + The goal of agent-based modelling (ABM) is to study the unknown (often complex) behaviour of systems comprised of agents with known (much simpler) behaviour. ABM is a popular technique for studying biological and social systems. Despite some similarities between ABM and the AEA framework, the two have fundamentally different goals. ABM's goal is not the design of agents or solving specific practical or engineering problems. Although it would be potentially possible, it would likely be inefficient to use the AEA framework for that kind of problems. + + You can find more details on the application areas of the AEA framework here. + +??? question "When a new AEA is created, is the `vendor` folder populated with some default packages?" + All AEA projects by default hold the `fetchai/default:1.1.6`, `fetchai/state_update:1.1.6` and `fetchai/signing:1.1.6` protocols. These (as all other packages installed from the registry) are placed in the `vendor` folder. + + You can find more details about the file structure here. + +??? question "Is there a standardization for private key files?" + Currently, the private keys are stored in `.txt` files. This is temporary and will be improved soon. + +??? question "How to use the same protocol in different skills?" + The details of envelope/message routing by the AEA framework are discussed in this guide. + +??? question "Why does the AEA framework use its own package registry?" + AEA packages could be described as personalized plugins for the AEA runtime. They are not like a library - they have no direct use outside the context of the framework - and therefore are not suitable for distribution via PyPI. diff --git a/docs/quickstart.md b/docs/quickstart.md index 4931a1cfac..0e1bdf9c05 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,3 +1,5 @@ +# AEA Quick Start + If you want to create Autonomous Economic Agents (AEAs) that can act independently of constant user input and autonomously execute actions to achieve their objective, you can use the AEA framework. @@ -10,94 +12,80 @@ The AEA framework can be used on `Windows`, `Ubuntu/Debian` and `MacOS`. You need Python 3.6 or higher as well as Go 1.14.2 or higher installed. -​GCC installation is required: -* Ubuntu: `apt-get install gcc` -* Windows (with `choco` +GCC installation is required: + +- Ubuntu: `apt-get install gcc` +- Windows (with `choco` installed): `choco install mingw` -* MacOS X (with home brew): `brew install gcc` +- MacOS X (with home brew): `brew install gcc` -### Option 1: Manual system preparation +### Option 1: Manual System Preparation Install a compatible Python and Go version on your system (see this external resource for a comprehensive guide). -
Manual approach +??? note "Manual approach:" -The following hints can help: + The following hints can help: + + - To install Go, follow the official guide, depending on your platform here + - Python is already included by default on many Linux distributions (e.g. Ubuntu), as well as MacOS. To check you have the right version, open a terminal and run: -
    -
  • To install Go, follow the official guide, depending on your platform here
  • + ``` bash + python3 --version + ``` -
  • Python is already included by default on -many Linux distributions (e.g. Ubuntu), as well as MacOS. -To check you have the right version, open a terminal and run: -``` bash -python3 --version -``` -
  • + - To install Python on Windows machines, you can download a specific release here. + - Ubuntu/Debian systems only: install Python headers, depending on the Python version you have installed on your machine. E.g. for Python 3.7: -
  • To install Python on Windows machines, you can download a specific release here.
  • + ``` bash + sudo apt-get install python3.7-dev + ``` -
  • Ubuntu/Debian systems only: install Python headers, - depending on the Python version you have installed on your machine. - E.g. for Python 3.7: -``` bash -sudo apt-get install python3.7-dev -``` -
  • - -
  • Windows users: install tools for Visual Studio.
  • -
+ - Windows users: install tools for Visual Studio. -
- -### Option 2: Using an automated install script +### Option 2: Using an 'Automated Install' Script We provide a script to automatically install all framework dependencies and the framework itself. This means that if you follow this option, you can skip the installation step that comes later on this page. -
Automated install script approach +??? note "The 'Automated install' script approach:" + On macOS or Ubuntu run the following commands to download and install: -On MacOS or Ubuntu run the following commands to download and install: + ``` bash + curl https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.sh --output install.sh + chmod +x install.sh + ./install.sh + ``` -``` bash -curl https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.sh --output install.sh -chmod +x install.sh -./install.sh -``` - -On Windows: download https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.ps1, then run install.ps1 with the PowerShell terminal. - -
+ On Windows: download https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.ps1, then run install.ps1 with the PowerShell terminal. ### Option 3: Using Docker + ​ We also provide a Docker image with all the needed dependencies. -
Docker approach - -To use the image you will first have to pull it and than run it with your current local directory mounted as a docker volume. This allows you to keep your agents local while working on them from within the docker container. - -To pull: - -``` bash -docker pull fetchai/aea-user:latest -``` +??? note "Docker approach:" + To use the image, you will first have to pull it, then run it with your current local directory mounted as a docker volume. This allows you to keep your agents local while working on them from within the docker container. -To run the image on Linux and MacOs: + To pull: -``` bash -docker run -it -v $(pwd):/agents --workdir=/agents fetchai/aea-user:latest -``` + ``` bash + docker pull fetchai/aea-user:latest + ``` + + To run the image on Linux and MacOs: -And on Windows: + ``` bash + docker run -it -v $(pwd):/agents --workdir=/agents fetchai/aea-user:latest + ``` -``` bash -docker run -it -v %cd%:/agents --workdir=/agents fetchai/aea-user:latest -``` + And on Windows: -Once successfully logged into the docker container, -you can follow the rest of the guide the same way as if not using docker. -​ -
+ ``` bash + docker run -it -v %cd%:/agents --workdir=/agents fetchai/aea-user:latest + ``` + + Once successfully logged into the docker container, + you can follow the rest of the guide the same way as if not using docker. ## Preliminaries @@ -125,32 +113,34 @@ Once installed, create a new environment and open it (here we use Python 3.7 but touch Pipfile && pipenv --python 3.7 && pipenv shell ``` - ## Installation -The following installs the entire AEA package which also includes a command-line interface (CLI). (You can skip this step if you used the install script above: Option 2 .) +The following installs the entire AEA package which also includes a command-line interface (CLI). (You can skip this step if you used the 'install script' above: Option 2 .) ``` bash pip install aea[all] ``` If you are using `zsh` rather than `bash` type + ``` zsh pip install 'aea[all]' ``` If the installation steps fail, it might be a dependency issue. Make sure you have followed all the relevant system specific steps above under `System Requirements`. -## Setup author name +## Setup Author Name You can set up your author name using the `init` command: + ``` bash aea init ``` -## Register as an AEA author (optional) +## Register as an AEA Author (optional) + +AEAs are composed of components. AEAs and AEA components can be developed by anyone and pushed to the AEA registry for others to use. To publish packages to the registry, we need to register an author name: -AEAs are composed from components. AEAs and AEA components can be developed by anyone and pushed to the AEA registry for others to use. To publish packages to the registry, we need to register an author name: ``` bash aea register ``` @@ -158,6 +148,7 @@ aea register This is your unique author (or developer) name in the AEA ecosystem. You should see a similar output (with your input instead of the sample username and email): + ``` bash Do you have a Registry account? [y/N]: n Create a new account on the Registry now: @@ -177,14 +168,12 @@ v1.2.4 AEA configurations successfully initialized: {'author': 'fetchai'} ``` -
-

Note

-

If you would rather not create an account on the registry at this point, then run aea init --local instead.

-
+!!! note + If you would rather not create an account on the registry at this point, then run `aea init --local` instead. -## Echo skill demo +## Echo Skill Demo -This is a simple demo that introduces you to the main components of an AEA. +This is a simple demo that introduces you to the main components of an AEA. The fastest way to have your first AEA is to fetch one that already exists! @@ -195,43 +184,45 @@ cd my_first_aea To learn more about the folder structure of an AEA project read on here. -
Alternatively: step by step install +??? note "Alternatively: step by step install:" + **Create a new AEA** - Create a new AEA -
-First, create a new AEA project and enter it. -``` bash -aea create my_first_aea -cd my_first_aea -``` -
-Add the stub connection -
-Second, add the stub connection to the project. -``` bash -aea add connection fetchai/stub:0.21.2 -``` -
-Add the echo skill -
-Third, add the echo skill to the project. -``` bash -aea add skill fetchai/echo:0.20.5 -``` -This copies the fetchai/echo:0.20.5 skill code containing the "behaviours", and "handlers" into the project, ready to run. The identifier of the skill fetchai/echo:0.20.5 consists of the name of the author of the skill, followed by the skill name and its version. -
+ First, create a new AEA project and enter it. + + ``` bash + aea create my_first_aea + cd my_first_aea + ``` + + **Add the stub connection** + + Second, add the stub connection to the project. + + ``` bash + aea add connection fetchai/stub:0.21.2 + ``` + + **Add the echo skill** + + Third, add the echo skill to the project. + + ``` bash + aea add skill fetchai/echo:0.20.5 + ``` + + This copies the fetchai/echo:0.20.5 skill code containing the "behaviours", and "handlers" into the project, ready to run. The identifier of the skill fetchai/echo:0.20.5 consists of the name of the author of the skill, followed by the skill name and its version. -### Echo skill +### Echo Skill Just like humans, AEAs can have _skills_ to achieve their tasks. As an agent developer, you can create skills to add to your own AEAs. You can also choose to publish your skills so others add them to their AEAs. More details on skills can be found on this page . The above agent has an echo skill, fetched from the registry, which simply echoes any messages it receives back to its sender. -### Communication via envelopes and messages +### Communication via Envelopes and Messages AEAs use envelopes containing messages for communication. To learn more, check out the next section. -### Stub connection +### Stub Connection Besides skills, AEAs may have one or more _connections_ enabling them to interface with entities in the outside world. For example, an HTTP client connection allows an AEA to communicate with HTTP servers. To read more about connections see this page. @@ -253,13 +244,13 @@ For example: recipient_aea,sender_aea,fetchai/default:1.0.0,\x08\x01\x12\x011*\x07\n\x05hello, ``` -### Install AEA dependencies +### Install AEA Dependencies ``` bash aea install ``` -### Add and create a private key +### Add and Create a Private Key All AEAs need a private key to run. Add one now: @@ -299,7 +290,7 @@ info: Echo Behaviour: act method called. The framework first calls the `setup` methods in the skill's `Handler` and `Behaviour` classes in that order; after which it repeatedly calls the `act` method of `Behaviour` class. This is the main agent loop in action. -#### Add a message to the input file +#### Add a Message to the Input File You can send the AEA a message wrapped in an envelope using the CLI's `interact` command. @@ -310,7 +301,7 @@ cd my_first_aea aea interact ``` -You can now send messages to this AEA via an interactive tool by typing anything into the prompt and hitting enter twice (once to send the message and once more to check for a response). +You can now send messages to this AEA via an interactive tool by typing anything into the prompt and hitting enter twice (once to send the message and once more to check for a response). Let us send `hello` to this AEA (type `hello` and press enter twice). In the original terminal, you will see the `Echo Handler` dealing with this envelope and its contained message. You should see an output similar to the one below but with a different `dialogue_reference`. @@ -321,26 +312,23 @@ info: Echo Behaviour: act method called. info: Echo Behaviour: act method called. ``` -
Manual approach +??? note "Manual approach:" + Optionally, from a different terminal and same directory (i.e. the `my_first_aea` project), you can send the AEA a message wrapped in an envelope via the input file. -Optionally, from a different terminal and same directory (i.e. the my_first_aea project), you can send the AEA a message wrapped in an envelope via the input file. - -``` bash -echo 'my_first_aea,sender_aea,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello,' >> input_file -``` - -You will see the Echo Handler dealing with the envelope and responding with the same message to the output_file, and also decoding the Base64 encrypted message in this case. - -``` bash -info: Echo Behaviour: act method called. -Echo Handler: message=Message(sender=sender_aea,to=my_first_aea,content=b'hello',dialogue_reference=('1', ''),message_id=1,performative=bytes,target=0), sender=sender_aea -info: Echo Behaviour: act method called. -info: Echo Behaviour: act method called. -``` + ``` bash + echo 'my_first_aea,sender_aea,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello,' >> input_file + ``` -Note, due to the dialogue reference having to be incremented, you can only send the above envelope once! This approach does not work in conjunction with the aea interact command. + You will see the Echo Handler dealing with the envelope and responding with the same message to the output_file, and also decoding the Base64 encrypted message in this case. -
+ ``` bash + info: Echo Behaviour: act method called. + Echo Handler: message=Message(sender=sender_aea,to=my_first_aea,content=b'hello',dialogue_reference=('1', ''),message_id=1,performative=bytes,target=0), sender=sender_aea + info: Echo Behaviour: act method called. + info: Echo Behaviour: act method called. + ``` + + Note, due to the dialogue reference having to be incremented, you can only send the above envelope once! This approach does not work in conjunction with the aea interact command. ### Stop the AEA @@ -357,103 +345,100 @@ info: Echo Handler: teardown method called. info: Echo Behaviour: teardown method called. ``` -### Write a test for the AEA +### Write a Test for the AEA We can write an end-to-end test for the AEA utilising helper classes provided by the framework. -
Writing tests - -The following test class replicates the preceding demo and tests it's correct behaviour. The AEATestCase classes are a tool for AEA developers to write useful end-to-end tests of their AEAs. - -First, get the packages directory from the AEA repository (execute from the working directory which contains the my_first_aea folder): - -``` bash -svn export https://github.com/fetchai/agents-aea.git/trunk/packages -``` - -Then write the test: - -``` python -import signal -import time - -from aea.common import Address -from aea.mail.base import Envelope -from aea.protocols.base import Message -from aea.protocols.dialogue.base import Dialogue - -from packages.fetchai.protocols.default.dialogues import DefaultDialogue, DefaultDialogues -from packages.fetchai.protocols.default.message import DefaultMessage -from packages.fetchai.protocols.default.serialization import DefaultSerializer -from aea.test_tools.test_cases import AEATestCase - - -class TestEchoSkill(AEATestCase): - """Test that echo skill works.""" - - def test_echo(self): - """Run the echo skill sequence.""" - process = self.run_agent() - is_running = self.is_running(process) - assert is_running, "AEA not running within timeout!" - - # add sending and receiving envelope from input/output files - sender_aea = "sender_aea" - def role_from_first_message( - message: Message, receiver_address: Address - ) -> Dialogue.Role: - return DefaultDialogue.Role.AGENT - dialogues = DefaultDialogues(sender_aea, role_from_first_message) - message_content = b"hello" - message = DefaultMessage( - performative=DefaultMessage.Performative.BYTES, - dialogue_reference=dialogues.new_self_initiated_dialogue_reference(), - content=message_content, - ) - sent_envelope = Envelope( - to=self.agent_name, - sender=sender_aea, - protocol_id=message.protocol_id, - message=DefaultSerializer().encode(message), - ) - - self.send_envelope_to_agent(sent_envelope, self.agent_name) - - time.sleep(2.0) - received_envelope = self.read_envelope_from_agent(self.agent_name) - - assert sent_envelope.to == received_envelope.sender - assert sent_envelope.sender == received_envelope.to - assert sent_envelope.protocol_id == received_envelope.protocol_id - received_message = DefaultMessage.serializer.decode(received_envelope.message) - assert message.content == received_message.content - - check_strings = ( - "Echo Handler: setup method called.", - "Echo Behaviour: setup method called.", - "Echo Behaviour: act method called.", - "content={}".format(message_content), - ) - missing_strings = self.missing_from_output(process, check_strings) - assert ( - missing_strings == [] - ), "Strings {} didn't appear in agent output.".format(missing_strings) - - assert ( - self.is_successfully_terminated() - ), "Echo agent wasn't successfully terminated." - -``` - -Place the above code into a file test.py in your AEA project directory (the same level as the aea-config.yaml file). - -To run, execute the following: - -``` bash -pytest test.py -``` - -
+??? note "Writing tests:" + The following test class replicates the preceding demo and tests its correct behaviour. The `AEATestCase` classes are a tool for AEA developers to write useful end-to-end tests of their AEAs. + + First, get the `packages` directory from the AEA repository (execute from the working directory which contains the my_first_aea folder): + + ``` bash + svn export https://github.com/fetchai/agents-aea.git/trunk/packages + ``` + + Then write the test: + + ``` python + import signal + import time + + from aea.common import Address + from aea.mail.base import Envelope + from aea.protocols.base import Message + from aea.protocols.dialogue.base import Dialogue + + from packages.fetchai.protocols.default.dialogues import DefaultDialogue, DefaultDialogues + from packages.fetchai.protocols.default.message import DefaultMessage + from packages.fetchai.protocols.default.serialization import DefaultSerializer + from aea.test_tools.test_cases import AEATestCase + + + class TestEchoSkill(AEATestCase): + """Test that echo skill works.""" + + def test_echo(self): + """Run the echo skill sequence.""" + process = self.run_agent() + is_running = self.is_running(process) + assert is_running, "AEA not running within timeout!" + + # add sending and receiving envelope from input/output files + sender_aea = "sender_aea" + def role_from_first_message( + message: Message, receiver_address: Address + ) -> Dialogue.Role: + return DefaultDialogue.Role.AGENT + dialogues = DefaultDialogues(sender_aea, role_from_first_message) + message_content = b"hello" + message = DefaultMessage( + performative=DefaultMessage.Performative.BYTES, + dialogue_reference=dialogues.new_self_initiated_dialogue_reference(), + content=message_content, + ) + sent_envelope = Envelope( + to=self.agent_name, + sender=sender_aea, + protocol_id=message.protocol_id, + message=DefaultSerializer().encode(message), + ) + + self.send_envelope_to_agent(sent_envelope, self.agent_name) + + time.sleep(2.0) + received_envelope = self.read_envelope_from_agent(self.agent_name) + + assert sent_envelope.to == received_envelope.sender + assert sent_envelope.sender == received_envelope.to + assert sent_envelope.protocol_id == received_envelope.protocol_id + received_message = DefaultMessage.serializer.decode(received_envelope.message) + assert message.content == received_message.content + + check_strings = ( + "Echo Handler: setup method called.", + "Echo Behaviour: setup method called.", + "Echo Behaviour: act method called.", + "content={}".format(message_content), + ) + missing_strings = self.missing_from_output(process, check_strings) + assert ( + missing_strings == [] + ), "Strings {} didn't appear in agent output.".format(missing_strings) + + assert ( + self.is_successfully_terminated() + ), "Echo agent wasn't successfully terminated." + + ``` + + Place the above code into a file test.py in your AEA project directory (the same level as the aea-config.yaml file). + + To run, execute the following: + + ``` bash + pytest test.py + ``` ### Delete the AEA @@ -463,16 +448,14 @@ Delete the AEA from the parent directory (`cd ..` to go to the parent directory) aea delete my_first_aea ``` -## Next steps +## Next Steps To gain an understanding of the core components of the framework, please continue to the next page: - Core components - Part 1 -For more demos, use cases or step by step guides, please check the following: +For more demos, use cases or step-by-step guides, please check the following: - Generic skill use case - Weather skill demo - Generic step by step guide - -
diff --git a/docs/raspberry-set-up.md b/docs/raspberry-set-up.md index d90033dc8c..19b00bcbfd 100644 --- a/docs/raspberry-set-up.md +++ b/docs/raspberry-set-up.md @@ -1,9 +1,11 @@ +# Build an AEA on a Raspberry Pi + This guide explains how to run an AEA inside a Raspberry Pi. ## Prerequisites -* Raspberry Pi 4 (You can also use Raspberry Pi3 b or Raspberry Pi3 b+) -* Internet connection (preferably wireless to minimise the number of wires connecting into your device) +- Raspberry Pi 4 (You can also use Raspberry Pi3 b or Raspberry Pi3 b+) +- Internet connection (preferably wireless to minimise the number of wires connecting into your device) ## Preparing the Raspberry Pi @@ -20,7 +22,7 @@ First download the tool from this guide to set up your SD card. When you get to the step of choosing an operating system, select the downloaded and unzipped AEA Raspberry Pi Image (`AEA_RPI.IMG`), or for a manual installation, select the latest Raspberry Pi OS. -Once you have set up your SD card, plug it into your Raspberry Pi, connect the power and boot up. +Once you have set up your SD card, plug it into your Raspberry Pi, connect the power and boot up. ## Booting up with the AEA Raspberry Pi Image @@ -28,13 +30,13 @@ After booting up, you may be prompted to log in as the `aea` user and the passwo Next, navigate to settings menu to set up your internet connection. Your Raspberry Pi is now ready to run an AEA! You can find some preloaded demos in the folder `~/aea/demos`. -To run these demos, navigate to one of the subfolders and enter `aea run`. +To run these demos, navigate to one of the sub-folders and enter `aea run`. -## Booting up with the Raspberry Pi OS for manual installation +## Booting up with the Raspberry Pi OS for Manual Installation -When you first boot your Raspberry Pi, you will be prompted to enter a password for the Raspberry Pi and your WiFi password so the device can access the internet. You may also be given the option to update the operating system and software. We recommend that you let the system update. Once finished you will be prompted to restart. +When you first boot your Raspberry Pi, you will be prompted to enter a password for the Raspberry Pi and your Wi-Fi password so the device can access the internet. You may also be given the option to update the operating system and software. We recommend that you let the system update. Once finished you will be prompted to restart. -Even if your Raspberry Pi updated itself, we recommend that you make sure it is completely up to date using the terminal. Open a Terminal window (your Raspberry Pi might restart a few times during this process): +Even if your Raspberry Pi updated itself, we recommend that you make sure it is completely up-to-date using the terminal. Open a Terminal window (your Raspberry Pi might restart a few times during this process): ``` bash sudo apt update -y @@ -42,62 +44,65 @@ sudo apt-get update sudo apt-get dist-upgrade ``` -## Install common dependencies +## Install Common Dependencies ``` bash sudo apt install cmake golang -y ``` -## Install less common dependencies (optional) +## Install Less Common Dependencies (optional) For some of the more advanced AEAs that make use of SciPy, such as the Car Park Detector, you will need some additional dependencies. -
Install additional dependencies with the enclosed steps -

+??? note "Install additional dependencies with the enclosed steps:" -Install additional dependencies -``` bash -sudo apt install gfortran libatlas-base-dev libopenblas-dev -y -``` + Install additional dependencies -Increase the swap space for the SciPy installation: -``` bash -sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024 -sudo /sbin/mkswap /var/swap.1 -sudo chmod 600 /var/swap.1 -sudo /sbin/swapon /var/swap.1 -``` + ``` bash + sudo apt install gfortran libatlas-base-dev libopenblas-dev -y + ``` -Install NumPy and scikit-image (including SciPy) -``` bash -pip install numpy --upgrade -pip install scikit-image -``` + Increase the swap space for the SciPy installation: -Revert to default swap space -``` bash -sudo swapoff /var/swap.1 -sudo rm /var/swap.1 -``` + ``` bash + sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024 + sudo /sbin/mkswap /var/swap.1 + sudo chmod 600 /var/swap.1 + sudo /sbin/swapon /var/swap.1 + ``` + + Install NumPy and scikit-image (including SciPy) + + ``` bash + pip install numpy --upgrade + pip install scikit-image + ``` -

-
+ Revert to default swap space + + ``` bash + sudo swapoff /var/swap.1 + sudo rm /var/swap.1 + ``` ## Install the AEA Framework -Add to the local `PATH` environment variable (this will happen automatically the next time you login): +Add to the local `PATH` environment variable (this will happen automatically the next time you log in): + ``` bash export PATH="$HOME/.local/bin:$PATH" ``` Finally, install the AEA framework from PyPI: + ``` bash pip install aea[all] ``` Check to make sure installation was successful: + ``` bash aea --version ``` -Your Raspberry Pi is now ready to run an AEA! \ No newline at end of file +Your Raspberry Pi is now ready to run an AEA! diff --git a/docs/runtime-cost.md b/docs/runtime-cost.md index 751df8fbdb..a9b6f6affe 100644 --- a/docs/runtime-cost.md +++ b/docs/runtime-cost.md @@ -1,13 +1,15 @@ +# Profiling -## Measuring runtime cost +## Measuring Runtime Cost It is important to emphasise the fact that the AEA is a framework, so ultimately its running cost will highly depend on the number and type of components which are being run as part of a given AEA. The other cost factor is determined by the cost of running the core framework itself and how fast and efficient the framework is in interconnecting the components. These observations can provide guidance on what to report as part of the cost of running an AEA. Here is a list of suggestion on how to measure the cost of running an AEA: + - the cost of running the framework itself: by running a minimal agent with an idle loop (the default one) with no connections, skills or protocols and measuring memory usage and CPU consumption as a baseline. -- the cost of interconnecting components: by running an a agent with a basic skill (e.g. `fetchai/echo`) and measuring memory usage and CPU consumption relative to number of messages exchanged as well as bandwidth. +- the cost of interconnecting components: by running an agent with a basic skill (e.g. `fetchai/echo`) and measuring memory usage and CPU consumption relative to number of messages exchanged as well as bandwidth. - the cost of basic components: dialogues memory relative to number of messages, SOEF connection baseline memory usage, P2P connection baseline memory usage, smart contract baseline memory usage The `aea run --profiling SECONDS` command can be used to report measures in all of the above scenarios. diff --git a/docs/scaffolding.md b/docs/scaffolding.md index 0165340fe1..2f1f163126 100644 --- a/docs/scaffolding.md +++ b/docs/scaffolding.md @@ -1,4 +1,6 @@ -## Scaffold generator +# Scaffolding Packages + +## Scaffold Generator The scaffold generator builds out the directory structure required when adding new skills, protocols, contracts and connections to the AEA. @@ -11,28 +13,25 @@ cd my_aea Then, enter into your project directory and scaffold your project skill, protocol, or connection. - -### Scaffold a skill +### Scaffold a Skill ``` bash aea scaffold skill my_skill ``` - -### Scaffold a protocol +### Scaffold a Protocol ``` bash aea scaffold protocol my_protocol ``` - -### Scaffold a contract +### Scaffold a Contract ``` bash aea scaffold contract my_contract ``` -### Scaffold a connection +### Scaffold a Connection ``` bash aea scaffold connection my_connection @@ -47,5 +46,3 @@ aea fingerprint [package_name] [public_id] ``` Then you are ready to run the AEA. - -
\ No newline at end of file diff --git a/docs/security.md b/docs/security.md index 23e15b24f0..ceebff2bd0 100644 --- a/docs/security.md +++ b/docs/security.md @@ -1,3 +1,4 @@ +# Security The AEA framework takes every care to follow best practice around security. @@ -11,4 +12,4 @@ The following advice will help you when writing your own code: - Try to avoid using the `pickle` module. Pickle should never be used for agent-to-agent communication protocols. -- By design, the framework prevents skill code from accessing private keys directly, as they are not reachable from the skill execution context through attribute getters. However, if the flag `-p` or the option `--password` are not used when generating private keys for an AEA project via the aea CLI tool, the private keys will be stored in plaintext. This allows the skills to access them via interaction with the OS file system. We recommend to always specify a password to encrypt private keys by using the flag argument. \ No newline at end of file +- By design, the framework prevents skill code from accessing private keys directly, as they are not reachable from the skill execution context through attribute getters. However, if the flag `-p` or the option `--password` are not used when generating private keys for an AEA project via the aea CLI tool, the private keys will be stored in plaintext. This allows the skills to access them via interaction with the OS file system. We recommend to always specify a password to encrypt private keys by using the flag argument. diff --git a/docs/simple-oef-usage.md b/docs/simple-oef-usage.md index 3de8a60624..fc66e10822 100644 --- a/docs/simple-oef-usage.md +++ b/docs/simple-oef-usage.md @@ -1,14 +1,19 @@ +# SOEF Connection + You can use the SOEF in the agent framework by using the SOEF connection as a package in your agent project. -## Add the SOEF package -Check out the CLI guide on details how to add a connection. You will want to add the `fetchai/soef:0.27.5` connection package. +## Add the SOEF Package + +Check out the CLI guide on details how to add a connection. You will want to add the `fetchai/soef:0.27.5` connection package. + +## Register your Agent and its Services -## Register your agent and its services +### Register Agent Location -### Register agent location To register your agent's location, you have to send a message in the `fetchai/oef_search:1.0.0` protocol to the SOEF connection. First, define a data model for location data: + ``` python from aea.helpers.search.models import Attribute, DataModel, Location @@ -18,9 +23,11 @@ AGENT_LOCATION_MODEL = DataModel( "A data model to describe location of an agent.", ) ``` + It is important to use this exact data model, as the SOEF connection can only process specific data models. Second, create a location object: + ``` python from aea.helpers.search.models import Location @@ -28,6 +35,7 @@ agent_location = Location(52.2057092, 2.1183431) ``` Third, construct a service description instance with location and data model: + ``` python from aea.helpers.search.models import Description @@ -38,6 +46,7 @@ service_description = Description( ``` Finally, construct a message and send it: + ``` python from packages.fetchai.protocols.oef_search.message import OefSearchMessage @@ -51,9 +60,10 @@ In case everything is registered OK, you will not receive any message back. If something goes wrong you will receive an error message with performative `OefSearchMessage.Performative.OEF_ERROR`. -### Register personality pieces +### Register Personality Pieces To register personality pieces, you have to use a specific data model: + ``` python from aea.helpers.search.models import Attribute, DataModel, Location @@ -68,6 +78,7 @@ AGENT_PERSONALITY_MODEL = DataModel( ``` An example follows: + ``` python service_instance = {"piece": "genus", "value": "service"} service_description = Description( @@ -75,9 +86,10 @@ service_description = Description( ) ``` -### Register services +### Register Services To set some service key and value you have to use a specific data model: + ``` python SET_SERVICE_KEY_MODEL = DataModel( "set_service_key", @@ -90,6 +102,7 @@ SET_SERVICE_KEY_MODEL = DataModel( ``` An example follows: + ``` python service_instance = {"key": "test", "value": "test"} service_description = Description( @@ -97,9 +110,10 @@ service_description = Description( ) ``` -### Remove service key +### Remove Service Key To remove service key have to use a specific data model: + ``` python REMOVE_SERVICE_KEY_MODEL = DataModel( "remove_service_key", @@ -109,6 +123,7 @@ REMOVE_SERVICE_KEY_MODEL = DataModel( ``` An example follows: + ``` python service_instance = {"key": "test"} service_description = Description( @@ -116,16 +131,15 @@ service_description = Description( ) ``` -
-

Note

-

Currently, the soef does not allow for multiple registrations to be combined into a single command. -

+!!! note + Currently, the soef does not allow for multiple registrations to be combined into a single command. -## Perform a search +## Perform a Search To perform a search for services registered you have to define a search query consisting of constraints. The location constraints is required, personality pieces or services keys constraints are optional. An example follows: + ``` python from aea.helpers.search.models import ( Constraint, @@ -159,11 +173,12 @@ message = OefSearchMessage( ) ``` -In case of error you will received a message with `OefSearchMessage.Performative.OEF_ERROR`. In case of successful search you will receive a message with performative `OefSearchMessage.Performative.SEARCH_RESULT` and the list of matched agents addresses. +In case of error, you will receive a message with `OefSearchMessage.Performative.OEF_ERROR`. In case of successful search you will receive a message with performative `OefSearchMessage.Performative.SEARCH_RESULT` and the list of matched agents addresses. -## Generic command +## Generic Command To send a generic command request to the SOEF use the following (here on the example of setting a declared name): + ``` python import urllib @@ -188,4 +203,4 @@ message = OefSearchMessage( performative=OefSearchMessage.Performative.REGISTER_SERVICE, service_description=service_description, ) -``` \ No newline at end of file +``` diff --git a/docs/skill-guide.md b/docs/skill-guide.md index 5ac8235190..c7ea699bdd 100644 --- a/docs/skill-guide.md +++ b/docs/skill-guide.md @@ -1,3 +1,5 @@ +# Build your First Skill - Search & Discovery + This guide will take you through the development of your first skill. It will teach you, how to connect the AEA to the digital world, register the AEA and search for other AEAs. Although one can imagine scenarios where a single AEA pursues its goals in isolation without interacting with other AEAs, there is no doubt that by working together, AEAs can achieve much more. To do so, an AEA must be seen and found by other AEAs so that they can trade and do other useful things. Fetch.ai’s search-and-discovery mechanism, the simple OEF (or SOEF, for short) lets your agents register, be discovered, and find other agents. You can then negotiate using the AEA framework’s peer-to-peer network (ACN) and trade. This guide covers getting your AEA connected to the SOEF, and describing your AEA to make itself visible. @@ -10,8 +12,6 @@ The more you describe your AEA, the easier it is for others to find it using spe Follow the Preliminaries and Installation sections from the AEA quick start. - - ## Step 1: Setup We will first create an AEA and add a scaffold skill, which we call `my_search`. @@ -118,10 +118,8 @@ Searches are proactive and, as such, well placed in a -

Note

-

Note that the import paths to agent packages, for example packages.fetchai.skills.my_search.dialogues above, are not actual paths. Package files always reside in your AEA's folder, either under a specific package directory (e.g. connection, protocol, skill) if the package is custom built, or under vendor if it is pulled from the registry. These paths are virtual and created automatically when an AEA is run. See this page for more details.

- +!!! note + The import paths to agent packages, for example `packages.fetchai.skills.my_search.dialogues` above, are not actual paths. Package files always reside in your AEA's folder, either under a specific package directory (e.g. connection, protocol, skill) if the package is custom-built, or under `vendor` if it is pulled from the registry. These paths are virtual and created automatically when an AEA is run. See this page for more details. ## Step 3: Develop a Handler @@ -264,7 +262,7 @@ class MySearchHandler(Handler): ) ``` -We create a handler which is registered for the `oef_search` protocol. Whenever it receives a search result, we log the number of agents returned in the search - the agents matching the search query - and update the counter of received searches. +We create a handler which is registered for the `oef_search` protocol. Whenever it receives a search result, we log the number of agents returned by the search - the agents matching the search query - and update the counter of received searches. We also implement a trivial check on the difference between the amount of search requests sent and responses received. @@ -274,7 +272,7 @@ Also note, how we have access to other objects in the skill via `self.context`, We place this code in `my_aea/skills/my_search/handlers.py`. Ensure you replace the `fetchai` author in this line `from packages.fetchai.skills.my_search.dialogues import (` with your author handle (run `aea init` to set or check the author name). -## Step 4: Add dialogues model +## Step 4: Add Dialogues Model We have implemented a behaviour and a handler. We now implement a `Model`, in particular we implement the `Dialogue` and `Dialogues` classes. These ensure that the message flow satisfies the `fetchai/oef_search:1.0.0` protocol and keep track of the individual messages being sent and received. @@ -326,7 +324,7 @@ class OefSearchDialogues(Model, BaseOefSearchDialogues): We add this code in the file `my_aea/skills/my_search/my_model.py`, replacing its original content. We then rename `my_aea/skills/my_search/my_model.py` to `my_aea/skills/my_search/dialogues.py`. -## Step 5: Create the configuration file +## Step 5: Create the Configuration File Based on our skill components above, we create the following configuration file. @@ -408,19 +406,23 @@ from aea.configurations.base import PublicId PUBLIC_ID = PublicId.from_str("fetchai/my_search:0.1.0") ``` + Again, ensure the author field matches your own. -## Step 6: Update fingerprint +## Step 6: Update Fingerprint To run an AEA with new or modified code, you need to update the fingerprint of the new/modified components. In this case, we need to fingerprint our skill: + ``` bash aea fingerprint skill fetchai/my_search:0.1.0 ``` + Ensure, you use the correct author name to reference your skill (here we use `fetchai` as the author.) -## Step 7: Add the OEF protocol and connection +## Step 7: Add the OEF Protocol and Connection Our AEA does not have the OEF protocol yet so let's add it. + ``` bash aea add protocol fetchai/oef_search:1.1.6 ``` @@ -428,6 +430,7 @@ aea add protocol fetchai/oef_search:1.1.6 This adds the protocol to our AEA and makes it available on the path `packages.fetchai.protocols...`. At this point we need to add the SOEF and P2P connections to allow the AEA to communicate with the SOEF node and other AEAs, install the AEA's dependencies, and configure the AEA: + ``` bash aea add connection fetchai/soef:0.27.5 aea add connection fetchai/p2p_libp2p:0.27.4 @@ -442,11 +445,12 @@ aea config set --type dict agent.default_routing \ The last command will ensure that search requests are processed by the correct connection. -## Step 8: Run a service provider AEA +## Step 8: Run a Service Provider AEA -In order for this AEA to find another AEA when searching, the second AEA (let's call it the service provider AEA) must exist and have been registered with the SOEF. +In order for this AEA to find another AEA when searching, the second AEA (let's call it the service provider AEA) must exist and have been registered with the SOEF. From a different terminal window, we fetch a finished service provider AEA and install its Python dependencies: + ``` bash aea fetch fetchai/simple_service_registration:0.32.4 && cd simple_service_registration && aea install && aea build ``` @@ -454,642 +458,646 @@ aea fetch fetchai/simple_service_registration:0.32.4 && cd simple_service_regist This AEA will simply register a location service on the SOEF search node so we can search for it. We first create the private key for the service provider AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` Then we run the AEA: + ``` bash aea run ``` Once you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) This is the entry peer address for the local agent communication network created by the `simple_service_registration` (service provider) AEA. -
Click here to see full code and guide for this AEA -

- -We use a TickerBehaviour to update the service registration at regular intervals. The following code is placed in behaviours.py. - -``` python -from typing import Any, Optional, cast - -from aea.helpers.search.models import Description -from aea.skills.behaviours import TickerBehaviour - -from packages.fetchai.protocols.oef_search.message import OefSearchMessage -from packages.fetchai.skills.simple_service_registration.dialogues import ( - OefSearchDialogues, -) -from packages.fetchai.skills.simple_service_registration.strategy import Strategy - - -DEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5 -DEFAULT_SERVICES_INTERVAL = 30.0 - - -class ServiceRegistrationBehaviour(TickerBehaviour): - """This class implements a behaviour.""" - - def __init__(self, **kwargs: Any) -> None: - """Initialise the behaviour.""" - services_interval = kwargs.pop( - "services_interval", DEFAULT_SERVICES_INTERVAL - ) # type: int - self._max_soef_registration_retries = kwargs.pop( - "max_soef_registration_retries", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES - ) # type: int - super().__init__(tick_interval=services_interval, **kwargs) - - self.failed_registration_msg = None # type: Optional[OefSearchMessage] - self._nb_retries = 0 - - def setup(self) -> None: - """ - Implement the setup. - - :return: None - """ - self._register_agent() - - def act(self) -> None: - """ - Implement the act. - - :return: None - """ - self._retry_failed_registration() - - def teardown(self) -> None: - """ - Implement the task teardown. - - :return: None - """ - self._unregister_service() - self._unregister_agent() - - def _retry_failed_registration(self) -> None: - """ - Retry a failed registration. - - :return: None - """ - if self.failed_registration_msg is not None: - self._nb_retries += 1 - if self._nb_retries > self._max_soef_registration_retries: - self.context.is_active = False - return - +??? note "Click here to see full code and guide for this AEA:" + We use a `TickerBehaviour` to update the service registration at regular intervals. The following code is placed in `behaviours.py`. + + ``` python + from typing import Any, Optional, cast + + from aea.helpers.search.models import Description + from aea.skills.behaviours import TickerBehaviour + + from packages.fetchai.protocols.oef_search.message import OefSearchMessage + from packages.fetchai.skills.simple_service_registration.dialogues import ( + OefSearchDialogues, + ) + from packages.fetchai.skills.simple_service_registration.strategy import Strategy + + + DEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5 + DEFAULT_SERVICES_INTERVAL = 30.0 + + + class ServiceRegistrationBehaviour(TickerBehaviour): + """This class implements a behaviour.""" + + def __init__(self, **kwargs: Any) -> None: + """Initialise the behaviour.""" + services_interval = kwargs.pop( + "services_interval", DEFAULT_SERVICES_INTERVAL + ) # type: int + self._max_soef_registration_retries = kwargs.pop( + "max_soef_registration_retries", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES + ) # type: int + super().__init__(tick_interval=services_interval, **kwargs) + + self.failed_registration_msg = None # type: Optional[OefSearchMessage] + self._nb_retries = 0 + + def setup(self) -> None: + """ + Implement the setup. + + :return: None + """ + self._register_agent() + + def act(self) -> None: + """ + Implement the act. + + :return: None + """ + self._retry_failed_registration() + + def teardown(self) -> None: + """ + Implement the task teardown. + + :return: None + """ + self._unregister_service() + self._unregister_agent() + + def _retry_failed_registration(self) -> None: + """ + Retry a failed registration. + + :return: None + """ + if self.failed_registration_msg is not None: + self._nb_retries += 1 + if self._nb_retries > self._max_soef_registration_retries: + self.context.is_active = False + return + + oef_search_dialogues = cast( + OefSearchDialogues, self.context.oef_search_dialogues + ) + oef_search_msg, _ = oef_search_dialogues.create( + counterparty=self.failed_registration_msg.to, + performative=self.failed_registration_msg.performative, + service_description=self.failed_registration_msg.service_description, + ) + self.context.outbox.put_message(message=oef_search_msg) + self.context.logger.info( + f"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}." + ) + + self.failed_registration_msg = None + + def _register(self, description: Description, logger_msg: str) -> None: + """ + Register something on the SOEF. + + :param description: the description of what is being registered + :param logger_msg: the logger message to print after the registration + + :return: None + """ oef_search_dialogues = cast( OefSearchDialogues, self.context.oef_search_dialogues ) oef_search_msg, _ = oef_search_dialogues.create( - counterparty=self.failed_registration_msg.to, - performative=self.failed_registration_msg.performative, - service_description=self.failed_registration_msg.service_description, + counterparty=self.context.search_service_address, + performative=OefSearchMessage.Performative.REGISTER_SERVICE, + service_description=description, ) self.context.outbox.put_message(message=oef_search_msg) - self.context.logger.info( - f"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}." + self.context.logger.info(logger_msg) + + def _register_agent(self) -> None: + """ + Register the agent's location. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_location_description() + self._register(description, "registering agent on SOEF.") + + def register_service(self) -> None: + """ + Register the agent's service. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_register_service_description() + self._register(description, "registering agent's service on the SOEF.") + + def register_genus(self) -> None: + """ + Register the agent's personality genus. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_register_personality_description() + self._register( + description, "registering agent's personality genus on the SOEF." ) - - self.failed_registration_msg = None - - def _register(self, description: Description, logger_msg: str) -> None: - """ - Register something on the SOEF. - - :param description: the description of what is being registered - :param logger_msg: the logger message to print after the registration - - :return: None - """ - oef_search_dialogues = cast( - OefSearchDialogues, self.context.oef_search_dialogues - ) - oef_search_msg, _ = oef_search_dialogues.create( - counterparty=self.context.search_service_address, - performative=OefSearchMessage.Performative.REGISTER_SERVICE, - service_description=description, - ) - self.context.outbox.put_message(message=oef_search_msg) - self.context.logger.info(logger_msg) - - def _register_agent(self) -> None: - """ - Register the agent's location. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_location_description() - self._register(description, "registering agent on SOEF.") - - def register_service(self) -> None: - """ - Register the agent's service. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_register_service_description() - self._register(description, "registering agent's service on the SOEF.") - - def register_genus(self) -> None: - """ - Register the agent's personality genus. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_register_personality_description() - self._register( - description, "registering agent's personality genus on the SOEF." - ) - - def register_classification(self) -> None: - """ - Register the agent's personality classification. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_register_classification_description() - self._register( - description, "registering agent's personality classification on the SOEF." - ) - - def _unregister_service(self) -> None: - """ - Unregister service from the SOEF. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_unregister_service_description() - oef_search_dialogues = cast( - OefSearchDialogues, self.context.oef_search_dialogues - ) - oef_search_msg, _ = oef_search_dialogues.create( - counterparty=self.context.search_service_address, - performative=OefSearchMessage.Performative.UNREGISTER_SERVICE, - service_description=description, - ) - self.context.outbox.put_message(message=oef_search_msg) - self.context.logger.info("unregistering service from SOEF.") - - def _unregister_agent(self) -> None: - """ - Unregister agent from the SOEF. - - :return: None - """ - strategy = cast(Strategy, self.context.strategy) - description = strategy.get_location_description() - oef_search_dialogues = cast( - OefSearchDialogues, self.context.oef_search_dialogues - ) - oef_search_msg, _ = oef_search_dialogues.create( - counterparty=self.context.search_service_address, - performative=OefSearchMessage.Performative.UNREGISTER_SERVICE, - service_description=description, - ) - self.context.outbox.put_message(message=oef_search_msg) - self.context.logger.info("unregistering agent from SOEF.") -``` - -We create a Model type strategy class and place it in strategy.py. We use a generic data model to register the service. As part of the registration we register a location and a key pair describing our service. - -``` python -from typing import Any - -from aea.exceptions import enforce -from aea.helpers.search.generic import ( - AGENT_LOCATION_MODEL, - AGENT_PERSONALITY_MODEL, - AGENT_REMOVE_SERVICE_MODEL, - AGENT_SET_SERVICE_MODEL, -) -from aea.helpers.search.models import Description, Location -from aea.skills.base import Model - - -DEFAULT_LOCATION = {"longitude": 0.1270, "latitude": 51.5194} -DEFAULT_SERVICE_DATA = {"key": "seller_service", "value": "generic_service"} -DEFAULT_PERSONALITY_DATA = {"piece": "genus", "value": "data"} -DEFAULT_CLASSIFICATION = {"piece": "classification", "value": "seller"} - - -class Strategy(Model): - """This class defines a strategy for the agent.""" - - def __init__(self, **kwargs: Any) -> None: - """ - Initialize the strategy of the agent. - - :return: None - """ - location = kwargs.pop("location", DEFAULT_LOCATION) - self._agent_location = { - "location": Location( - latitude=location["latitude"], longitude=location["longitude"] + + def register_classification(self) -> None: + """ + Register the agent's personality classification. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_register_classification_description() + self._register( + description, "registering agent's personality classification on the SOEF." ) - } - self._set_personality_data = kwargs.pop( - "personality_data", DEFAULT_PERSONALITY_DATA - ) - enforce( - len(self._set_personality_data) == 2 - and "piece" in self._set_personality_data - and "value" in self._set_personality_data, - "personality_data must contain keys `key` and `value`", - ) - self._set_classification = kwargs.pop("classification", DEFAULT_CLASSIFICATION) - enforce( - len(self._set_classification) == 2 - and "piece" in self._set_classification - and "value" in self._set_classification, - "classification must contain keys `key` and `value`", - ) - self._set_service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA) - enforce( - len(self._set_service_data) == 2 - and "key" in self._set_service_data - and "value" in self._set_service_data, - "service_data must contain keys `key` and `value`", - ) - self._remove_service_data = {"key": self._set_service_data["key"]} - super().__init__(**kwargs) - - def get_location_description(self) -> Description: - """ - Get the location description. - - :return: a description of the agent's location - """ - description = Description( - self._agent_location, data_model=AGENT_LOCATION_MODEL, - ) - return description - - def get_register_service_description(self) -> Description: - """ - Get the register service description. - - :return: a description of the offered services - """ - description = Description( - self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL, - ) - return description - - def get_register_personality_description(self) -> Description: - """ - Get the register personality description. - - :return: a description of the personality - """ - description = Description( - self._set_personality_data, data_model=AGENT_PERSONALITY_MODEL, - ) - return description - - def get_register_classification_description(self) -> Description: - """ - Get the register classification description. - - :return: a description of the classification - """ - description = Description( - self._set_classification, data_model=AGENT_PERSONALITY_MODEL, - ) - return description - - def get_unregister_service_description(self) -> Description: - """ - Get the unregister service description. - - :return: a description of the to be removed service - """ - description = Description( - self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL, - ) - return description -``` - -We create a Model type dialogue class and place it in dialogues.py. These classes ensure that the message flow satisfies the fetchai/oef_search:1.0.0 protocol and keep track of the individual messages being sent and received. - -``` python -from typing import Any - -from aea.protocols.base import Address, Message -from aea.protocols.dialogue.base import Dialogue as BaseDialogue -from aea.skills.base import Model - -from packages.fetchai.protocols.oef_search.dialogues import ( - OefSearchDialogue as BaseOefSearchDialogue, -) -from packages.fetchai.protocols.oef_search.dialogues import ( - OefSearchDialogues as BaseOefSearchDialogues, -) - - -OefSearchDialogue = BaseOefSearchDialogue - - -class OefSearchDialogues(Model, BaseOefSearchDialogues): - """This class keeps track of all oef_search dialogues.""" - - def __init__(self, **kwargs: Any) -> None: - """ - Initialize dialogues. - - :param agent_address: the address of the agent for whom dialogues are maintained - :return: None - """ - Model.__init__(self, **kwargs) - - def role_from_first_message( # pylint: disable=unused-argument - message: Message, receiver_address: Address - ) -> BaseDialogue.Role: - """Infer the role of the agent from an incoming/outgoing first message - - :param message: an incoming/outgoing first message - :param receiver_address: the address of the receiving agent - :return: The role of the agent + + def _unregister_service(self) -> None: """ - return BaseOefSearchDialogue.Role.AGENT - - BaseOefSearchDialogues.__init__( - self, - self_address=str(self.skill_id), - role_from_first_message=role_from_first_message, - ) - -``` - -Finally, we have a handler, placed in handlers.py. The handler deals with handling any error messages which might occur during service registration: - -``` python -from typing import Optional, cast - -from aea.configurations.base import PublicId -from aea.protocols.base import Message -from aea.skills.base import Handler - -from packages.fetchai.protocols.oef_search.message import OefSearchMessage -from packages.fetchai.skills.simple_service_registration.behaviours import ( - ServiceRegistrationBehaviour, -) -from packages.fetchai.skills.simple_service_registration.dialogues import ( - OefSearchDialogue, - OefSearchDialogues, -) - - -class OefSearchHandler(Handler): - """This class implements an OEF search handler.""" - - SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[PublicId] - - def setup(self) -> None: - """Call to setup the handler.""" - - def handle(self, message: Message) -> None: - """ - Implement the reaction to a message. - - :param message: the message - :return: None - """ - oef_search_msg = cast(OefSearchMessage, message) - - # recover dialogue - oef_search_dialogues = cast( - OefSearchDialogues, self.context.oef_search_dialogues - ) - oef_search_dialogue = cast( - Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg) - ) - if oef_search_dialogue is None: - self._handle_unidentified_dialogue(oef_search_msg) - return - - # handle message - if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS: - self._handle_success(oef_search_msg, oef_search_dialogue) - elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR: - self._handle_error(oef_search_msg, oef_search_dialogue) - else: - self._handle_invalid(oef_search_msg, oef_search_dialogue) - - def teardown(self) -> None: - """ - Implement the handler teardown. - - :return: None - """ - - def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None: - """ - Handle an unidentified dialogue. - - :param msg: the message - """ - self.context.logger.info( - "received invalid oef_search message={}, unidentified dialogue.".format( - oef_search_msg + Unregister service from the SOEF. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_unregister_service_description() + oef_search_dialogues = cast( + OefSearchDialogues, self.context.oef_search_dialogues ) - ) - - def _handle_success( - self, - oef_search_success_msg: OefSearchMessage, - oef_search_dialogue: OefSearchDialogue, - ) -> None: - """ - Handle an oef search message. - - :param oef_search_success_msg: the oef search message - :param oef_search_dialogue: the dialogue - :return: None - """ - self.context.logger.info( - "received oef_search success message={} in dialogue={}.".format( - oef_search_success_msg, oef_search_dialogue + oef_search_msg, _ = oef_search_dialogues.create( + counterparty=self.context.search_service_address, + performative=OefSearchMessage.Performative.UNREGISTER_SERVICE, + service_description=description, ) - ) - target_message = cast( - OefSearchMessage, - oef_search_dialogue.get_message_by_id(oef_search_success_msg.target), - ) - if ( - target_message.performative - == OefSearchMessage.Performative.REGISTER_SERVICE - ): - description = target_message.service_description - data_model_name = description.data_model.name - registration_behaviour = cast( - ServiceRegistrationBehaviour, self.context.behaviours.service, + self.context.outbox.put_message(message=oef_search_msg) + self.context.logger.info("unregistering service from SOEF.") + + def _unregister_agent(self) -> None: + """ + Unregister agent from the SOEF. + + :return: None + """ + strategy = cast(Strategy, self.context.strategy) + description = strategy.get_location_description() + oef_search_dialogues = cast( + OefSearchDialogues, self.context.oef_search_dialogues ) - if "location_agent" in data_model_name: - registration_behaviour.register_service() - elif "set_service_key" in data_model_name: - registration_behaviour.register_genus() - elif ( - "personality_agent" in data_model_name - and description.values["piece"] == "genus" - ): - registration_behaviour.register_classification() - elif ( - "personality_agent" in data_model_name - and description.values["piece"] == "classification" - ): - self.context.logger.info( - "the agent, with its genus and classification, and its service are successfully registered on the SOEF." + oef_search_msg, _ = oef_search_dialogues.create( + counterparty=self.context.search_service_address, + performative=OefSearchMessage.Performative.UNREGISTER_SERVICE, + service_description=description, + ) + self.context.outbox.put_message(message=oef_search_msg) + self.context.logger.info("unregistering agent from SOEF.") + ``` + + We create a Model type strategy class and place it in strategy.py. We use a generic data model to register the service. As part of the registration we register a location and a key pair describing our service. + + ``` python + from typing import Any + + from aea.exceptions import enforce + from aea.helpers.search.generic import ( + AGENT_LOCATION_MODEL, + AGENT_PERSONALITY_MODEL, + AGENT_REMOVE_SERVICE_MODEL, + AGENT_SET_SERVICE_MODEL, + ) + from aea.helpers.search.models import Description, Location + from aea.skills.base import Model + + + DEFAULT_LOCATION = {"longitude": 0.1270, "latitude": 51.5194} + DEFAULT_SERVICE_DATA = {"key": "seller_service", "value": "generic_service"} + DEFAULT_PERSONALITY_DATA = {"piece": "genus", "value": "data"} + DEFAULT_CLASSIFICATION = {"piece": "classification", "value": "seller"} + + + class Strategy(Model): + """This class defines a strategy for the agent.""" + + def __init__(self, **kwargs: Any) -> None: + """ + Initialize the strategy of the agent. + + :return: None + """ + location = kwargs.pop("location", DEFAULT_LOCATION) + self._agent_location = { + "location": Location( + latitude=location["latitude"], longitude=location["longitude"] ) + } + self._set_personality_data = kwargs.pop( + "personality_data", DEFAULT_PERSONALITY_DATA + ) + enforce( + len(self._set_personality_data) == 2 + and "piece" in self._set_personality_data + and "value" in self._set_personality_data, + "personality_data must contain keys `key` and `value`", + ) + self._set_classification = kwargs.pop("classification", DEFAULT_CLASSIFICATION) + enforce( + len(self._set_classification) == 2 + and "piece" in self._set_classification + and "value" in self._set_classification, + "classification must contain keys `key` and `value`", + ) + self._set_service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA) + enforce( + len(self._set_service_data) == 2 + and "key" in self._set_service_data + and "value" in self._set_service_data, + "service_data must contain keys `key` and `value`", + ) + self._remove_service_data = {"key": self._set_service_data["key"]} + super().__init__(**kwargs) + + def get_location_description(self) -> Description: + """ + Get the location description. + + :return: a description of the agent's location + """ + description = Description( + self._agent_location, data_model=AGENT_LOCATION_MODEL, + ) + return description + + def get_register_service_description(self) -> Description: + """ + Get the register service description. + + :return: a description of the offered services + """ + description = Description( + self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL, + ) + return description + + def get_register_personality_description(self) -> Description: + """ + Get the register personality description. + + :return: a description of the personality + """ + description = Description( + self._set_personality_data, data_model=AGENT_PERSONALITY_MODEL, + ) + return description + + def get_register_classification_description(self) -> Description: + """ + Get the register classification description. + + :return: a description of the classification + """ + description = Description( + self._set_classification, data_model=AGENT_PERSONALITY_MODEL, + ) + return description + + def get_unregister_service_description(self) -> Description: + """ + Get the unregister service description. + + :return: a description of the to be removed service + """ + description = Description( + self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL, + ) + return description + ``` + + We create a Model type dialogue class and place it in dialogues.py. These classes ensure that the message flow satisfies the fetchai/oef_search:1.0.0 protocol and keep track of the individual messages being sent and received. + + ``` python + from typing import Any + + from aea.protocols.base import Address, Message + from aea.protocols.dialogue.base import Dialogue as BaseDialogue + from aea.skills.base import Model + + from packages.fetchai.protocols.oef_search.dialogues import ( + OefSearchDialogue as BaseOefSearchDialogue, + ) + from packages.fetchai.protocols.oef_search.dialogues import ( + OefSearchDialogues as BaseOefSearchDialogues, + ) + + + OefSearchDialogue = BaseOefSearchDialogue + + + class OefSearchDialogues(Model, BaseOefSearchDialogues): + """This class keeps track of all oef_search dialogues.""" + + def __init__(self, **kwargs: Any) -> None: + """ + Initialize dialogues. + + :param agent_address: the address of the agent for whom dialogues are maintained + :return: None + """ + Model.__init__(self, **kwargs) + + def role_from_first_message( # pylint: disable=unused-argument + message: Message, receiver_address: Address + ) -> BaseDialogue.Role: + """Infer the role of the agent from an incoming/outgoing first message + + :param message: an incoming/outgoing first message + :param receiver_address: the address of the receiving agent + :return: The role of the agent + """ + return BaseOefSearchDialogue.Role.AGENT + + BaseOefSearchDialogues.__init__( + self, + self_address=str(self.skill_id), + role_from_first_message=role_from_first_message, + ) + + ``` + + Finally, we have a handler, placed in handlers.py. The handler deals with handling any error messages which might occur during service registration: + + ``` python + from typing import Optional, cast + + from aea.configurations.base import PublicId + from aea.protocols.base import Message + from aea.skills.base import Handler + + from packages.fetchai.protocols.oef_search.message import OefSearchMessage + from packages.fetchai.skills.simple_service_registration.behaviours import ( + ServiceRegistrationBehaviour, + ) + from packages.fetchai.skills.simple_service_registration.dialogues import ( + OefSearchDialogue, + OefSearchDialogues, + ) + + + class OefSearchHandler(Handler): + """This class implements an OEF search handler.""" + + SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[PublicId] + + def setup(self) -> None: + """Call to setup the handler.""" + + def handle(self, message: Message) -> None: + """ + Implement the reaction to a message. + + :param message: the message + :return: None + """ + oef_search_msg = cast(OefSearchMessage, message) + + # recover dialogue + oef_search_dialogues = cast( + OefSearchDialogues, self.context.oef_search_dialogues + ) + oef_search_dialogue = cast( + Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg) + ) + if oef_search_dialogue is None: + self._handle_unidentified_dialogue(oef_search_msg) + return + + # handle message + if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS: + self._handle_success(oef_search_msg, oef_search_dialogue) + elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR: + self._handle_error(oef_search_msg, oef_search_dialogue) else: - self.context.logger.warning( - f"received soef SUCCESS message as a reply to the following unexpected message: {target_message}" + self._handle_invalid(oef_search_msg, oef_search_dialogue) + + def teardown(self) -> None: + """ + Implement the handler teardown. + + :return: None + """ + + def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None: + """ + Handle an unidentified dialogue. + + :param msg: the message + """ + self.context.logger.info( + "received invalid oef_search message={}, unidentified dialogue.".format( + oef_search_msg ) - - def _handle_error( - self, - oef_search_error_msg: OefSearchMessage, - oef_search_dialogue: OefSearchDialogue, - ) -> None: - """ - Handle an oef search message. - - :param oef_search_error_msg: the oef search message - :param oef_search_dialogue: the dialogue - :return: None - """ - self.context.logger.info( - "received oef_search error message={} in dialogue={}.".format( - oef_search_error_msg, oef_search_dialogue ) - ) - target_message = cast( - OefSearchMessage, - oef_search_dialogue.get_message_by_id(oef_search_error_msg.target), - ) - if ( - target_message.performative - == OefSearchMessage.Performative.REGISTER_SERVICE - ): - registration_behaviour = cast( - ServiceRegistrationBehaviour, self.context.behaviours.service, + + def _handle_success( + self, + oef_search_success_msg: OefSearchMessage, + oef_search_dialogue: OefSearchDialogue, + ) -> None: + """ + Handle an oef search message. + + :param oef_search_success_msg: the oef search message + :param oef_search_dialogue: the dialogue + :return: None + """ + self.context.logger.info( + "received oef_search success message={} in dialogue={}.".format( + oef_search_success_msg, oef_search_dialogue + ) ) - registration_behaviour.failed_registration_msg = target_message - - def _handle_invalid( - self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue - ) -> None: - """ - Handle an oef search message. - - :param oef_search_msg: the oef search message - :param oef_search_dialogue: the dialogue - :return: None - """ - self.context.logger.warning( - "cannot handle oef_search message of performative={} in dialogue={}.".format( - oef_search_msg.performative, oef_search_dialogue, + target_message = cast( + OefSearchMessage, + oef_search_dialogue.get_message_by_id(oef_search_success_msg.target), ) - ) -``` - -The associated skill.yaml is: - -``` yaml -name: simple_service_registration -author: fetchai -version: 0.20.0 -type: skill -description: The simple service registration skills is a skill to register a service. -license: Apache-2.0 -aea_version: '>=1.0.0, <2.0.0' -fingerprint: - README.md: QmUgCcR7sDBQeeCBRKwDT7tPBTi3t4zSibyEqR3xdQUKmh - __init__.py: QmZd48HmYDr7FMxNaVeGfWRvVtieEdEV78hd7h7roTceP2 - behaviours.py: QmQHf6QL5aBtLJ34D2tdcbjJLbzom9gaA3HWgRn3rWyigM - dialogues.py: QmTT9dvFhWt6qvxjwBfMFDTrgEtgWbvgANYafyRg2BXwcR - handlers.py: QmZqPt8toGbJgTT6NZBLxjkusrQCZ8GmUEwcmqZ1sd7DpG - strategy.py: QmVXfQpk4cjDw576H2ELE12tEiN5brPkwvffvcTeMbsugA -fingerprint_ignore_patterns: [] -connections: [] -contracts: [] -protocols: -- fetchai/oef_search:1.1.6 -skills: [] -behaviours: - service: - args: - max_soef_registration_retries: 5 - services_interval: 30 - class_name: ServiceRegistrationBehaviour -handlers: - oef_search: - args: {} - class_name: OefSearchHandler -models: - oef_search_dialogues: - args: {} - class_name: OefSearchDialogues - strategy: - args: - classification: - piece: classification - value: seller - location: - latitude: 51.5194 - longitude: 0.127 - personality_data: - piece: genus - value: data - service_data: - key: seller_service - value: generic_service - class_name: Strategy -dependencies: {} -is_abstract: false -``` -

-
+ if ( + target_message.performative + == OefSearchMessage.Performative.REGISTER_SERVICE + ): + description = target_message.service_description + data_model_name = description.data_model.name + registration_behaviour = cast( + ServiceRegistrationBehaviour, self.context.behaviours.service, + ) + if "location_agent" in data_model_name: + registration_behaviour.register_service() + elif "set_service_key" in data_model_name: + registration_behaviour.register_genus() + elif ( + "personality_agent" in data_model_name + and description.values["piece"] == "genus" + ): + registration_behaviour.register_classification() + elif ( + "personality_agent" in data_model_name + and description.values["piece"] == "classification" + ): + self.context.logger.info( + "the agent, with its genus and classification, and its service are successfully registered on the SOEF." + ) + else: + self.context.logger.warning( + f"received soef SUCCESS message as a reply to the following unexpected message: {target_message}" + ) + + def _handle_error( + self, + oef_search_error_msg: OefSearchMessage, + oef_search_dialogue: OefSearchDialogue, + ) -> None: + """ + Handle an oef search message. + + :param oef_search_error_msg: the oef search message + :param oef_search_dialogue: the dialogue + :return: None + """ + self.context.logger.info( + "received oef_search error message={} in dialogue={}.".format( + oef_search_error_msg, oef_search_dialogue + ) + ) + target_message = cast( + OefSearchMessage, + oef_search_dialogue.get_message_by_id(oef_search_error_msg.target), + ) + if ( + target_message.performative + == OefSearchMessage.Performative.REGISTER_SERVICE + ): + registration_behaviour = cast( + ServiceRegistrationBehaviour, self.context.behaviours.service, + ) + registration_behaviour.failed_registration_msg = target_message + + def _handle_invalid( + self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue + ) -> None: + """ + Handle an oef search message. + + :param oef_search_msg: the oef search message + :param oef_search_dialogue: the dialogue + :return: None + """ + self.context.logger.warning( + "cannot handle oef_search message of performative={} in dialogue={}.".format( + oef_search_msg.performative, oef_search_dialogue, + ) + ) + ``` + + The associated skill.yaml is: + + ``` yaml + name: simple_service_registration + author: fetchai + version: 0.20.0 + type: skill + description: The simple service registration skills is a skill to register a service. + license: Apache-2.0 + aea_version: '>=1.0.0, <2.0.0' + fingerprint: + README.md: QmUgCcR7sDBQeeCBRKwDT7tPBTi3t4zSibyEqR3xdQUKmh + __init__.py: QmZd48HmYDr7FMxNaVeGfWRvVtieEdEV78hd7h7roTceP2 + behaviours.py: QmQHf6QL5aBtLJ34D2tdcbjJLbzom9gaA3HWgRn3rWyigM + dialogues.py: QmTT9dvFhWt6qvxjwBfMFDTrgEtgWbvgANYafyRg2BXwcR + handlers.py: QmZqPt8toGbJgTT6NZBLxjkusrQCZ8GmUEwcmqZ1sd7DpG + strategy.py: QmVXfQpk4cjDw576H2ELE12tEiN5brPkwvffvcTeMbsugA + fingerprint_ignore_patterns: [] + connections: [] + contracts: [] + protocols: + - fetchai/oef_search:1.1.6 + skills: [] + behaviours: + service: + args: + max_soef_registration_retries: 5 + services_interval: 30 + class_name: ServiceRegistrationBehaviour + handlers: + oef_search: + args: {} + class_name: OefSearchHandler + models: + oef_search_dialogues: + args: {} + class_name: OefSearchDialogues + strategy: + args: + classification: + piece: classification + value: seller + location: + latitude: 51.5194 + longitude: 0.127 + personality_data: + piece: genus + value: data + service_data: + key: seller_service + value: generic_service + class_name: Strategy + dependencies: {} + is_abstract: false + ``` ## Step 9: Run the Search AEA First, create the private key for the search AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` Then, in the search AEA, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -1100,6 +1108,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + This allows the search AEA to connect to the same local agent communication network as the service registration AEA. We can then launch our AEA. @@ -1112,8 +1121,7 @@ We can see that the AEA sends search requests to the SOE We stop the AEA with `CTRL + C`. -## Next steps - +## Next Steps ### Recommended @@ -1121,8 +1129,6 @@ We recommend you continue with the next step in the 'Getting Started' series: - Core components (Part 2) -### Relevant deep-dives - - This guide goes through a more elaborate scenario than the one on this page, where after finding each other, the two AEAs negotiate and trade via a ledger. +### Relevant Deep-Dives -
\ No newline at end of file + This guide goes through a more elaborate scenario than the one on this page, where after finding each other, the two AEAs negotiate and trade via a ledger. diff --git a/docs/skill-testing.md b/docs/skill-testing.md index 55bd92e7cc..535449770a 100644 --- a/docs/skill-testing.md +++ b/docs/skill-testing.md @@ -1,10 +1,12 @@ -In this guide we describe some of the tools the framework offers for testing skills. +# Testing Skills -## The `BaseSkillTestCase` class +In this guide, we describe some of the tools the framework offers for testing skills. -The framework offers a `BaseSkillTestCase` class which you can subclass and write your test cases with. +## The `BaseSkillTestCase` Class -Let us assume you want to test the `my_behaviour` behaviour of a `CustomSkill` skill you have developed. +The framework offers a `BaseSkillTestCase` class which you can subclass and write your test cases with. + +Let us assume you want to test the `my_behaviour` behaviour of a `CustomSkill` skill you have developed. You can create a `TestMyBehaviour` class which inherits `BaseSkillTestCase` as below: @@ -52,7 +54,7 @@ In the above, we make the `my_behaviour` behaviour object accessible for every t ### Skill and Skill Context -The skill object itself is exposed via a property. So you can access the skill object by `self.skill` and by extension all of its attributes. This crucially includes the complete `skill_context`. This means that for example, all of the components of the skill (e.g. behaviours, handlers, models) can be accessed via the skill context. +The skill object itself is exposed via a property. So you can access the skill object by `self.skill` and by extension all of its attributes. This crucially includes the complete `skill_context`. This means that for example, every component of the skill (e.g. behaviours, handlers, models) can be accessed via the skill context. In the above code snippet, `my_behavior` is accessed and exposed as a class attribute. Note accessing the skill context is slightly different in the above because it is a class method. If this was a test method, you could access the behaviour via `self.skill.skill_context.behaviours.my_behaviour`. @@ -85,19 +87,19 @@ agent_context = AgentContext( Some of the useful objects you can access in your test class for the loaded skill are below: -* `self.skill.skill_context.agent_address`: this is the agent identity the skill uses and is set to `"test_agent_address"`. -* `self.skill.skill_context.search_service_address`: this is the address of the search service and is set to `"dummy_search_service_address"`. -* `self.skill.skill_context.skill_id`: this is the id of the skill. -* `self.skill.skill_context.decision_maker_address`: this is the address of the decision maker and is set to `"dummy_decision_maker_address"`. +- `self.skill.skill_context.agent_address`: this is the agent identity the skill uses and is set to `"test_agent_address"`. +- `self.skill.skill_context.search_service_address`: this is the address of the search service and is set to `"dummy_search_service_address"`. +- `self.skill.skill_context.skill_id`: this is the id of the skill. +- `self.skill.skill_context.decision_maker_address`: this is the address of the decision maker and is set to `"dummy_decision_maker_address"`. ### Some Useful `BaseSkillTestCase` Methods There are a number of methods that `BaseSkillTestCase` offers to make testing skills easier. Some of these are mentioned below. For the rest, consult the API for `BaseSkillTestCase`: -* `self.get_quantity_in_outbox()`: gives you the number of messages which are in the outbox. After running a part of the skill which is expected to send messages, you can use this method to assert the correct number of messages are indeed sent. -* `self.get_message_from_outbox()`: gives you the last message in the outbox. Together with the above, you can use this method to grab the last message sent by the skill code you tested and check this is indeed the expected message. -* `self.message_has_attributes(actual_message: Message, message_type: Type[Message], **kwargs,)`: you can use this method in tandem with the above method to check that a message has the attributes you expect it to have. You have to supply it with the actual message (e.g. using `self.get_message_from_outbox()`), specify its expected type (e.g. `FipaMessage`), and any other attribute you expect the message to have (e.g. `message_id` is 1) may be provided via keyword arguments. -* `self.build_incoming_message`: this is an especially useful method to test handlers. Since handlers handle incoming messages, you can create an incoming message using this method to feed it to the handler and test its execution. +- `self.get_quantity_in_outbox()`: gives you the number of messages which are in the outbox. After running a part of the skill which is expected to send messages, you can use this method to assert the correct number of messages are indeed sent. +- `self.get_message_from_outbox()`: gives you the last message in the outbox. Together with the above, you can use this method to grab the last message sent by the skill code you tested and check this is indeed the expected message. +- `self.message_has_attributes(actual_message: Message, message_type: Type[Message], **kwargs,)`: you can use this method in tandem with the above method to check that a message has the attributes you expect it to have. You have to supply it with the actual message (e.g. using `self.get_message_from_outbox()`), specify its expected type (e.g. `FipaMessage`), and any other attribute you expect the message to have (e.g. `message_id` is 1) may be provided via keyword arguments. +- `self.build_incoming_message`: this is an especially useful method to test handlers. Since handlers handle incoming messages, you can create an incoming message using this method to feed it to the handler and test its execution. #### Checking Logger Output @@ -115,8 +117,8 @@ mock_logger.assert_any_call(logging.INFO, "some_logger_message") In the above, we mock the logger before running `my_behaviour`'s `act()` method and check that the string `"some_logger_message"` is indeed passed to the logger. -## Next steps +## Next Steps You can consult the `fetchai/generic_buyer` and `fetchai/generic_seller` skills and their associated tests here to study how `BaseSkillTestCase` can help you in testing your skills. -You can also refer to the API to study the different methods `BaseSkillTestCase` makes available to make testing your skills easier. +You can also refer to the API to study the different methods `BaseSkillTestCase` makes available to make testing your skills easier. diff --git a/docs/skill.md b/docs/skill.md index 3d21023e4a..ad85c9267f 100644 --- a/docs/skill.md +++ b/docs/skill.md @@ -1,15 +1,17 @@ +# Skills + `Skills` are the core focus of the framework's extensibility as they implement business logic to deliver economic value for the AEA. They are self-contained capabilities that AEAs can dynamically take on board, in order to expand their effectiveness in different situations. Skill components of an AEA A skill encapsulates implementations of the three abstract base classes `Handler`, `Behaviour`, `Model`, and is closely related with the abstract base class `Task`: -* `Handler`: each skill has zero, one or more `Handler` objects, each responsible for the registered messaging protocol. Handlers implement AEAs' **reactive** behaviour. If the AEA understands the protocol referenced in a received `Envelope`, the `Handler` reacts appropriately to the corresponding message. Each `Handler` is responsible for only one protocol. A `Handler` is also capable of dealing with internal messages (see next section). -* `Behaviour`: zero, one or more `Behaviours` encapsulate actions which further the AEAs goal and are initiated by internals of the AEA, rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of abstract base classes implementing different types of behaviours (e.g. cyclic/one-shot/finite-state-machine/etc.). -* `Model`: zero, one or more `Models` that inherit from the `Model` class. `Models` encapsulate custom objects which are made accessible to any part of a skill via the `SkillContext`. -* `Task`: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of skills, but `Task`s are declared in or from skills if a packaging approach for AEA creation is used. +- `Handler`: each skill has zero, one or more `Handler` objects, each responsible for the registered messaging protocol. Handlers implement AEAs' **reactive** behaviour. If the AEA understands the protocol referenced in a received `Envelope`, the `Handler` reacts appropriately to the corresponding message. Each `Handler` is responsible for only one protocol. A `Handler` is also capable of dealing with internal messages (see next section). +- `Behaviour`: zero, one or more `Behaviours` encapsulate actions which further the AEAs goal and are initiated by internals of the AEA, rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of abstract base classes implementing different types of behaviours (e.g. cyclic/one-shot/finite-state-machine/etc.). +- `Model`: zero, one or more `Models` that inherit from the `Model` class. `Models` encapsulate custom objects which are made accessible to any part of a skill via the `SkillContext`. +- `Task`: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of skills, but `Task`s are declared in or from skills if a packaging approach for AEA creation is used. -A skill can read (parts of) the state of the the AEA (as summarised in the `AgentContext`), and suggest actions to the AEA according to its specific logic. As such, more than one skill could exist per protocol, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms this means skills are horizontally arranged. +A skill can read (parts of) the state of the AEA (as summarised in the `AgentContext`), and propose actions to the AEA according to its specific logic. As such, more than one skill could exist per protocol, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms this means skills are horizontally arranged. For instance, an AEA who is trading goods, could subscribe to more than one skill, where each skill corresponds to a different trading strategy. The skills could then read the preference and ownership state of the AEA, and independently suggest profitable transactions. @@ -17,7 +19,7 @@ The framework places no limits on the complexity of skills. They can implement s The framework provides one default skill, called `error`. Additional skills can be added as packages. -## Independence of skills +## Independence of Skills Skills are `horizontally layered`, that is they run independently of each other. They also cannot access each other's state. @@ -33,15 +35,15 @@ For example, in the `ErrorHandler(Handler)` class, the code often grabs a refere ``` python self.context.outbox.put_message(message=reply) -``` +``` Moreover, you can read/write to the _agent context namespace_ by accessing the attribute `SkillContext.namespace`. Importantly, however, a skill does not have access to the context of another skill or protected AEA components like the `DecisionMaker`. -## What to code +## What to Code -Each of the skill classes has three methods that must be implemented. All of them include a `setup()` and `teardown()` method which the developer must implement. +Each of the skill classes has three methods that must be implemented. All of them include a `setup()` and `teardown()` method which the developer must implement. Then there is a specific method that the framework requires for each class. @@ -51,7 +53,7 @@ There can be none, one or more `Handler` class per skill. `Handler` classes can receive `Message` objects of one protocol type only. However, `Handler` classes can send `Envelope` objects of any type of protocol they require. -* `handle(self, message: Message)`: is where the skill receives a `Message` of the specified protocol and decides what to do with it. +- `handle(self, message: Message)`: is where the skill receives a `Message` of the specified protocol and decides what to do with it. A handler can be registered in one way: @@ -71,7 +73,7 @@ Conceptually, a `Behaviour` class contains the business logic specific to initi There can be one or more `Behaviour` classes per skill. The developer must create a subclass from the abstract class `Behaviour` to create a new `Behaviour`. -* `act(self)`: is how the framework calls the `Behaviour` code. +- `act(self)`: is how the framework calls the `Behaviour` code. A behaviour can be registered in two ways: @@ -82,14 +84,13 @@ The framework supports different types of behaviours: - `OneShotBehaviour`: this behaviour is executed only once. - `TickerBehaviour`: the `act()` method is called every `tick_interval`. E.g. if the `TickerBehaviour` subclass is instantiated - + There is another category of behaviours, called `CompositeBehaviour`: -- `SequenceBehaviour`: a sequence of `Behaviour` classes, executed +- `SequenceBehaviour`: a sequence of `Behaviour` classes, executed one after the other. - `FSMBehaviour`: a state machine of `State` behaviours. A state is in charge of scheduling the next state. - If your behaviour fits one of the above, we suggest subclassing your behaviour class with that behaviour class. Otherwise, you can always subclass the general-purpose `Behaviour` class. @@ -123,6 +124,7 @@ self.context.new_behaviours.put(HelloWorldBehaviour(name="hello_world", skill_co ``` Or, equivalently to the previous two code blocks: + ``` python def hello(): print("Hello, World!") @@ -131,9 +133,9 @@ self.context.new_behaviours.put(OneShotBehaviour(act=hello, name="hello_world", ``` The callable passed to the `act` parameter is equivalent to the implementation -of the `act` method described above. +of the `act` method described above. -The framework is then in charge of registering the behaviour and scheduling it +The framework is then in charge of registering the behaviour and scheduling it for execution. ### `tasks.py` @@ -142,22 +144,23 @@ Conceptually, a `Task` is where the developer codes any internal tasks the AEA r There can be one or more `Task` classes per skill. The developer subclasses abstract class `Task` to create a new `Task`. -* `execute(self)`: is how the framework calls a `Task`. +- `execute(self)`: is how the framework calls a `Task`. The `Task` class implements the functor pattern. -An instance of the `Task` class can be invoked as if it +An instance of the `Task` class can be invoked as if it were an ordinary function. Once completed, it will store the result in the property `result`. Raises error if the task has not been executed yet, or an error occurred during computation. We suggest using the `task_manager`, accessible through the skill context, -to manage long-running tasks. The task manager uses `multiprocessing` to -schedule tasks, so be aware that the changes on the task object will +to manage long-running tasks. The task manager uses `multiprocessing` to +schedule tasks, so be aware that the changes on the task object will not be updated. Here's an example: In `tasks.py`: + ``` python from aea.skills.tasks import Task @@ -193,6 +196,7 @@ class LongTask(Task): ``` In `behaviours.py`: + ``` python from aea.skills.behaviours import TickerBehaviour @@ -228,17 +232,19 @@ class MyBehaviour(TickerBehaviour): The developer might want to add other classes on the context level which are shared equally across the `Handler`, `Behaviour` and `Task` classes. To this end, the developer can subclass an abstract `Model`. These models are made available on the context level upon initialization of the AEA. Say, the developer has a class called `SomeModel` + ``` python class SomeModel(Model): ... ``` Then, an instance of this class is available on the context level like so: + ``` python some_model = self.context.some_model -``` +``` -### Skill configuration +### Skill Configuration Each skill has a `skill.yaml` configuration file which lists all `Behaviour`, `Handler`, and `Task` objects pertaining to the skill. @@ -265,22 +271,20 @@ protocols: - fetchai/default:1.1.6 ``` - -## Error skill +## Error Skill All AEAs have a default `error` skill that contains error handling code for a number of scenarios: -* Received envelopes with unsupported protocols -* Received envelopes with unsupported skills (i.e. protocols for which no handler is registered) -* Envelopes with decoding errors -* Invalid messages with respect to the registered protocol +- Received envelopes with unsupported protocols +- Received envelopes with unsupported skills (i.e. protocols for which no handler is registered) +- Envelopes with decoding errors +- Invalid messages with respect to the registered protocol The error skill relies on the `fetchai/default:1.0.0` protocol which provides error codes for the above. +## Custom Error Handler -## Custom Error handler - -The framework implements a default `ErrorHandler`. +The framework implements a default `ErrorHandler`. You can implement your own and mount it. The easiest way to do this is to run the following command to scaffold a custom `ErrorHandler`: ``` bash @@ -288,7 +292,4 @@ aea scaffold error-handler ``` Now you will see a file called `error_handler.py` in the AEA project root. -You can then implement your own custom logic to process messages. - - -
+You can then implement your own custom logic to process messages. diff --git a/docs/standalone-transaction.md b/docs/standalone-transaction.md index 64a141d2a4..e4eda05418 100644 --- a/docs/standalone-transaction.md +++ b/docs/standalone-transaction.md @@ -1,7 +1,10 @@ +# Create Stand-Alone Transaction + In this guide, we will generate some wealth for the Fetch.ai testnet and create a standalone transaction. After the completion of the transaction, we get the transaction digest. With this we can search for the transaction on the block explorer This guide requires the `aea-ledger-fetchai` plug-in installed in your Python environment: -```bash + +``` bash pip install aea-ledger-fetchai ``` @@ -24,7 +27,7 @@ FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" ``` -## Create the private keys +## Create the Private Keys ``` python # Create a private keys @@ -36,7 +39,7 @@ FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" ) ``` -## Create the wallets +## Create the Wallets Once we created the private keys we need to generate the wallets. @@ -46,10 +49,11 @@ Once we created the private keys we need to generate the wallets. wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2}) ``` -## Generate wealth +## Generate Wealth Since we want to send funds from `wallet_1` to `wallet_2`, we need to generate some wealth for the `wallet_1`. We can do this with the following code + ``` python # Generate some wealth try_generate_testnet_wealth( @@ -57,7 +61,7 @@ do this with the following code ) ``` -## Send transaction +## Send Transaction Finally, we create a transaction that sends the funds to the `wallet_2` @@ -87,75 +91,74 @@ Finally, we create a transaction that sends the funds to the `wallet_2` logger.info("The transaction digest is {}".format(transaction_digest)) ``` -
Stand-alone transaction full code - -``` python -import logging - -from aea_ledger_fetchai import FetchAICrypto - -from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth -from aea.crypto.ledger_apis import LedgerApis -from aea.crypto.wallet import Wallet - - -logger = logging.getLogger("aea") -logging.basicConfig(level=logging.INFO) - -FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" -FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" - - -def run(): - """Run demo.""" - - # Create a private keys - create_private_key( - FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1 - ) - create_private_key( - FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2 - ) - - # Set up the wallets - wallet_1 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_1}) - wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2}) - - # Generate some wealth - try_generate_testnet_wealth( - FetchAICrypto.identifier, wallet_1.addresses[FetchAICrypto.identifier] - ) - - logger.info( - "Sending amount to {}".format(wallet_2.addresses.get(FetchAICrypto.identifier)) - ) - - # Create the transaction and send it to the ledger. - tx_nonce = LedgerApis.generate_tx_nonce( - FetchAICrypto.identifier, - wallet_2.addresses.get(FetchAICrypto.identifier), - wallet_1.addresses.get(FetchAICrypto.identifier), - ) - transaction = LedgerApis.get_transfer_transaction( - identifier=FetchAICrypto.identifier, - sender_address=wallet_1.addresses.get(FetchAICrypto.identifier), - destination_address=wallet_2.addresses.get(FetchAICrypto.identifier), - amount=1, - tx_fee=1, - tx_nonce=tx_nonce, - ) - signed_transaction = wallet_1.sign_transaction( - FetchAICrypto.identifier, transaction - ) - transaction_digest = LedgerApis.send_signed_transaction( - FetchAICrypto.identifier, signed_transaction - ) - - logger.info("Transaction complete.") - logger.info("The transaction digest is {}".format(transaction_digest)) - - -if __name__ == "__main__": - run() -``` -
+??? note "Stand-alone transaction full code:" + + ``` python + import logging + + from aea_ledger_fetchai import FetchAICrypto + + from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth + from aea.crypto.ledger_apis import LedgerApis + from aea.crypto.wallet import Wallet + + + logger = logging.getLogger("aea") + logging.basicConfig(level=logging.INFO) + + FETCHAI_PRIVATE_KEY_FILE_1 = "fetchai_private_key_1.txt" + FETCHAI_PRIVATE_KEY_FILE_2 = "fetchai_private_key_2.txt" + + + def run(): + """Run demo.""" + + # Create a private keys + create_private_key( + FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1 + ) + create_private_key( + FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2 + ) + + # Set up the wallets + wallet_1 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_1}) + wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2}) + + # Generate some wealth + try_generate_testnet_wealth( + FetchAICrypto.identifier, wallet_1.addresses[FetchAICrypto.identifier] + ) + + logger.info( + "Sending amount to {}".format(wallet_2.addresses.get(FetchAICrypto.identifier)) + ) + + # Create the transaction and send it to the ledger. + tx_nonce = LedgerApis.generate_tx_nonce( + FetchAICrypto.identifier, + wallet_2.addresses.get(FetchAICrypto.identifier), + wallet_1.addresses.get(FetchAICrypto.identifier), + ) + transaction = LedgerApis.get_transfer_transaction( + identifier=FetchAICrypto.identifier, + sender_address=wallet_1.addresses.get(FetchAICrypto.identifier), + destination_address=wallet_2.addresses.get(FetchAICrypto.identifier), + amount=1, + tx_fee=1, + tx_nonce=tx_nonce, + ) + signed_transaction = wallet_1.sign_transaction( + FetchAICrypto.identifier, transaction + ) + transaction_digest = LedgerApis.send_signed_transaction( + FetchAICrypto.identifier, signed_transaction + ) + + logger.info("Transaction complete.") + logger.info("The transaction digest is {}".format(transaction_digest)) + + + if __name__ == "__main__": + run() + ``` diff --git a/docs/step-one.md b/docs/step-one.md index f5e818e7fe..bb6b5bdabe 100644 --- a/docs/step-one.md +++ b/docs/step-one.md @@ -1,14 +1,12 @@ +# Ways to Build an AEA + There are a number of ways to build an AEA: -
    -
  • To start with, we recommended you build an AEA project step-by-step with the CLI tool as demonstrated in the quick start guide and described here. -
  • Using the CLI aea fetch command, pull in an already built project and run as is or extend it to your needs.
  • -
  • The last option is to build an AEA programmatically as described here.
  • -
+ +- To start with, we recommended you build an AEA project step-by-step with the CLI tool as demonstrated in the quick start guide and described here. +- Using the CLI `aea fetch` command, pull in an already built project and run as is or extend it to your needs. +- The last option is to build an AEA programmatically as described here. Sometimes, an AEA is more than is required for the task at hand. In particular, an AEA is much more than just an agent. In those cases, we suggest you have a look at the following two guides: -
    -
  • the AEA vs Agents guide shows the difference between an agent and an AEA in code, -
  • the Use multiplexer standalone guide shows how to use the multiplexer on its own to receive and send envelopes. -
-
\ No newline at end of file +- the AEA vs Agents guide shows the difference between an agent and an AEA in code, +- the Use multiplexer standalone guide shows how to use the multiplexer on its own to receive and send envelopes. diff --git a/docs/tac-skills-contract.md b/docs/tac-skills-contract.md index 909369e23c..f8f2173ef5 100644 --- a/docs/tac-skills-contract.md +++ b/docs/tac-skills-contract.md @@ -1,13 +1,15 @@ +# TAC Skills Ledger-Based + The AEA TAC - trading agent competition - skills demonstrate an interaction between multiple AEAs in a game. There are two types of AEAs: -* The `tac_controller` which coordinates the game. -* The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility. +- The `tac_controller` which coordinates the game. +- The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility. ## Discussion -This demo shows how agents negotiate autonomously with each other while they pursue their goals by participating in the Trading Agents Competition (TAC). +This demo shows how agents negotiate autonomously with each other while they pursue their goals by participating in the Trading Agents Competition (TAC). The demo can be run against Fetchai or Ethereum ledger. Transactions are validated on an ERC1155 smart contract on the Fetchai Dorado or a local Ganache Ethereum testnet. @@ -18,13 +20,15 @@ In the following video we discuss the framework and TAC in more detail: ## Communication There are two types of interactions: + - between the controller and participants (game management communication) - between the participants (negotiations) -### Registration communication -This diagram shows the communication between the various entities during the registration phase. +### Registration Communication -
+This diagram shows the communication between the various entities during the registration phase. + +``` mermaid sequenceDiagram participant Agent_2 participant Agent_1 @@ -50,12 +54,13 @@ This diagram shows the communication between the various entities during the reg deactivate Agent_2 deactivate Search deactivate Controller -
+``` -### Transaction communication -This diagram shows the communication between two AEAs and a controller. In this case, we have a `Seller_Agent` which is set up as a seller (and registers itself as such with the controller during the registration phase). We also have the `Searching_Agent` which is set up to search for sellers. +### Transaction Communication -
+This diagram shows the communication between two AEAs and a controller. In this case, we have a `Seller_Agent` which is set up as a seller (and registers itself as such with the controller during the registration phase). We also have the `Searching_Agent` which is set up to search for sellers. + +``` mermaid sequenceDiagram participant Buyer_Agent participant Seller_Agent @@ -83,72 +88,68 @@ This diagram shows the communication between two AEAs and a controller. In this deactivate Seller_Agent deactivate Search deactivate Controller - -
+``` In the above case, the proposal received contains a set of goods to sell and an associated price. The buyer AEA needs to determine if this is a good deal for them, and if so, it accepts. -There is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead be a list of goods that the buyer wishes to buy and the price it is willing to pay for them. - +There is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead be a list of goods that the buyer wishes to buy and the price it is willing to pay for them. -## Preparation instructions +## Preparation Instructions ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -## Demo instructions (Fetchai): +## Demo Instructions (Fetchai) Follow this instruction to run TAC against the fetch.ai Dorado testnet. -### Fetch TAC controller AEA +### Fetch TAC Controller AEA In the root directory, fetch the controller AEA: -``` bash -aea fetch fetchai/tac_controller_contract:0.32.4 -cd tac_controller_contract -aea install -aea build -``` -
Alternatively, create from scratch. -

- -The following steps create the controller from scratch: ``` bash -aea create tac_controller_contract +aea fetch fetchai/tac_controller_contract:0.32.4 cd tac_controller_contract -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_control_contract:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc -aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'[{"identifier": "acn", "ledger_id": "fetchai", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' aea install aea build ``` -

-
- -### Fetch the TAC participant AEAs +??? note "Alternatively, create from scratch:" + The following steps create the controller from scratch: + + ``` bash + aea create tac_controller_contract + cd tac_controller_contract + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_control_contract:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc + aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '[{"identifier": "acn", "ledger_id": "fetchai", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' + aea install + aea build + ``` + +### Fetch the TAC Participant AEAs In separate terminals, in the root directory, fetch at least two participants: + ``` bash aea fetch fetchai/tac_participant_contract:0.22.4 --alias tac_participant_one cd tac_participant_one @@ -161,110 +162,111 @@ aea install aea build ``` -
Alternatively, create from scratch. -

- -In a separate terminal, in the root directory, create at least two tac participant AEAs: -``` bash -aea create tac_participant_one -aea create tac_participant_two -``` - -Build participant one: -``` bash -cd tac_participant_one -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc -aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool -aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'''[{"identifier": "acn", "ledger_id": "fetchai", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' -aea install -aea build -``` - -Then, build participant two: -``` bash -cd tac_participant_two -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc -aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool -aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'''[{"identifier": "acn", "ledger_id": "fetchai", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' -aea install -aea build -``` - -

-
- -### Add keys for all AEAs +??? note "Alternatively, create from scratch:" + In a separate terminal, in the root directory, create at least two tac participant AEAs: + + ``` bash + aea create tac_participant_one + aea create tac_participant_two + ``` + + Build participant one: + + ``` bash + cd tac_participant_one + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc + aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool + aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '''[{"identifier": "acn", "ledger_id": "fetchai", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' + aea install + aea build + ``` + + Then, build participant two: + + ``` bash + cd tac_participant_two + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc + aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool + aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '''[{"identifier": "acn", "ledger_id": "fetchai", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' + aea install + aea build + ``` + +### Add Keys for All AEAs For every AEA in the competition (controller and participants): First generate and add a private key: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then create and add a separate private key for secure communication: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Update the game parameters in the controller +### Update the Game Parameters in the Controller In the tac controller project, get and set the registration start time (set it to at least 5 minutes in the future): @@ -274,23 +276,23 @@ aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args ``` To set the registration time, you may find handy the following command: + ``` bash aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time "$(date -d "5 minutes" +'%d %m %Y %H:%M')" ``` - -### Update the connection parameters +### Update the Connection Parameters Update the connection parameters of the TAC participants to allow them to connect to the same local agent communication network as the TAC controller. First, retrieve controller's local ACN address by running the following in the controller agent's project terminal: -```bash +``` bash aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri ``` - Then, in participant one, run this command (replace `SOME_ADDRESS` with the value you retrieved above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -303,6 +305,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ ``` Do the same in participant two (beware of the different port numbers): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -314,11 +317,11 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ }' ``` -## Fund agents' accounts +## Fund Agents' Accounts Retrieve the address of each agent (in each terminal): -```bash +``` bash aea get-address fetchai ``` @@ -333,13 +336,15 @@ aea get-wealth fetchai ### Run the AEAs First, launch the `tac_contract_controller` then the participants by executing the following from their respective terminals: + ``` bash aea run ``` -The CLI tool supports launching several agents at once. +The CLI tool supports launching several agents at once. For example, assuming you followed the tutorial, you can launch both TAC participant agents as follows from the root directory (ensure you run the controller agent first as above): + ``` bash aea launch tac_participant_one tac_participant_two ``` @@ -351,64 +356,63 @@ in the same process. ### Cleaning up When you're finished, delete your AEAs: + ``` bash aea delete tac_controller_contract aea delete tac_participant_one aea delete tac_participant_two ``` -## Demo instructions (Ethereum): +## Demo Instructions (Ethereum) Follow this instruction to run TAC against a local Ganache Ethereum test-net. -### Create TAC controller AEA +### Create TAC Controller AEA In the root directory, fetch the controller AEA: -``` bash -aea fetch fetchai/tac_controller_contract:0.32.4 -cd tac_controller_contract -aea install -aea build -``` -
Alternatively, create from scratch. -

- -The following steps create the controller from scratch: ``` bash -aea create tac_controller_contract +aea fetch fetchai/tac_controller_contract:0.32.4 cd tac_controller_contract -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_control_contract:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger ethereum -aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum -aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' aea install aea build ``` -

-
- -### Fetch the TAC participant AEAs +??? note "Alternatively, create from scratch:" + The following steps create the controller from scratch: + + ``` bash + aea create tac_controller_contract + cd tac_controller_contract + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_control_contract:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger ethereum + aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum + aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' + aea install + aea build + ``` + +### Fetch the TAC Participant AEAs In separate terminals, in the root directory, fetch at least two participants: + ``` bash aea fetch fetchai/tac_participant_contract:0.22.4 --alias tac_participant_one cd tac_participant_one @@ -421,121 +425,122 @@ aea install aea build ``` -
Alternatively, create from scratch. -

- -In a separate terminal, in the root directory, create at least two tac participant AEAs: -``` bash -aea create tac_participant_one -aea create tac_participant_two -``` - -Build participant one: -``` bash -cd tac_participant_one -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger ethereum -aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum -aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool -aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'''[{"identifier": "acn", "ledger_id": "ethereum", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' -aea install -aea build -``` - -Then, build participant two: -``` bash -cd tac_participant_two -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, - "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger ethereum -aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum -aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool -aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool -aea config set --type dict agent.default_routing \ -'{ - "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ -'''[{"identifier": "acn", "ledger_id": "ethereum", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' -aea install -aea build -``` - -

-
- -### Configure the agents to use Ethereum +??? note "Alternatively, create from scratch:" + In a separate terminal, in the root directory, create at least two tac participant AEAs: + + ``` bash + aea create tac_participant_one + aea create tac_participant_two + ``` + + Build participant one: + + ``` bash + cd tac_participant_one + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger ethereum + aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum + aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool + aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '''[{"identifier": "acn", "ledger_id": "ethereum", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' + aea install + aea build + ``` + + Then, build participant two: + + ``` bash + cd tac_participant_two + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"}, + "aea-ledger-ethereum": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger ethereum + aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum + aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool + aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool + aea config set --type dict agent.default_routing \ + '{ + "fetchai/contract_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ + '''[{"identifier": "acn", "ledger_id": "ethereum", "message_format": "'{public_key}'", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]''' + aea install + aea build + ``` + +### Configure the Agents to Use Ethereum Run the following in every AEA's terminal: -```bash +``` bash aea config set agent.default_ledger ethereum json=$(printf '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "message_format": "{public_key}", "save_path": ".certs/conn_cert.txt"}]') aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests "$json" aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum ``` -### Add keys for all AEAs +### Add Keys for All AEAs For every AEA in the competition (controller and participants): First generate and add a private key: + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` Then create and add a separate private key for secure communication: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Update the game parameters in the controller +### Update the Game Parameters in the Controller In the tac controller project, get and set the registration start time (set it to at least 5 minutes in the future): @@ -545,22 +550,23 @@ aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args ``` To set the registration time, you may find handy the following command: + ``` bash aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time "$(date -d "5 minutes" +'%d %m %Y %H:%M')" ``` - -### Update the connection parameters +### Update the Connection Parameters Update the connection parameters of the TAC participants to allow them to connect to the same local agent communication network as the TAC controller. First, retrieve controller's local ACN address by running the following in the controller agent's project terminal: -```bash +``` bash aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri ``` Then, in participant one, run this command (replace `SOME_ADDRESS` with the value you retrieved above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -573,6 +579,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ ``` Do the same in participant two (beware of the different port numbers): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -584,9 +591,10 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ }' ``` -## Fund agents' accounts +## Fund Agents' Accounts Run a local Ganache Ethereum test-net with funds for the addresses of the three AEAs in this demo: + ``` bash docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat tac_controller_contract/ethereum_private_key.txt),1000000000000000000000" --account="$(cat tac_participant_one/ethereum_private_key.txt),1000000000000000000000" --account="$(cat tac_participant_two/ethereum_private_key.txt),1000000000000000000000" ``` @@ -602,13 +610,15 @@ You should get `1000000000000000000000`. ### Run the AEAs First, launch the `tac_contract_controller` then the participants by executing the following from their respective terminals: + ``` bash aea run ``` -The CLI tool supports launching several agents at once. +The CLI tool supports launching several agents at once. For example, assuming you followed the tutorial, you can launch both TAC participant agents as follows from the root directory (ensure you run the controller agent first as above): + ``` bash aea launch tac_participant_one tac_participant_two ``` @@ -620,6 +630,7 @@ in the same process. ### Cleaning up When you're finished, delete your AEAs: + ``` bash aea delete tac_controller_contract aea delete tac_participant_one diff --git a/docs/tac-skills.md b/docs/tac-skills.md index 2154767d12..69284df352 100644 --- a/docs/tac-skills.md +++ b/docs/tac-skills.md @@ -1,25 +1,28 @@ +# TAC Skills + The AEA TAC - trading agent competition - skills demonstrate an interaction between multiple AEAs in a game. There are two types of AEAs: -* The `tac_controller` which coordinates the game. -* The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility. +- The `tac_controller` which coordinates the game. +- The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility. ## Discussion -The scope of this specific demo is to demonstrate how the agents negotiate autonomously with each other while they pursue their goals by playing a game of TAC. Another AEA has the role of the controller and it's responsible for calculating the revenue for each participant and if the transaction messages are valid. Transactions are settled with the controller agent rather than against a public ledger. +The scope of this specific demo is to demonstrate how the agents negotiate autonomously with each other while they pursue their goals by playing a game of TAC. Another AEA has the role of the controller, responsible for calculating the revenue for each participant and checking if the transaction messages are valid. Transactions are settled with the controller agent rather than against a public ledger. ## Communication There are two types of interactions: + - between the participants and the controller, the game communication - between the participants, the negotiation -### Registration communication +### Registration Communication -This diagram shows the communication between the various entities during the registration phase. +This diagram shows the communication between the various entities during the registration phase. -
+``` mermaid sequenceDiagram participant Agent_2 participant Agent_1 @@ -46,13 +49,13 @@ This diagram shows the communication between the various entities during the reg deactivate Agent_2 deactivate Search deactivate Controller -
+``` -### Transaction communication +### Transaction Communication This diagram shows the communication between two AEAs and the controller. In this case, we have an AEA in the role of the seller, referred to as `Seller_Agent`. We also have an AEA in the role of the buyer, referred to as `Buyer_Agent`. During a given TAC, an AEA can be in both roles simultaneously in different bilateral interactions. -
+``` mermaid sequenceDiagram participant Buyer_Agent participant Seller_Agent @@ -80,22 +83,21 @@ This diagram shows the communication between two AEAs and the controller. In thi deactivate Seller_Agent deactivate Search deactivate Controller - -
+``` In the above case, the proposal received contains a set of good which the seller wishes to sell and a cost of them. The buyer AEA needs to determine if this is a good deal for them and if so, it accepts. -There is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead, be a list of goods that the buyer wishes to buy and the price it is willing to pay for them. +There is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead, be a list of goods that the buyer wishes to buy and the price it is willing to pay for them. -## Option 1: AEA Manager approach +## Option 1: AEA Manager Approach -Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. -### Preparation instructions +### Preparation Instructions Install the AEA Manager. -### Demo instructions +### Demo Instructions The following steps assume you have launched the AEA Manager Desktop app. @@ -109,88 +111,88 @@ The following steps assume you have launched the AEA Manager Desktop app. 5. Run the `controller` AEA. Navigate to its logs and copy the multiaddress displayed. Stop the `controller`. -5. Navigate to the settings of `participant_1` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11001", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9001", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9001" -} -``` +6. Navigate to the settings of `participant_1` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -6. Navigate to the settings of `participant_2` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11002", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9002", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9002" -} -``` + ``` bash + { + "delegate_uri": "127.0.0.1:11001", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9001", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9001" + } + ``` + +7. Navigate to the settings of `participant_2` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): + + ``` bash + { + "delegate_uri": "127.0.0.1:11002", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9002", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9002" + } + ``` -7. You may add more participants by repeating steps 3 (with an updated name) and 6 (bumping the port numbers. See the difference between steps 5 and 6). +8. You may add more participants by repeating steps 3 (with an updated name) and 6 (bumping the port numbers. See the difference between steps 5 and 6). -8. Run the `controller`, then `participant_1` and `participant_2` (and any other participants you added). +9. Run the `controller`, then `participant_1` and `participant_2` (and any other participants you added). In the `controller`'s log, you should see the details of the transactions participants submit as well as changes in their scores and holdings. In participants' logs, you should see the agents trading. -
-## Option 2: CLI approach +## Option 2: CLI Approach Follow this approach when using the `aea` CLI. -## Preparation instructions +## Preparation Instructions ### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -## Demo instructions: +## Demo Instructions -### Create TAC controller AEA +### Create TAC Controller AEA In the root directory, fetch the controller AEA: -``` bash -aea fetch fetchai/tac_controller:0.30.4 -cd tac_controller -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the controller from scratch: ``` bash -aea create tac_controller +aea fetch fetchai/tac_controller:0.30.4 cd tac_controller -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_control:0.25.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set --type dict agent.default_routing \ -'{ - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- -### Create the TAC participant AEAs +??? note "Alternatively, create from scratch:" + + The following steps create the controller from scratch: + + ``` bash + aea create tac_controller + cd tac_controller + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_control:0.25.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set --type dict agent.default_routing \ + '{ + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +### Create the TAC Participant AEAs In a separate terminal, in the root directory, fetch at least two participants: + ``` bash aea fetch fetchai/tac_participant:0.32.4 --alias tac_participant_one cd tac_participant_one @@ -202,94 +204,96 @@ cd tac_participant_two aea build ``` -
Alternatively, create from scratch. -

- -In a separate terminal, in the root directory, create at least two tac participant AEAs: -``` bash -aea create tac_participant_one -aea create tac_participant_two -``` - -Build participant one: -``` bash -cd tac_participant_one -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea install -aea build -``` - -Then, build participant two: -``` bash -cd tac_participant_two -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/tac_participation:0.25.5 -aea add skill fetchai/tac_negotiation:0.29.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set agent.default_ledger fetchai -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' -aea config set --type dict agent.decision_maker_handler \ -'{ - "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", - "file_path": null -}' -aea install -aea build -``` - -

-
- -### Add keys for all AEAs +??? note "Alternatively, create from scratch:" + + In a separate terminal, in the root directory, create at least two tac participant AEAs: + + ``` bash + aea create tac_participant_one + aea create tac_participant_two + ``` + + Build participant one: + + ``` bash + cd tac_participant_one + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea install + aea build + ``` + + Then, build participant two: + + ``` bash + cd tac_participant_two + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/tac_participation:0.25.5 + aea add skill fetchai/tac_negotiation:0.29.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set agent.default_ledger fetchai + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea config set --type dict agent.decision_maker_handler \ + '{ + "dotted_path": "aea.decision_maker.gop:DecisionMakerHandler", + "file_path": null + }' + aea install + aea build + ``` + +### Add Keys for All AEAs Create the private key for the AEA for Fetch.ai `Dorado`: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -### Update the game parameters in the controller +### Update the Game Parameters in the Controller Navigate to the tac controller project, then use the command line to get and set the start time (set it to at least two minutes in the future): @@ -299,11 +303,12 @@ aea config set vendor.fetchai.skills.tac_control.models.parameters.args.registra ``` To set the registration time, you may find handy the following command: + ``` bash aea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time "$(date -d "2 minutes" +'%d %m %Y %H:%M')" ``` -### Update the connection parameters +### Update the Connection Parameters Briefly run the controller AEA: @@ -314,6 +319,7 @@ aea run Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) Then, in the participant one, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -326,6 +332,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ ``` Do the same in participant two (beware of the different port numbers): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -339,10 +346,10 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ This allows the TAC participants to connect to the same local agent communication network as the TAC controller. - ### Run the AEAs First, launch the `tac_controller`: + ``` bash aea run ``` @@ -352,6 +359,7 @@ at once. For example, assuming you followed the tutorial, you can launch both the TAC agents as follows from the root directory: + ``` bash aea launch tac_participant_one tac_participant_two ``` @@ -363,8 +371,9 @@ in the same process. ### Cleaning up When you're finished, delete your AEAs: + ``` bash aea delete tac_controller aea delete tac_participant_one aea delete tac_participant_two -``` \ No newline at end of file +``` diff --git a/docs/tac.md b/docs/tac.md index 74b60dc6ac..bc060cbd7d 100644 --- a/docs/tac.md +++ b/docs/tac.md @@ -1,16 +1,19 @@ -The original TAC has its own repo. +# TAC External App -Follow the instructions below to build and run the TAC demo. +!!! note + This app is no longer maintained. + +The original TAC has its own repo. +Follow the instructions below to build and run the TAC demo. ## Requirements Make sure you are running Docker and Docker Compose. +## Quick Start -## Quick start - -Clone the repo to include sub-modules. +Clone the repo to include submodules. ``` bash git clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac @@ -24,7 +27,6 @@ which pipenv If you don't have it, install it. Instructions are here. - Create and launch a virtual environment. ``` bash @@ -37,13 +39,12 @@ Install the dependencies. pipenv install ``` - Install the package. + ``` bash python setup.py install ``` - Run the launch script. This may take a while. ``` bash @@ -58,7 +59,7 @@ In the Environment tab, make sure you have the `tac_controller` environment sele AEA Visdom UI -## Alternative build and run +## Alternative Build and Run In a new terminal window, clone the repo, build the sandbox, and launch it. @@ -79,7 +80,7 @@ python templates/v1/basic.py --name my_agent --dashboard Click through to the controller GUI. -## Possible gotchas +## Possible Gotchas Stop all running containers before restart. @@ -93,7 +94,3 @@ To remove all images, run the following command. # mac docker ps -q | xargs docker stop ; docker system prune -a ``` - - - -
\ No newline at end of file diff --git a/docs/thermometer-skills.md b/docs/thermometer-skills.md index 679eaaac19..8dac120a67 100644 --- a/docs/thermometer-skills.md +++ b/docs/thermometer-skills.md @@ -1,7 +1,9 @@ -The AEA thermometer skills demonstrate an interaction between two AEAs, one purchasing temperature data from the other. +# Thermometer Skills -* The provider of thermometer data (the `thermometer`). -* The buyer of thermometer data (the `thermometer_client`). +The AEA thermometer skills demonstrate an interaction between two AEAs, one purchasing temperature data from the other. + +- The provider of thermometer data (the `thermometer`). +- The buyer of thermometer data (the `thermometer_client`). ## Discussion @@ -9,9 +11,9 @@ This demo aims to demonstrate how to create a very simple AEA with the usage of ## Communication -This diagram shows the communication between the various entities as data is successfully sold by the thermometer AEA to the client AEA. +This diagram shows the communication between the various entities as data is successfully sold by the thermometer AEA to the client AEA. -
+``` mermaid sequenceDiagram participant Search participant Client_AEA @@ -39,19 +41,17 @@ This diagram shows the communication between the various entities as data is suc deactivate Search deactivate Thermometer_AEA deactivate Blockchain - -
-
+``` -## Option 1: AEA Manager approach +## Option 1: AEA Manager Approach -Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. -### Preparation instructions +### Preparation Instructions Install the AEA Manager. -### Demo instructions +### Demo Instructions The following steps assume you have launched the AEA Manager Desktop app. @@ -64,144 +64,145 @@ The following steps assume you have launched the AEA Manager Desktop app. 4. Run the `my_thermometer_aea` AEA. Navigate to its logs and copy the multiaddress displayed. 5. Navigate to the settings of the `my_thermometer_client` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11001", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9001", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9001" -} -``` + + ``` bash + { + "delegate_uri": "127.0.0.1:11001", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9001", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9001" + } + ``` 6. Run the `my_thermometer_client`. In the AEA's logs, you should see the agent trading successfully. -
-## Option 2: CLI approach +## Option 2: CLI Approach Follow this approach when using the `aea` CLI. -### Preparation instructions - +### Preparation Instructions + #### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -### Demo instructions +### Demo Instructions A demo to run the thermometer scenario with a true ledger transaction This demo assumes the buyer trusts the seller AEA to send the data upon successful payment. -#### Create thermometer AEA +#### Create Thermometer AEA First, fetch the thermometer AEA: -``` bash -aea fetch fetchai/thermometer_aea:0.30.4 --alias my_thermometer_aea -cd my_thermometer_aea -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the thermometer AEA from scratch: ``` bash -aea create my_thermometer_aea +aea fetch fetchai/thermometer_aea:0.30.4 --alias my_thermometer_aea cd my_thermometer_aea -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/thermometer:0.27.5 aea install aea build -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' ``` -

-
- -#### Create thermometer client +??? note "Alternatively, create from scratch:" + The following steps create the thermometer AEA from scratch: + + ``` bash + aea create my_thermometer_aea + cd my_thermometer_aea + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/thermometer:0.27.5 + aea install + aea build + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + ``` + +#### Create Thermometer Client Then, fetch the thermometer client AEA: -``` bash -aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client -cd my_thermometer_client -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the thermometer client from scratch: ``` bash -aea create my_thermometer_client +aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client cd my_thermometer_client -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/thermometer_client:0.26.5 aea install aea build -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' ``` -

-
- -#### Add keys for the thermometer AEA +??? note "Alternatively, create from scratch:" + The following steps create the thermometer client from scratch: + + ``` bash + aea create my_thermometer_client + cd my_thermometer_client + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/thermometer_client:0.26.5 + aea install + aea build + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + ``` + +#### Add Keys for the Thermometer AEA First, create the private key for the thermometer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -#### Add keys and generate wealth for the thermometer client AEA +#### Add Keys and Generate Wealth for the Thermometer Client AEA The thermometer client needs to have some wealth to purchase the thermometer information. First, create the private key for the thermometer client AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for your thermometer client based on the network you want to transact with. On the Fetch.ai `testnet` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` @@ -219,6 +220,7 @@ aea run Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) This is the entry peer address for the local agent communication network created by the thermometer AEA. Then, in the thermometer client, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -229,9 +231,11 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + This allows the thermometer client to connect to the same local agent communication network as the thermometer AEA. Then run the thermometer client AEA: + ``` bash aea run ``` @@ -247,5 +251,3 @@ cd .. aea delete my_thermometer_aea aea delete my_thermometer_client ``` - -
\ No newline at end of file diff --git a/docs/trust.md b/docs/trust.md index b7d20f5d92..1bccb3428a 100644 --- a/docs/trust.md +++ b/docs/trust.md @@ -1,11 +1,11 @@ +# Trust Minimisation + AEA applications have different requirements for _trustlessness_ or _trust minimisation_. For example, using the AEA weather skills demo _without_ ledger payments means that the client has to trust the weather station to send the weather data it purchased and that this data is in fact valid. Similarly, the weather station must trust that the client somehow sends the payment amount to which they agreed. -A step up, if you run the weather skills demo with a ledger (e.g. Fetch.ai or Ethereum) then the client must still trust that the weather station sends valid data. However, all payment transactions are executed via the public ledger. This means the weather station no longer needs to trust the client for payment and can verify whether the transactions take place on the public ledger. +A step-up, if you run the weather skills demo with a ledger (e.g. Fetch.ai or Ethereum) then the client must still trust that the weather station sends valid data. However, all payment transactions are executed via the public ledger. This means the weather station no longer needs to trust the client for payment and can verify whether the transactions take place on the public ledger. We can further minimise trust requirements by incorporating a third party as an arbitrator or escrow implemented in a smart contract to further reduce trust requirements. However, in the current weather skills demo, there are limits to trustlessness as the station ultimately offers unverifiable data. Another example of minimising trust, is applications with (non-fungible) token transactions involving atomic swaps where trustlessness is clearly satisfied (e.g. in the TAC demo). - -
diff --git a/docs/upgrading.md b/docs/upgrading.md index 78fc5f6940..7fc1ae037f 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -1,3 +1,5 @@ +# Upgrading + This page provides some tips on how to upgrade AEA projects between different versions of the AEA framework. For full release notes check the AEA repo. The primary tool for upgrading AEA projects is the `aea upgrade` command in the CLI. @@ -20,7 +22,6 @@ Update the packages to the latest versions (especially protocols). Regenerate your own written protocols (protocol generator was updated) - ## `v1.1.1` to `v1.2.0` Ensure you update the plugins to their latest version (fetchai and cosmos plugins are changed in this release) @@ -89,7 +90,7 @@ Take special care when upgrading to `v0.11.0`. We introduced several breaking ch We removed the CLI GUI. It was not used by anyone as far as we know and needs to be significantly improved. Soon we will release the AEA Manager App to make up for this. -### Message routing +### Message Routing Routing has been completely revised and simplified. The new message routing logic is described here. @@ -99,7 +100,7 @@ When upgrading take the following steps: - For component-to-component communication: there is now only one single way to route component to component (skill to skill, skill to connection, connection to skill) messages, this is by specifying the component id in string form in the `sender`/`to` field. The `EnvelopeContext` can no longer be used, messages are routed based on their target (`to` field). Ensure that dialogues in skills set the `skill_id` as the `self_address` (in connections they need to set the `connection_id`). -### Agent configuration and ledger plugins +### Agent Configuration and Ledger Plugins Agent configuration files have a new optional field, `dependencies`, analogous to `dependencies` field in other AEA packages. The default value is the empty object `{}`. The field will be made mandatory in the next release. @@ -110,7 +111,8 @@ Crypto modules have been extracted and released as independent plug-ins, release - Cosmos crypto classes have been released in the `aea-ledger-cosmos` package. If an AEA project, or an AEA package, makes use of crypto functionalities, it will be needed to add the above packages as PyPI dependencies with version specifiers ranging from the latest minor and the latest minor + 1 (excluded). E.g. if the latest version if `0.1.0`, the version specifier should be `<0.2.0,>=0.1.0`: -```yaml + +``` yaml dependencies: aea-ledger-cosmos: version: <2.0.0,>=1.0.0 @@ -119,6 +121,7 @@ dependencies: aea-ledger-fetchai: version: <2.0.0,>=1.0.0 ``` + The version specifier sets are important, as these plug-ins, at version `0.1.0`, depend on a specific range of the `aea` package. Then, running `aea install` inside the AEA project should install them in the current Python environment. @@ -131,7 +134,7 @@ No backwards incompatible changes for skill and connection development. ## `v0.9.2` to `v0.10.0` -Skill development sees no backward incompatible changes. +Skill development sees no backward incompatible changes. Connection development requires updating the keyword arguments of the constructor: the new `data_dir` argument must be defined. @@ -208,11 +211,11 @@ from aea.configurations.base import PublicId PUBLIC_ID = PublicId.from_str("author/name:0.1.0") ``` + - The `fetchai/http` protocol's `bodyy` field has been renamed to `body`. - Skills can now specify `connections` as dependencies in the configuration YAML. - ## `v0.6.2` to `v0.6.3` A new `upgrade` command is introduced to upgrade agent projects and components to their latest versions on the registry. To use the command first upgrade the AEA PyPI package to the latest version, then enter your project and run `aea upgrade`. The project's vendor dependencies will be updated where possible. @@ -227,11 +230,12 @@ The `soef` connection and `oef_search` protocol have backward incompatible chang ## `v0.5.4` to `v0.6.0` -### `Dialogue` and `Dialogues` API updates +### `Dialogue` and `Dialogues` API Updates The dialogue and dialogues APIs have changed significantly. The constructor is different for both classes and there are now four primary methods for the developer: - `Dialogues.create`: this method is used to create a new dialogue and message: + ``` python cfp_msg, fipa_dialogue = fipa_dialogues.create( counterparty=opponent_address, @@ -239,26 +243,32 @@ cfp_msg, fipa_dialogue = fipa_dialogues.create( query=query, ) ``` + The method will raise if the provided arguments are inconsistent. - `Dialogues.create_with_message`: this method is used to create a new dialogue from a message: + ``` python fipa_dialogue = fipa_dialogues.create_with_message( counterparty=opponent_address, initial_message=cfp_msg ) ``` + The method will raise if the provided arguments are inconsistent. - `Dialogues.update`: this method is used to handle messages passed by the framework: + ``` python fipa_dialogue = fipa_dialogues.update( message=cfp_msg ) ``` + The method will return a valid dialogue if it is a valid message, otherwise it will return `None`. - `Dialogue.reply`: this method is used to reply within a dialogue: + ``` python proposal_msg = fipa_dialogue.reply( performative=FipaMessage.Performative.PROPOSE, @@ -266,23 +276,24 @@ proposal_msg = fipa_dialogue.reply( proposal=proposal, ) ``` + The method will raise if the provided arguments are inconsistent. The new methods significantly reduce the lines of code needed to maintain a dialogue. They also make it easier for the developer to construct valid dialogues and messages. -### `FetchAICrypto` - default crypto +### `FetchAICrypto` - Default Crypto The `FetchAICrypto` has been upgraded to the default crypto. Update your `default_ledger` to `fetchai`. -### Private key file naming +### Private Key File Naming The private key files are now consistently named with the `ledger_id` followed by `_private_key.txt` (e.g. `fetchai_private_key.txt`). Rename your existing files to match this pattern. -### Type in package YAML +### Type in Package YAML The package YAML files now contain a type field. This must be added for the loading mechanism to work properly. -### Moved address type +### Moved Address Type The address type has moved to `aea.common`. The import paths must be updated. @@ -321,65 +332,63 @@ Connections are now added via - +- Message sending in the skills has been updated. In the past you had to construct messages, then serialize them and place them in an envelope: + + ``` python + cfp_msg = FipaMessage(...) + self.context.outbox.put_message( + to=opponent_addr, + sender=self.context.agent_address, + protocol_id=FipaMessage.protocol_id, + message=FipaSerializer().encode(cfp_msg), + ) + # or + cfp_msg = FipaMessage(...) + envelope = Envelope( + to=opponent_addr, + sender=self.context.agent_address, + protocol_id=FipaMessage.protocol_id, + message=FipaSerializer().encode(cfp_msg), + ) + self.context.outbox.put(envelope) + ``` + + Now this has been simplified to: + + ``` python + cfp_msg = FipaMessage(...) + cfp_msg.counterparty = opponent_addr + self.context.outbox.put_message(message=cfp_msg) + ``` + + You must update your skills as the old implementation is no longer supported. + +- Connection constructors have been simplified. In the past you had to implement both the `__init__` as well as the `from_config` methods of a Connection. Now you only have to implement the `__init__` method which by default at load time now receives the following keyword arguments: `configuration: ConnectionConfig, identity: Identity, crypto_store: CryptoStore`. See for example in the scaffold connection: + + ``` python + class MyScaffoldConnection(Connection): + """Proxy to the functionality of the SDK or API.""" + + connection_id = PublicId.from_str("fetchai/scaffold:0.1.0") + + def __init__( + self, + configuration: ConnectionConfig, + identity: Identity, + crypto_store: CryptoStore, + ): + """ + Initialize a connection to an SDK or API. + + :param configuration: the connection configuration. + :param crypto_store: object to access the connection crypto objects. + :param identity: the identity object. + """ + super().__init__( + configuration=configuration, crypto_store=crypto_store, identity=identity + ) + ``` + + As a result of this feature, you are now able to pass key-pairs to your connections via the `CryptoStore`. + + You must update your connections as the old implementation is no longer supported. diff --git a/docs/version.md b/docs/version.md index e41a3bd1ec..a44a6123ec 100644 --- a/docs/version.md +++ b/docs/version.md @@ -1,6 +1,8 @@ +# Version + The latest version of the Python implementation of the AEA Framework: -PyPI. +PyPI. The framework is under rapid development with frequent breaking changes in the run-up to version `1.0` which is due in Q1 2021. diff --git a/docs/vision.md b/docs/vision.md index 11cce3e5a4..a7384e2c64 100644 --- a/docs/vision.md +++ b/docs/vision.md @@ -1,19 +1,19 @@ +# Vision + Our vision is that the AEA framework enables businesses of all sizes, from single independent developers to large corporations and consortiums, to create and deploy agent-based solutions in different domains, thus contributing to and advancing a decentralized agent economy as envisaged by Fetch.ai. -## Open source technology for everyone +## Open Source Technology for Everyone -We are creating infrastructure for developers to build their own agent-based solutions. +We are creating infrastructure for developers to build their own agent-based solutions. AEA users include, amongst others: -* Data scientists -* Economists -* Researchers (Artificial Intelligence, Machine Learning, Multi-Agent Systems) -* Engineers -* Machine learning experts -* Independent developers -* Students and academics -* Crypto connoisseurs and enthusiasts -* Web developers - -
\ No newline at end of file +- Data scientists +- Economists +- Researchers (Artificial Intelligence, Machine Learning, Multi-Agent Systems) +- Engineers +- Machine learning experts +- Independent developers +- Students and academics +- Crypto connoisseurs and enthusiasts +- Web developers diff --git a/docs/wealth.md b/docs/wealth.md index 3ee782d841..6c009f073b 100644 --- a/docs/wealth.md +++ b/docs/wealth.md @@ -1,41 +1,47 @@ +# Generating Wealth To fund an AEA for testing on a test-net you need to request some test tokens from a faucet. First, make sure you have installed the crypto plugin of the target test-net. E.g. for Fetch.AI: + ``` bash pip install aea-ledger-fetchai ``` And for Ethereum: + ``` bash pip install aea-ledger-ethereum ``` Add a private key to the agent + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + or + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` -
-

Note

-

If you already have keys in your project, the commands will prompt you for confirmation whether or not to replace the existing keys. -

-
+!!! note + If you already have keys in your project, the commands prompt you to confirm whether to replace the existing keys. -## Using a faucet website +## Using a Faucet Website First, print the address: + ``` bash aea get-address fetchai ``` -or + +or + ``` bash aea get-address ethereum ``` @@ -43,10 +49,13 @@ aea get-address ethereum This will print the address to the console. Copy the address into the clipboard and request test tokens from the faucet here for Fetch.ai or here for Ethereum. It will take a while for the tokens to become available. Second, after some time, check the wealth associated with the address: + ``` bash aea get-wealth fetchai ``` + or + ``` bash aea get-wealth ethereum ``` @@ -54,18 +63,16 @@ aea get-wealth ethereum ## Using the CLI Simply generate wealth via the CLI: + ``` bash aea generate-wealth fetchai ``` -or + +or + ``` bash aea generate-wealth ethereum ``` -
-

Note

-

This approach can be unreliable for non-fetchai test nets. -

-
- -
+!!! note + This approach can be unreliable for non-fetchai test nets. diff --git a/docs/weather-skills.md b/docs/weather-skills.md index 1ce4784be7..0192b2db96 100644 --- a/docs/weather-skills.md +++ b/docs/weather-skills.md @@ -1,7 +1,9 @@ +# Weather Skills + The AEA weather skills demonstrate an interaction between two AEAs. -* The provider of weather data (the `weather_station`). -* The buyer of weather data (the `weather_client`). +- The provider of weather data (the `weather_station`). +- The buyer of weather data (the `weather_client`). ## Discussion @@ -13,9 +15,9 @@ You can use this AEA as an example of how to read data from a database and adver ## Communication -This diagram shows the communication between the various entities as data is successfully sold by the weather station AEA to the client. +This diagram shows the communication between the various entities as data is successfully sold by the weather station AEA to the client. -
+``` mermaid sequenceDiagram participant Search participant Client_AEA @@ -42,20 +44,18 @@ This diagram shows the communication between the various entities as data is suc deactivate Client_AEA deactivate Search deactivate Weather_AEA - deactivate Blockchain - -
-
+ deactivate Blockchain +``` -## Option 1: AEA Manager approach +## Option 1: AEA Manager Approach -Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. -### Preparation instructions +### Preparation Instructions Install the AEA Manager. -### Demo instructions +### Demo Instructions The following steps assume you have launched the AEA Manager Desktop app. @@ -68,155 +68,154 @@ The following steps assume you have launched the AEA Manager Desktop app. 4. Run the `my_weather_station` AEA. Navigate to its logs and copy the multiaddress displayed. 5. Navigate to the settings of the `my_weather_client` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress): -``` bash -{ - "delegate_uri": "127.0.0.1:11001", - "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], - "local_uri": "127.0.0.1:9001", - "log_file": "libp2p_node.log", - "public_uri": "127.0.0.1:9001" -} -``` + + ``` bash + { + "delegate_uri": "127.0.0.1:11001", + "entry_peers": ["REPLACE_WITH_MULTI_ADDRESS_HERE"], + "local_uri": "127.0.0.1:9001", + "log_file": "libp2p_node.log", + "public_uri": "127.0.0.1:9001" + } + ``` 6. Run the `my_weather_client`. In the AEA's logs, you should see the agent trading successfully. -
-## Option 2: CLI approach +## Option 2: CLI Approach Follow this approach when using the `aea` CLI. -### Preparation instructions +### Preparation Instructions #### Dependencies Follow the Preliminaries and Installation sections from the AEA quick start. -### Demo instructions: +### Demo Instructions A demo to run the same scenario but with a true ledger transaction on Fetch.ai `testnet` or Ethereum `ropsten` network. This demo assumes the buyer trusts the seller AEA to send the data upon successful payment. -#### Create the weather station +#### Create the Weather Station First, fetch the AEA that will provide weather measurements: -``` bash -aea fetch fetchai/weather_station:0.32.4 --alias my_weather_station -cd my_weather_station -aea install -aea build -``` -
Alternatively, create from scratch. -

- -The following steps create the weather station from scratch: ``` bash -aea create my_weather_station +aea fetch fetchai/weather_station:0.32.4 --alias my_weather_station cd my_weather_station -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/weather_station:0.27.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- - -#### Create the weather client +??? note "Alternatively, create from scratch:" + The following steps create the weather station from scratch: + + ``` bash + aea create my_weather_station + cd my_weather_station + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/weather_station:0.27.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Create the Weather Client In another terminal, fetch the AEA that will query the weather station: -``` bash -aea fetch fetchai/weather_client:0.33.4 --alias my_weather_client -cd my_weather_client -aea install -aea build -``` - -
Alternatively, create from scratch. -

-The following steps create the weather client from scratch: ``` bash -aea create my_weather_client +aea fetch fetchai/weather_client:0.33.4 --alias my_weather_client cd my_weather_client -aea add connection fetchai/p2p_libp2p:0.27.4 -aea add connection fetchai/soef:0.27.5 -aea add connection fetchai/ledger:0.21.4 -aea add skill fetchai/weather_client:0.26.5 -aea config set --type dict agent.dependencies \ -'{ - "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} -}' -aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 -aea config set --type dict agent.default_routing \ -'{ - "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", - "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" -}' aea install aea build ``` -

-
- - -#### Add keys for the weather station AEA +??? note "Alternatively, create from scratch:" + The following steps create the weather client from scratch: + + ``` bash + aea create my_weather_client + cd my_weather_client + aea add connection fetchai/p2p_libp2p:0.27.4 + aea add connection fetchai/soef:0.27.5 + aea add connection fetchai/ledger:0.21.4 + aea add skill fetchai/weather_client:0.26.5 + aea config set --type dict agent.dependencies \ + '{ + "aea-ledger-fetchai": {"version": "<2.0.0,>=1.0.0"} + }' + aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 + aea config set --type dict agent.default_routing \ + '{ + "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4", + "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" + }' + aea install + aea build + ``` + +#### Add Keys for the Weather Station AEA First, create the private key for the weather station AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` -#### Add keys and generate wealth for the weather client AEA +#### Add Keys and Generate Wealth for the Weather Client AEA The weather client needs to have some wealth to purchase the service from the weather station. First, create the private key for the weather client AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use: + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` Then, create some wealth for your weather client based on the network you want to transact with. On the Fetch.ai `Dorado` network: + ``` bash aea generate-wealth fetchai ``` Next, create a private key used to secure the AEA's communications: + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` Finally, certify the key for use by the connections that request that: + ``` bash aea issue-certificates ``` @@ -234,6 +233,7 @@ aea run Once you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri` to retrieve the address.) This is the entry peer address for the local agent communication network created by the weather station. Then, in the weather client, run this command (replace `SOME_ADDRESS` with the correct value as described above): + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -244,9 +244,11 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + This allows the weather client to connect to the same local agent communication network as the weather station. Then run the weather client AEA: + ``` bash aea run ``` @@ -262,5 +264,3 @@ cd .. aea delete my_weather_station aea delete my_weather_client ``` - -
\ No newline at end of file diff --git a/examples/aealite_go/README.md b/examples/aealite_go/README.md index e4a7f4d588..0707ae2e56 100644 --- a/examples/aealite_go/README.md +++ b/examples/aealite_go/README.md @@ -1 +1 @@ -# A simple example using the Golang `aealite` module \ No newline at end of file +#  A simple example using the Golang `aealite` module diff --git a/examples/gym_ex/README.md b/examples/gym_ex/README.md index 9dc9519601..068503c4b8 100644 --- a/examples/gym_ex/README.md +++ b/examples/gym_ex/README.md @@ -12,4 +12,4 @@ From root execute: python examples/gym_ex/train.py ` -which has the usual RL setup (that is, the `fit` method of the `RLAgent` has the typical signature and familiar implementation). \ No newline at end of file +which has the usual RL setup (that is, the `fit` method of the `RLAgent` has the typical signature and familiar implementation). diff --git a/examples/tac_deploy/README.md b/examples/tac_deploy/README.md index ef71ade2fe..6de8ae24d3 100644 --- a/examples/tac_deploy/README.md +++ b/examples/tac_deploy/README.md @@ -2,11 +2,12 @@ The TAC deployment deploys one controller and `n` tac participants. -### Build the image +## Build the image First, ensure the specifications in `.env` match your requirements. Then, to build the image run: + ``` bash docker build -t tac-deploy -f Dockerfile . --no-cache ``` @@ -14,11 +15,13 @@ docker build -t tac-deploy -f Dockerfile . --no-cache ## Run locally Specify preferred amount of tac participants agents in `.env` file, e.g.: -``` + +``` bash PARTICIPANTS_AMOUNT=5 ``` Run: + ``` bash docker run --env-file .env -v "$(pwd)/data:/data" -ti tac-deploy ``` @@ -30,11 +33,13 @@ GCloud should be [configured](https://cloud.google.com/sdk/docs/initializing) fi ### Push image Tag the image first with the latest tag: + ``` bash docker image tag tac-deploy gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14 ``` Push it to remote repo: + ``` bash docker push gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14 ``` @@ -42,11 +47,13 @@ docker push gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14 ### Run it manually Run it + ``` bash kubectl run tac-deploy-{SOMETHING} --image=gcr.io/fetch-ai-sandbox/tac_deploy:0.0.13 --env="PARTICIPANTS_AMOUNT=5" --attach ``` Or simply restart existing deployment and latest image will be used with default configurations (see below): + ``` bash kubectl delete pod tac-deploy-{SOMETHING} ``` @@ -54,44 +61,51 @@ kubectl delete pod tac-deploy-{SOMETHING} ### Manipulate container To access the container run: + ``` bash kubectl exec tac-deploy-{SOMETHING} -ti -- /bin/sh ``` To remove all logs and all keys: + ``` bash cd ../../data find . -name \*.log -type f -delete find . -name \*.txt -type f -delete ``` -### Full deployment: +### Full deployment First, push the latest image, as per above. Second, update the `tac-deployment.yaml` file with the correct image tag and configurations and then run: + ``` bash kubectl apply -f ./tac-deployment.yaml ``` Check for pods list: + ``` bash kubectl get pods ``` To fetch logs: + ``` bash kubectl cp tac-deploy-{SOMETHING}:/data ./output_dir ``` To delete deployment: + ``` bash kubectl delete deployment tac-deploy ``` -### Analysing Logs: +### Analysing Logs Handy commands to analyse logs: + ``` bash grep -rl 'TAKE CARE! Circumventing controller identity check!' output_dir/ | sort grep -rl 'TAKE CARE! Circumventing controller identity check!' output_dir/ | wc -l diff --git a/libs/go/aealite/README.md b/libs/go/aealite/README.md index fc00481bf7..a0524f0604 100644 --- a/libs/go/aealite/README.md +++ b/libs/go/aealite/README.md @@ -2,74 +2,73 @@ `aealite` is a lightweight implementation of an AEA library in Golang. - ## Usage example ``` golang package main import ( - "log" - "os" - "os/signal" + "log" + "os" + "os/signal" - aea "aealite" - connections "aealite/connections" + aea "aealite" + connections "aealite/connections" ) func main() { - var err error - - // env file - if len(os.Args) != 2 { - log.Print("Usage: main ENV_FILE") - os.Exit(1) - } - envFile := os.Args[1] - - log.Print("Agent starting ...") - - - // Create agent - agent := aea.Agent{} - - // Set connection - agent.Connection = &connections.P2PClientApi{} - - // Initialise agent from environment file (first arg to process) - err = agent.InitFromEnv(envFile) - if err != nil { - log.Fatal("Failed to initialise agent", err) - } - log.Print("successfully initialized AEA!") - - err = agent.Start() - if err != nil { - log.Fatal("Failed to start agent", err) - } - log.Print("successfully started AEA!") - - // // Send envelope to target - // agent.Put(envel) - // // Print out received envelopes - // go func() { - // for envel := range agent.Queue() { - // envelope := envel - // logger.Info().Msgf("received envelope: %s", envelope) - // } - // }() - - // Wait until Ctrl+C or a termination call is done. - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - <-c - - err = agent.Stop() - if err != nil { - log.Fatal("Failed to stop agent", err) - } - log.Print("Agent stopped") + var err error + + // env file + if len(os.Args) != 2 { + log.Print("Usage: main ENV_FILE") + os.Exit(1) + } + envFile := os.Args[1] + + log.Print("Agent starting ...") + + + // Create agent + agent := aea.Agent{} + + // Set connection + agent.Connection = &connections.P2PClientApi{} + + // Initialise agent from environment file (first arg to process) + err = agent.InitFromEnv(envFile) + if err != nil { + log.Fatal("Failed to initialise agent", err) + } + log.Print("successfully initialized AEA!") + + err = agent.Start() + if err != nil { + log.Fatal("Failed to start agent", err) + } + log.Print("successfully started AEA!") + + // // Send envelope to target + // agent.Put(envel) + // // Print out received envelopes + // go func() { + // for envel := range agent.Queue() { + // envelope := envel + // logger.Info().Msgf("received envelope: %s", envelope) + // } + // }() + + // Wait until Ctrl+C or a termination call is done. + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c + + err = agent.Stop() + if err != nil { + log.Fatal("Failed to stop agent", err) + } + log.Print("Agent stopped") } ``` @@ -95,4 +94,4 @@ cd .. protoc -I="aealite/protocols/" --go_out="." aealite/protocols/acn.proto protoc -I="aealite/protocols/" --go_out="." aealite/protocols/base.proto cd aealite -``` \ No newline at end of file +``` diff --git a/libs/go/libp2p_node/README.md b/libs/go/libp2p_node/README.md index 6bac84ad3c..8a75d073a9 100644 --- a/libs/go/libp2p_node/README.md +++ b/libs/go/libp2p_node/README.md @@ -1,3 +1,4 @@ +# Libp2p Node The `libp2p_node` is an integral part of the ACN. @@ -24,7 +25,7 @@ staticcheck ./... ``` For mocks generation: -check https://github.com/golang/mock +check ## Messaging patterns @@ -35,8 +36,7 @@ ___ TCP/UDP/... ___ -### Messaging patterns inwards ACN: - +### Messaging patterns inwards ACN Connection (`p2p_libp2p_client`) > Delegate Client > Relay Peer > Peer (Discouraged!) @@ -46,10 +46,8 @@ Connection (`p2p_libp2p`) > Relay Peer > Peer Connection (`p2p_libp2p`) > Peer - ### Messaging patterns outwards ACN - Peer > Relay Peer > Delegate Client > Connection (`p2p_libp2p_client`) (Discouraged!) Peer > Relay Peer > Connection (`p2p_libp2p`) @@ -58,14 +56,13 @@ Peer > Delegate Client > Connection (`p2p_libp2p_client`) Peer > Connection (`p2p_libp2p`) - In total 4*4 = 16 patterns (practically: 3*3 = 9 patterns) ## Guarantees ACN should guarantee total ordering of messages for all agent pairs, independent of the type of connection and ACN messaging pattern used. -## Advanced feature (post `v1`): +## Advanced feature (post `v1`) Furthermore, there is the agent mobility. An agent can move between entry-points (Relay Peer/Peer/Delegate Client). The ACN must ensure that all messaging patterns maintain total ordering of messages for agent pairs during the move. diff --git a/mkdocs.yml b/mkdocs.yml index 5f42ec3d1a..18b93a9e87 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,14 +1,11 @@ -site_name: aea -site_url: https://docs.fetch.ai/ -site_description: Everything you need to know about AEAs. -repo_url: https://github.com/agents-aea/docs +site_name: AEA Framework Documentation +site_url: https://docs.fetch.ai/aea +site_description: Everything you need to know about the Autonomous Economic Agents. +repo_url: https://github.com/fetchai/agents-aea +repo_name: fetchai/agents-aea +edit_uri: "" site_author: developer@fetch.ai - -theme: - name: 'material' - logo: assets/logo.png - feature: - tabs: true +copyright: Copyright © 2018 - 2023 Fetch.ai # Copyright notice in footer strict: true @@ -32,10 +29,9 @@ nav: - Gym skill: 'gym-skill.md' - ML skills: 'ml-skills.md' - Oracle skills: 'oracle-demo.md' - - Aggegation skill: 'aggregation-demo.md' + - Aggregation skill: 'aggregation-demo.md' - TAC skills: 'tac-skills.md' - TAC skills ledger-based: 'tac-skills-contract.md' - - TAC external app: 'tac.md' - Thermometer skills: 'thermometer-skills.md' - Weather skills: 'weather-skills.md' - Development - Beginner: @@ -245,7 +241,7 @@ nav: - Helper: 'api/plugins/aea_ledger_fetchai/_cosmos.md' - Development - Use Case: - Generic skills: 'generic-skills.md' - - Front-end intergration: 'connect-a-frontend.md' + - Front-end integration: 'connect-a-frontend.md' - HTTP Connection: 'http-connection-and-skill.md' - ORM integration: 'orm-integration.md' - Contract deploy and interact: 'erc1155-skills.md' @@ -253,17 +249,86 @@ nav: - Build an AEA on a Raspberry Pi: 'raspberry-set-up.md' - Glossary: 'glossary.md' - Q&A: 'questions-and-answers.md' + - Archives: + - TAC external app: 'tac.md' -plugins: - - markdownmermaid - -markdown_extensions: - - pymdownx.superfences - - pymdownx.highlight - - admonition +theme: + name: material + language: en + palette: # Set light/dark theme button next to the search bar + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/weather-night + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/weather-sunny + name: Switch to light mode + logo: assets/images/logo.png # Set Fetch Logo top left + favicon: assets/images/favicon.ico # Set Fetch favicon + icon: + repo: fontawesome/brands/github + features: + - navigation.instant # Fast page loading + - navigation.tracking # URL automatically updated with the currently active anchor + - navigation.top # Back-to-top button + - search.suggest # Completion for the searched word (can be accepted with ->). + - search.highlight # Highlight all occurrences after following a search result link + - search.share # Show share button for copying deep link to the current search query and result + - toc.follow # Follow the table of content + - content.action.view # Shows button to "view the source of this page" + - content.code.copy # Shows a button next to code blocks to copy the code into clipboard +# custom_dir: docs/overrides # Uncomment to enable announcements bar at the top extra_css: - css/my-styles.css -extra_javascript: - - https://unpkg.com/mermaid@8.10.1/dist/mermaid.min.js +markdown_extensions: + - admonition # Required by admonitions + - pymdownx.superfences: # Required by admonitions, annotations, tabs. Enables arbitrary nesting of code and content blocks + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.highlight: # Required by code blocks + anchor_linenums: true + - pymdownx.inlinehilite # Required by code blocks + - pymdownx.snippets # Required by code blocks + - pymdownx.superfences # Required by admonitions, code blocks + - pymdownx.details # Required by admonitions, code blocks + - attr_list # Required by annotations + - md_in_html # Required by annotations + - pymdownx.tabbed: # Required by tabs + alternate_style: true + - tables # # Required by tables + - toc: + permalink: true + +plugins: + - search # Enables search + +extra: + social: + - icon: fontawesome/brands/twitter + link: https://bit.ly/3oDuI3f + name: fetch.ai on twitter + - icon: fontawesome/brands/telegram + link: https://t.me/fetch_ai + name: fetch.ai on telegram + - icon: fontawesome/brands/discord + link: https://bit.ly/3ra5uMI + name: fetch.ai on discord + - icon: fontawesome/brands/github + link: https://bit.ly/3AFCWxl + name: fetch.ai on github + - icon: fontawesome/brands/reddit + link: https://bit.ly/30zS1Tg + name: fetch.ai on reddit + - icon: fontawesome/brands/youtube + link: https://bit.ly/3DxFazs + name: fetch.ai on youtube + - icon: fontawesome/brands/linkedin + link: https://bit.ly/3kNO70p + name: fetch.ai on linkedin \ No newline at end of file diff --git a/packages/fetchai/agents/aries_alice/README.md b/packages/fetchai/agents/aries_alice/README.md index 8f17b0438a..743582a218 100644 --- a/packages/fetchai/agents/aries_alice/README.md +++ b/packages/fetchai/agents/aries_alice/README.md @@ -6,10 +6,10 @@ This agent represents the Alice actor in AEA Aries Demo -* Hyperledger Demo +- AEA Aries Demo +- Hyperledger Demo diff --git a/packages/fetchai/agents/aries_faber/README.md b/packages/fetchai/agents/aries_faber/README.md index f45848656a..06d7822631 100644 --- a/packages/fetchai/agents/aries_faber/README.md +++ b/packages/fetchai/agents/aries_faber/README.md @@ -5,15 +5,16 @@ This agent represents the Faber actor in AEA Aries Demo -* Hyperledger Demo +- AEA Aries Demo +- Hyperledger Demo diff --git a/packages/fetchai/agents/car_data_buyer/README.md b/packages/fetchai/agents/car_data_buyer/README.md index 6756753fd2..95fc889f32 100644 --- a/packages/fetchai/agents/car_data_buyer/README.md +++ b/packages/fetchai/agents/car_data_buyer/README.md @@ -4,10 +4,10 @@ This agent purchases information on available car parking spaces in a vicinity. ## Description -This agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_client` skill, to find an agent on the `SOEF` service that sells car park availability data in a vicinity. +This agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_client` skill, to find an agent on the `SOEF` service that sells car park availability data in a vicinity. -Once found, it requests this data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data. +Once found, it requests this data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data. ## Links -* Car Park Demo +- Car Park Demo diff --git a/packages/fetchai/agents/car_detector/README.md b/packages/fetchai/agents/car_detector/README.md index 67dd3c2e88..36a6b44d82 100644 --- a/packages/fetchai/agents/car_detector/README.md +++ b/packages/fetchai/agents/car_detector/README.md @@ -4,10 +4,10 @@ This agent sells information on the number of car parking spaces available in a ## Description -This agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_detection` skill, to register its car park availability data selling service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/carpark_client` agent) to provide its data. +This agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_detection` skill, to register its car park availability data selling service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/carpark_client` agent) to provide its data. Once such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment. ## Links -* Car Park Demo +- Car Park Demo diff --git a/packages/fetchai/agents/coin_price_feed/README.md b/packages/fetchai/agents/coin_price_feed/README.md index 342354a985..2ad498cc1d 100644 --- a/packages/fetchai/agents/coin_price_feed/README.md +++ b/packages/fetchai/agents/coin_price_feed/README.md @@ -1,6 +1,6 @@ # Coin Price Feed AEA -An agent that fetches a coin price from an API and makes it available by http request. +An agent that fetches a coin price from an API and makes it available by http request. ## Description diff --git a/packages/fetchai/agents/coin_price_oracle/README.md b/packages/fetchai/agents/coin_price_oracle/README.md index ddf42ac958..9122d69135 100644 --- a/packages/fetchai/agents/coin_price_oracle/README.md +++ b/packages/fetchai/agents/coin_price_oracle/README.md @@ -1,8 +1,7 @@ # Coin Price Oracle AEA -An agent that fetches a coin price from an API and makes it available by request to an oracle smart contract. +An agent that fetches a coin price from an API and makes it available by request to an oracle smart contract. ## Description This agent uses the `fetchai/simple_oracle` skill to deploy an oracle smart contract to a ledger and updates this contract with the latest value of a coin price fetched using the `fetchai/advanced_data_request` skill. - diff --git a/packages/fetchai/agents/coin_price_oracle_client/README.md b/packages/fetchai/agents/coin_price_oracle_client/README.md index e6b02830cc..2307d0cf8e 100644 --- a/packages/fetchai/agents/coin_price_oracle_client/README.md +++ b/packages/fetchai/agents/coin_price_oracle_client/README.md @@ -5,4 +5,3 @@ An agent that deploys an oracle client contract that can request a coin price fr ## Description This agent uses the `fetchai/simple_oracle_client` skill to deploy an oracle client smart contract to a ledger and periodically calls the contract function that requests the latest value of a coin price from a deployed oracle smart contract. - diff --git a/packages/fetchai/agents/erc1155_client/README.md b/packages/fetchai/agents/erc1155_client/README.md index a39124f5b5..458659cc0d 100644 --- a/packages/fetchai/agents/erc1155_client/README.md +++ b/packages/fetchai/agents/erc1155_client/README.md @@ -5,9 +5,9 @@ An agent that purchases data via a smart contract. ## Description This agent uses its primary skill, the `fetchai/erc1155_client` skill, to find an agent selling data on the `SOEF` service. - + Once found, it requests specific data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount via a deployed smart contract and receives the data. ## Links -* Contract Deployment Guide +- Contract Deployment Guide diff --git a/packages/fetchai/agents/erc1155_deployer/README.md b/packages/fetchai/agents/erc1155_deployer/README.md index 03b2bf9caa..699affb08a 100644 --- a/packages/fetchai/agents/erc1155_deployer/README.md +++ b/packages/fetchai/agents/erc1155_deployer/README.md @@ -4,10 +4,10 @@ An agent that deploys a smart contract sells data using it. ## Description -This agent uses its primary skill, the `fetchai/erc1155_deploy` skill, to deploy a smart contract, create and mint tokens, and register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/erc1155_client` agent) to provide specific data. +This agent uses its primary skill, the `fetchai/erc1155_deploy` skill, to deploy a smart contract, create and mint tokens, and register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/erc1155_client` agent) to provide specific data. Once such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment via the deployed smart contract. ## Links -* Contract Deployment Guide +- Contract Deployment Guide diff --git a/packages/fetchai/agents/fipa_dummy_buyer/README.md b/packages/fetchai/agents/fipa_dummy_buyer/README.md index 97ba212b7f..01074508f9 100644 --- a/packages/fetchai/agents/fipa_dummy_buyer/README.md +++ b/packages/fetchai/agents/fipa_dummy_buyer/README.md @@ -3,5 +3,5 @@ A sample agent for FIPA protocol interaction. ## Description -Dummy agent that tries to communicate with FIPA seller agent over libp2p connection. +Dummy agent that tries to communicate with FIPA seller agent over libp2p connection. diff --git a/packages/fetchai/agents/generic_buyer/README.md b/packages/fetchai/agents/generic_buyer/README.md index 2193c18a3c..ceaba24c1b 100644 --- a/packages/fetchai/agents/generic_buyer/README.md +++ b/packages/fetchai/agents/generic_buyer/README.md @@ -4,11 +4,11 @@ A generic agent for buying data. ## Description -This agent uses its primary skill, the `fetchai/generic_buyer` skill, to find an agent selling data on the `SOEF` service. +This agent uses its primary skill, the `fetchai/generic_buyer` skill, to find an agent selling data on the `SOEF` service. Once found, it requests specific data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data. ## Links -* Generic Skills -* Generic Skill Step by Step Guide +- Generic Skills +- Generic Skill Step by Step Guide diff --git a/packages/fetchai/agents/generic_seller/README.md b/packages/fetchai/agents/generic_seller/README.md index aa8be1c442..7cab3097e4 100644 --- a/packages/fetchai/agents/generic_seller/README.md +++ b/packages/fetchai/agents/generic_seller/README.md @@ -4,11 +4,11 @@ A generic agent for selling data. ## Description -This agent uses its primary skill, the `fetchai/generic_seller` skill, to register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/generic_buyer` agent) to provide specific data. +This agent uses its primary skill, the `fetchai/generic_seller` skill, to register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/generic_buyer` agent) to provide specific data. Once such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment. ## Links -* Generic Skills -* Generic Skill Step by Step Guide +- Generic Skills +- Generic Skill Step by Step Guide diff --git a/packages/fetchai/agents/gym_aea/README.md b/packages/fetchai/agents/gym_aea/README.md index 2de7c9c696..6b606777fb 100644 --- a/packages/fetchai/agents/gym_aea/README.md +++ b/packages/fetchai/agents/gym_aea/README.md @@ -4,12 +4,12 @@ This agent trains an RL algorithm using OpenAI Gym. ## Description -This agent is part of the Fetch.ai Gym demo. It uses its primary skill, the `fetchai/gym` skill, to train a reinforcement learning (RL) algorithm using OpenAI Gym. +This agent is part of the Fetch.ai Gym demo. It uses its primary skill, the `fetchai/gym` skill, to train a reinforcement learning (RL) algorithm using OpenAI Gym. It demonstrate how an RL agent can be wrapped inside a skill by decoupling the RL agent from the gym environment, allowing them to run in separate execution environments. ## Links -* Gym Demo -* Gym Example -* OpenAI Gym \ No newline at end of file +- Gym Demo +- Gym Example +- OpenAI Gym diff --git a/packages/fetchai/agents/hello_world/README.md b/packages/fetchai/agents/hello_world/README.md index 32be067f2f..28cf566d69 100644 --- a/packages/fetchai/agents/hello_world/README.md +++ b/packages/fetchai/agents/hello_world/README.md @@ -4,5 +4,5 @@ This is a "Hello World" agent! ## Description -This agent uses its primary `fetchai/hello_world` skill to print `Hello World!` on the screen. -The message to be printed can be configured to be any string. +This agent uses its primary `fetchai/hello_world` skill to print `Hello World!` on the screen. +The message to be printed can be configured to be any string. diff --git a/packages/fetchai/agents/latest_block_feed/README.md b/packages/fetchai/agents/latest_block_feed/README.md index a5f7052743..0f067fd979 100644 --- a/packages/fetchai/agents/latest_block_feed/README.md +++ b/packages/fetchai/agents/latest_block_feed/README.md @@ -1,6 +1,6 @@ # Random Beacon Feed AEA -An agent that fetches the latest block from the Fetch ledger. +An agent that fetches the latest block from the Fetch ledger. ## Description diff --git a/packages/fetchai/agents/ml_data_provider/README.md b/packages/fetchai/agents/ml_data_provider/README.md index 8601515d03..db123ec2ed 100644 --- a/packages/fetchai/agents/ml_data_provider/README.md +++ b/packages/fetchai/agents/ml_data_provider/README.md @@ -4,12 +4,12 @@ This agent sells ML data for training. ## Description -This agent is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_data_provider` skill, to register its 'ML-data-selling' service on the `SOEF`. +This agent is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_data_provider` skill, to register its 'ML-data-selling' service on the `SOEF`. -It can be contacted by another agent (for example the `fetchai/ml_train` agent) to provide specific data samples. +It can be contacted by another agent (for example the `fetchai/ml_train` agent) to provide specific data samples. Once such a request is made and the terms of trade are agreed by both agents, it delivers the data after receiving payment. ## Links -* ML Demo +- ML Demo diff --git a/packages/fetchai/agents/ml_model_trainer/README.md b/packages/fetchai/agents/ml_model_trainer/README.md index 5ebc2a08f5..7eb40dd456 100644 --- a/packages/fetchai/agents/ml_model_trainer/README.md +++ b/packages/fetchai/agents/ml_model_trainer/README.md @@ -4,10 +4,10 @@ This agent buys ML data for training. ## Description -This skill is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_train` skill, to find an agent selling ML data on the `SOEF` service (for example a `fetchai/ml_data_provider` agent). +This skill is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_train` skill, to find an agent selling ML data on the `SOEF` service (for example a `fetchai/ml_data_provider` agent). Once found, it requests specific data samples. If both parties agree with the terms of trade, it pays the proposed amount and trains an ML model using the data bought. ## Links -* ML Demo \ No newline at end of file +- ML Demo diff --git a/packages/fetchai/agents/my_first_aea/README.md b/packages/fetchai/agents/my_first_aea/README.md index 54777073b9..036b68d9d9 100644 --- a/packages/fetchai/agents/my_first_aea/README.md +++ b/packages/fetchai/agents/my_first_aea/README.md @@ -8,5 +8,5 @@ This agent uses its primary skill, the `fetchai/echo` skill, to sends back the c ## Links -* Quick Start -* Programmatically Build an AEA \ No newline at end of file +- Quick Start +- Programmatically Build an AEA diff --git a/packages/fetchai/agents/simple_aggregator/README.md b/packages/fetchai/agents/simple_aggregator/README.md index e4d4316fad..12ede6af92 100644 --- a/packages/fetchai/agents/simple_aggregator/README.md +++ b/packages/fetchai/agents/simple_aggregator/README.md @@ -5,4 +5,3 @@ An agent that aggregates individual observations for an oracle network ## Description This agent uses the `fetchai/oracle_aggregation` skill to find peers and aggregate values. - diff --git a/packages/fetchai/agents/simple_service_registration/README.md b/packages/fetchai/agents/simple_service_registration/README.md index a6a49d0a32..6bb9990129 100644 --- a/packages/fetchai/agents/simple_service_registration/README.md +++ b/packages/fetchai/agents/simple_service_registration/README.md @@ -8,4 +8,4 @@ This agent is used in the "Guide on Writing a Skill" section of the documentatio ## Links -* Guide on Building a Skill +- Guide on Building a Skill diff --git a/packages/fetchai/agents/simple_service_search/README.md b/packages/fetchai/agents/simple_service_search/README.md index 5ad78e1591..99c801de44 100644 --- a/packages/fetchai/agents/simple_service_search/README.md +++ b/packages/fetchai/agents/simple_service_search/README.md @@ -8,4 +8,4 @@ This agent is used in the "Guide on Writing a Skill" section of the documentatio ## Links -* Guide on Building a Skill +- Guide on Building a Skill diff --git a/packages/fetchai/agents/tac_controller/README.md b/packages/fetchai/agents/tac_controller/README.md index b930623ea0..ca28101682 100644 --- a/packages/fetchai/agents/tac_controller/README.md +++ b/packages/fetchai/agents/tac_controller/README.md @@ -4,10 +4,10 @@ This is a controller agent for a Trading Agent Competition (TAC). ## Description -This agent is part of the Fetch.ai TAC demo. +This agent is part of the Fetch.ai TAC demo. It uses its `fetchai/tac_control` skill to manage the progression of a competition across various stages. ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/agents/tac_controller_contract/README.md b/packages/fetchai/agents/tac_controller_contract/README.md index c2385e5b16..ddcca1779d 100644 --- a/packages/fetchai/agents/tac_controller_contract/README.md +++ b/packages/fetchai/agents/tac_controller_contract/README.md @@ -4,10 +4,10 @@ This is a controller agent for a Trading Agent Competition (TAC) using smart con ## Description -This agent is part of the Fetch.ai TAC demo. +This agent is part of the Fetch.ai TAC demo. It uses its `fetchai/tac_control` skill to manage the progression of a competition across various stages, and uses its `fetchai/tac_control_contract` skill to create and maintain a smart contract (for example, deploying the contract, creating and minting tokens, etc). ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/agents/tac_participant/README.md b/packages/fetchai/agents/tac_participant/README.md index ceb9e91505..d53b9a5884 100644 --- a/packages/fetchai/agents/tac_participant/README.md +++ b/packages/fetchai/agents/tac_participant/README.md @@ -4,7 +4,7 @@ This is an agent that participates in a Trading Agent Competition (TAC). ## Description -This agent is part of the Fetch.ai TAC demo. +This agent is part of the Fetch.ai TAC demo. It uses its `fetchai/tac_participation` skill to find and register with a TAC by communicating with a controller agent. @@ -12,4 +12,4 @@ It then uses its `fetchai/tac_negotiation` skill to find trading partners, negot ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/agents/tac_participant_contract/README.md b/packages/fetchai/agents/tac_participant_contract/README.md index 28bc3c7f95..3e0ab85018 100644 --- a/packages/fetchai/agents/tac_participant_contract/README.md +++ b/packages/fetchai/agents/tac_participant_contract/README.md @@ -4,7 +4,7 @@ This is an agent that participates in a Trading Agent Competition (TAC) using a ## Description -This agent is part of the Fetch.ai TAC demo. +This agent is part of the Fetch.ai TAC demo. It uses its `fetchai/tac_participation` skill to find and register with a TAC by communicating with a controller agent. @@ -12,4 +12,4 @@ It then uses its `fetchai/tac_negotiation` skill to find trading partners, negot ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/agents/thermometer_aea/README.md b/packages/fetchai/agents/thermometer_aea/README.md index 2200d07086..79f4187c20 100644 --- a/packages/fetchai/agents/thermometer_aea/README.md +++ b/packages/fetchai/agents/thermometer_aea/README.md @@ -4,12 +4,12 @@ This agent sells thermometer data. ## Description -This agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer` skill, to register its 'thermometer-data-selling' service on the `SOEF`. +This agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer` skill, to register its 'thermometer-data-selling' service on the `SOEF`. -It can be contacted by another agent (for example the `fetchai/thermometer_client` agent) to provide data from a thermometer reading. +It can be contacted by another agent (for example the `fetchai/thermometer_client` agent) to provide data from a thermometer reading. Once such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it reads data from a (real or fake) thermometer, and delivers it after receiving payment. ## Links -* Thermometer Demo +- Thermometer Demo diff --git a/packages/fetchai/agents/thermometer_client/README.md b/packages/fetchai/agents/thermometer_client/README.md index 4f6d651cb5..b8a39742d4 100644 --- a/packages/fetchai/agents/thermometer_client/README.md +++ b/packages/fetchai/agents/thermometer_client/README.md @@ -4,10 +4,10 @@ This agent buys thermometer data. ## Description -This agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer_client` skill, to find an agent selling thermometer data on the `SOEF` service. +This agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer_client` skill, to find an agent selling thermometer data on the `SOEF` service. Once found, it requests data from a thermometer reading, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data. ## Links -* Thermometer Demo +- Thermometer Demo diff --git a/packages/fetchai/agents/weather_client/README.md b/packages/fetchai/agents/weather_client/README.md index b414d7f2e0..d19412e696 100644 --- a/packages/fetchai/agents/weather_client/README.md +++ b/packages/fetchai/agents/weather_client/README.md @@ -4,10 +4,10 @@ This agent buys dummy weather data. ## Description -This agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_client` skill, to find an agent selling weather data on the `SOEF` service. +This agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_client` skill, to find an agent selling weather data on the `SOEF` service. Once found, it requests weather data for specific dates, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data. ## Links -* Weather Demo \ No newline at end of file +- Weather Demo diff --git a/packages/fetchai/agents/weather_station/README.md b/packages/fetchai/agents/weather_station/README.md index c2f0a5a964..7f73503b70 100644 --- a/packages/fetchai/agents/weather_station/README.md +++ b/packages/fetchai/agents/weather_station/README.md @@ -4,12 +4,12 @@ This agent sells dummy weather data. ## Description -This agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_station` skill, to registers its 'weather-data-selling' service on the `SOEF`. This data comes from a database that is populated with dummy data from a weather station. +This agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_station` skill, to registers its 'weather-data-selling' service on the `SOEF`. This data comes from a database that is populated with dummy data from a weather station. -It can be contacted by another agent (for example the `fetchai/weather_client` agent) to provide weather data for specific dates.. +It can be contacted by another agent (for example the `fetchai/weather_client` agent) to provide weather data for specific dates.. Once such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the weather data after receiving payment. ## Links -* Weather Demo +- Weather Demo diff --git a/packages/fetchai/connections/gym/README.md b/packages/fetchai/connections/gym/README.md index 17f7c22c9c..7d4af1ea97 100644 --- a/packages/fetchai/connections/gym/README.md +++ b/packages/fetchai/connections/gym/README.md @@ -1,6 +1,6 @@ # Gym connection -Connection providing access to the gym interface (https://github.com/openai/gym) for training reinforcement learning systems. +Connection providing access to the gym interface () for training reinforcement learning systems. The connection wraps a gym and allows the AEA to interact with the gym interface via the `gym` protocol. diff --git a/packages/fetchai/connections/gym/connection.yaml b/packages/fetchai/connections/gym/connection.yaml index dcc7f049eb..e02ccce720 100644 --- a/packages/fetchai/connections/gym/connection.yaml +++ b/packages/fetchai/connections/gym/connection.yaml @@ -6,7 +6,7 @@ description: The gym connection wraps an OpenAI gym. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qmc6XqGTME67UWxZZZbZi3pcZ636JYZ7jRXLNQNX7sma5T + README.md: QmTBSGhMSyLPXiGRbJKRqikw2zb9utb3UM4NJm5mpaScUt __init__.py: QmaxS1pbCJtyT7zjAamvEnwLyR1LdrHK6VDcfN45jFgwQH connection.py: QmduX1Gb283UBHMDLuYmcTmkDMdQPtr1YEZAcmtqb7Av33 fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/http_server/README.md b/packages/fetchai/connections/http_server/README.md index ad6db8563c..643c580afa 100644 --- a/packages/fetchai/connections/http_server/README.md +++ b/packages/fetchai/connections/http_server/README.md @@ -4,4 +4,4 @@ This connection wraps an HTTP server. It consumes requests from clients, transla ## Usage -First, add the connection to your AEA project (`aea add connection fetchai/http_server:0.23.5`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server. Optionally, provide a path to an [OpenAPI specification](https://swagger.io/docs/specification/about/) for request validation. \ No newline at end of file +First, add the connection to your AEA project (`aea add connection fetchai/http_server:0.23.5`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server. Optionally, provide a path to an [OpenAPI specification](https://swagger.io/docs/specification/about/) for request validation. diff --git a/packages/fetchai/connections/http_server/connection.yaml b/packages/fetchai/connections/http_server/connection.yaml index faace9c8dd..b54cd249e5 100644 --- a/packages/fetchai/connections/http_server/connection.yaml +++ b/packages/fetchai/connections/http_server/connection.yaml @@ -7,7 +7,7 @@ description: The HTTP server connection that wraps http server implementing a RE license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmYmnXv1Y7iDu8HJ7cSc8iexWjK8a6gwoD52C2azoCgcb8 + README.md: QmcZWakNoHKmTiKz8cUnQFDLofyPZHGsizWBKsUksgi62a __init__.py: QmPQbWNzuoYoaWQ35b4XUzGUZqwm2YYNg9XpngS4xqCdiZ connection.py: QmW7RSdTFkSHPuD8ruVRzfcCdHereTVnD21e297EXbiEAE fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/oef/README.md b/packages/fetchai/connections/oef/README.md index 363c6291a1..37d94bcdba 100644 --- a/packages/fetchai/connections/oef/README.md +++ b/packages/fetchai/connections/oef/README.md @@ -1,7 +1,7 @@ # OEF connection -Connection to interact with an OEF node (https://fetchai.github.io/oef-sdk-python/user/introduction.html). +Connection to interact with an OEF node (). ## Usage -Register/unregister services, perform searches using `fetchai/oef_search:1.1.6` protocol and send messages of any protocol to other agents connected to the same node. \ No newline at end of file +Register/unregister services, perform searches using `fetchai/oef_search:1.1.6` protocol and send messages of any protocol to other agents connected to the same node. diff --git a/packages/fetchai/connections/oef/connection.yaml b/packages/fetchai/connections/oef/connection.yaml index d61e2e9407..4526afe744 100644 --- a/packages/fetchai/connections/oef/connection.yaml +++ b/packages/fetchai/connections/oef/connection.yaml @@ -7,7 +7,7 @@ description: The oef connection provides a wrapper around the OEF SDK for connec license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmanfBiS9gD9MBXfNLr9RY7tFeVRhud5vxwEv3a64FnMAw + README.md: QmZGv1JVuU9SYbZnLabhePrVVCrtQY62bUR1BXsqoNq36f __init__.py: QmPyDUmHgQdAtuq46GSQ75kpkeH3jg5LQoZm2xQi9j9PMk connection.py: QmYgKDjLXoVoYkmhtAJYFtxC3DzmPVPMUF4EGqeDf6Kx2X object_translator.py: QmTcyE7yVMzx72zr7JJoZDftL42aP5s3jQQBgMCGqgY6PW diff --git a/packages/fetchai/connections/p2p_libp2p/connection.yaml b/packages/fetchai/connections/p2p_libp2p/connection.yaml index db7997436e..6094b2d15f 100644 --- a/packages/fetchai/connections/p2p_libp2p/connection.yaml +++ b/packages/fetchai/connections/p2p_libp2p/connection.yaml @@ -16,7 +16,7 @@ fingerprint: libp2p_node/.dockerignore: QmVwyNjya468nRTxSjFP73dSzQdSffp74osz5dGEAHHweA libp2p_node/Dockerfile: QmeZ6KJf4cpgL7DY6qdWetVfTPPijUvHxoCUbYgSS3SsWM libp2p_node/Makefile: Qmezxsp96mW85mJhjGAarLmwWJG9JvGJowcY5h56oPB9bt - libp2p_node/README.md: QmRBC7o5y1TBQGwviJ9XxywdeuSSz6dNgvGE9wQhFPES4D + libp2p_node/README.md: QmR1Lk6utZWxN1rEBmTodenwfyjTucv5akx9GGcFzxmPjb libp2p_node/acn/utils.go: Qmb39aDGu7N5a8JPdHeRsjSzJ9fyKp2jT3EkULocvGGYKV libp2p_node/aea/api.go: QmW7mHHShumfDHg9Ds1nxHZJN4EAHGLrr15jLX7kKYkcV9 libp2p_node/aea/envelope.pb.go: QmRfUNGpCeVJfsW3H1MzCN4pwDWgumfyWufVFp6xvUjjug diff --git a/packages/fetchai/connections/p2p_libp2p/libp2p_node/README.md b/packages/fetchai/connections/p2p_libp2p/libp2p_node/README.md index 6bac84ad3c..8a75d073a9 100644 --- a/packages/fetchai/connections/p2p_libp2p/libp2p_node/README.md +++ b/packages/fetchai/connections/p2p_libp2p/libp2p_node/README.md @@ -1,3 +1,4 @@ +# Libp2p Node The `libp2p_node` is an integral part of the ACN. @@ -24,7 +25,7 @@ staticcheck ./... ``` For mocks generation: -check https://github.com/golang/mock +check ## Messaging patterns @@ -35,8 +36,7 @@ ___ TCP/UDP/... ___ -### Messaging patterns inwards ACN: - +### Messaging patterns inwards ACN Connection (`p2p_libp2p_client`) > Delegate Client > Relay Peer > Peer (Discouraged!) @@ -46,10 +46,8 @@ Connection (`p2p_libp2p`) > Relay Peer > Peer Connection (`p2p_libp2p`) > Peer - ### Messaging patterns outwards ACN - Peer > Relay Peer > Delegate Client > Connection (`p2p_libp2p_client`) (Discouraged!) Peer > Relay Peer > Connection (`p2p_libp2p`) @@ -58,14 +56,13 @@ Peer > Delegate Client > Connection (`p2p_libp2p_client`) Peer > Connection (`p2p_libp2p`) - In total 4*4 = 16 patterns (practically: 3*3 = 9 patterns) ## Guarantees ACN should guarantee total ordering of messages for all agent pairs, independent of the type of connection and ACN messaging pattern used. -## Advanced feature (post `v1`): +## Advanced feature (post `v1`) Furthermore, there is the agent mobility. An agent can move between entry-points (Relay Peer/Peer/Delegate Client). The ACN must ensure that all messaging patterns maintain total ordering of messages for agent pairs during the move. diff --git a/packages/fetchai/connections/p2p_libp2p_client/README.md b/packages/fetchai/connections/p2p_libp2p_client/README.md index de74ed71c0..0171f342c1 100644 --- a/packages/fetchai/connections/p2p_libp2p_client/README.md +++ b/packages/fetchai/connections/p2p_libp2p_client/README.md @@ -4,8 +4,7 @@ A lightweight TCP connection to a libp2p DHT node. It allows for using the DHT without having to deploy a node by delegating its communication traffic to an already running DHT node with delegate service enabled. - -## Usage +## Usage First, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p_client:0.20.5`. diff --git a/packages/fetchai/connections/p2p_libp2p_client/connection.yaml b/packages/fetchai/connections/p2p_libp2p_client/connection.yaml index 05bd0105e0..ca962dca30 100644 --- a/packages/fetchai/connections/p2p_libp2p_client/connection.yaml +++ b/packages/fetchai/connections/p2p_libp2p_client/connection.yaml @@ -8,7 +8,7 @@ description: The libp2p client connection implements a tcp connection to a runni license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmchaNxQavwRaKMhZYaYpDjWUiRb4CA11FSaPPJVshpi9s + README.md: QmfH6xi3GdxqTMZY91RgdqFG4ibWYVRGBjMwjZsoiVMv5d __init__.py: QmXwtBAZxhrLXVTU5FYytTxnoh7vScRQBRjtMvFerXH31e connection.py: QmaSGTqkCbshgJvvHA3jQBUjFt6cG3mabpQ27rhoew13DR fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/p2p_libp2p_mailbox/README.md b/packages/fetchai/connections/p2p_libp2p_mailbox/README.md index de74ed71c0..0171f342c1 100644 --- a/packages/fetchai/connections/p2p_libp2p_mailbox/README.md +++ b/packages/fetchai/connections/p2p_libp2p_mailbox/README.md @@ -4,8 +4,7 @@ A lightweight TCP connection to a libp2p DHT node. It allows for using the DHT without having to deploy a node by delegating its communication traffic to an already running DHT node with delegate service enabled. - -## Usage +## Usage First, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p_client:0.20.5`. diff --git a/packages/fetchai/connections/p2p_libp2p_mailbox/connection.yaml b/packages/fetchai/connections/p2p_libp2p_mailbox/connection.yaml index 2326b243f3..7e7e836900 100644 --- a/packages/fetchai/connections/p2p_libp2p_mailbox/connection.yaml +++ b/packages/fetchai/connections/p2p_libp2p_mailbox/connection.yaml @@ -8,7 +8,7 @@ description: The libp2p client connection implements a tcp connection to a runni license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmchaNxQavwRaKMhZYaYpDjWUiRb4CA11FSaPPJVshpi9s + README.md: QmfH6xi3GdxqTMZY91RgdqFG4ibWYVRGBjMwjZsoiVMv5d __init__.py: QmXwtBAZxhrLXVTU5FYytTxnoh7vScRQBRjtMvFerXH31e connection.py: QmZpAfHrPLT4yHaMxyzbfi4MahdzmKhuS1F5zSJ6bNS4b5 fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/prometheus/README.md b/packages/fetchai/connections/prometheus/README.md index 951915c8dd..58e7c4de84 100644 --- a/packages/fetchai/connections/prometheus/README.md +++ b/packages/fetchai/connections/prometheus/README.md @@ -1,4 +1,5 @@ # Prometheus connection + AEAs can create and update prometheus metrics for remote monitoring by sending messages to the prometheus connection. ## Usage diff --git a/packages/fetchai/connections/prometheus/connection.yaml b/packages/fetchai/connections/prometheus/connection.yaml index cca2472278..09ea5bf372 100644 --- a/packages/fetchai/connections/prometheus/connection.yaml +++ b/packages/fetchai/connections/prometheus/connection.yaml @@ -6,7 +6,7 @@ description: Connection for exposing agent metrics to prometheus server license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmWyfBxrcdSDqgUSffMrALDdMcDFt1fn7ace8XtMuKgd6o + README.md: QmbbJJFxskRX9j8U3ZmtVpWyyFrk9v5Vfw7BYuq5KVvaL3 __init__.py: QmW4f9cnBi7hiCqyiNk7Xx4bS1y6yt5B1b64FErHCm8BSA connection.py: QmfDvjDhTTtzmrBAP9SmdTkJptvCD7jdd9Fj2byiPwanFp fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/soef/README.md b/packages/fetchai/connections/soef/README.md index 4c204ab874..19a2caac01 100644 --- a/packages/fetchai/connections/soef/README.md +++ b/packages/fetchai/connections/soef/README.md @@ -6,4 +6,4 @@ The SOEF connection is used to connect to an SOEF node. The SOEF provides OEF se First, add the connection to your AEA project: `aea add connection fetchai/soef:0.27.5`. Then ensure the `config` in `connection.yaml` matches your need. In particular, make sure `chain_identifier` matches your `default_ledger`. -To register/unregister services and perform searches use the `fetchai/oef_search:1.1.6` protocol \ No newline at end of file +To register/unregister services and perform searches use the `fetchai/oef_search:1.1.6` protocol diff --git a/packages/fetchai/connections/soef/connection.yaml b/packages/fetchai/connections/soef/connection.yaml index 908dc405ce..5f6eb141a0 100644 --- a/packages/fetchai/connections/soef/connection.yaml +++ b/packages/fetchai/connections/soef/connection.yaml @@ -6,7 +6,7 @@ description: The soef connection provides a connection api to the simple OEF. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmXPeSsoYp7XggSMmLbJXjLFXCVHLrV6yrjSmaZS8ZmMD1 + README.md: Qmaq4ytB6CBNCTQhAdqsPYFNcmx9vzQXY7zrGhsdJdb6Y8 __init__.py: QmTCY2JASjfXJdt9ywBE5pejcXKvbrtSNCzJ9uiiEoHKFm connection.py: QmdwrWnhqWotXQJLeVvbmaoX6m5jgJcLofY3qzgJchdGj1 fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/connections/stub/README.md b/packages/fetchai/connections/stub/README.md index 668e22ef09..f2888a6410 100644 --- a/packages/fetchai/connections/stub/README.md +++ b/packages/fetchai/connections/stub/README.md @@ -1,7 +1,9 @@ # Stub connection + A simple connection for communication with an AEA, using the file system as a point of data exchange. ## Usage + First, add the connection to your AEA project: `aea add connection fetchai/stub:0.21.2`. (If you have created your AEA project with `aea create` then the connection will already be available by default.) Optionally, in the `connection.yaml` file under `config` set the `input_file` and `output_file` to the desired file path. The `stub` connection reads encoded envelopes from the `input_file` and writes encoded envelopes to the `output_file`. diff --git a/packages/fetchai/connections/stub/connection.yaml b/packages/fetchai/connections/stub/connection.yaml index 9c3962efec..52f9ecf4c3 100644 --- a/packages/fetchai/connections/stub/connection.yaml +++ b/packages/fetchai/connections/stub/connection.yaml @@ -7,7 +7,7 @@ description: The stub connection implements a connection stub which reads/writes license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmdgS2TuTmQaqTfKMzWb8RPRnTLbwdmqGZ8j8MA3BHyo3J + README.md: Qmam3xmWZWFfCMLrDZR5m5u7r5yYP4gb26Qg94TG4S1YA8 __init__.py: QmU3CUkFsuMuBuFtcrCkUpt7ydGXRfM5PtBmamTk3yP2uP connection.py: QmfXm6BU6PGqWYc27sitUurndBPd38kQCKQtKxECU1VTje fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/contracts/erc1155/README.md b/packages/fetchai/contracts/erc1155/README.md index 86406c500a..2494e10dc8 100644 --- a/packages/fetchai/contracts/erc1155/README.md +++ b/packages/fetchai/contracts/erc1155/README.md @@ -6,21 +6,20 @@ This contract package is used to interface with an ERC1155 smart contract. ## Functions -* `generate_token_ids(token_type, nb_tokens, starting_index)`: Generate token ids. -* `get_create_batch_transaction(token_ids)`: Get the transaction to create a batch of `token_ids` tokens. -* `get_create_single_transaction()`: Get the transaction to create a single `token_id` token. -* `get_mint_batch_transaction(token_ids, mint_quantities)`: Get the transaction to mint `mint_quantities` number of `token_ids` tokens. -* `validate_mint_quantities(token_ids, mint_quantities)`: Validate the mint quantities -* `get_mint_single_transaction(token_id, mint_quantity)`: Get the transaction to mint `mint_quantity` number of a single `token_id` token. -* `get_balance(token_id)`: Get the balance for a specific `token_id`. -* `get_atomic_swap_single_transaction(token_id)`: Get the transaction for a trustless trade between two agents for a single `token_id` token. -* `get_balances(token_ids)`: Get the balances for a batch of specific `token_ids`. -* `get_atomic_swap_batch_transaction(token_ids)`: Get the transaction for a trustless trade between two agents for a batch of `token_ids` tokens. -* `get_hash_single(token_id)`: Get the hash for a trustless trade between two agents for a single `token_id` token. -* `get_hash_batch(token_ids)`: Get the hash for a trustless trade between two agents for a batch of `token_ids` token. -* `generate_trade_nonce()`: Generate a valid trade nonce. - +- `generate_token_ids(token_type, nb_tokens, starting_index)`: Generate token ids. +- `get_create_batch_transaction(token_ids)`: Get the transaction to create a batch of `token_ids` tokens. +- `get_create_single_transaction()`: Get the transaction to create a single `token_id` token. +- `get_mint_batch_transaction(token_ids, mint_quantities)`: Get the transaction to mint `mint_quantities` number of `token_ids` tokens. +- `validate_mint_quantities(token_ids, mint_quantities)`: Validate the mint quantities +- `get_mint_single_transaction(token_id, mint_quantity)`: Get the transaction to mint `mint_quantity` number of a single `token_id` token. +- `get_balance(token_id)`: Get the balance for a specific `token_id`. +- `get_atomic_swap_single_transaction(token_id)`: Get the transaction for a trustless trade between two agents for a single `token_id` token. +- `get_balances(token_ids)`: Get the balances for a batch of specific `token_ids`. +- `get_atomic_swap_batch_transaction(token_ids)`: Get the transaction for a trustless trade between two agents for a batch of `token_ids` tokens. +- `get_hash_single(token_id)`: Get the hash for a trustless trade between two agents for a single `token_id` token. +- `get_hash_batch(token_ids)`: Get the hash for a trustless trade between two agents for a batch of `token_ids` token. +- `generate_trade_nonce()`: Generate a valid trade nonce. ## Links -* ERC1155 Standard +- ERC1155 Standard diff --git a/packages/fetchai/contracts/erc1155/contract.yaml b/packages/fetchai/contracts/erc1155/contract.yaml index 023619fb31..cd60484571 100644 --- a/packages/fetchai/contracts/erc1155/contract.yaml +++ b/packages/fetchai/contracts/erc1155/contract.yaml @@ -6,7 +6,7 @@ description: The erc1155 contract implements an ERC1155 contract package. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmbM3Jrh5fFuRR3rfyF3FxiriwGGJ2Q6Bob7LrVQWcHscu + README.md: QmVKKf8Uyub6iUQytLSKVJBrFW9h6ALtHY4c8XF7pihuhg __init__.py: QmTDUtfiUxkNFz3yemKkghfwsC7wYcyVJ9zzs99PXrrrVf build/Migrations.json: QmfFYYWoq1L1Ni6YPBWWoRPvCZKBLZ7qzN3UDX537mCeuE build/erc1155.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw diff --git a/packages/fetchai/contracts/fet_erc20/README.md b/packages/fetchai/contracts/fet_erc20/README.md index dc9494a750..6145b7104d 100644 --- a/packages/fetchai/contracts/fet_erc20/README.md +++ b/packages/fetchai/contracts/fet_erc20/README.md @@ -6,5 +6,5 @@ This contract package is used to interface with a Fetch ERC20 contract. ## Functions -* approve(spender, amount): approve address `spender` to transfer up to `amount` tokens on behalf of sender -* transfer(receiver, amount): transfer `amount` tokens from sender to receiver \ No newline at end of file +- approve(spender, amount): approve address `spender` to transfer up to `amount` tokens on behalf of sender +- transfer(receiver, amount): transfer `amount` tokens from sender to receiver diff --git a/packages/fetchai/contracts/fet_erc20/contract.yaml b/packages/fetchai/contracts/fet_erc20/contract.yaml index 504398b79c..b09d175171 100644 --- a/packages/fetchai/contracts/fet_erc20/contract.yaml +++ b/packages/fetchai/contracts/fet_erc20/contract.yaml @@ -6,7 +6,7 @@ description: The fet_erc20 contract contains a mock Fetch ERC20 contract license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmdksAfBj3gVPH8zmzpHjjpXsf1gtAY6z6gjrfYfiicLrr + README.md: QmWVwuKSyna278svBZ18tdxHtVfhHuTV6pZ79UH5gmaNes __init__.py: QmRCPaWpwzAgESvZPpgyNQwSHAfDcU9rnEH2PauuLgfVor build/FetERC20Mock.json: QmPKt6BUTUotWS7mtdHLxfg7dEw3cATzNojNBiJ1nifwF9 contract.py: QmSdHVqrAeC5Fbuwn3X9mQv4oq2jSQSyt2WSsyy4674CxY diff --git a/packages/fetchai/contracts/oracle/README.md b/packages/fetchai/contracts/oracle/README.md index 6ebc89d1f8..7b933fae38 100644 --- a/packages/fetchai/contracts/oracle/README.md +++ b/packages/fetchai/contracts/oracle/README.md @@ -6,5 +6,5 @@ This contract package is used to interface with a Fetch Oracle contract, which m ## Functions -* `grantRole(oracle_role, oracle_address)`: grant oracle role to address `oracle_address` -* `updateOracleValue(value, decimals, txExpirationBlock)`: update oracle contract value to `value` with `decimals` decimal places, to expire at block `txExpirationBlock` \ No newline at end of file +- `grantRole(oracle_role, oracle_address)`: grant oracle role to address `oracle_address` +- `updateOracleValue(value, decimals, txExpirationBlock)`: update oracle contract value to `value` with `decimals` decimal places, to expire at block `txExpirationBlock` diff --git a/packages/fetchai/contracts/oracle/contract.yaml b/packages/fetchai/contracts/oracle/contract.yaml index e13cd0f15f..b3132e24d9 100644 --- a/packages/fetchai/contracts/oracle/contract.yaml +++ b/packages/fetchai/contracts/oracle/contract.yaml @@ -6,7 +6,7 @@ description: Fetch oracle contract license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmWgKLF6Fe4tESTdhStxYJrEVKP2xSthd2fcMm2LSfkygL + README.md: QmQvXSNH6CN9uNqF8bjuCiv7ThQ5D7SCEZvNgKw88uYTdT __init__.py: QmYWrZY2q18XGiS8EDki97v3Gi9KHLi1YhC7e7cpbkEXU2 build/FetchOracle.json: QmfEMai1yxPtWoshFahBk2EyVHd9Mo8pSp1SAE83rRvQgH build/oracle.wasm: QmPkM6EDcizaV39AhqynLSu7bFpy27Kda27r1bJ61W73AA diff --git a/packages/fetchai/contracts/oracle_client/README.md b/packages/fetchai/contracts/oracle_client/README.md index 4bf6d36919..3d5f7e0cd7 100644 --- a/packages/fetchai/contracts/oracle_client/README.md +++ b/packages/fetchai/contracts/oracle_client/README.md @@ -6,4 +6,4 @@ This contract package is used to interface with a Fetch Oracle Client contract, ## Functions -* `queryOracleValue()`: call contract method that requests oracle value from associated oracle contract \ No newline at end of file +- `queryOracleValue()`: call contract method that requests oracle value from associated oracle contract diff --git a/packages/fetchai/contracts/oracle_client/contract.yaml b/packages/fetchai/contracts/oracle_client/contract.yaml index 1ba4f7c2bb..fe28629df5 100644 --- a/packages/fetchai/contracts/oracle_client/contract.yaml +++ b/packages/fetchai/contracts/oracle_client/contract.yaml @@ -6,7 +6,7 @@ description: Fetch oracle client contract license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmUBEziYn29b61higYFNsSxtnKcSNq7CRFpsQ68WjmTCcN + README.md: Qmasz3mr6zrBNWULfiMeeMC9py561evkcwsCbkjEZnwto5 __init__.py: QmYWrZY2q18XGiS8EDki97v3Gi9KHLi1YhC7e7cpbkEXU2 build/FetchOracleTestClient.json: QmbqwQiYs8Tb2DKB1BDiigqmXxVt1BmfM5RVXHwkvysdqf build/oracle_client.wasm: QmXE7H9JqjJFNEzjUiMv5Sv6NyaMqB4eYDwSVym66L52xU diff --git a/packages/fetchai/contracts/staking_erc20/README.md b/packages/fetchai/contracts/staking_erc20/README.md index 701b64c72a..4f41140334 100644 --- a/packages/fetchai/contracts/staking_erc20/README.md +++ b/packages/fetchai/contracts/staking_erc20/README.md @@ -6,4 +6,4 @@ This contract package is used to interface with a Fetch staking ERC20 contract. ## Functions -* `get_stake(address)`: Get the balance for a specific `address` \ No newline at end of file +- `get_stake(address)`: Get the balance for a specific `address` diff --git a/packages/fetchai/contracts/staking_erc20/contract.yaml b/packages/fetchai/contracts/staking_erc20/contract.yaml index f25c7c07bb..2206721001 100644 --- a/packages/fetchai/contracts/staking_erc20/contract.yaml +++ b/packages/fetchai/contracts/staking_erc20/contract.yaml @@ -7,7 +7,7 @@ description: The staking_erc20 contract contains the main staking contract of Fe license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmR5xGpZ8gZkUyWxz6EBkVpsYGuULcN13yNEALoxmDTx6t + README.md: QmXcVNZrAEX5Ja2fPKBYDVV77s5JKXtyGP19pgZfJNerrw __init__.py: QmdKarQHWsEyedE8E3X6my3zLZkdTGGrbmyJaidti3Sqyx build/Migrations.json: QmfFYYWoq1L1Ni6YPBWWoRPvCZKBLZ7qzN3UDX537mCeuE build/staking_erc20.json: QmVf2BuDDJPoCHDwEQKHdgfph4CbTFpqJJvcDLaM9tyoQq diff --git a/packages/fetchai/protocols/cosm_trade/README.md b/packages/fetchai/protocols/cosm_trade/README.md index 7a7a5ca0cc..d4cb871ee9 100644 --- a/packages/fetchai/protocols/cosm_trade/README.md +++ b/packages/fetchai/protocols/cosm_trade/README.md @@ -2,10 +2,9 @@ ## Description -This is a protocol for preparing an atomic swap bilateral transaction for cosmos-based ledgers, including fetchai's. +This is a protocol for preparing an atomic swap bilateral transaction for cosmos-based ledgers, including fetchai's. For two parties A and B to atomically swap tokens on cosmos-based networks, A has to send its public key to B. -Then B constructs the transaction using both his public key and A's, signs the transaction, adds its signature to the list of signatures in the transaction and sends this to A. -After receiving, A signs the transaction, adds its signature to the list of signatures in the transaction and broadcasts it to the network for processing. +Then B constructs the transaction using both his public key and A's, signs the transaction, adds its signature to the list of signatures in the transaction and sends this to A. After receiving, A signs the transaction, adds its signature to the list of signatures in the transaction and broadcasts it to the network for processing. ## Specification diff --git a/packages/fetchai/protocols/cosm_trade/protocol.yaml b/packages/fetchai/protocols/cosm_trade/protocol.yaml index 7ea3ccf1f1..6c366ef14c 100644 --- a/packages/fetchai/protocols/cosm_trade/protocol.yaml +++ b/packages/fetchai/protocols/cosm_trade/protocol.yaml @@ -8,7 +8,7 @@ description: A protocol for preparing an atomic swap bilateral transaction for c license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmaGRhL44vq5fJnfunNMD9RoxHFHQggUy6Xv2LAmVHL6RJ + README.md: QmVnxEW616ppAPsYZKoFGfSTXsP9bwJVNfxy7PxE9JhNwz __init__.py: QmfDKZU1wzmhTQLQSyTJ1Gwjbr5YwD7GpLCXgn29S6rmZr cosm_trade.proto: QmWJZbNWJD8Qz1A1ju89wWoxFjMhC7RHn1pkeVPW3s3CPT cosm_trade_pb2.py: Qma3GnRA8g9t6RADbYyagW747CcDmuNUEqahpjHvsroTTx diff --git a/packages/fetchai/protocols/fipa/README.md b/packages/fetchai/protocols/fipa/README.md index 667de2d3a7..757f5ebabb 100644 --- a/packages/fetchai/protocols/fipa/README.md +++ b/packages/fetchai/protocols/fipa/README.md @@ -58,4 +58,4 @@ keep_terminal_state_dialogues: true ## Links -* FIPA Foundation +- FIPA Foundation diff --git a/packages/fetchai/protocols/fipa/protocol.yaml b/packages/fetchai/protocols/fipa/protocol.yaml index 56ef7e864c..58827db6b6 100644 --- a/packages/fetchai/protocols/fipa/protocol.yaml +++ b/packages/fetchai/protocols/fipa/protocol.yaml @@ -7,7 +7,7 @@ description: A protocol for FIPA ACL. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmYkcFE9JsK9imfMe84om7UbU8qi8nDtCoxFWBEkqgAKpQ + README.md: QmeWg8xspRuFyJ1m9oGkA6rxWECWmSYMQGex4br14LpKiw __init__.py: QmYSuvPPBZTR7HT7f7dFM525WarQccFQrw2qRQUB6nPeFK custom_types.py: QmNibpgi18PbM4drwbYxw18GwMkBAToh21EhKimnF3j7Sg dialogues.py: QmS2o9G3AyW7n7R6Ec9n3KSSntMx5MrGARD3Ya67FDAa2s diff --git a/packages/fetchai/protocols/gym/README.md b/packages/fetchai/protocols/gym/README.md index 5e06ebbd86..84f8839d5f 100644 --- a/packages/fetchai/protocols/gym/README.md +++ b/packages/fetchai/protocols/gym/README.md @@ -51,4 +51,4 @@ keep_terminal_state_dialogues: false ## Links -* OpenAI Gym +- OpenAI Gym diff --git a/packages/fetchai/protocols/gym/protocol.yaml b/packages/fetchai/protocols/gym/protocol.yaml index 784782b2b7..ad910f4162 100644 --- a/packages/fetchai/protocols/gym/protocol.yaml +++ b/packages/fetchai/protocols/gym/protocol.yaml @@ -7,7 +7,7 @@ description: A protocol for interacting with a gym connection. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qma2cGSh5ZPoKYFwD2jQ9jscUaCnXfAYG7d7GKRCoWCSJY + README.md: QmVv9RWqFe16t8ar8K9UrPxXd422VubyPcekKPeYBVnXwx __init__.py: QmSvPUzRBduygp7MS1xmzGxon4UXCKxxgaR8JhxS2PQHf8 custom_types.py: QmX11ojHWTmPcEVWk8fzDiHdKwDQDccTLPYx8KoPiKiPPS dialogues.py: QmTjYmokn1ayZYPSosarwJMpTPU4jAHfy4rftDgzcvNGLb diff --git a/packages/fetchai/protocols/http/README.md b/packages/fetchai/protocols/http/README.md index 289196af6f..5bfb4f1b8d 100644 --- a/packages/fetchai/protocols/http/README.md +++ b/packages/fetchai/protocols/http/README.md @@ -43,4 +43,4 @@ keep_terminal_state_dialogues: false ## Links -* HTTP Specification +- HTTP Specification diff --git a/packages/fetchai/protocols/http/protocol.yaml b/packages/fetchai/protocols/http/protocol.yaml index a993c5a6d4..f6e59e9b2c 100644 --- a/packages/fetchai/protocols/http/protocol.yaml +++ b/packages/fetchai/protocols/http/protocol.yaml @@ -7,7 +7,7 @@ description: A protocol for HTTP requests and responses. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmcZmB65nV5YAodzDTvj2Fp5VYD9gfLQcuRp65Z1VQS5xM + README.md: QmTjWriXYziJZPT7S9tuG19Af7h5V6qCWW8nqXjW8P2eLN __init__.py: QmatteE6QhCeWxHKpFxLH9ZB1kjVDA3jVNwkiBjW7r6Xzx dialogues.py: QmUcjazcTHwvVMQk2vPjsJQjscbm5mE1mKBHYVUrNJbTsR http.proto: Qmag9uQYVPQwsdZfH1GEaBX5xgikoYuphQpXnWP2xob6Ys diff --git a/packages/fetchai/protocols/tac/README.md b/packages/fetchai/protocols/tac/README.md index 1cb6475ffc..af1ed81c1b 100644 --- a/packages/fetchai/protocols/tac/README.md +++ b/packages/fetchai/protocols/tac/README.md @@ -86,4 +86,4 @@ keep_terminal_state_dialogues: true ## Links -* TAC skill in the AEA framework +- TAC skill in the AEA framework diff --git a/packages/fetchai/protocols/tac/protocol.yaml b/packages/fetchai/protocols/tac/protocol.yaml index 718904e89c..9c34559daa 100644 --- a/packages/fetchai/protocols/tac/protocol.yaml +++ b/packages/fetchai/protocols/tac/protocol.yaml @@ -8,7 +8,7 @@ description: The tac protocol implements the messages an AEA needs to participat license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmNRbnPjaBY74axmHbz1Nt3tJxeYNKdXhQ2s35WkvJLVrN + README.md: QmPhQKfSQEt8CEAvj2zsvjMCPyin2d1oHKY5mSTYGcJ3qL __init__.py: QmYtMZSvoLkKpvtFeHq73CErchuNGvQF2SvaEKkmpFoYWy custom_types.py: QmWUg194r4jqm6U2SY4B9CADn2bNE56qrpWJrVnGPvSz8v dialogues.py: QmRhZrnyT4YaXsPXAr1ota3ndp64MAcc3XNcGF2sCN4z4Q diff --git a/packages/fetchai/skills/advanced_data_request/README.md b/packages/fetchai/skills/advanced_data_request/README.md index b29cf5438b..7f8a6fe9b0 100644 --- a/packages/fetchai/skills/advanced_data_request/README.md +++ b/packages/fetchai/skills/advanced_data_request/README.md @@ -6,8 +6,8 @@ This skill is used to get specific data from an API, which can either be shared ## Behaviours -* `advanced_data_request_behaviour`: requests data from specified source every `tick_interval` seconds from the API endpoint `url` specified in the skill configuration. +- `advanced_data_request_behaviour`: requests data from specified source every `tick_interval` seconds from the API endpoint `url` specified in the skill configuration. ## Handlers -* `http`: handles incoming `http` messages, retrieves the data from the appropriate response, stores it in shared state under the key: `observation`, and responds to requests satisfying the API specification listed in `api_spec.yaml`. +- `http`: handles incoming `http` messages, retrieves the data from the appropriate response, stores it in shared state under the key: `observation`, and responds to requests satisfying the API specification listed in `api_spec.yaml`. diff --git a/packages/fetchai/skills/advanced_data_request/skill.yaml b/packages/fetchai/skills/advanced_data_request/skill.yaml index fdc275a627..092df1e556 100644 --- a/packages/fetchai/skills/advanced_data_request/skill.yaml +++ b/packages/fetchai/skills/advanced_data_request/skill.yaml @@ -6,7 +6,7 @@ description: Retrieve data from an API license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmQEKGxJfUy6vg3aPg6jRNHQ4vzr4rUHYVac5eYG5C6Uxb + README.md: QmaibnVqk95FVuhSXKCsYvUQFAkLCwYtPyWDmaNVDSFWvp __init__.py: Qma4ivubRLou6uMtfYwuqMzRymYWmYGNS4CZEZXMxHGZR5 api_spec.yaml: QmUPhCYr6tWDMysdMCQxT67oAKRdMbGpgqDfAA5wpei12s behaviours.py: QmNubn8GCjV2d12FQu2Zv3FjXyoxoEsKzAg3fbskhtL3S2 diff --git a/packages/fetchai/skills/aries_alice/README.md b/packages/fetchai/skills/aries_alice/README.md index dcca1a398c..523675af06 100644 --- a/packages/fetchai/skills/aries_alice/README.md +++ b/packages/fetchai/skills/aries_alice/README.md @@ -8,15 +8,15 @@ This skill is part of the Fetch.ai Aries demo. It simulates the Alice actor of t ## Behaviours -* `alice`: registers and unregisters Alice AEA on the sOEF +- `alice`: registers and unregisters Alice AEA on the sOEF ## Handlers -* `default`: handles `default` messages for the invitation detail it receives from the Faber AEA -* `http`: handles `http` messages for communicating with Alice ACA -* `oef_search`: handles `oef_search` messages if registration on the sOEF was erratic +- `default`: handles `default` messages for the invitation detail it receives from the Faber AEA +- `http`: handles `http` messages for communicating with Alice ACA +- `oef_search`: handles `oef_search` messages if registration on the sOEF was erratic ## Links -* AEA Aries Demo -* Hyperledger Demo +- AEA Aries Demo +- Hyperledger Demo diff --git a/packages/fetchai/skills/aries_alice/skill.yaml b/packages/fetchai/skills/aries_alice/skill.yaml index 245cc88e9d..5bda467e1b 100644 --- a/packages/fetchai/skills/aries_alice/skill.yaml +++ b/packages/fetchai/skills/aries_alice/skill.yaml @@ -7,7 +7,7 @@ description: The aries_alice skill implements the alice player in the aries clou license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qmc88RFakLqDTqT42YGJDCDrH22tW2dkCBAs8wLKMGt5TV + README.md: QmdtgELuz8SmSp3xdHdktd1SvmzSFsavwVYXjZxPMke5ij __init__.py: QmbjrRC14YPUd2mXsD8K4SpiVNzvh1tmoVyJ9WUNiuw9fx behaviours.py: QmYc2UCizXg86mBBjS43K73Bq3URdnsW5BefnzfzA7fz4k dialogues.py: QmQvsX9sx5bDf588rrXmT2kzZSZapVpix2TkX4x422iTiu diff --git a/packages/fetchai/skills/aries_faber/README.md b/packages/fetchai/skills/aries_faber/README.md index 6bc07674a7..a6b8fbb08e 100644 --- a/packages/fetchai/skills/aries_faber/README.md +++ b/packages/fetchai/skills/aries_faber/README.md @@ -5,22 +5,23 @@ This skill emulates the Faber actor in this demo. This skill is part of the Fetch.ai Aries demo. It simulates the Faber actor of the demo linked above. It first registers a decentralised ID on an underlying ledger. It then connects with an underlying Aries cloud agent (ACA) instance, and forwards the following instructions: - * register schema definition - * register credential definition - * create an invitation - + +- register schema definition +- register credential definition +- create an invitation + It then sends the invitation detail to an Alice agent that it finds via the sOEF. ## Behaviours -* `faber`: searches for Alice AEA +- `faber`: searches for Alice AEA ## Handlers -* `http`: handles `http` messages for communicating with the ledger and Faber ACA -* `oef_search`: handles `oef_search` messages of finding Alice on the sOEF +- `http`: handles `http` messages for communicating with the ledger and Faber ACA +- `oef_search`: handles `oef_search` messages of finding Alice on the sOEF ## Links -* AEA Aries Demo -* Hyperledger Demo +- AEA Aries Demo +- Hyperledger Demo diff --git a/packages/fetchai/skills/aries_faber/skill.yaml b/packages/fetchai/skills/aries_faber/skill.yaml index e26dfd2a07..f4786129f3 100644 --- a/packages/fetchai/skills/aries_faber/skill.yaml +++ b/packages/fetchai/skills/aries_faber/skill.yaml @@ -7,7 +7,7 @@ description: The aries_faber skill implements the faber player in the aries clou license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmUQB9uBtWGWY5zETSyJnbPZixRj1c4suedVwGPegrTQWs + README.md: QmYKuXNqtkUvz4esnYnmg2iUvN3cNKTUzF92NmwPbD66L3 __init__.py: QmQCKiH4mSda1NGCJDuGieQjxnyPi5mtfvPhYqqCVuJixf behaviours.py: QmZRkMM7UMa7x6jdUkHyDtGq1kBXVTHDwszcDna3HNQsdE dialogues.py: QmRXXA2vT1r65yb8iKAdhCbys7s2wy2M9Cjpf6jfEX6KZB diff --git a/packages/fetchai/skills/carpark_client/README.md b/packages/fetchai/skills/carpark_client/README.md index 12074901f1..84e642f5fa 100644 --- a/packages/fetchai/skills/carpark_client/README.md +++ b/packages/fetchai/skills/carpark_client/README.md @@ -6,20 +6,18 @@ This skill purchases information on available car parking spaces in a vicinity. This skill finds an agent on the sOEF which sells car park availability data in a vicinity, requests this data, negotiates the price, pays the proposed amount if agreement is reach, and receives the data bought. - ## Behaviours -* `search`: searches for car park data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for car park data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Car Park Demo +- Car Park Demo diff --git a/packages/fetchai/skills/carpark_client/skill.yaml b/packages/fetchai/skills/carpark_client/skill.yaml index 631acfb436..523f6ed233 100644 --- a/packages/fetchai/skills/carpark_client/skill.yaml +++ b/packages/fetchai/skills/carpark_client/skill.yaml @@ -7,7 +7,7 @@ description: The carpark client skill implements the functionality to run a clie license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmXD1pndXTJafb8YY4xRTM47LCoeiQ9VxAvzj474TNknT4 + README.md: QmdrvGfoAncV3e76Aiq5irJSKYXXwmhJTv7w8hPoadcFgt __init__.py: Qmf2Ca5aSemKdy8R1FqLoiFeFqMxfxU5A9LrBmCf52KVwG behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix diff --git a/packages/fetchai/skills/carpark_detection/README.md b/packages/fetchai/skills/carpark_detection/README.md index ccd52ff4d1..02408276bf 100644 --- a/packages/fetchai/skills/carpark_detection/README.md +++ b/packages/fetchai/skills/carpark_detection/README.md @@ -8,14 +8,14 @@ This skill is part of the Fetch.ai car park demo. It registers the "car park ava ## Behaviours -* `service_registration`: registers car park info selling service on the sOEF +- `service_registration`: registers car park info selling service on the sOEF ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Links -* Car Park Demo +- Car Park Demo diff --git a/packages/fetchai/skills/carpark_detection/skill.yaml b/packages/fetchai/skills/carpark_detection/skill.yaml index 544f2607fc..d2bcd5ff88 100644 --- a/packages/fetchai/skills/carpark_detection/skill.yaml +++ b/packages/fetchai/skills/carpark_detection/skill.yaml @@ -7,7 +7,7 @@ description: The carpark detection skill implements the detection and trading fu license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qmd5Xe9jY8AjJjFR5QY7L9QQ3AeCEKx837UgiGuf3BSRVN + README.md: QmZYxDqNu3RnTkhNCgp7VPBMpYxaqRT4Hb64ipgYvgJ5wn __init__.py: QmPqGBZJSu9XPcwatszvuqeWYdurUnLRb17vDtqybNwUBd behaviours.py: QmYgNwz5EA4yhEnMyiV3oe16g1MAKpFPJsTENfkVMySfr8 database.py: QmQ2Gh58YtC1eHAu1bavLPh6D9xeDaAGgye8vG2Z1SYjgA diff --git a/packages/fetchai/skills/confirmation_aw1/README.md b/packages/fetchai/skills/confirmation_aw1/README.md index e7da239aa6..84beb04f62 100644 --- a/packages/fetchai/skills/confirmation_aw1/README.md +++ b/packages/fetchai/skills/confirmation_aw1/README.md @@ -6,15 +6,15 @@ The `confirmation_aw1` skill is for handling registrations in Agent World 1. ## Behaviours -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `contract_api`: handles `contract_api` messages for communication with a staking contract -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `registration`: handles `register` messages for registration requests -* `signing`: handles `signing` messages for transaction signing by the decision maker +- `contract_api`: handles `contract_api` messages for communication with a staking contract +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `registration`: handles `register` messages for registration requests +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Models -* `strategy`: contains the confirmation configuration +- `strategy`: contains the confirmation configuration diff --git a/packages/fetchai/skills/confirmation_aw1/skill.yaml b/packages/fetchai/skills/confirmation_aw1/skill.yaml index b636cf2dcc..99ba0b621b 100644 --- a/packages/fetchai/skills/confirmation_aw1/skill.yaml +++ b/packages/fetchai/skills/confirmation_aw1/skill.yaml @@ -7,7 +7,7 @@ description: The confirmation_aw1 skill is a skill to confirm registration for A license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmWEG3A5xRL3yf65UHfrKhUwazR5bjpxSiuuBGMYX7t7Co + README.md: QmaGTwfKyYVAJEfqHjGVViTYer2f3JJj22ftQH19NuA3eQ __init__.py: Qmc4MHyZV31ZKUxc4QsRtpVhr6WGWCpCrVyNsxj7Xs9CrF behaviours.py: QmZVaGLyZZZJu5HBR1rNukpfnvpvEFxn8tA2JKL8JgFWUB dialogues.py: QmQnYQyRtmFYhHxCirxg5vchWSogwnKVEgozKBwL19svGe diff --git a/packages/fetchai/skills/confirmation_aw2/README.md b/packages/fetchai/skills/confirmation_aw2/README.md index 8563297198..eeb564b10a 100644 --- a/packages/fetchai/skills/confirmation_aw2/README.md +++ b/packages/fetchai/skills/confirmation_aw2/README.md @@ -6,21 +6,19 @@ This skill purchases information from other agents as specified in its configura This skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once it found some agents which match Agent World 2 criteria, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought. - ## Behaviours -* `search`: searches for data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `default`: handles `default` messages for registration -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `default`: handles `default` messages for registration +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Models -* `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 2 are enforced. +- `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 2 are enforced. diff --git a/packages/fetchai/skills/confirmation_aw2/skill.yaml b/packages/fetchai/skills/confirmation_aw2/skill.yaml index 4489d9ee73..2010dffe59 100644 --- a/packages/fetchai/skills/confirmation_aw2/skill.yaml +++ b/packages/fetchai/skills/confirmation_aw2/skill.yaml @@ -7,7 +7,7 @@ description: This skill purchases information from other agents as specified in license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmQtVnRU5nNhxkaVKX6Go5G4X5dVcocLGM5uynZ1wzHCKK + README.md: QmSQgVJrmh5XBGLKVmzEzUVmeEr6BmZmeWebqixq6EBftd __init__.py: QmYE19gCv9jnQxhQLGiSB8qkFHgUNvyY7a8N4GNxqexCRh behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix diff --git a/packages/fetchai/skills/confirmation_aw3/README.md b/packages/fetchai/skills/confirmation_aw3/README.md index 50e1c8bb1a..3f4afd8bb6 100644 --- a/packages/fetchai/skills/confirmation_aw3/README.md +++ b/packages/fetchai/skills/confirmation_aw3/README.md @@ -6,21 +6,19 @@ This skill purchases information from other agents as specified in its configura This skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once it found some agents which match Agent World 3 criteria, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought. The skill just randomly selects the location in which it searches and the query from a list. On each search it completes as many trade as possible. - ## Behaviours -* `search`: searches for data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `default`: handles `default` messages for registration -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `default`: handles `default` messages for registration +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Models -* `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 3 are enforced. +- `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 3 are enforced. diff --git a/packages/fetchai/skills/confirmation_aw3/skill.yaml b/packages/fetchai/skills/confirmation_aw3/skill.yaml index 6c949ac9b8..e7d59a7515 100644 --- a/packages/fetchai/skills/confirmation_aw3/skill.yaml +++ b/packages/fetchai/skills/confirmation_aw3/skill.yaml @@ -7,7 +7,7 @@ description: This skill purchases information from other agents as specified in license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmNecTgkCBTBCsNB4B5o3YVwdAC3xozJodg8NiAWMT1zyf + README.md: Qmc4XzqCbGB6mS17ZuvW2xuYnR796NX5KD3fyaNqchLirS __init__.py: QmX6XqvWwpXSoGxj7bjR7T53JmHs4dtixnNwKxeBkbAJXP behaviours.py: QmagZNufvC8QgMRkPokWg71Gg2nbNSL5bBurxZtvgpGVhw dialogues.py: QmXzPttMCTFQxh7R1BXzqFcdezGp7yybstkZDPJFzjECMM diff --git a/packages/fetchai/skills/echo/README.md b/packages/fetchai/skills/echo/README.md index 77e2132c58..371ee0c9b8 100644 --- a/packages/fetchai/skills/echo/README.md +++ b/packages/fetchai/skills/echo/README.md @@ -4,15 +4,15 @@ This skill sends back the contents of any message it receives. -## Behaviours +## Behaviours -* `echo`: outputs messages +- `echo`: outputs messages ## Handlers -* `echo`: handles `default` messages for echoing back the contents of any message received +- `echo`: handles `default` messages for echoing back the contents of any message received ## Links -* Quick Start -* Programmatically Build an AEA \ No newline at end of file +- Quick Start +- Programmatically Build an AEA diff --git a/packages/fetchai/skills/echo/skill.yaml b/packages/fetchai/skills/echo/skill.yaml index 168e2bfe24..39ef653f3c 100644 --- a/packages/fetchai/skills/echo/skill.yaml +++ b/packages/fetchai/skills/echo/skill.yaml @@ -6,7 +6,7 @@ description: The echo skill implements simple echo functionality. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmX9GoSQWdmvvWuf3VZjKy5fSAARmrLVxUpu2eGrXzocHB + README.md: QmNijzN1uUKmcH64VUGCfZBDzAnJjkqjUrnFALVaAceU6i __init__.py: QmWrAvFTQmJ7prk9VnTahykP5qad7YvjUMNwCGVGbebXdk behaviours.py: QmRAFuVFQr6LkXLU8jMkHksd2YUiTrx2ABSSTZgFrJpFxT dialogues.py: QmeV9E8Qf5cLCjWD3F5MLthpoP5oZwr52RJrAXc4p9ZntY diff --git a/packages/fetchai/skills/erc1155_client/README.md b/packages/fetchai/skills/erc1155_client/README.md index 8eba9abf4c..6e1c0dc0e4 100644 --- a/packages/fetchai/skills/erc1155_client/README.md +++ b/packages/fetchai/skills/erc1155_client/README.md @@ -6,20 +6,18 @@ This is a skill for demoing the purchase of data via a smart contract. This skill finds an `ERC1155 contract deployment AEA` on the sOEF, requests specific data, negotiates the price, pays the proposed amount via smart contract if agreement is reach, and receives the data bought. - ## Behaviours -* `search`: searches for the ERC1155 deployment agent on the sOEF +- `search`: searches for the ERC1155 deployment agent on the sOEF ## Handlers -* `contract_api`: handles `contract_api` messages for interactions with the smart contract -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `contract_api`: handles `contract_api` messages for interactions with the smart contract +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Contract Deployment Guide +- Contract Deployment Guide diff --git a/packages/fetchai/skills/erc1155_client/skill.yaml b/packages/fetchai/skills/erc1155_client/skill.yaml index a8c2948675..45c76512f0 100644 --- a/packages/fetchai/skills/erc1155_client/skill.yaml +++ b/packages/fetchai/skills/erc1155_client/skill.yaml @@ -7,7 +7,7 @@ description: The erc1155 client interacts with the erc1155 deployer to conduct a license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmWwmYKMpr8A9VsN1dNAi8BdfkbVhFVrDfaSZeEgwgcVGv + README.md: QmYpkQVUiWY7aWc8xN8FMzxKWSawHs2cyjWijzK6PDbsLX __init__.py: QmeS5fozP8DJKLZwuDbB9kxs3PFBthxB4RPupfFEyGmFvD behaviours.py: QmQohMmSi8PYAeyjGcusSaMbEAeSsVXGcVtS5XZjLgdPg1 dialogues.py: QmVFyavVzUv88AZGD8Wca4yyV4y9DU3Akw5M4RFxqnAnUm diff --git a/packages/fetchai/skills/erc1155_deploy/README.md b/packages/fetchai/skills/erc1155_deploy/README.md index b74595aaa3..9fc6b89cf7 100644 --- a/packages/fetchai/skills/erc1155_deploy/README.md +++ b/packages/fetchai/skills/erc1155_deploy/README.md @@ -8,16 +8,16 @@ This skill registers some data selling service on the sOEF. It can be requested ## Behaviours -* `service_registration`: Deploys the smart contract, creates and mints tokens, registers `ERC1155 data selling service` on the sOEF +- `service_registration`: Deploys the smart contract, creates and mints tokens, registers `ERC1155 data selling service` on the sOEF ## Handlers -* `contract_api`: handles `contract_api` messages for interactions with the smart contract -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger. -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful -* `signing`: handles `signing` messages for transaction signing by the decision maker +- `contract_api`: handles `contract_api` messages for interactions with the smart contract +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger. +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Contract Deployment Guide +- Contract Deployment Guide diff --git a/packages/fetchai/skills/erc1155_deploy/skill.yaml b/packages/fetchai/skills/erc1155_deploy/skill.yaml index 76a6a4e79d..3891c086d7 100644 --- a/packages/fetchai/skills/erc1155_deploy/skill.yaml +++ b/packages/fetchai/skills/erc1155_deploy/skill.yaml @@ -7,7 +7,7 @@ description: The ERC1155 deploy skill has the ability to deploy and interact wit license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmNg45JuqfVzDmvgpWLeaR861LSEvf9pishDKSPihtQnLE + README.md: QmX98yCz4tVKF5dJUDUVh6T4vD3y9Gv42semKkpckqXjAA __init__.py: QmP9qVeTABzn1jbAAbfMhFNvyeRih9gMXvVZto7YFK4Cfe behaviours.py: QmXxfA42Zi2eYgfRQEKDxcotw628KTTRPTCyeJv6aBJmuH dialogues.py: QmRsL56kWqrs6pf8MKBdU1bxrYpuwgt63yugtMYnjWmzvo diff --git a/packages/fetchai/skills/error/README.md b/packages/fetchai/skills/error/README.md index fcd2160739..0a88385b67 100644 --- a/packages/fetchai/skills/error/README.md +++ b/packages/fetchai/skills/error/README.md @@ -10,7 +10,6 @@ It handles the following cases: - AEA experiences a decoding error when reading an envelope, - AEA receives an envelope referencing a protocol for which no skill is active. - ## Handlers -* `error_handler`: handles `default` messages for problematic envelopes/messages. +- `error_handler`: handles `default` messages for problematic envelopes/messages. diff --git a/packages/fetchai/skills/error/skill.yaml b/packages/fetchai/skills/error/skill.yaml index eda07a620f..35e6309605 100644 --- a/packages/fetchai/skills/error/skill.yaml +++ b/packages/fetchai/skills/error/skill.yaml @@ -6,7 +6,7 @@ description: The error skill implements basic error handling required by all AEA license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmXqqMwZhZWcrUFxQ4S9FsFsUw5RmMaDQwR9LcKUrRTpH7 + README.md: QmNw5XkR9DfMycuD3j7dpGdvnyQEZTBRoYdraFiTXYTLkv __init__.py: QmW5BcBz9ynfV4SDCx2QMLwHfns1EJqSiEJf7U7BfoBn6e handlers.py: QmfEqAzS2PTcxrgh7crVrvuDVkjF3Fa2GndRyUu8UPUSq4 fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/skills/error_test_skill/README.md b/packages/fetchai/skills/error_test_skill/README.md index 4c46d680d0..cda2fba099 100644 --- a/packages/fetchai/skills/error_test_skill/README.md +++ b/packages/fetchai/skills/error_test_skill/README.md @@ -4,9 +4,9 @@ Skill raises an exception on behaviour's act -## Behaviours +## Behaviours -* RaiseError - just raises an error on act +- RaiseError - just raises an error on act ## Handlers diff --git a/packages/fetchai/skills/error_test_skill/skill.yaml b/packages/fetchai/skills/error_test_skill/skill.yaml index 7c15eef980..362bd23d71 100644 --- a/packages/fetchai/skills/error_test_skill/skill.yaml +++ b/packages/fetchai/skills/error_test_skill/skill.yaml @@ -6,7 +6,7 @@ description: The error test skil for testing. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmagPotUCmCn9Ht33h3TL4VFX8g4gqB7UMTKzpXMvy6Nq9 + README.md: QmWt4ZwTxErR6E8jhJGNoL7aJ2Re1W9WjZ9J13gh2xzKeX __init__.py: QmX4LUU6y8wtXBsahnAnFLCzQM3Qqry4oNQ3o5fThPgxNJ behaviours.py: Qmcfd3fEUiKgSPcXpeTMtCojfjpGBc9LjRwx3X22TsMxKW fingerprint_ignore_patterns: [] diff --git a/packages/fetchai/skills/fetch_block/README.md b/packages/fetchai/skills/fetch_block/README.md index fcf54305c5..85fd3a95b5 100644 --- a/packages/fetchai/skills/fetch_block/README.md +++ b/packages/fetchai/skills/fetch_block/README.md @@ -6,8 +6,8 @@ This skill is used to get the latest block data from the Fetch ledger. ## Behaviours -* `fetch_block_behaviour`: requests latest block data every `tick_interval` seconds from the REST endpoint for the FetchAI ledger. +- `fetch_block_behaviour`: requests latest block data every `tick_interval` seconds from the REST endpoint for the FetchAI ledger. ## Handlers -* `http`: handles incoming `http` messages, retrieves the block data from the appropriate response, and stores it in shared state under the key: `block_data`. +- `http`: handles incoming `http` messages, retrieves the block data from the appropriate response, and stores it in shared state under the key: `block_data`. diff --git a/packages/fetchai/skills/fetch_block/skill.yaml b/packages/fetchai/skills/fetch_block/skill.yaml index d8e774d374..90312af720 100644 --- a/packages/fetchai/skills/fetch_block/skill.yaml +++ b/packages/fetchai/skills/fetch_block/skill.yaml @@ -6,7 +6,7 @@ description: Retrieve the latest block from the Fetch ledger license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmTSH7GkNmRif1a7dZf5aTmBjkr2tVpu7bnBNMTVFKfg5Z + README.md: QmNi2rZ6b8pgx5Uop4FMvNagGLbzHEJUruwFzbqHMHpYtd __init__.py: QmYB6cYBbaxn13xHVG45RuqeVLYdAPx2W5kiAjEjG4MEJK behaviours.py: Qmdg334UUoAyvcuqv2eVKAG42fMYzB4kqTjDcyBZsWtoYJ dialogues.py: Qma1KWoLRxPJMaxacGLbVEdkuvERG7UbmA4hT385KYww3A diff --git a/packages/fetchai/skills/generic_buyer/README.md b/packages/fetchai/skills/generic_buyer/README.md index 13862447e8..f752ca3782 100644 --- a/packages/fetchai/skills/generic_buyer/README.md +++ b/packages/fetchai/skills/generic_buyer/README.md @@ -6,21 +6,19 @@ This is a generic skill for buying data. This skill finds an agent on the sOEF which sells data, requests specific data, negotiates the price, pays the proposed amount if agreement is reach, and receives the data bought. - ## Behaviours -* `search`: searches for data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Generic Skills -* Generic Skill Step by Step Guide +- Generic Skills +- Generic Skill Step by Step Guide diff --git a/packages/fetchai/skills/generic_buyer/skill.yaml b/packages/fetchai/skills/generic_buyer/skill.yaml index 3f57805976..a2edfeb17d 100644 --- a/packages/fetchai/skills/generic_buyer/skill.yaml +++ b/packages/fetchai/skills/generic_buyer/skill.yaml @@ -6,7 +6,7 @@ description: The weather client skill implements the skill to purchase weather d license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qmd7hF4eNgxUoGaxkPEKVPQNxpLG2aG4DvovSLKkwKxVYt + README.md: QmRUURLxvnfRR8Qq1UBeecFRoKiJLxQJj5GtUyKP7SyhTu __init__.py: QmdFyK7JXnVCnDHhHpAEX8BesiWstjWVm2x4aAKwTRVQmx behaviours.py: QmVydJUVMEG4o2WNFdPN1bo8Rv46c7Mpt8K5jQkF2fpPLz dialogues.py: QmZ8yqZRJ8KhFXcfA5H7XWBTyqZf9tCyCR22HVUpfb6aJs diff --git a/packages/fetchai/skills/generic_seller/README.md b/packages/fetchai/skills/generic_seller/README.md index 3ac8c59299..204bada524 100644 --- a/packages/fetchai/skills/generic_seller/README.md +++ b/packages/fetchai/skills/generic_seller/README.md @@ -8,15 +8,15 @@ This skill registers some data selling service on the sOEF. It can be requested ## Behaviours -* `service_registration`: registers data selling service on the sOEF +- `service_registration`: registers data selling service on the sOEF ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Links -* Generic Skills -* Generic Skill Step by Step Guide +- Generic Skills +- Generic Skill Step by Step Guide diff --git a/packages/fetchai/skills/generic_seller/skill.yaml b/packages/fetchai/skills/generic_seller/skill.yaml index 808ae59002..caec982601 100644 --- a/packages/fetchai/skills/generic_seller/skill.yaml +++ b/packages/fetchai/skills/generic_seller/skill.yaml @@ -7,7 +7,7 @@ description: The weather station skill implements the functionality to sell weat license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmQ3hBSdCTwsFziUgPkbUqRcBU95yF2yZfrGXbowgaof5R + README.md: QmfQM11g1zjQYDUmia3eFmeckab2FDBCGwG8QDRZfEG4RY __init__.py: QmWHqoio5YTW5CJNaZaUJQsxMfcKicASSdL8rhUFAwkL3K behaviours.py: QmNmZHrFPVninUyyNDWng6o9fBLZ2vJmVLRxP1fzMapLai dialogues.py: QmXcoYGuAdAD5HerA2khymJicPqf9VgtZ9YS6zx4mx8MWy diff --git a/packages/fetchai/skills/gym/README.md b/packages/fetchai/skills/gym/README.md index 6d27284c17..e62b513585 100644 --- a/packages/fetchai/skills/gym/README.md +++ b/packages/fetchai/skills/gym/README.md @@ -8,11 +8,10 @@ This skill is part of the Fetch.ai Gym demo. It trains a reinforcement learning ## Handlers -* `gym`: handles `gym` messages for interactions with a gym environment. - +- `gym`: handles `gym` messages for interactions with a gym environment. ## Links -* Gym Demo -* Gym Example -* OpenAI Gym \ No newline at end of file +- Gym Demo +- Gym Example +- OpenAI Gym diff --git a/packages/fetchai/skills/gym/skill.yaml b/packages/fetchai/skills/gym/skill.yaml index d166b425b7..9cc79047a0 100644 --- a/packages/fetchai/skills/gym/skill.yaml +++ b/packages/fetchai/skills/gym/skill.yaml @@ -6,7 +6,7 @@ description: The gym skill wraps an RL agent. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmPwx59WZfJjauEiEXhcfQeUH1zFeEbkr1G8i2KVPWYao6 + README.md: QmeYFajc1RJmSTi37WtrT6bY6cBNs5jua7oVkxbUegK3tW __init__.py: QmdutuKyrDd3rLZApR43ho4Diz8ApZsRdC8wk6tjJ2aNYk dialogues.py: QmVePSYdPfXczXsriLxWguySkzHrRqkvs17HYhCu3W1poH handlers.py: QmQB9c4Pf4Unr4qDEbsFinKeLJGZVukq5V4k8U3jcfqcAo diff --git a/packages/fetchai/skills/http_echo/README.md b/packages/fetchai/skills/http_echo/README.md index 5614d317fd..990a8e4206 100644 --- a/packages/fetchai/skills/http_echo/README.md +++ b/packages/fetchai/skills/http_echo/README.md @@ -8,8 +8,8 @@ This skill is part of the Fetch.ai "HTTP Connection and Skill" guide. Upon recei ## Handlers -* `http_handler`: handles `http` messages for echoing back an HTTP request as an HTTP response. +- `http_handler`: handles `http` messages for echoing back an HTTP request as an HTTP response. ## Links -* HTTP Connection and Skill \ No newline at end of file +- HTTP Connection and Skill diff --git a/packages/fetchai/skills/http_echo/skill.yaml b/packages/fetchai/skills/http_echo/skill.yaml index a642e5dd75..8a3d2f4fc2 100644 --- a/packages/fetchai/skills/http_echo/skill.yaml +++ b/packages/fetchai/skills/http_echo/skill.yaml @@ -7,7 +7,7 @@ description: The http echo skill prints out the content of received http message license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmYC2Y95Mg327LyHzQ3WbxZA8g1NfSHasmDTRcvrGCXmiR + README.md: QmPCkgR8tH6rUeBhiykisZsQ3qi4eoSRVSx2xhyjCULnu1 __init__.py: QmTSqVqRhVrU7Xq9hgrAN2hZH1WdQxdCvHFyUkib6XKkJo dialogues.py: QmXft7PHDgb8MgEicPukB768qKLxNgYorX6VpNR4vDSLU6 handlers.py: QmQrwrsyp5qpFeerfSM8iBVdsowTfZa9Fwso5juN1Q8Vw8 diff --git a/packages/fetchai/skills/ml_data_provider/README.md b/packages/fetchai/skills/ml_data_provider/README.md index 6369779d5b..a33ca9a5c8 100644 --- a/packages/fetchai/skills/ml_data_provider/README.md +++ b/packages/fetchai/skills/ml_data_provider/README.md @@ -8,14 +8,14 @@ This skill is part of the Fetch.ai ML skill demo. It registers its "ML data sell ## Behaviours -* `service_registration`: registers service on the sOEF search service +- `service_registration`: registers service on the sOEF search service ## Handlers -* `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Links -* ML Demo +- ML Demo diff --git a/packages/fetchai/skills/ml_data_provider/skill.yaml b/packages/fetchai/skills/ml_data_provider/skill.yaml index cd6063d4fa..e5b440cee1 100644 --- a/packages/fetchai/skills/ml_data_provider/skill.yaml +++ b/packages/fetchai/skills/ml_data_provider/skill.yaml @@ -7,7 +7,7 @@ description: The ml data provider skill implements a provider for Machine Learni license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmYBr97UhQA8GoWFN6yNKdWix1AKJYx4zY246HYAFGpYRP + README.md: QmcPsTwjWbUTMamK8aH94yRgYrKrmCwzffmMUueLya5wAg __init__.py: QmcknNVN92YuDs73HveMKx5Dkr6JCxHfzeF7ywX3tSRakX behaviours.py: QmZvLViapWxG1H41wn4e6Mzt8nmV6yyuk2sSsLJKZTQy2c dialogues.py: QmaVve3Ldt3TN1QSA1x58tBruPDRZ5bnVYHencsVHvfsoh diff --git a/packages/fetchai/skills/ml_train/README.md b/packages/fetchai/skills/ml_train/README.md index 0427f17727..23af78789b 100644 --- a/packages/fetchai/skills/ml_train/README.md +++ b/packages/fetchai/skills/ml_train/README.md @@ -8,17 +8,16 @@ This skill is part of the Fetch.ai ML skill demo. It finds an agent which sells ## Behaviours -* `search`: searches for ML data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for ML data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* ML Demo \ No newline at end of file +- ML Demo diff --git a/packages/fetchai/skills/ml_train/skill.yaml b/packages/fetchai/skills/ml_train/skill.yaml index 98c5d90099..d4707e8008 100644 --- a/packages/fetchai/skills/ml_train/skill.yaml +++ b/packages/fetchai/skills/ml_train/skill.yaml @@ -7,7 +7,7 @@ description: The ml train and predict skill implements a simple skill which buys license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmUk1XEpYnxte5GKZjSvJY2LJPpVzzP6zLvnxT2Y1g9f4m + README.md: QmPzgPycfq5bRWQhFqy1ARH1vMyXzDZucn9zXuf4V3hGnS __init__.py: QmX3a1CNyyPNTp7iLVc1P47JSrPiRV7TxVwZv6GhgxUBPX behaviours.py: QmWeexaVncgAR3vZa3CBDfvzTfZDTcG6GXHwFjbM6wzJed dialogues.py: QmdVwUF6wjX8bkfpsnog7KGF269HK5395DUjmqD1eT3qUR diff --git a/packages/fetchai/skills/registration_aw1/README.md b/packages/fetchai/skills/registration_aw1/README.md index 2160d77884..c80dedfdc5 100644 --- a/packages/fetchai/skills/registration_aw1/README.md +++ b/packages/fetchai/skills/registration_aw1/README.md @@ -6,13 +6,13 @@ The `registration_aw1` skill is for registration in Agent World 1. ## Behaviours -* `registration`: manages the registration flow. +- `registration`: manages the registration flow. ## Handlers -* `registration`: handles `register` messages. -* `signing`: handles `signing` messages for transaction signing by the decision maker +- `registration`: handles `register` messages. +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Models -* `strategy`: contains the registration configurations +- `strategy`: contains the registration configurations diff --git a/packages/fetchai/skills/registration_aw1/skill.yaml b/packages/fetchai/skills/registration_aw1/skill.yaml index 1e876a1ca3..050ff07811 100644 --- a/packages/fetchai/skills/registration_aw1/skill.yaml +++ b/packages/fetchai/skills/registration_aw1/skill.yaml @@ -7,7 +7,7 @@ description: The registration_aw1 skill is a skill for registration in Agent Wor license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: Qmc9dfzqAXJWCJxYNqLd1yz8U7p4DQNbGGMmXMP73wUvJR + README.md: QmUMdQxB7uC3SuP92vfiCRr4fHUeWMcfJNmJ74BoCk8eHT __init__.py: QmegXC4RzwC3pZw8SzsW41Yk2sHGHMor6FK9Frz7eGdyUd behaviours.py: QmS5mMwaq2pQSaphNPA4QRxXRBBUpVerLvpYfg532Hb9wk dialogues.py: QmbdecnniJWxH7dnNUB14JKU16BwSKx37USyqcJahEQpVw diff --git a/packages/fetchai/skills/simple_aggregation/README.md b/packages/fetchai/skills/simple_aggregation/README.md index 9ac71dd434..b3ecbc9051 100644 --- a/packages/fetchai/skills/simple_aggregation/README.md +++ b/packages/fetchai/skills/simple_aggregation/README.md @@ -6,10 +6,10 @@ This skill is used to find peers on the agent communication network, exchange ob ## Behaviours -* `search_behaviour`: searches for other aggregating peers every `search_interval` seconds, as specified in the skill configuration. -* `aggregation_behaviour`: makes observations and aggregates those received from peers every `aggregation_interval` seconds, as specified in the skill configuration. +- `search_behaviour`: searches for other aggregating peers every `search_interval` seconds, as specified in the skill configuration. +- `aggregation_behaviour`: makes observations and aggregates those received from peers every `aggregation_interval` seconds, as specified in the skill configuration. ## Handlers -* `aggregation`: handles `aggregation` messages to and from peers -* `oef_search`: handles `oef_search` messages for interacting with the SOEF +- `aggregation`: handles `aggregation` messages to and from peers +- `oef_search`: handles `oef_search` messages for interacting with the SOEF diff --git a/packages/fetchai/skills/simple_aggregation/skill.yaml b/packages/fetchai/skills/simple_aggregation/skill.yaml index 263d5875fb..eae5e8c74c 100644 --- a/packages/fetchai/skills/simple_aggregation/skill.yaml +++ b/packages/fetchai/skills/simple_aggregation/skill.yaml @@ -6,7 +6,7 @@ description: The skill for aggregating observations between AEAs license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmSFsC6K217XxwuH5fXGQYU29J44VvW9Qim5yNPAbXLegV + README.md: QmcHh82NQkgDx4w2cNN6sGzWquSXEYp4BgPrbSBo5tTf2w __init__.py: QmcULexa5ETeBtWNkvYDSqXWDqf4n4x5rJBF7S3uZ2qsov behaviours.py: QmXsdJUEC9MPAGQvUgUYuZV8du9Dtejexbe941sqgYaSzh dialogues.py: QmeGB6miynaHtBG9LU96tiwCp8AKZwJ8y9oGqVeRNkWpvW diff --git a/packages/fetchai/skills/simple_buyer/README.md b/packages/fetchai/skills/simple_buyer/README.md index 591907b517..36f9444fab 100644 --- a/packages/fetchai/skills/simple_buyer/README.md +++ b/packages/fetchai/skills/simple_buyer/README.md @@ -6,20 +6,18 @@ This skill purchases information from other agents as specified in its configura This skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once found, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought. - ## Behaviours -* `search`: searches for data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Models -* `strategy`: allows the configuration of the purchasing. In particular, `location` and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. +- `strategy`: allows the configuration of the purchasing. In particular, `location` and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. diff --git a/packages/fetchai/skills/simple_buyer/skill.yaml b/packages/fetchai/skills/simple_buyer/skill.yaml index 7eb7a474b9..e43a9afe85 100644 --- a/packages/fetchai/skills/simple_buyer/skill.yaml +++ b/packages/fetchai/skills/simple_buyer/skill.yaml @@ -7,7 +7,7 @@ description: This skill purchases information from other agents as specified in license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmedLNAAofsr7WC4DqeU3qZNVwSQvPeqNHqdeLeua5qhDW + README.md: QmSYbruWV7Cte46FvKgPK8LcJXsShGMTmW6Q2oMxekz327 __init__.py: QmVVRVWEh66YZwNGpXNVcwhc2mZ5NA4X61MKKJZmXk4KXs behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix diff --git a/packages/fetchai/skills/simple_data_request/README.md b/packages/fetchai/skills/simple_data_request/README.md index 934e4b49da..858bffc553 100644 --- a/packages/fetchai/skills/simple_data_request/README.md +++ b/packages/fetchai/skills/simple_data_request/README.md @@ -6,8 +6,8 @@ This skill is used to request data from a HTTP endpoint and then save it in the ## Behaviours -* `http_request`: requests data every `request_interval` seconds from a HTTP endpoint using the `url`, `method` and `body` specified in the skill configuration. +- `http_request`: requests data every `request_interval` seconds from a HTTP endpoint using the `url`, `method` and `body` specified in the skill configuration. ## Handlers -* `http`: handles incoming `http` messages. Data received in responses is saved in the shared state using the key specified in the skill configuration: `shared_state_key`. +- `http`: handles incoming `http` messages. Data received in responses is saved in the shared state using the key specified in the skill configuration: `shared_state_key`. diff --git a/packages/fetchai/skills/simple_data_request/skill.yaml b/packages/fetchai/skills/simple_data_request/skill.yaml index af3086bb8f..1a3ed2f10d 100644 --- a/packages/fetchai/skills/simple_data_request/skill.yaml +++ b/packages/fetchai/skills/simple_data_request/skill.yaml @@ -7,7 +7,7 @@ description: This skill is used to request data from a HTTP endpoint and then sa license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmTpjAtR8qUBsF9TbwDRQ6Zg3TsDu4tP9GcQpYxHXcS6Ap + README.md: QmemL4YrZjQSMjhF2uymRmntNHSoyvAQ66R9TtnEwmDxiv __init__.py: QmUF9T3TLcR2enCvJVptLzsnjcLB5Ws41ByeXfZbmz8uLU behaviours.py: QmcAsxDGEjf2zofag5X3PxmaPBwrjqf9zoSZVdLwCUFRaC dialogues.py: QmVYsxmS1okvCqTQFs6PwNRWvzP1YeguD1FxLopQWe1a9h diff --git a/packages/fetchai/skills/simple_oracle/README.md b/packages/fetchai/skills/simple_oracle/README.md index c850234cdd..6c69ddd233 100644 --- a/packages/fetchai/skills/simple_oracle/README.md +++ b/packages/fetchai/skills/simple_oracle/README.md @@ -6,11 +6,11 @@ This skill is used to deploy an oracle smart contract to a ledger, grant oracle ## Behaviours -* `simple_oracle_behaviour`: deploys oracle contract, grants the oracle role to the agent address, and updates the oracle value every `tick_interval` seconds, as specified in the skill configuration. +- `simple_oracle_behaviour`: deploys oracle contract, grants the oracle role to the agent address, and updates the oracle value every `tick_interval` seconds, as specified in the skill configuration. ## Handlers -* `contract_api`: handles `contract_api` messages for interactions with a smart contract -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `prometheus`: handles `prometheus` messages for interactions with a prometheus server -* `signing`: handles `signing` messages for transaction signing by the decision maker \ No newline at end of file +- `contract_api`: handles `contract_api` messages for interactions with a smart contract +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `prometheus`: handles `prometheus` messages for interactions with a prometheus server +- `signing`: handles `signing` messages for transaction signing by the decision maker diff --git a/packages/fetchai/skills/simple_oracle/skill.yaml b/packages/fetchai/skills/simple_oracle/skill.yaml index a6847b52ee..886051f6f6 100644 --- a/packages/fetchai/skills/simple_oracle/skill.yaml +++ b/packages/fetchai/skills/simple_oracle/skill.yaml @@ -6,7 +6,7 @@ description: This skill deploys a Fetch oracle contract license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmcvyraEedZd5PEnmbijkkcsDrQQKDVJxPDUXVrwP3Ni3J + README.md: Qme3QavjkmFm4HWMLEAJpAHCYd4miKq2j2LXayRDSRSGiw __init__.py: QmWPQ8JQpyj51mZUcz76DnAAfPFYEJH94LLQR151hBArT3 behaviours.py: QmXyscjzvxLeJcssKgpuxqXwDyX1QGcwPPvEcMa5ymyTbH dialogues.py: QmS4XJDpNXxjKewDUk6HREXrm8pa3KndTR7vzppVcAURCt diff --git a/packages/fetchai/skills/simple_oracle_client/README.md b/packages/fetchai/skills/simple_oracle_client/README.md index f68f6e9f13..d010d2a29d 100644 --- a/packages/fetchai/skills/simple_oracle_client/README.md +++ b/packages/fetchai/skills/simple_oracle_client/README.md @@ -6,10 +6,10 @@ This skill is used to deploy an oracle client smart contract to a ledger, approv ## Behaviours -* `simple_oracle_client_behaviour`: deploys oracle client contract, approves contract transactions, and calls the contract to request the oracle value every `tick_interval` seconds, as specified in the skill configuration. +- `simple_oracle_client_behaviour`: deploys oracle client contract, approves contract transactions, and calls the contract to request the oracle value every `tick_interval` seconds, as specified in the skill configuration. ## Handlers -* `contract_api`: handles `contract_api` messages for interactions with the smart contract -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `signing`: handles `signing` messages for transaction signing by the decision maker \ No newline at end of file +- `contract_api`: handles `contract_api` messages for interactions with the smart contract +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `signing`: handles `signing` messages for transaction signing by the decision maker diff --git a/packages/fetchai/skills/simple_oracle_client/skill.yaml b/packages/fetchai/skills/simple_oracle_client/skill.yaml index 78e596f2da..506d185400 100644 --- a/packages/fetchai/skills/simple_oracle_client/skill.yaml +++ b/packages/fetchai/skills/simple_oracle_client/skill.yaml @@ -7,7 +7,7 @@ description: This skill deploys a Fetch oracle client contract and calls this co license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmRqzw2aTE6rsUnoB8XvvWoF4sg4ZUpvgQwStZpAVG5sUj + README.md: QmeP17RSTejkr3mmh4UsMFN6H6L8XL2a6EsdEaKQshgXJW __init__.py: QmY9QW49DW731K4CY5jELzFAvSeLSHf1M6nTYv5nSa1DCC behaviours.py: QmafcEseTDXqwTHoPF41PSaFT7reEuV2ZUsrXH26L1dNey dialogues.py: QmZJwtbs31WczMtXCK9jfaxh29mohBEY7YdRQ4zaReD2mF diff --git a/packages/fetchai/skills/simple_seller/README.md b/packages/fetchai/skills/simple_seller/README.md index 88efe2f412..b6db03a49f 100644 --- a/packages/fetchai/skills/simple_seller/README.md +++ b/packages/fetchai/skills/simple_seller/README.md @@ -6,14 +6,14 @@ This skill is used to sell data present in the shared state. ## Behaviours -* `service_registration`: registers data selling service on the sOEF +- `service_registration`: registers data selling service on the sOEF ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Models -* the `strategy` model is extended from the `fetchai/generic_seller` skill and loads data from the shared state using the key `shared_state_key` specified in the skill configuration. +- the `strategy` model is extended from the `fetchai/generic_seller` skill and loads data from the shared state using the key `shared_state_key` specified in the skill configuration. diff --git a/packages/fetchai/skills/simple_seller/skill.yaml b/packages/fetchai/skills/simple_seller/skill.yaml index bb4fb1c2fb..3bd34cfd8b 100644 --- a/packages/fetchai/skills/simple_seller/skill.yaml +++ b/packages/fetchai/skills/simple_seller/skill.yaml @@ -7,7 +7,7 @@ description: The simple_seller skill extends the generic_seller skill and sells license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmfKe4D4dyoN9hrJhQFJgDd9myNEqqU6SrZHYqYFAZ8y6Y + README.md: QmcBRmTneLHvBfHcw4ZfVKkMw8cZFbvHdmAactNhNrd4HU __init__.py: QmX5EUZ9KyWrHaaiShdf7iFMeZeu1fWEj9LQUj2nrmmBdf behaviours.py: QmPjoQS4RdWpsmhh2xabtW3MDRAdRch4J2MMe8MdpSGFYp dialogues.py: QmSY1VNCShSjiVuwToNvu7k5pfYEXiHjRQP5fHRkrx8UHz diff --git a/packages/fetchai/skills/simple_service_registration/README.md b/packages/fetchai/skills/simple_service_registration/README.md index 38c1e24666..70f2e3d57e 100644 --- a/packages/fetchai/skills/simple_service_registration/README.md +++ b/packages/fetchai/skills/simple_service_registration/README.md @@ -8,12 +8,12 @@ This skill is used in the "Guide on Writing a Skill" section in the documentatio ## Behaviours -* `service`: registers and unregisters a service on the sOEF +- `service`: registers and unregisters a service on the sOEF ## Handlers -* `oef_search`: handles `oef_search` messages if interactions with the sOEF is erratic +- `oef_search`: handles `oef_search` messages if interactions with the sOEF is erratic ## Links -* Guide on Building a Skill +- Guide on Building a Skill diff --git a/packages/fetchai/skills/simple_service_registration/skill.yaml b/packages/fetchai/skills/simple_service_registration/skill.yaml index a4bedd7759..48b0c8fe40 100644 --- a/packages/fetchai/skills/simple_service_registration/skill.yaml +++ b/packages/fetchai/skills/simple_service_registration/skill.yaml @@ -6,7 +6,7 @@ description: The simple service registration skills is a skill to register a ser license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmUgCcR7sDBQeeCBRKwDT7tPBTi3t4zSibyEqR3xdQUKmh + README.md: QmcAU3oi7tWS86UmAePbubQLinLutQsSQ1eGce5LperZty __init__.py: QmXRcGYBPxfZXFBxDvYjLKm7WCP6biG8sHG6P3g43Aaf5a behaviours.py: QmWuomUzWYZXeshgbnnzzeC9xE3tNwJReGwCBtbqhMXcaY dialogues.py: QmbgKy2b6WiWSFXxdwDaawAsoBY2VsBAdhRgUL6WTaGhEt diff --git a/packages/fetchai/skills/simple_service_search/README.md b/packages/fetchai/skills/simple_service_search/README.md index ec32c4d63e..81fb46507e 100644 --- a/packages/fetchai/skills/simple_service_search/README.md +++ b/packages/fetchai/skills/simple_service_search/README.md @@ -6,12 +6,12 @@ This skill searches for services on the sOEF. ## Behaviours -* `service_search`: sends search queries to the sOEF using the `oef_search` protocol. +- `service_search`: sends search queries to the sOEF using the `oef_search` protocol. ## Handlers -* `oef_search`: handles `oef_search` messages, in particular search responses. Search results are stored in the shared state using the key `shared_storage_key`. +- `oef_search`: handles `oef_search` messages, in particular search responses. Search results are stored in the shared state using the key `shared_storage_key`. ## Models -* `strategy`: builds the search query from the data provided in the skill configuration: `search_location`, `search_query` and `search_radius`. +- `strategy`: builds the search query from the data provided in the skill configuration: `search_location`, `search_query` and `search_radius`. diff --git a/packages/fetchai/skills/simple_service_search/skill.yaml b/packages/fetchai/skills/simple_service_search/skill.yaml index c2ff8dbcfc..4e701e98e4 100644 --- a/packages/fetchai/skills/simple_service_search/skill.yaml +++ b/packages/fetchai/skills/simple_service_search/skill.yaml @@ -6,7 +6,7 @@ description: A simple search skill utilising the SOEF search node. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmdwNVXwPsrA2sYiGae2koQjETVTfxLe6VXyfS3ya5KnyG + README.md: Qme6VKFeMeJe4BjUEeqL1tTVisW4QUEFDu3PCgcHyUJWG8 __init__.py: QmT5AtvVKPwihV3oLuCD5L97UdFPdgUijX26rdCdTHu7ez behaviours.py: QmQVn5ASsL6fPgyvLJbKt9DHKaPRtQbtvNbj4L9Wk1zKr8 dialogues.py: QmazwDnVLDM3UsfDHPcamVWaipNVnNDAsRqTZe8vB6cXTn diff --git a/packages/fetchai/skills/tac_control/README.md b/packages/fetchai/skills/tac_control/README.md index 84317a5868..fd1da621c0 100644 --- a/packages/fetchai/skills/tac_control/README.md +++ b/packages/fetchai/skills/tac_control/README.md @@ -8,13 +8,13 @@ This skill is part of the Fetch.ai TAC demo. It manages the progression of the c ## Behaviours -* `tac`: manages progression of the competition +- `tac`: manages progression of the competition ## Handlers -* `tac`: handles `tac` messages for managing the competition -* `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful +- `tac`: handles `tac` messages for managing the competition +- `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/skills/tac_control/skill.yaml b/packages/fetchai/skills/tac_control/skill.yaml index e564227b47..0d357fcd50 100644 --- a/packages/fetchai/skills/tac_control/skill.yaml +++ b/packages/fetchai/skills/tac_control/skill.yaml @@ -7,7 +7,7 @@ description: The tac control skill implements the logic for an AEA to control an license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmPakq2qYHCenyWKfqQHRLWdF7uo6eG24GTprsBfrkyny2 + README.md: QmdQcAgQ21CSovduTzvhf1nsxwQZWTYkDAc9Tfsz6gXWMh __init__.py: QmcudXhuG63zFXbVdbdwPLpdHR2HJ2Gm7MYNhweFXNMyq4 behaviours.py: QmNmcawRFT6NEFCWpwECwE7bbX7ZnVVZXDLDeP5pKiQSZr dialogues.py: QmQWmTQKxhNV9A8B4h2dfmy917LCut3PY7Ny61nJvdxJPH diff --git a/packages/fetchai/skills/tac_control_contract/README.md b/packages/fetchai/skills/tac_control_contract/README.md index 5b5da779c3..1f03ff8327 100644 --- a/packages/fetchai/skills/tac_control_contract/README.md +++ b/packages/fetchai/skills/tac_control_contract/README.md @@ -8,16 +8,16 @@ This skill is part of the Fetch.ai TAC demo. It manages the smart contract (cont ## Behaviours -* `tac`: deploys smart contract, manages progression of the competition +- `tac`: deploys smart contract, manages progression of the competition ## Handlers -* `contract_api`: handles `contract_api` messages for interaction with a smart contract -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful -* `signing`: handles `signing` messages for interaction with the decision maker -* `tac`: handles `tac` messages for registering/unregistering agents in the TAC +- `contract_api`: handles `contract_api` messages for interaction with a smart contract +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful +- `signing`: handles `signing` messages for interaction with the decision maker +- `tac`: handles `tac` messages for registering/unregistering agents in the TAC ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/skills/tac_control_contract/skill.yaml b/packages/fetchai/skills/tac_control_contract/skill.yaml index 79ad3feb85..e020bf548f 100644 --- a/packages/fetchai/skills/tac_control_contract/skill.yaml +++ b/packages/fetchai/skills/tac_control_contract/skill.yaml @@ -7,7 +7,7 @@ description: The tac control skill implements the logic for an AEA to control an license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmX9HuMvkRptLc4QnuagUGmN4HzxH5jnxXJYtw565dMnXg + README.md: QmYoLcfTSQNX3FPna6g2ttKTQRjF8DpxpzLxEQLdg4whe1 __init__.py: Qmf9DsWcApFgXn5mkDtYnmc42rxs5bMwMpjd3y2JxxYL61 behaviours.py: QmV6UDZrmUXVfoqU8J5GgQmtanDKNbUd14t6UEJGSaynx8 dialogues.py: QmbxjXD42RbKtYWUwnQzscAiKJuijfNgUK3G1WJfU9Lkxf diff --git a/packages/fetchai/skills/tac_negotiation/README.md b/packages/fetchai/skills/tac_negotiation/README.md index a1f42868d6..dbc784d04c 100644 --- a/packages/fetchai/skills/tac_negotiation/README.md +++ b/packages/fetchai/skills/tac_negotiation/README.md @@ -8,17 +8,17 @@ This skill is part of the Fetch.ai TAC demo. It manages registration and searchi ## Behaviours -* `clean_up`: updates and cleans up confirmed and pending transactions -* `tac_negotiation`: registers/unregisters the agent and its buying/selling services on the sOEF +- `clean_up`: updates and cleans up confirmed and pending transactions +- `tac_negotiation`: registers/unregisters the agent and its buying/selling services on the sOEF ## Handlers -* `contract_api`: handles `contract_api` messages for interaction with a smart contract -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef`: handles `oef_search` messages to manage the buyers/sellers it finds -* `signing`: handles `signing` messages for transaction signing by the decision maker +- `contract_api`: handles `contract_api` messages for interaction with a smart contract +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef`: handles `oef_search` messages to manage the buyers/sellers it finds +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/skills/tac_negotiation/skill.yaml b/packages/fetchai/skills/tac_negotiation/skill.yaml index 64c3626180..8cf19121c9 100644 --- a/packages/fetchai/skills/tac_negotiation/skill.yaml +++ b/packages/fetchai/skills/tac_negotiation/skill.yaml @@ -7,7 +7,7 @@ description: The tac negotiation skill implements the logic for an AEA to do fip license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmdpJypf1uoDBW54DC2req7bst1Hw548piYmMKUaPPVHeB + README.md: QmNWeRkM9RzqkyPu5vQpdgXw5Qw8DpkX2ghNaAD6cNQnUo __init__.py: QmPBgoVQZ5ByP7RgkbJFTHAoNV47GdqqwzxsynwcPB9KLn behaviours.py: QmP4S2fTjtYXYc4YRAgwafE3uXAAERbPienc4yBuAJojDA dialogues.py: QmT3koAkBQ8ZBRMDrkKQV9K7s71mYxPTVDCDL7b9UcmsRe diff --git a/packages/fetchai/skills/tac_participation/README.md b/packages/fetchai/skills/tac_participation/README.md index 77c7071e33..1f26f3f45e 100644 --- a/packages/fetchai/skills/tac_participation/README.md +++ b/packages/fetchai/skills/tac_participation/README.md @@ -8,14 +8,14 @@ This skill is part of the Fetch.ai TAC demo. It searches for a TAC on the sOEF, ## Behaviours -* `tac_search`: searches for a TAC -* `transaction_processing`: processes transactions during the competition +- `tac_search`: searches for a TAC +- `transaction_processing`: processes transactions during the competition ## Handlers -* `tac`: handles `tac` messages by the controller for participating in the competition -* `oef`: handles `oef_search` messages to find and connect with a controller +- `tac`: handles `tac` messages by the controller for participating in the competition +- `oef`: handles `oef_search` messages to find and connect with a controller ## Links -* TAC Demo +- TAC Demo diff --git a/packages/fetchai/skills/tac_participation/skill.yaml b/packages/fetchai/skills/tac_participation/skill.yaml index adacbf972e..88aef52022 100644 --- a/packages/fetchai/skills/tac_participation/skill.yaml +++ b/packages/fetchai/skills/tac_participation/skill.yaml @@ -7,7 +7,7 @@ description: The tac participation skill implements the logic for an AEA to part license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmXMADH6TxdWKhQ5EUxq7XjzHN4ECK3rD6Zj8RV2Pt9DYF + README.md: QmW3M9mYP2NdtzpBytNaLCUrkno3xZoNieBZ58cdcku5nm __init__.py: Qmb3SUUEVRajhHhQsSt1WKTL46ekU2FSodi29NRjhtjsCY behaviours.py: QmVVeGX9SfhS59k1FDxdUNTexybigvjLRPZiVkrf2yG5kd dialogues.py: QmWrqCc6RpPQW8Dw4sEocGHSRHPkrnAHfPqLhZsT1H5FJB diff --git a/packages/fetchai/skills/task_test_skill/README.md b/packages/fetchai/skills/task_test_skill/README.md index 1313d425f4..9be12d64e3 100644 --- a/packages/fetchai/skills/task_test_skill/README.md +++ b/packages/fetchai/skills/task_test_skill/README.md @@ -6,6 +6,4 @@ Simple task skill to test ## Handlers - - ## Links diff --git a/packages/fetchai/skills/task_test_skill/skill.yaml b/packages/fetchai/skills/task_test_skill/skill.yaml index da61f28d48..0c13205d52 100644 --- a/packages/fetchai/skills/task_test_skill/skill.yaml +++ b/packages/fetchai/skills/task_test_skill/skill.yaml @@ -6,7 +6,7 @@ description: Skill with simple task to run. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmYkiShbUg3zyT8SMxh9ty2MLg7LMgVwEJAAGxVEXyjRk8 + README.md: QmcXGDniXKQgNuoKwYor6mb5qXMWRHSvFT8cppxTj66Ngz __init__.py: QmS8m3SjyMuVtDN7H5gCszTa4EqnKgqjR5kxvJtgTQxXTH behaviours.py: QmSV3NmWaVLDF5GvCLXMjYSxUqZ5dAT5vXtazNZUtiquV8 tasks.py: QmUA5k1vGCXVfBA5RTcJZXnbQgy5YL7ZWtVViiJiBVmLiF diff --git a/packages/fetchai/skills/thermometer/README.md b/packages/fetchai/skills/thermometer/README.md index 760fca0912..8ed80f3236 100644 --- a/packages/fetchai/skills/thermometer/README.md +++ b/packages/fetchai/skills/thermometer/README.md @@ -8,14 +8,14 @@ This skill is part of the Fetch.ai thermometer demo. It can be requested (for ex ## Behaviours -* `service_registration`: registers thermometer data selling service on the sOEF +- `service_registration`: registers thermometer data selling service on the sOEF ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Links -* Thermometer Demo +- Thermometer Demo diff --git a/packages/fetchai/skills/thermometer/skill.yaml b/packages/fetchai/skills/thermometer/skill.yaml index 1c234cfc8e..1e7ed445a4 100644 --- a/packages/fetchai/skills/thermometer/skill.yaml +++ b/packages/fetchai/skills/thermometer/skill.yaml @@ -6,7 +6,7 @@ description: The thermometer skill implements the functionality to sell data. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmdmXfMJB3eGNJYE71MbfdtZPWLDiWKwW4SLhxjmcH45H1 + README.md: QmUTeGxHXAZcM9hLcWTYywxMTdKjw7gQrXs2EAwgqejce9 __init__.py: QmT4dXcKeUvffw9T8odJzGcqPVpHyJpNphowyV9bd9PqCY behaviours.py: QmZvLViapWxG1H41wn4e6Mzt8nmV6yyuk2sSsLJKZTQy2c dialogues.py: QmZckK3x2oPgXmnP4XaEBJQoaPp8Gh4ojDHnxzeNsTf4tC diff --git a/packages/fetchai/skills/thermometer_client/README.md b/packages/fetchai/skills/thermometer_client/README.md index 0ed6b566c8..5fcf4dd159 100644 --- a/packages/fetchai/skills/thermometer_client/README.md +++ b/packages/fetchai/skills/thermometer_client/README.md @@ -8,17 +8,16 @@ This skill is part of the Fetch.ai thermometer demo. It finds an agent which sel ## Behaviours -* `search`: searches for thermometer data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for thermometer data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Thermometer Demo +- Thermometer Demo diff --git a/packages/fetchai/skills/thermometer_client/skill.yaml b/packages/fetchai/skills/thermometer_client/skill.yaml index f734f32c77..185f46d946 100644 --- a/packages/fetchai/skills/thermometer_client/skill.yaml +++ b/packages/fetchai/skills/thermometer_client/skill.yaml @@ -7,7 +7,7 @@ description: The thermometer client skill implements the skill to purchase tempe license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmT1Nm7vfaUs3oxt5awfQLkezXkqkkabYaKc2q5bDgdq1K + README.md: QmdjHRzrhq636HNZYKaR8YCFKromFJqkKL3vMKHFpnmwSq __init__.py: QmYAqGMnn4SKHVNhxA1Z3goWVFvF5B4Z9DS1R6WvoewtE5 behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix diff --git a/packages/fetchai/skills/weather_client/README.md b/packages/fetchai/skills/weather_client/README.md index 0cd5d30a32..f1921c99b1 100644 --- a/packages/fetchai/skills/weather_client/README.md +++ b/packages/fetchai/skills/weather_client/README.md @@ -8,17 +8,16 @@ This skill is part of the Fetch.ai weather demo. It finds an agent which sells w ## Behaviours -* `search`: searches for weather data selling service on the sOEF -* `transaction`: sequentially processes transactions' settlements on a blockchain +- `search`: searches for weather data selling service on the sOEF +- `transaction`: sequentially processes transactions' settlements on a blockchain ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages to manage the sellers found -* `signing`: handles `signing` messages for transaction signing by the decision maker - +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages to manage the sellers found +- `signing`: handles `signing` messages for transaction signing by the decision maker ## Links -* Weather Demo \ No newline at end of file +- Weather Demo diff --git a/packages/fetchai/skills/weather_client/skill.yaml b/packages/fetchai/skills/weather_client/skill.yaml index 3f558a0336..93e8659e07 100644 --- a/packages/fetchai/skills/weather_client/skill.yaml +++ b/packages/fetchai/skills/weather_client/skill.yaml @@ -6,7 +6,7 @@ description: The weather client skill implements the skill to purchase weather d license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmPmhswajW8dw1sJgvkCQXYMVCf9nCsHxJX3nzX21qEbN2 + README.md: Qma4TrocZKtFcLeL1xKZxwz5no5qVHp5HjLrynYsKpw15Z __init__.py: QmbJq6yXTebkEcu8s2Y6f6LR9j9GBzTNBtDNGPFtwmrYiF behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix diff --git a/packages/fetchai/skills/weather_station/README.md b/packages/fetchai/skills/weather_station/README.md index 0be0db4d48..28656f029e 100644 --- a/packages/fetchai/skills/weather_station/README.md +++ b/packages/fetchai/skills/weather_station/README.md @@ -8,14 +8,14 @@ This skill is part of the Fetch.ai weather demo. It reads data from a database, ## Behaviours -* `service_registration`: registers weather selling service on the sOEF +- `service_registration`: registers weather selling service on the sOEF ## Handlers -* `fipa`: handles `fipa` messages for negotiation -* `ledger_api`: handles `ledger_api` messages for interacting with a ledger -* `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful +- `fipa`: handles `fipa` messages for negotiation +- `ledger_api`: handles `ledger_api` messages for interacting with a ledger +- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful ## Links -* Weather Demo +- Weather Demo diff --git a/packages/fetchai/skills/weather_station/skill.yaml b/packages/fetchai/skills/weather_station/skill.yaml index f278ae8ddb..ce5a0fce8c 100644 --- a/packages/fetchai/skills/weather_station/skill.yaml +++ b/packages/fetchai/skills/weather_station/skill.yaml @@ -7,7 +7,7 @@ description: The weather station skill implements the functionality to sell weat license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: QmV56JmGf2DsJw3m2zu8fjL7Jvgdtsg7pXsgN7J35suZk4 + README.md: QmVbpEJquwxzBZ2feJuRYBWrWjxQ9jhE1Er4LvmPU24ki9 __init__.py: QmRpWGsMzLXDi51M4sN2anyUTNvLvTQL5CrHXx6QFPuXJj behaviours.py: QmaRDMaDVsjVfkAtAHkWLU9Fa88UxyLTczdkm97E9c5TFT db_communication.py: QmYY2eMJ8YHSnkKzvrQYe46rgwZJCjwDayCGKv8C2HroRQ diff --git a/packages/hashes.csv b/packages/hashes.csv index 7959b2caa6..d6b58cdfb6 100644 --- a/packages/hashes.csv +++ b/packages/hashes.csv @@ -1,72 +1,72 @@ -fetchai/agents/aries_alice,QmNWJQkuoVNopQDYY7p1YkXGkvdi8eaBrn6qdzUEzFYJrt -fetchai/agents/aries_faber,QmNtJEXZBozPYxAHkqnP3zkmniEi4nXwvHEkuYwFmJgK64 -fetchai/agents/car_data_buyer,QmNySV8JzviUKC5wMqx4wM7HePHky2bhETM9Dsv6QfHgNc -fetchai/agents/car_detector,QmR58ffeqVsTWpKj9MaVk4k9Eyh4ZM55qkAQHHRgBN5RrT -fetchai/agents/coin_price_feed,QmWbQmUvQ7HgPzG9Srx4TW389pdigKooVgmzqKhheRNWkZ -fetchai/agents/coin_price_oracle,QmWyiDHqdMEWdCtqNzQ9JdF8i4Q5NY9L62htTM2iu3AQjw -fetchai/agents/coin_price_oracle_client,QmdK4ByHbuamz6QCpYQmn9BTiqJfCqpk2VRRwb8qGh3crs +fetchai/agents/aries_alice,QmdCqacWxnymMzVWeGWsD38kuF3MKCJPUNEsqprbCBG7w4 +fetchai/agents/aries_faber,QmRgDUKVV3sX4C7aVqijhkfuKyJPRuW17a9aSWgPVHWgYQ +fetchai/agents/car_data_buyer,QmUVevAWH8xEHbReGYhortFwhMCaKmSm8G87u6rH4kyWxa +fetchai/agents/car_detector,QmUKqGr3k3hN421KhbgQGxBi9o8UEBQuf6ZKD4EGbLnaNb +fetchai/agents/coin_price_feed,QmQe65WKTJoTSurXpz3rRrZAJtPePn1tL39Gnca78sk2Xo +fetchai/agents/coin_price_oracle,QmWXHCYdx5Pvt5d7wsPK2KGpNgL43eXupz4nYBpDPQbNBX +fetchai/agents/coin_price_oracle_client,QmYxisbGnjqM3L1Jbx5X9wG1mHTcWbkFQNvAFsM66ZjGwH fetchai/agents/confirmation_aea_aw1,Qmc6oN9GRwfww4aHMGymhEW9wSyyoKtE5Xc54fs71sG5VG fetchai/agents/confirmation_aea_aw2,QmUEGiVmwgLP65jgzw44wHD61G2fiSZC3e37N3KLP2QyK8 fetchai/agents/confirmation_aea_aw3,QmWprPePHGAFJVRheU7tquHL7bqup3wYD62xBph6qSx24y fetchai/agents/confirmation_aea_aw5,QmSHX7itB2gxEZNkEysmt8Qrarc9dXghDJ2ZK7iMMQn8qs -fetchai/agents/erc1155_client,QmQ8kE7DCJi5mXWfHbPfW3Lv6rMfmAAZ11uuQUdedkSAAk -fetchai/agents/erc1155_deployer,QmdKybfNFHSCWStHffEusiQThk16sovz94kWYp5YYADmV2 +fetchai/agents/erc1155_client,QmPy5Ucb8tKww8kMGTQUXaZEcSypa8u9VHxotiCTaVPxyt +fetchai/agents/erc1155_deployer,QmehGLCmdYFaftXn7RAHJ2eZzaWqFWNreSnSKThoigQZu5 fetchai/agents/error_test,QmXXnkxCrMKK2nba2UVjofKgNrGRaxrhvqhNX2PkZqrgd9 -fetchai/agents/fipa_dummy_buyer,Qmbrs5FPFXPbFFBMa8Kth12Yrx8sb4c8GdbHCZ718N183G -fetchai/agents/generic_buyer,QmVyvrfL3JBHnvY9CrnV9yqG9KVtz7t31cZr15nE26za9u -fetchai/agents/generic_seller,QmYStzCcrU4q1kJiFix5kVgcKWPjC5QWjXy4e63cNRPfqz -fetchai/agents/gym_aea,QmXw5DDYJjpLso9yKbtc1umsqz9XxYi21QuDcVkrA181tC -fetchai/agents/hello_world,QmZ1Zf5HUo1hS8t9TTsFZX8aYsFjknN3Tny2aF4AV9gr1s -fetchai/agents/latest_block_feed,QmYEDg2MrWFmD3FzT1n2WyJ9M8892SH3y7CntbBMYvCBHu -fetchai/agents/ml_data_provider,QmWyFi6bB8Q2ZqQfSKHazYyvbpYkA8Cxipk7ToRxUjny27 -fetchai/agents/ml_model_trainer,QmeZf18pg1rpfYxdCy2LiaM4r1vqhpCRgW96d6Uf5Xd4TG -fetchai/agents/my_first_aea,QmPXDz7a5Rie9b44kJY4p9Nj2P6vJbLHgvEziPhQKdoQWW +fetchai/agents/fipa_dummy_buyer,QmdWEAT4oHXFCtQhJ32j63DuJN9Z12iSETwbLN4DHCE7mN +fetchai/agents/generic_buyer,QmVcWdKSb9JAvN5LuaBDTYfKL9WejZgnwiEG8WCjHN3DPp +fetchai/agents/generic_seller,QmdNU5cbxoPD8oMR6b8vAA334tsXFmHPW11ZkWPEAcgFaK +fetchai/agents/gym_aea,QmUrhWUFfzWcp1zvzXHGV83hYU7KJZw3w6uz29MdaiMrbA +fetchai/agents/hello_world,QmYL1zmpaFgcGDEBNGBvpRsKHMNbtGhErFCHfqsXaGFe1T +fetchai/agents/latest_block_feed,QmVFdQ6JUYwqnj4ZNDuy5FKoUynJ8QH6rhXhga7a12wDt4 +fetchai/agents/ml_data_provider,QmUXNnPpTuSpwYAdLPXgJuzoGtqR7374JLWdnbB6o7gYnf +fetchai/agents/ml_model_trainer,QmVMpVmfz76xJdxpZrbKpoibJmboZja1E3TbxBQ5xRFZhW +fetchai/agents/my_first_aea,QmZuiKeoVhW7arpebj8pfg17SCEzme8Mt1ekqeue4hdxAE fetchai/agents/registration_aea_aw1,QmSJapmBH1o5CLoq72JoQyAunrpbeZC1JgAbXx1Emuc6jw -fetchai/agents/simple_aggregator,QmaHpMKj9fts4LwMDkETy5L7oTkMHHcqkFoLJpX3vXsn8q +fetchai/agents/simple_aggregator,QmSuUS1kCwsSNrbdYbvXCchkpGge9iNUbwp79uqbQfXNMG fetchai/agents/simple_buyer_aw2,QmbFyS6f7wZnVbiEEQroAdTHdB7z2RNpU7BKE3jaxmgfdy fetchai/agents/simple_buyer_aw5,QmPRxczS8uFycFjNEdiopEqknVHLnYjUrwY9LyF4ZNQyJ8 fetchai/agents/simple_seller_aw2,QmeASk1owaDjWiZkYSheGSaGWYaonQjSpAkUpWRNfR2Vz1 fetchai/agents/simple_seller_aw5,QmT443Y4UcoirDLvkHe9KGuJf8GzvEnqgNAZKSgThxwgFs -fetchai/agents/simple_service_registration,QmNpkNzhHyDr7GbsrriqkqDQEWym3sx48jhjp4GzF5k9DK -fetchai/agents/simple_service_search,QmU4WG4iD7E9JzpCfDqeGzsByazyZ3TTHN5wCx3yhDZ3s2 -fetchai/agents/tac_controller,QmTwzz3NwztyAjdEccC4Rq45fYcHVZWrSR4rZJz6pxFymX -fetchai/agents/tac_controller_contract,Qma51FtBt2R7wxkGTqvkWFgQ3teZzbVLSGVdEHhRbcZywm -fetchai/agents/tac_participant,QmXPq16BjJsqxbVB2mEWf2npaBvkXLYHfNt5wijC6YK5Xo -fetchai/agents/tac_participant_contract,QmdmDACF2eBjDoMdGWLktoX457pVMhC5zeux4CFuFCwEMH -fetchai/agents/thermometer_aea,QmPUatESAbWbyQyhTPTFCroo3wZQh2RqXE9uJB2qUGfk5M -fetchai/agents/thermometer_client,QmPRGD3J9qjxiFFzmQ5GTE3em82kYgXZCBV3VBsueNTW5o -fetchai/agents/weather_client,QmRLD1bqumvgohLFpoJJigoLsoZYuyBRFzMe9qKddNYhdU -fetchai/agents/weather_station,QmRL3siKgX2WwJhTnShJh1HiXQPuKncmQ2hkeoRy1fo5Dw -fetchai/connections/gym,QmRs13wcGeaQxJhmdHBRQcgYzhQkvViUzPaUvjLsumkv4f +fetchai/agents/simple_service_registration,QmUPoeQB6KFPJs3eKB4RfULF4btwvdjcM64V5VvjnucGgw +fetchai/agents/simple_service_search,QmRyywNVhnNdyt6trK2FUCngBnT1oN1nh76HZ33ajBke4q +fetchai/agents/tac_controller,QmdX3JLAFWUYMdFcNtNn8DH6r33FJjuUYHAefbKS5vkGDW +fetchai/agents/tac_controller_contract,QmPhKdZeyrY6oyMz7CzBopo5SPaw6NVcnkB4buCkkyFFdq +fetchai/agents/tac_participant,QmWS7e6euDJnJzk9aKU5GipDXcCZeQMwpfccyWdLHYaDuE +fetchai/agents/tac_participant_contract,QmTbSwVs9ycNfv8rSsTtFQBiYnEuPTjCjnf4nhs7P6rU6D +fetchai/agents/thermometer_aea,QmWg5sTKanGkaskcCcx4v99fyF5TmRgSnX9SSFbiky6yRX +fetchai/agents/thermometer_client,QmZZR7WU5GBtWVr7yNhXqWZTLRPZDyks3EmBAbAMwft7Ee +fetchai/agents/weather_client,QmdyFTmMAFzeord8HjbjET4kdooYP8EKEDZGyJVJnsBfi2 +fetchai/agents/weather_station,QmRuGgrBPHC7VFKZKH5t2m7rtaedt8jjkXFweLDTqBZmiK +fetchai/connections/gym,QmPhkcG5WZ5BdGi4yUMFvh3oUU5bGtKkkj8f2mG8Rk1SmQ fetchai/connections/http_client,QmVQD5gqD9hVhJvDrvcJtKuQUURwa8CNCmdLUyBTcG3bfi -fetchai/connections/http_server,QmdKGv9JDXmZdQ8cZqk8aCwhB8h2My4Pa2qS6sAytaPnyq +fetchai/connections/http_server,QmVitwZAp6ivs6SDxyfKh5qQH4XzoKJa549yZ8ympRrXvB fetchai/connections/ledger,QmZeQeyjefvyMveRZ5qzPt12LPYpc5nJnX22ECqmdzByqG fetchai/connections/local,Qmd72quWMgugAi5CNPRBQbaFoHafrUDg5hfNqxxRMsqzem -fetchai/connections/oef,QmYS3bbEgkQWPJfnG7mJFMPcZ1WCJ8XVtBEppsBWrYykEP -fetchai/connections/p2p_libp2p,QmWbU7ERgfsc6QDX29fqEzr7G2RGjGgcdNy6DTMBHswHF5 -fetchai/connections/p2p_libp2p_client,QmeohR216rFn3NbFh6gKZgoWKqPwGHggvYF1uFhhwPqo33 -fetchai/connections/p2p_libp2p_mailbox,QmXo8FdXaaswq1D9M4bUSSH6NJmSUfwe2mmKU69vyWkdNG +fetchai/connections/oef,QmbWFyGjrMhsr4YKqRARevn2BbuK8VLruZ4fGSdVyUhpbH +fetchai/connections/p2p_libp2p,QmYZfPfkqDbhgQJ2sPNuhmaHwZXA8UY9xedSV1fx8YsZZa +fetchai/connections/p2p_libp2p_client,QmZtbAaqcYGFQY5c4BqtNs57uZVj1Da6h8uhCUMf1dkatS +fetchai/connections/p2p_libp2p_mailbox,QmeBf26Z4BKQB4YyfMkD7tcTjJWoHHwud13i4gq6JR7tRn fetchai/connections/p2p_stub,QmSqsHaiN9TcDtJi5hfc4R5tNm88SZg2aNNdZT6rQ5EmNZ -fetchai/connections/prometheus,QmYKZ8W7Mtx4gH6sCBX65fBqKQwrPjiGmtG2tYZg4yWivd -fetchai/connections/scaffold,QmP5nnCSz7sgg7aWRaYtx6KYpaTZ7CC55i8A8m8SAUujKS -fetchai/connections/soef,QmT72DV9wzYts3RXdDKNU1Q7BE152HWH8Ko7V9nB2si8m8 -fetchai/connections/stub,QmVaUvTG8xN5CxoaJG1trV57Cj87FBoxsmqvsbAw7qoBiT +fetchai/connections/prometheus,QmNngs42LpGnGYDAgdqKLpg4Hnv6kRgPKEoahAx1yha4CT +fetchai/connections/scaffold,QmYRgd4gLA3CtevU3Rj72Vafu9V6sjk4xRrHu5JosvB7gP +fetchai/connections/soef,QmRpQXTzeMtz7He9h2cgKkXXX5dLvhnL98Ez3eQhj4Byud +fetchai/connections/stub,QmTfviFPpH4wxNKmHRuqLi9LXJWdEQ7Yh8vjt3QNUyGfoe fetchai/connections/tcp,Qmdzf1zRAaHuc5LuNZXNMxHpGSKcaQbKqwx7WXXP8f87sN fetchai/connections/webhook,Qmdn8UrH27A9jPrbeMCTPrMnVYMqmJCrZ43LrGcrE5wQU7 -fetchai/contracts/erc1155,Qme2ayAahvc92xJZcsr91EVmm9Pi39nhadJSeN3qJqBqdo -fetchai/contracts/fet_erc20,QmTsUVT5kTt5HBwBiREWMyJ1uTjukwFpoe19iWbKVdZysk -fetchai/contracts/oracle,QmPXmkTd88fwua9Jexrrpk6ysxE54QWeDC8L7hB7Etvm8d -fetchai/contracts/oracle_client,QmV8sVRN26h5J4ZA7weadsMGPKrZ1h5ZjhSZZ7FaBaZwjD +fetchai/contracts/erc1155,QmXzZ5iEsW6He2vDKAWXWp2opKPxB1yM25TMb5XfXus38o +fetchai/contracts/fet_erc20,QmNRf7R7MtP9CtZKrZksytrBuJofCfPrmcGHZ3ddWKVCCS +fetchai/contracts/oracle,QmaRhUJHxYBVWkZt6ntXZQpunAHVhwSK6Ud3XnoV3VDWfe +fetchai/contracts/oracle_client,QmbUnraKtLHyZVSJX6eF49T4ZWmcZBhRb6RcbRAY5r5Rvw fetchai/contracts/scaffold,QmVgRzr6yJ3AV2Y6DFxz5EMtTgDmSkeg2b6Cx3H2WkFBHR -fetchai/contracts/staking_erc20,QmWrVQXcdWGmmqM2MwcUtfrcKJaM2LwPqYfKmSfyEvR67u +fetchai/contracts/staking_erc20,QmeF3nLXkqUSWHkmJX7hpxZdPRsEjzrDmRjuRRtCggQpBv fetchai/protocols/acn,QmcdHJCGxzBU8yuHX114U9H9Pw9PawQLuL79ReWMSytMDB fetchai/protocols/aggregation,QmVFFyJ7iB1JwNmstCANF64NVXAc9RRifZhzM7akKWz8Hd fetchai/protocols/contract_api,QmdGiwwH8fLJn9H8pVVAgUKHrbC4AssEDaEjKZFBBvSbYY -fetchai/protocols/cosm_trade,Qmbb5c8x5E4s1g6J2ATU8Hf2JZgSmSD1Jkuh6rcLkf8zMS +fetchai/protocols/cosm_trade,Qmcxt4Piq7Rm8ECx8pK7KWDdzx2sgYKr1k6PYei2Y69fu7 fetchai/protocols/default,QmPntD9jdwVtTddM7oqV5v2TqAwZNs49oPTH7PJkR77PjX -fetchai/protocols/fipa,QmSySE5qeE4yAmianLEB6jXjXfjKyxvh4KMAYbwr5aoq43 -fetchai/protocols/gym,QmRbJywaMtNAEo9hSd27YgHfJKYQeCcq3wHeyF3tbPuhg7 -fetchai/protocols/http,QmVZS9T9QSX6rYxAj3WtwMiQ9mnvFizpFYsM9Ugkvr64na +fetchai/protocols/fipa,QmdF5919bSK45YT6iAdZGCSN1uWKUMRcYE4YAwc5Tayyf9 +fetchai/protocols/gym,QmbrCKR5HYasP5VDAcFgYGZDrYETpQi1bWDCyXhyUQRkAE +fetchai/protocols/http,QmYZvk4MSQ55cC2RK744orYNj3XtFHStPt3Mm4T5prWWZ7 fetchai/protocols/ledger_api,QmYZAHdSCgCZMWuGkKWZEMfpGSvtyvysYA2RsuCiUo1h97 fetchai/protocols/ml_trade,QmS531k57opZbdNrinyhYftWJKpPpdwyXEa6EYN4jTNbRb fetchai/protocols/oef_search,QmSfwFC69jyZnccihVmeBSgmjeHi576FEeEKuVwq6P7Qt9 @@ -75,45 +75,45 @@ fetchai/protocols/register,QmZbUZ5gfzhoS3p1uSRQXU5X4jm68kpb6fNR4wq11iBvQH fetchai/protocols/scaffold,QmakHDyafqNtxVyV47M17zHyhzf7osfcnzsbfmvsorhydL fetchai/protocols/signing,Qmf1q73rWKW7TDt9DS9nAsH9cpWR46S1RHnKd93ukoXHoM fetchai/protocols/state_update,QmY2md9qF5n218E297CtN9GdoKJXBnFQZ6nN1W8j4U1jZy -fetchai/protocols/tac,QmU2isihDJZLfisGGuhe1PZt1M4tuDjVmD71NnAZr9SvPH -fetchai/skills/advanced_data_request,Qmd1hXesiyAPCdexj9jhxjrewbDsMoc3sSnwHV1hhEVWQ2 -fetchai/skills/aries_alice,QmQmmnzqfhfaisVfjh3DQVvWxLwLPpukjdxgHk8atRpZCN -fetchai/skills/aries_faber,QmcdhWp9H4VLq4LwVezfgt8FdSSXMyFLyfK1xLNxKR2kQy -fetchai/skills/carpark_client,QmborrEAjM5weiKV4sDwoFrz2zvPGTcmGV9XuViNvJBnCE -fetchai/skills/carpark_detection,QmQ2F8u25zrZPnfHrfHw8koTZdm4qDRJ3YkBNVATSq1abg -fetchai/skills/confirmation_aw1,QmTdFRddmQDg5TqWMS13RbWLunpMrJpTDfnKXWWxXYoDSS -fetchai/skills/confirmation_aw2,QmNLykPNUwBWb5jC2toxDRmBRKdEi5s8jHpuzJjBdrbrEk -fetchai/skills/confirmation_aw3,QmWM95KugRep4R851jM7cHEgWRhLgoXK8yHJtyBVwcoQ3v -fetchai/skills/echo,QmVq7s2QBudCJNSNXXo1KzWMe5nzyE4tQ2uqAU7FXKYNb3 -fetchai/skills/erc1155_client,Qmf3JpQhRyY4dQxk8acTxZmtMTcxW3vs5zoBsc7wBs7S2s -fetchai/skills/erc1155_deploy,QmWs74KuoAm9w3947GnNUNztDeWi6cQvQXC3BCMu14FsXQ -fetchai/skills/error,QmR8XQVqoS13xRnXLiH9PV2nwceW9Rc8zuw2UKacjiwySo -fetchai/skills/error_test_skill,Qmc9p8wDt4ouERsdYUHqU3LWC7v1yRjPiGZNJC5vdsigQ5 -fetchai/skills/fetch_block,QmPH3X42omsGpD54N3jT9b2aJYuZMdjQd6aJv3qBMx5nWD +fetchai/protocols/tac,QmZFgXp6yS4t1542zSLsh4xoMtDtqgHL7K81NpSbbx44a7 +fetchai/skills/advanced_data_request,QmRftEdsEEUeRJ8vaqYBVhWWw58GLMweFxiKf34EmEPx92 +fetchai/skills/aries_alice,QmWSM7T4dvs9rmfskDzk8AWWF9oN1U9uRGnCxP5BDpf2cp +fetchai/skills/aries_faber,QmfSoRMq55M3AqFAUhxBbNRwk3njnJL3zCDe3B8CnJCxVM +fetchai/skills/carpark_client,QmczMz92fNU8M1kTXvydNrpsWFcv6piKnBwM9ARhekEVpH +fetchai/skills/carpark_detection,QmWrBFLU8H3qe2CxYWugro6vVxSq5DUhPpQkERVqmA7YLU +fetchai/skills/confirmation_aw1,QmeMbaGg1p4uyJ5s7bEH5DBeps8JHXPQJ8oC165jmE8aYr +fetchai/skills/confirmation_aw2,QmY5XPxdnWU6RhWtJNMA5dRZxXEUT95WNDWkPQ6xkfQRGg +fetchai/skills/confirmation_aw3,QmQcyhgMHLMT2Fx1W1i46duSKXVeqCHSa1mtmkyCD1j9K2 +fetchai/skills/echo,QmbajFi6G1U4hCh5168EJ2BFPzfMgLyHP5dbYnCRkTzFVY +fetchai/skills/erc1155_client,Qmb822b7XLtvxss5MvkEjG98difhDC2orBX1Q64JFFuQpG +fetchai/skills/erc1155_deploy,QmdxPnGWVNBTPsnnBshrchv3k61QhzBEFsnN77NPP5pKAN +fetchai/skills/error,QmPHAkWDMB3FWbJwQXeLSs1Z4jBvwzJQ5cDmuAy4aLRzvN +fetchai/skills/error_test_skill,QmcQ8XjhajuN7m7KxWBaz7zPp9ycDJTBADoS4pNpMKwYrT +fetchai/skills/fetch_block,Qmd2uLReSr2Bo3e9126xyVemZ1hEY6vHKHVMWC3yAH7hY5 fetchai/skills/fipa_dummy_buyer,QmbxDxp13aGQQG2kFPmzXpaCZTkpjNnFo7gym77vfp2kEa -fetchai/skills/generic_buyer,QmXXGbrAHjocaeNHiEjMxfNTai8GxKcEBGhQMHto29E8cB -fetchai/skills/generic_seller,Qmd9YzLT5uN7nWEwzptoaEu9DGFGfWb9sXoLZyqxAhEb5c -fetchai/skills/gym,QmYCe9UZbdSVQZ3GmjAAfQjpVkDbNG8LqpRB6c7SzzyqHY +fetchai/skills/generic_buyer,QmSkZeyX7tuQwWvCVDwZNfyXwgNK8jdKXEinpxErxQ42vY +fetchai/skills/generic_seller,QmX3VZtYWBenqKF4DgLYKP5rhnzNA7TsebxC1maBMK4WUZ +fetchai/skills/gym,QmWh21SZLkxRHi4QBJkBdJKL6WpQfByK1JJdwFpt76B7LB fetchai/skills/hello_world,QmXZQSU52Y4znomVXD7pvr5PA5q6pu4AKEu1p9EwkJnfhA -fetchai/skills/http_echo,QmUuT5RneDUgSF4xmXQVNs3pYjZXhy2xCsxWh5kt9pV5z9 -fetchai/skills/ml_data_provider,QmTrUyQgzQyiS9htkyQCwrPLLD5v8k7YJSdD7mAXSSPDRi -fetchai/skills/ml_train,QmYwdNjch4PPBpmiGZiqi9kRAU1MWfaxEBxGFSVKD3XYBD -fetchai/skills/registration_aw1,QmWYYizypmqFmGKPa8CWN6qdSFNreANwMr8oEWBmTrG7BX +fetchai/skills/http_echo,QmQYhgKQ1WEM7SV17RvKKWLLUVaSZ2KhMze6zpKKxgYgfu +fetchai/skills/ml_data_provider,Qme95Rzn54znKSjj611hAfEWmpvVHsa9RCx6gzBtnzu3eZ +fetchai/skills/ml_train,QmXZS3Mzm761Wox4V4KGdDBYkPHBzDYa2cYWgLVYsUeUGp +fetchai/skills/registration_aw1,QmTapQmGBuB9GzPtZyospy62tRykkKZCEw6xCrsdTzQD8m fetchai/skills/scaffold,QmfMLDBLPiBjQmDJHthYm59565NGNKEp9nCNgU4YaMrgSf -fetchai/skills/simple_aggregation,QmR7m2HSyGuaMhzsg4x9ffD9FLtzWH9984LnAViUPpUse9 -fetchai/skills/simple_buyer,QmfKpG8HdR6KoeLKgypXFricnMfkFYNtAZrcW6pqBvU4KD -fetchai/skills/simple_data_request,Qmcxchy7cEeNTR5sbwaXRYgpb4Bffgstdxvn5G329KQ379 -fetchai/skills/simple_oracle,QmPWFJYcQbmYmkx7yNq16TPCVQnAprsvD29dBiF9o6RzRS -fetchai/skills/simple_oracle_client,QmS7bJ4KnjmkRXuN6eyjc95ZUJGsA9sJTPJTcRkHCrFw5A -fetchai/skills/simple_seller,QmdPBWpxhPA6ShxTTFyfbRXJD9Tgb9kdYUMMhgxkikcuXp -fetchai/skills/simple_service_registration,QmS3RqdhAzN1ije4LFxbUzC8LnRn5Zv4XkS1EvPhu68eW9 -fetchai/skills/simple_service_search,QmbaWsnvYSuVGSkvRozUKe3G43R9TSTnbf4qqzkJ4Uuf4c -fetchai/skills/tac_control,QmUdG2rap2sAFzA6MfQFDa56gzk5zeHSUSxPJ1nbF7p6Tq -fetchai/skills/tac_control_contract,QmSvR9d9ecitBaC8G66hQJ7tYC7qFrikX4T9kgQe7YDaFj -fetchai/skills/tac_negotiation,QmR6AEde1dBmPGE871PeAQEsLULAE6w6hyAp4fLNiSxvjQ -fetchai/skills/tac_participation,QmfR9H4VDGPyAsyhZt9KYUNHPmssmso217wm7SXgmEW2yT -fetchai/skills/task_test_skill,QmQxVZojLMid9puAda8Hy2qbaVRCre3RTitjVKR6rEBVy3 -fetchai/skills/thermometer,QmZxmbAFAT69BW3wM9eEpoTmWe5YhAhk2xsTkxsQVomeW2 -fetchai/skills/thermometer_client,Qmc4zF67qep25NUHAKDvgggpY3N652kJWjQqFFkaJ4hk9U -fetchai/skills/weather_client,QmYUtA2P3CMN6S6dNLTEo2Y8KQHbQLybwMe4UKfumKzn8Y -fetchai/skills/weather_station,QmUJwdPymeyAnqMuFuq6wGCdZbjragNRKxnz49xBcHodrN +fetchai/skills/simple_aggregation,QmRxRFRkns942MLquJoqFT3XKagcmYnGS4sLU4GMLhajJp +fetchai/skills/simple_buyer,Qmaq1Xpbo286SJj7K7qUviY3hQFdnt5jeFjzKM9n6Auy1T +fetchai/skills/simple_data_request,QmUtn9VQWe4AVCsKVbUq3CLkYDPiexXSSfXgqBxDLv5RDa +fetchai/skills/simple_oracle,QmYoEwGyVc8sfoLk3s9dz39LrEJLh38EJdvmywsNVPJ4KD +fetchai/skills/simple_oracle_client,QmPmZhESt4BJ8eeVjj1xHoGeh8odW7CfLMVxNaED7fCjRp +fetchai/skills/simple_seller,QmVvB3D1AxCaDc9CoFSMoA6tfymAMxJUWxSZ9phGaveupU +fetchai/skills/simple_service_registration,QmPMtdG25eVS1665GzacdyCygy3JkKmHyLZPNUaKRA7ibU +fetchai/skills/simple_service_search,QmPi99VJnJzLKYMD3Ra8iRhHUJaA9P9Y77U2o7qy8YTADa +fetchai/skills/tac_control,QmZwYyf9tnv6Em41GVtZf6q7hjNdLG3Ubz7ku197WSWjto +fetchai/skills/tac_control_contract,Qmcjnqwrcd3DBxmrTVQKD8j8rmiBSDqxSS6nZNVZxUjZ5n +fetchai/skills/tac_negotiation,QmV4G14onbXD9MvPkQRdcb49tfkdg5KrJ2ijLDWsydWmFX +fetchai/skills/tac_participation,QmTC412QEzs6q2a7Brcgp1F1Kg8kqqVdht6gFkaGKwXfVx +fetchai/skills/task_test_skill,QmXe3JBbnMSb5FqX98eLw1ghr7e9sNFRHNg9tzvCTUsMym +fetchai/skills/thermometer,QmPv53RpTohmgv5BUJJZ2oWixH9YvqotADj761TkoNaqsV +fetchai/skills/thermometer_client,QmPAdevs7ZknhuMKEDfthb8pfEkBmadxiAnVra5bwbPCXB +fetchai/skills/weather_client,QmNgSsqTQYzU5A4LN8ZxJFM1TN92tnDH3KPjXGuQQ7negn +fetchai/skills/weather_station,QmUMqoXhEXj2w78f3hFjvBX6au4r34jBLRLnntZJb2VJ4x diff --git a/plugins/aea-cli-ipfs/README.md b/plugins/aea-cli-ipfs/README.md index 583432bc96..732117a73c 100644 --- a/plugins/aea-cli-ipfs/README.md +++ b/plugins/aea-cli-ipfs/README.md @@ -7,6 +7,7 @@ IPFS command to publish and download directories. Make sure you have `aea` installed. Then, install the plug-in: + ``` bash pip install aea-cli-ipfs ``` diff --git a/plugins/aea-ledger-ethereum/setup.py b/plugins/aea-ledger-ethereum/setup.py index 0c6f76cd1c..0dc32ae2ed 100644 --- a/plugins/aea-ledger-ethereum/setup.py +++ b/plugins/aea-ledger-ethereum/setup.py @@ -32,7 +32,7 @@ packages=find_packages(include=["aea_ledger_ethereum*"]), install_requires=[ "aea>=1.0.0, <2.0.0", - "web3>=5.31.0,<6.0.0", + "web3==5.31.1", "ipfshttpclient==0.8.0a2", ], tests_require=["pytest"], diff --git a/poetry.lock b/poetry.lock index 55dba0f9c8..4af3e5b017 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "absl-py" -version = "1.3.0" +version = "1.4.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." category = "dev" optional = false @@ -62,7 +62,7 @@ python-versions = "*" [[package]] name = "astroid" -version = "2.12.13" +version = "2.13.2" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -70,7 +70,7 @@ python-versions = ">=3.7.2" [package.dependencies] lazy-object-proxy = ">=1.4.0" -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +typing-extensions = ">=4.0.0" wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} [[package]] @@ -184,7 +184,7 @@ develop = ["coverage (>=5.3)", "flake8 (>=3.8)", "isort (>=5.8)", "mypy (>=0.900 [[package]] name = "bitarray" -version = "2.6.1" +version = "2.6.2" description = "efficient arrays of booleans -- C extension" category = "dev" optional = false @@ -225,7 +225,7 @@ wheel = "*" [[package]] name = "cachetools" -version = "5.2.0" +version = "5.2.1" description = "Extensible memoizing collections and decorators" category = "dev" optional = false @@ -359,7 +359,7 @@ requests = "*" [[package]] name = "coverage" -version = "7.0.0" +version = "7.0.5" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -750,15 +750,15 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.8.2" +version = "3.9.0" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2022.9.29)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=6.5)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] [[package]] name = "flake8" @@ -830,7 +830,7 @@ test = ["pytest"] [[package]] name = "flatbuffers" -version = "22.12.6" +version = "23.1.4" description = "The FlatBuffers serialization format for Python" category = "dev" optional = false @@ -846,7 +846,7 @@ python-versions = ">=3.7" [[package]] name = "future" -version = "0.18.2" +version = "0.18.3" description = "Clean single-source support for Python 3 and 2" category = "dev" optional = false @@ -917,7 +917,7 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] [[package]] name = "google-api-python-client" -version = "2.70.0" +version = "2.72.0" description = "Google API Client Library for Python" category = "dev" optional = false @@ -932,7 +932,7 @@ uritemplate = ">=3.0.1,<5" [[package]] name = "google-auth" -version = "2.15.0" +version = "2.16.0" description = "Google Authentication Library" category = "dev" optional = false @@ -949,6 +949,7 @@ aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"] enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0dev)"] [[package]] name = "google-auth-httplib2" @@ -991,7 +992,7 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.57.0" +version = "1.58.0" description = "Common protobufs used in Google APIs" category = "dev" optional = false @@ -1110,7 +1111,7 @@ python-versions = ">=3.5" [[package]] name = "imageio" -version = "2.23.0" +version = "2.24.0" description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." category = "dev" optional = false @@ -1125,10 +1126,10 @@ all-plugins = ["astropy", "av", "imageio-ffmpeg", "opencv-python", "psutil", "ti all-plugins-pypy = ["av", "imageio-ffmpeg", "psutil", "tifffile"] build = ["wheel"] dev = ["black", "flake8", "fsspec[github]", "invoke", "pytest", "pytest-cov"] -docs = ["numpydoc", "pydata-sphinx-theme", "sphinx"] +docs = ["numpydoc", "pydata-sphinx-theme", "sphinx (<6)"] ffmpeg = ["imageio-ffmpeg", "psutil"] fits = ["astropy"] -full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "invoke", "itk", "numpydoc", "opencv-python", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx", "tifffile", "wheel"] +full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "invoke", "itk", "numpydoc", "opencv-python", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"] gdal = ["gdal"] itk = ["itk"] linting = ["black", "flake8"] @@ -1155,7 +1156,7 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag [[package]] name = "importlib-resources" -version = "5.10.1" +version = "5.10.2" description = "Read resources from Python packages" category = "main" optional = false @@ -1165,16 +1166,16 @@ python-versions = ">=3.7" zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "ipfshttpclient" @@ -1269,7 +1270,7 @@ python-versions = ">=3.7" [[package]] name = "lazy-object-proxy" -version = "1.8.0" +version = "1.9.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false @@ -1277,7 +1278,7 @@ python-versions = ">=3.7" [[package]] name = "libclang" -version = "14.0.6" +version = "15.0.6.1" description = "Clang Python Bindings, mirrored from the official LLVM repo: https://github.com/llvm/llvm-project/tree/main/clang/bindings/python, to make the installation process easier." category = "dev" optional = false @@ -1407,19 +1408,21 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp [[package]] name = "mkdocs-material" -version = "8.5.11" +version = "9.0.5" description = "Documentation that simply works" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] -jinja2 = ">=3.0.2" +colorama = ">=0.4" +jinja2 = ">=3.0" markdown = ">=3.2" -mkdocs = ">=1.4.0" +mkdocs = ">=1.4.2" mkdocs-material-extensions = ">=1.1" -pygments = ">=2.12" -pymdown-extensions = ">=9.4" +pygments = ">=2.14" +pymdown-extensions = ">=9.9.1" +regex = ">=2022.4.24" requests = ">=2.26" [[package]] @@ -1466,7 +1469,7 @@ varint = "*" [[package]] name = "multidict" -version = "6.0.3" +version = "6.0.4" description = "multidict implementation" category = "dev" optional = false @@ -1508,17 +1511,17 @@ python-versions = "*" [[package]] name = "networkx" -version = "2.8.8" +version = "3.0" description = "Python package for creating and manipulating graphs and networks" category = "dev" optional = false python-versions = ">=3.8" [package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=0.982)", "pre-commit (>=2.20)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (>=5.2)", "sphinx-gallery (>=0.11)", "texext (>=0.6.6)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] +default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=0.991)", "pre-commit (>=2.20)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (==5.2.3)", "sphinx-gallery (>=0.11)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] @@ -1535,7 +1538,7 @@ typing-extensions = ">=3.0.0" [[package]] name = "numpy" -version = "1.24.0" +version = "1.24.1" description = "Fundamental package for array computing in Python" category = "dev" optional = false @@ -1626,7 +1629,7 @@ python-versions = ">=3.7" [[package]] name = "pbr" -version = "5.11.0" +version = "5.11.1" description = "Python Build Reasonableness" category = "dev" optional = false @@ -1645,14 +1648,14 @@ ptyprocess = ">=0.5" [[package]] name = "pillow" -version = "9.3.0" +version = "9.4.0" description = "Python Imaging Library (Fork)" category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] [[package]] @@ -1665,15 +1668,15 @@ python-versions = ">=3.6" [[package]] name = "platformdirs" -version = "2.6.0" +version = "2.6.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] -test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -1798,17 +1801,17 @@ yapf = ">=0.30.0" [[package]] name = "pydocstyle" -version = "6.1.1" +version = "6.2.3" description = "Python docstring style checker" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -snowballstemmer = "*" +snowballstemmer = ">=2.2.0" [package.extras] -toml = ["toml"] +toml = ["tomli (>=1.2.3)"] [[package]] name = "pyflakes" @@ -1831,7 +1834,7 @@ future = "*" [[package]] name = "pygments" -version = "2.13.0" +version = "2.14.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -1865,7 +1868,7 @@ testutils = ["gitpython (>3)"] [[package]] name = "pymdown-extensions" -version = "9.9" +version = "9.9.1" description = "Extension pack for Python Markdown." category = "dev" optional = false @@ -1925,7 +1928,7 @@ pywin32 = ">=223" [[package]] name = "pyrsistent" -version = "0.19.2" +version = "0.19.3" description = "Persistent/Functional/Immutable data structures" category = "main" optional = false @@ -1944,7 +1947,7 @@ cp2110 = ["hidapi"] [[package]] name = "pytest" -version = "7.2.0" +version = "7.2.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -2095,9 +2098,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "regex" +version = "2022.10.31" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "requests" -version = "2.28.1" +version = "2.28.2" description = "Python HTTP for Humans." category = "main" optional = false @@ -2105,7 +2116,7 @@ python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" +charset-normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" @@ -2226,19 +2237,19 @@ test = ["asv", "codecov", "flake8", "matplotlib (>=3.0.3)", "pooch (>=1.3.0)", " [[package]] name = "scipy" -version = "1.9.3" +version = "1.10.0" description = "Fundamental algorithms for scientific computing in Python" category = "dev" optional = false -python-versions = ">=3.8" +python-versions = "<3.12,>=3.8" [package.dependencies] -numpy = ">=1.18.5,<1.26.0" +numpy = ">=1.19.5,<1.27.0" [package.extras] -dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] -doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] -test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] +test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "semantic-version" @@ -2262,14 +2273,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "setuptools" -version = "65.6.3" +version = "66.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -2307,7 +2318,7 @@ python-versions = ">=3.6" [[package]] name = "sqlalchemy" -version = "1.4.45" +version = "1.4.46" description = "Database Abstraction Library" category = "dev" optional = false @@ -2455,7 +2466,7 @@ tensorflow-rocm = ["tensorflow-rocm (>=2.11.0,<2.12.0)"] [[package]] name = "termcolor" -version = "2.1.1" +version = "2.2.0" description = "ANSI color formatting for output in terminal" category = "dev" optional = false @@ -2556,6 +2567,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "types-docutils" +version = "0.19.1.1" +description = "Typing stubs for docutils" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "types-pyyaml" version = "6.0.12.2" @@ -2577,12 +2596,15 @@ types-urllib3 = "<1.27" [[package]] name = "types-setuptools" -version = "65.6.0.2" +version = "65.7.0.1" description = "Typing stubs for setuptools" category = "dev" optional = false python-versions = "*" +[package.dependencies] +types-docutils = "*" + [[package]] name = "types-urllib3" version = "1.26.25.4" @@ -2609,7 +2631,7 @@ python-versions = ">=3.6" [[package]] name = "urllib3" -version = "1.26.13" +version = "1.26.14" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -2658,7 +2680,7 @@ toml = "*" [[package]] name = "watchdog" -version = "2.2.0" +version = "2.2.1" description = "Filesystem events monitoring" category = "dev" optional = false @@ -2669,7 +2691,7 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "web3" -version = "5.31.3" +version = "5.31.1" description = "Web3.py" category = "dev" optional = false @@ -2677,7 +2699,7 @@ python-versions = ">=3.6,<4" [package.dependencies] aiohttp = ">=3.7.4.post0,<4" -eth-abi = ">=2.2.0,<3.0.0" +eth-abi = ">=2.0.0b6,<3.0.0" eth-account = ">=0.5.9,<0.6.0" eth-hash = {version = ">=0.2.0,<1.0.0", extras = ["pycryptodome"]} eth-rlp = "<0.3" @@ -2693,10 +2715,10 @@ requests = ">=2.16.0,<3.0.0" websockets = ">=9.1,<10" [package.extras] -dev = ["Jinja2 (<=3.0.3)", "bumpversion", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "eth-tester[py-evm] (==v0.6.0-beta.7)", "flake8 (==3.8.3)", "flaky (>=3.7.0,<4)", "hypothesis (>=3.31.2,<6)", "importlib-metadata (<5.0)", "isort (>=4.2.15,<4.3.5)", "mock", "mypy (==0.910)", "pluggy (==0.13.1)", "py-geth (>=3.9.1,<4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-mock (>=1.10,<2)", "pytest-pythonpath (>=0.3)", "pytest-watch (>=4.2,<5)", "pytest-xdist (>=1.29,<2)", "setuptools (>=38.6.0)", "sphinx (>=3.0,<4)", "sphinx-better-theme (>=0.1.4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "tox (>=1.8.0)", "tqdm (>4.32,<5)", "twine (>=1.13,<2)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1,<3)", "types-setuptools (>=57.4.4,<58)", "urllib3", "wheel", "when-changed (>=0.3.0,<0.4)"] +dev = ["Jinja2 (<=3.0.3)", "bumpversion", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "eth-tester[py-evm] (==v0.6.0-beta.6)", "flake8 (==3.8.3)", "flaky (>=3.7.0,<4)", "hypothesis (>=3.31.2,<6)", "importlib-metadata (<5.0)", "isort (>=4.2.15,<4.3.5)", "mock", "mypy (==0.910)", "pluggy (==0.13.1)", "py-geth (>=3.9.1,<4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-mock (>=1.10,<2)", "pytest-pythonpath (>=0.3)", "pytest-watch (>=4.2,<5)", "pytest-xdist (>=1.29,<2)", "setuptools (>=38.6.0)", "sphinx (>=3.0,<4)", "sphinx-better-theme (>=0.1.4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "tox (>=1.8.0)", "tqdm (>4.32,<5)", "twine (>=1.13,<2)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1,<3)", "types-setuptools (>=57.4.4,<58)", "urllib3", "wheel", "when-changed (>=0.3.0,<0.4)"] docs = ["Jinja2 (<=3.0.3)", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "mock", "py-geth (>=3.9.1,<4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "sphinx (>=3.0,<4)", "sphinx-better-theme (>=0.1.4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "urllib3", "wheel"] linter = ["flake8 (==3.8.3)", "isort (>=4.2.15,<4.3.5)", "mypy (==0.910)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1,<3)", "types-setuptools (>=57.4.4,<58)"] -tester = ["eth-tester[py-evm] (==v0.6.0-beta.7)", "py-geth (>=3.9.1,<4)"] +tester = ["eth-tester[py-evm] (==v0.6.0-beta.6)", "py-geth (>=3.9.1,<4)"] [[package]] name = "websocket-client" @@ -2791,12 +2813,12 @@ cli = ["click"] [metadata] lock-version = "1.1" python-versions = ">=3.8,<3.11" -content-hash = "804791c0a5055684498b194116cf827bc30d5d34d60f3eba5b4cee786940aec7" +content-hash = "313d90b2beaeec043b6228f275e6fbcb60f0a3a3eb350225e20c73d73e9d8761" [metadata.files] absl-py = [ - {file = "absl-py-1.3.0.tar.gz", hash = "sha256:463c38a08d2e4cef6c498b76ba5bd4858e4c6ef51da1a5a1f27139a022e20248"}, - {file = "absl_py-1.3.0-py3-none-any.whl", hash = "sha256:34995df9bd7a09b3b8749e230408f5a2a2dd7a68a0d33c12a3d0cb15a041a507"}, + {file = "absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d"}, + {file = "absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47"}, ] aiohttp = [ {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"}, @@ -2899,8 +2921,8 @@ asn1crypto = [ {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, ] astroid = [ - {file = "astroid-2.12.13-py3-none-any.whl", hash = "sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907"}, - {file = "astroid-2.12.13.tar.gz", hash = "sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7"}, + {file = "astroid-2.13.2-py3-none-any.whl", hash = "sha256:8f6a8d40c4ad161d6fc419545ae4b2f275ed86d1c989c97825772120842ee0d2"}, + {file = "astroid-2.13.2.tar.gz", hash = "sha256:3bc7834720e1a24ca797fd785d77efb14f7a28ee8e635ef040b6e2d80ccb3303"}, ] astunparse = [ {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, @@ -2935,93 +2957,93 @@ bip-utils = [ {file = "bip_utils-2.7.0.tar.gz", hash = "sha256:bc6302840a95695609e215ad362ddb42d70d472b3cb1494d1fb2112d08c1c707"}, ] bitarray = [ - {file = "bitarray-2.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:758e078c8b04e32fa2926b00484ba251fd4e580bff45c477a0d97de8d9aca26a"}, - {file = "bitarray-2.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:391868f7c60993afddb33dd4f6de0fed3583572133c6c1fdb3301c423dcaa1bd"}, - {file = "bitarray-2.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc2ecc8d3d49a178a7fc78ddcd8e6126c552c0d905de709eb9d4fe7cfba5f62b"}, - {file = "bitarray-2.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a04654315dbe4d137e2d55234496091d5c6602f886798832b46a1e0bdba3d52"}, - {file = "bitarray-2.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33e50f3af1fad9bc92544017b577ddc0a8be01411a19cf14afb1add1ec809835"}, - {file = "bitarray-2.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a102c90e82b80b88d934794b3506ff3a41a4964b9a1b0895bf480303ca99ef82"}, - {file = "bitarray-2.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c82c2057e2af71a930983ff51eddfeec1e5169af376975f1716f785cd2aabe6"}, - {file = "bitarray-2.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:097a2e6015e1ba663b3235b4c305470717f1a1e9d6dd211212010431e80b91f9"}, - {file = "bitarray-2.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db9894527bac35c4740dee96abe37978a8be91f774b69fa033dc1264a8a114ac"}, - {file = "bitarray-2.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f7b632757a2fa7f19f29c5c750a389a5f4681636936d327c020acd186e2d82bc"}, - {file = "bitarray-2.6.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:404064972413c8e8bec99de20b37f8617f74c73e13a4439bbc8bd7a3801182f8"}, - {file = "bitarray-2.6.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7e6d14e391bac9e53009d16548eed5243e6956752807621715cc5b07f69c55bf"}, - {file = "bitarray-2.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:034712f8843544ba2e9aa574628035e3e8d141e878365623b594c7fbe6440f4b"}, - {file = "bitarray-2.6.1-cp310-cp310-win32.whl", hash = "sha256:f559a645e50d081bf5ba25550bffe1126cfbd1e2b3d57dd3fb688fb5da66e718"}, - {file = "bitarray-2.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:e6137124297839bc2dc073d97b9dbdb22e476bf9cae7ca68d64d937a66ff19e4"}, - {file = "bitarray-2.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f5a1eb0b9e853631025353b813e5fb05e68a6113708afdfdaff84dde59f9b3a"}, - {file = "bitarray-2.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49772c92b10b989fd4581f7c354a83f4cc20bbd2c6c48bef57aa73a23f9e3ebc"}, - {file = "bitarray-2.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:096e538a25c2323eb72720c8b8681900b48012f82e4548bb4ec2eda16f634455"}, - {file = "bitarray-2.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77599b490e42e901f656666bbad50b2e08791a8381275a01a22cf461d95627f2"}, - {file = "bitarray-2.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2477dec4feeff17202074a2adee37efcb1ecec8dc2f10f35d552d0bfaf2ec7b7"}, - {file = "bitarray-2.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af2820fab55a7533133286fedae649e77c9ae8d8a0485afc895268e50dd96eba"}, - {file = "bitarray-2.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7348712346082ae9f246b92b1b17b6cdd7daab5fda3d7b0604c3d569ad953548"}, - {file = "bitarray-2.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c539b56b78a54b83a07a371f9db0e35a59fac6a12fe89a2632a2cfefa89197da"}, - {file = "bitarray-2.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e20edff57f3fa26b457311f887e076e773d3b13acbbaf8dfdf18c7019c971f4"}, - {file = "bitarray-2.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:97643c9f755f1754cf17f063688826012e6d70b1b341c4bb22323589ff010288"}, - {file = "bitarray-2.6.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:9df2525c68dea2f8d2700a2307533f5c34854cd0f6455f92e1da1ed3e80dc512"}, - {file = "bitarray-2.6.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ffbaad32418e91f7f7916447a3c3f6e2dd3f12abeb71ca43b063c64f3d2beb05"}, - {file = "bitarray-2.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8909a248227beef7ed222f5031519436a986a36b9f82f63f5c25e1b510728247"}, - {file = "bitarray-2.6.1-cp311-cp311-win32.whl", hash = "sha256:cd977dce97e0b3d16cf28a21e5d28d4f462dddac7d3c6f4e434ec409c78adeb1"}, - {file = "bitarray-2.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:3cdfed3c81035385ae7dd859d1e054a0dda6770e83bc5b112ca0b4bce91a753a"}, - {file = "bitarray-2.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5123a30bc921158286f06259517b962e8c42c845572bd0be16de491ee990bede"}, - {file = "bitarray-2.6.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c3fa5743d1882a1f32f5b908065c7feb374fd43ae6e936442d532b71e7aff3c"}, - {file = "bitarray-2.6.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8118fca0202467f4d6935836d597f43d840238b599c1ee1e3ef3a7ddeb8782c8"}, - {file = "bitarray-2.6.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30b9fa3a1f52e9d395049be6c410e435d20ff8f97429896a40788d3b055cceca"}, - {file = "bitarray-2.6.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b754b3e6d2e4699c5989734864492bdd47478c0b3fb225c03e2016fe01a5c109"}, - {file = "bitarray-2.6.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ac5fb13391507aa33ee4189ed5e640ddbbfd7106fc4290677061f1b3b997fb0"}, - {file = "bitarray-2.6.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:ea19a8a7a53894fc3ecf2f94829a72cf253fc08ea7e7d7d617e4f4f5bd5b7550"}, - {file = "bitarray-2.6.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:491f5360c787eaf9b809b258a43d88ab151770d6d0cb2b64a49516798f322ee2"}, - {file = "bitarray-2.6.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:db285a317ff423bbe6a7f11ae76de77e6bcf6f3584ce5a79e428f26b25a191b6"}, - {file = "bitarray-2.6.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:1f22552be33cb8b5fa86c68ae21e3d512bb73c304cadfd2912857cd694c70159"}, - {file = "bitarray-2.6.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3b6d788f72e64d18cbc270e757e32b90ef1dbd1190614d67bb395ad1edc0cf58"}, - {file = "bitarray-2.6.1-cp36-cp36m-win32.whl", hash = "sha256:2e6a2087ed0fd1e1ecf8729f89998304e22034d7b53baf689c94ddc101c7d6d5"}, - {file = "bitarray-2.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:47d6cdcc77e42e5e48ed04e009ec6371a972ca1ffefdfd66545bb7213754fb62"}, - {file = "bitarray-2.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:96a814c8350d97a31d0b7d4174f1ee8e335abc486bd5a4e8c7497314757546d6"}, - {file = "bitarray-2.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb817e2943ba4702f8e0c8cfcec9228fff1379434d8c0ab4ee198bd121a2222"}, - {file = "bitarray-2.6.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce95811e39e3483bdfd82423593a3c90b6df121010257af3aad28222221b6610"}, - {file = "bitarray-2.6.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6608473dea7905ef0b1b2a2153a8f6bd9a474c70166ff58e7092a965be2bf76"}, - {file = "bitarray-2.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a6af23cb8d3308d2424556f85ea99eb4aa673f279f9b55a3fc0f138df0170aa"}, - {file = "bitarray-2.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0649effe8f2b905c5160a30eaa56bda03bf322829f7bf9001d209391173b2764"}, - {file = "bitarray-2.6.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a6af2a375512fa86476412cde0b57a398164792567ebc4ac38bd789bdfb49a2b"}, - {file = "bitarray-2.6.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8c10449d1960009d8cb1b1c8e863671a092fdc8f952979562a1b60a1fd42172d"}, - {file = "bitarray-2.6.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f9e76ba953713ab88da89d9fe811cc74391d422ce2dbc89bfb7b33c92582b104"}, - {file = "bitarray-2.6.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6955f750cc6a9d142e3ba323eb093ed8355cfdea648c35499bc45bdfd7da03b2"}, - {file = "bitarray-2.6.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7f65a7d571d201f7cb45e35a6f90465137a4362b7ddc0dca98fe4bcc179af65"}, - {file = "bitarray-2.6.1-cp37-cp37m-win32.whl", hash = "sha256:7cdf27dc8a20793ef52b1dbecb5aa0d62ce34700410b9681bffc3f3d89337d59"}, - {file = "bitarray-2.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d252f88dd22a9786dbe78451e1776a09ab4fea5dbf151c0d97149b1a91499d5c"}, - {file = "bitarray-2.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0abffbb04c6238430ce2ebec4254ed1136557c522f406cefad33aeca6dc15628"}, - {file = "bitarray-2.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20fb3e6ea148548d7c2a50bcb4238d1c8c2be21f04e101ba648f5f28636a7cad"}, - {file = "bitarray-2.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0c139c9a89291989b45a09f1bc6911dd97695d31311f9ec466ae09cb56166fcb"}, - {file = "bitarray-2.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779779bc7f4924a0e4d9d1ff3222c295571a56b597557faedcdd4f4c1067e8f6"}, - {file = "bitarray-2.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c5e137dd85a0fef71ac3d602dfd1fafadcdc54371e879b312290ec8ab75260d"}, - {file = "bitarray-2.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0867f4e48884ccf9e3324916122e20193f0f04ef407df58f76b29b0b7c4dde2e"}, - {file = "bitarray-2.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2740880c8664a09ca0044ad251701fad5647b91959c1d036b27387e582e7abd"}, - {file = "bitarray-2.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a69cc8ddd15bb129306c8be7b9eb0e2a52b689a99daaa884f09ceba385313781"}, - {file = "bitarray-2.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98ad08c01b120f64aaea87d65395e8f43c74dedd8cc51d12d834687313c80059"}, - {file = "bitarray-2.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f90dcf9e91ff9a15a5392d79ece61d02482a894d53e95cf26d78c620d3be65c"}, - {file = "bitarray-2.6.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1bec2595891ca421c14f577937d889d164d3cd069a0caa7b3de003a822f0ec59"}, - {file = "bitarray-2.6.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:94da059dd7c7415d0857bcf271a5af626593b9b3b478fba2d9a1c03fd6fddf54"}, - {file = "bitarray-2.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f44c3c52446ea168466ac86bc215be3be49d8417133a7914f9ac7d83dd891714"}, - {file = "bitarray-2.6.1-cp38-cp38-win32.whl", hash = "sha256:70ed1fa0141d3c4a17e529c096a8ed46a681ea1b7719f4022c7751e8a7be578a"}, - {file = "bitarray-2.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:a57acfb28cebb79afde68f9b42c02c8f3e34a808a164e420a2c799035c01f579"}, - {file = "bitarray-2.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:45d52a5f1b99ffa64cf0ff822d4efec848ccc4c5b62e22157cb5ec86c6cf4940"}, - {file = "bitarray-2.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:85ec485bbc08812594e5971d32dab4acd73ad347b388f8d0f299e4c0e154e29d"}, - {file = "bitarray-2.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:61d57f9e4880fdf107ad5c9e84e3742ef8b5f67b5869e5da7b45d30ac8168129"}, - {file = "bitarray-2.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411b1c01de6ba6581259cade18676f023447e22744ce1d5b44ff5beb3f7ef824"}, - {file = "bitarray-2.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf8857f0e745c55d19a0ac2b36b43e70b782c0c29094b3941dfd77f69aae61b9"}, - {file = "bitarray-2.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:428785f992b774ba5eaf1c9dacca532c03b8db416a61898b21f09c91c9f924a4"}, - {file = "bitarray-2.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a68a3c7b134c6947ae4186edde865aae56bfe6a86f22b76fa6d5d53165fe43"}, - {file = "bitarray-2.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df1b099d1b76c83db15164588b8abecf09fdbad665db7b550d40468e14087515"}, - {file = "bitarray-2.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cbb191a80bf728c2cfd8e06fb9c1ebe5a53cf9d36303e74260a8288317024b15"}, - {file = "bitarray-2.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6d1600401b0d673333f7b11e0a7da665c2502216031399444cf2217a3211d077"}, - {file = "bitarray-2.6.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d28f390dee46f7b8eec6378474f16935a9db2eb14b1f8eb7c3a42fc4218fe099"}, - {file = "bitarray-2.6.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b24a9c8ad7cea786e4bad5780748efa4a3ba32b4457d173d49285cf22e64dc10"}, - {file = "bitarray-2.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:529da137751c0d619871f6886373428df19a268fcf96830c10e213f377947e3e"}, - {file = "bitarray-2.6.1-cp39-cp39-win32.whl", hash = "sha256:8aeb90e9ec5555618db564de6a4ec62eab6fd21233d8dee524a09941430ff6d5"}, - {file = "bitarray-2.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:916f9025c672394a628b6fe1a27193c62f1947bcf075cbbebcf5b7f4869f0be6"}, - {file = "bitarray-2.6.1.tar.gz", hash = "sha256:8440a5493221f6ed6c4e0d9cb2ba6e4e600a5fb639f66003eaf15b7150a49230"}, + {file = "bitarray-2.6.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5d3edf2988fff6629698e693b08787567016559f5d28f94ea0179f59a492cd74"}, + {file = "bitarray-2.6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f14f628e984d46988d01402fb6ea3fae323c4bf374701c9f9c3c0d47698f02f2"}, + {file = "bitarray-2.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e73a6f8f5e42092bc5369276d8852d3f01412f135bc8338575841886a90095b7"}, + {file = "bitarray-2.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff7ad4a624a70e13361aedeab1c4043aa3ceb0f1af2fe36b1a74bbbdbb99001d"}, + {file = "bitarray-2.6.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c8ec7e422b539000ab589d4a45db83f854e3fc21a73a740cb4dc40a1737b146"}, + {file = "bitarray-2.6.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fecc66634f011eda569dbf09886c237225224033fc31a5c90e17fa6478d09ff"}, + {file = "bitarray-2.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a70a264caff98525ea3ca62849649771fbb05b9e52e2ced47e092f6f4c0530d"}, + {file = "bitarray-2.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cea20ec562c982234a07e0a94c1653fb88afdc45c587b353cc16f25ba3a38da"}, + {file = "bitarray-2.6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9a8551dd0d255d16979c23d03f26b08993167789023dd2eb99cf0d7bebbc56e7"}, + {file = "bitarray-2.6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d5fc9464457ffd3fbd400b26bfdcb6cad72fc90c1cf2697cd0d58e056b17681b"}, + {file = "bitarray-2.6.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df692091edc855e74c6c753e20faa4e75da22da73736924a7f13f6c1842e121d"}, + {file = "bitarray-2.6.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:a84ae1f37644317627859f4d68f9be4cfe6fcd2709e1fc7d511b23eb7aff3030"}, + {file = "bitarray-2.6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e44146573e2934b1be17459dc497c7d41774b9cbdb1946657799303dfffb68d2"}, + {file = "bitarray-2.6.2-cp310-cp310-win32.whl", hash = "sha256:c1649dff7ddbee282a52b2b692e320a7a72de994c486a97d90d161ce5fa72c5c"}, + {file = "bitarray-2.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:88c327d53acd5faf9c6c537d2c5df75e057baecd6b46768becc7fe14cdd8d9cd"}, + {file = "bitarray-2.6.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:43a474e78d1fbafd09837140ca3e31429ee31a6ad86ab146af577019d41bfc8b"}, + {file = "bitarray-2.6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c484020a523f2c671bdc5a91bd7f1ce87440b817ec14f0dd4b2320f32bc8ee9"}, + {file = "bitarray-2.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c939e71e9985ac836bc193fb1a3a4c7feb8d88bb6d1e4afe9cd6abe4181ef8d5"}, + {file = "bitarray-2.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194b738cbc8cdceaa25a4b393a3a8f43090f14704ecfdadac8c18407c15e158d"}, + {file = "bitarray-2.6.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce07f0271eec9ad21451fe9b94192e0430567ab9b3bd2c819465dc87eb3dc4fc"}, + {file = "bitarray-2.6.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d04f76a0dc1a84a96b9fe1ad346b36796185b3334ba69877cd20cf735c98830b"}, + {file = "bitarray-2.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76f94b1a536a2c38512875b1bc82a39d1e4682d74f79eb19db9107d8882150c8"}, + {file = "bitarray-2.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d9863eaad6e5b7a7e93291f568b3b49b6c006e32e6bc0f1bdf4509deb39dc4"}, + {file = "bitarray-2.6.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3643817c717bbfaf7ee44d40b0b1b0fd0fb3dcd7e9d14c742d7c08cc8e7b8a31"}, + {file = "bitarray-2.6.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4839626b802fc85adf61753dcc526e585b49b32e8cd0a46fdc8fd91970cd0d72"}, + {file = "bitarray-2.6.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:606f63dc9345c69598d5248900d497a83b58958003f246470e25de66b400c3f2"}, + {file = "bitarray-2.6.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:61a1b2a4826588fee73a3b87a86b7d2ae2cd16859ef4aca2d7fb244ae51932e0"}, + {file = "bitarray-2.6.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b444416cca8caa5c9a86e63703514c166bc6e3f37d7ce3668c7e9b93403f0de0"}, + {file = "bitarray-2.6.2-cp311-cp311-win32.whl", hash = "sha256:acce34ebcb69bc1a14ec7a9834bb63bb65eeb6d01b8346c5e06835423e4f5709"}, + {file = "bitarray-2.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae0b4e7f07a2c6283686f3143bb6a9a4d95a930a21b54dfb1ecad65724879faf"}, + {file = "bitarray-2.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de93a82a13f042e978fbc6650112c3cd4aedabb272a6ebfc431b150889e6143b"}, + {file = "bitarray-2.6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e3a0178cd4fd7cdd835d8cd166bf8a3e5b1bd5703a2e14d15ed6234737517ef"}, + {file = "bitarray-2.6.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e1d4dd3d7a84f70d01be0fe53da69f1954b68139ea552406169ae9c5e4cadee"}, + {file = "bitarray-2.6.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e50a54c8c8d17903f714e270ceb7b13d5d14d899f5be0828f37e1cb192a8e069"}, + {file = "bitarray-2.6.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:333747da2365c1df10881a57f2015bcf93cf3cb2cd8e33207628596e42c3d618"}, + {file = "bitarray-2.6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f437687aed4accb75ec6325d4c8747901e766b12df1c4ed9eebaca1f98068c8"}, + {file = "bitarray-2.6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1740c618c903e24797ca5fae3d85f8806c9193623106cef99b7aa60e457c2cc3"}, + {file = "bitarray-2.6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:42da7ab8fade0adcc9594b546ab57acca167bff57d1b2f1ec9fd2b9bdddd46ad"}, + {file = "bitarray-2.6.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:021d5f69b6ed3d674d95c99d7e3f16c8f750f67ac7395592543807c36e706f0e"}, + {file = "bitarray-2.6.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:c6a9018839e104238ae0512f61d4c8414ce53f01971e9a0417c90eea19869c1e"}, + {file = "bitarray-2.6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a15cfa5f58a1d3124d43d93a642625caa72234687bfbd4dbff24c84457b64ee7"}, + {file = "bitarray-2.6.2-cp36-cp36m-win32.whl", hash = "sha256:b75b825ecb338a93f10048e121b7f38cf4dbdecf8a7b6ca3a85f5a58d6920397"}, + {file = "bitarray-2.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:51fe3da246133779617ae333ac81b32e1bc3e7603f89d31929e51553e1511a8f"}, + {file = "bitarray-2.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c66d9a05f32bf5390c4ef838a0a444ecb1f5ef98b5ce398490f57abfefc26a56"}, + {file = "bitarray-2.6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c8f3ab0d95ff7eb30c556d71c166d7f5f2a40f1db365e7c703f9a32ff525e1"}, + {file = "bitarray-2.6.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db0d0682d8334c2f347a5fb2544beb9167a2209d5c2bf2f92a3398f189600c0"}, + {file = "bitarray-2.6.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b70a480515ee9b41ce634b17939a754340febad06d422b12e4a4772e2760e710"}, + {file = "bitarray-2.6.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619693e63c558b535d2f43e576f8f1d8c3b25428a7b73ad68b5e35e70812323e"}, + {file = "bitarray-2.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cbc14b8940e801cc54707aa01e5a8c94517a517f720aa3236cc1cd7486c5e5c"}, + {file = "bitarray-2.6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:50a97cce5d9612a12a9a7b3a974f91c0621565898a365cb9dad3e11f65165a0b"}, + {file = "bitarray-2.6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:89bec783329e9a318ff7f6bacebe14c246a7bf9f3922d7ad09053860b0803cd1"}, + {file = "bitarray-2.6.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:6dca5a48446f04828a19a0cc5379bd855aad26eff1e50cc6b79cb96afab342e6"}, + {file = "bitarray-2.6.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5f5f065d51ec4479a04bb5197ec47afd47c26590c92d90efdc7ab945d8d3fab4"}, + {file = "bitarray-2.6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b06ea7287def76def64ec0203b32f2c171d6b8b378f1125ac3f3a96414e7a69b"}, + {file = "bitarray-2.6.2-cp37-cp37m-win32.whl", hash = "sha256:52677ae25ffa19691401bf47db16141e708398a456b96353ec2abe90511cd2d2"}, + {file = "bitarray-2.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b5580d0b094ef766f50e1d2286b2192d13f4300a6ee03a56cdf763df9623bae8"}, + {file = "bitarray-2.6.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1e51133da6c01c028d8fae0145bb3f82475f06bb23b35ef262c0c1bd15db0ff5"}, + {file = "bitarray-2.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:026cfda32022ee80b4956665f9536b4ff7ace6612f113c412d477d63b05745d7"}, + {file = "bitarray-2.6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f20ec7427bd2a1496a8704688e419e47c2fb46f3812b091fb521dcdffdde578c"}, + {file = "bitarray-2.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a0a72fcc106e1ae5a9261de1d99ce188517dc1343d05e781c2f3fef1d07f58"}, + {file = "bitarray-2.6.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fed50b9f47823879f1e62c7d599777cdeabe0979919fb94e2aa4ee4e8a5f58d"}, + {file = "bitarray-2.6.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a00da10ad5afb77fa1eded733634647c83f87eafcfc8bb58de275da65266c21"}, + {file = "bitarray-2.6.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b356a87cd0271988a90783bccf48bc8e1c7b2e026f8782107aa5b2459369014"}, + {file = "bitarray-2.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e421015c881bbcc509d40469ed84058c7c39d72ed459c68e90be5f40f1e82f"}, + {file = "bitarray-2.6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d9d92b9d82264f2289097c15c0ef354fba58e58127d5ddeb17421283c3d901d"}, + {file = "bitarray-2.6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a2741442796db0d44a1b6108c102457c3aec19df56d2211f6de30beea025ca5c"}, + {file = "bitarray-2.6.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f03b7e95c7101ab4b347441daa57a847d0a48e9cb20faf1ebbfeecfba9107b16"}, + {file = "bitarray-2.6.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:1f16738dd55788a19bfde25ba2ab4f60fefd028b659a6ce2ae2158371ad166d6"}, + {file = "bitarray-2.6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f86e128040198940ebb1631d59d372e388f4f19a023cc69f3156a97a56a1bab9"}, + {file = "bitarray-2.6.2-cp38-cp38-win32.whl", hash = "sha256:8ea16ce12b894f423126478508b169a6440fc9799a7f7eb35e08473d1788ae80"}, + {file = "bitarray-2.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:ca96bd9124ed7c24b1b86f7ecfb188eff3ceb422f15408388bd9e42c2ccb5ca0"}, + {file = "bitarray-2.6.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9002ee11167174d874daec377f67c2683f7c10d4ff84e3f0bbda1bf444d78dae"}, + {file = "bitarray-2.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:615b078e6b37b1885a65e08d7c0656d1608b8ec7b512702a5643f3a14652060c"}, + {file = "bitarray-2.6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6f31c0df0ebb8908240d6d5c938ba640713920ae4996f9cfc8f5bc2f175c24fa"}, + {file = "bitarray-2.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ad90016568279754f4e1772becfce0766593ea51339dbba71a7457ac66866f"}, + {file = "bitarray-2.6.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da723afce203274297028f07f7b8c8cc6daa2a31b905b6eba860741d2dda8bd1"}, + {file = "bitarray-2.6.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c139bfc8f10fdb43303b3e1e1b4bcc75511c45cd8b383a34f808734751614e4f"}, + {file = "bitarray-2.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7276c6b57523f37e0b66610a543b66e33aa8bae8c4582392664a29088714567"}, + {file = "bitarray-2.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5ae1bac51da6e0cc74259cac43a3dfb2daa37e72546f1365da6161c8a43426a"}, + {file = "bitarray-2.6.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:900b008a7c57806ac3112d785a5b54b7a9c685e582910b1bdb68be57b2d0fc80"}, + {file = "bitarray-2.6.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1190c963e38cb6d60574155b62b2ef130ce0ad14cb79d84ea1a39b27a784dbf7"}, + {file = "bitarray-2.6.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:5257c30f744a2483d43c577724b4a553232c6dcd1ded32cd1aeb4c890e709ec8"}, + {file = "bitarray-2.6.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:8b98bcbf3b3eb4992cf8e884beb6fe42d25d3d1a575c1f455567336fb3e16ddf"}, + {file = "bitarray-2.6.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9212e13cf20ab3388c3ef1b72ea32c77778115f33ff0de2c093bd19360206ae"}, + {file = "bitarray-2.6.2-cp39-cp39-win32.whl", hash = "sha256:4fc37c92391f1d0ecbdfabf1b68db2f13eacdec4b1db1604c72dd3c3f923bf90"}, + {file = "bitarray-2.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:3af6c3b7d803df41a68092b6d1164feeca8bb7eb5a1b2be9b666700ffa18e84b"}, + {file = "bitarray-2.6.2.tar.gz", hash = "sha256:90bac83ba6c37ab5048b43e07eba7d0de12f301ad6641633656fa269618a7301"}, ] black = [ {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, @@ -3064,8 +3086,8 @@ blspy = [ {file = "blspy-1.0.16.tar.gz", hash = "sha256:5c005d4ba082509a59f4dd55adad3bf15d07a03537daed65df2cfde99287c057"}, ] cachetools = [ - {file = "cachetools-5.2.0-py3-none-any.whl", hash = "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db"}, - {file = "cachetools-5.2.0.tar.gz", hash = "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757"}, + {file = "cachetools-5.2.1-py3-none-any.whl", hash = "sha256:8462eebf3a6c15d25430a8c27c56ac61340b2ecf60c9ce57afc2b97e450e47da"}, + {file = "cachetools-5.2.1.tar.gz", hash = "sha256:5991bc0e08a1319bb618d3195ca5b6bc76646a49c21d55962977197b301cc1fe"}, ] cbor2 = [ {file = "cbor2-5.4.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:309fffbb7f561d67f02095d4b9657b73c9220558701c997e9bfcfbca2696e927"}, @@ -3240,57 +3262,57 @@ cosmpy = [ {file = "cosmpy-0.6.2.tar.gz", hash = "sha256:a7c92b13a34bfa4b5287e56c3d4c7cb85cc3e8d008965da3fb18711c46c18ab6"}, ] coverage = [ - {file = "coverage-7.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2569682d6ea9628da8d6ba38579a48b1e53081226ec7a6c82b5024b3ce5009f"}, - {file = "coverage-7.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ec256a592b497f26054195f7d7148892aca8c4cdcc064a7cc66ef7a0455b811"}, - {file = "coverage-7.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5885a4ceb6dde34271bb0adafa4a248a7f589c89821e9da3110c39f92f41e21b"}, - {file = "coverage-7.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d43d406a4d73aa7f855fa44fa77ff47e739b565b2af3844600cdc016d01e46b9"}, - {file = "coverage-7.0.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18df11efa615b79b9ecc13035a712957ff6283f7b244e57684e1c092869f541"}, - {file = "coverage-7.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f6a4bf5bdee93f6817797beba7086292c2ebde6df0d5822e0c33f8b05415c339"}, - {file = "coverage-7.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:33efe89cd0efef016db19d8d05aa46631f76793de90a61b6717acb202b36fe60"}, - {file = "coverage-7.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96b5b1f1079e48f56bfccf103bcf44d48b9eb5163f1ea523fad580f15d3fe5e0"}, - {file = "coverage-7.0.0-cp310-cp310-win32.whl", hash = "sha256:fb85b7a7a4b204bd59d6d0b0c8d87d9ffa820da225e691dfaffc3137dc05b5f6"}, - {file = "coverage-7.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:793dcd9d42035746fc7637df4336f7581df19d33c5c5253cf988c99d8e93a8ba"}, - {file = "coverage-7.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d564142a03d3bc8913499a458e931b52ddfe952f69b6cd4b24d810fd2959044a"}, - {file = "coverage-7.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0a8b0e86bede874bf5da566b02194fbb12dd14ce3585cabd58452007f272ba81"}, - {file = "coverage-7.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e645c73cbfc4577d93747d3f793115acf6f907a7eb9208fa807fdcf2da1964a4"}, - {file = "coverage-7.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de06e7585abe88c6d38c1b73ce4c3cb4c1a79fbb0da0d0f8e8689ef5729ec60d"}, - {file = "coverage-7.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a30b646fbdd5bc52f506e149fa4fbdef82432baf6b81774e61ec4e3b43b9cbde"}, - {file = "coverage-7.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:db8141856dc9be0917413df7200f53accf1d84c8b156868e6af058a1ea8e903a"}, - {file = "coverage-7.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:59e71912c7fc78d08a567ee65656123878f49ca1b5672e660ea70bf8dfbebf8f"}, - {file = "coverage-7.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b8f7cd942dda3795fc9eadf303cc53a422ac057e3b70c2ad6d4276ec6a83a541"}, - {file = "coverage-7.0.0-cp311-cp311-win32.whl", hash = "sha256:bf437a04b9790d3c9cd5b48e9ce9aa84229040e3ae7d6c670a55118906113c5a"}, - {file = "coverage-7.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a7e1bb36b4e57a2d304322021b35d4e4a25fa0d501ba56e8e51efaebf4480556"}, - {file = "coverage-7.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:215f40ef86f1958a1151fa7fad2b4f2f99534c4e10a34a1e065eba3f19ef8868"}, - {file = "coverage-7.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae088eb1cbdad8206931b1bf3f11dee644e038a9300be84d3e705e29356e5b1d"}, - {file = "coverage-7.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9071e197faa24837b967bc9aa0b9ef961f805a75f1ee3ea1f3367f55cd46c3c"}, - {file = "coverage-7.0.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f1e6d9c70d45a960d3f3d781ea62b167fdf2e0e1f6bb282b96feea653adb923"}, - {file = "coverage-7.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9fadd15f9fcfd7b16d9cccce9f5e6ec6f9b8df860633ad9aa62c2b14c259560f"}, - {file = "coverage-7.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:10b6246cae61896ab4c7568e498e492cbb73a2dfa4c3af79141c43cf806f929a"}, - {file = "coverage-7.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a8785791c2120af114ea7a06137f7778632e568a5aa2bbfc3b46c573b702af74"}, - {file = "coverage-7.0.0-cp37-cp37m-win32.whl", hash = "sha256:30220518dd89c4878908d73f5f3d1269f86e9e045354436534587a18c7b9da85"}, - {file = "coverage-7.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bc904aa96105d73357de03de76336b1e3db28e2b12067d36625fd9646ab043fd"}, - {file = "coverage-7.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2331b7bd84a1be79bd17ca8e103ce38db8cbf7cb354dc56e651ba489cf849212"}, - {file = "coverage-7.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e907db8bdd0ad1253a33c20fdc5f0f6209d271114a9c6f1fcdf96617343f7ca0"}, - {file = "coverage-7.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0deee68e0dae1d6e3fe6943c76d7e66fbeb6519bd08e4e5366bcc28a8a9aca"}, - {file = "coverage-7.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fff0f08bc5ffd0d78db821971472b4adc2ee876b86f743e46d634fb8e3c22f"}, - {file = "coverage-7.0.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a290b7921c1c05787b953e5854d394e887df40696f21381cc33c4e2179bf50ac"}, - {file = "coverage-7.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:100546219af59d2ad82d4575de03a303eb27b75ea36ffbd1677371924d50bcbc"}, - {file = "coverage-7.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c1ba6e63b831112b9484ff5905370d89e43d4316bac76d403031f60d61597466"}, - {file = "coverage-7.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c685fc17d6f4f1a3833e9dac27d0b931f7ccb52be6c30d269374203c7d0204a2"}, - {file = "coverage-7.0.0-cp38-cp38-win32.whl", hash = "sha256:8938f3a10f45019b502020ba9567b97b6ecc8c76b664b421705c5406d4f92fe8"}, - {file = "coverage-7.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:c4b63888bef2928d0eca12cbce0760cfb696acb4fe226eb55178b6a2a039328a"}, - {file = "coverage-7.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cda63459eb20652b22e038729a8f5063862c189a3963cb042a764b753172f75e"}, - {file = "coverage-7.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e06abac1a4aec1ff989131e43ca917fc7bd296f34bf0cfe86cbf74343b21566d"}, - {file = "coverage-7.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b94ad926e933976627f040f96dd1d9b0ac91f8d27e868c30a28253b9b6ac2d"}, - {file = "coverage-7.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6b4af31fb49a2ae8de1cd505fa66c403bfcc5066e845ac19d8904dcfc9d40da"}, - {file = "coverage-7.0.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36b62f0220459e528ad5806cc7dede71aa716e067d2cb10cb4a09686b8791fba"}, - {file = "coverage-7.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:43ec1935c6d6caab4f3bc126d20bd709c0002a175d62208ebe745be37a826a41"}, - {file = "coverage-7.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8593c9baf1f0f273afa22f5b45508b76adc7b8e94e17e7d98fbe1e3cd5812af2"}, - {file = "coverage-7.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fee283cd36c3f14422d9c1b51da24ddbb5e1eed89ad2480f6a9f115df38b5df8"}, - {file = "coverage-7.0.0-cp39-cp39-win32.whl", hash = "sha256:97c0b001ff15b8e8882995fc07ac0a08c8baf8b13c1145f3f12e0587bbb0e335"}, - {file = "coverage-7.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:8dbf83a4611c591b5de65069b6fd4dd3889200ed270cd2f7f5ac765d3842889f"}, - {file = "coverage-7.0.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:bcaf18e46668057051a312c714a4548b81f7e8fb3454116ad97be7562d2a99e4"}, - {file = "coverage-7.0.0.tar.gz", hash = "sha256:9a175da2a7320e18fc3ee1d147639a2b3a8f037e508c96aa2da160294eb50e17"}, + {file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"}, + {file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"}, + {file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"}, + {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"}, + {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"}, + {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"}, + {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"}, + {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"}, + {file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"}, + {file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"}, + {file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"}, + {file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"}, + {file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"}, + {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"}, + {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"}, + {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"}, + {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"}, + {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"}, + {file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"}, + {file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"}, + {file = "coverage-7.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b69522b168a6b64edf0c33ba53eac491c0a8f5cc94fa4337f9c6f4c8f2f5296c"}, + {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436e103950d05b7d7f55e39beeb4d5be298ca3e119e0589c0227e6d0b01ee8c7"}, + {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c56bec53d6e3154eaff6ea941226e7bd7cc0d99f9b3756c2520fc7a94e6d96"}, + {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a38362528a9115a4e276e65eeabf67dcfaf57698e17ae388599568a78dcb029"}, + {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f67472c09a0c7486e27f3275f617c964d25e35727af952869dd496b9b5b7f6a3"}, + {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:220e3fa77d14c8a507b2d951e463b57a1f7810a6443a26f9b7591ef39047b1b2"}, + {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecb0f73954892f98611e183f50acdc9e21a4653f294dfbe079da73c6378a6f47"}, + {file = "coverage-7.0.5-cp37-cp37m-win32.whl", hash = "sha256:d8f3e2e0a1d6777e58e834fd5a04657f66affa615dae61dd67c35d1568c38882"}, + {file = "coverage-7.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9e662e6fc4f513b79da5d10a23edd2b87685815b337b1a30cd11307a6679148d"}, + {file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"}, + {file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"}, + {file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"}, + {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"}, + {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"}, + {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"}, + {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"}, + {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"}, + {file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"}, + {file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"}, + {file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"}, + {file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"}, + {file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"}, + {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"}, + {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"}, + {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"}, + {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"}, + {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"}, + {file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"}, + {file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"}, + {file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"}, + {file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"}, ] crcmod = [ {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, @@ -3498,8 +3520,8 @@ exceptiongroup = [ {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, ] filelock = [ - {file = "filelock-3.8.2-py3-none-any.whl", hash = "sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c"}, - {file = "filelock-3.8.2.tar.gz", hash = "sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2"}, + {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, + {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, ] flake8 = [ {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, @@ -3522,8 +3544,8 @@ flake8-isort = [ {file = "flake8_isort-5.0.0-py3-none-any.whl", hash = "sha256:c73f9cbd1bf209887f602a27b827164ccfeba1676801b2aa23cb49051a1be79c"}, ] flatbuffers = [ - {file = "flatbuffers-22.12.6-py2.py3-none-any.whl", hash = "sha256:b12a3214e73f325ecd392503e821ac43a791181356f020cc3657ba829b4947c8"}, - {file = "flatbuffers-22.12.6.tar.gz", hash = "sha256:27f67c6fb102d41c911c26867bda71f1f8622176ac072fa30f668f4d023b5826"}, + {file = "flatbuffers-23.1.4-py2.py3-none-any.whl", hash = "sha256:8bf47bcaef0deac76ae95586032e867e1d6d8fd429d00ca8d3d01e43fd3d1f8f"}, + {file = "flatbuffers-23.1.4.tar.gz", hash = "sha256:04d2141ea38866600beda17ffebf739b23f4f500cc22606076cc83079155106d"}, ] frozenlist = [ {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"}, @@ -3602,7 +3624,7 @@ frozenlist = [ {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"}, ] future = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, + {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, ] gast = [ {file = "gast-0.4.0-py3-none-any.whl", hash = "sha256:b7adcdd5adbebf1adf17378da5ba3f543684dbec47b1cda1f3997e573cd542c4"}, @@ -3625,12 +3647,12 @@ google-api-core = [ {file = "google_api_core-2.11.0-py3-none-any.whl", hash = "sha256:ce222e27b0de0d7bc63eb043b956996d6dccab14cc3b690aaea91c9cc99dc16e"}, ] google-api-python-client = [ - {file = "google-api-python-client-2.70.0.tar.gz", hash = "sha256:262de094d5a30d337f59e66581019fed45b698c078397ac48dd323c0968236e7"}, - {file = "google_api_python_client-2.70.0-py2.py3-none-any.whl", hash = "sha256:67da78956f2bf4b763305cd791aeab250878c1f88f1422aaba4682a608b8e5a4"}, + {file = "google-api-python-client-2.72.0.tar.gz", hash = "sha256:0ddf4a44256d4516635578b93a9ac0dfba7d8bd357cd896e68ef9c549a840b2f"}, + {file = "google_api_python_client-2.72.0-py2.py3-none-any.whl", hash = "sha256:271b49fc9ce6c133620169e6ca4a92682b92c288444e6e00a51f78072b42169c"}, ] google-auth = [ - {file = "google-auth-2.15.0.tar.gz", hash = "sha256:72f12a6cfc968d754d7bdab369c5c5c16032106e52d32c6dfd8484e4c01a6d1f"}, - {file = "google_auth-2.15.0-py2.py3-none-any.whl", hash = "sha256:6897b93556d8d807ad70701bb89f000183aea366ca7ed94680828b37437a4994"}, + {file = "google-auth-2.16.0.tar.gz", hash = "sha256:ed7057a101af1146f0554a769930ac9de506aeca4fd5af6543ebe791851a9fbd"}, + {file = "google_auth-2.16.0-py2.py3-none-any.whl", hash = "sha256:5045648c821fb72384cdc0e82cc326df195f113a33049d9b62b74589243d2acc"}, ] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, @@ -3646,8 +3668,8 @@ google-pasta = [ {file = "google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed"}, ] googleapis-common-protos = [ - {file = "googleapis-common-protos-1.57.0.tar.gz", hash = "sha256:27a849d6205838fb6cc3c1c21cb9800707a661bb21c6ce7fb13e99eb1f8a0c46"}, - {file = "googleapis_common_protos-1.57.0-py2.py3-none-any.whl", hash = "sha256:a9f4a1d7f6d9809657b7f1316a1aa527f6664891531bcfcc13b6696e685f443c"}, + {file = "googleapis-common-protos-1.58.0.tar.gz", hash = "sha256:c727251ec025947d545184ba17e3578840fc3a24a0516a020479edab660457df"}, + {file = "googleapis_common_protos-1.58.0-py2.py3-none-any.whl", hash = "sha256:ca3befcd4580dab6ad49356b46bf165bb68ff4b32389f028f1abd7c10ab9519a"}, ] graphviz = [ {file = "graphviz-0.20.1-py3-none-any.whl", hash = "sha256:587c58a223b51611c0cf461132da386edd896a029524ca61a1462b880bf97977"}, @@ -3798,20 +3820,20 @@ idna = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] imageio = [ - {file = "imageio-2.23.0-py3-none-any.whl", hash = "sha256:3f937396c2f341a7d7600a99cd14727cc90002f850fd136cf65fad79c2ff44a0"}, - {file = "imageio-2.23.0.tar.gz", hash = "sha256:cb635709765e527c94890b4fbb6870e59213fe182a1c8086d167eb3626073cbd"}, + {file = "imageio-2.24.0-py3-none-any.whl", hash = "sha256:c4ccd0293a1aeb566c7fa04260d51897be064b8fb287a77548ce42050ec06d7a"}, + {file = "imageio-2.24.0.tar.gz", hash = "sha256:f240f8229f4f329a1546281194b52da5d6694141a524668fed3f81b0d07782fa"}, ] importlib-metadata = [ {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, ] importlib-resources = [ - {file = "importlib_resources-5.10.1-py3-none-any.whl", hash = "sha256:c09b067d82e72c66f4f8eb12332f5efbebc9b007c0b6c40818108c9870adc363"}, - {file = "importlib_resources-5.10.1.tar.gz", hash = "sha256:32bb095bda29741f6ef0e5278c42df98d135391bee5f932841efc0041f748dc3"}, + {file = "importlib_resources-5.10.2-py3-none-any.whl", hash = "sha256:7d543798b0beca10b6a01ac7cafda9f822c54db9e8376a6bf57e0cbd74d486b6"}, + {file = "importlib_resources-5.10.2.tar.gz", hash = "sha256:e4a96c8cc0339647ff9a5e0550d9f276fc5a01ffa276012b58ec108cfd7b8484"}, ] iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] ipfshttpclient = [ {file = "ipfshttpclient-0.8.0a2-py3-none-any.whl", hash = "sha256:ce6bac0e3963c4ced74d7eb6978125362bb05bbe219088ca48f369ce14d3cc39"}, @@ -3907,37 +3929,52 @@ kiwisolver = [ {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.8.0.tar.gz", hash = "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156"}, - {file = "lazy_object_proxy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe"}, - {file = "lazy_object_proxy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25"}, - {file = "lazy_object_proxy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b"}, - {file = "lazy_object_proxy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7"}, - {file = "lazy_object_proxy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e"}, - {file = "lazy_object_proxy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d"}, - {file = "lazy_object_proxy-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c"}, - {file = "lazy_object_proxy-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd"}, - {file = "lazy_object_proxy-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858"}, - {file = "lazy_object_proxy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada"}, - {file = "lazy_object_proxy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f"}, - {file = "lazy_object_proxy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c"}, - {file = "lazy_object_proxy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288"}, - {file = "lazy_object_proxy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f"}, - {file = "lazy_object_proxy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0"}, - {file = "lazy_object_proxy-1.8.0-pp37-pypy37_pp73-any.whl", hash = "sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891"}, - {file = "lazy_object_proxy-1.8.0-pp38-pypy38_pp73-any.whl", hash = "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec"}, - {file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"}, + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] libclang = [ - {file = "libclang-14.0.6-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:8791cf3c3b087c373a6d61e9199da7a541da922c9ddcfed1122090586b996d6e"}, - {file = "libclang-14.0.6-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b06fc76bd1e67c8b04b5719bf2ac5d6a323b289b245dfa9e468561d99538188"}, - {file = "libclang-14.0.6-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:e429853939423f276a25140b0b702442d7da9a09e001c05e48df888336947614"}, - {file = "libclang-14.0.6-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:206d2789e4450a37d054e63b70451a6fc1873466397443fa13de2b3d4adb2796"}, - {file = "libclang-14.0.6-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:e2add1703129b2abe066fb1890afa880870a89fd6ab4ec5d2a7a8dc8d271677e"}, - {file = "libclang-14.0.6-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:5dd3c6fca1b007d308a4114afa8e4e9d32f32b2572520701d45fcc626ac5cd6c"}, - {file = "libclang-14.0.6-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cfb0e892ebb5dff6bd498ab5778adb8581f26a00fd8347b3c76c989fe2fd04f7"}, - {file = "libclang-14.0.6-py2.py3-none-win_amd64.whl", hash = "sha256:ea03c12675151837660cdd5dce65bd89320896ac3421efef43a36678f113ce95"}, - {file = "libclang-14.0.6-py2.py3-none-win_arm64.whl", hash = "sha256:2e4303e04517fcd11173cb2e51a7070eed71e16ef45d4e26a82c5e881cac3d27"}, - {file = "libclang-14.0.6.tar.gz", hash = "sha256:9052a8284d8846984f6fa826b1d7460a66d3b23a486d782633b42b6e3b418789"}, + {file = "libclang-15.0.6.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:8621795e07b87e17fc7aac9f071bc7fe6b52ed6110c0a96a9975d8113c8c2527"}, + {file = "libclang-15.0.6.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:69b01a23ab543908a661532595daa23cf88bd96d80e41f58ba0eaa6a378fe0d8"}, + {file = "libclang-15.0.6.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:4a5188184b937132c198ee9de9a8a2316d5fdd1a825398d5ad1a8f5e06f9b40e"}, + {file = "libclang-15.0.6.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:f7ffa02ac5e586cfffde039dcccc439d88d0feac7d77bf9426d9ba7543d16545"}, + {file = "libclang-15.0.6.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:aaebb6aa1db73bac3a0ac41e57ef78743079eb68728adbf7e80ee917ae171529"}, + {file = "libclang-15.0.6.1-py2.py3-none-win_amd64.whl", hash = "sha256:85afb47630d2070e74b886040ceea1846097ca53cc88d0f1d7751d0f49220028"}, + {file = "libclang-15.0.6.1-py2.py3-none-win_arm64.whl", hash = "sha256:687d8549c110c700fece58dd87727421d0710fdd111aa7eecb01faf8e3f50d4e"}, + {file = "libclang-15.0.6.1.tar.gz", hash = "sha256:a1a8fe038af2962c787c5bac81bfa4b82bb8e279e61e70cc934c10f6e20c73ec"}, ] liccheck = [ {file = "liccheck-0.7.2-py2.py3-none-any.whl", hash = "sha256:a50d212b943d119f61d822080e0b7bcefbae4c3b7cc7b54b47b465c191bfc8aa"}, @@ -4087,8 +4124,8 @@ mkdocs = [ {file = "mkdocs-1.4.2.tar.gz", hash = "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5"}, ] mkdocs-material = [ - {file = "mkdocs_material-8.5.11-py3-none-any.whl", hash = "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e"}, - {file = "mkdocs_material-8.5.11.tar.gz", hash = "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7"}, + {file = "mkdocs_material-9.0.5-py3-none-any.whl", hash = "sha256:53194bf8ae7dfb527fef2892a6ee291d3efc7b57d010b04dbb818b4ee88074a5"}, + {file = "mkdocs_material-9.0.5.tar.gz", hash = "sha256:bbfed71788223b4c548a6e637cb7a9ee5b6ad6593c6d5b04e57c9c4d2c39d76b"}, ] mkdocs-material-extensions = [ {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, @@ -4100,80 +4137,80 @@ multiaddr = [ {file = "multiaddr-0.0.9.tar.gz", hash = "sha256:30b2695189edc3d5b90f1c303abb8f02d963a3a4edf2e7178b975eb417ab0ecf"}, ] multidict = [ - {file = "multidict-6.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:73009ea04205966d47e16d98686ac5c438af23a1bb30b48a2c5da3423ec9ce37"}, - {file = "multidict-6.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b92a9f3ab904397a33b193000dc4de7318ea175c4c460a1e154c415f9008e3d"}, - {file = "multidict-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:578bfcb16f4b8675ef71b960c00f174b0426e0eeb796bab6737389d8288eb827"}, - {file = "multidict-6.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1650ea41c408755da5eed52ac6ccbc8938ccc3e698d81e6f6a1be02ff2a0945"}, - {file = "multidict-6.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d52442e7c951e4c9ee591d6047706e66923d248d83958bbf99b8b19515fffaef"}, - {file = "multidict-6.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad7d66422b9cc51125509229693d27e18c08f2dea3ac9de408d821932b1b3759"}, - {file = "multidict-6.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cd14e61f0da2a2cfb9fe05bfced2a1ed7063ce46a7a8cd473be4973de9a7f91"}, - {file = "multidict-6.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:190626ced82d4cc567a09e7346340d380154a493bac6905e0095d8158cdf1e38"}, - {file = "multidict-6.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:791458a1f7d1b4ab3bd9e93e0dcd1d59ef7ee9aa051dcd1ea030e62e49b923fd"}, - {file = "multidict-6.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b46e79a9f4db53897d17bc64a39d1c7c2be3e3d4f8dba6d6730a2b13ddf0f986"}, - {file = "multidict-6.0.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e4a095e18847c12ec20e55326ab8782d9c2d599400a3a2f174fab4796875d0e2"}, - {file = "multidict-6.0.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fb6c3dc3d65014d2c782f5acf0b3ba14e639c6c33d3ed8932ead76b9080b3544"}, - {file = "multidict-6.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3541882266247c7cd3dba78d6ef28dbe704774df60c9e4231edaa4493522e614"}, - {file = "multidict-6.0.3-cp310-cp310-win32.whl", hash = "sha256:67090b17a0a5be5704fd109f231ee73cefb1b3802d41288d6378b5df46ae89ba"}, - {file = "multidict-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:36df958b15639e40472adaa4f0c2c7828fe680f894a6b48c4ce229f59a6a798b"}, - {file = "multidict-6.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b51969503709415a35754954c2763f536a70b8bf7360322b2edb0c0a44391f6"}, - {file = "multidict-6.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24e8d513bfcaadc1f8b0ebece3ff50961951c54b07d5a775008a882966102418"}, - {file = "multidict-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d325d61cac602976a5d47b19eaa7d04e3daf4efce2164c630219885087234102"}, - {file = "multidict-6.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbbe17f8a7211b623502d2bf41022a51da3025142401417c765bf9a56fed4c"}, - {file = "multidict-6.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fb3fe591956d8841882c463f934c9f7485cfd5f763a08c0d467b513dc18ef89"}, - {file = "multidict-6.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1925f78a543b94c3d46274c66a366fee8a263747060220ed0188e5f3eeea1c0"}, - {file = "multidict-6.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e1ce0b187c4e93112304dcde2aa18922fdbe8fb4f13d8aa72a5657bce0563a"}, - {file = "multidict-6.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e07c24018986fb00d6e7eafca8fcd6e05095649e17fcf0e33a592caaa62a78b9"}, - {file = "multidict-6.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:114a4ab3e5cfbc56c4b6697686ecb92376c7e8c56893ef20547921552f8bdf57"}, - {file = "multidict-6.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4ccf55f28066b4f08666764a957c2b7c241c7547b0921d69c7ceab5f74fe1a45"}, - {file = "multidict-6.0.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:9d359b0a962e052b713647ac1f13eabf2263167b149ed1e27d5c579f5c8c7d2c"}, - {file = "multidict-6.0.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:df7b4cee3ff31b3335aba602f8d70dbc641e5b7164b1e9565570c9d3c536a438"}, - {file = "multidict-6.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ee9b1cae9a6c5d023e5a150f6f6b9dbb3c3bbc7887d6ee07d4c0ecb49a473734"}, - {file = "multidict-6.0.3-cp311-cp311-win32.whl", hash = "sha256:960ce1b790952916e682093788696ef7e33ac6a97482f9b983abdc293091b531"}, - {file = "multidict-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:2b66d61966b12e6bba500e5cbb2c721a35e119c30ee02495c5629bd0e91eea30"}, - {file = "multidict-6.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:526f8397fc124674b8f39748680a0ff673bd6a715fecb4866716d36e380f015f"}, - {file = "multidict-6.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d5129a937af4e3c4a1d6c139f4051b7d17d43276cefdd8d442a7031f7eef2"}, - {file = "multidict-6.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38d394814b39be1c36ac709006d39d50d72a884f9551acd9c8cc1ffae3fc8c4e"}, - {file = "multidict-6.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99341ca1f1db9e7f47914cb2461305665a662383765ced6f843712564766956d"}, - {file = "multidict-6.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5790cc603456b6dcf8a9a4765f666895a6afddc88b3d3ba7b53dea2b6e23116"}, - {file = "multidict-6.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce8e51774eb03844588d3c279adb94efcd0edeccd2f97516623292445bcc01f9"}, - {file = "multidict-6.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:baa96a3418e27d723064854143b2f414a422c84cc87285a71558722049bebc5a"}, - {file = "multidict-6.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cb4a08f0aaaa869f189ffea0e17b86ad0237b51116d494da15ef7991ee6ad2d7"}, - {file = "multidict-6.0.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:62db44727d0befea68e8ad2881bb87a9cfb6b87d45dd78609009627167f37b69"}, - {file = "multidict-6.0.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:4cc5c8cd205a9810d16a5cd428cd81bac554ad1477cb87f4ad722b10992e794d"}, - {file = "multidict-6.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f76109387e1ec8d8e2137c94c437b89fe002f29e0881aae8ae45529bdff92000"}, - {file = "multidict-6.0.3-cp37-cp37m-win32.whl", hash = "sha256:f8a728511c977df6f3d8af388fcb157e49f11db4a6637dd60131b8b6e40b0253"}, - {file = "multidict-6.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c2a1168e5aa7c72499fb03c850e0f03f624fa4a5c8d2e215c518d0a73872eb64"}, - {file = "multidict-6.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eddf604a3de2ace3d9a4e4d491be7562a1ac095a0a1c95a9ec5781ef0273ef11"}, - {file = "multidict-6.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d09daf5c6ce7fc6ed444c9339bbde5ea84e2534d1ca1cd37b60f365c77f00dea"}, - {file = "multidict-6.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:12e0d396faa6dc55ff5379eee54d1df3b508243ff15bfc8295a6ec7a4483a335"}, - {file = "multidict-6.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70740c2bc9ab1c99f7cdcb104f27d16c63860c56d51c5bf0ef82fc1d892a2131"}, - {file = "multidict-6.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e322c94596054352f5a02771eec71563c018b15699b961aba14d6dd943367022"}, - {file = "multidict-6.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4159fc1ec9ede8ab93382e0d6ba9b1b3d23c72da39a834db7a116986605c7ab4"}, - {file = "multidict-6.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47defc0218682281a52fb1f6346ebb8b68b17538163a89ea24dfe4da37a8a9a3"}, - {file = "multidict-6.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f9511e48bde6b995825e8d35e434fc96296cf07a25f4aae24ff9162be7eaa46"}, - {file = "multidict-6.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0bce9f7c30e7e3a9e683f670314c0144e8d34be6b7019e40604763bd278d84f"}, - {file = "multidict-6.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:01b456046a05ff7cceefb0e1d2a9d32f05efcb1c7e0d152446304e11557639ce"}, - {file = "multidict-6.0.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8230a39bae6c2e8a09e4da6bace5064693b00590a4a213e38f9a9366da10e7dd"}, - {file = "multidict-6.0.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:445c0851a1cbc1f2ec3b40bc22f9c4a235edb3c9a0906122a9df6ea8d51f886c"}, - {file = "multidict-6.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9aac6881454a750554ed4b280a839dcf9e2133a9d12ab4d417d673fb102289b7"}, - {file = "multidict-6.0.3-cp38-cp38-win32.whl", hash = "sha256:81c3d597591b0940e04949e4e4f79359b2d2e542a686ba0da5e25de33fec13e0"}, - {file = "multidict-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:dc4cfef5d899f5f1a15f3d2ac49f71107a01a5a2745b4dd53fa0cede1419385a"}, - {file = "multidict-6.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d408172519049e36fb6d29672f060dc8461fc7174eba9883c7026041ef9bfb38"}, - {file = "multidict-6.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e068dfeadbce63072b2d8096486713d04db4946aad0a0f849bd4fc300799d0d3"}, - {file = "multidict-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8b817d4ed68fd568ec5e45dd75ddf30cc72a47a6b41b74d5bb211374c296f5e"}, - {file = "multidict-6.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf5d19e12eff855aa198259c0b02fd3f5d07e1291fbd20279c37b3b0e6c9852"}, - {file = "multidict-6.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5a811aab1b4aea0b4be669363c19847a8c547510f0e18fb632956369fdbdf67"}, - {file = "multidict-6.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cfda34b7cb99eacada2072e0f69c0ad3285cb6f8e480b11f2b6d6c1c6f92718"}, - {file = "multidict-6.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beeca903e4270b4afcd114f371a9602240dc143f9e944edfea00f8d4ad56c40d"}, - {file = "multidict-6.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd5771e8ea325f85cbb361ddbdeb9ae424a68e5dfb6eea786afdcd22e68a7d5d"}, - {file = "multidict-6.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9dbab2a7e9c073bc9538824a01f5ed689194db7f55f2b8102766873e906a6c1a"}, - {file = "multidict-6.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2c0957b3e8c66c10d27272709a5299ab3670a0f187c9428f3b90d267119aedb"}, - {file = "multidict-6.0.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:94cbe5535ef150546b8321aebea22862a3284da51e7b55f6f95b7d73e96d90ee"}, - {file = "multidict-6.0.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0e798b072cf2aab9daceb43d97c9c527a0c7593e67a7846ad4cc6051de1e303"}, - {file = "multidict-6.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a27b029caa3b555a4f3da54bc1e718eb55fcf1a11fda8bf0132147b476cf4c08"}, - {file = "multidict-6.0.3-cp39-cp39-win32.whl", hash = "sha256:018c8e3be7f161a12b3e41741b6721f9baeb2210f4ab25a6359b7d76c1017dce"}, - {file = "multidict-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:5e58ec0375803526d395f6f7e730ecc45d06e15f68f7b9cdbf644a2918324e51"}, - {file = "multidict-6.0.3.tar.gz", hash = "sha256:2523a29006c034687eccd3ee70093a697129a3ffe8732535d3b2df6a4ecc279d"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, + {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, + {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, + {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, + {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, + {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, + {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, + {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, + {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, + {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, + {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, + {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, + {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] mypy = [ {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, @@ -4210,42 +4247,42 @@ netaddr = [ {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"}, ] networkx = [ - {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"}, - {file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"}, + {file = "networkx-3.0-py3-none-any.whl", hash = "sha256:58058d66b1818043527244fab9d41a51fcd7dcc271748015f3c181b8a90c8e2e"}, + {file = "networkx-3.0.tar.gz", hash = "sha256:9a9992345353618ae98339c2b63d8201c381c2944f38a2ab49cb45a4c667e412"}, ] nr-util = [ {file = "nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb"}, {file = "nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4"}, ] numpy = [ - {file = "numpy-1.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6e73a1f4f5b74a42abb55bc2b3d869f1b38cbc8776da5f8b66bf110284f7a437"}, - {file = "numpy-1.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9387c7d6d50e8f8c31e7bfc034241e9c6f4b3eb5db8d118d6487047b922f82af"}, - {file = "numpy-1.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ad6a024a32ee61d18f5b402cd02e9c0e22c0fb9dc23751991b3a16d209d972e"}, - {file = "numpy-1.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73cf2c5b5a07450f20a0c8e04d9955491970177dce8df8d6903bf253e53268e0"}, - {file = "numpy-1.24.0-cp310-cp310-win32.whl", hash = "sha256:cec79ff3984b2d1d103183fc4a3361f5b55bbb66cb395cbf5a920a4bb1fd588d"}, - {file = "numpy-1.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:4f5e78b8b710cd7cd1a8145994cfffc6ddd5911669a437777d8cedfce6c83a98"}, - {file = "numpy-1.24.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4445f472b246cad6514cc09fbb5ecb7aab09ca2acc3c16f29f8dca6c468af501"}, - {file = "numpy-1.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ec3e5e8172a0a6a4f3c2e7423d4a8434c41349141b04744b11a90e017a95bad5"}, - {file = "numpy-1.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9168790149f917ad8e3cf5047b353fefef753bd50b07c547da0bdf30bc15d91"}, - {file = "numpy-1.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada6c1e9608ceadaf7020e1deea508b73ace85560a16f51bef26aecb93626a72"}, - {file = "numpy-1.24.0-cp311-cp311-win32.whl", hash = "sha256:f3c4a9a9f92734a4728ddbd331e0124eabbc968a0359a506e8e74a9b0d2d419b"}, - {file = "numpy-1.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:90075ef2c6ac6397d0035bcd8b298b26e481a7035f7a3f382c047eb9c3414db0"}, - {file = "numpy-1.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0885d9a7666cafe5f9876c57bfee34226e2b2847bfb94c9505e18d81011e5401"}, - {file = "numpy-1.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e63d2157f9fc98cc178870db83b0e0c85acdadd598b134b00ebec9e0db57a01f"}, - {file = "numpy-1.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8960f72997e56781eb1c2ea256a70124f92a543b384f89e5fb3503a308b1d3"}, - {file = "numpy-1.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f8e0df2ecc1928ef7256f18e309c9d6229b08b5be859163f5caa59c93d53646"}, - {file = "numpy-1.24.0-cp38-cp38-win32.whl", hash = "sha256:fe44e925c68fb5e8db1334bf30ac1a1b6b963b932a19cf41d2e899cf02f36aab"}, - {file = "numpy-1.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:d7f223554aba7280e6057727333ed357b71b7da7422d02ff5e91b857888c25d1"}, - {file = "numpy-1.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ab11f6a7602cf8ea4c093e091938207de3068c5693a0520168ecf4395750f7ea"}, - {file = "numpy-1.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12bba5561d8118981f2f1ff069ecae200c05d7b6c78a5cdac0911f74bc71cbd1"}, - {file = "numpy-1.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9af91f794d2d3007d91d749ebc955302889261db514eb24caef30e03e8ec1e41"}, - {file = "numpy-1.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b1ddfac6a82d4f3c8e99436c90b9c2c68c0bb14658d1684cdd00f05fab241f5"}, - {file = "numpy-1.24.0-cp39-cp39-win32.whl", hash = "sha256:ac4fe68f1a5a18136acebd4eff91aab8bed00d1ef2fdb34b5d9192297ffbbdfc"}, - {file = "numpy-1.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:667b5b1f6a352419e340f6475ef9930348ae5cb7fca15f2cc3afcb530823715e"}, - {file = "numpy-1.24.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4d01f7832fa319a36fd75ba10ea4027c9338ede875792f7bf617f4b45056fc3a"}, - {file = "numpy-1.24.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb0490f0a880700a6cc4d000384baf19c1f4df59fff158d9482d4dbbca2b239"}, - {file = "numpy-1.24.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0104d8adaa3a4cc60c2777cab5196593bf8a7f416eda133be1f3803dd0838886"}, - {file = "numpy-1.24.0.tar.gz", hash = "sha256:c4ab7c9711fe6b235e86487ca74c1b092a6dd59a3cb45b63241ea0a148501853"}, + {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, + {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, + {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, + {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, + {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, + {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, + {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, + {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, + {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, + {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, + {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, ] oauthlib = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, @@ -4276,83 +4313,85 @@ pathspec = [ {file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"}, ] pbr = [ - {file = "pbr-5.11.0-py2.py3-none-any.whl", hash = "sha256:db2317ff07c84c4c63648c9064a79fe9d9f5c7ce85a9099d4b6258b3db83225a"}, - {file = "pbr-5.11.0.tar.gz", hash = "sha256:b97bc6695b2aff02144133c2e7399d5885223d42b7912ffaec2ca3898e673bfe"}, + {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, + {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, ] pexpect = [ {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, ] pillow = [ - {file = "Pillow-9.3.0-1-cp37-cp37m-win32.whl", hash = "sha256:e6ea6b856a74d560d9326c0f5895ef8050126acfdc7ca08ad703eb0081e82b74"}, - {file = "Pillow-9.3.0-1-cp37-cp37m-win_amd64.whl", hash = "sha256:32a44128c4bdca7f31de5be641187367fe2a450ad83b833ef78910397db491aa"}, - {file = "Pillow-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2"}, - {file = "Pillow-9.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c"}, - {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de"}, - {file = "Pillow-9.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7"}, - {file = "Pillow-9.3.0-cp310-cp310-win32.whl", hash = "sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91"}, - {file = "Pillow-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b"}, - {file = "Pillow-9.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20"}, - {file = "Pillow-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812"}, - {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c"}, - {file = "Pillow-9.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11"}, - {file = "Pillow-9.3.0-cp311-cp311-win32.whl", hash = "sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c"}, - {file = "Pillow-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef"}, - {file = "Pillow-9.3.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b"}, - {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee"}, - {file = "Pillow-9.3.0-cp37-cp37m-win32.whl", hash = "sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29"}, - {file = "Pillow-9.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4"}, - {file = "Pillow-9.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4"}, - {file = "Pillow-9.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07"}, - {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636"}, - {file = "Pillow-9.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32"}, - {file = "Pillow-9.3.0-cp38-cp38-win32.whl", hash = "sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"}, - {file = "Pillow-9.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc"}, - {file = "Pillow-9.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad"}, - {file = "Pillow-9.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd"}, - {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c"}, - {file = "Pillow-9.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448"}, - {file = "Pillow-9.3.0-cp39-cp39-win32.whl", hash = "sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48"}, - {file = "Pillow-9.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e"}, - {file = "Pillow-9.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65"}, - {file = "Pillow-9.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8"}, - {file = "Pillow-9.3.0.tar.gz", hash = "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f"}, + {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, + {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, + {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, + {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, + {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, + {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, + {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, + {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, + {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, + {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, + {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, + {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, + {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, + {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, ] pkgutil-resolve-name = [ {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, ] platformdirs = [ - {file = "platformdirs-2.6.0-py3-none-any.whl", hash = "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca"}, - {file = "platformdirs-2.6.0.tar.gz", hash = "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"}, + {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, + {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, @@ -4522,8 +4561,8 @@ pydoc-markdown = [ {file = "pydoc_markdown-4.6.4.tar.gz", hash = "sha256:c3feab1240d397e38b132340dd2310b58a8538eaea78c939e1ca4df9ce098561"}, ] pydocstyle = [ - {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, - {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"}, + {file = "pydocstyle-6.2.3-py3-none-any.whl", hash = "sha256:a04ed1e6fe0be0970eddbb1681a7ab59b11eb92729fdb4b9b24f0eb11a25629e"}, + {file = "pydocstyle-6.2.3.tar.gz", hash = "sha256:d867acad25e48471f2ad8a40ef9813125e954ad675202245ca836cb6e28b2297"}, ] pyflakes = [ {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, @@ -4534,16 +4573,16 @@ pyglet = [ {file = "pyglet-1.5.0.zip", hash = "sha256:6ea918985feddfa9bf0fcc01ffe9ff5849e7b6e832d9b2e03b9d2a36369cb6ee"}, ] pygments = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, + {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, + {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, ] pylint = [ {file = "pylint-2.15.5-py3-none-any.whl", hash = "sha256:c2108037eb074334d9e874dc3c783752cc03d0796c88c9a9af282d0f161a1004"}, {file = "pylint-2.15.5.tar.gz", hash = "sha256:3b120505e5af1d06a5ad76b55d8660d44bf0f2fc3c59c2bdd94e39188ee3a4df"}, ] pymdown-extensions = [ - {file = "pymdown_extensions-9.9-py3-none-any.whl", hash = "sha256:ac698c15265680db5eb13cd4342abfcde2079ac01e5486028f47a1b41547b859"}, - {file = "pymdown_extensions-9.9.tar.gz", hash = "sha256:0f8fb7b74a37a61cc34e90b2c91865458b713ec774894ffad64353a5fce85cfc"}, + {file = "pymdown_extensions-9.9.1-py3-none-any.whl", hash = "sha256:8a8973933ab45b6fe8f5f8da1de25766356b1f91dee107bf4a34efd158dc340b"}, + {file = "pymdown_extensions-9.9.1.tar.gz", hash = "sha256:abed29926960bbb3b40f5ed5fa6375e29724d4e3cb86ced7c2bbd37ead1afeea"}, ] pymultihash = [ {file = "pymultihash-0.8.2-py3-none-any.whl", hash = "sha256:f7fa840b24bd6acbd6b073fcd330f10e15619387297babf1dd13ca4dae6e8209"}, @@ -4570,36 +4609,41 @@ pypiwin32 = [ {file = "pypiwin32-223.tar.gz", hash = "sha256:71be40c1fbd28594214ecaecb58e7aa8b708eabfa0125c8a109ebd51edbd776a"}, ] pyrsistent = [ - {file = "pyrsistent-0.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6982b5a0237e1b7d876b60265564648a69b14017f3b5f908c5be2de3f9abb7a"}, - {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:187d5730b0507d9285a96fca9716310d572e5464cadd19f22b63a6976254d77a"}, - {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:055ab45d5911d7cae397dc418808d8802fb95262751872c841c170b0dbf51eed"}, - {file = "pyrsistent-0.19.2-cp310-cp310-win32.whl", hash = "sha256:456cb30ca8bff00596519f2c53e42c245c09e1a4543945703acd4312949bfd41"}, - {file = "pyrsistent-0.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:b39725209e06759217d1ac5fcdb510e98670af9e37223985f330b611f62e7425"}, - {file = "pyrsistent-0.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aede922a488861de0ad00c7630a6e2d57e8023e4be72d9d7147a9fcd2d30712"}, - {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879b4c2f4d41585c42df4d7654ddffff1239dc4065bc88b745f0341828b83e78"}, - {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43bec251bbd10e3cb58ced80609c5c1eb238da9ca78b964aea410fb820d00d6"}, - {file = "pyrsistent-0.19.2-cp37-cp37m-win32.whl", hash = "sha256:d690b18ac4b3e3cab73b0b7aa7dbe65978a172ff94970ff98d82f2031f8971c2"}, - {file = "pyrsistent-0.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3ba4134a3ff0fc7ad225b6b457d1309f4698108fb6b35532d015dca8f5abed73"}, - {file = "pyrsistent-0.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a178209e2df710e3f142cbd05313ba0c5ebed0a55d78d9945ac7a4e09d923308"}, - {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e371b844cec09d8dc424d940e54bba8f67a03ebea20ff7b7b0d56f526c71d584"}, - {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111156137b2e71f3a9936baf27cb322e8024dac3dc54ec7fb9f0bcf3249e68bb"}, - {file = "pyrsistent-0.19.2-cp38-cp38-win32.whl", hash = "sha256:e5d8f84d81e3729c3b506657dddfe46e8ba9c330bf1858ee33108f8bb2adb38a"}, - {file = "pyrsistent-0.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:9cd3e9978d12b5d99cbdc727a3022da0430ad007dacf33d0bf554b96427f33ab"}, - {file = "pyrsistent-0.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f1258f4e6c42ad0b20f9cfcc3ada5bd6b83374516cd01c0960e3cb75fdca6770"}, - {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21455e2b16000440e896ab99e8304617151981ed40c29e9507ef1c2e4314ee95"}, - {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd880614c6237243ff53a0539f1cb26987a6dc8ac6e66e0c5a40617296a045e"}, - {file = "pyrsistent-0.19.2-cp39-cp39-win32.whl", hash = "sha256:71d332b0320642b3261e9fee47ab9e65872c2bd90260e5d225dabeed93cbd42b"}, - {file = "pyrsistent-0.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:dec3eac7549869365fe263831f576c8457f6c833937c68542d08fde73457d291"}, - {file = "pyrsistent-0.19.2-py3-none-any.whl", hash = "sha256:ea6b79a02a28550c98b6ca9c35b9f492beaa54d7c5c9e9949555893c8a9234d0"}, - {file = "pyrsistent-0.19.2.tar.gz", hash = "sha256:bfa0351be89c9fcbcb8c9879b826f4353be10f58f8a677efab0c017bf7137ec2"}, + {file = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"}, + {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"}, + {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"}, + {file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"}, + {file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"}, + {file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"}, + {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"}, + {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"}, + {file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"}, + {file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"}, + {file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"}, + {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"}, + {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"}, + {file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"}, + {file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"}, + {file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"}, + {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"}, + {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"}, + {file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"}, + {file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"}, + {file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"}, + {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"}, ] pyserial = [ {file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"}, {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"}, ] pytest = [ - {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, - {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, @@ -4708,9 +4752,99 @@ pyyaml-env-tag = [ quantile-python = [ {file = "quantile-python-1.1.tar.gz", hash = "sha256:558629e88c497ef3b9b1081349c1ae6a61b53590e317724298ff54c674db7969"}, ] +regex = [ + {file = "regex-2022.10.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8ff454ef0bb061e37df03557afda9d785c905dab15584860f982e88be73015f"}, + {file = "regex-2022.10.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1eba476b1b242620c266edf6325b443a2e22b633217a9835a52d8da2b5c051f9"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0e5af9a9effb88535a472e19169e09ce750c3d442fb222254a276d77808620b"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d03fe67b2325cb3f09be029fd5da8df9e6974f0cde2c2ac6a79d2634e791dd57"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9d0b68ac1743964755ae2d89772c7e6fb0118acd4d0b7464eaf3921c6b49dd4"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a45b6514861916c429e6059a55cf7db74670eaed2052a648e3e4d04f070e001"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b0886885f7323beea6f552c28bff62cbe0983b9fbb94126531693ea6c5ebb90"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5aefb84a301327ad115e9d346c8e2760009131d9d4b4c6b213648d02e2abe144"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:702d8fc6f25bbf412ee706bd73019da5e44a8400861dfff7ff31eb5b4a1276dc"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a3c1ebd4ed8e76e886507c9eddb1a891673686c813adf889b864a17fafcf6d66"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:50921c140561d3db2ab9f5b11c5184846cde686bb5a9dc64cae442926e86f3af"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7db345956ecce0c99b97b042b4ca7326feeec6b75facd8390af73b18e2650ffc"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:763b64853b0a8f4f9cfb41a76a4a85a9bcda7fdda5cb057016e7706fde928e66"}, + {file = "regex-2022.10.31-cp310-cp310-win32.whl", hash = "sha256:44136355e2f5e06bf6b23d337a75386371ba742ffa771440b85bed367c1318d1"}, + {file = "regex-2022.10.31-cp310-cp310-win_amd64.whl", hash = "sha256:bfff48c7bd23c6e2aec6454aaf6edc44444b229e94743b34bdcdda2e35126cf5"}, + {file = "regex-2022.10.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b4b1fe58cd102d75ef0552cf17242705ce0759f9695334a56644ad2d83903fe"}, + {file = "regex-2022.10.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:542e3e306d1669b25936b64917285cdffcd4f5c6f0247636fec037187bd93542"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c27cc1e4b197092e50ddbf0118c788d9977f3f8f35bfbbd3e76c1846a3443df7"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8e38472739028e5f2c3a4aded0ab7eadc447f0d84f310c7a8bb697ec417229e"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76c598ca73ec73a2f568e2a72ba46c3b6c8690ad9a07092b18e48ceb936e9f0c"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28d3309ebd6d6b2cf82969b5179bed5fefe6142c70f354ece94324fa11bf6a1"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9af69f6746120998cd9c355e9c3c6aec7dff70d47247188feb4f829502be8ab4"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a5f9505efd574d1e5b4a76ac9dd92a12acb2b309551e9aa874c13c11caefbe4f"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5ff525698de226c0ca743bfa71fc6b378cda2ddcf0d22d7c37b1cc925c9650a5"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe7fda2fe7c8890d454f2cbc91d6c01baf206fbc96d89a80241a02985118c0c"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2cdc55ca07b4e70dda898d2ab7150ecf17c990076d3acd7a5f3b25cb23a69f1c"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:44a6c2f6374e0033873e9ed577a54a3602b4f609867794c1a3ebba65e4c93ee7"}, + {file = "regex-2022.10.31-cp311-cp311-win32.whl", hash = "sha256:d8716f82502997b3d0895d1c64c3b834181b1eaca28f3f6336a71777e437c2af"}, + {file = "regex-2022.10.31-cp311-cp311-win_amd64.whl", hash = "sha256:61edbca89aa3f5ef7ecac8c23d975fe7261c12665f1d90a6b1af527bba86ce61"}, + {file = "regex-2022.10.31-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a069c8483466806ab94ea9068c34b200b8bfc66b6762f45a831c4baaa9e8cdd"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d26166acf62f731f50bdd885b04b38828436d74e8e362bfcb8df221d868b5d9b"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac741bf78b9bb432e2d314439275235f41656e189856b11fb4e774d9f7246d81"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75f591b2055523fc02a4bbe598aa867df9e953255f0b7f7715d2a36a9c30065c"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bddd61d2a3261f025ad0f9ee2586988c6a00c780a2fb0a92cea2aa702c54"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef4163770525257876f10e8ece1cf25b71468316f61451ded1a6f44273eedeb5"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7b280948d00bd3973c1998f92e22aa3ecb76682e3a4255f33e1020bd32adf443"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d0213671691e341f6849bf33cd9fad21f7b1cb88b89e024f33370733fec58742"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:22e7ebc231d28393dfdc19b185d97e14a0f178bedd78e85aad660e93b646604e"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8ad241da7fac963d7573cc67a064c57c58766b62a9a20c452ca1f21050868dfa"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:586b36ebda81e6c1a9c5a5d0bfdc236399ba6595e1397842fd4a45648c30f35e"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0653d012b3bf45f194e5e6a41df9258811ac8fc395579fa82958a8b76286bea4"}, + {file = "regex-2022.10.31-cp36-cp36m-win32.whl", hash = "sha256:144486e029793a733e43b2e37df16a16df4ceb62102636ff3db6033994711066"}, + {file = "regex-2022.10.31-cp36-cp36m-win_amd64.whl", hash = "sha256:c14b63c9d7bab795d17392c7c1f9aaabbffd4cf4387725a0ac69109fb3b550c6"}, + {file = "regex-2022.10.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4cac3405d8dda8bc6ed499557625585544dd5cbf32072dcc72b5a176cb1271c8"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23cbb932cc53a86ebde0fb72e7e645f9a5eec1a5af7aa9ce333e46286caef783"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74bcab50a13960f2a610cdcd066e25f1fd59e23b69637c92ad470784a51b1347"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d680ef3e4d405f36f0d6d1ea54e740366f061645930072d39bca16a10d8c93"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6910b56b700bea7be82c54ddf2e0ed792a577dfaa4a76b9af07d550af435c6"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:659175b2144d199560d99a8d13b2228b85e6019b6e09e556209dfb8c37b78a11"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1ddf14031a3882f684b8642cb74eea3af93a2be68893901b2b387c5fd92a03ec"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b683e5fd7f74fb66e89a1ed16076dbab3f8e9f34c18b1979ded614fe10cdc4d9"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2bde29cc44fa81c0a0c8686992c3080b37c488df167a371500b2a43ce9f026d1"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4919899577ba37f505aaebdf6e7dc812d55e8f097331312db7f1aab18767cce8"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:9c94f7cc91ab16b36ba5ce476f1904c91d6c92441f01cd61a8e2729442d6fcf5"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae1e96785696b543394a4e3f15f3f225d44f3c55dafe3f206493031419fedf95"}, + {file = "regex-2022.10.31-cp37-cp37m-win32.whl", hash = "sha256:c670f4773f2f6f1957ff8a3962c7dd12e4be54d05839b216cb7fd70b5a1df394"}, + {file = "regex-2022.10.31-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0caeff18b96ea90fc0eb6e3bdb2b10ab5b01a95128dfeccb64a7238decf5f0"}, + {file = "regex-2022.10.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:131d4be09bea7ce2577f9623e415cab287a3c8e0624f778c1d955ec7c281bd4d"}, + {file = "regex-2022.10.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e613a98ead2005c4ce037c7b061f2409a1a4e45099edb0ef3200ee26ed2a69a8"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052b670fafbe30966bbe5d025e90b2a491f85dfe5b2583a163b5e60a85a321ad"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa62a07ac93b7cb6b7d0389d8ef57ffc321d78f60c037b19dfa78d6b17c928ee"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5352bea8a8f84b89d45ccc503f390a6be77917932b1c98c4cdc3565137acc714"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f61c9944f0be2dc2b75689ba409938c14876c19d02f7585af4460b6a21403e"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29c04741b9ae13d1e94cf93fca257730b97ce6ea64cfe1eba11cf9ac4e85afb6"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:543883e3496c8b6d58bd036c99486c3c8387c2fc01f7a342b760c1ea3158a318"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7a8b43ee64ca8f4befa2bea4083f7c52c92864d8518244bfa6e88c751fa8fff"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6a9a19bea8495bb419dc5d38c4519567781cd8d571c72efc6aa959473d10221a"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6ffd55b5aedc6f25fd8d9f905c9376ca44fcf768673ffb9d160dd6f409bfda73"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4bdd56ee719a8f751cf5a593476a441c4e56c9b64dc1f0f30902858c4ef8771d"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ca88da1bd78990b536c4a7765f719803eb4f8f9971cc22d6ca965c10a7f2c4c"}, + {file = "regex-2022.10.31-cp38-cp38-win32.whl", hash = "sha256:5a260758454580f11dd8743fa98319bb046037dfab4f7828008909d0aa5292bc"}, + {file = "regex-2022.10.31-cp38-cp38-win_amd64.whl", hash = "sha256:5e6a5567078b3eaed93558842346c9d678e116ab0135e22eb72db8325e90b453"}, + {file = "regex-2022.10.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5217c25229b6a85049416a5c1e6451e9060a1edcf988641e309dbe3ab26d3e49"}, + {file = "regex-2022.10.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bf41b8b0a80708f7e0384519795e80dcb44d7199a35d52c15cc674d10b3081b"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf0da36a212978be2c2e2e2d04bdff46f850108fccc1851332bcae51c8907cc"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d403d781b0e06d2922435ce3b8d2376579f0c217ae491e273bab8d092727d244"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a37d51fa9a00d265cf73f3de3930fa9c41548177ba4f0faf76e61d512c774690"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4f781ffedd17b0b834c8731b75cce2639d5a8afe961c1e58ee7f1f20b3af185"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d243b36fbf3d73c25e48014961e83c19c9cc92530516ce3c43050ea6276a2ab7"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:370f6e97d02bf2dd20d7468ce4f38e173a124e769762d00beadec3bc2f4b3bc4"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:597f899f4ed42a38df7b0e46714880fb4e19a25c2f66e5c908805466721760f5"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7dbdce0c534bbf52274b94768b3498abdf675a691fec5f751b6057b3030f34c1"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:22960019a842777a9fa5134c2364efaed5fbf9610ddc5c904bd3a400973b0eb8"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7f5a3ffc731494f1a57bd91c47dc483a1e10048131ffb52d901bfe2beb6102e8"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7ef6b5942e6bfc5706301a18a62300c60db9af7f6368042227ccb7eeb22d0892"}, + {file = "regex-2022.10.31-cp39-cp39-win32.whl", hash = "sha256:395161bbdbd04a8333b9ff9763a05e9ceb4fe210e3c7690f5e68cedd3d65d8e1"}, + {file = "regex-2022.10.31-cp39-cp39-win_amd64.whl", hash = "sha256:957403a978e10fb3ca42572a23e6f7badff39aa1ce2f4ade68ee452dc6807692"}, + {file = "regex-2022.10.31.tar.gz", hash = "sha256:a3a98921da9a1bf8457aeee6a551948a83601689e5ecdd736894ea9bbec77e83"}, +] requests = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, + {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, + {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, ] requests-oauthlib = [ {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, @@ -4796,27 +4930,27 @@ scikit-image = [ {file = "scikit_image-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:32fb88cc36203b99c9672fb972c9ef98635deaa5fc889fe969f3e11c44f22919"}, ] scipy = [ - {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, - {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, - {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, - {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, - {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, - {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, - {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, + {file = "scipy-1.10.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b901b423c91281a974f6cd1c36f5c6c523e665b5a6d5e80fcb2334e14670eefd"}, + {file = "scipy-1.10.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:16ba05d3d1b9f2141004f3f36888e05894a525960b07f4c2bfc0456b955a00be"}, + {file = "scipy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:151f066fe7d6653c3ffefd489497b8fa66d7316e3e0d0c0f7ff6acca1b802809"}, + {file = "scipy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f9ea0a37aca111a407cb98aa4e8dfde6e5d9333bae06dfa5d938d14c80bb5c3"}, + {file = "scipy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:27e548276b5a88b51212b61f6dda49a24acf5d770dff940bd372b3f7ced8c6c2"}, + {file = "scipy-1.10.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:42ab8b9e7dc1ebe248e55f54eea5307b6ab15011a7883367af48dd781d1312e4"}, + {file = "scipy-1.10.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e096b062d2efdea57f972d232358cb068413dc54eec4f24158bcbb5cb8bddfd8"}, + {file = "scipy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df25a28bd22c990b22129d3c637fd5c3be4b7c94f975dca909d8bab3309b694"}, + {file = "scipy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ad449db4e0820e4b42baccefc98ec772ad7818dcbc9e28b85aa05a536b0f1a2"}, + {file = "scipy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:6faf86ef7717891195ae0537e48da7524d30bc3b828b30c9b115d04ea42f076f"}, + {file = "scipy-1.10.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:4bd0e3278126bc882d10414436e58fa3f1eca0aa88b534fcbf80ed47e854f46c"}, + {file = "scipy-1.10.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:38bfbd18dcc69eeb589811e77fae552fa923067fdfbb2e171c9eac749885f210"}, + {file = "scipy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ab2a58064836632e2cec31ca197d3695c86b066bc4818052b3f5381bfd2a728"}, + {file = "scipy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd7a30970c29d9768a7164f564d1fbf2842bfc77b7d114a99bc32703ce0bf48"}, + {file = "scipy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:9b878c671655864af59c108c20e4da1e796154bd78c0ed6bb02bc41c84625686"}, + {file = "scipy-1.10.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:3afcbddb4488ac950ce1147e7580178b333a29cd43524c689b2e3543a080a2c8"}, + {file = "scipy-1.10.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:6e4497e5142f325a5423ff5fda2fff5b5d953da028637ff7c704378c8c284ea7"}, + {file = "scipy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:441cab2166607c82e6d7a8683779cb89ba0f475b983c7e4ab88f3668e268c143"}, + {file = "scipy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0490dc499fe23e4be35b8b6dd1e60a4a34f0c4adb30ac671e6332446b3cbbb5a"}, + {file = "scipy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:954ff69d2d1bf666b794c1d7216e0a746c9d9289096a64ab3355a17c7c59db54"}, + {file = "scipy-1.10.0.tar.gz", hash = "sha256:c8b3cbc636a87a89b770c6afc999baa6bcbb01691b5ccbbc1b1791c7c0a07540"}, ] semantic-version = [ {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"}, @@ -4827,8 +4961,8 @@ semver = [ {file = "semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"}, ] setuptools = [ - {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, - {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, + {file = "setuptools-66.0.0-py3-none-any.whl", hash = "sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab"}, + {file = "setuptools-66.0.0.tar.gz", hash = "sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, @@ -4847,47 +4981,47 @@ soupsieve = [ {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.45-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:f1d3fb02a4d0b07d1351a4a52f159e5e7b3045c903468b7e9349ebf0020ffdb9"}, - {file = "SQLAlchemy-1.4.45-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9b7025d46aba946272f6b6b357a22f3787473ef27451f342df1a2a6de23743e3"}, - {file = "SQLAlchemy-1.4.45-cp27-cp27m-win32.whl", hash = "sha256:26b8424b32eeefa4faad21decd7bdd4aade58640b39407bf43e7d0a7c1bc0453"}, - {file = "SQLAlchemy-1.4.45-cp27-cp27m-win_amd64.whl", hash = "sha256:13578d1cda69bc5e76c59fec9180d6db7ceb71c1360a4d7861c37d87ea6ca0b1"}, - {file = "SQLAlchemy-1.4.45-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6cd53b4c756a6f9c6518a3dc9c05a38840f9ae442c91fe1abde50d73651b6922"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:ca152ffc7f0aa069c95fba46165030267ec5e4bb0107aba45e5e9e86fe4d9363"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06055476d38ed7915eeed22b78580556d446d175c3574a01b9eb04d91f3a8b2e"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:081e2a2d75466353c738ca2ee71c0cfb08229b4f9909b5fa085f75c48d021471"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96821d806c0c90c68ce3f2ce6dd529c10e5d7587961f31dd5c30e3bfddc4545d"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-win32.whl", hash = "sha256:c8051bff4ce48cbc98f11e95ac46bfd1e36272401070c010248a3230d099663f"}, - {file = "SQLAlchemy-1.4.45-cp310-cp310-win_amd64.whl", hash = "sha256:16ad798fc121cad5ea019eb2297127b08c54e1aa95fe17b3fea9fdbc5c34fe62"}, - {file = "SQLAlchemy-1.4.45-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:099efef0de9fbda4c2d7cb129e4e7f812007901942259d4e6c6e19bd69de1088"}, - {file = "SQLAlchemy-1.4.45-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29a29d02c9e6f6b105580c5ed7afb722b97bc2e2fdb85e1d45d7ddd8440cfbca"}, - {file = "SQLAlchemy-1.4.45-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc10423b59d6d032d6dff0bb42aa06dc6a8824eb6029d70c7d1b6981a2e7f4d8"}, - {file = "SQLAlchemy-1.4.45-cp311-cp311-win32.whl", hash = "sha256:1a92685db3b0682776a5abcb5f9e9addb3d7d9a6d841a452a17ec2d8d457bea7"}, - {file = "SQLAlchemy-1.4.45-cp311-cp311-win_amd64.whl", hash = "sha256:db3ccbce4a861bf4338b254f95916fc68dd8b7aa50eea838ecdaf3a52810e9c0"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a62ae2ea3b940ce9c9cbd675489c2047921ce0a79f971d3082978be91bd58117"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87f8595390764db333a1705591d0934973d132af607f4fa8b792b366eacbb3c"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a21c1fb71c69c8ec65430160cd3eee44bbcea15b5a4e556f29d03f246f425ec"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7944b04e6fcf8d733964dd9ee36b6a587251a1a4049af3a9b846f6e64eb349a"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-win32.whl", hash = "sha256:a3bcd5e2049ceb97e8c273e6a84ff4abcfa1dc47b6d8bbd36e07cce7176610d3"}, - {file = "SQLAlchemy-1.4.45-cp36-cp36m-win_amd64.whl", hash = "sha256:5953e225be47d80410ae519f865b5c341f541d8e383fb6d11f67fb71a45bf890"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:6a91b7883cb7855a27bc0637166eed622fdf1bb94a4d1630165e5dd88c7e64d3"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d458fd0566bc9e10b8be857f089e96b5ca1b1ef033226f24512f9ffdf485a8c0"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f4ad3b081c0dbb738886f8d425a5d983328670ee83b38192687d78fc82bd1e"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd95a3e6ab46da2c5b0703e797a772f3fab44d085b3919a4f27339aa3b1f51d3"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-win32.whl", hash = "sha256:715f5859daa3bee6ecbad64501637fa4640ca6734e8cda6135e3898d5f8ccadd"}, - {file = "SQLAlchemy-1.4.45-cp37-cp37m-win_amd64.whl", hash = "sha256:2d1539fbc82d2206380a86d6d7d0453764fdca5d042d78161bbfb8dd047c80ec"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:01aa76f324c9bbc0dcb2bc3d9e2a9d7ede4808afa1c38d40d5e2007e3163b206"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:416fe7d228937bd37990b5a429fd00ad0e49eabcea3455af7beed7955f192edd"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7e32ce2584564d9e068bb7e0ccd1810cbb0a824c0687f8016fe67e97c345a637"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:561605cfc26273825ed2fb8484428faf36e853c13e4c90c61c58988aeccb34ed"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-win32.whl", hash = "sha256:55ddb5585129c5d964a537c9e32a8a68a8c6293b747f3fa164e1c034e1657a98"}, - {file = "SQLAlchemy-1.4.45-cp38-cp38-win_amd64.whl", hash = "sha256:445914dcadc0b623bd9851260ee54915ecf4e3041a62d57709b18a0eed19f33b"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2db887dbf05bcc3151de1c4b506b14764c6240a42e844b4269132a7584de1e5f"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52b90c9487e4449ad954624d01dea34c90cd8c104bce46b322c83654f37a23c5"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f61e54b8c2b389de1a8ad52394729c478c67712dbdcdadb52c2575e41dae94a5"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e91a5e45a2ea083fe344b3503405978dff14d60ef3aa836432c9ca8cd47806b6"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-win32.whl", hash = "sha256:0e068b8414d60dd35d43c693555fc3d2e1d822cef07960bb8ca3f1ee6c4ff762"}, - {file = "SQLAlchemy-1.4.45-cp39-cp39-win_amd64.whl", hash = "sha256:2d6f178ff2923730da271c8aa317f70cf0df11a4d1812f1d7a704b1cf29c5fe3"}, - {file = "SQLAlchemy-1.4.45.tar.gz", hash = "sha256:fd69850860093a3f69fefe0ab56d041edfdfe18510b53d9a2eaecba2f15fa795"}, + {file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, + {file = "SQLAlchemy-1.4.46-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf"}, + {file = "SQLAlchemy-1.4.46-cp27-cp27m-win32.whl", hash = "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854"}, + {file = "SQLAlchemy-1.4.46-cp27-cp27m-win_amd64.whl", hash = "sha256:7b81b1030c42b003fc10ddd17825571603117f848814a344d305262d370e7c34"}, + {file = "SQLAlchemy-1.4.46-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:939f9a018d2ad04036746e15d119c0428b1e557470361aa798e6e7d7f5875be0"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b7f4b6aa6e87991ec7ce0e769689a977776db6704947e562102431474799a857"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf17ac9a61e7a3f1c7ca47237aac93cabd7f08ad92ac5b96d6f8dea4287fc1"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7f8267682eb41a0584cf66d8a697fef64b53281d01c93a503e1344197f2e01fe"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cb0ad8a190bc22d2112001cfecdec45baffdf41871de777239da6a28ed74b6"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-win32.whl", hash = "sha256:5f752676fc126edc1c4af0ec2e4d2adca48ddfae5de46bb40adbd3f903eb2120"}, + {file = "SQLAlchemy-1.4.46-cp310-cp310-win_amd64.whl", hash = "sha256:31de1e2c45e67a5ec1ecca6ec26aefc299dd5151e355eb5199cd9516b57340be"}, + {file = "SQLAlchemy-1.4.46-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d68e1762997bfebf9e5cf2a9fd0bcf9ca2fdd8136ce7b24bbd3bbfa4328f3e4a"}, + {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d112b0f3c1bc5ff70554a97344625ef621c1bfe02a73c5d97cac91f8cd7a41e"}, + {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69fac0a7054d86b997af12dc23f581cf0b25fb1c7d1fed43257dee3af32d3d6d"}, + {file = "SQLAlchemy-1.4.46-cp311-cp311-win32.whl", hash = "sha256:887865924c3d6e9a473dc82b70977395301533b3030d0f020c38fd9eba5419f2"}, + {file = "SQLAlchemy-1.4.46-cp311-cp311-win_amd64.whl", hash = "sha256:984ee13543a346324319a1fb72b698e521506f6f22dc37d7752a329e9cd00a32"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:9167d4227b56591a4cc5524f1b79ccd7ea994f36e4c648ab42ca995d28ebbb96"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d61e9ecc849d8d44d7f80894ecff4abe347136e9d926560b818f6243409f3c86"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3ec187acf85984263299a3f15c34a6c0671f83565d86d10f43ace49881a82718"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9883f5fae4fd8e3f875adc2add69f8b945625811689a6c65866a35ee9c0aea23"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-win32.whl", hash = "sha256:535377e9b10aff5a045e3d9ada8a62d02058b422c0504ebdcf07930599890eb0"}, + {file = "SQLAlchemy-1.4.46-cp36-cp36m-win_amd64.whl", hash = "sha256:18cafdb27834fa03569d29f571df7115812a0e59fd6a3a03ccb0d33678ec8420"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:a1ad90c97029cc3ab4ffd57443a20fac21d2ec3c89532b084b073b3feb5abff3"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4847f4b1d822754e35707db913396a29d874ee77b9c3c3ef3f04d5a9a6209618"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a99282848b6cae0056b85da17392a26b2d39178394fc25700bcf967e06e97a"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b1cc7835b39835c75cf7c20c926b42e97d074147c902a9ebb7cf2c840dc4e2"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-win32.whl", hash = "sha256:c522e496f9b9b70296a7675272ec21937ccfc15da664b74b9f58d98a641ce1b6"}, + {file = "SQLAlchemy-1.4.46-cp37-cp37m-win_amd64.whl", hash = "sha256:ae067ab639fa499f67ded52f5bc8e084f045d10b5ac7bb928ae4ca2b6c0429a5"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:e3c1808008124850115a3f7e793a975cfa5c8a26ceeeb9ff9cbb4485cac556df"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d164df3d83d204c69f840da30b292ac7dc54285096c6171245b8d7807185aa"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b33ffbdbbf5446cf36cd4cc530c9d9905d3c2fe56ed09e25c22c850cdb9fac92"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d94682732d1a0def5672471ba42a29ff5e21bb0aae0afa00bb10796fc1e28dd"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-win32.whl", hash = "sha256:f8cb80fe8d14307e4124f6fad64dfd87ab749c9d275f82b8b4ec84c84ecebdbe"}, + {file = "SQLAlchemy-1.4.46-cp38-cp38-win_amd64.whl", hash = "sha256:07e48cbcdda6b8bc7a59d6728bd3f5f574ffe03f2c9fb384239f3789c2d95c2e"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1b1e5e96e2789d89f023d080bee432e2fef64d95857969e70d3cadec80bd26f0"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3714e5b33226131ac0da60d18995a102a17dddd42368b7bdd206737297823ad"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:955162ad1a931fe416eded6bb144ba891ccbf9b2e49dc7ded39274dd9c5affc5"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6e4cb5c63f705c9d546a054c60d326cbde7421421e2d2565ce3e2eee4e1a01f"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-win32.whl", hash = "sha256:51e1ba2884c6a2b8e19109dc08c71c49530006c1084156ecadfaadf5f9b8b053"}, + {file = "SQLAlchemy-1.4.46-cp39-cp39-win_amd64.whl", hash = "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466"}, + {file = "SQLAlchemy-1.4.46.tar.gz", hash = "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30"}, ] stevedore = [ {file = "stevedore-4.1.1-py3-none-any.whl", hash = "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e"}, @@ -4951,8 +5085,8 @@ tensorflow-io-gcs-filesystem = [ {file = "tensorflow_io_gcs_filesystem-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:bcb7405474ed136b3a2e2181a732968c52ba9f35a03fe296acc9f1ec4e7044ee"}, ] termcolor = [ - {file = "termcolor-2.1.1-py3-none-any.whl", hash = "sha256:fa852e957f97252205e105dd55bbc23b419a70fec0085708fc0515e399f304fd"}, - {file = "termcolor-2.1.1.tar.gz", hash = "sha256:67cee2009adc6449c650f6bcf3bdeed00c8ba53a8cda5362733c53e0a39fb70b"}, + {file = "termcolor-2.2.0-py3-none-any.whl", hash = "sha256:91ddd848e7251200eac969846cbae2dacd7d71c2871e92733289e7e3666f48e7"}, + {file = "termcolor-2.2.0.tar.gz", hash = "sha256:dfc8ac3f350788f23b2947b3e6cfa5a53b630b612e6cd8965a015a776020b99a"}, ] tifffile = [ {file = "tifffile-2022.10.10-py3-none-any.whl", hash = "sha256:87f3aee8a0d06b74655269a105de75c1958a24653e1930d523eb516100043503"}, @@ -4990,6 +5124,10 @@ types-click = [ {file = "types-click-7.1.8.tar.gz", hash = "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092"}, {file = "types_click-7.1.8-py3-none-any.whl", hash = "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81"}, ] +types-docutils = [ + {file = "types-docutils-0.19.1.1.tar.gz", hash = "sha256:be0a51ba1c7dd215d9d2df66d6845e63c1009b4bbf4c5beb87a0d9745cdba962"}, + {file = "types_docutils-0.19.1.1-py3-none-any.whl", hash = "sha256:a024cada35f0c13cc45eb0b68a102719018a634013690b7fef723bcbfadbd1f1"}, +] types-pyyaml = [ {file = "types-PyYAML-6.0.12.2.tar.gz", hash = "sha256:6840819871c92deebe6a2067fb800c11b8a063632eb4e3e755914e7ab3604e83"}, {file = "types_PyYAML-6.0.12.2-py3-none-any.whl", hash = "sha256:1e94e80aafee07a7e798addb2a320e32956a373f376655128ae20637adb2655b"}, @@ -4999,8 +5137,8 @@ types-requests = [ {file = "types_requests-2.28.11.7-py3-none-any.whl", hash = "sha256:b6a2fca8109f4fdba33052f11ed86102bddb2338519e1827387137fefc66a98b"}, ] types-setuptools = [ - {file = "types-setuptools-65.6.0.2.tar.gz", hash = "sha256:ad60ccf01d626de9762224448f36c13e0660e863afd6dc11d979b3739a6c7d24"}, - {file = "types_setuptools-65.6.0.2-py3-none-any.whl", hash = "sha256:2c2b4f756f79778074ce2d21f745aa737b12160d9f8dfa274f47a7287c7a2fee"}, + {file = "types-setuptools-65.7.0.1.tar.gz", hash = "sha256:fe89f2d15caee7015708bed8fb68ff578b4d96f9a64b6e2010dad42bb9cc82a6"}, + {file = "types_setuptools-65.7.0.1-py3-none-any.whl", hash = "sha256:667597f0773464f0259524d349d37503bffefc9d0d3fae621e4493d2fd7b1602"}, ] types-urllib3 = [ {file = "types-urllib3-1.26.25.4.tar.gz", hash = "sha256:eec5556428eec862b1ac578fb69aab3877995a99ffec9e5a12cf7fbd0cc9daee"}, @@ -5015,8 +5153,8 @@ uritemplate = [ {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, ] urllib3 = [ - {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, - {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, + {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, + {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, ] varint = [ {file = "varint-1.0.2.tar.gz", hash = "sha256:a6ecc02377ac5ee9d65a6a8ad45c9ff1dac8ccee19400a5950fb51d594214ca5"}, @@ -5030,38 +5168,38 @@ vulture = [ {file = "vulture-2.6.tar.gz", hash = "sha256:2515fa848181001dc8a73aba6a01a1a17406f5d372f24ec7f7191866f9f4997e"}, ] watchdog = [ - {file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed91c3ccfc23398e7aa9715abf679d5c163394b8cad994f34f156d57a7c163dc"}, - {file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:76a2743402b794629a955d96ea2e240bd0e903aa26e02e93cd2d57b33900962b"}, - {file = "watchdog-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:920a4bda7daa47545c3201a3292e99300ba81ca26b7569575bd086c865889090"}, - {file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ceaa9268d81205876bedb1069f9feab3eccddd4b90d9a45d06a0df592a04cae9"}, - {file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1893d425ef4fb4f129ee8ef72226836619c2950dd0559bba022b0818c63a7b60"}, - {file = "watchdog-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e99c1713e4436d2563f5828c8910e5ff25abd6ce999e75f15c15d81d41980b6"}, - {file = "watchdog-2.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a5bd9e8656d07cae89ac464ee4bcb6f1b9cecbedc3bf1334683bed3d5afd39ba"}, - {file = "watchdog-2.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a048865c828389cb06c0bebf8a883cec3ae58ad3e366bcc38c61d8455a3138f"}, - {file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e722755d995035dd32177a9c633d158f2ec604f2a358b545bba5bed53ab25bca"}, - {file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af4b5c7ba60206759a1d99811b5938ca666ea9562a1052b410637bb96ff97512"}, - {file = "watchdog-2.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:619d63fa5be69f89ff3a93e165e602c08ed8da402ca42b99cd59a8ec115673e1"}, - {file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f2b0665c57358ce9786f06f5475bc083fea9d81ecc0efa4733fd0c320940a37"}, - {file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:441024df19253bb108d3a8a5de7a186003d68564084576fecf7333a441271ef7"}, - {file = "watchdog-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a410dd4d0adcc86b4c71d1317ba2ea2c92babaf5b83321e4bde2514525544d5"}, - {file = "watchdog-2.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28704c71afdb79c3f215c90231e41c52b056ea880b6be6cee035c6149d658ed1"}, - {file = "watchdog-2.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ac0bd7c206bb6df78ef9e8ad27cc1346f2b41b1fef610395607319cdab89bc1"}, - {file = "watchdog-2.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27e49268735b3c27310883012ab3bd86ea0a96dcab90fe3feb682472e30c90f3"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:2af1a29fd14fc0a87fb6ed762d3e1ae5694dcde22372eebba50e9e5be47af03c"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:c7bd98813d34bfa9b464cf8122e7d4bec0a5a427399094d2c17dd5f70d59bc61"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_i686.whl", hash = "sha256:56fb3f40fc3deecf6e518303c7533f5e2a722e377b12507f6de891583f1b48aa"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:74535e955359d79d126885e642d3683616e6d9ab3aae0e7dcccd043bd5a3ff4f"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cf05e6ff677b9655c6e9511d02e9cc55e730c4e430b7a54af9c28912294605a4"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:d6ae890798a3560688b441ef086bb66e87af6b400a92749a18b856a134fc0318"}, - {file = "watchdog-2.2.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5aed2a700a18c194c39c266900d41f3db0c1ebe6b8a0834b9995c835d2ca66e"}, - {file = "watchdog-2.2.0-py3-none-win32.whl", hash = "sha256:d0fb5f2b513556c2abb578c1066f5f467d729f2eb689bc2db0739daf81c6bb7e"}, - {file = "watchdog-2.2.0-py3-none-win_amd64.whl", hash = "sha256:1f8eca9d294a4f194ce9df0d97d19b5598f310950d3ac3dd6e8d25ae456d4c8a"}, - {file = "watchdog-2.2.0-py3-none-win_ia64.whl", hash = "sha256:ad0150536469fa4b693531e497ffe220d5b6cd76ad2eda474a5e641ee204bbb6"}, - {file = "watchdog-2.2.0.tar.gz", hash = "sha256:83cf8bc60d9c613b66a4c018051873d6273d9e45d040eed06d6a96241bd8ec01"}, + {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"}, + {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"}, + {file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"}, + {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:102a60093090fc3ff76c983367b19849b7cc24ec414a43c0333680106e62aae1"}, + {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:748ca797ff59962e83cc8e4b233f87113f3cf247c23e6be58b8a2885c7337aa3"}, + {file = "watchdog-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ccd8d84b9490a82b51b230740468116b8205822ea5fdc700a553d92661253a3"}, + {file = "watchdog-2.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6e01d699cd260d59b84da6bda019dce0a3353e3fcc774408ae767fe88ee096b7"}, + {file = "watchdog-2.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8586d98c494690482c963ffb24c49bf9c8c2fe0589cec4dc2f753b78d1ec301d"}, + {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:adaf2ece15f3afa33a6b45f76b333a7da9256e1360003032524d61bdb4c422ae"}, + {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83a7cead445008e880dbde833cb9e5cc7b9a0958edb697a96b936621975f15b9"}, + {file = "watchdog-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8ac23ff2c2df4471a61af6490f847633024e5aa120567e08d07af5718c9d092"}, + {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d0f29fd9f3f149a5277929de33b4f121a04cf84bb494634707cfa8ea8ae106a8"}, + {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:967636031fa4c4955f0f3f22da3c5c418aa65d50908d31b73b3b3ffd66d60640"}, + {file = "watchdog-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96cbeb494e6cbe3ae6aacc430e678ce4b4dd3ae5125035f72b6eb4e5e9eb4f4e"}, + {file = "watchdog-2.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61fdb8e9c57baf625e27e1420e7ca17f7d2023929cd0065eb79c83da1dfbeacd"}, + {file = "watchdog-2.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb5ecc332112017fbdb19ede78d92e29a8165c46b68a0b8ccbd0a154f196d5e"}, + {file = "watchdog-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a480d122740debf0afac4ddd583c6c0bb519c24f817b42ed6f850e2f6f9d64a8"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:978a1aed55de0b807913b7482d09943b23a2d634040b112bdf31811a422f6344"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:8c28c23972ec9c524967895ccb1954bc6f6d4a557d36e681a36e84368660c4ce"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_i686.whl", hash = "sha256:c27d8c1535fd4474e40a4b5e01f4ba6720bac58e6751c667895cbc5c8a7af33c"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d6b87477752bd86ac5392ecb9eeed92b416898c30bd40c7e2dd03c3146105646"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cece1aa596027ff56369f0b50a9de209920e1df9ac6d02c7f9e5d8162eb4f02b"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:8b5cde14e5c72b2df5d074774bdff69e9b55da77e102a91f36ef26ca35f9819c"}, + {file = "watchdog-2.2.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e038be858425c4f621900b8ff1a3a1330d9edcfeaa1c0468aeb7e330fb87693e"}, + {file = "watchdog-2.2.1-py3-none-win32.whl", hash = "sha256:bc43c1b24d2f86b6e1cc15f68635a959388219426109233e606517ff7d0a5a73"}, + {file = "watchdog-2.2.1-py3-none-win_amd64.whl", hash = "sha256:17f1708f7410af92ddf591e94ae71a27a13974559e72f7e9fde3ec174b26ba2e"}, + {file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"}, + {file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"}, ] web3 = [ - {file = "web3-5.31.3-py3-none-any.whl", hash = "sha256:39ad206db390ae1a9001522e300da66d766fa2f1bf2f15422f2fee29f97b81ef"}, - {file = "web3-5.31.3.tar.gz", hash = "sha256:4b2d420647c81856e3cf398996cd3cc80c719dc3a10881884c5c3b1467e4f850"}, + {file = "web3-5.31.1-py3-none-any.whl", hash = "sha256:9c2e72688a5b35881062ef4f9da01c4a1e922afeb3134cfc92f6b4b95bb7df06"}, + {file = "web3-5.31.1.tar.gz", hash = "sha256:74732fbd4b2e2baff9d0ac61f268b3e7b25b09ca6572d619390a9d782c2289f2"}, ] websocket-client = [ {file = "websocket-client-1.4.2.tar.gz", hash = "sha256:d6e8f90ca8e2dd4e8027c4561adeb9456b54044312dba655e7cae652ceb9ae59"}, diff --git a/pyproject.toml b/pyproject.toml index 1981369af5..d72fb482e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,13 +98,13 @@ pexpect = "^4.8.0" sqlalchemy = ">=1.4.41" # used in one test mistune = "^2.0.4" requests = "^2.28.0" -web3 = ">=5.31.0,<6.0.0" +web3 = "==5.31.1" [tool.poetry.group.docs] optional = true [tool.poetry.group.docs.dependencies] -mkdocs-material = "^8.5.7" +mkdocs-material = "^9.0.3" mkdocs-mermaid-plugin = { git = "https://github.com/pugong/mkdocs-mermaid-plugin.git" } pydoc-markdown = "^4.6.3" pydocstyle = "^6.1.1" diff --git a/scripts/NOTES.md b/scripts/NOTES.md index 022065ce21..6ea71dbf88 100644 --- a/scripts/NOTES.md +++ b/scripts/NOTES.md @@ -2,4 +2,4 @@ ## Threading -- always join the thread. Setting no timeout means the calling thread's execution will block until the thread is terminated (https://docs.python.org/3/library/threading.html) \ No newline at end of file +- always join the thread. Setting no timeout means the calling thread's execution will block until the thread is terminated () diff --git a/scripts/RELEASE_PROCESS.md b/scripts/RELEASE_PROCESS.md index 9efac17275..c996cef1d6 100644 --- a/scripts/RELEASE_PROCESS.md +++ b/scripts/RELEASE_PROCESS.md @@ -1,8 +1,8 @@ # Release Process from develop to main -1. Make sure all tests pass, coverage is at 100% and the local branch is in a clean state (nothing to commit). Make sure you have a clean develop virtual environment. - +1. Make sure all tests pass, coverage is at 100% and the local branch is in a clean state (nothing to commit). Make sure you have a clean develop virtual environment. + 2. Determine the next AEA version. Create a new release branch named "feature/release-{new-version}". Switch to this branch. Run `python scripts/bump_aea_version.py --new-version NEW_VERSION_HERE`. Commit if satisfied. 3. Bump plugin versions if necessary by running `python scripts/update_plugin_versions.py --update "PLUGIN_NAME,NEW_VERSION"`. Commit if satisfied. diff --git a/scripts/acn/README.md b/scripts/acn/README.md index 066335abed..a840552a47 100644 --- a/scripts/acn/README.md +++ b/scripts/acn/README.md @@ -1,4 +1,6 @@ -# Installing the agent communication network (ACN) in Kubernetes using helm +# Agent Communication Network (ACN) + +## Installing the agent communication network (ACN) in Kubernetes using helm **Requirements:** `helm` needs to be installed. @@ -11,17 +13,17 @@ To deploy a test network do the following steps: 1. Build and upload the ACN node image by running `./build_upload_img.sh`. You have to execute this from this folder. 2. update the image tag (two instances) in the `helm-chart/values.yaml` 3. `cd helm-chart` + **NOTE: Make sure to be in the `agents-p2p-dht-testnet` namespace before proceeding** +4. If: + 1. this is the first time deploying: run `helm install agents-dht-test .` + 2. you are upgrading an existing installation (see if there is one by `helm ls`): run `helm upgrade agents-dht-test .` -**NOTE: Make sure to be in the `agents-p2p-dht-testnet` namespace before proceeding** - -4. a) If this is the first time deploying run `helm install agents-dht-test .` - b) If you are upgrading an existing installation (see if there is one by `helm ls`) run `helm upgrade agents-dht-test .` - -## Simple image update: +### Simple image update Run `./build_upload_img.sh` and take note of the image tag. Replace below `IMAGE_TAG_HERE` with the image tag. + ``` bash kubens agents-p2p-dht-testnet kubectl set image sts/acn-node-9005 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE} @@ -34,46 +36,49 @@ kubectl set image sts/acn-node-9000 acn-node=gcr.io/fetch-ai-colearn/acn_node:{I kubectl set image sts/acn-node-9001 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE} ``` -# The agent communication network (ACN) Kubernetes deployment script +## The agent communication network (ACN) Kubernetes deployment script The `k8s_deploy_acn_node.py` script provides a configurable, reproducible, and verifiable deployment of the ACN node to a Kubernetes cluster. Configuration of the ACN node, docker image, and Kubernetes is passed through command-line interface. The script will then verify it, generate the -corresponding YAML deployment file and finally deploy it. +corresponding YAML deployment file and finally deploy it. The script can also delete a deployment by appending `--delete` to the CLI arguments used to create the deployment. The generated YAML deployment file includes: + - a `statefulSet` to persist ACN node log file across runs - a service for restarting the node (pod) in case of failure - a `DNSEndpoint` to expose public port -- a secret to safely upload the node's private key +- a secret to safely upload the node's private key -The generated YAML deployment file can be saved for future re-deployments by using CLI option `--from-file`. +The generated YAML deployment file can be saved for future re-deployments by using CLI option `--from-file`. Options `--from-file` and `--delete` can be combined as quick way to delete a previous deployment from Kubernetes cluster. Option `--generate-only` can be used to generate the deployment file without submitting it to the cluster. To reduce the number of CLI arguments to pass, the script offers defaults for docker and Kubernetes configuration that can be used by setting `--k8s-fetchai-defaults`, `--docker-fetchai-defaults` or `--docker-fetchai-defaults-dev`. -## Usage examples - +### Usage examples - deploy a node using CLI options + ```bash python3 scripts/acn/k8s_deploy_acn_node.py --acn-key-file fet_key_test_1.txt --acn-port 9009 --acn-port-delegate 11009 --k8s-fetchai-defaults --docker-fetchai-defaults-dev ``` - delete deployment using CLI options + ```bash python3 scripts/acn/k8s_deploy_acn_node.py --acn-key-file fet_key_test_1.txt --acn-port 9009 --acn-port-delegate 11009 --k8s-fetchai-defaults --docker-fetchai-defaults-dev --delete ``` - redeploy using the generated deployment file + ```bash python3 scripts/acn/k8s_deploy_acn_node.py --from-file .acn_deployment.yaml ``` - delete deployment using the generated deployment file + ```bash python3 scripts/acn/k8s_deploy_acn_node.py --from-file .acn_deployment.yaml --delete ``` - diff --git a/tests/test_aea/test_helpers/test_ipfs/test_base.py b/tests/test_aea/test_helpers/test_ipfs/test_base.py index fe0fd355ea..aeeac2ff94 100644 --- a/tests/test_aea/test_helpers/test_ipfs/test_base.py +++ b/tests/test_aea/test_helpers/test_ipfs/test_base.py @@ -33,7 +33,7 @@ def test_get_hash(): """Test get hash IPFSHashOnly.""" ipfs_hash = IPFSHashOnly().get(file_path=os.path.join(CUR_PATH, FILE_PATH)) - assert ipfs_hash == "QmbfrfW8V4u1gtQZ4ZjsJubrwkahYjAGVY1RSBVbvM9UXw" + assert ipfs_hash == "QmVyhvd64oCVNqs4Vg2zn8WE6UsK1tk1jTW4GEopcUVyuH" def test_is_text_negative(): diff --git a/tests/test_docs/helper.py b/tests/test_docs/helper.py index 770b672d5c..28c6c63884 100644 --- a/tests/test_docs/helper.py +++ b/tests/test_docs/helper.py @@ -18,10 +18,11 @@ # ------------------------------------------------------------------------------ """This module contains helper function to extract code from the .md files.""" +import re import traceback from functools import partial from pathlib import Path -from typing import Dict, List, Optional +from typing import Dict, List, Optional, cast import mistune import pytest @@ -51,13 +52,91 @@ def type_filter(type_: Optional[str], b: Dict) -> bool: return b["info"].strip() == type_ if b["info"] is not None else False +def extract_dicts(dictionary: Dict, collection_dict: List[Dict]) -> List[Dict]: + """Extract code blocks from .md files.""" + if all(not isinstance(v, list) for v in dictionary.values()): + collection_dict.append(dictionary) + else: + for dict_el in dictionary.values(): + if isinstance(dict_el, list): + for list_el in dict_el: + if isinstance(list_el, dict): + extract_dicts(list_el, collection_dict) + return collection_dict + + +def flatten_blocks(blocks: List[Dict]) -> List[Dict]: + """Convert a list of dicts with nested dicts, into a list containing all dicts.""" + new_blocks: List[Dict] = [] + if isinstance(blocks, list): + for el in blocks: + if isinstance(el, dict): + extract_dicts(el, new_blocks) + return new_blocks + + +def correct_spacing(string: str) -> str: + """Convert a list of dicts with nested dicts, into a list containing all dicts.""" + new_string = "" + string_no_back_quote = string[:-3] + last_new_line = string.rfind("\n") + last_none_space = len(string_no_back_quote.strip(" ")) - 1 + + if last_new_line != -1 and last_new_line == last_none_space: + number_of_trailing_spaces = (len(string_no_back_quote) - 1) - last_none_space + for line in string.splitlines(): + number_of_leading_spaces = len(line) - len(line.lstrip(" ")) + if number_of_leading_spaces >= number_of_trailing_spaces: + new_line = line[number_of_trailing_spaces:] + new_string += new_line + else: + new_string += line + new_string += "\n" + return new_string + return string + + +def extract_inner_code_blocks(block: Dict, code_blocks: List[Dict]) -> None: + """Replace code_block with any sub code_blocks it may have""" + text = cast(str, block["text"]) + indexes = [m.start() for m in re.finditer("```", text)] + if indexes: + if len(indexes) % 2 != 0: + raise SyntaxError(f"un-matching ``` found in the block: {text}") + while indexes: + starting_index = indexes.pop(0) + ending_index = indexes.pop(0) + 3 + sub_string = text[starting_index:ending_index] + new_substring = correct_spacing(sub_string) + new_dict = { + "type": block["type"], + "text": new_substring, + "info": block["info"], + } + code_blocks.insert(code_blocks.index(block), new_dict) + code_blocks.remove(block) + + def extract_code_blocks(filepath, filter_=None): """Extract code blocks from .md files.""" content = Path(filepath).read_text(encoding="utf-8") markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer()) blocks = markdown_parser(content) + flat_blocks = flatten_blocks(blocks) actual_type_filter = partial(type_filter, filter_) - code_blocks = list(filter(block_code_filter, blocks)) + code_blocks = list(filter(block_code_filter, flat_blocks)) + + for code_block in code_blocks: + extract_inner_code_blocks(code_block, code_blocks) + + for block in code_blocks: + if block["text"].startswith("``` "): + type_ = block["text"][4 : block["text"].find("\n")] + block["text"] = block["text"].strip()[block["text"].find("\n") + 1 :] + if block["text"].endswith("```"): + block["text"] = block["text"].strip()[:-3] + block["info"] = f"{type_}" + bash_code_blocks = filter(actual_type_filter, code_blocks) return list(b["text"] for b in bash_code_blocks) @@ -116,6 +195,7 @@ class BaseTestMarkdownDocs: DOC_PATH: Path blocks: List[Dict] + flat_blocks: List[Dict] python_blocks: List[Dict] @classmethod @@ -125,8 +205,9 @@ def setup_class(cls): cls.doc_path = cls.DOC_PATH cls.doc_content = cls.doc_path.read_text() cls.blocks = markdown_parser(cls.doc_content) - cls.code_blocks = list(filter(block_code_filter, cls.blocks)) - cls.python_blocks = list(filter(cls._python_selector, cls.blocks)) + cls.flat_blocks = flatten_blocks(cls.blocks) + cls.code_blocks = list(filter(block_code_filter, cls.flat_blocks)) + cls.python_blocks = list(filter(cls._python_selector, cls.flat_blocks)) @classmethod def _python_selector(cls, block: Dict) -> bool: diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-aggregation-demo.md b/tests/test_docs/test_bash_yaml/md_files/bash-aggregation-demo.md index 601e45a60d..5555b9ca53 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-aggregation-demo.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-aggregation-demo.md @@ -5,6 +5,7 @@ cd $agent_name aea install aea build ``` + ``` bash agent_name="agg$i" aea create agent_name @@ -21,38 +22,47 @@ aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 aea install aea build ``` + ``` bash aea config set --type int vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals 0 ``` + ``` bash aea config set --type bool vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server false ``` + ``` bash aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ '[{"identifier": "acn", "ledger_id": "fetchai", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "message_format": "{public_key}", "save_path": ".certs/conn_cert.txt"}]' ``` + ``` bash aea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url $COIN_URL aea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{"name": "price", "json_path": '"\"$JSON_PATH\""'}]' ``` + ``` bash aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.quantity_name price aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.aggregation_function mean ``` + ``` bash SERVICE_ID=my_btc_aggregation_service aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.service_id $SERVICE_ID aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.search_query.search_value $SERVICE_ID ``` + ``` bash aea generate-key fetchai aea add-key fetchai aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash MULTIADDR=$(cd ../agg0 && aea get-multiaddress fetchai --connection) aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ @@ -66,23 +76,29 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ aea config set vendor.fetchai.connections.prometheus.config.port $((20000+i)) aea config set vendor.fetchai.connections.http_server.config.port $((8000+i)) ``` + ``` bash aea add connection fetchai/ledger:0.21.4 aea add skill fetchai/simple_oracle:0.16.4 ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value ``` -``` + +``` bash aea generate-wealth fetchai ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price_mean ``` + ``` bash aea run ``` + ``` bash info: [agg_i] found agents... ... @@ -98,4 +114,3 @@ info: [agg_i] Observations:... ... info: [agg_i] Aggregation (mean):... ``` - diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md b/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md index dbbabd4f10..98f2ba4d4c 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md @@ -1,23 +1,29 @@ ``` bash pip install aries-cloudagent ``` + ``` bash ./manage build ./manage start --logs -``` +``` + ``` bash aca-py start --help ``` + ``` bash aca-py start --admin 127.0.0.1 8021 --admin-insecure-mode --inbound-transport http 0.0.0.0 8020 --outbound-transport http --webhook-url http://127.0.0.1:8022/webhooks ``` + ``` bash aca-py start --admin 127.0.0.1 8031 --admin-insecure-mode --inbound-transport http 0.0.0.0 8030 --outbound-transp http --webhook-url http://127.0.0.1:8032/webhooks ``` + ``` bash aea fetch fetchai/aries_alice:0.32.4 cd aries_alice ``` + ``` bash aea create aries_alice cd aries_alice @@ -27,18 +33,23 @@ aea add connection fetchai/http_client:0.24.5 aea add connection fetchai/webhook:0.20.5 aea add skill fetchai/aries_alice:0.26.5 ``` + ``` bash aea config set vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host 127.0.0.1 ``` + ``` bash aea config set --type int vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port 8031 ``` + ``` bash aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032 ``` + ``` bash aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/ ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -49,17 +60,21 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:7000" }' ``` + ``` bash aea install aea build ``` + ``` bash aea run ``` + ``` bash aea fetch fetchai/aries_faber:0.32.4 cd aries_faber ``` + ``` bash aea create aries_faber cd aries_faber @@ -69,18 +84,23 @@ aea add connection fetchai/http_client:0.24.5 aea add connection fetchai/webhook:0.20.5 aea add skill fetchai/aries_faber:0.24.4 ``` + ``` bash aea config set vendor.fetchai.skills.aries_faber.models.strategy.args.admin_host 127.0.0.1 ``` + ``` bash aea config set --type int vendor.fetchai.skills.aries_faber.models.strategy.args.admin_port 8021 ``` + ``` bash aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022 ``` + ``` bash aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/ ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -91,14 +111,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:7001" }' ``` + ``` bash aea install aea build ``` + ``` bash aea run ``` + ``` bash aea delete aries_faber aea delete aries_alice -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md index 69849fb440..f13696b0f4 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md @@ -7,12 +7,14 @@ "public_uri": "127.0.0.1:9001" } ``` + ``` bash aea fetch fetchai/car_detector:0.32.4 cd car_detector aea install aea build ``` + ``` bash aea create car_detector cd car_detector @@ -33,12 +35,14 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/car_data_buyer:0.33.4 cd car_data_buyer aea install aea build ``` + ``` bash aea create car_data_buyer cd car_data_buyer @@ -59,35 +63,44 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt aea add-key fetchai fetchai_private_key.txt --connection ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -98,14 +111,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete car_detector aea delete car_data_buyer ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -117,4 +133,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md b/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md index d30ad741a6..b705c5edd0 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md @@ -1,15 +1,19 @@ ``` bash pip install aea[cli] ``` + ``` bash pip install aea[all] ``` + ``` bash pip install aea[all] --force --no-cache-dir ``` + ``` bash aea ``` + ``` bash python -m aea.cli -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md b/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md index b396decc5a..0db0e4c3dc 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md @@ -1,32 +1,40 @@ ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/packages ``` + ```bash pip install aea-ledger-fetchai ``` + ``` bash aea fetch fetchai/weather_station:0.32.4 cd weather_station aea install aea build ``` + ``` bash aea config set vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx False --type bool ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash python weather_client.py ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-config.md b/tests/test_docs/test_bash_yaml/md_files/bash-config.md index 2118557cd9..dadb92a2c3 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-config.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-config.md @@ -4,6 +4,7 @@ AUTHOR_REGEX: "[a-zA-Z_][a-zA-Z0-9_]*" PUBLIC_ID_REGEX: "^[a-zA-Z0-9_]*/[a-zA-Z_][a-zA-Z0-9_]*:(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" LEDGER_ID_REGEX: "^[^\\d\\W]\\w*\\Z" ``` + ``` yaml agent_name: my_agent # Name of the AEA project (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the project's author (must satisfy AUTHOR_REGEX) @@ -33,6 +34,7 @@ logging_config: # The logging configurations the version: 1 dependencies: {} # The python dependencies the AEA relies on (e.g. plugins). They will be installed when `aea install` is run. ``` + ``` yaml period: 0.05 # The period to call agent's act execution_timeout: 0 # The execution time limit on each call to `react` and `act` (0 disables the feature) @@ -47,11 +49,13 @@ decision_maker_handler: None # The decision maker handler to storage_uri: None # The URI to the storage. data_dir: None # The path to the directory for local files. Defaults to current working directory. ``` + ``` yaml public_id: some_author/some_package:0.1.0 # The public id of the connection (must satisfy PUBLIC_ID_REGEX). type: connection # for connections, this must be "connection". config: ... # a dictionary to overwrite the `config` field (see below) ``` + ``` yaml public_id: some_author/some_package:0.1.0 # The public id of the connection (must satisfy PUBLIC_ID_REGEX). type: skill # for skills, this must be "skill". @@ -68,6 +72,7 @@ models: # override configurations for mo args: # arguments for a specific model (see below) foo: bar ``` + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -90,6 +95,7 @@ restricted_to_protocols: [] # The list of protocol public id dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. is_abstract: false # An optional boolean that if `true` makes the connection ``` + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -108,6 +114,7 @@ config: # A dictionary containing the kw foo: bar dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) @@ -123,6 +130,7 @@ fingerprint: # Fingerprint of package compone fingerprint_ignore_patterns: [] # Ignore pattern for the fingerprinting tool. dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` + ``` yaml name: scaffold # Name of the package (must satisfy PACKAGE_REGEX) author: fetchai # Author handle of the package's author (must satisfy AUTHOR_REGEX) diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-connection.md b/tests/test_docs/test_bash_yaml/md_files/bash-connection.md index 6e31289201..d9acdb45cb 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-connection.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-connection.md @@ -1,6 +1,7 @@ ``` bash aea scaffold connection my_new_connection ``` + ``` yaml connections: [] protocols: [] @@ -12,4 +13,4 @@ restricted_to_protocols: [] dependencies: {} is_abstract: false cert_requests: [] -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-contract.md b/tests/test_docs/test_bash_yaml/md_files/bash-contract.md index 78c8a7c5c5..a2bf64e14b 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-contract.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-contract.md @@ -1,6 +1,7 @@ ``` bash aea scaffold contract my_new_contract ``` + ``` yaml contract_interface_paths: ethereum: build/my_contract.json diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-decision-maker.md b/tests/test_docs/test_bash_yaml/md_files/bash-decision-maker.md index ae5357d1e6..7236b4681c 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-decision-maker.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-decision-maker.md @@ -4,6 +4,7 @@ decision_maker_handler: dotted_path: "aea.decision_maker.gop:DecisionMakerHandler" file_path: null ``` + ``` bash aea scaffold decision-maker-handler ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md index 0815d2cd0e..f8e0b6ab38 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md @@ -4,6 +4,7 @@ cd erc1155_deployer aea install aea build ``` + ``` bash aea create erc1155_deployer cd erc1155_deployer @@ -29,26 +30,32 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash aea config set agent.default_ledger ethereum ``` + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea fetch fetchai/erc1155_client:0.34.4 cd erc1155_client aea install aea build ``` + ``` bash aea create erc1155_client cd erc1155_client @@ -74,35 +81,45 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash aea config set agent.default_ledger ethereum ``` + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat erc1155_deployer/ethereum_private_key.txt),1000000000000000000000" --account="$(cat erc1155_client/ethereum_private_key.txt),1000000000000000000000" ``` + ``` bash aea get-wealth ethereum ``` + ``` bash aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum ``` + ``` bash aea run ``` + ``` bash registering service on SOEF. ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -113,26 +130,31 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete erc1155_deployer aea delete erc1155_client ``` + ``` yaml default_routing: fetchai/contract_api:1.1.6: fetchai/ledger:0.21.4 fetchai/ledger_api:1.1.6: fetchai/ledger:0.21.4 fetchai/oef_search:1.1.6: fetchai/soef:0.27.5 ``` + ``` yaml default_routing: fetchai/contract_api:1.1.6: fetchai/ledger:0.21.4 fetchai/ledger_api:1.1.6: fetchai/ledger:0.21.4 fetchai/oef_search:1.1.6: fetchai/soef:0.27.5 ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -144,4 +166,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md index 36cd41efdb..a39ce9cabf 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md @@ -1,57 +1,71 @@ ``` bash sudo nano 99-hidraw-permissions.rules ``` + ``` bash KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev" ``` + ``` bash aea fetch fetchai/generic_seller:0.29.4 cd generic_seller aea eject skill fetchai/generic_seller:0.28.5 cd .. ``` + ``` bash aea fetch fetchai/generic_buyer:0.30.4 cd generic_buyer aea eject skill fetchai/generic_buyer:0.27.5 cd .. ``` + ``` bash aea init --reset --author fetchai ``` + ``` bash aea create my_generic_seller cd my_generic_seller aea install ``` + ``` bash aea scaffold skill generic_seller ``` + ``` bash aea fingerprint skill fetchai/generic_seller:0.1.0 ``` + ``` bash aea create my_generic_buyer cd my_generic_buyer aea install ``` + ``` bash aea scaffold skill generic_buyer ``` + ``` bash aea fingerprint skill fetchai/generic_buyer:0.1.0 ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea config set --type dict agent.default_routing \ '{ @@ -59,9 +73,11 @@ aea config set --type dict agent.default_routing \ "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" }' ``` + ``` bash aea generate-wealth fetchai --sync ``` + ``` bash aea add connection fetchai/p2p_libp2p:0.27.4 aea add connection fetchai/soef:0.27.5 @@ -72,7 +88,8 @@ aea build aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 aea run ``` -``` bash + +``` bash aea add connection fetchai/p2p_libp2p:0.27.4 aea add connection fetchai/soef:0.27.5 aea add connection fetchai/ledger:0.21.4 @@ -82,6 +99,7 @@ aea install aea build aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -92,14 +110,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` -``` bash + +``` bash cd .. aea delete my_generic_seller aea delete my_generic_buyer ``` + ``` yaml name: generic_seller author: fetchai @@ -172,6 +193,7 @@ models: is_abstract: false dependencies: {} ``` + ``` yaml name: generic_buyer author: fetchai @@ -258,6 +280,7 @@ models: is_abstract: false dependencies: {} ``` + ``` yaml config: delegate_uri: 127.0.0.1:11001 @@ -265,4 +288,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md index f171e956b9..ba02b69a6a 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md @@ -4,6 +4,7 @@ cd my_seller_aea aea install aea build ``` + ``` bash aea create my_seller_aea cd my_seller_aea @@ -24,12 +25,14 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/generic_buyer:0.30.4 --alias my_buyer_aea cd my_buyer_aea aea install aea build ``` + ``` bash aea create my_buyer_aea cd my_buyer_aea @@ -50,43 +53,54 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt aea add-key fetchai fetchai_private_key.txt --connection ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash cd my_seller_aea aea config set vendor.fetchai.skills.generic_seller.is_abstract false --type bool ``` + ``` bash cd my_buyer_aea aea config set vendor.fetchai.skills.generic_buyer.is_abstract false --type bool ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -97,14 +111,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete my_seller_aea aea delete my_buyer_aea ``` + ``` yaml models: ... @@ -126,6 +143,7 @@ models: unit_price: 10 class_name: GenericStrategy ``` + ``` yaml models: ... @@ -148,6 +166,7 @@ models: service_id: generic_service class_name: GenericStrategy ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -159,4 +178,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-gym-example.md b/tests/test_docs/test_bash_yaml/md_files/bash-gym-example.md index 12b4c53b9f..c1e16d9a9f 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-gym-example.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-gym-example.md @@ -2,9 +2,11 @@ svn export https://github.com/fetchai/agents-aea.git/trunk/examples svn export https://github.com/fetchai/agents-aea.git/trunk/packages ``` + ``` bash pip install numpy gym ``` + ``` bash python examples/gym_ex/train.py ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md index d94e219b8f..8602125ebf 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md @@ -2,41 +2,52 @@ mkdir gym_skill_agent svn export https://github.com/fetchai/agents-aea.git/trunk/examples ``` + ``` bash pip install numpy gym ``` + ``` bash aea fetch fetchai/gym_aea:0.26.4 --alias my_gym_aea cd my_gym_aea aea install ``` + ``` bash aea create my_gym_aea cd my_gym_aea ``` + ``` bash aea add skill fetchai/gym:0.21.5 ``` + ``` bash aea config set agent.default_connection fetchai/gym:0.20.5 ``` + ``` bash aea install ``` + ``` bash mkdir gyms cp -a ../examples/gym_ex/gyms/. gyms/ ``` + ``` bash aea config set vendor.fetchai.connections.gym.config.env 'gyms.env.BanditNArmedRandom' ``` + ``` bash aea generate-key fetchai aea add-key fetchai ``` + ``` bash aea run ``` + ``` bash cd .. aea delete my_gym_aea diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md index 610e2facfa..610b1491aa 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md @@ -2,34 +2,44 @@ aea create my_aea cd my_aea ``` + ``` bash aea add connection fetchai/http_server:0.23.5 ``` + ``` bash aea config set agent.default_connection fetchai/http_server:0.23.5 ``` + ``` bash aea config set vendor.fetchai.connections.http_server.config.api_spec_path "../examples/http_ex/petstore.yaml" ``` + ``` bash aea generate-key fetchai aea add-key fetchai ``` + ``` bash aea install ``` + ``` bash aea scaffold skill http_echo ``` + ``` bash aea fingerprint skill fetchai/http_echo:0.21.5 ``` + ``` bash aea config set vendor.fetchai.connections.http_server.config.target_skill_id "$(aea config get agent.author)/http_echo:0.1.0" ``` + ``` bash aea run ``` + ``` yaml handlers: http_handler: @@ -42,4 +52,4 @@ models: http_dialogues: args: {} class_name: HttpDialogues -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-language-agnostic-definition.md b/tests/test_docs/test_bash_yaml/md_files/bash-language-agnostic-definition.md index aace3deee7..32dc55fecb 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-language-agnostic-definition.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-language-agnostic-definition.md @@ -11,6 +11,7 @@ message Envelope{ string uri = 5; } ``` + ``` proto import "google/protobuf/struct.proto"; @@ -29,6 +30,7 @@ message Message { } } ``` + ``` proto syntax = "proto3"; @@ -69,4 +71,4 @@ message DefaultMessage{ Error_Performative error = 7; } } -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-logging.md b/tests/test_docs/test_bash_yaml/md_files/bash-logging.md index 0cb1d94593..cd82b2d9ce 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-logging.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-logging.md @@ -2,6 +2,7 @@ aea create my_aea cd my_aea ``` + ``` yaml agent_name: my_aea author: fetchai @@ -27,6 +28,7 @@ logging_config: version: 1 private_key_paths: {} ``` + ``` yaml logging_config: version: 1 @@ -52,6 +54,7 @@ logging_config: level: DEBUG propagate: False ``` + ``` yaml logging_config: version: 1 diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md index 6f0aba0895..c437a0938d 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md @@ -7,12 +7,14 @@ "public_uri": "127.0.0.1:9001" } ``` + ``` bash aea fetch fetchai/ml_data_provider:0.32.4 cd ml_data_provider aea install aea build -``` +``` + ``` bash aea create ml_data_provider cd ml_data_provider @@ -33,12 +35,14 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/ml_model_trainer:0.33.4 cd ml_model_trainer aea install aea build ``` + ``` bash aea create ml_model_trainer cd ml_model_trainer @@ -59,35 +63,44 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt aea add-key fetchai fetchai_private_key.txt --connection ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -98,14 +111,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete ml_data_provider aea delete ml_model_trainer ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -117,4 +133,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md b/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md index f6c140d02e..dcdb2c0f81 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md @@ -1,6 +1,7 @@ ``` bash python scripts/oef/launch.py -c ./scripts/oef/launch_config.json ``` + ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/examples svn export https://github.com/fetchai/agents-aea.git/trunk/scripts diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-oracle-demo.md b/tests/test_docs/test_bash_yaml/md_files/bash-oracle-demo.md index eb41bc7064..ad6b6b744e 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-oracle-demo.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-oracle-demo.md @@ -3,6 +3,7 @@ aea fetch fetchai/coin_price_oracle:0.17.5 cd coin_price_oracle aea install ``` + ``` bash aea create coin_price_oracle cd coin_price_oracle @@ -19,15 +20,19 @@ aea config set --type dict agent.dependencies \ aea config set agent.default_connection fetchai/ledger:0.21.4 aea install ``` + ``` bash aea config set --type str vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url "https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd" ``` + ``` bash aea config set --type list vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{"name": "price", "json_path": "fetch-ai.usd"}]' ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price ``` + ``` bash aea config set --type dict agent.default_routing \ '{ @@ -36,37 +41,47 @@ aea config set --type dict agent.default_routing \ "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" }' ``` + ``` bash aea config set agent.default_ledger fetchai ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value ``` + ``` bash LEDGER_ID=fetchai ``` + ``` bash LEDGER_ID=ethereum ``` + ``` bash aea config set agent.default_ledger ethereum ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id ethereum aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function updateOracleValue ``` + ``` bash aea generate-key $LEDGER_ID --add-key ``` + ``` bash aea generate-wealth $LEDGER_ID ``` + ``` bash aea fetch fetchai/coin_price_oracle_client:0.12.5 cd coin_price_oracle_client aea install ``` + ``` bash aea create coin_price_oracle_client cd coin_price_oracle_client @@ -81,6 +96,7 @@ aea config set --type dict agent.dependencies \ aea config set agent.default_connection fetchai/ledger:0.21.4 aea install ``` + ``` bash aea config set --type dict agent.default_routing \ '{ @@ -89,38 +105,49 @@ aea config set --type dict agent.default_routing \ "fetchai/ledger_api:1.1.6": "fetchai/ledger:0.21.4" }' ``` + ``` bash aea config set agent.default_ledger fetchai ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id fetchai aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function query_oracle_value ``` + ``` bash aea config set agent.default_ledger ethereum ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id ethereum aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function queryOracleValue ``` + ``` bash aea generate-key $LEDGER_ID --add-key ``` + ``` bash aea generate-wealth $LEDGER_ID ``` + ``` bash docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat coin_price_oracle/ethereum_private_key.txt),1000000000000000000000" --account="$(cat coin_price_oracle_client/ethereum_private_key.txt),1000000000000000000000" ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address $ERC20_ADDRESS ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address $ERC20_ADDRESS ``` + ``` bash aea run ``` + ``` bash info: [coin_price_oracle] Oracle contract successfully deployed at address: ... ... @@ -128,15 +155,19 @@ info: [coin_price_oracle] Oracle role successfully granted! ... info: [coin_price_oracle] Oracle value successfully updated! ``` + ``` bash aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address $ORACLE_ADDRESS ``` + ``` bash Oracle contract successfully deployed at address: ORACLE_ADDRESS ``` + ``` bash aea run ``` + ``` bash info: [coin_price_oracle_client] Oracle client contract successfully deployed at address: ... ... diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md b/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md index 018a0b876c..c524ad5735 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md @@ -4,6 +4,7 @@ cd my_thermometer_aea aea install aea build ``` + ``` bash aea create my_thermometer_aea cd my_thermometer_aea @@ -24,12 +25,14 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client cd my_thermometer_client aea install aea build ``` + ``` bash aea create my_thermometer_client cd my_thermometer_client @@ -50,44 +53,56 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea install aea build ``` + ``` bash aea eject skill fetchai/thermometer:0.27.5 ``` + ``` bash aea fingerprint skill {YOUR_AUTHOR_HANDLE}/thermometer:0.1.0 ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -98,14 +113,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` -``` bash + +``` bash cd .. aea delete my_thermometer_aea aea delete my_thermometer_client ``` + ``` yaml models: ... @@ -129,6 +147,7 @@ models: dependencies: SQLAlchemy: {} ``` + ``` yaml models: ... @@ -151,6 +170,7 @@ models: service_id: thermometer_data class_name: Strategy ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -162,4 +182,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md b/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md index a0ff917577..c2e95b3f7d 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md @@ -1,6 +1,7 @@ ``` bash pip install aea-ledger-fetchai ``` + ``` bash aea create my_genesis_aea cd my_genesis_aea @@ -9,6 +10,7 @@ aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt @@ -16,9 +18,11 @@ aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection aea issue-certificates ``` + ``` bash aea run --connections fetchai/p2p_libp2p:0.27.4 ``` + ``` bash aea create my_other_aea cd my_other_aea @@ -27,6 +31,7 @@ aea config set agent.default_connection fetchai/p2p_libp2p:0.27.4 aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt @@ -34,6 +39,7 @@ aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection aea issue-certificates ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -44,43 +50,53 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run --connections fetchai/p2p_libp2p:0.27.4 ``` - ``` bash - svn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p - cd p2p_libp2p - go build - chmod +x libp2p_node - ``` - ``` bash - docker build -t acn_node_standalone -f scripts/acn/Dockerfile . - ``` - ``` bash - python3 run_acn_node_standalone.py libp2p_node --config-from-env - ``` - ``` bash - python3 run_acn_node_standalone.py libp2p_node --config-from-file - ``` - ``` bash - docker run -v :/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config - ``` - ``` bash - python3 run_acn_node_standalone.py libp2p_node --key-file \ - --uri --uri-external \ - --uri-delegate \ - --entry-peers-maddrs ... - ``` - ``` bash - docker run -v :/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \ - --uri --uri-external \ - --uri-delegate \ - --entry-peers-maddrs ... - ``` + +``` bash +svn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p +cd p2p_libp2p +go build +chmod +x libp2p_node +``` + +``` bash +docker build -t acn_node_standalone -f scripts/acn/Dockerfile . +``` + +``` bash +python3 run_acn_node_standalone.py libp2p_node --config-from-env +``` + +``` bash +python3 run_acn_node_standalone.py libp2p_node --config-from-file +``` + +``` bash +docker run -v :/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config +``` + +``` bash +python3 run_acn_node_standalone.py libp2p_node --key-file \ + --uri --uri-external \ + --uri-delegate \ + --entry-peers-maddrs ... +``` + +``` bash +docker run -v :/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \ + --uri --uri-external \ + --uri-delegate \ + --entry-peers-maddrs ... +``` + ``` yaml /dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -90,4 +106,4 @@ config: entry_peers: [/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx,/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW] public_uri: null local_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md b/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md index e1d35cc409..fba206994b 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md @@ -27,6 +27,7 @@ aea_name/ skills/ Directory containing all the added skills from author_1 ... ... ``` + ``` yaml connections: - fetchai/stub:0.21.2 diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-performance-benchmark.md b/tests/test_docs/test_bash_yaml/md_files/bash-performance-benchmark.md index 739eaf6e9b..78bcd1a37e 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-performance-benchmark.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-performance-benchmark.md @@ -19,6 +19,7 @@ Options: -P, --plot INTEGER X axis parameter idx --help Show this message and exit. ``` + ``` bash Test execution timeout: 10.0 Test execution measure period: 0.1 @@ -47,6 +48,7 @@ mem min (kb): 53.98828125 ± 0 mem max (kb): 53.98828125 ± 0 mem mean (kb): 53.98828125 ± 0 ``` + ``` bash Test execution timeout: 10.0 Test execution measure period: 0.1 diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-por.md b/tests/test_docs/test_bash_yaml/md_files/bash-por.md index ff21da7f73..ac6831577e 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-por.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-por.md @@ -7,4 +7,4 @@ cert_requests: public_key: fetchai message_format: '{public_key}' save_path: .certs/conn_cert.txt -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-protocol-generator.md b/tests/test_docs/test_bash_yaml/md_files/bash-protocol-generator.md index 475333f6a1..a952d63538 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-protocol-generator.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-protocol-generator.md @@ -1,16 +1,20 @@ ``` bash aea generate protocol ``` + ``` bash aea generate protocol --l ``` + ``` bash aea create my_aea cd my_aea ``` + ``` bash aea generate protocol ../examples/protocol_specification_ex/sample.yaml ``` + ``` yaml --- name: two_party_negotiation diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md b/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md index bffbc621f5..9d495aaddc 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md @@ -1,50 +1,64 @@ ``` bash python3 --version ``` + ``` bash sudo apt-get install python3.7-dev ``` + ``` bash curl https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.sh --output install.sh chmod +x install.sh ./install.sh ``` + ```bash docker pull fetchai/aea-user:latest ``` + ```bash docker run -it -v $(pwd):/agents --workdir=/agents fetchai/aea-user:latest ``` + ```bash docker run -it -v %cd%:/agents --workdir=/agents fetchai/aea-user:latest ``` + ``` bash mkdir my_aea_projects/ cd my_aea_projects/ ``` + ``` bash which pipenv ``` + ``` bash touch Pipfile && pipenv --python 3.7 && pipenv shell ``` + ``` bash svn export https://github.com/fetchai/agents-aea.git/trunk/examples svn export https://github.com/fetchai/agents-aea.git/trunk/scripts svn export https://github.com/fetchai/agents-aea.git/trunk/packages ``` + ``` bash pip install aea[all] ``` + ``` bash sudo apt-get install python3.7-dev ``` -``` bash + +``` bash aea init ``` + ``` bash aea register ``` + ``` bash Do you have a Registry account? [y/N]: n Create a new account on the Registry now: @@ -63,36 +77,46 @@ v1.2.4 AEA configurations successfully initialized: {'author': 'fetchai'} ``` + ``` bash aea fetch fetchai/my_first_aea:0.28.4 cd my_first_aea ``` + ``` bash aea create my_first_aea cd my_first_aea ``` + ``` bash aea add connection fetchai/stub:0.21.2 ``` + ``` bash aea add skill fetchai/echo:0.20.5 ``` + ``` bash TO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE, ``` + ``` bash recipient_aea,sender_aea,fetchai/default:1.0.0,\x08\x01\x12\x011*\x07\n\x05hello, ``` + ``` bash aea install ``` + ``` bash aea generate-key fetchai aea add-key fetchai ``` + ``` bash aea run ``` + ``` bash _ _____ _ / \ | ____| / \ @@ -111,25 +135,30 @@ info: Echo Behaviour: act method called. info: Echo Behaviour: act method called. ... ``` + ``` bash cd my_first_aea aea interact ``` + ``` bash info: Echo Behaviour: act method called. info: Echo Handler: message=Message(dialogue_reference=('1', '') message_id=1 target=0 performative=bytes content=b'hello'), sender=my_first_aea_interact info: Echo Behaviour: act method called. info: Echo Behaviour: act method called. ``` + ``` bash echo 'my_first_aea,sender_aea,fetchai/default:1.0.0,\x12\x10\x08\x01\x12\x011*\t*\x07\n\x05hello,' >> input_file ``` + ``` bash info: Echo Behaviour: act method called. Echo Handler: message=Message(sender=sender_aea,to=my_first_aea,content=b'hello',dialogue_reference=('1', ''),message_id=1,performative=bytes,target=0), sender=sender_aea info: Echo Behaviour: act method called. info: Echo Behaviour: act method called. ``` + ``` bash info: Echo Behaviour: act method called. info: Echo Behaviour: act method called. @@ -138,12 +167,15 @@ my_first_aea stopping ... info: Echo Handler: teardown method called. info: Echo Behaviour: teardown method called. ``` + ``` bash aea interact ``` + ``` bash pytest test.py ``` + ``` bash aea delete my_first_aea ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-raspberry-set-up.md b/tests/test_docs/test_bash_yaml/md_files/bash-raspberry-set-up.md index 7e406051ff..3b9d8709c9 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-raspberry-set-up.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-raspberry-set-up.md @@ -3,32 +3,40 @@ sudo apt update -y sudo apt-get update sudo apt-get dist-upgrade ``` + ``` bash sudo apt install cmake golang -y ``` + ``` bash sudo apt install gfortran libatlas-base-dev libopenblas-dev -y ``` + ``` bash sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024 sudo /sbin/mkswap /var/swap.1 sudo chmod 600 /var/swap.1 sudo /sbin/swapon /var/swap.1 ``` + ``` bash pip install numpy --upgrade pip install scikit-image ``` + ``` bash sudo swapoff /var/swap.1 sudo rm /var/swap.1 ``` + ``` bash export PATH="$HOME/.local/bin:$PATH" ``` + ``` bash pip install aea[all] ``` + ``` bash aea --version ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-scaffolding.md b/tests/test_docs/test_bash_yaml/md_files/bash-scaffolding.md index faac445e5b..347959170b 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-scaffolding.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-scaffolding.md @@ -2,18 +2,23 @@ aea create my_aea --author "fetchai" cd my_aea ``` + ``` bash aea scaffold skill my_skill ``` + ``` bash aea scaffold protocol my_protocol ``` + ``` bash aea scaffold contract my_contract ``` + ``` bash aea scaffold connection my_connection ``` + ``` bash aea fingerprint [package_name] [public_id] ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md b/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md index b1329ed49f..ffeac7f375 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md @@ -2,12 +2,15 @@ aea create my_aea && cd my_aea aea scaffold skill my_search ``` + ``` bash aea fingerprint skill fetchai/my_search:0.1.0 ``` + ``` bash aea add protocol fetchai/oef_search:1.1.6 ``` + ``` bash aea add connection fetchai/soef:0.27.5 aea add connection fetchai/p2p_libp2p:0.27.4 @@ -19,34 +22,43 @@ aea config set --type dict agent.default_routing \ "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" }' ``` + ``` bash aea fetch fetchai/simple_service_registration:0.32.4 && cd simple_service_registration && aea install && aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -57,9 +69,11 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` yaml name: my_search author: fetchai @@ -101,6 +115,7 @@ dependencies: version: <2.0.0,>=1.0.0 is_abstract: false ``` + ``` yaml name: simple_service_registration author: fetchai @@ -153,4 +168,4 @@ models: class_name: Strategy dependencies: {} is_abstract: false -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-skill.md index f650539b0d..2cb97d9adc 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-skill.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-skill.md @@ -18,6 +18,7 @@ dependencies: {} protocols: - fetchai/default:1.1.6 ``` -``` + +``` bash aea scaffold error-handler -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md index 48815fbebf..6981da9532 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md @@ -4,6 +4,7 @@ cd tac_controller_contract aea install aea build ``` + ``` bash aea create tac_controller_contract cd tac_controller_contract @@ -31,6 +32,7 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash aea fetch fetchai/tac_participant_contract:0.22.4 --alias tac_participant_one cd tac_participant_one @@ -42,10 +44,12 @@ cd tac_participant_two aea install aea build ``` + ``` bash aea create tac_participant_one aea create tac_participant_two ``` + ``` bash cd tac_participant_one aea add connection fetchai/p2p_libp2p:0.27.4 @@ -79,6 +83,7 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash cd tac_participant_two aea add connection fetchai/p2p_libp2p:0.27.4 @@ -112,27 +117,34 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020 00:01' ``` + ``` bash aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time "$(date -d "5 minutes" +'%d %m %Y %H:%M')" ``` + ``` bash aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -143,6 +155,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -153,29 +166,36 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9002" }' ``` + ``` bash aea get-address fetchai ``` + ``` bash aea get-wealth fetchai ``` + ``` bash aea run ``` + ``` bash aea launch tac_participant_one tac_participant_two ``` + ``` bash aea delete tac_controller_contract aea delete tac_participant_one aea delete tac_participant_two ``` + ``` bash aea fetch fetchai/tac_controller_contract:0.32.4 cd tac_controller_contract aea install aea build ``` + ``` bash aea create tac_controller_contract cd tac_controller_contract @@ -203,6 +223,7 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash aea fetch fetchai/tac_participant_contract:0.22.4 --alias tac_participant_one cd tac_participant_one @@ -214,10 +235,12 @@ cd tac_participant_two aea install aea build ``` + ``` bash aea create tac_participant_one aea create tac_participant_two ``` + ``` bash cd tac_participant_one aea add connection fetchai/p2p_libp2p:0.27.4 @@ -251,6 +274,7 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ``` bash cd tac_participant_two aea add connection fetchai/p2p_libp2p:0.27.4 @@ -284,33 +308,41 @@ aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ aea install aea build ``` + ```bash aea config set agent.default_ledger ethereum json=$(printf '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2023-01-01", "not_before": "2022-01-01", "public_key": "fetchai", "message_format": "{public_key}", "save_path": ".certs/conn_cert.txt"}]') aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests "$json" aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum ``` + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020 00:01' ``` + ``` bash aea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time "$(date -d "5 minutes" +'%d %m %Y %H:%M')" ``` + ```bash aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.4 -u public_uri ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -321,6 +353,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -331,20 +364,25 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9002" }' ``` + ``` bash docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account="$(cat tac_controller_contract/ethereum_private_key.txt),1000000000000000000000" --account="$(cat tac_participant_one/ethereum_private_key.txt),1000000000000000000000" --account="$(cat tac_participant_two/ethereum_private_key.txt),1000000000000000000000" ``` + ``` bash aea get-wealth ethereum ``` + ``` bash aea run ``` + ``` bash aea launch tac_participant_one tac_participant_two ``` + ``` bash aea delete tac_controller_contract aea delete tac_participant_one aea delete tac_participant_two -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md index 7e512e0f10..616216c56f 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md @@ -7,6 +7,7 @@ "public_uri": "127.0.0.1:9001" } ``` + ``` bash { "delegate_uri": "127.0.0.1:11002", @@ -16,12 +17,14 @@ "public_uri": "127.0.0.1:9002" } ``` + ``` bash aea fetch fetchai/tac_controller:0.30.4 cd tac_controller aea install aea build ``` + ``` bash aea create tac_controller cd tac_controller @@ -42,6 +45,7 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/tac_participant:0.32.4 --alias tac_participant_one cd tac_participant_one @@ -52,10 +56,12 @@ aea fetch fetchai/tac_participant:0.32.4 --alias tac_participant_two cd tac_participant_two aea build ``` + ``` bash aea create tac_participant_one aea create tac_participant_two ``` + ``` bash cd tac_participant_one aea add connection fetchai/p2p_libp2p:0.27.4 @@ -82,6 +88,7 @@ aea config set --type dict agent.decision_maker_handler \ aea install aea build ``` + ``` bash cd tac_participant_two aea add connection fetchai/p2p_libp2p:0.27.4 @@ -108,27 +115,34 @@ aea config set --type dict agent.decision_maker_handler \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea config get vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time aea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time '01 01 2020 00:01' ``` + ``` bash aea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time "$(date -d "2 minutes" +'%d %m %Y %H:%M')" ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -139,6 +153,7 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -149,17 +164,21 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9002" }' ``` + ``` bash aea run ``` + ``` bash aea launch tac_participant_one tac_participant_two ``` + ``` bash aea delete tac_controller aea delete tac_participant_one aea delete tac_participant_two ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -171,6 +190,7 @@ config: log_file: libp2p_node.log public_uri: 127.0.0.1:9001 ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -181,4 +201,4 @@ config: local_uri: 127.0.0.1:9002 log_file: libp2p_node.log public_uri: 127.0.0.1:9002 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-tac.md b/tests/test_docs/test_bash_yaml/md_files/bash-tac.md index 0c5d52405c..bf98eeff7b 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-tac.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-tac.md @@ -1,21 +1,27 @@ ``` bash git clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac ``` + ``` bash which pipenv ``` + ``` bash pipenv --python 3.7 && pipenv shell ``` + ``` bash pipenv install ``` + ``` bash python setup.py install ``` + ``` bash python scripts/launch.py ``` + ``` bash git clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac pipenv --python 3.7 && pipenv shell @@ -23,13 +29,16 @@ python setup.py install cd sandbox && docker-compose build docker-compose up ``` + ``` bash pipenv shell python templates/v1/basic.py --name my_agent --dashboard ``` + ``` bash docker stop $(docker ps -q) ``` + ``` bash # mac docker ps -q | xargs docker stop ; docker system prune -a diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md index ab118ca6d3..846db8c224 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md @@ -7,12 +7,14 @@ "public_uri": "127.0.0.1:9001" } ``` -``` bash + +``` bash aea fetch fetchai/thermometer_aea:0.30.4 --alias my_thermometer_aea cd my_thermometer_aea aea install aea build ``` + ``` bash aea create my_thermometer_aea cd my_thermometer_aea @@ -29,12 +31,14 @@ aea config set --type dict agent.default_routing \ "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" }' ``` + ``` bash aea fetch fetchai/thermometer_client:0.32.4 --alias my_thermometer_client cd my_thermometer_client aea install aea build ``` + ``` bash aea create my_thermometer_client cd my_thermometer_client @@ -51,35 +55,44 @@ aea config set --type dict agent.default_routing \ "fetchai/oef_search:1.1.6": "fetchai/soef:0.27.5" }' ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt aea add-key fetchai fetchai_private_key.txt --connection ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -90,14 +103,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete my_thermometer_aea aea delete my_thermometer_client ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -109,4 +125,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-version.md b/tests/test_docs/test_bash_yaml/md_files/bash-version.md index 84a9a26ac0..11f7e1aef0 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-version.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-version.md @@ -1,3 +1,3 @@ ``` bash aea --version -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-wealth.md b/tests/test_docs/test_bash_yaml/md_files/bash-wealth.md index ca6d735c4b..af0fc22628 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-wealth.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-wealth.md @@ -1,32 +1,41 @@ ``` bash pip install aea-ledger-fetchai ``` + ``` bash pip install aea-ledger-ethereum ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key ethereum aea add-key ethereum ethereum_private_key.txt ``` + ``` bash aea get-address fetchai -``` +``` + ``` bash aea get-address ethereum ``` + ``` bash aea get-wealth fetchai ``` + ``` bash aea get-wealth ethereum ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-wealth ethereum ``` diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md index 354fc87f85..5f9527a23a 100644 --- a/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md +++ b/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md @@ -7,12 +7,14 @@ "public_uri": "127.0.0.1:9001" } ``` + ``` bash aea fetch fetchai/weather_station:0.32.4 --alias my_weather_station cd my_weather_station aea install aea build ``` + ``` bash aea create my_weather_station cd my_weather_station @@ -33,12 +35,14 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea fetch fetchai/weather_client:0.33.4 --alias my_weather_client cd my_weather_client aea install aea build ``` + ``` bash aea create my_weather_client cd my_weather_client @@ -59,35 +63,44 @@ aea config set --type dict agent.default_routing \ aea install aea build ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea generate-key fetchai aea add-key fetchai fetchai_private_key.txt aea add-key fetchai fetchai_private_key.txt --connection ``` + ``` bash aea generate-wealth fetchai ``` + ``` bash aea generate-key fetchai fetchai_connection_private_key.txt aea add-key fetchai fetchai_connection_private_key.txt --connection ``` + ``` bash aea issue-certificates ``` + ``` bash aea run ``` + ``` bash aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ '{ @@ -98,14 +111,17 @@ aea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \ "public_uri": "127.0.0.1:9001" }' ``` + ``` bash aea run ``` + ``` bash cd .. aea delete my_weather_station aea delete my_weather_client ``` + ``` yaml --- public_id: fetchai/p2p_libp2p:0.27.4 @@ -117,4 +133,4 @@ config: local_uri: 127.0.0.1:9001 log_file: libp2p_node.log public_uri: 127.0.0.1:9001 -``` \ No newline at end of file +``` diff --git a/tests/test_docs/test_language_agnostic_definition.py b/tests/test_docs/test_language_agnostic_definition.py index 36662c70a0..d15262661b 100644 --- a/tests/test_docs/test_language_agnostic_definition.py +++ b/tests/test_docs/test_language_agnostic_definition.py @@ -47,7 +47,7 @@ def _proto_snippet_selector(cls, block: Dict) -> bool: def setup_class(cls): """Set up the test.""" super().setup_class() - cls.code_blocks = list(filter(cls._proto_snippet_selector, cls.blocks)) + cls.code_blocks = list(filter(cls._proto_snippet_selector, cls.flat_blocks)) cls.actual_mail_base_file_content = MAIL_BASE_PROTO.read_text() cls.actual_default_message_file_content = DEFAULT_MESSAGE_PROTO.read_text() diff --git a/tests/test_docs/test_quickstart.py b/tests/test_docs/test_quickstart.py index d34158f34a..05a19616bb 100644 --- a/tests/test_docs/test_quickstart.py +++ b/tests/test_docs/test_quickstart.py @@ -36,7 +36,7 @@ def test_correct_echo_string(): """Test the echo string in the quickstart is using the correct protocol specification id.""" file_path = Path(ROOT_DIR, "docs", "quickstart.md") bash_code_blocks = extract_code_blocks(filepath=file_path, filter_="bash") - echo_bloc = bash_code_blocks[19] + echo_bloc = bash_code_blocks[24] default_protocol_spec_id = echo_bloc.split(",")[2] assert ( str(DefaultMessage.protocol_specification_id) == default_protocol_spec_id diff --git a/user-image/README.md b/user-image/README.md index 5caf7df12b..c2d6978b37 100644 --- a/user-image/README.md +++ b/user-image/README.md @@ -14,6 +14,6 @@ First, ./user-image/scripts/docker-publish-img.sh -And then, in `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=fetchai/aea-user:latest` and comment the alternative line, then run the publish command again: +And then, in `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=fetchai/aea-user:latest` and comment the alternative line, then run the publish command again: ./user-image/scripts/docker-publish-img.sh