From ba055b3fbd8a60b7dbb23198038f51e194417feb Mon Sep 17 00:00:00 2001 From: James Riehl Date: Fri, 24 Jan 2025 11:30:57 +0000 Subject: [PATCH 1/2] chore(core): update network and prefix properties --- python/docs/api/uagents/agent.md | 7 +++-- python/docs/api/uagents/network.md | 18 ++++++----- python/docs/api/uagents/resolver.md | 8 +++-- python/docs/api/uagents/utils.md | 14 +++++++++ python/src/uagents/agent.py | 31 ++++++++++-------- python/src/uagents/network.py | 49 ++++++++++++++++------------- python/src/uagents/resolver.py | 12 ++++--- python/src/uagents/types.py | 1 + 8 files changed, 87 insertions(+), 53 deletions(-) diff --git a/python/docs/api/uagents/agent.md b/python/docs/api/uagents/agent.md index b33c0fe4b..7ff52badf 100644 --- a/python/docs/api/uagents/agent.md +++ b/python/docs/api/uagents/agent.md @@ -158,7 +158,8 @@ An agent that interacts within a communication environment. - `protocols` _Dict[str, Protocol]_ - Dictionary mapping all supported protocol digests to their corresponding protocols. - `_ctx` _Context_ - The context for agent interactions. -- `_test` _bool_ - True if the agent will register and transact on the testnet. +- `_network` _str_ - The network to use for the agent ('mainnet' or 'testnet'). +- `_prefix` _str_ - The address prefix for the agent (determined by the network). - `_enable_agent_inspector` _bool_ - Enable the agent inspector REST endpoints. - `_metadata` _Dict[str, Any]_ - Metadata associated with the agent. - `_readme` _Optional[str]_ - The agent's README file. @@ -194,7 +195,7 @@ def __init__(name: Optional[str] = None, wallet_key_derivation_index: Optional[int] = 0, max_resolver_endpoints: Optional[int] = None, version: Optional[str] = None, - test: bool = True, + network: AgentNetwork = "testnet", loop: Optional[asyncio.AbstractEventLoop] = None, log_level: Union[int, str] = logging.INFO, enable_agent_inspector: bool = True, @@ -222,7 +223,7 @@ Initialize an Agent instance. - `wallet_key_derivation_index` _Optional[int]_ - The index used for deriving the wallet key. - `max_resolver_endpoints` _Optional[int]_ - The maximum number of endpoints to resolve. - `version` _Optional[str]_ - The version of the agent. -- `test` _Optional[bool]_ - True if the agent will register and transact on the testnet. +- `network` _Literal["mainnet", "testnet"]_ - The network to use for the agent. - `loop` _Optional[asyncio.AbstractEventLoop]_ - The asyncio event loop to use. - `log_level` _Union[int, str]_ - The logging level for the agent. - `enable_agent_inspector` _bool_ - Enable the agent inspector for debugging. diff --git a/python/docs/api/uagents/network.md b/python/docs/api/uagents/network.md index e16e88a26..14fc93386 100644 --- a/python/docs/api/uagents/network.md +++ b/python/docs/api/uagents/network.md @@ -19,14 +19,14 @@ Raised when an agent has insufficient funds for a transaction. #### get`_`ledger ```python -def get_ledger(test: bool = True) -> LedgerClient +def get_ledger(network: AgentNetwork = "testnet") -> LedgerClient ``` Get the Ledger client. **Arguments**: -- `test` _bool_ - Whether to use the testnet or mainnet. Defaults to True. +- `network` _AgentNetwork, optional_ - The network to use. Defaults to "testnet". **Returns**: @@ -356,14 +356,15 @@ Get the agent's sequence number for Almanac registration. #### get`_`almanac`_`contract ```python -def get_almanac_contract(test: bool = True) -> Optional[AlmanacContract] +def get_almanac_contract( + network: AgentNetwork = "testnet") -> Optional[AlmanacContract] ``` Get the AlmanacContract instance. **Arguments**: -- `test` _bool_ - Whether to use the testnet or mainnet. Defaults to True. +- `network` _AgentNetwork_ - The network to use. Defaults to "testnet". **Returns**: @@ -406,7 +407,7 @@ Execute a query with additional checks and error handling. **Raises**: -- `RuntimeError` - If the contract address is not set or the query fails. +- `ValueError` - If the response from contract is not a dict. @@ -495,8 +496,8 @@ Retrieve the previous records for a given name within a specified domain. ```python def get_registration_tx(name: str, wallet_address: Address, - agent_records: Union[List[Dict[str, Any]], - str], domain: str, test: bool) + agent_records: Union[List[Dict[str, Any]], str], + domain: str, network: AgentNetwork) ``` Get the registration transaction for registering a name within a domain. @@ -563,7 +564,8 @@ Unregister a name within a domain using the NameService contract. #### get`_`name`_`service`_`contract ```python -def get_name_service_contract(test: bool = True) -> NameServiceContract +def get_name_service_contract( + network: AgentNetwork = "testnet") -> NameServiceContract ``` Get the NameServiceContract instance. diff --git a/python/docs/api/uagents/resolver.md b/python/docs/api/uagents/resolver.md index f0a81bb65..b04b7b88a 100644 --- a/python/docs/api/uagents/resolver.md +++ b/python/docs/api/uagents/resolver.md @@ -93,7 +93,8 @@ Parse an agent identifier string into prefix, name, and address. #### query`_`record ```python -def query_record(agent_address: str, service: str, test: bool) -> dict +def query_record(agent_address: str, service: str, + network: AgentNetwork) -> dict ``` Query a record from the Almanac contract. @@ -102,6 +103,7 @@ Query a record from the Almanac contract. - `agent_address` _str_ - The address of the agent. - `service` _str_ - The type of service to query. +- `network` _AgentNetwork_ - The network to query (mainnet or testnet). **Returns**: @@ -113,7 +115,7 @@ Query a record from the Almanac contract. #### get`_`agent`_`address ```python -def get_agent_address(name: str, test: bool) -> Optional[str] +def get_agent_address(name: str, network: AgentNetwork) -> Optional[str] ``` Get the agent address associated with the provided name from the name service contract. @@ -121,7 +123,7 @@ Get the agent address associated with the provided name from the name service co **Arguments**: - `name` _str_ - The name to query. -- `test` _bool_ - Whether to use the testnet or mainnet contract. +- `network` _AgentNetwork_ - The network to query (mainnet or testnet). **Returns**: diff --git a/python/docs/api/uagents/utils.md b/python/docs/api/uagents/utils.md index 5cfa6eab3..0828d3f82 100644 --- a/python/docs/api/uagents/utils.md +++ b/python/docs/api/uagents/utils.md @@ -28,3 +28,17 @@ Log a message with the given logger and level. - `level` _int_ - The logging level. - `message` _str_ - The message to log. + + +#### set`_`global`_`log`_`level + +```python +def set_global_log_level(level: Union[int, str]) +``` + +Set the log level for all modules globally. Can still be overruled manually. + +**Arguments**: + +- `level` _Union[int, str]_ - The logging level as defined in _logging_. + diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index fa238af77..53a8f732f 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -69,9 +69,11 @@ from uagents.resolver import GlobalResolver, Resolver from uagents.storage import KeyValueStore, get_or_create_private_keys from uagents.types import ( + AddressPrefix, AgentEndpoint, AgentInfo, AgentMetadata, + AgentNetwork, EventCallback, IntervalCallback, JsonStr, @@ -249,7 +251,8 @@ class Agent(Sink): protocols (Dict[str, Protocol]): Dictionary mapping all supported protocol digests to their corresponding protocols. _ctx (Context): The context for agent interactions. - _test (bool): True if the agent will register and transact on the testnet. + _network (str): The network to use for the agent ('mainnet' or 'testnet'). + _prefix (str): The address prefix for the agent (determined by the network). _enable_agent_inspector (bool): Enable the agent inspector REST endpoints. _metadata (Dict[str, Any]): Metadata associated with the agent. _readme (Optional[str]): The agent's README file. @@ -284,7 +287,7 @@ def __init__( wallet_key_derivation_index: Optional[int] = 0, max_resolver_endpoints: Optional[int] = None, version: Optional[str] = None, - test: bool = True, + network: AgentNetwork = "testnet", loop: Optional[asyncio.AbstractEventLoop] = None, log_level: Union[int, str] = logging.INFO, enable_agent_inspector: bool = True, @@ -311,7 +314,7 @@ def __init__( wallet_key_derivation_index (Optional[int]): The index used for deriving the wallet key. max_resolver_endpoints (Optional[int]): The maximum number of endpoints to resolve. version (Optional[str]): The version of the agent. - test (Optional[bool]): True if the agent will register and transact on the testnet. + network (Literal["mainnet", "testnet"]): The network to use for the agent. loop (Optional[asyncio.AbstractEventLoop]): The asyncio event loop to use. log_level (Union[int, str]): The logging level for the agent. enable_agent_inspector (bool): Enable the agent inspector for debugging. @@ -354,8 +357,8 @@ def __init__( almanac_api_url=self._almanac_api_url, ) - self._ledger = get_ledger(test) - self._almanac_contract = get_almanac_contract(test) + self._ledger = get_ledger(network) + self._almanac_contract = get_almanac_contract(network) self._storage = KeyValueStore(self.address[0:16]) self._interval_handlers: List[Tuple[IntervalCallback, float]] = [] self._interval_messages: Set[str] = set() @@ -371,7 +374,10 @@ def __init__( self._message_queue = asyncio.Queue() self._on_startup = [] self._on_shutdown = [] - self._test = test + self._network = network + self._prefix: AddressPrefix = ( + MAINNET_PREFIX if network == "mainnet" else TESTNET_PREFIX + ) self._version = version or "0.1.0" self._registration_policy = registration_policy or None @@ -380,7 +386,7 @@ def __init__( self._ledger, self._wallet, self._almanac_contract, - self._test, + self._network == "testnet", almanac_api=self._almanac_api_url, ) self._metadata = self._initialize_metadata(metadata) @@ -424,7 +430,7 @@ async def _handle_error_message(ctx: Context, sender: str, msg: ErrorMessage): async def _handle_get_info(_ctx: Context): return AgentInfo( address=self.address, - prefix=TESTNET_PREFIX if self._test else MAINNET_PREFIX, + prefix=self._prefix, endpoints=self._endpoints, protocols=list(self.protocols.keys()), ) @@ -450,7 +456,7 @@ async def _handle_connect(_ctx: Context, request: AgentverseConnectRequest): return await register_in_agentverse( request, self._identity, - TESTNET_PREFIX if self._test else MAINNET_PREFIX, + self._prefix, self._agentverse, agent_details, ) @@ -601,8 +607,7 @@ def identifier(self) -> str: Returns: str: The agent's identifier. """ - prefix = TESTNET_PREFIX if self._test else MAINNET_PREFIX - return prefix + "://" + self._identity.address + return self._prefix + "://" + self._identity.address @property def wallet(self) -> LocalWallet: @@ -675,7 +680,7 @@ def info(self) -> AgentInfo: """ return AgentInfo( address=self.address, - prefix=TESTNET_PREFIX if self._test else MAINNET_PREFIX, + prefix=self._prefix, endpoints=self._endpoints, protocols=list(self.protocols.keys()), metadata=self.metadata, @@ -1508,7 +1513,7 @@ def _update_agent(self, agent: Agent): agent._ledger, agent._wallet, agent._almanac_contract, - agent._test, + agent._network == "testnet", logger=agent._logger, ) diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index c9fb22594..bd0304409 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -33,7 +33,7 @@ TESTNET_CONTRACT_NAME_SERVICE, ) from uagents.crypto import Identity -from uagents.types import AgentEndpoint, AgentInfo +from uagents.types import AgentEndpoint, AgentInfo, AgentNetwork from uagents.utils import get_logger logger = get_logger("network") @@ -61,19 +61,19 @@ def sign(self, identity: Identity): ) -def get_ledger(test: bool = True) -> LedgerClient: +def get_ledger(network: AgentNetwork = "testnet") -> LedgerClient: """ Get the Ledger client. Args: - test (bool): Whether to use the testnet or mainnet. Defaults to True. + network (AgentNetwork, optional): The network to use. Defaults to "testnet". Returns: LedgerClient: The Ledger client instance. """ - if test: - return _testnet_ledger - return _mainnet_ledger + if network == "mainnet": + return _mainnet_ledger + return _testnet_ledger def get_faucet() -> FaucetApi: @@ -491,22 +491,22 @@ def get_sequence(self, address: str) -> int: ) -def get_almanac_contract(test: bool = True) -> Optional[AlmanacContract]: +def get_almanac_contract( + network: AgentNetwork = "testnet", +) -> Optional[AlmanacContract]: """ Get the AlmanacContract instance. Args: - test (bool): Whether to use the testnet or mainnet. Defaults to True. + network (AgentNetwork): The network to use. Defaults to "testnet". Returns: AlmanacContract: The AlmanacContract instance if version is supported. """ - if test: - if _testnet_almanac_contract.check_version(): - return _testnet_almanac_contract - return None - if _mainnet_almanac_contract.check_version(): + if network == "mainnet" and _mainnet_almanac_contract.check_version(): return _mainnet_almanac_contract + if _testnet_almanac_contract.check_version(): + return _testnet_almanac_contract return None @@ -618,7 +618,7 @@ def get_registration_tx( wallet_address: Address, agent_records: Union[List[Dict[str, Any]], str], domain: str, - test: bool, + network: AgentNetwork, ): """ Get the registration transaction for registering a name within a domain. @@ -637,7 +637,9 @@ def get_registration_tx( transaction = Transaction() contract = Address( - TESTNET_CONTRACT_NAME_SERVICE if test else MAINNET_CONTRACT_NAME_SERVICE + MAINNET_CONTRACT_NAME_SERVICE + if network == "mainnet" + else TESTNET_CONTRACT_NAME_SERVICE ) if self.is_name_available(name, domain): @@ -694,6 +696,11 @@ async def register( """ logger.info("Registering name...") chain_id = ledger.query_chain_id() + network = ( + "mainnet" + if chain_id == NetworkConfig.fetchai_mainnet().chain_id + else "testnet" + ) records = parse_record_config(agent_records) if not records: @@ -701,7 +708,7 @@ async def register( agent_addresses = [val.get("address") for val in records] for agent_address in agent_addresses: - if not get_almanac_contract(chain_id == "dorado-1").is_registered( + if not get_almanac_contract(network).is_registered( agent_address # type: ignore ): logger.warning( @@ -731,7 +738,7 @@ async def register( wallet.address(), records, domain, - chain_id == "dorado-1", + network=network, ) if transaction is None: @@ -783,7 +790,7 @@ async def unregister( ) -def get_name_service_contract(test: bool = True) -> NameServiceContract: +def get_name_service_contract(network: AgentNetwork = "testnet") -> NameServiceContract: """ Get the NameServiceContract instance. @@ -793,6 +800,6 @@ def get_name_service_contract(test: bool = True) -> NameServiceContract: Returns: NameServiceContract: The NameServiceContract instance. """ - if test: - return _testnet_name_service_contract - return _mainnet_name_service_contract + if network == "mainnet": + return _mainnet_name_service_contract + return _testnet_name_service_contract diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 147391a8d..6c15858e4 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -19,6 +19,7 @@ ) from uagents.crypto import is_user_address from uagents.network import get_almanac_contract, get_name_service_contract +from uagents.types import AgentNetwork from uagents.utils import get_logger LOGGER = get_logger("resolver", logging.WARNING) @@ -106,18 +107,19 @@ def parse_identifier(identifier: str) -> Tuple[str, str, str]: return prefix, name, address -def query_record(agent_address: str, service: str, test: bool) -> dict: +def query_record(agent_address: str, service: str, network: AgentNetwork) -> dict: """ Query a record from the Almanac contract. Args: agent_address (str): The address of the agent. service (str): The type of service to query. + network (AgentNetwork): The network to query (mainnet or testnet). Returns: dict: The query result. """ - contract = get_almanac_contract(test) + contract = get_almanac_contract(network) query_msg = { "query_record": {"agent_address": agent_address, "record_type": service} } @@ -125,19 +127,19 @@ def query_record(agent_address: str, service: str, test: bool) -> dict: return result -def get_agent_address(name: str, test: bool) -> Optional[str]: +def get_agent_address(name: str, network: AgentNetwork) -> Optional[str]: """ Get the agent address associated with the provided name from the name service contract. Args: name (str): The name to query. - test (bool): Whether to use the testnet or mainnet contract. + network (AgentNetwork): The network to query (mainnet or testnet). Returns: Optional[str]: The associated agent address if found. """ query_msg = {"domain_record": {"domain": f"{name}"}} - result = get_name_service_contract(test).query(query_msg) + result = get_name_service_contract(network).query(query_msg) if result["record"] is not None: registered_records = result["record"]["records"][0]["agent_address"]["records"] if len(registered_records) > 0: diff --git a/python/src/uagents/types.py b/python/src/uagents/types.py index 081f1f0d3..397233083 100644 --- a/python/src/uagents/types.py +++ b/python/src/uagents/types.py @@ -39,6 +39,7 @@ AddressPrefix = Literal["agent", "test-agent"] +AgentNetwork = Literal["mainnet", "testnet"] class AgentEndpoint(BaseModel): From 27ccb58d74dd060fadaefa3ac22984418d651dfa Mon Sep 17 00:00:00 2001 From: James Riehl Date: Fri, 24 Jan 2025 16:16:05 +0000 Subject: [PATCH 2/2] fix: name service example --- python/examples/13-agent-name-service/agent1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 06604f51f..e8cda52eb 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -19,7 +19,7 @@ class Message(Model): my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") -name_service_contract = get_name_service_contract(test=True) +name_service_contract = get_name_service_contract() faucet = get_faucet() DOMAIN = "example.agent"