uagents-core 0.3.1__tar.gz → 0.3.3__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.3.1 → uagents_core-0.3.3}/PKG-INFO +1 -1
- {uagents_core-0.3.1 → uagents_core-0.3.3}/pyproject.toml +1 -1
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/registration.py +11 -1
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/storage.py +1 -1
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/utils/registration.py +176 -16
- {uagents_core-0.3.1 → uagents_core-0.3.3}/README.md +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/config.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/contrib/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/contrib/protocols/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/contrib/protocols/chat/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/contrib/protocols/subscriptions/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/envelope.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/helpers.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/identity.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/logger.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/models.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/protocol.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/types.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/utils/__init__.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/utils/messages.py +0 -0
- {uagents_core-0.3.1 → uagents_core-0.3.3}/uagents_core/utils/resolver.py +0 -0
@@ -70,7 +70,11 @@ class VerifiableModel(BaseModel):
|
|
70
70
|
class AgentRegistrationAttestation(VerifiableModel):
|
71
71
|
protocols: list[str]
|
72
72
|
endpoints: list[AgentEndpoint]
|
73
|
-
metadata: dict[str, str | dict[str, str]] | None = None
|
73
|
+
metadata: dict[str, str | list[str] | dict[str, str]] | None = None
|
74
|
+
|
75
|
+
|
76
|
+
class AgentRegistrationAttestationBatch(BaseModel):
|
77
|
+
attestations: list[AgentRegistrationAttestation]
|
74
78
|
|
75
79
|
|
76
80
|
# Agentverse related models
|
@@ -107,3 +111,9 @@ class AgentUpdates(BaseModel):
|
|
107
111
|
avatar_url: str | None = Field(default=None, max_length=4000)
|
108
112
|
short_description: str | None = Field(default=None, max_length=300)
|
109
113
|
agent_type: AgentType | None = "custom"
|
114
|
+
|
115
|
+
|
116
|
+
class AgentStatusUpdate(VerifiableModel):
|
117
|
+
is_active: bool = Field(
|
118
|
+
..., description="Indicates whether the agent is currently active"
|
119
|
+
)
|
@@ -56,7 +56,7 @@ class ExternalStorage:
|
|
56
56
|
raise RuntimeError("No identity or API token available for authentication")
|
57
57
|
|
58
58
|
def upload(
|
59
|
-
self, asset_id: str,
|
59
|
+
self, asset_id: str, content: bytes, mime_type: str = "text/plain"
|
60
60
|
) -> dict:
|
61
61
|
url = f"{self.storage_url}/assets/{asset_id}/contents/"
|
62
62
|
headers = self._get_auth_header()
|
@@ -19,6 +19,8 @@ from uagents_core.logger import get_logger
|
|
19
19
|
from uagents_core.protocol import is_valid_protocol_digest
|
20
20
|
from uagents_core.registration import (
|
21
21
|
AgentRegistrationAttestation,
|
22
|
+
AgentRegistrationAttestationBatch,
|
23
|
+
AgentStatusUpdate,
|
22
24
|
AgentUpdates,
|
23
25
|
AgentverseConnectRequest,
|
24
26
|
ChallengeRequest,
|
@@ -26,11 +28,33 @@ from uagents_core.registration import (
|
|
26
28
|
RegistrationRequest,
|
27
29
|
RegistrationResponse,
|
28
30
|
)
|
29
|
-
from uagents_core.types import AgentEndpoint
|
31
|
+
from uagents_core.types import AddressPrefix, AgentEndpoint
|
30
32
|
|
31
33
|
logger = get_logger("uagents_core.utils.registration")
|
32
34
|
|
33
35
|
|
36
|
+
class AgentRegistrationInput:
|
37
|
+
identity: Identity
|
38
|
+
prefix: str | None = None
|
39
|
+
endpoints: list[str]
|
40
|
+
protocol_digests: list[str]
|
41
|
+
metadata: dict[str, str | list[str] | dict[str, str]] | None = None
|
42
|
+
|
43
|
+
def __init__(
|
44
|
+
self,
|
45
|
+
identity: Identity,
|
46
|
+
endpoints: list[str],
|
47
|
+
protocol_digests: list[str],
|
48
|
+
prefix: AddressPrefix | None = None,
|
49
|
+
metadata: dict[str, str | list[str] | dict[str, str]] | None = None,
|
50
|
+
):
|
51
|
+
self.identity = identity
|
52
|
+
self.prefix = prefix
|
53
|
+
self.endpoints = endpoints
|
54
|
+
self.protocol_digests = protocol_digests
|
55
|
+
self.metadata = metadata
|
56
|
+
|
57
|
+
|
34
58
|
def _send_post_request(
|
35
59
|
url: str,
|
36
60
|
data: BaseModel,
|
@@ -62,11 +86,32 @@ def _send_post_request(
|
|
62
86
|
return False, None
|
63
87
|
|
64
88
|
|
89
|
+
def _build_signed_attestation(
|
90
|
+
item: AgentRegistrationInput,
|
91
|
+
) -> AgentRegistrationAttestation:
|
92
|
+
agent_endpoints: list[AgentEndpoint] = [
|
93
|
+
AgentEndpoint(url=endpoint, weight=1) for endpoint in item.endpoints
|
94
|
+
]
|
95
|
+
|
96
|
+
attestation = AgentRegistrationAttestation(
|
97
|
+
agent_identifier=f"{item.prefix}://{item.identity.address}"
|
98
|
+
if item.prefix
|
99
|
+
else item.identity.address,
|
100
|
+
protocols=item.protocol_digests,
|
101
|
+
endpoints=agent_endpoints,
|
102
|
+
metadata=item.metadata,
|
103
|
+
)
|
104
|
+
|
105
|
+
attestation.sign(item.identity)
|
106
|
+
return attestation
|
107
|
+
|
108
|
+
|
65
109
|
def register_in_almanac(
|
66
110
|
identity: Identity,
|
67
111
|
endpoints: list[str],
|
68
112
|
protocol_digests: list[str],
|
69
|
-
metadata: dict[str, str | dict[str, str]] | None = None,
|
113
|
+
metadata: dict[str, str | list[str] | dict[str, str]] | None = None,
|
114
|
+
prefix: AddressPrefix | None = None,
|
70
115
|
*,
|
71
116
|
agentverse_config: AgentverseConfig | None = None,
|
72
117
|
timeout: int = DEFAULT_REQUEST_TIMEOUT,
|
@@ -76,6 +121,7 @@ def register_in_almanac(
|
|
76
121
|
|
77
122
|
Args:
|
78
123
|
identity (Identity): The identity of the agent.
|
124
|
+
prefix (AddressPrefix | None): The prefix for the agent identifier.
|
79
125
|
endpoints (list[str]): The endpoints that the agent can be reached at.
|
80
126
|
protocol_digests (list[str]): The digests of the protocol that the agent supports
|
81
127
|
agentverse_config (AgentverseConfig): The configuration for the agentverse API
|
@@ -94,10 +140,6 @@ def register_in_almanac(
|
|
94
140
|
)
|
95
141
|
return False
|
96
142
|
|
97
|
-
agent_endpoints: list[AgentEndpoint] = [
|
98
|
-
AgentEndpoint(url=endpoint, weight=1) for endpoint in endpoints
|
99
|
-
]
|
100
|
-
|
101
143
|
# check protocol digests
|
102
144
|
for proto_digest in protocol_digests:
|
103
145
|
if not is_valid_protocol_digest(proto_digest):
|
@@ -111,22 +153,18 @@ def register_in_almanac(
|
|
111
153
|
agentverse_config = agentverse_config or AgentverseConfig()
|
112
154
|
almanac_api = urllib.parse.urljoin(agentverse_config.url, DEFAULT_ALMANAC_API_PATH)
|
113
155
|
|
114
|
-
# get the agent address
|
115
|
-
agent_address = identity.address
|
116
|
-
|
117
156
|
# create the attestation
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
endpoints=
|
157
|
+
item = AgentRegistrationInput(
|
158
|
+
identity=identity,
|
159
|
+
prefix=prefix,
|
160
|
+
endpoints=endpoints,
|
161
|
+
protocol_digests=protocol_digests,
|
122
162
|
metadata=metadata,
|
123
163
|
)
|
164
|
+
attestation = _build_signed_attestation(item)
|
124
165
|
|
125
166
|
logger.info(msg="Registering with Almanac API", extra=attestation.model_dump())
|
126
167
|
|
127
|
-
# sign the attestation
|
128
|
-
attestation.sign(identity)
|
129
|
-
|
130
168
|
# submit the attestation to the API
|
131
169
|
status, _ = _send_post_request(
|
132
170
|
url=f"{almanac_api}/agents", data=attestation, timeout=timeout
|
@@ -134,6 +172,94 @@ def register_in_almanac(
|
|
134
172
|
return status
|
135
173
|
|
136
174
|
|
175
|
+
def register_batch_in_almanac(
|
176
|
+
items: list[AgentRegistrationInput],
|
177
|
+
*,
|
178
|
+
agentverse_config: AgentverseConfig | None = None,
|
179
|
+
timeout: int = DEFAULT_REQUEST_TIMEOUT,
|
180
|
+
validate_all_before_registration: bool = False,
|
181
|
+
) -> tuple[bool, list[str]]:
|
182
|
+
"""
|
183
|
+
Register multiple identities with the Almanac API to make them discoverable by other agents.
|
184
|
+
|
185
|
+
The return value is a 2-tuple including:
|
186
|
+
* (bool) Whether the registration request was both attempted and successful.
|
187
|
+
* (list[str]) A list of addresses of identities that failed validation.
|
188
|
+
|
189
|
+
If `validate_all_before_registration` is `True`, no registration request will be sent
|
190
|
+
unless all identities pass validation.
|
191
|
+
|
192
|
+
Args:
|
193
|
+
items (list[AgentRegistrationInput]): The list of identities to register.
|
194
|
+
See `register_in_almanac` for details about attributes in `AgentRegistrationInput`.
|
195
|
+
agentverse_config (AgentverseConfig): The configuration for the agentverse API
|
196
|
+
timeout (int): The timeout for the request
|
197
|
+
"""
|
198
|
+
invalid_identities: list[str] = []
|
199
|
+
attestations: list[AgentRegistrationAttestation] = []
|
200
|
+
|
201
|
+
for item in items:
|
202
|
+
# check endpoints
|
203
|
+
if not item.endpoints:
|
204
|
+
logger.warning(
|
205
|
+
f"No endpoints provided for {item.identity.address}; skipping registration",
|
206
|
+
)
|
207
|
+
invalid_identities.append(item.identity.address)
|
208
|
+
for endpoint in item.endpoints:
|
209
|
+
result = urllib.parse.urlparse(endpoint)
|
210
|
+
if not all([result.scheme, result.netloc]):
|
211
|
+
logger.error(
|
212
|
+
msg=f"Invalid endpoint provided for {item.identity.address}; "
|
213
|
+
+ "skipping registration",
|
214
|
+
extra={"endpoint": endpoint},
|
215
|
+
)
|
216
|
+
invalid_identities.append(item.identity.address)
|
217
|
+
|
218
|
+
# check protocol digests
|
219
|
+
for proto_digest in item.protocol_digests:
|
220
|
+
if not is_valid_protocol_digest(proto_digest):
|
221
|
+
logger.error(
|
222
|
+
msg=f"Invalid protocol digest provided for {item.identity.address}; "
|
223
|
+
+ "skipping registration",
|
224
|
+
extra={"protocol_digest": proto_digest},
|
225
|
+
)
|
226
|
+
invalid_identities.append(item.identity.address)
|
227
|
+
|
228
|
+
# Remove duplicates
|
229
|
+
invalid_identities = sorted(list(set(invalid_identities)))
|
230
|
+
|
231
|
+
for item in items:
|
232
|
+
if item.identity.address not in invalid_identities:
|
233
|
+
attestations.append(_build_signed_attestation(item))
|
234
|
+
|
235
|
+
if validate_all_before_registration and invalid_identities:
|
236
|
+
return False, invalid_identities
|
237
|
+
|
238
|
+
# get the almanac API endpoint
|
239
|
+
agentverse_config = agentverse_config or AgentverseConfig()
|
240
|
+
almanac_api = urllib.parse.urljoin(agentverse_config.url, DEFAULT_ALMANAC_API_PATH)
|
241
|
+
|
242
|
+
logger.info(
|
243
|
+
msg="Bulk registering with Almanac API",
|
244
|
+
extra={
|
245
|
+
"agent_addresses": [
|
246
|
+
attestation.agent_identifier for attestation in attestations
|
247
|
+
]
|
248
|
+
},
|
249
|
+
)
|
250
|
+
attestation_batch = AgentRegistrationAttestationBatch(
|
251
|
+
attestations=attestations,
|
252
|
+
)
|
253
|
+
|
254
|
+
# submit the attestation to the API
|
255
|
+
status, _ = _send_post_request(
|
256
|
+
url=f"{almanac_api}/agents/batch",
|
257
|
+
data=attestation_batch,
|
258
|
+
timeout=timeout,
|
259
|
+
)
|
260
|
+
return status, invalid_identities
|
261
|
+
|
262
|
+
|
137
263
|
# associate user account with your agent
|
138
264
|
def register_in_agentverse(
|
139
265
|
request: AgentverseConnectRequest,
|
@@ -269,3 +395,37 @@ def register_in_agentverse(
|
|
269
395
|
exc_info=e,
|
270
396
|
)
|
271
397
|
return False
|
398
|
+
|
399
|
+
|
400
|
+
def update_agent_status(active: bool, identity: Identity):
|
401
|
+
"""
|
402
|
+
Update the agent's active/inactive status in the Almanac API.
|
403
|
+
|
404
|
+
Args:
|
405
|
+
active (bool): The status of the agent.
|
406
|
+
identity (Identity): The identity of the agent.
|
407
|
+
"""
|
408
|
+
almanac_api = AgentverseConfig().url + DEFAULT_ALMANAC_API_PATH
|
409
|
+
|
410
|
+
status_update = AgentStatusUpdate(
|
411
|
+
agent_identifier=identity.address, is_active=active
|
412
|
+
)
|
413
|
+
status_update.sign(identity)
|
414
|
+
|
415
|
+
logger.debug(
|
416
|
+
msg="Updating agent status in Almanac API",
|
417
|
+
extra=status_update.model_dump(),
|
418
|
+
)
|
419
|
+
|
420
|
+
status, _ = _send_post_request(
|
421
|
+
url=f"{almanac_api}/agents/{identity.address}/status",
|
422
|
+
data=status_update,
|
423
|
+
)
|
424
|
+
|
425
|
+
if status:
|
426
|
+
logger.info(
|
427
|
+
msg=f"Agent status updated to {'active' if active else 'inactive'}",
|
428
|
+
extra={"agent_address": identity.address},
|
429
|
+
)
|
430
|
+
|
431
|
+
return status
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{uagents_core-0.3.1 → uagents_core-0.3.3}/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
|