uagents-core 0.3.3__py3-none-any.whl → 0.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
uagents_core/config.py CHANGED
@@ -7,6 +7,7 @@ DEFAULT_CHALLENGE_PATH = "/v1/auth/challenge"
7
7
  DEFAULT_MAILBOX_PATH = "/v1/submit"
8
8
  DEFAULT_PROXY_PATH = "/v1/proxy/submit"
9
9
  DEFAULT_STORAGE_PATH = "/v1/storage"
10
+ DEFAULT_PAYMENTS_PATH = "/v1/payments"
10
11
 
11
12
  DEFAULT_MAX_ENDPOINTS = 10
12
13
 
@@ -35,3 +36,7 @@ class AgentverseConfig(BaseModel):
35
36
  @property
36
37
  def storage_endpoint(self) -> str:
37
38
  return f"{self.url}{DEFAULT_STORAGE_PATH}"
39
+
40
+ @property
41
+ def payments_endpoint(self) -> str:
42
+ return f"{self.url}{DEFAULT_PAYMENTS_PATH}"
uagents_core/storage.py CHANGED
@@ -2,7 +2,6 @@ import base64
2
2
  import struct
3
3
  from datetime import datetime
4
4
  from secrets import token_bytes
5
- from typing import Optional
6
5
 
7
6
  import requests
8
7
 
@@ -34,38 +33,57 @@ def compute_attestation(
34
33
  class ExternalStorage:
35
34
  def __init__(
36
35
  self,
37
- identity: Optional[Identity] = None,
38
- storage_url: Optional[str] = None,
39
- api_token: Optional[str] = None,
36
+ *,
37
+ identity: Identity | None = None,
38
+ storage_url: str | None = None,
39
+ api_token: str | None = None,
40
40
  ):
41
41
  self.identity = identity
42
42
  self.api_token = api_token
43
+ if not (identity or api_token):
44
+ raise ValueError(
45
+ "Either an identity or an API token must be provided for authentication"
46
+ )
43
47
  self.storage_url = storage_url or AgentverseConfig().storage_endpoint
44
48
 
45
49
  def _make_attestation(self) -> str:
46
50
  nonce = token_bytes(32)
47
51
  now = datetime.now()
48
- return compute_attestation(self.identity, now, 3600, nonce)
52
+ if not self.identity:
53
+ raise RuntimeError("No identity available to create attestation")
54
+ return compute_attestation(
55
+ identity=self.identity,
56
+ validity_start=now,
57
+ validity_secs=3600,
58
+ nonce=nonce,
59
+ )
49
60
 
50
61
  def _get_auth_header(self) -> dict:
51
62
  if self.api_token:
52
63
  return {"Authorization": f"Bearer {self.api_token}"}
53
- elif self.identity:
64
+ if self.identity:
54
65
  return {"Authorization": f"Agent {self._make_attestation()}"}
55
- else:
56
- raise RuntimeError("No identity or API token available for authentication")
66
+ raise RuntimeError("No identity or API token available for authentication")
57
67
 
58
68
  def upload(
59
- self, asset_id: str, content: bytes, mime_type: str = "text/plain"
69
+ self,
70
+ asset_id: str,
71
+ asset_content: bytes,
72
+ mime_type: str = "text/plain",
60
73
  ) -> dict:
61
74
  url = f"{self.storage_url}/assets/{asset_id}/contents/"
62
75
  headers = self._get_auth_header()
63
76
  headers["Content-Type"] = "application/json"
64
77
  payload = {
65
- "contents": base64.b64encode(content).decode(),
78
+ "contents": base64.b64encode(asset_content).decode(),
66
79
  "mime_type": mime_type,
67
80
  }
68
- response = requests.put(url, json=payload, headers=headers)
81
+ response = requests.put(
82
+ url=url,
83
+ json=payload,
84
+ headers=headers,
85
+ timeout=10,
86
+ )
69
87
  if response.status_code != 200:
70
88
  raise RuntimeError(
71
89
  f"Upload failed: {response.status_code}, {response.text}"
@@ -76,8 +94,11 @@ class ExternalStorage:
76
94
  def download(self, asset_id: str) -> dict:
77
95
  url = f"{self.storage_url}/assets/{asset_id}/contents/"
78
96
  headers = self._get_auth_header()
79
-
80
- response = requests.get(url, headers=headers)
97
+ response = requests.get(
98
+ url=url,
99
+ headers=headers,
100
+ timeout=10,
101
+ )
81
102
  if response.status_code != 200:
82
103
  raise RuntimeError(
83
104
  f"Download failed: {response.status_code}, {response.text}"
@@ -104,7 +125,12 @@ class ExternalStorage:
104
125
  "lifetime_hours": lifetime_hours,
105
126
  }
106
127
 
107
- response = requests.post(url, json=payload, headers=headers)
128
+ response = requests.post(
129
+ url=url,
130
+ json=payload,
131
+ headers=headers,
132
+ timeout=10,
133
+ )
108
134
  if response.status_code != 201:
109
135
  raise RuntimeError(
110
136
  f"Asset creation failed: {response.status_code}, {response.text}"
@@ -114,7 +140,7 @@ class ExternalStorage:
114
140
 
115
141
  def set_permissions(
116
142
  self, asset_id: str, agent_address: str, read: bool = True, write: bool = True
117
- ):
143
+ ) -> dict:
118
144
  if not self.api_token:
119
145
  raise RuntimeError("API token required to set permissions")
120
146
  url = f"{self.storage_url}/assets/{asset_id}/permissions/"
@@ -126,7 +152,12 @@ class ExternalStorage:
126
152
  "write": write,
127
153
  }
128
154
 
129
- response = requests.put(url, json=payload, headers=headers)
155
+ response = requests.put(
156
+ url=url,
157
+ json=payload,
158
+ headers=headers,
159
+ timeout=10,
160
+ )
130
161
  if response.status_code != 200:
131
162
  raise RuntimeError(
132
163
  f"Set permissions failed: {response.status_code}, {response.text}"
@@ -0,0 +1,82 @@
1
+ """
2
+ This module provides methods related to agent bases subscriptions.
3
+
4
+ Example usage:
5
+ ```
6
+ from uagents_core.contrib.protocols.subscriptions import TierType
7
+
8
+ @protocol.on_message(ChatMessage)
9
+ async def handle_message(ctx: Context, sender: str, msg: ChatMessage):
10
+ subscription_tier = get_subscription_tier(
11
+ identity=ctx.agent.identity,
12
+ requester_address=sender
13
+ )
14
+
15
+ if subscription_tier == TierType.PLUS:
16
+ ...
17
+
18
+ if subscription_tier == TierType.PRO:
19
+ ...
20
+
21
+ ...
22
+ ```
23
+
24
+ """
25
+
26
+ from datetime import datetime
27
+ from secrets import token_bytes
28
+
29
+ import requests
30
+
31
+ from uagents_core.config import AgentverseConfig
32
+ from uagents_core.contrib.protocols.subscriptions import TierType
33
+ from uagents_core.identity import Identity
34
+ from uagents_core.logger import get_logger
35
+ from uagents_core.storage import compute_attestation
36
+
37
+ logger = get_logger("uagents_core.utils.subscriptions")
38
+
39
+
40
+ def get_subscription_tier(
41
+ identity: Identity,
42
+ requester_address: str,
43
+ agentverse_config: AgentverseConfig | None = None,
44
+ ) -> TierType:
45
+ """
46
+ Get the subscription tier of the requester for a specific agent.
47
+
48
+ This function is used to verify the type of subscription before processing
49
+ an incoming message.
50
+
51
+ Args:
52
+ identity (Identity): The identity of the agent that is requested.
53
+ requester_address (str): The address of the requester to check.
54
+ agentverse_config (AgentverseConfig | None): The configuration for the Agentverse.
55
+ If not provided, defaults to a new instance of AgentverseConfig.
56
+
57
+ Returns:
58
+ TierType: The subscription tier type of the requester.
59
+ """
60
+ if not agentverse_config:
61
+ agentverse_config = AgentverseConfig()
62
+ attestation: str = compute_attestation(
63
+ identity=identity,
64
+ validity_start=datetime.now(),
65
+ validity_secs=60,
66
+ nonce=token_bytes(nbytes=32),
67
+ )
68
+ url: str = (
69
+ f"{agentverse_config.payments_endpoint}/subscriptions"
70
+ + f"/{identity.address}/{requester_address}"
71
+ )
72
+ headers: dict[str, str] = {"Authorization": f"Agent {attestation}"}
73
+
74
+ try:
75
+ response = requests.get(url=url, headers=headers, timeout=10)
76
+ response.raise_for_status()
77
+ except requests.RequestException as e:
78
+ logger.error(f"Failed to get subscription tier: {e}")
79
+ return TierType.FREE
80
+
81
+ data: dict = response.json()
82
+ return data.get("tier_type", TierType.FREE)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: uagents-core
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Core components for agent based systems
5
5
  License: Apache 2.0
6
6
  Author: Ed FitzGerald
@@ -1,5 +1,5 @@
1
1
  uagents_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- uagents_core/config.py,sha256=Cz2c2qhS_0uqUPxG7mWiqQSXWI_rPrfC7VoTSwBkdWk,940
2
+ uagents_core/config.py,sha256=dvecXVs_Ej2UqjgrL96QwsEoUpkwJX5rQ09hikCRbDQ,1086
3
3
  uagents_core/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  uagents_core/contrib/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  uagents_core/contrib/protocols/chat/__init__.py,sha256=EAt2uQeaZtrSEdt2SiFyqFcC4nxKtyoJRaHhjKtwngw,3032
@@ -11,12 +11,13 @@ uagents_core/logger.py,sha256=5XLs3-XpKDeoSwtAE5pEM9h6x3pUPNbb0T0J7KvFmG0,877
11
11
  uagents_core/models.py,sha256=fxsFjRochkJUdgPltT1HWgBl-9K-HVQWl8sSMVgeJFY,1066
12
12
  uagents_core/protocol.py,sha256=T9jasOkltne33E16Y7VrqcB2moWVsv-Qh4XLZotyz8g,5428
13
13
  uagents_core/registration.py,sha256=lmDXnsAs2CvpgE1Ik0qja_0RAY7zJruK11_jUrlqlWs,3226
14
- uagents_core/storage.py,sha256=Nb_vvckp5FV48bcewFmYUoLFHAsWxwaiIv_-idFpGqQ,4480
14
+ uagents_core/storage.py,sha256=VLqMSFXOspzrlbUNvaqS95ht9oJze1c-p4CD6Ul80h4,5150
15
15
  uagents_core/types.py,sha256=_W3EN1wEIRFxuhhBxyZxQH_dA_3AtoPPReIzrgcTUHc,1167
16
16
  uagents_core/utils/__init__.py,sha256=v0MaxDYCTtQlwbblEHCfLtbeTnA2hCmKKJk7mlcE20U,135
17
17
  uagents_core/utils/messages.py,sha256=5o3ahVaeGwzWMAxDs0fl2pC1duDq2VS_-czoVtZpkOc,5066
18
18
  uagents_core/utils/registration.py,sha256=Lp17tn4knw4qpKx_mZO5gDHD6pGssUhux6SGDhhb7rc,14607
19
19
  uagents_core/utils/resolver.py,sha256=X18oe-WPU_6pfTc6x_Oa69kZQYCMidkaSeCs68Poaik,2169
20
- uagents_core-0.3.3.dist-info/METADATA,sha256=qXEPfhisZj17usBXwFkMcoFYtsd8l39XYGu5FHypvQc,1009
21
- uagents_core-0.3.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
22
- uagents_core-0.3.3.dist-info/RECORD,,
20
+ uagents_core/utils/subscriptions.py,sha256=l29elYqKycgU3s2SN_oh-svfhDkqZce0-EIiv4jjxJw,2450
21
+ uagents_core-0.3.4.dist-info/METADATA,sha256=ETB4mlX4APkU5KarF2ivzpT7C9I0xmsfXV_37DYYZrY,1009
22
+ uagents_core-0.3.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
23
+ uagents_core-0.3.4.dist-info/RECORD,,