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)
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))
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)
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)
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)
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)
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"))
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"))
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)
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)
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)
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"]))
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)
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"))
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"))
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)
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))
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)
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
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)
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"))
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"]))
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()
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"))
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"))
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"))
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"))
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)
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"))
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"]))