Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom packages #717

Merged
merged 15 commits into from
Feb 19, 2024
3 changes: 2 additions & 1 deletion aea/cli/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
DEFAULT_AEA_CONFIG_FILE,
PROTOCOL,
SKILL,
CUSTOM,
)
from aea.exceptions import enforce
from aea.helpers.io import open_file
Expand Down Expand Up @@ -266,7 +267,7 @@ def _fetch_agent_deps(ctx: Context) -> None:

:param ctx: context object.
"""
for item_type in (PROTOCOL, CONTRACT, CONNECTION, SKILL):
for item_type in (PROTOCOL, CONTRACT, CUSTOM, CONNECTION, SKILL):
item_type_plural = "{}s".format(item_type)
required_items = cast(set, getattr(ctx.agent_config, item_type_plural))
required_items_check = required_items.copy()
Expand Down
1 change: 1 addition & 0 deletions aea/cli/utils/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ def _update_dependencies(updates: Dependencies) -> None:
for item_type in (
PackageType.PROTOCOL,
PackageType.CONTRACT,
PackageType.CUSTOM,
PackageType.CONNECTION,
PackageType.SKILL,
PackageType.AGENT,
Expand Down
125 changes: 119 additions & 6 deletions aea/configurations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@
from aea.configurations.constants import (
CONNECTIONS,
CONTRACTS,
CUSTOMS,
DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE,
DEFAULT_AEA_CONFIG_FILE,
DEFAULT_CONNECTION_CONFIG_FILE,
DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE,
DEFAULT_CONTRACT_CONFIG_FILE,
DEFAULT_FINGERPRINT_IGNORE_PATTERNS,
DEFAULT_LICENSE,
Expand Down Expand Up @@ -146,6 +149,8 @@ def _get_default_configuration_file_name_from_type(
return DEFAULT_CONTRACT_CONFIG_FILE
if item_type == PackageType.SERVICE:
return DEFAULT_SERVICE_CONFIG_FILE
if item_type == PackageType.CUSTOM:
return DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE
raise ValueError( # pragma: no cover
"Item type not valid: {}".format(str(item_type))
)
Expand Down Expand Up @@ -964,6 +969,7 @@ class SkillConfig(ComponentConfiguration):
"connections",
"protocols",
"contracts",
"customs",
"skills",
"dependencies",
"description",
Expand All @@ -987,6 +993,7 @@ def __init__(
connections: Optional[Set[PublicId]] = None,
protocols: Optional[Set[PublicId]] = None,
contracts: Optional[Set[PublicId]] = None,
customs: Optional[Set[PublicId]] = None,
skills: Optional[Set[PublicId]] = None,
dependencies: Optional[Dependencies] = None,
description: str = "",
Expand All @@ -1008,6 +1015,7 @@ def __init__(
self.connections = connections if connections is not None else set()
self.protocols = protocols if protocols is not None else set()
self.contracts = contracts if contracts is not None else set()
self.customs = customs if customs is not None else set()
self.skills = skills if skills is not None else set()
self.dependencies = dependencies if dependencies is not None else {}
self.description = description
Expand Down Expand Up @@ -1040,6 +1048,12 @@ def package_dependencies(self) -> Set[ComponentId]:
for connection_id in self.connections
}
)
.union(
{
ComponentId(ComponentType.CUSTOM, custom_id)
for custom_id in self.customs
}
)
)

@property
Expand All @@ -1063,6 +1077,7 @@ def json(self) -> Dict:
"fingerprint_ignore_patterns": self.fingerprint_ignore_patterns,
CONNECTIONS: sorted(map(str, self.connections)),
CONTRACTS: sorted(map(str, self.contracts)),
CUSTOMS: sorted(map(str, self.customs)),
PROTOCOLS: sorted(map(str, self.protocols)),
SKILLS: sorted(map(str, self.skills)),
"behaviours": {key: b.json for key, b in self.behaviours.read_all()},
Expand Down Expand Up @@ -1097,6 +1112,7 @@ def _create_or_update_from_json(
connections = {PublicId.from_str(id_) for id_ in obj.get(CONNECTIONS, set())}
protocols = {PublicId.from_str(id_) for id_ in obj.get(PROTOCOLS, set())}
contracts = {PublicId.from_str(id_) for id_ in obj.get(CONTRACTS, set())}
customs = {PublicId.from_str(id_) for id_ in obj.get(CUSTOMS, set())}
skills = {PublicId.from_str(id_) for id_ in obj.get(SKILLS, set())}
dependencies = dependencies_from_json(obj.get("dependencies", {}))
description = cast(str, obj.get("description", ""))
Expand All @@ -1112,6 +1128,7 @@ def _create_or_update_from_json(
connections=connections,
protocols=protocols,
contracts=contracts,
customs=customs,
skills=skills,
dependencies=dependencies,
description=description,
Expand Down Expand Up @@ -1211,6 +1228,7 @@ class AgentConfig(PackageConfiguration):
"protocols",
"skills",
"contracts",
"customs",
"period",
"execution_timeout",
"max_reactions",
Expand Down Expand Up @@ -1294,6 +1312,7 @@ def __init__( # pylint: disable=too-many-arguments,too-many-locals
)
self.connections = set() # type: Set[PublicId]
self.contracts = set() # type: Set[PublicId]
self.customs = set() # type: Set[PublicId]
self.protocols = set() # type: Set[PublicId]
self.skills = set() # type: Set[PublicId]

Expand Down Expand Up @@ -1341,6 +1360,7 @@ def component_configurations(self, d: Dict[ComponentId, Dict]) -> None:
PackageType.PROTOCOL: {epid.without_hash() for epid in self.protocols},
PackageType.CONNECTION: {epid.without_hash() for epid in self.connections},
PackageType.CONTRACT: {epid.without_hash() for epid in self.contracts},
PackageType.CUSTOM: {epid.without_hash() for epid in self.customs},
PackageType.SKILL: {epid.without_hash() for epid in self.skills},
}
for component_id, component_configuration in d.items():
Expand Down Expand Up @@ -1368,13 +1388,14 @@ def package_dependencies(self) -> Set[ComponentId]:
skills = set(
ComponentId(ComponentType.SKILL, public_id) for public_id in self.skills
)

contracts = set(
ComponentId(ComponentType.CONTRACT, public_id)
for public_id in self.contracts
)

return set.union(protocols, contracts, connections, skills)
customs = set(
ComponentId(ComponentType.CUSTOM, public_id) for public_id in self.customs
)
return set.union(protocols, contracts, customs, connections, skills)

@property
def private_key_paths_dict(self) -> Dict[str, str]:
Expand Down Expand Up @@ -1421,9 +1442,12 @@ def json(self) -> Dict:
CONTRACTS: sorted(map(str, self.contracts)),
PROTOCOLS: sorted(map(str, self.protocols)),
SKILLS: sorted(map(str, self.skills)),
"default_connection": str(self.default_connection)
if self.default_connection is not None
else None,
CUSTOMS: sorted(map(str, self.customs)),
"default_connection": (
DavidMinarsch marked this conversation as resolved.
Show resolved Hide resolved
str(self.default_connection)
if self.default_connection is not None
else None
),
"default_ledger": self.default_ledger,
"required_ledgers": self.required_ledgers or [],
"default_routing": {
Expand Down Expand Up @@ -1540,6 +1564,14 @@ def _create_or_update_from_json(
)
)

# parse contracts public ids
DavidMinarsch marked this conversation as resolved.
Show resolved Hide resolved
agent_config.customs = set(
map(
PublicId.from_str,
obj.get(CUSTOMS, []),
)
)

# parse protocol public ids
agent_config.protocols = set(
map(
Expand Down Expand Up @@ -1575,6 +1607,7 @@ def all_components_id(self) -> List[ComponentId]:
ComponentType.PROTOCOL: self.protocols,
ComponentType.CONNECTION: self.connections,
ComponentType.CONTRACT: self.contracts,
ComponentType.CUSTOM: self.customs,
ComponentType.SKILL: self.skills,
}
result = []
Expand Down Expand Up @@ -1879,6 +1912,85 @@ def package_dependencies(self) -> Set[ComponentId]:
}


class CustomComponentConfig(PackageConfiguration):
"""Custom component configuratiopn."""

default_configuration_filename = DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE
package_type = PackageType.CUSTOM
schema = "custom-config_schema.json"

FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset(
["config", "cert_requests", "is_abstract", "build_directory"]
)

def __init__(
self,
name: SimpleIdOrStr,
author: SimpleIdOrStr,
version: str = "",
license_: str = "",
aea_version: str = "",
description: str = "",
fingerprint: Optional[Dict[str, str]] = None,
fingerprint_ignore_patterns: Optional[Sequence[str]] = None,
dependencies: Optional[Dependencies] = None,
**kwargs: Any,
) -> None:
super().__init__(
name,
author,
version,
license_,
aea_version,
fingerprint,
fingerprint_ignore_patterns,
)
self.dependencies = dependencies if dependencies is not None else {}
self.description = description
self.kwargs = kwargs

def get(self, name: str) -> Any:
"""Get parameter."""
return self.kwargs.get(name)

def set(self, name: str, value: Any) -> None:
"""Set extra parameter value."""
self.kwargs[name] = value

@property
def json(self) -> Dict:
"""Return the JSON representation."""
result = OrderedDict(
{
"name": self.name,
"author": self.author,
"version": self.version,
"type": self.component_type.value,
"description": self.description,
"license": self.license,
"aea_version": self.aea_version,
"fingerprint": self.fingerprint,
"fingerprint_ignore_patterns": self.fingerprint_ignore_patterns,
"dependencies": dependencies_to_json(self.dependencies),
**self.kwargs,
}
)
return result

@classmethod
def _create_or_update_from_json(
cls, obj: Dict, instance: Optional["CustomComponentConfig"] = None
) -> "CustomComponentConfig":
"""Initialize from a JSON object."""
params = {**(instance.json if instance else {}), **copy(obj)}
params["dependencies"] = cast(
Dependencies, dependencies_from_json(obj.get("dependencies", {}))
)
return cast(
CustomComponentConfig, cls._apply_params_to_instance(params, instance)
)


"""The following functions are called from aea.cli.utils."""


Expand Down Expand Up @@ -2045,4 +2157,5 @@ def _get_public_id_from_file(
PackageType.CONNECTION: ConnectionConfig,
PackageType.SKILL: SkillConfig,
PackageType.CONTRACT: ContractConfig,
PackageType.CUSTOM: CustomComponentConfig,
}
5 changes: 5 additions & 0 deletions aea/configurations/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
AGENT = "agent"
AGENTS = "agents"
BUILD = "build"
CUSTOM = "custom"
CUSTOMS = "customs"
CONNECTION = "connection"
CONNECTIONS = "connections"
CONTRACT = "contract"
Expand All @@ -66,6 +68,7 @@
DEFAULT_AEA_CONFIG_FILE = "aea-config.yaml"
DEFAULT_SKILL_CONFIG_FILE = "skill.yaml"
DEFAULT_CONNECTION_CONFIG_FILE = "connection.yaml"
DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE = "component.yaml"
DEFAULT_CONTRACT_CONFIG_FILE = "contract.yaml"
DEFAULT_PROTOCOL_CONFIG_FILE = "protocol.yaml"
DEFAULT_SERVICE_CONFIG_FILE = "service.yaml"
Expand All @@ -81,6 +84,7 @@
DEFAULT_CONNECTION_CONFIG_FILE,
DEFAULT_SKILL_CONFIG_FILE,
DEFAULT_CONTRACT_CONFIG_FILE,
DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE,
PRIVATE_KEY_PATH_SCHEMA.format("*"),
]
DEFAULT_PYPI_INDEX_URL = "https://pypi.org/simple"
Expand All @@ -100,6 +104,7 @@
DEFAULT_CONTRACT_CONFIG_FILE: CONTRACT,
DEFAULT_SERVICE_CONFIG_FILE: SERVICE,
DEFAULT_AEA_CONFIG_FILE: AGENT,
DEFAULT_CUSTOM_COMPONENT_CONFIG_FILE: CUSTOM,
} # type: Dict[str, str]

PACKAGE_TYPE_TO_CONFIG_FILE = {
Expand Down
6 changes: 5 additions & 1 deletion aea/configurations/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
PROTOCOL,
SERVICE,
SKILL,
CUSTOM,
)
from aea.helpers.base import (
IPFSHash,
Expand Down Expand Up @@ -170,6 +171,7 @@ class PackageType(Enum):
PROTOCOL = PROTOCOL
CONNECTION = CONNECTION
CONTRACT = CONTRACT
CUSTOM = CUSTOM
SKILL = SKILL
SERVICE = SERVICE

Expand Down Expand Up @@ -204,6 +206,7 @@ class ComponentType(Enum):
CONNECTION = CONNECTION
SKILL = SKILL
CONTRACT = CONTRACT
CUSTOM = CUSTOM

def to_package_type(self) -> PackageType:
"""Get package type for component type."""
Expand Down Expand Up @@ -559,13 +562,14 @@ def __str__(self) -> str:
class PackageId:
"""A package identifier."""

PACKAGE_TYPE_REGEX = r"({}|{}|{}|{}|{}|{})".format(
PACKAGE_TYPE_REGEX = r"({}|{}|{}|{}|{}|{}|{})".format(
PackageType.AGENT,
PackageType.PROTOCOL,
PackageType.SKILL,
PackageType.CONNECTION,
PackageType.CONTRACT,
PackageType.SERVICE,
PackageType.CUSTOM,
)
PACKAGE_ID_URI_REGEX = r"{}/{}".format(
PACKAGE_TYPE_REGEX, PublicId.PUBLIC_ID_URI_REGEX[1:-1]
Expand Down
12 changes: 8 additions & 4 deletions aea/configurations/schemas/aea-config_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,15 @@
"$ref": "definitions.json#/definitions/public_id"
}
},
"customs": {
"type": "array",
"uniqueItems": true,
"items": {
"$ref": "definitions.json#/definitions/public_id"
}
},
"default_connection": {
"type": [
"string",
"null"
]
"type": ["string", "null"]
},
"protocols": {
"type": "array",
Expand Down
Loading
Loading