class Context(object): """A class to keep configuration of the cli tool.""" agent_config: AgentConfig def __init__(self, cwd: str = "."): """Init the context.""" self.config = dict() # type: Dict self.agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) self.skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) self.connection_loader = ConfigLoader("connection-config_schema.json", ConnectionConfig) self.protocol_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) self.cwd = cwd def set_config(self, key, value) -> None: """ Set a config. :param key: the key for the configuration. :param value: the value associated with the key. :return: None """ self.config[key] = value logger.debug(' config[%s] = %s' % (key, value)) def get_dependencies(self) -> List[str]: """Aggregate the dependencies from every component. :return a list of dependency version specification. e.g. ["gym >= 1.0.0"] """ dependencies = [] # type: List[str] for protocol_id in self.agent_config.protocols: path = str( Path("protocols", protocol_id, DEFAULT_PROTOCOL_CONFIG_FILE)) protocol_config = self.protocol_loader.load(open(path)) deps = cast(List[str], protocol_config.dependencies) dependencies.extend(deps) for connection_id in self.agent_config.connections: path = str( Path("connections", connection_id, DEFAULT_CONNECTION_CONFIG_FILE)) connection_config = self.connection_loader.load(open(path)) deps = cast(List[str], connection_config.dependencies) dependencies.extend(deps) for skill_id in self.agent_config.skills: path = str(Path("skills", skill_id, DEFAULT_SKILL_CONFIG_FILE)) skill_config = self.skill_loader.load(open(path)) deps = cast(List[str], skill_config.dependencies) dependencies.extend(deps) return sorted(set(dependencies))
def verify_or_create_private_keys(ctx: Context) -> None: """ Verify or create private keys. :param ctx: Context """ path = Path(DEFAULT_AEA_CONFIG_FILE) agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in registry.supported_crypto_ids: ValueError("Unsupported identifier in private key paths.") for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items(): config_private_key_path = aea_conf.private_key_paths.read(identifier) if config_private_key_path is None: create_private_key(identifier) aea_conf.private_key_paths.update(identifier, private_key_path) else: try: _try_validate_private_key_path(identifier, private_key_path) except FileNotFoundError: # pragma: no cover raise click.ClickException( "File {} for private key {} not found.".format( repr(private_key_path), identifier, ) ) # update aea config path = Path(DEFAULT_AEA_CONFIG_FILE) fp = path.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) ctx.agent_config = aea_conf
def _add_protocol(self, directory: str, protocol_name: str): """ Add a protocol. :param directory: the agent's resources directory. :param protocol_name: the name of the protocol to be added. :return: None """ # get the serializer serialization_spec = importlib.util.spec_from_file_location("serialization", os.path.join(directory, "protocols", protocol_name, "serialization.py")) serialization_module = importlib.util.module_from_spec(serialization_spec) serialization_spec.loader.exec_module(serialization_module) # type: ignore classes = inspect.getmembers(serialization_module, inspect.isclass) serializer_classes = list(filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) serializer_class = serializer_classes[0][1] logger.debug("Found serializer class {serializer_class} for protocol {protocol_name}" .format(serializer_class=serializer_class, protocol_name=protocol_name)) serializer = serializer_class() config_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = config_loader.load(open(Path(directory, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))) # instantiate the protocol manager. protocol = Protocol(protocol_name, serializer, protocol_config) self.register((protocol_name, None), protocol)
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 from_dir(cls, directory: str) -> "Protocol": """ Load a protocol from a directory. :param directory: the skill directory. :param agent_context: the agent's context :return: the Protocol object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. protocol_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = protocol_loader.load( open(os.path.join(directory, DEFAULT_PROTOCOL_CONFIG_FILE))) protocol_module = load_module("protocols", Path(directory, "serialization.py")) add_agent_component_module_to_sys_modules("protocol", protocol_config.name, protocol_config.author, protocol_module) classes = inspect.getmembers(protocol_module, inspect.isclass) serializer_classes = list( filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) assert len( serializer_classes) == 1, "Not exactly one serializer detected." serializer_class = serializer_classes[0][1] protocol_id = PublicId(protocol_config.author, protocol_config.name, protocol_config.version) protocol = Protocol(protocol_id, serializer_class(), protocol_config) return protocol
def retrieve_details(name: str, loader: ConfigLoader, config_filepath: str): """Return description of a protocol, skill or connection.""" config = loader.load(open(str(config_filepath))) assert config.name == name return { "name": config.name, "description": config.description, "version": config.version }
def from_dir(cls, directory: str, agent_context: AgentContext) -> 'Skill': """ Load a skill from a directory. :param directory: the skill :param agent_context: the agent's context :return: the Skill object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load(open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) skills_spec = importlib.util.spec_from_file_location(skill_config.name, os.path.join(directory, "__init__.py")) skill_module = importlib.util.module_from_spec(skills_spec) sys.modules[skill_config.name + "_skill"] = skill_module loader_contents = [path.name for path in Path(directory).iterdir()] skills_packages = list(filter(lambda x: not x.startswith("__"), loader_contents)) # type: ignore logger.debug("Processing the following skill package: {}".format(skills_packages)) skill_context = SkillContext(agent_context) handlers_by_id = skill_config.handlers.read_all() if len(handlers_by_id) > 0: handlers_configurations = list(dict(handlers_by_id).values()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_configurations, skill_context) else: handlers = [] behaviours_by_id = skill_config.behaviours.read_all() if len(behaviours_by_id) > 0: behaviours_configurations = list(dict(behaviours_by_id).values()) behaviours = Behaviour.parse_module(os.path.join(directory, "behaviours.py"), behaviours_configurations, skill_context) else: behaviours = [] tasks_by_id = skill_config.tasks.read_all() if len(tasks_by_id) > 0: tasks_configurations = list(dict(tasks_by_id).values()) tasks = Task.parse_module(os.path.join(directory, "tasks.py"), tasks_configurations, skill_context) else: tasks = [] shared_classes_by_id = skill_config.shared_classes.read_all() if len(shared_classes_by_id) > 0: shared_classes_configurations = list(dict(shared_classes_by_id).values()) shared_classes_instances = SharedClass.parse_module(directory, shared_classes_configurations, skill_context) else: shared_classes_instances = [] skill = Skill(skill_config, skill_context, handlers, behaviours, tasks, shared_classes_instances) skill_context._skill = skill return skill
def from_dir(cls, directory: str, agent_context: AgentContext) -> "Skill": """ Load a skill from a directory. :param directory: the skill directory. :param agent_context: the agent's context :return: the Skill object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load( open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) skill_module = load_agent_component_package("skill", skill_config.name, skill_config.author, Path(directory)) add_agent_component_module_to_sys_modules("skill", skill_config.name, skill_config.author, skill_module) loader_contents = [path.name for path in Path(directory).iterdir()] skills_packages = list( filter(lambda x: not x.startswith("__"), loader_contents)) # type: ignore logger.debug("Processing the following skill package: {}".format( skills_packages)) skill_context = SkillContext(agent_context) # set the logger of the skill context. logger_name = "aea.{}.skills.{}.{}".format(agent_context.agent_name, skill_config.author, skill_config.name) skill_context._logger = logging.getLogger(logger_name) handlers_by_id = dict(skill_config.handlers.read_all()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_by_id, skill_context) behaviours_by_id = dict(skill_config.behaviours.read_all()) behaviours = Behaviour.parse_module( os.path.join(directory, "behaviours.py"), behaviours_by_id, skill_context, ) models_by_id = dict(skill_config.models.read_all()) model_instances = Model.parse_module(directory, models_by_id, skill_context) skill = Skill(skill_config, skill_context, handlers, behaviours, model_instances) skill_context._skill = skill return skill
def _verify_or_create_private_keys(aea_project_path: Path) -> None: """Verify or create private keys.""" path_to_configuration = aea_project_path / DEFAULT_AEA_CONFIG_FILE agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp_read = path_to_configuration.open(mode="r", encoding="utf-8") agent_configuration = agent_loader.load(fp_read) for identifier, _value in agent_configuration.private_key_paths.read_all(): if identifier not in SUPPORTED_CRYPTOS: ValueError("Unsupported identifier in private key paths.") fetchai_private_key_path = agent_configuration.private_key_paths.read(FETCHAI) if fetchai_private_key_path is None: _create_fetchai_private_key( private_key_file=str(aea_project_path / FETCHAI_PRIVATE_KEY_FILE) ) agent_configuration.private_key_paths.update(FETCHAI, FETCHAI_PRIVATE_KEY_FILE) else: try: _try_validate_fet_private_key_path( str(aea_project_path / fetchai_private_key_path), exit_on_error=False ) except FileNotFoundError: # pragma: no cover logger.error( "File {} for private key {} not found.".format( repr(fetchai_private_key_path), FETCHAI, ) ) raise ethereum_private_key_path = agent_configuration.private_key_paths.read(ETHEREUM) if ethereum_private_key_path is None: _create_ethereum_private_key( private_key_file=str(aea_project_path / ETHEREUM_PRIVATE_KEY_FILE) ) agent_configuration.private_key_paths.update( ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE ) else: try: _try_validate_ethereum_private_key_path( str(aea_project_path / ethereum_private_key_path), exit_on_error=False ) except FileNotFoundError: # pragma: no cover logger.error( "File {} for private key {} not found.".format( repr(ethereum_private_key_path), ETHEREUM, ) ) raise fp_write = path_to_configuration.open(mode="w", encoding="utf-8") agent_loader.dump(agent_configuration, fp_write)
def _retrieve_details(name: str, loader: ConfigLoader, config_filepath: str) -> Dict: """Return description of a protocol, skill, connection.""" config = loader.load(open(str(config_filepath))) item_name = config.agent_name if isinstance(config, AgentConfig) else config.name assert item_name == name return { "public_id": str(config.public_id), "name": item_name, "author": config.author, "description": config.description, "version": config.version, }
def _add_protocol( self, protocol_directory: Path, allowed_protocols: Optional[Set[PublicId]] = None, ): """ Add a protocol. If the protocol is not allowed, it is ignored. :param protocol_directory: the directory of the protocol to be added. :param allowed_protocols: an optional set of allowed protocols. If None, every protocol is allowed. :return: None """ protocol_name = protocol_directory.name config_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = config_loader.load( open(protocol_directory / DEFAULT_PROTOCOL_CONFIG_FILE)) protocol_public_id = PublicId(protocol_config.author, protocol_config.name, protocol_config.version) if (allowed_protocols is not None and protocol_public_id not in allowed_protocols): logger.debug( "Ignoring protocol {}, not declared in the configuration file." .format(protocol_public_id)) return # get the serializer serialization_spec = importlib.util.spec_from_file_location( "serialization", protocol_directory / "serialization.py") serialization_module = importlib.util.module_from_spec( serialization_spec) serialization_spec.loader.exec_module( serialization_module) # type: ignore classes = inspect.getmembers(serialization_module, inspect.isclass) serializer_classes = list( filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) serializer_class = serializer_classes[0][1] logger.debug( "Found serializer class {serializer_class} for protocol {protocol_name}" .format(serializer_class=serializer_class, protocol_name=protocol_name)) serializer = serializer_class() # instantiate the protocol protocol = Protocol(protocol_config.public_id, serializer, protocol_config) self.register(protocol_public_id, protocol)
def retrieve_details(name: str, loader: ConfigLoader, config_filepath: str) -> Dict: """Return description of a protocol, skill, connection.""" with open(str(config_filepath)) as fp: config = loader.load(fp) item_name = config.agent_name if isinstance(config, AgentConfig) else config.name enforce(item_name == name, "Item names do not match!") return { "public_id": str(config.public_id), "name": item_name, "author": config.author, "description": config.description, "version": config.version, }
def _verify_or_create_private_keys(ctx: Context) -> None: """ Verify or create private keys. :param ctx: Context """ path = Path(DEFAULT_AEA_CONFIG_FILE) agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in SUPPORTED_CRYPTOS: ValueError("Unsupported identifier in private key paths.") fetchai_private_key_path = aea_conf.private_key_paths.read(FETCHAI) if fetchai_private_key_path is None: _create_fetchai_private_key() aea_conf.private_key_paths.update(FETCHAI, FETCHAI_PRIVATE_KEY_FILE) else: try: _try_validate_fet_private_key_path(fetchai_private_key_path) except FileNotFoundError: # pragma: no cover logger.error("File {} for private key {} not found.".format( repr(fetchai_private_key_path), FETCHAI, )) sys.exit(1) ethereum_private_key_path = aea_conf.private_key_paths.read(ETHEREUM) if ethereum_private_key_path is None: _create_ethereum_private_key() aea_conf.private_key_paths.update(ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE) else: try: _try_validate_ethereum_private_key_path(ethereum_private_key_path) except FileNotFoundError: # pragma: no cover logger.error("File {} for private key {} not found.".format( repr(ethereum_private_key_path), ETHEREUM, )) sys.exit(1) # update aea config path = Path(DEFAULT_AEA_CONFIG_FILE) fp = path.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) ctx.agent_config = aea_conf
def verify_or_create_private_keys( aea_project_path: Path, exit_on_error: bool = True, ) -> AgentConfig: """ Verify or create private keys. :param ctx: Context """ path_to_aea_config = aea_project_path / DEFAULT_AEA_CONFIG_FILE agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path_to_aea_config.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in crypto_registry.supported_ids: # pragma: nocover ValueError("Unsupported identifier in private key paths.") for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items(): config_private_key_path = aea_conf.private_key_paths.read(identifier) if config_private_key_path is None: if identifier == aea_conf.default_ledger: # pragma: nocover create_private_key( identifier, private_key_file=str(aea_project_path / private_key_path), ) aea_conf.private_key_paths.update(identifier, private_key_path) else: try: try_validate_private_key_path( identifier, str(aea_project_path / private_key_path), exit_on_error=exit_on_error, ) except FileNotFoundError: # pragma: no cover raise ValueError( "File {} for private key {} not found.".format( repr(private_key_path), identifier, )) # update aea config fp = path_to_aea_config.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) return aea_conf
def from_dir(cls, directory: str, agent_context: AgentContext) -> Optional['Skill']: """ Load a skill from a directory. :param directory: the skill :param agent_context: the agent's context :return: the Skill object. None if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load(open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) if skill_config is None: return None skills_spec = importlib.util.spec_from_file_location(skill_config.name, os.path.join(directory, "__init__.py")) if skills_spec is None: logger.warning("No skill found.") return None skill_module = importlib.util.module_from_spec(skills_spec) sys.modules[skill_config.name + "_skill"] = skill_module skills_packages = list(filter(lambda x: not x.startswith("__"), skills_spec.loader.contents())) # type: ignore logger.debug("Processing the following skill package: {}".format(skills_packages)) skill_context = SkillContext(agent_context) handlers_configurations = list(dict(skill_config.handlers.read_all()).values()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_configurations, skill_context) behaviours_configurations = list(dict(skill_config.behaviours.read_all()).values()) behaviours = Behaviour.parse_module(os.path.join(directory, "behaviours.py"), behaviours_configurations, skill_context) tasks_configurations = list(dict(skill_config.tasks.read_all()).values()) tasks = Task.parse_module(os.path.join(directory, "tasks.py"), tasks_configurations, skill_context) shared_classes_configurations = list(dict(skill_config.shared_classes.read_all()).values()) shared_classes_instances = SharedClass.parse_module(directory, shared_classes_configurations, skill_context) skill = Skill(skill_config, skill_context, handlers, behaviours, tasks, shared_classes_instances) skill_context._skill = skill return skill
def _verify_or_create_private_keys(ctx: Context) -> None: """ Verify or create private keys. :param ctx: Context """ 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.private_key_paths.read_all(): if identifier not in SUPPORTED_CRYPTOS: ValueError("Unsupported identifier in private key paths.") default_private_key_config = aea_conf.private_key_paths.read(DEFAULT) if default_private_key_config is None: _create_default_private_key() default_private_key_config = PrivateKeyPathConfig( DEFAULT, DEFAULT_PRIVATE_KEY_FILE) aea_conf.private_key_paths.create(default_private_key_config.ledger, default_private_key_config) else: default_private_key_config = cast(PrivateKeyPathConfig, default_private_key_config) try: _try_validate_private_key_pem_path(default_private_key_config.path) except FileNotFoundError: logger.error("File {} for private key {} not found.".format( repr(default_private_key_config.path), default_private_key_config.ledger)) sys.exit(1) fetchai_private_key_config = aea_conf.private_key_paths.read(FETCHAI) if fetchai_private_key_config is None: _create_fetchai_private_key() fetchai_private_key_config = PrivateKeyPathConfig( FETCHAI, FETCHAI_PRIVATE_KEY_FILE) aea_conf.private_key_paths.create(fetchai_private_key_config.ledger, fetchai_private_key_config) else: fetchai_private_key_config = cast(PrivateKeyPathConfig, fetchai_private_key_config) try: _try_validate_fet_private_key_path(fetchai_private_key_config.path) except FileNotFoundError: logger.error("File {} for private key {} not found.".format( repr(fetchai_private_key_config.path), fetchai_private_key_config.ledger)) sys.exit(1) ethereum_private_key_config = aea_conf.private_key_paths.read(ETHEREUM) if ethereum_private_key_config is None: _create_ethereum_private_key() ethereum_private_key_config = PrivateKeyPathConfig( ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE) aea_conf.private_key_paths.create(ethereum_private_key_config.ledger, ethereum_private_key_config) else: ethereum_private_key_config = cast(PrivateKeyPathConfig, ethereum_private_key_config) try: _try_validate_ethereum_private_key_path( ethereum_private_key_config.path) except FileNotFoundError: logger.error("File {} for private key {} not found.".format( repr(ethereum_private_key_config.path), ethereum_private_key_config.ledger)) sys.exit(1) # update aea config path = Path(DEFAULT_AEA_CONFIG_FILE) fp = open(str(path), mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) ctx.agent_config = aea_conf