diff --git a/.coveragerc b/.coveragerc index 1efb2816e0..21a2be6fe7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,5 +7,5 @@ omit = packages/fetchai/skills/erc1155_client/* packages/fetchai/skills/erc1155_deploy/* packages/fetchai/skills/gym/* - packages/fetchai/skills/registration_aw1/* + packages/fetchai/skills/fipa_dummy_buyer/* plugins/aea-ledger-cosmos/aea_ledger_cosmos/cosmos.py \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index b6beb97410..db1d24562e 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -149,8 +149,8 @@ jobs: run: tox -e package_version_checks - name: Check package dependencies run: tox -e package_dependencies_checks - - name: Check generate protocols - run: tox -e check_generate_all_protocols + # - name: Check generate protocols + # run: tox -e check_generate_all_protocols - name: Generate Documentation run: tox -e docs @@ -207,7 +207,39 @@ jobs: - name: Check aea dependenices and imports run: | tox -e dependencies_check - + plugins_install_check: + continue-on-error: False + runs-on: ${{ matrix.sys.os }} + strategy: + matrix: + sys: + - { os: windows-latest, shell: 'msys2 {0}' } + - { os: ubuntu-latest, shell: bash } + - { os: macos-latest, shell: bash } + python_version: [3.6] + timeout-minutes: 10 + steps: + - uses: actions/checkout@master + - if: matrix.sys.os == 'windows-latest' + uses: msys2/setup-msys2@v2 + - uses: actions/setup-python@master + with: + python-version: ${{ matrix.python_version }} + - name: Install tox + run : | + pip install tox + - name: Check plugin aea-ledger-cosmos + run : | + tox -r -e plugins_env -- sh -c "pip install ./plugins/aea-ledger-cosmos && aea generate-key cosmos && echo aea-ledger-cosmos checked!" + - name: Check plugin aea-ledger-ethereum + run : | + tox -r -e plugins_env -- sh -c "pip install ./plugins/aea-ledger-ethereum && aea generate-key ethereum && echo aea-ledger-ethereum checked!" + - name: Check plugin aea-ledger-fetchai + run : | + tox -r -e plugins_env -- sh -c "pip install ./plugins/aea-ledger-fetchai && aea generate-key fetchai && echo aea-ledger-fetchai checked!" + - name: Check plugin aea-cli-ipfs + run : | + tox -r -e plugins_env -- sh -c "pip install ./plugins/aea-cli-ipfs && aea ipfs --help && echo aea-cli-ipfs checked!" protolint: continue-on-error: False runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ff7e172de8..2b4e78d5b1 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,5 @@ packages/fetchai/connections/p2p_libp2p/libp2p_node/libp2p_node !plugins/aea-ledger-fetchai/tests/data/dummy_contract/build deploy-image/.env + +!libs/go/aea_end2end/seller_agent diff --git a/.spelling b/.spelling index fbaab9e45f..1d60a13e1e 100644 --- a/.spelling +++ b/.spelling @@ -186,6 +186,9 @@ install.ps1 pylint quickstart CVE-2021-27291 +AgentLand +GCloud +p2p - docs/language-agnostic-definition.md fetchai protocol_id diff --git a/HISTORY.md b/HISTORY.md index bae72b4082..00d6841a6c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,36 @@ # Release History +## 1.0.1 (2020-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 +- Ensures genus and classifications are used in all skills using SOEF +- Extends SOEF connection to implement `oef_search` protocol fully +- Handles SOEF failures in skills +- Adds simple aggregation skills including tests and docs +- Adds tests for registration AW agents +- Adds tests for reconnection logic in p2p connections +- 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 + ## 1.0.0 (2020-03-30) - Improves contributor guide diff --git a/Makefile b/Makefile index 3f583d7860..70ab85b23c 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,11 @@ install: clean .PHONY: dist dist: clean python setup.py sdist - python setup.py bdist_wheel + WIN_BUILD_WHEEL=1 python setup.py bdist_wheel --plat-name=win_amd64 + WIN_BUILD_WHEEL=1 python setup.py bdist_wheel --plat-name=win32 + python setup.py bdist_wheel --plat-name=manylinux1_x86_64 + python setup.py bdist_wheel --plat-name=manylinux2014_aarch64 + python setup.py bdist_wheel --plat-name=macosx_10_9_x86_64 h := $(shell git rev-parse --abbrev-ref HEAD) @@ -150,4 +154,4 @@ protolint: protolint_install_win: powershell -command '$$env:GO111MODULE="on"; go get -u -v github.com/yoheimuta/protolint/cmd/protolint@v0.27.0' protolint_win: - protolint lint -config_path=./protolint.yaml -fix ./aea/mail ./packages/fetchai/protocols \ No newline at end of file + protolint lint -config_path=./protolint.yaml -fix ./aea/mail ./packages/fetchai/protocols diff --git a/aea/__version__.py b/aea/__version__.py index ea8e2e6ba2..460085a0b7 100644 --- a/aea/__version__.py +++ b/aea/__version__.py @@ -22,7 +22,7 @@ __title__ = "aea" __description__ = "Autonomous Economic Agent framework" __url__ = "https://github.com/fetchai/agents-aea.git" -__version__ = "1.0.0" +__version__ = "1.0.1" __author__ = "Fetch.AI Limited" __license__ = "Apache-2.0" __copyright__ = "2019 Fetch.AI Limited" diff --git a/aea/cli/add.py b/aea/cli/add.py index ffea55151c..2a15571436 100644 --- a/aea/cli/add.py +++ b/aea/cli/add.py @@ -47,6 +47,7 @@ SkillConfig, ) from aea.configurations.constants import CONNECTION, CONTRACT, PROTOCOL, SKILL +from aea.exceptions import enforce @click.group() @@ -56,8 +57,18 @@ def add(click_context: click.Context, local: bool, remote: bool) -> None: """Add a package to the agent.""" ctx = cast(Context, click_context.obj) + enforce( + not (local and remote), "'local' and 'remote' options are mutually exclusive." + ) + if not local and not remote: + try: + ctx.registry_path + except ValueError as e: + click.echo(f"{e}\nTrying remote registry (`--remote`).") + remote = True + is_mixed = not local and not remote ctx.set_config("is_local", local and not remote) - ctx.set_config("is_mixed", not local and not remote) + ctx.set_config("is_mixed", is_mixed) @add.command() diff --git a/aea/cli/create.py b/aea/cli/create.py index a03a6b1f95..aa2f4bcccc 100644 --- a/aea/cli/create.py +++ b/aea/cli/create.py @@ -28,6 +28,7 @@ from aea import get_current_aea_version from aea.cli.add import add_item from aea.cli.init import do_init +from aea.cli.utils.click_utils import registry_flag from aea.cli.utils.config import get_or_create_cli_config from aea.cli.utils.constants import AUTHOR_KEY from aea.cli.utils.context import Context @@ -50,6 +51,7 @@ STATE_UPDATE_PROTOCOL, VENDOR, ) +from aea.exceptions import enforce from aea.helpers.base import compute_specifier_from_version from aea.helpers.io import open_file @@ -62,7 +64,10 @@ required=False, help="Add the author to run `init` before `create` execution.", ) -@click.option("--local", is_flag=True, help="For using local folder.") +@registry_flag( + help_local="For fetching agent from local folder.", + help_remote="For fetching agent from remote registry.", +) @click.option("--empty", is_flag=True, help="Not adding default dependencies.") @click.pass_context def create( @@ -70,11 +75,12 @@ def create( agent_name: str, author: str, local: bool, + remote: bool, empty: bool, ) -> None: """Create a new agent.""" ctx = cast(Context, click_context.obj) - create_aea(ctx, agent_name, local, author=author, empty=empty) + create_aea(ctx, agent_name, local, remote, author=author, empty=empty) @clean_after @@ -82,6 +88,7 @@ def create_aea( ctx: Context, agent_name: str, local: bool, + remote: bool = False, # for backwards compatibility author: Optional[str] = None, empty: bool = False, ) -> None: @@ -89,14 +96,29 @@ def create_aea( Create AEA project. :param ctx: Context object. - :param local: boolean flag for local folder usage. :param agent_name: agent name. - :param author: optional author name (valid with local=True only). + :param local: boolean flag for local registry usage. + :param remote: boolean flag for remote registry usage. + :param author: optional author name (valid with local=True and remote=False only). :param empty: optional boolean flag for skip adding default dependencies. :return: None :raises: ClickException if an error occurred. """ + enforce( + not (local and remote), "'local' and 'remote' options are mutually exclusive." + ) + if not local and not remote: + try: + ctx.registry_path + except ValueError as e: + click.echo(f"{e}\nTrying remote registry (`--remote`).") + remote = True + is_mixed = not local and not remote + is_local = local and not remote + ctx.set_config("is_local", is_local) + ctx.set_config("is_mixed", is_mixed) + try: _check_is_parent_folders_are_aea_projects_recursively() except Exception: @@ -105,7 +127,7 @@ def create_aea( ) if author is not None: - if local: + if is_local: do_init(author, False, False, False) # pragma: nocover else: raise click.ClickException( @@ -151,8 +173,6 @@ def create_aea( if not empty: click.echo("Adding default packages ...") - if local: - ctx.set_config("is_local", True) add_item(ctx, PROTOCOL, PublicId.from_str(DEFAULT_PROTOCOL)) add_item(ctx, PROTOCOL, PublicId.from_str(SIGNING_PROTOCOL)) add_item(ctx, PROTOCOL, PublicId.from_str(STATE_UPDATE_PROTOCOL)) diff --git a/aea/cli/fetch.py b/aea/cli/fetch.py index ac1ed6ec6e..c9a91c0b89 100644 --- a/aea/cli/fetch.py +++ b/aea/cli/fetch.py @@ -89,6 +89,12 @@ def do_fetch( enforce( not (local and remote), "'local' and 'remote' options are mutually exclusive." ) + if not local and not remote: + try: + ctx.registry_path + except ValueError as e: + click.echo(f"{e}\nTrying remote registry (`--remote`).") + remote = True is_mixed = not local and not remote ctx.set_config("is_local", local and not remote) ctx.set_config("is_mixed", is_mixed) @@ -131,8 +137,13 @@ def fetch_agent_locally( :param target_dir: the target directory to which the agent is fetched. :return: None """ + try: + registry_path = ctx.registry_path + except ValueError as e: + raise click.ClickException(str(e)) + source_path = try_get_item_source_path( - ctx.registry_path, public_id.author, AGENTS, public_id.name + registry_path, public_id.author, AGENTS, public_id.name ) enforce( ctx.config.get("is_local") is True or ctx.config.get("is_mixed") is True, diff --git a/aea/cli/issue_certificates.py b/aea/cli/issue_certificates.py index f9ea832c34..fd88d6078e 100644 --- a/aea/cli/issue_certificates.py +++ b/aea/cli/issue_certificates.py @@ -44,7 +44,7 @@ def issue_certificates(click_context: click.Context, password: Optional[str]) -> """Issue certificates for connections that require them.""" ctx = cast(Context, click_context.obj) agent_config_manager = AgentConfigManager.load(ctx.cwd) - issue_certificates_(ctx.cwd, agent_config_manager, password) + issue_certificates_(ctx.cwd, agent_config_manager, password=password) def issue_certificates_( @@ -124,7 +124,9 @@ def _process_certificate( connection_private_key_path, path_prefix ) connection_crypto = crypto_registry.make( - key_identifier, private_key_path=new_connection_private_key_path + key_identifier, + private_key_path=new_connection_private_key_path, + password=password, ) public_key = connection_crypto.public_key else: diff --git a/aea/cli/publish.py b/aea/cli/publish.py index 4508eec8d6..fe46c72a53 100644 --- a/aea/cli/publish.py +++ b/aea/cli/publish.py @@ -151,29 +151,26 @@ def _save_agent_locally(ctx: Context, is_mixed: bool = False) -> None: :return: None """ + try: + registry_path = ctx.registry_path + except ValueError as e: # pragma: nocover + raise click.ClickException(str(e)) for item_type_plural in (CONNECTIONS, CONTRACTS, PROTOCOLS, SKILLS): dependencies = getattr(ctx.agent_config, item_type_plural) for public_id in dependencies: if is_mixed: _check_is_item_in_registry_mixed( - PublicId.from_str(str(public_id)), - item_type_plural, - ctx.registry_path, + PublicId.from_str(str(public_id)), item_type_plural, registry_path, ) else: _check_is_item_in_local_registry( - PublicId.from_str(str(public_id)), - item_type_plural, - ctx.registry_path, + PublicId.from_str(str(public_id)), item_type_plural, registry_path, ) item_type_plural = AGENTS target_dir = try_get_item_target_path( - ctx.registry_path, - ctx.agent_config.author, - item_type_plural, - ctx.agent_config.name, + registry_path, ctx.agent_config.author, item_type_plural, ctx.agent_config.name, ) if not os.path.exists(target_dir): os.makedirs(target_dir, exist_ok=True) diff --git a/aea/cli/push.py b/aea/cli/push.py index 35287175b4..ec9795aa25 100644 --- a/aea/cli/push.py +++ b/aea/cli/push.py @@ -116,8 +116,12 @@ def _save_item_locally(ctx: Context, item_type: str, item_id: PublicId) -> None: check_package_public_id(source_path, item_type, item_id) + try: + registry_path = ctx.registry_path + except ValueError as e: # pragma: nocover + raise click.ClickException(str(e)) target_path = try_get_item_target_path( - ctx.registry_path, ctx.agent_config.author, item_type_plural, item_id.name, + registry_path, ctx.agent_config.author, item_type_plural, item_id.name, ) copytree(source_path, target_path) click.echo( diff --git a/aea/cli/search.py b/aea/cli/search.py index e2336a47b8..0422129515 100644 --- a/aea/cli/search.py +++ b/aea/cli/search.py @@ -172,10 +172,14 @@ def _search_items_locally(ctx: Context, item_type_plural: str) -> List[Dict]: result, ) + try: + registry_path = ctx.registry_path + except ValueError as e: # pragma: nocover + raise click.ClickException(str(e)) # look in packages dir for all other packages _get_details_from_dir( cast(ConfigLoader, configs[item_type_plural]["loader"]), - ctx.registry_path, + registry_path, "*/{}".format(item_type_plural), cast(str, configs[item_type_plural]["config_file"]), result, diff --git a/aea/cli/utils/context.py b/aea/cli/utils/context.py index 16939cb962..41f3c96a11 100644 --- a/aea/cli/utils/context.py +++ b/aea/cli/utils/context.py @@ -74,7 +74,7 @@ def registry_path(self) -> str: if registry_path.is_dir(): return str(registry_path) raise ValueError( - f"Registry path not provided and `{DEFAULT_REGISTRY_NAME}` not found in current ({self.cwd}) and parent directory." + f"Registry path not provided and local registry `{DEFAULT_REGISTRY_NAME}` not found in current ({self.cwd}) and parent directory." ) @property diff --git a/aea/cli/utils/package_utils.py b/aea/cli/utils/package_utils.py index 7795cc0c48..4c8d19370b 100644 --- a/aea/cli/utils/package_utils.py +++ b/aea/cli/utils/package_utils.py @@ -302,9 +302,14 @@ def find_item_locally( item_type_plural = item_type + "s" item_name = item_public_id.name + try: + registry_path = ctx.registry_path + except ValueError as e: + raise click.ClickException(str(e)) + # check in registry package_path = Path( - ctx.registry_path, item_public_id.author, item_type_plural, item_name + registry_path, item_public_id.author, item_type_plural, item_name ) config_file_name = _get_default_configuration_file_name_from_type(item_type) item_configuration_filepath = package_path / config_file_name diff --git a/aea/helpers/pipe.py b/aea/helpers/pipe.py index 574bebb236..5e450da4cb 100644 --- a/aea/helpers/pipe.py +++ b/aea/helpers/pipe.py @@ -316,7 +316,7 @@ async def close(self) -> None: wait_closed = getattr(self._writer, "wait_closed", None) if wait_closed: # in py3.6 writer does not have the coroutine - await wait_closed() #  pragma: nocover + await wait_closed() # pragma: nocover class TCPSocketChannel(IPCChannel): @@ -511,8 +511,13 @@ def __init__( # pylint: disable=unused-argument """ self.logger = logger self._loop = loop - - self._port = int(in_path) + parts = in_path.split(":") + if len(parts) == 1: + self._port = int(in_path) + self._host = "127.0.0.1" + else: # pragma: nocover + self._port = int(parts[1]) + self._host = parts[0] self._sock = None # type: Optional[TCPSocketProtocol] self._attempts = TCP_SOCKET_PIPE_CLIENT_CONN_ATTEMPTS @@ -538,7 +543,7 @@ async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool: self._attempts -= 1 try: reader, writer = await asyncio.open_connection( - "127.0.0.1", + self._host, self._port, # pylint: disable=protected-access loop=self._loop, ) diff --git a/aea/manager/project.py b/aea/manager/project.py index 8e00d08884..04d8aa2a04 100644 --- a/aea/manager/project.py +++ b/aea/manager/project.py @@ -270,7 +270,10 @@ def get_aea_instance(self) -> AEA: def issue_certificates(self) -> None: """Issue the certificates for this agent.""" issue_certificates_( - self.project.path, self.agent_config_manager, self._data_dir + self.project.path, + self.agent_config_manager, + path_prefix=self._data_dir, + password=self._password, ) def set_overrides( diff --git a/aea/protocols/dialogue/base.py b/aea/protocols/dialogue/base.py index e11a00a3b6..fd9b2ccc55 100644 --- a/aea/protocols/dialogue/base.py +++ b/aea/protocols/dialogue/base.py @@ -130,9 +130,12 @@ def dialogue_starter_addr(self) -> str: def __eq__(self, other: Any) -> bool: """Check for equality between two DialogueLabel objects.""" - if isinstance(other, DialogueLabel): - return hash(self) == hash(other) - return False + return ( + isinstance(other, DialogueLabel) + and self.dialogue_reference == other.dialogue_reference + and self.dialogue_opponent_addr == other.dialogue_opponent_addr + and self.dialogue_starter_addr == other.dialogue_starter_addr + ) def __hash__(self) -> int: """Turn object into hash.""" diff --git a/benchmark/checks/data/2021.04.01_v1_benchmark.txt b/benchmark/checks/data/2021.04.01_v1_benchmark.txt new file mode 100644 index 0000000000..c708499ff2 --- /dev/null +++ b/benchmark/checks/data/2021.04.01_v1_benchmark.txt @@ -0,0 +1,113 @@ +Performance report for 01.04.2021 +----------------------------- + +Multi agents with http dialogues: number of runs: 100, num_agents: 10, messages: 100 +------------------------------------------------------------------ +runtime mode duration value mean stdev +------------------------------------------------------------------ +async 2 mem 63.065273 0.41207 +async 5 mem 64.22625 0.379626 +async 10 mem 66.182461 0.40166 +async 20 mem 69.05918 0.282377 +async 30 mem 71.520469 0.438192 +async 50 mem 76.893984 0.882001 + + +Message generation and allocation: number of runs: 100 +------------------------------------------------------------------ +message value mean stdev +------------------------------------------------------------------ +10000 mem 0.304688 0.051566 +10000 time 0.509305 0.031975 +50000 mem 6.645781 0.065213 +50000 time 2.743519 0.10603 +100000 mem 14.294063 0.024781 +100000 time 5.541937 0.326452 + + +Dialogues message processing: number of runs: 100 +------------------------------------------------------------------ +message value mean stdev +------------------------------------------------------------------ +10000 mem 7.238008 0.065209 +10000 time 3.555162 0.141159 +20000 mem 14.319102 0.025112 +20000 time 6.942097 0.232013 +50000 mem 38.223203 0.139953 +50000 time 17.392467 0.503368 + + + +Reactive: number of runs: 100, duration: 10 +---------------------------------------------------- +runtime mode value mean stdev +---------------------------------------------------- +threaded latency 1350.913681 39.467721 +threaded rate 654.473 17.384876 +async latency 1094.870201 46.66503 +async rate 788.42 28.667664 + +Proactive: number of runs: 100, duration: 10 +---------------------------------------------------- +runtime mode value mean stdev +---------------------------------------------------- +threaded rate 3136.821 50.660694 +async rate 0.791 0.028762 + +MultiAgent: number of runs: 100, duration: 10, messages: 100 +------------------------------------------------------------------ +runtime mode num_agents value mean stdev +------------------------------------------------------------------ +threaded 2 rate 675.654 13.657716 +threaded 2 mem 48.126836 0.176016 +threaded 2 RTT 0.596222 0.011607 +threaded 2 latency 0.297669 0.005628 +threaded 4 rate 679.966 17.678088 +threaded 4 mem 49.095859 0.218971 +threaded 4 RTT 3.662645 0.078505 +threaded 4 latency 1.802625 0.03475 +threaded 8 rate 1449.882 281.714217 +threaded 8 mem 52.813281 0.467479 +threaded 8 RTT 19.373796 3.780258 +threaded 8 latency 10.401749 1.717344 +threaded 16 rate 4735.086 1410.656106 +threaded 16 mem 61.390781 1.540248 +threaded 16 RTT 60.171576 14.865577 +threaded 16 latency 35.057816 9.472234 +threaded 32 rate 14810.817 6722.336041 +threaded 32 mem 87.794141 8.46622 +threaded 32 RTT 189.72728 79.581276 +threaded 32 latency 122.309386 51.589368 +threaded 64 rate 27860.344 18340.58782 +threaded 64 mem 163.312305 44.267701 +threaded 64 RTT 419.02488 271.182984 +threaded 64 latency 282.563078 179.758986 +threaded 128 rate 49397.043 18398.274532 +threaded 128 mem 294.158906 103.471503 +threaded 128 RTT 855.809125 483.501904 +threaded 128 latency 568.189828 301.868828 +async 2 rate 670.926 13.463461 +async 2 mem 48.149766 0.174008 +async 2 RTT 0.597284 0.012575 +async 2 latency 0.298328 0.006285 +async 4 rate 609.235 11.144201 +async 4 mem 49.121719 0.154711 +async 4 RTT 3.841597 0.070842 +async 4 latency 1.858407 0.038073 +async 8 rate 548.831 25.953609 +async 8 mem 51.70832 0.193377 +async 8 RTT 2.237455 4.020524 +async 8 latency 6.375603 0.453957 +async 16 rate 2249.182 823.35554 +async 16 mem 55.84707 0.714784 +async 16 RTT 28.762427 25.072808 +async 16 latency 28.067046 12.508153 +async 32 rate 3961.37 3479.249814 +async 32 mem 70.209453 2.544705 +async 32 RTT 38.147726 78.039112 +async 32 latency 42.875331 68.118355 +async 64 rate 7647.276 2359.938405 +async 64 mem 132.389844 13.37811 +async 64 RTT 167.018874 138.893537 +async 64 latency 65.395231 79.366779 + diff --git a/deploy-image/Dockerfile b/deploy-image/Dockerfile index 28fd84e671..d91c96d732 100644 --- a/deploy-image/Dockerfile +++ b/deploy-image/Dockerfile @@ -16,7 +16,7 @@ RUN apk add --no-cache go # aea installation RUN pip install --upgrade pip -RUN pip install --upgrade --force-reinstall aea[all]==1.0.0 +RUN pip install --upgrade --force-reinstall aea[all]==1.0.1 # directories and aea cli config COPY /.aea /home/.aea diff --git a/develop-image/docker-env.sh b/develop-image/docker-env.sh index 9883e2579d..45a055e6a9 100755 --- a/develop-image/docker-env.sh +++ b/develop-image/docker-env.sh @@ -1,7 +1,7 @@ #!/bin/bash # Swap the following lines if you want to work with 'latest' -DOCKER_IMAGE_TAG=fetchai/aea-develop:1.0.0 +DOCKER_IMAGE_TAG=fetchai/aea-develop:1.0.1 # DOCKER_IMAGE_TAG=aea-develop:latest DOCKER_BUILD_CONTEXT_DIR=.. diff --git a/docs/aggregation-demo.md b/docs/aggregation-demo.md new file mode 100644 index 0000000000..0514feb161 --- /dev/null +++ b/docs/aggregation-demo.md @@ -0,0 +1,171 @@ +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 + +### Dependencies + +Follow the Preliminaries and Installation sections from the AEA quick start. + +## Demo + +### Create the AEAs + +Repeat the following process four times in four different terminals (for each {`i=0`, `i=1`, `i=2`, `i=3`}): + +Fetch the aggregator AEA: +``` bash +agent_name="agg$i" +aea fetch fetchai/simple_aggregator:0.1.0 --alias $agent_name +cd $agent_name +aea install +aea build +``` + +
Alternatively, create from scratch. +

+ +Create the AEA. + +``` bash +agent_name="agg$i" +aea create agent_name +cd agent_name +aea add connection fetchai/http_client:0.22.0 +aea add connection fetchai/http_server:0.21.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 +aea add connection fetchai/prometheus:0.7.0 +aea add skill fetchai/advanced_data_request:0.5.0 +aea add skill fetchai/simple_aggregation:0.1.0 + +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 +aea install +aea build +``` + +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 +``` + +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": "2022-01-01", "not_before": "2021-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 +aea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.search_query.search_value $SERVICE_ID +``` + +Additionally, create private keys for use with the ledger and the peer-to-peer connection: +``` 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 +``` + +Finally, certify the keys for use by the connections that request them: +``` bash +aea issue-certificates +``` + +### Configure the peer-to-peer network + +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 \ +'{ +"delegate_uri": "127.0.0.1:'$((11000+i))'", +"entry_peers": ["/dns4/127.0.0.1/tcp/9000/p2p/'"$MULTIADDR\""'], +"local_uri": "127.0.0.1:'$((9000+i))'", +"log_file": "libp2p_node.log", +"public_uri": "127.0.0.1:'$((9000+i))'" +}' +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) + +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.18.0 +aea add skill fetchai/simple_oracle:0.12.0 +``` + +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: +``` +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: +``` 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... +... +info: [agg_i] Fetching data from... +... +info: [agg_i] Observation: {'price': {'value':... +... +info: [agg_i] sending observation to peer... +... +info: [agg_i] received observation from sender... +... +info: [agg_i] Observations:... +... +info: [agg_i] Aggregation (mean):... +``` diff --git a/docs/aries-cloud-agent-demo.md b/docs/aries-cloud-agent-demo.md index 010549c9bb..69e1a599d2 100644 --- a/docs/aries-cloud-agent-demo.md +++ b/docs/aries-cloud-agent-demo.md @@ -180,7 +180,7 @@ Now you can create **Alice_AEA** and **Faber_AEA** in terminals 3 and 4 respecti In the third terminal, fetch **Alice_AEA** and move into its project folder: ``` bash -aea fetch fetchai/aries_alice:0.27.0 +aea fetch fetchai/aries_alice:0.28.0 cd aries_alice ``` @@ -191,11 +191,11 @@ The following steps create Alice_AEA from scratch: ``` bash aea create aries_alice cd aries_alice -aea add connection fetchai/p2p_libp2p:0.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/http_client:0.22.0 aea add connection fetchai/webhook:0.18.0 -aea add skill fetchai/aries_alice:0.21.0 +aea add skill fetchai/aries_alice:0.22.0 ```

@@ -257,14 +257,14 @@ Finally run **Alice_AEA**: 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.21.0 -u public_uri` to retrieve the address.) We will refer to this as **Alice_AEA's P2P address**. +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.22.0 -u public_uri` to retrieve the address.) We will refer to this as **Alice_AEA's P2P address**. ### Faber_AEA In the fourth terminal, fetch **Faber_AEA** and move into its project folder: ``` bash -aea fetch fetchai/aries_faber:0.27.0 +aea fetch fetchai/aries_faber:0.28.0 cd aries_faber ``` @@ -275,8 +275,8 @@ The following steps create Faber_AEA from scratch: ``` bash aea create aries_faber cd aries_faber -aea add connection fetchai/p2p_libp2p:0.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/http_client:0.22.0 aea add connection fetchai/webhook:0.18.0 aea add skill fetchai/aries_faber:0.20.0 diff --git a/docs/assets/simplified-aea.jpg b/docs/assets/simplified-aea.jpg index 4337707d5c..cf9af99106 100644 Binary files a/docs/assets/simplified-aea.jpg and b/docs/assets/simplified-aea.jpg differ diff --git a/docs/assets/simplified-aea_.jpg b/docs/assets/simplified-aea_.jpg index 9d1fe3b464..62bf29c0bb 100644 Binary files a/docs/assets/simplified-aea_.jpg and b/docs/assets/simplified-aea_.jpg differ diff --git a/docs/car-park-skills.md b/docs/car-park-skills.md index 9b4bdd0fb2..ed0a9c9bf2 100644 --- a/docs/car-park-skills.md +++ b/docs/car-park-skills.md @@ -43,6 +43,47 @@ This diagram shows the communication between the various entities as data is suc deactivate Car_Park_AEA deactivate Blockchain +
+ +# Option 1: AEA Manager approach + +Follow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below. + +## Preparation instructions + +Install the AEA Manager. + +## Demo instructions + +The following steps assume you have launched the AEA Manager Desktop app. + +1. Add a new AEA called `car_detector` with public id `fetchai/car_detector:0.28.0`. + +2. Add another new AEA called `car_data_buyer` with public id `fetchai/car_data_buyer:0.29.0`. + +3. Copy the address from the `car_data_buyer` into your clip board. Then go to the AgentLand block explorer and request some test tokens via `Get Funds`. + +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 update as follows: +``` 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 should see the agent trading successfully. +
+ +# Option 2: CLI approach + +Follow this approach when using the `aea` CLI. ## Preparation instructions @@ -56,7 +97,7 @@ Follow the Preliminaries and =1.0.0"} }' -aea config set agent.default_connection fetchai/p2p_libp2p:0.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -94,7 +135,7 @@ aea build Then, fetch the car data client AEA: ``` bash -aea fetch fetchai/car_data_buyer:0.28.0 +aea fetch fetchai/car_data_buyer:0.29.0 cd car_data_buyer aea install aea build @@ -107,19 +148,19 @@ 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.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add skill fetchai/carpark_client:0.25.0 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.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -184,7 +225,7 @@ First, run the car data seller AEA: 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.21.0 -u public_uri` to retrieve the address.) +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.22.0 -u public_uri` to retrieve the address.) 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): diff --git a/docs/cli-vs-programmatic-aeas.md b/docs/cli-vs-programmatic-aeas.md index ba778c1085..df7c8685cf 100644 --- a/docs/cli-vs-programmatic-aeas.md +++ b/docs/cli-vs-programmatic-aeas.md @@ -33,7 +33,7 @@ If you want to create the weather station AEA step by step you can follow this g Fetch the weather station AEA with the following command : ``` bash -aea fetch fetchai/weather_station:0.27.0 +aea fetch fetchai/weather_station:0.28.0 cd weather_station aea install aea build diff --git a/docs/config.md b/docs/config.md index fe00b7aec9..0caaca2295 100644 --- a/docs/config.md +++ b/docs/config.md @@ -27,7 +27,7 @@ protocols: # The list of protocol public id - fetchai/default:1.0.0 skills: # The list of skill public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX). - fetchai/error:0.16.0 -default_connection: fetchai/p2p_libp2p:0.21.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX). +default_connection: fetchai/p2p_libp2p:0.22.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX). default_ledger: fetchai # The default ledger identifier the AEA project uses (must satisfy LEDGER_ID_REGEX) required_ledgers: [fetchai] # the list of identifiers of ledgers that the AEA project requires key pairs for (each item must satisfy LEDGER_ID_REGEX) default_routing: {} # The default routing scheme applied to envelopes sent by the AEA, it maps from protocol public ids to connection public ids (both keys and values must satisfy PUBLIC_ID_REGEX) @@ -38,7 +38,7 @@ private_key_paths: # The private key paths the AEA logging_config: # The logging configurations the AEA project uses disable_existing_loggers: false version: 1 -dependencies: {} # The python dependencies the AEA relies on (e.g. plugins). +dependencies: {} # The python dependencies the AEA relies on (e.g. plugins). They will be installed when `aea install` is run. ``` The `aea-config.yaml` can be extended with a number of optional fields: @@ -107,7 +107,7 @@ config: # A dictionary containing the kw foo: bar excluded_protocols: [] # The list of protocol public ids the package does not permit (each public id must satisfy PUBLIC_ID_REGEX). restricted_to_protocols: [] # The list of protocol public ids the package is limited to (each public id must satisfy PUBLIC_ID_REGEX). -dependencies: {} # The python dependencies the package relies on. +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 ``` @@ -130,7 +130,7 @@ class_name: MyScaffoldContract # The class name of the class im contract_interface_paths: {} # The paths to the contract interfaces (one for each ledger identifier). config: # A dictionary containing the kwargs for the contract instantiation. foo: bar -dependencies: {} # The python dependencies the package relies on. +dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` ## Protocol configuration YAML @@ -149,7 +149,7 @@ fingerprint: # Fingerprint of package compone message.py: QmdvAdYSHNdZyUMrK3ue7quHAuSNwgZZSHqxYXyvh8Nie4 serialization.py: QmVUzwaSMErJgNFYQZkzsDhuuT2Ht4EdbGJ443usHmPxVv fingerprint_ignore_patterns: [] # Ignore pattern for the fingerprinting tool. -dependencies: {} # The python dependencies the package relies on. +dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` ## Skill configuration YAML @@ -188,5 +188,5 @@ models: # The dictionary describing the args: # Keyword arguments provided to the skill component on instantiation. foo: bar class_name: MyModel # The class name of the class implementing the model interface. -dependencies: {} # The python dependencies the package relies on. +dependencies: {} # The python dependencies the package relies on. They will be installed when `aea install` is run. ``` diff --git a/docs/connect-a-frontend.md b/docs/connect-a-frontend.md index c502e9fea5..0ccebe43bd 100644 --- a/docs/connect-a-frontend.md +++ b/docs/connect-a-frontend.md @@ -6,4 +6,4 @@ This page lays out two options for connecting a front-end to an AEA. The followi 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.21.0`) 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.21.0`). 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.22.0`). 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 diff --git a/docs/contract.md b/docs/contract.md index 8815b4fd65..37abf56d76 100644 --- a/docs/contract.md +++ b/docs/contract.md @@ -182,4 +182,4 @@ class MyContract(Contract): ``` 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.18.0` 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.21.0`, and skills using them, like `fetchai/erc1155_client:0.11.0` and `fetchai/erc1155_deploy:0.27.0`, for inspiration and guidance. +It helps to look at existing contract packages, like `fetchai/erc1155:0.21.0`, and skills using them, like `fetchai/erc1155_client:0.11.0` and `fetchai/erc1155_deploy:0.28.0`, for inspiration and guidance. diff --git a/docs/erc1155-skills.md b/docs/erc1155-skills.md index c423850ff1..b1a4b840bb 100644 --- a/docs/erc1155-skills.md +++ b/docs/erc1155-skills.md @@ -25,7 +25,7 @@ The scope of this guide is demonstrating how you can deploy a smart contract and Fetch the AEA that will deploy the contract: ``` bash -aea fetch fetchai/erc1155_deployer:0.29.0 +aea fetch fetchai/erc1155_deployer:0.30.0 cd erc1155_deployer aea install aea build @@ -39,22 +39,22 @@ Create the AEA that will deploy the contract. ``` bash aea create erc1155_deployer cd erc1155_deployer -aea add connection fetchai/p2p_libp2p:0.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 -aea add skill fetchai/erc1155_deploy:0.27.0 +aea add skill fetchai/erc1155_deploy:0.28.0 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.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/contract_api:1.0.0": "fetchai/ledger:0.18.0", "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2022-01-01", "not_before": "2021-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' @@ -95,7 +95,7 @@ aea issue-certificates In another terminal, fetch the client AEA which will receive some tokens from the deployer. ``` bash -aea fetch fetchai/erc1155_client:0.29.0 +aea fetch fetchai/erc1155_client:0.30.0 cd erc1155_client aea install aea build @@ -109,8 +109,8 @@ 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.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add skill fetchai/erc1155_client:0.26.0 aea config set --type dict agent.dependencies \ @@ -119,12 +119,12 @@ aea config set --type dict agent.dependencies \ "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.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/contract_api:1.0.0": "fetchai/ledger:0.18.0", "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \ '[{"identifier": "acn", "ledger_id": "ethereum", "not_after": "2022-01-01", "not_before": "2021-01-01", "public_key": "fetchai", "save_path": ".certs/conn_cert.txt"}]' @@ -199,7 +199,7 @@ aea run 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.21.0 -u public_uri` to retrieve the address. The output will be something like `/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm2JPsUX1Su59YVDXJQizYkNSe8JCusqRpLeeTbvY76fE5`. +Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.22.0 -u public_uri` to retrieve the address. The output will be something like `/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm2JPsUX1Su59YVDXJQizYkNSe8JCusqRpLeeTbvY76fE5`. This is the entry peer address for the local agent communication network created by the deployer. diff --git a/docs/generic-skills-step-by-step.md b/docs/generic-skills-step-by-step.md index e5249dc472..6f29619ee2 100644 --- a/docs/generic-skills-step-by-step.md +++ b/docs/generic-skills-step-by-step.md @@ -11,14 +11,14 @@ Follow the Preliminaries and `Behaviour` class contains Open the `behaviours.py` file (`my_generic_seller/skills/generic_seller/behaviours.py`) and replace the stub code with the following: ``` python -from typing import Any, cast +from typing import Any, Optional, cast +from aea.helpers.search.models import Description from aea.skills.behaviours import TickerBehaviour from packages.fetchai.connections.ledger.base import ( @@ -79,6 +80,7 @@ from packages.fetchai.skills.generic_seller.strategy import GenericStrategy DEFAULT_SERVICES_INTERVAL = 60.0 +DEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5 LEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID) @@ -90,8 +92,14 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): 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. @@ -111,7 +119,6 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): ) self.context.outbox.put_message(message=ledger_api_msg) self._register_agent() - self._register_service_personality_classification() def act(self) -> None: """ @@ -119,6 +126,7 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): :return: None """ + self._retry_failed_registration() def teardown(self) -> None: """ @@ -129,14 +137,42 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): self._unregister_service() self._unregister_agent() - def _register_agent(self) -> None: + def _retry_failed_registration(self) -> None: """ - Register the agent's location. + 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 """ - strategy = cast(GenericStrategy, self.context.strategy) - description = strategy.get_location_description() oef_search_dialogues = cast( OefSearchDialogues, self.context.oef_search_dialogues ) @@ -146,31 +182,51 @@ class GenericServiceRegistrationBehaviour(TickerBehaviour): service_description=description, ) self.context.outbox.put_message(message=oef_search_msg) - self.context.logger.info("registering agent on SOEF.") + self.context.logger.info(logger_msg) - def _register_service_personality_classification(self) -> None: + def _register_agent(self) -> None: """ - Register the agent's service, personality and classification. + Register the agent's location. :return: None """ strategy = cast(GenericStrategy, self.context.strategy) - descriptions = [ - strategy.get_register_service_description(), - strategy.get_register_personality_description(), - strategy.get_register_classification_description(), - ] - oef_search_dialogues = cast( - OefSearchDialogues, self.context.oef_search_dialogues + 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(GenericStrategy, 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(GenericStrategy, 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(GenericStrategy, self.context.strategy) + description = strategy.get_register_classification_description() + self._register( + description, "registering agent's personality classification on the SOEF." ) - for description in descriptions: - 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("registering service on SOEF.") def _unregister_service(self) -> None: """ @@ -281,6 +337,9 @@ from packages.fetchai.protocols.default.message import DefaultMessage from packages.fetchai.protocols.fipa.message import FipaMessage from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage from packages.fetchai.protocols.oef_search.message import OefSearchMessage +from packages.fetchai.skills.generic_seller.behaviours import ( + GenericServiceRegistrationBehaviour, +) from packages.fetchai.skills.generic_seller.dialogues import ( DefaultDialogues, FipaDialogue, @@ -745,7 +804,9 @@ class GenericOefSearchHandler(Handler): return # handle message - if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR: + 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) @@ -769,21 +830,88 @@ class GenericOefSearchHandler(Handler): ) ) + 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 + ) + ) + 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( + GenericServiceRegistrationBehaviour, + self.context.behaviours.service_registration, + ) + 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_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue + self, + oef_search_error_msg: OefSearchMessage, + oef_search_dialogue: OefSearchDialogue, ) -> None: """ Handle an oef search message. - :param oef_search_msg: the 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_msg, oef_search_dialogue + 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( + GenericServiceRegistrationBehaviour, + self.context.behaviours.service_registration, + ) + registration_behaviour.failed_registration_msg = target_message def _handle_invalid( self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue @@ -3162,7 +3290,7 @@ In both AEAs run: aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' ``` @@ -3179,13 +3307,13 @@ aea generate-wealth fetchai --sync Add the remaining packages for the seller AEA, then run it: ``` bash -aea add connection fetchai/p2p_libp2p:0.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add protocol fetchai/fipa:1.0.0 aea install aea build -aea config set agent.default_connection fetchai/p2p_libp2p:0.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea run ``` @@ -3196,14 +3324,14 @@ Once you see a message of the form `To join its network use multiaddr: ['SOME_AD Add the remaining packages for the buyer AEA: ``` bash -aea add connection fetchai/p2p_libp2p:0.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add protocol fetchai/fipa:1.0.0 aea add protocol fetchai/signing:1.0.0 aea install aea build -aea config set agent.default_connection fetchai/p2p_libp2p:0.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 ``` Then, update the configuration of the buyer AEA's P2P connection: diff --git a/docs/generic-skills.md b/docs/generic-skills.md index 47aa817bf4..126acd44be 100644 --- a/docs/generic-skills.md +++ b/docs/generic-skills.md @@ -58,7 +58,7 @@ Follow the Preliminaries and =1.0.0"} }' -aea config set agent.default_connection fetchai/p2p_libp2p:0.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -96,7 +96,7 @@ aea build Then, in another terminal fetch the buyer AEA: ``` bash -aea fetch fetchai/generic_buyer:0.25.0 --alias my_buyer_aea +aea fetch fetchai/generic_buyer:0.26.0 --alias my_buyer_aea cd my_buyer_aea aea install aea build @@ -109,19 +109,19 @@ 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.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add skill fetchai/generic_buyer:0.25.0 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.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -252,7 +252,7 @@ First, run the seller AEA: aea run ``` -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.21.0 -u public_uri` to retrieve the 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.22.0 -u public_uri` to retrieve the address.) 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: diff --git a/docs/http-connection-and-skill.md b/docs/http-connection-and-skill.md index d89069cbcc..7fc85cb54f 100644 --- a/docs/http-connection-and-skill.md +++ b/docs/http-connection-and-skill.md @@ -8,7 +8,7 @@ The HTTP server connection allows you to run a server inside the connection itse ## HTTP Client -The `fetchai/simple_data_request:0.11.0` skill demonstrates a simple use case of the HTTP Client connection. +The `fetchai/simple_data_request:0.12.0` skill demonstrates a simple use case of the HTTP Client connection. 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. diff --git a/docs/ml-skills.md b/docs/ml-skills.md index c9cc320c5b..f460619035 100644 --- a/docs/ml-skills.md +++ b/docs/ml-skills.md @@ -62,7 +62,7 @@ Follow the Preliminaries and =1.0.0"} }' -aea config set agent.default_connection fetchai/p2p_libp2p:0.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -100,7 +100,7 @@ aea build Then, fetch the model trainer AEA: ``` bash -aea fetch fetchai/ml_model_trainer:0.28.0 +aea fetch fetchai/ml_model_trainer:0.29.0 cd ml_model_trainer aea install aea build @@ -113,19 +113,19 @@ 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.21.0 -aea add connection fetchai/soef:0.22.0 +aea add connection fetchai/p2p_libp2p:0.22.0 +aea add connection fetchai/soef:0.23.0 aea add connection fetchai/ledger:0.18.0 aea add skill fetchai/ml_train:0.26.0 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.21.0 +aea config set agent.default_connection fetchai/p2p_libp2p:0.22.0 aea config set --type dict agent.default_routing \ '{ "fetchai/ledger_api:1.0.0": "fetchai/ledger:0.18.0", - "fetchai/oef_search:1.0.0": "fetchai/soef:0.22.0" + "fetchai/oef_search:1.0.0": "fetchai/soef:0.23.0" }' aea install aea build @@ -190,7 +190,7 @@ First, run the data provider AEA: 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.21.0 -u public_uri` to retrieve the address.) +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.22.0 -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.