Skip to content

Commit

Permalink
feat: publish protocol manifest to agentverse (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrriehl committed Jul 19, 2023
1 parent 05b2ebc commit 01ae9d1
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 25 deletions.
8 changes: 4 additions & 4 deletions examples/09-booking-protocol-demo/restaurant.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@

fund_agent_if_low(restaurant.wallet.address())

# build the restaurant agent from stock protocols
restaurant.include(query_proto)
restaurant.include(book_proto)
restaurant.include(proto_query)
# build the restaurant agent from stock protocols and publish their details
restaurant.include(query_proto, publish_manifest=True)
restaurant.include(book_proto, publish_manifest=True)
restaurant.include(proto_query, publish_manifest=True)

TABLES = {
1: TableStatus(seats=2, time_start=16, time_end=22),
Expand Down
59 changes: 51 additions & 8 deletions src/uagents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import functools
from typing import Dict, List, Optional, Set, Union, Type, Tuple, Any
import uuid
import requests

from cosmpy.aerial.wallet import LocalWallet, PrivateKey
from cosmpy.crypto.address import Address
Expand Down Expand Up @@ -38,7 +39,7 @@
MIN_REGISTRATION_TIME,
LEDGER_PREFIX,
parse_endpoint_config,
parse_mailbox_config,
parse_agentverse_config,
get_logger,
)

Expand Down Expand Up @@ -66,6 +67,7 @@ def __init__(
port: Optional[int] = None,
seed: Optional[str] = None,
endpoint: Optional[Union[str, List[str], Dict[str, dict]]] = None,
agentverse: Optional[Union[str, Dict[str, str]]] = None,
mailbox: Optional[Union[str, Dict[str, str]]] = None,
resolve: Optional[Resolver] = None,
version: Optional[str] = None,
Expand All @@ -76,15 +78,29 @@ def __init__(
self._resolver = resolve if resolve is not None else GlobalResolver()
self._loop = asyncio.get_event_loop_policy().get_event_loop()

# initialize wallet and identity
self._initialize_wallet_and_identity(seed, name)

self._logger = get_logger(self.name)

# configure endpoints and mailbox
self._endpoints = parse_endpoint_config(endpoint)
self._use_mailbox = mailbox is not None
self._use_mailbox = False

if mailbox:
# agentverse config overrides mailbox config
# but mailbox is kept for backwards compatibility
if agentverse:
self._logger.warning(
"Ignoring the provided 'mailbox' configuration since 'agentverse' overrides it"
)
else:
agentverse = mailbox
self._logger.warning(
"The 'mailbox' configuration is deprecated in favor of 'agentverse'"
)
self._agentverse = parse_agentverse_config(agentverse)
self._use_mailbox = self._agentverse["use_mailbox"]
if self._use_mailbox:
self._mailbox = parse_mailbox_config(mailbox)
self._mailbox_client = MailboxClient(self, self._logger)
# if mailbox is provided, override endpoints with mailbox endpoint
self._endpoints = [
Expand All @@ -94,7 +110,6 @@ def __init__(
}
]
else:
self._mailbox = None
self._mailbox_client = None

self._ledger = get_ledger()
Expand Down Expand Up @@ -179,15 +194,23 @@ def storage(self) -> KeyValueStore:

@property
def mailbox(self) -> Dict[str, str]:
return self._mailbox
return self._agentverse

@property
def agentverse(self) -> Dict[str, str]:
return self._agentverse

@property
def mailbox_client(self) -> MailboxClient:
return self._mailbox_client

@mailbox.setter
def mailbox(self, config: Union[str, Dict[str, str]]):
self._mailbox = parse_mailbox_config(config)
self._agentverse = parse_agentverse_config(config)

@agentverse.setter
def agentverse(self, config: Union[str, Dict[str, str]]):
self._agentverse = parse_agentverse_config(config)

def sign(self, data: bytes) -> str:
return self._identity.sign(data)
Expand Down Expand Up @@ -318,7 +341,7 @@ def _add_event_handler(
elif event_type == "shutdown":
self._on_shutdown.append(func)

def include(self, protocol: Protocol):
def include(self, protocol: Protocol, publish_manifest: Optional[bool] = False):
for func, period in protocol.intervals:
self._interval_handlers.append((func, period))

Expand Down Expand Up @@ -348,6 +371,26 @@ def include(self, protocol: Protocol):
if protocol.digest is not None:
self.protocols[protocol.digest] = protocol

if publish_manifest:
self.publish_manifest(protocol.manifest())

def publish_manifest(self, manifest: Dict[str, Any]):
try:
resp = requests.post(
f"{self._agentverse['http_prefix']}://{self._agentverse['base_url']}"
+ "/v1/almanac/manifests",
json=manifest,
timeout=5,
)
if resp.status_code == 200:
self._logger.info(
f"Manifest published successfully: {manifest['metadata']['name']}"
)
else:
self._logger.warning(f"Unable to publish manifest: {resp.text}")
except requests.exceptions.RequestException as ex:
self._logger.warning(f"Unable to publish manifest: {ex}")

async def handle_message(
self, sender, schema_digest: str, message: JsonStr, session: uuid.UUID
):
Expand Down
32 changes: 19 additions & 13 deletions src/uagents/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AgentNetwork(Enum):
BLOCK_INTERVAL = 5
AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET

MAILBOX_SERVER_URL = "wss://agentverse.ai"
AGENTVERSE_URL = "https://agentverse.ai"
MAILBOX_POLL_INTERVAL_SECONDS = 1.0

DEFAULT_ENVELOPE_TIMEOUT_SECONDS = 30
Expand All @@ -49,28 +49,34 @@ def parse_endpoint_config(
return endpoints


def parse_mailbox_config(mailbox: Union[str, Dict[str, str]]) -> Dict[str, str]:
def parse_agentverse_config(
config: Optional[Union[str, Dict[str, str]]] = None,
) -> Dict[str, str]:
api_key = None
base_url = MAILBOX_SERVER_URL
if isinstance(mailbox, str):
if mailbox.count("@") == 1:
api_key, base_url = mailbox.split("@")
base_url = AGENTVERSE_URL
protocol = None
protocol_override = None
if isinstance(config, str):
if config.count("@") == 1:
api_key, base_url = config.split("@")
elif "://" in config:
base_url = config
else:
api_key = mailbox
elif isinstance(mailbox, dict):
api_key = mailbox.get("api_key")
base_url = mailbox.get("base_url")
protocol = mailbox.get("protocol") or "http"
api_key = config
elif isinstance(config, dict):
api_key = config.get("api_key")
base_url = config.get("base_url") or base_url
protocol_override = config.get("protocol")
if "://" in base_url:
protocol, base_url = base_url.split("://")
else:
protocol = "wss"
protocol = protocol_override or protocol or "https"
http_prefix = "https" if protocol in {"wss", "https"} else "http"
return {
"api_key": api_key,
"base_url": base_url,
"protocol": protocol,
"http_prefix": http_prefix,
"use_mailbox": api_key is not None,
}


Expand Down
112 changes: 112 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import unittest

from uagents import Agent


agents = [
Agent(),
Agent(mailbox="api_key@some_url"),
Agent(mailbox={"api_key": "api_key", "base_url": "some_url"}),
Agent(mailbox="api_key"),
Agent(agentverse="api_key@some_url"),
Agent(agentverse="api_key"),
Agent(agentverse="http://some_url"),
Agent(agentverse="wss://some_url"),
Agent(agentverse="ws://some_url"),
Agent(agentverse={"api_key": "api_key", "protocol": "wss"}),
Agent(agentverse="https://staging.agentverse.ai"),
Agent(agentverse={"base_url": "staging.agentverse.ai"}),
]

expected_configs = [
{
"api_key": None,
"base_url": "agentverse.ai",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": False,
},
{
"api_key": "api_key",
"base_url": "some_url",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": "api_key",
"base_url": "some_url",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": "api_key",
"base_url": "agentverse.ai",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": "api_key",
"base_url": "some_url",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": "api_key",
"base_url": "agentverse.ai",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": None,
"base_url": "some_url",
"protocol": "http",
"http_prefix": "http",
"use_mailbox": False,
},
{
"api_key": None,
"base_url": "some_url",
"protocol": "wss",
"http_prefix": "https",
"use_mailbox": False,
},
{
"api_key": None,
"base_url": "some_url",
"protocol": "ws",
"http_prefix": "http",
"use_mailbox": False,
},
{
"api_key": "api_key",
"base_url": "agentverse.ai",
"protocol": "wss",
"http_prefix": "https",
"use_mailbox": True,
},
{
"api_key": None,
"base_url": "staging.agentverse.ai",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": False,
},
{
"api_key": None,
"base_url": "staging.agentverse.ai",
"protocol": "https",
"http_prefix": "https",
"use_mailbox": False,
},
]


class TestConfig(unittest.TestCase):
def test_parse_agentverse_config(self):
for agent, expected_config in zip(agents, expected_configs):
self.assertEqual(agent.agentverse, expected_config)

0 comments on commit 01ae9d1

Please sign in to comment.