Example #1
0
def _find_connection_locally(ctx, connection_name):
    # check that the provided path points to a proper connection directory -> look for connection.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    connection_configuration_filepath = Path(os.path.join(registry_path, "connections", connection_name, DEFAULT_CONNECTION_CONFIG_FILE))
    if not connection_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        connection_configuration_filepath = Path(os.path.join(registry_path, "connections", connection_name, DEFAULT_CONNECTION_CONFIG_FILE))
        if not connection_configuration_filepath.exists():
            logger.error("Cannot find connection: '{}'.".format(connection_name))
            sys.exit(1)

    # try to load the connection configuration file
    try:
        connection_configuration = ctx.connection_loader.load(open(str(connection_configuration_filepath)))
        logger.info("Connection '{}' supports the following protocols: {}".format(connection_name, connection_configuration.restricted_to_protocols))
    except ValidationError as e:
        logger.error("Connection configuration file not valid: {}".format(str(e)))
        sys.exit(1)

    # copy the connection package into the agent's supported connections.
    src = str(Path(os.path.join(registry_path, "connections", connection_name)).absolute())
    dest = os.path.join(ctx.cwd, "connections", connection_name)
    logger.debug("Copying connection modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        sys.exit(1)
Example #2
0
def search(ctx: Context, registry):
    """Search for components in the registry.

    If called from an agent directory, it will check

    E.g.

        aea search connections
        aea search --registry skills
    """
    if registry:
        ctx.set_config("is_registry", True)
    else:
        # if we are in an agent directory, try to load the configuration file.
        # otherwise, use the default path (i.e. 'packages/' in the current directory.)
        try:
            try_to_load_agent_config(ctx, is_exit_on_except=False)
            # path = Path(DEFAULT_AEA_CONFIG_FILE)
            # fp = open(str(path), mode="r", encoding="utf-8")
            # agent_config = ctx.agent_loader.load(fp)
            registry_directory = ctx.agent_config.registry_path
        except Exception:
            registry_directory = os.path.join(ctx.cwd, DEFAULT_REGISTRY_PATH)

        ctx.set_config("registry_directory", registry_directory)
        logger.debug("Using registry {}".format(registry_directory))
Example #3
0
def _try_to_load_required_protocols(ctx: Context):
    for protocol_public_id in ctx.agent_config.protocols:
        protocol_name = protocol_public_id.name
        protocol_author = protocol_public_id.author
        logger.debug("Processing protocol {}".format(protocol_public_id))
        protocol_dir = Path("vendor", protocol_public_id.author, "protocols",
                            protocol_name)
        if not protocol_dir.exists():
            protocol_dir = Path("protocols", protocol_name)

        try:
            ctx.protocol_loader.load(
                open(protocol_dir / DEFAULT_PROTOCOL_CONFIG_FILE))
        except FileNotFoundError:
            logger.error(
                "Protocol configuration file for protocol {} not found.".
                format(protocol_name))
            sys.exit(1)

        try:
            protocol_package = load_agent_component_package(
                "protocol", protocol_name, protocol_author, protocol_dir)
            add_agent_component_module_to_sys_modules("protocol",
                                                      protocol_name,
                                                      protocol_author,
                                                      protocol_package)
        except Exception:
            logger.error(
                "A problem occurred while processing protocol {}.".format(
                    protocol_public_id))
            sys.exit(1)
Example #4
0
def _find_protocol_locally(ctx, protocol_name):
    # check that the provided path points to a proper protocol directory -> look for protocol.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    protocol_configuration_filepath = Path(os.path.join(registry_path, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))
    if not protocol_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        protocol_configuration_filepath = Path(os.path.join(registry_path, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))
        if not protocol_configuration_filepath.exists():
            logger.error("Cannot find protocol: '{}'.".format(protocol_name))
            sys.exit(1)

    # try to load the protocol configuration file
    try:
        protocol_configuration = ctx.protocol_loader.load(open(str(protocol_configuration_filepath)))
        logger.debug("Protocol available: {}".format(protocol_configuration.name))
    except ValidationError as e:
        logger.error("Protocol configuration file not valid: {}".format(str(e)))
        sys.exit(1)

    # copy the protocol package into the agent's supported connections.
    src = str(Path(os.path.join(registry_path, "protocols", protocol_name)).absolute())
    dest = os.path.join(ctx.cwd, "protocols", protocol_name)
    logger.debug("Copying protocol modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        sys.exit(1)
Example #5
0
def install(ctx: Context, requirement: Optional[str]):
    """Install the dependencies."""
    _try_to_load_agent_config(ctx)

    if requirement:
        logger.debug(
            "Installing the dependencies in '{}'...".format(requirement))
        dependencies = list(
            map(lambda x: x.strip(),
                open(requirement).readlines()))
    else:
        logger.debug("Installing all the dependencies...")
        dependencies = ctx.get_dependencies()

    for d in dependencies:
        logger.info("Installing {}...".format(d))
        try:
            subp = subprocess.Popen(
                [sys.executable, "-m", "pip", "install", d])
            subp.wait(30.0)
            assert subp.returncode == 0
        except Exception:
            logger.error(
                "An error occurred while installing {}. Stopping...".format(d))
            sys.exit(1)
Example #6
0
def _setup_package_folder(ctx, item_type_plural):
    """Set a package folder up."""
    Path(ctx.cwd, item_type_plural).mkdir()
    connections_init_module = os.path.join(ctx.cwd, item_type_plural,
                                           "__init__.py")
    logger.debug("Creating {}".format(connections_init_module))
    Path(connections_init_module).touch(exist_ok=True)
Example #7
0
def connection(ctx: Context, connection_name):
    """Remove a connection from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info(
        "Removing connection {connection_name} from the agent {agent_name}...".
        format(agent_name=agent_name, connection_name=connection_name))

    if connection_name not in ctx.agent_config.connections:
        logger.error("Connection '{}' not found.".format(connection_name))
        exit(-1)

    connection_folder = os.path.join("connections", connection_name)
    try:
        shutil.rmtree(connection_folder)
    except BaseException:
        logger.exception(
            "An error occurred while deleting '{}'.".format(connection_folder))
        exit(-1)

    # removing the connection to the configurations.
    logger.debug(
        "Removing the connection from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if connection_name in ctx.agent_config.connections:
        ctx.agent_config.connections.remove(connection_name)
        ctx.agent_loader.dump(ctx.agent_config,
                              open(DEFAULT_AEA_CONFIG_FILE, "w"))
Example #8
0
def protocol(ctx: Context, protocol_name):
    """Remove a protocol from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info(
        "Removing protocol {protocol_name} from the agent {agent_name}...".
        format(agent_name=agent_name, protocol_name=protocol_name))

    if protocol_name not in ctx.agent_config.protocols:
        logger.error("Protocol '{}' not found.".format(protocol_name))
        exit(-1)

    protocol_folder = os.path.join("protocols", protocol_name)
    try:
        shutil.rmtree(protocol_folder)
    except BaseException:
        logger.exception("An error occurred.")
        exit(-1)

    # removing the protocol to the configurations.
    logger.debug(
        "Removing the protocol from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if protocol_name in ctx.agent_config.protocols:
        ctx.agent_config.protocols.remove(protocol_name)
        ctx.agent_loader.dump(ctx.agent_config,
                              open(DEFAULT_AEA_CONFIG_FILE, "w"))
Example #9
0
def _install_dependency(dependency_name: str, dependency: Dependency):
    click.echo("Installing {}...".format(pprint.pformat(dependency_name)))
    try:
        index = dependency.get("index", None)
        git_url = dependency.get("git", None)
        revision = dependency.get("ref", "")
        version_constraint = dependency.get("version", "")
        command = [sys.executable, "-m", "pip", "install"]
        if git_url is not None:
            command += ["-i", index] if index is not None else []
            command += [
                "git+" + git_url + "@" + revision + "#egg=" + dependency_name
            ]
        else:
            command += ["-i", index] if index is not None else []
            command += [dependency_name + version_constraint]
        logger.debug("Calling '{}'".format(" ".join(command)))
        return_code = _try_install(command)
        if return_code == 1:
            # try a second time
            return_code = _try_install(command)
        assert return_code == 0
    except Exception as e:
        logger.error("An error occurred while installing {}, {}: {}".format(
            dependency_name, dependency, str(e)))
        sys.exit(1)
Example #10
0
def _verify_ledger_apis_access() -> None:
    """Verify access to ledger apis."""
    path = Path(DEFAULT_AEA_CONFIG_FILE)
    agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig)
    fp = open(str(path), mode="r", encoding="utf-8")
    aea_conf = agent_loader.load(fp)

    for identifier, value in aea_conf.ledger_apis.read_all():
        if identifier not in SUPPORTED_LEDGER_APIS:
            ValueError("Unsupported identifier in ledger apis.")

    fetchai_ledger_api_config = aea_conf.ledger_apis.read(FETCHAI)
    if fetchai_ledger_api_config is None:
        logger.debug("No fetchai ledger api config specified.")
    else:
        fetchai_ledger_api_config = cast(LedgerAPIConfig,
                                         fetchai_ledger_api_config)
        _try_to_instantiate_fetchai_ledger_api(fetchai_ledger_api_config.addr,
                                               fetchai_ledger_api_config.port)

    ethereum_ledger_config = aea_conf.ledger_apis.read(ETHEREUM)
    if ethereum_ledger_config is None:
        logger.debug("No ethereum ledger api config specified.")
    else:
        ethereum_ledger_config = cast(LedgerAPIConfig, ethereum_ledger_config)
        _try_to_instantiate_ethereum_ledger_api(ethereum_ledger_config.addr,
                                                ethereum_ledger_config.port)
Example #11
0
def _find_skill_locally(ctx, skill_name, click_context):
    # check that the provided path points to a proper skill directory -> look for skill.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    skill_configuration_filepath = Path(os.path.join(registry_path, "skills", skill_name, DEFAULT_SKILL_CONFIG_FILE))
    if not skill_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        skill_configuration_filepath = Path(os.path.join(registry_path, "skills", skill_name, DEFAULT_SKILL_CONFIG_FILE))
        if not skill_configuration_filepath.exists():
            logger.error("Cannot find skill: '{}'.".format(skill_name))
            sys.exit(1)

    # try to load the skill configuration file
    try:
        skill_configuration = ctx.skill_loader.load(open(str(skill_configuration_filepath)))
    except ValidationError as e:
        logger.error("Skill configuration file not valid: {}".format(str(e)))
        sys.exit(1)

    # copy the skill package into the agent's supported skills.
    src = str(Path(os.path.join(registry_path, "skills", skill_name)).absolute())
    dest = os.path.join(ctx.cwd, "skills", skill_name)
    logger.debug("Copying skill modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        sys.exit(1)

    # check for not supported protocol, and add it.
    for protocol_name in skill_configuration.protocols:
        if protocol_name not in ctx.agent_config.protocols:
            logger.debug("Adding protocol '{}' to the agent...".format(protocol_name))
            click_context.invoke(protocol, protocol_name=protocol_name)
Example #12
0
def publish_agent(ctx: Context):
    """Publish an agent."""
    try_to_load_agent_config(ctx)
    check_is_author_logged_in(ctx.agent_config.author)

    name = ctx.agent_config.agent_name
    agent_config_path = os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE)
    output_tar = os.path.join(ctx.cwd, "{}.tar.gz".format(name))
    _compress(output_tar, agent_config_path)

    data = {
        "name": name,
        "description": ctx.agent_config.description,
        "version": ctx.agent_config.version,
        "connections": ctx.agent_config.connections,
        "protocols": ctx.agent_config.protocols,
        "skills": ctx.agent_config.skills,
    }

    path = "/agents/create"
    logger.debug("Publishing agent {} to Registry ...".format(name))
    resp = request_api("POST",
                       path,
                       data=data,
                       is_auth=True,
                       filepath=output_tar)
    click.echo(
        "Successfully published agent {} to the Registry. Public ID: {}".
        format(name, resp["public_id"]))
Example #13
0
def _add_protocols(click_context, protocols: Collection[PublicId]):
    ctx = cast(Context, click_context.obj)
    # check for dependencies not yet added, and add them.
    for protocol_public_id in protocols:
        if protocol_public_id not in ctx.agent_config.protocols:
            logger.debug("Adding protocol '{}' to the agent...".format(
                protocol_public_id))
            _add_item(click_context, "protocol", protocol_public_id)
Example #14
0
def _add_item(click_context, item_type, item_public_id) -> None:
    """
    Add an item.

    :param click_context: the click context.
    :param item_type: the item type.
    :param item_public_id: the item public id.
    :return: None
    """
    ctx = cast(Context, click_context.obj)
    agent_name = cast(str, ctx.agent_config.agent_name)
    item_type_plural = item_type + "s"
    supported_items = getattr(ctx.agent_config, item_type_plural)

    is_local = ctx.config.get("is_local")

    click.echo("Adding {} '{}' to the agent '{}'...".format(
        item_type, item_public_id, agent_name))

    # check if we already have an item with the same name
    logger.debug("{} already supported by the agent: {}".format(
        item_type_plural.capitalize(), supported_items))
    if _is_item_present(item_type, item_public_id, ctx):
        logger.error("A {} with id '{}/{}' already exists. Aborting...".format(
            item_type, item_public_id.author, item_public_id.name))
        sys.exit(1)

    # find and add protocol
    if item_public_id in [DEFAULT_CONNECTION, DEFAULT_PROTOCOL, DEFAULT_SKILL]:
        package_path = _find_item_in_distribution(ctx, item_type,
                                                  item_public_id)
        _copy_package_directory(ctx, package_path, item_type,
                                item_public_id.name, item_public_id.author)
    elif is_local:
        package_path = _find_item_locally(ctx, item_type, item_public_id)
        _copy_package_directory(ctx, package_path, item_type,
                                item_public_id.name, item_public_id.author)
    else:
        package_path = fetch_package(item_type,
                                     public_id=item_public_id,
                                     cwd=ctx.cwd)
    if item_type in {"connection", "skill"}:
        configuration_file_name = _get_default_configuration_file_name_from_type(
            item_type)
        configuration_path = package_path / configuration_file_name
        configuration_loader = ConfigLoader.from_configuration_type(
            ConfigurationType(item_type))
        item_configuration = configuration_loader.load(
            configuration_path.open())
        _add_protocols(click_context, item_configuration.protocols)

    # add the item to the configurations.
    logger.debug("Registering the {} into {}".format(item_type,
                                                     DEFAULT_AEA_CONFIG_FILE))
    supported_items.add(item_public_id)
    ctx.agent_loader.dump(
        ctx.agent_config,
        open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #15
0
def _remove_item(ctx: Context, item_type, item_id: PublicId):
    """Remove an item from the configuration file and agent, given the public id."""
    item_name = item_id.name
    item_type_plural = "{}s".format(item_type)
    existing_item_ids = getattr(ctx.agent_config, item_type_plural)
    existing_items_name_to_ids = {
        public_id.name: public_id for public_id in existing_item_ids
    }

    agent_name = ctx.agent_config.agent_name
    click.echo(
        "Removing {item_type} '{item_name}' from the agent '{agent_name}'...".format(
            agent_name=agent_name, item_type=item_type, item_name=item_name
        )
    )

    if (
        item_id not in existing_items_name_to_ids.keys()
        and item_id not in existing_item_ids
    ):
        logger.error("The {} '{}' is not supported.".format(item_type, item_id))
        sys.exit(1)

    # TODO we assume the item in the agent config are necessarily in the agent projects.
    item_folder = Path("vendor", item_id.author, item_type_plural, item_name)
    if not item_folder.exists():
        # check if it is present in custom packages.
        item_folder = Path(item_type_plural, item_name)
        if not item_folder.exists():
            raise click.ClickException(
                "{} {} not found. Aborting.".format(item_type.title(), item_name)
            )
        elif (
            item_folder.exists() and not ctx.agent_config.author == item_id.author
        ):  # pragma: no cover
            raise click.ClickException(
                "{} {} author is different from {} agent author. "
                "Please fix the author field.".format(item_name, item_type, agent_name)
            )
        else:
            logger.debug(
                "Removing local {} {}.".format(item_type, item_name)
            )  # pragma: no cover

    try:
        shutil.rmtree(item_folder)
    except BaseException:
        logger.exception("An error occurred.")
        sys.exit(1)

    # removing the protocol to the configurations.
    item_public_id = existing_items_name_to_ids[item_name]
    logger.debug("Removing the {} from {}".format(item_type, DEFAULT_AEA_CONFIG_FILE))
    existing_item_ids.remove(item_public_id)
    ctx.agent_loader.dump(ctx.agent_config, open(DEFAULT_AEA_CONFIG_FILE, "w"))
Example #16
0
def install(click_context, requirement: Optional[str]):
    """Install the dependencies."""
    ctx = cast(Context, click_context.obj)

    if requirement:
        logger.debug(
            "Installing the dependencies in '{}'...".format(requirement))
        _install_from_requirement(requirement)
    else:
        logger.debug("Installing all the dependencies...")
        dependencies = ctx.get_dependencies()
        for name, d in dependencies.items():
            _install_dependency(name, d)
Example #17
0
def search(ctx: Context, registry):
    """Search for components in the registry.

    E.g.

        aea search --registry packages/ skills
    """
    if registry:
        ctx.set_config("is_registry", True)
    else:
        registry = os.path.join(ctx.cwd, DEFAULT_REGISTRY_PATH)
        ctx.set_config("registry", registry)
        logger.debug("Using registry {}".format(registry))
Example #18
0
def install(ctx: Context, requirement: Optional[str]):
    """Install the dependencies."""
    try_to_load_agent_config(ctx)

    if requirement:
        logger.debug(
            "Installing the dependencies in '{}'...".format(requirement))
        _install_from_requirement(requirement)
    else:
        logger.debug("Installing all the dependencies...")
        dependencies = ctx.get_dependencies()
        for name, d in dependencies.items():
            _install_dependency(name, d)
Example #19
0
def _setup_connection(connection_name: str, public_key: str,
                      ctx: Context) -> Connection:
    """
    Set up a connection.

    :param connection_name: the name of the connection.
    :param ctx: the CLI context object.
    :param public_key: the path of the public key.
    :return: a Connection object.
    :raises AEAConfigException: if the connection name provided as argument is not declared in the configuration file,
                              | or if the connection type is not supported by the framework.
    """
    if connection_name not in ctx.agent_config.connections:
        raise AEAConfigException(
            "Connection name '{}' not declared in the configuration file.".
            format(connection_name))

    try:
        connection_config = ctx.connection_loader.load(
            open(
                os.path.join(ctx.cwd, "connections", connection_name,
                             "connection.yaml")))
    except FileNotFoundError:
        raise AEAConfigException(
            "Connection config for '{}' not found.".format(connection_name))

    try:
        connection_spec = importlib.util.spec_from_file_location(
            connection_config.name,
            os.path.join(ctx.cwd, "connections", connection_config.name,
                         "connection.py"))
        connection_module = importlib.util.module_from_spec(connection_spec)
        connection_spec.loader.exec_module(connection_module)  # type: ignore
    except FileNotFoundError:
        raise AEAConfigException(
            "Connection '{}' not found.".format(connection_name))

    sys.modules[connection_spec.name + "_connection"] = connection_module
    classes = inspect.getmembers(connection_module, inspect.isclass)
    connection_classes = list(
        filter(lambda x: re.match("\\w+Connection", x[0]), classes))
    name_to_class = dict(connection_classes)
    connection_class_name = cast(str, connection_config.class_name)
    logger.debug("Processing connection {}".format(connection_class_name))
    connection_class = name_to_class.get(connection_class_name, None)
    if connection_class is None:
        raise AEAConfigException(
            "Connection class '{}' not found.".format(connection_class_name))

    connection = connection_class.from_config(public_key, connection_config)
    return connection
Example #20
0
def protocol(ctx: Context, protocol_name: str):
    """Add a protocol scaffolding to the configuration file and agent."""
    # check if we already have a protocol with the same name
    logger.debug("Protocols already supported by the agent: {}".format(
        ctx.agent_config.protocols))
    if protocol_name in ctx.agent_config.protocols:
        logger.error(
            "A protocol with name '{}' already exists. Aborting...".format(
                protocol_name))
        exit(-1)
        return

    try:
        # create the 'protocols' folder if it doesn't exist:
        if not os.path.exists("protocols"):
            os.makedirs("protocols")

        # create the protocol folder
        dest = Path(os.path.join("protocols", protocol_name))

        # copy the skill package into the agent's supported skills.
        src = Path(os.path.join(AEA_DIR, "protocols", "scaffold"))
        logger.info("Copying protocol modules. src={} dst={}".format(
            src, dest))
        try:
            shutil.copytree(src, dest)
        except Exception as e:
            logger.error(e)
            exit(-1)

        # add the protocol to the configurations.
        logger.info(
            "Registering the protocol into {}".format(DEFAULT_AEA_CONFIG_FILE))
        ctx.agent_config.protocols.add(protocol_name)
        ctx.agent_loader.dump(
            ctx.agent_config,
            open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))

    except OSError:
        logger.error("Directory already exist. Aborting...")
        exit(-1)
    except ValidationError as e:
        logger.error(str(e))
        shutil.rmtree(protocol_name, ignore_errors=True)
        exit(-1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(protocol_name, ignore_errors=True)
        exit(-1)
Example #21
0
def skill(click_context, skill_name):
    """Add a skill to the agent."""
    ctx = cast(Context, click_context.obj)
    agent_name = ctx.agent_config.agent_name
    logger.debug("Adding skill {} to the agent {}...".format(skill_name, agent_name))

    # check if we already have a skill with the same name
    logger.debug("Skills already supported by the agent: {}".format(ctx.agent_config.skills))
    if skill_name in ctx.agent_config.skills:
        logger.error("A skill with name '{}' already exists. Aborting...".format(skill_name))
        exit(-1)

    # check that the provided path points to a proper skill directory -> look for skill.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    skill_configuration_filepath = Path(os.path.join(registry_path, "skills", skill_name, DEFAULT_SKILL_CONFIG_FILE))
    if not skill_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        skill_configuration_filepath = Path(os.path.join(registry_path, "skills", skill_name, DEFAULT_SKILL_CONFIG_FILE))
        if not skill_configuration_filepath.exists():
            logger.error("Cannot find skill: '{}'.".format(skill_name))
            exit(-1)

    # try to load the skill configuration file
    try:
        skill_configuration = ctx.skill_loader.load(open(str(skill_configuration_filepath)))
    except ValidationError as e:
        logger.error("Skill configuration file not valid: {}".format(str(e)))
        exit(-1)

    # copy the skill package into the agent's supported skills.
    src = str(Path(os.path.join(registry_path, "skills", skill_name)).absolute())
    dest = os.path.join(ctx.cwd, "skills", skill_name)
    logger.info("Copying skill modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        exit(-1)

    # make the 'skills' folder a Python package.
    skills_init_module = os.path.join(ctx.cwd, "skills", "__init__.py")
    logger.debug("Creating {}".format(skills_init_module))
    Path(skills_init_module).touch(exist_ok=True)

    # check for not supported protocol, and add it.
    for protocol_name in skill_configuration.protocols:
        if protocol_name not in ctx.agent_config.protocols:
            logger.info("Adding protocol '{}' to the agent...".format(protocol_name))
            click_context.invoke(protocol, protocol_name=protocol_name)

    # add the skill to the configurations.
    logger.debug("Registering the skill into {}".format(DEFAULT_AEA_CONFIG_FILE))
    ctx.agent_config.skills.add(skill_name)
    ctx.agent_loader.dump(ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #22
0
def push_item(ctx: Context, item_type: str, item_id: PublicId) -> None:
    """
    Push item to the Registry.

    :param item_type: str type of item (connection/protocol/skill).
    :param item_id: str item name.

    :return: None
    """
    item_type_plural = item_type + "s"

    items_folder = os.path.join(ctx.cwd, item_type_plural)
    item_path = os.path.join(items_folder, item_id.name)

    item_config_filepath = os.path.join(item_path, "{}.yaml".format(item_type))
    logger.debug("Reading {} {} config ...".format(item_id.name, item_type))
    item_config = _load_yaml(item_config_filepath)
    check_is_author_logged_in(item_config["author"])

    logger.debug("Searching for {} {} in {} ...".format(
        item_id.name, item_type, items_folder))
    if not os.path.exists(item_path):
        raise click.ClickException(
            '{} "{}" not found  in {}. Make sure you run push command '
            "from a correct folder.".format(item_type.title(), item_id.name,
                                            items_folder))

    output_filename = "{}.tar.gz".format(item_id.name)
    logger.debug("Compressing {} {} to {} ...".format(item_id.name, item_type,
                                                      output_filename))
    _compress_dir(output_filename, item_path)
    output_filepath = os.path.join(ctx.cwd, output_filename)

    data = {
        "name": item_id.name,
        "description": item_config["description"],
        "version": item_config["version"],
    }

    # dependencies
    for key in ["connections", "contracts", "protocols", "skills"]:
        deps_list = item_config.get(key)
        if deps_list:
            data.update({key: deps_list})

    path = "/{}/create".format(item_type_plural)
    logger.debug("Pushing {} {} to Registry ...".format(
        item_id.name, item_type))
    resp = request_api("POST",
                       path,
                       data=data,
                       is_auth=True,
                       filepath=output_filepath)
    click.echo(
        "Successfully pushed {} {} to the Registry. Public ID: {}".format(
            item_type, item_id.name, resp["public_id"]))
Example #23
0
def run(ctx: Context, connection_name: str):
    """Run the agent."""
    _try_to_load_agent_config(ctx)
    agent_name = cast(str, ctx.agent_config.agent_name)
    private_key_pem_path = cast(str, ctx.agent_config.private_key_pem_path)
    if private_key_pem_path == "":
        private_key_pem_path = _create_temporary_private_key_pem_path()
    else:
        _try_validate_private_key_pem_path(private_key_pem_path)
    crypto = Crypto(private_key_pem_path=private_key_pem_path)
    public_key = crypto.public_key
    connection_name = ctx.agent_config.default_connection if connection_name is None else connection_name
    _try_to_load_protocols(ctx)
    try:
        connection = _setup_connection(connection_name, public_key, ctx)
    except AEAConfigException as e:
        logger.error(str(e))
        exit(-1)
        return

    logger.debug("Installing all the dependencies...")
    for d in ctx.get_dependencies():
        logger.debug("Installing {}...".format(d))
        try:
            subp = subprocess.Popen(
                [sys.executable, "-m", "pip", "install", d])
            subp.wait(30.0)
        except Exception:
            logger.error(
                "An error occurred while installing {}. Stopping...".format(d))
            exit(-1)

    mailbox = MailBox(connection)
    agent = AEA(agent_name,
                mailbox,
                private_key_pem_path=private_key_pem_path,
                directory=str(Path(".")))
    try:
        agent.start()
    except KeyboardInterrupt:
        logger.info("Interrupted.")
    except Exception as e:
        logger.exception(e)
    finally:
        agent.stop()
Example #24
0
def connection(click_context, connection_name):
    """Add a connection to the configuration file."""
    ctx = cast(Context, click_context.obj)
    agent_name = ctx.agent_config.agent_name
    logger.debug("Adding connection {} to the agent {}...".format(connection_name, agent_name))

    # check if we already have a connection with the same name
    logger.debug("Connection already supported by the agent: {}".format(ctx.agent_config.connections))
    if connection_name in ctx.agent_config.connections:
        logger.error("A connection with name '{}' already exists. Aborting...".format(connection_name))
        exit(-1)

    # check that the provided path points to a proper connection directory -> look for connection.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    connection_configuration_filepath = Path(os.path.join(registry_path, "connections", connection_name, DEFAULT_CONNECTION_CONFIG_FILE))
    if not connection_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        connection_configuration_filepath = Path(os.path.join(registry_path, "connections", connection_name, DEFAULT_CONNECTION_CONFIG_FILE))
        if not connection_configuration_filepath.exists():
            logger.error("Cannot find connection: '{}'.".format(connection_name))
            exit(-1)

    # try to load the connection configuration file
    try:
        connection_configuration = ctx.connection_loader.load(open(str(connection_configuration_filepath)))
        logger.info("Connection supports the following protocols: {}".format(connection_configuration.supported_protocols))
    except ValidationError as e:
        logger.error("Connection configuration file not valid: {}".format(str(e)))
        exit(-1)

    # copy the connection package into the agent's supported connections.
    src = str(Path(os.path.join(registry_path, "connections", connection_name)).absolute())
    dest = os.path.join(ctx.cwd, "connections", connection_name)
    logger.info("Copying connection modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        exit(-1)

    # make the 'connections' folder a Python package.
    connections_init_module = os.path.join(ctx.cwd, "connections", "__init__.py")
    logger.debug("Creating {}".format(connections_init_module))
    Path(connections_init_module).touch(exist_ok=True)

    # add the connections to the configurations.
    logger.debug("Registering the connection into {}".format(DEFAULT_AEA_CONFIG_FILE))
    ctx.agent_config.connections.add(connection_name)
    ctx.agent_loader.dump(ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #25
0
def protocol(click_context, protocol_name):
    """Add a protocol to the agent."""
    ctx = cast(Context, click_context.obj)
    agent_name = cast(str, ctx.agent_config.agent_name)
    logger.debug("Adding protocol {} to the agent {}...".format(protocol_name, agent_name))

    # check if we already have a protocol with the same name
    logger.debug("Protocols already supported by the agent: {}".format(ctx.agent_config.protocols))
    if protocol_name in ctx.agent_config.protocols:
        logger.error("A protocol with name '{}' already exists. Aborting...".format(protocol_name))
        exit(-1)

    # check that the provided path points to a proper protocol directory -> look for protocol.yaml file.
    # first check in aea dir
    registry_path = ctx.agent_config.registry_path
    protocol_configuration_filepath = Path(os.path.join(registry_path, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))
    if not protocol_configuration_filepath.exists():
        # then check in registry
        registry_path = AEA_DIR
        protocol_configuration_filepath = Path(os.path.join(registry_path, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))
        if not protocol_configuration_filepath.exists():
            logger.error("Cannot find protocol: '{}'.".format(protocol_name))
            exit(-1)

    # try to load the protocol configuration file
    try:
        protocol_configuration = ctx.protocol_loader.load(open(str(protocol_configuration_filepath)))
        logger.info("Protocol available: {}".format(protocol_configuration.name))
    except ValidationError as e:
        logger.error("Protocol configuration file not valid: {}".format(str(e)))
        exit(-1)
        return

    # copy the protocol package into the agent's supported connections.
    src = str(Path(os.path.join(registry_path, "protocols", protocol_name)).absolute())
    dest = os.path.join(ctx.cwd, "protocols", protocol_name)
    logger.info("Copying protocol modules. src={} dst={}".format(src, dest))
    try:
        shutil.copytree(src, dest)
    except Exception as e:
        logger.error(str(e))
        exit(-1)

    # make the 'protocols' folder a Python package.
    logger.debug("Creating {}".format(os.path.join(agent_name, "protocols", "__init__.py")))
    Path(os.path.join(ctx.cwd, "protocols", "__init__.py")).touch(exist_ok=True)

    # add the protocol to the configurations.
    logger.debug("Registering the protocol into {}".format(DEFAULT_AEA_CONFIG_FILE))
    ctx.agent_config.protocols.add(protocol_name)
    ctx.agent_loader.dump(ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #26
0
def connection(click_context, connection_name):
    """Add a connection to the configuration file."""
    ctx = cast(Context, click_context.obj)
    agent_name = ctx.agent_config.agent_name

    is_registry = ctx.config.get("is_registry")
    if is_registry:
        public_id = str(connection_name)
        connection_name = split_public_id(connection_name)[1]

    logger.info("Adding connection '{}' to the agent '{}'...".format(connection_name, agent_name))

    # check if we already have a connection with the same name
    logger.debug("Connections already supported by the agent: {}".format(ctx.agent_config.connections))
    if connection_name in ctx.agent_config.connections:
        logger.error("A connection with name '{}' already exists. Aborting...".format(connection_name))
        sys.exit(1)

    # find and add connection
    if is_registry:
        # fetch from Registry
        fetch_package('connection', public_id=public_id, cwd=ctx.cwd)
    else:
        _find_connection_locally(ctx, connection_name)

    # make the 'connections' folder a Python package.
    connections_init_module = os.path.join(ctx.cwd, "connections", "__init__.py")
    logger.debug("Creating {}".format(connections_init_module))
    Path(connections_init_module).touch(exist_ok=True)

    # add the connections to the configurations.
    logger.debug("Registering the connection into {}".format(DEFAULT_AEA_CONFIG_FILE))
    ctx.agent_config.connections.add(connection_name)
    ctx.agent_loader.dump(ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #27
0
def skill(click_context, skill_name):
    """Add a skill to the agent."""
    ctx = cast(Context, click_context.obj)
    agent_name = ctx.agent_config.agent_name

    is_registry = ctx.config.get("is_registry")
    if is_registry:
        public_id = str(skill_name)
        skill_name = split_public_id(skill_name)[1]

    logger.info("Adding skill '{}' to the agent '{}'...".format(skill_name, agent_name))

    # check if we already have a skill with the same name
    logger.debug("Skills already supported by the agent: {}".format(ctx.agent_config.skills))
    if skill_name in ctx.agent_config.skills:
        logger.error("A skill with name '{}' already exists. Aborting...".format(skill_name))
        sys.exit(1)

    # find and add protocol
    if is_registry:
        # fetch from Registry
        fetch_package('skill', public_id=public_id, cwd=ctx.cwd)
    else:
        _find_skill_locally(ctx, skill_name, click_context)

    # make the 'skills' folder a Python package.
    skills_init_module = os.path.join(ctx.cwd, "skills", "__init__.py")
    logger.debug("Creating {}".format(skills_init_module))
    Path(skills_init_module).touch(exist_ok=True)

    # add the skill to the configurations.
    logger.debug("Registering the skill into {}".format(DEFAULT_AEA_CONFIG_FILE))
    ctx.agent_config.skills.add(skill_name)
    ctx.agent_loader.dump(ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
Example #28
0
def fetch_package(obj_type: str, public_id: PublicId, cwd: str) -> Path:
    """
    Fetch connection/protocol/skill from Registry.

    :param obj_type: str type of object you want to fetch:
        'connection', 'protocol', 'skill'
    :param public_id: str public ID of object.
    :param cwd: str path to current working directory.

    :return: package path
    """
    logger.debug("Fetching {obj_type} {public_id} from Registry...".format(
        public_id=public_id, obj_type=obj_type))
    author, name, version = public_id.author, public_id.name, public_id.version
    item_type_plural = obj_type + "s"  # used for API and folder paths

    api_path = "/{}/{}/{}/{}".format(item_type_plural, author, name, version)
    resp = request_api("GET", api_path)
    file_url = resp["file"]

    logger.debug("Downloading {obj_type} {public_id}...".format(
        public_id=public_id, obj_type=obj_type))
    filepath = download_file(file_url, cwd)
    target_folder = os.path.join(cwd, "vendor", author, item_type_plural)

    logger.debug("Extracting {obj_type} {public_id}...".format(
        public_id=public_id, obj_type=obj_type))
    extract(filepath, target_folder)
    click.echo("Successfully fetched {obj_type}: {public_id}.".format(
        public_id=public_id, obj_type=obj_type))
    package_path = os.path.join(target_folder, public_id.name)
    return Path(package_path)
Example #29
0
def skill(ctx: Context, skill_name):
    """Remove a skill from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info("Removing skill '{skill_name}' from the agent '{agent_name}'..."
                .format(agent_name=agent_name, skill_name=skill_name))

    if skill_name not in ctx.agent_config.skills:
        logger.error("The skill '{}' is not supported.".format(skill_name))
        sys.exit(1)

    skill_folder = os.path.join("skills", skill_name)
    try:
        shutil.rmtree(skill_folder)
    except BaseException:
        logger.exception("An error occurred.")
        sys.exit(1)

    # removing the protocol to the configurations.
    logger.debug("Removing the skill from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if skill_name in ctx.agent_config.skills:
        ctx.agent_config.skills.remove(skill_name)
        ctx.agent_loader.dump(ctx.agent_config, open(DEFAULT_AEA_CONFIG_FILE, "w"))
Example #30
0
def publish_agent(ctx: Context):
    """Publish an agent."""
    try_to_load_agent_config(ctx)
    check_is_author_logged_in(ctx.agent_config.author)

    name = ctx.agent_config.agent_name
    config_file_source_path = os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE)
    output_tar = os.path.join(ctx.cwd, "{}.tar.gz".format(name))

    with tempfile.TemporaryDirectory() as temp_dir:
        package_dir = os.path.join(temp_dir, name)
        os.makedirs(package_dir)
        config_file_target_path = os.path.join(package_dir,
                                               DEFAULT_AEA_CONFIG_FILE)
        shutil.copy(config_file_source_path, config_file_target_path)

        _compress(output_tar, package_dir)

    data = {
        "name": name,
        "description": ctx.agent_config.description,
        "version": ctx.agent_config.version,
        "connections": ctx.agent_config.connections,
        "contracts": ctx.agent_config.contracts,
        "protocols": ctx.agent_config.protocols,
        "skills": ctx.agent_config.skills,
    }

    path = "/agents/create"
    logger.debug("Publishing agent {} to Registry ...".format(name))
    resp = request_api("POST",
                       path,
                       data=data,
                       is_auth=True,
                       filepath=output_tar)
    click.echo(
        "Successfully published agent {} to the Registry. Public ID: {}".
        format(name, resp["public_id"]))