uagents-core 0.2.3__tar.gz → 0.3.1__tar.gz
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-0.2.3 → uagents_core-0.3.1}/PKG-INFO +1 -1
- {uagents_core-0.2.3 → uagents_core-0.3.1}/pyproject.toml +1 -1
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/config.py +5 -0
- uagents_core-0.3.1/uagents_core/storage.py +135 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/README.md +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/contrib/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/contrib/protocols/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/contrib/protocols/chat/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/contrib/protocols/subscriptions/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/envelope.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/helpers.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/identity.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/logger.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/models.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/protocol.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/registration.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/types.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/utils/__init__.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/utils/messages.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/utils/registration.py +0 -0
- {uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/utils/resolver.py +0 -0
@@ -6,6 +6,7 @@ DEFAULT_REGISTRATION_PATH = "/v1/agents"
|
|
6
6
|
DEFAULT_CHALLENGE_PATH = "/v1/auth/challenge"
|
7
7
|
DEFAULT_MAILBOX_PATH = "/v1/submit"
|
8
8
|
DEFAULT_PROXY_PATH = "/v1/proxy/submit"
|
9
|
+
DEFAULT_STORAGE_PATH = "/v1/storage"
|
9
10
|
|
10
11
|
DEFAULT_MAX_ENDPOINTS = 10
|
11
12
|
|
@@ -30,3 +31,7 @@ class AgentverseConfig(BaseModel):
|
|
30
31
|
@property
|
31
32
|
def proxy_endpoint(self) -> str:
|
32
33
|
return f"{self.url}{DEFAULT_PROXY_PATH}"
|
34
|
+
|
35
|
+
@property
|
36
|
+
def storage_endpoint(self) -> str:
|
37
|
+
return f"{self.url}{DEFAULT_STORAGE_PATH}"
|
@@ -0,0 +1,135 @@
|
|
1
|
+
import base64
|
2
|
+
import struct
|
3
|
+
from datetime import datetime
|
4
|
+
from secrets import token_bytes
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
import requests
|
8
|
+
|
9
|
+
from uagents_core.config import AgentverseConfig
|
10
|
+
from uagents_core.identity import Identity
|
11
|
+
|
12
|
+
|
13
|
+
def compute_attestation(
|
14
|
+
identity: Identity, validity_start: datetime, validity_secs: int, nonce: bytes
|
15
|
+
) -> str:
|
16
|
+
"""
|
17
|
+
Compute a valid agent attestation token for authentication.
|
18
|
+
"""
|
19
|
+
assert len(nonce) == 32, "Nonce is of invalid length"
|
20
|
+
|
21
|
+
valid_from = int(validity_start.timestamp())
|
22
|
+
valid_to = valid_from + validity_secs
|
23
|
+
|
24
|
+
public_key = bytes.fromhex(identity.pub_key)
|
25
|
+
|
26
|
+
payload = public_key + struct.pack(">QQ", valid_from, valid_to) + nonce
|
27
|
+
assert len(payload) == 81, "attestation payload is incorrect"
|
28
|
+
|
29
|
+
signature = identity.sign(payload)
|
30
|
+
attestation = f"attr:{base64.b64encode(payload).decode()}:{signature}"
|
31
|
+
return attestation
|
32
|
+
|
33
|
+
|
34
|
+
class ExternalStorage:
|
35
|
+
def __init__(
|
36
|
+
self,
|
37
|
+
identity: Optional[Identity] = None,
|
38
|
+
storage_url: Optional[str] = None,
|
39
|
+
api_token: Optional[str] = None,
|
40
|
+
):
|
41
|
+
self.identity = identity
|
42
|
+
self.api_token = api_token
|
43
|
+
self.storage_url = storage_url or AgentverseConfig().storage_endpoint
|
44
|
+
|
45
|
+
def _make_attestation(self) -> str:
|
46
|
+
nonce = token_bytes(32)
|
47
|
+
now = datetime.now()
|
48
|
+
return compute_attestation(self.identity, now, 3600, nonce)
|
49
|
+
|
50
|
+
def _get_auth_header(self) -> dict:
|
51
|
+
if self.api_token:
|
52
|
+
return {"Authorization": f"Bearer {self.api_token}"}
|
53
|
+
elif self.identity:
|
54
|
+
return {"Authorization": f"Agent {self._make_attestation()}"}
|
55
|
+
else:
|
56
|
+
raise RuntimeError("No identity or API token available for authentication")
|
57
|
+
|
58
|
+
def upload(
|
59
|
+
self, asset_id: str, asset_content: bytes, mime_type: str = "text/plain"
|
60
|
+
) -> dict:
|
61
|
+
url = f"{self.storage_url}/assets/{asset_id}/contents/"
|
62
|
+
headers = self._get_auth_header()
|
63
|
+
headers["Content-Type"] = "application/json"
|
64
|
+
payload = {
|
65
|
+
"contents": base64.b64encode(content).decode(),
|
66
|
+
"mime_type": mime_type,
|
67
|
+
}
|
68
|
+
response = requests.put(url, json=payload, headers=headers)
|
69
|
+
if response.status_code != 200:
|
70
|
+
raise RuntimeError(
|
71
|
+
f"Upload failed: {response.status_code}, {response.text}"
|
72
|
+
)
|
73
|
+
|
74
|
+
return response.json()
|
75
|
+
|
76
|
+
def download(self, asset_id: str) -> dict:
|
77
|
+
url = f"{self.storage_url}/assets/{asset_id}/contents/"
|
78
|
+
headers = self._get_auth_header()
|
79
|
+
|
80
|
+
response = requests.get(url, headers=headers)
|
81
|
+
if response.status_code != 200:
|
82
|
+
raise RuntimeError(
|
83
|
+
f"Download failed: {response.status_code}, {response.text}"
|
84
|
+
)
|
85
|
+
|
86
|
+
return response.json()
|
87
|
+
|
88
|
+
def create_asset(
|
89
|
+
self,
|
90
|
+
name: str,
|
91
|
+
content: bytes,
|
92
|
+
mime_type: str = "text/plain",
|
93
|
+
lifetime_hours: int = 24,
|
94
|
+
) -> str:
|
95
|
+
if not self.api_token:
|
96
|
+
raise RuntimeError("API token required to create assets")
|
97
|
+
url = f"{self.storage_url}/assets/"
|
98
|
+
headers = self._get_auth_header()
|
99
|
+
headers["Content-Type"] = "application/json"
|
100
|
+
payload = {
|
101
|
+
"name": name,
|
102
|
+
"mime_type": mime_type,
|
103
|
+
"contents": base64.b64encode(content).decode(),
|
104
|
+
"lifetime_hours": lifetime_hours,
|
105
|
+
}
|
106
|
+
|
107
|
+
response = requests.post(url, json=payload, headers=headers)
|
108
|
+
if response.status_code != 201:
|
109
|
+
raise RuntimeError(
|
110
|
+
f"Asset creation failed: {response.status_code}, {response.text}"
|
111
|
+
)
|
112
|
+
|
113
|
+
return response.json()["asset_id"]
|
114
|
+
|
115
|
+
def set_permissions(
|
116
|
+
self, asset_id: str, agent_address: str, read: bool = True, write: bool = True
|
117
|
+
):
|
118
|
+
if not self.api_token:
|
119
|
+
raise RuntimeError("API token required to set permissions")
|
120
|
+
url = f"{self.storage_url}/assets/{asset_id}/permissions/"
|
121
|
+
headers = self._get_auth_header()
|
122
|
+
headers["Content-Type"] = "application/json"
|
123
|
+
payload = {
|
124
|
+
"agent_address": agent_address,
|
125
|
+
"read": read,
|
126
|
+
"write": write,
|
127
|
+
}
|
128
|
+
|
129
|
+
response = requests.put(url, json=payload, headers=headers)
|
130
|
+
if response.status_code != 200:
|
131
|
+
raise RuntimeError(
|
132
|
+
f"Set permissions failed: {response.status_code}, {response.text}"
|
133
|
+
)
|
134
|
+
|
135
|
+
return response.json()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{uagents_core-0.2.3 → uagents_core-0.3.1}/uagents_core/contrib/protocols/subscriptions/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|