agentaddress 0.9.1__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.
aap/__init__.py ADDED
@@ -0,0 +1,327 @@
1
+ """aap — reference Python implementation of the Agent Address Protocol."""
2
+
3
+ from aap.address import Address
4
+ from aap.envelope import Envelope, EnvelopeError
5
+ from aap.encryption import (
6
+ ENCRYPTED_ENVELOPE_TYPE,
7
+ HPKE_ALGORITHM,
8
+ EncryptedEnvelope,
9
+ EncryptionError,
10
+ decrypt_envelope,
11
+ derive_encryption_keypair,
12
+ encrypt_envelope,
13
+ encryption_key_id,
14
+ encryption_public_from_private,
15
+ generate_encryption_keypair,
16
+ )
17
+ from aap.envelope_policy import (
18
+ DEFAULT_ENVELOPE_MAX_AGE_SECONDS,
19
+ DEFAULT_FUTURE_SKEW_SECONDS,
20
+ EnvelopePolicyError,
21
+ EnvelopeReplayCache,
22
+ envelope_replay_key,
23
+ parse_rfc3339,
24
+ validate_envelope_iat,
25
+ verify_envelope,
26
+ )
27
+ from aap.keys import (
28
+ decode_b64url,
29
+ encode_b64url,
30
+ generate_keypair,
31
+ seed_to_keypair,
32
+ sign,
33
+ verify,
34
+ )
35
+ from aap.payloads import (
36
+ AgentCard,
37
+ DiscoveryIntroductionRequest,
38
+ DiscoveryIntroductionResponse,
39
+ DiscoveryQueryResponse,
40
+ GroupComplete,
41
+ GroupInvitation,
42
+ GroupLeave,
43
+ GroupMembershipUpdate,
44
+ RelationshipAccept,
45
+ RelationshipDecline,
46
+ RelationshipProposal,
47
+ RelationshipRevoke,
48
+ ServiceFollowup,
49
+ ServiceFollowupGrant,
50
+ ServiceRequest,
51
+ ServiceResponse,
52
+ ServiceResponseStatus,
53
+ VerificationAttestation,
54
+ VerifyConfirmResponse,
55
+ VerifyStartResponse,
56
+ VerifiedIdentity,
57
+ )
58
+ from aap.group_flow import (
59
+ build_group_complete_envelope,
60
+ build_group_invitation_envelope,
61
+ build_group_leave_envelope,
62
+ build_group_membership_update_envelope,
63
+ )
64
+ from aap.messages import (
65
+ CHAT_PAYLOAD_TYPE,
66
+ ROUTING_ENVELOPE_TYPE,
67
+ UnsupportedPayloadType,
68
+ build_chat_envelope,
69
+ unwrap_chat_envelope,
70
+ wrap_routing_envelope,
71
+ )
72
+ from aap.host_policy import (
73
+ DEFAULT_LIFETIME_DAYS,
74
+ HIGH_RISK_LIFETIME_DAYS,
75
+ WILDCARD,
76
+ is_high_risk_scope,
77
+ should_auto_renew,
78
+ token_lifetime_days,
79
+ )
80
+ from aap.inbound import (
81
+ InboundPolicyError,
82
+ ValidatedChat,
83
+ ValidatedEnvelope,
84
+ validate_inbound_chat,
85
+ validate_inbound_envelope,
86
+ )
87
+ from aap.trusted_verifiers import VerifierTrustListEntry, parse_trusted_verifiers
88
+ from aap.transport import InsecureTransportError, require_secure_url
89
+ from aap.client import AAPClient, AAPClientError, AgentCardKeyChanged, KeyChangeRejected
90
+ from aap.did_web import (
91
+ DIDWebError,
92
+ KeyPinChanged,
93
+ KeyPins,
94
+ did_web_document_url,
95
+ did_web_domain,
96
+ resolve_did_web_key,
97
+ )
98
+ from aap.identity import IdentityFile, load_or_generate
99
+ from aap.verifier_client import (
100
+ VerifierClientError,
101
+ VerifyStartResult,
102
+ confirm_email_verification,
103
+ confirm_sms_verification,
104
+ start_email_verification,
105
+ start_sms_verification,
106
+ )
107
+ from aap.verifiers import (
108
+ DEFAULT_TRUSTED_VERIFIERS_URL,
109
+ TRUSTED_VERIFIERS_ISSUER,
110
+ TRUSTED_VERIFIERS_PAYLOAD_TYPE,
111
+ TrustListCache,
112
+ VerifierPubkeyCache,
113
+ trusted_verifiers_supporting,
114
+ verifier_relay_address,
115
+ )
116
+ from aap.relationships import (
117
+ RelationshipRecord,
118
+ RelationshipRevocationRecord,
119
+ RelationshipStore,
120
+ VALID_RELATIONSHIP_TYPES,
121
+ build_relationship_accept_envelope,
122
+ build_relationship_decline_envelope,
123
+ build_relationship_proposal_envelope,
124
+ build_relationship_revoke_envelope,
125
+ )
126
+ from aap.services import (
127
+ SERVICE_CATALOG_PAYLOAD_TYPE,
128
+ ServiceCatalog,
129
+ ServiceCatalogCache,
130
+ ServiceCatalogPayload,
131
+ ServiceDefinition,
132
+ ValidationFailure,
133
+ build_service_catalog_envelope,
134
+ build_service_request_envelope,
135
+ build_service_response_envelope,
136
+ validate_service_payload,
137
+ )
138
+ from aap.service_followups import (
139
+ FollowupGrantStore,
140
+ StoredFollowupGrant,
141
+ build_followup_envelope,
142
+ build_followup_grant_envelope,
143
+ parse_iso_duration,
144
+ )
145
+ from aap.conversations import (
146
+ Conversation,
147
+ ConversationEventRecord,
148
+ ConversationPolicyError,
149
+ ConversationStore,
150
+ broadcast_to_conversation,
151
+ )
152
+ from aap.pending_responses import PendingResponses
153
+ from aap.stores.attestations import AttestationStore, StoredAttestation
154
+ from aap.stores.consent import PendingConsent
155
+ from aap.stores.identity_bindings import IdentityBinding, IdentityBindingStore
156
+ from aap.stores.outbound_contacts import DEFAULT_REPLY_WINDOW, OutboundContactStore
157
+ from aap.discovery import (
158
+ build_introduction_response_envelope,
159
+ extract_searcher_identities,
160
+ query_discovery,
161
+ )
162
+ from aap.stores.pending_introductions import PendingIntroductionRow, PendingIntroductions
163
+ from aap.stores.pending_proposals import (
164
+ PendingInbound,
165
+ PendingOutbound,
166
+ PendingProposalStore,
167
+ )
168
+ from aap.stores.verification_flow import PendingVerifications, PendingVerificationRow
169
+ from aap.stores.service_request_groups import ServiceRequestGroupIndex
170
+ from aap.stores.service_requests import (
171
+ ServiceRequestStore,
172
+ StoredServiceRequest,
173
+ StoredServiceResponse,
174
+ )
175
+ from aap.version import __version__
176
+
177
+ __all__ = [
178
+ "__version__",
179
+ "AAPClient",
180
+ "AAPClientError",
181
+ "AgentCardKeyChanged",
182
+ "Address",
183
+ "AgentCard",
184
+ "AttestationStore",
185
+ "CHAT_PAYLOAD_TYPE",
186
+ "Conversation",
187
+ "ConversationEventRecord",
188
+ "ConversationPolicyError",
189
+ "ConversationStore",
190
+ "DEFAULT_LIFETIME_DAYS",
191
+ "DEFAULT_ENVELOPE_MAX_AGE_SECONDS",
192
+ "DEFAULT_FUTURE_SKEW_SECONDS",
193
+ "DEFAULT_REPLY_WINDOW",
194
+ "DEFAULT_TRUSTED_VERIFIERS_URL",
195
+ "TRUSTED_VERIFIERS_ISSUER",
196
+ "TRUSTED_VERIFIERS_PAYLOAD_TYPE",
197
+ "DIDWebError",
198
+ "KeyPinChanged",
199
+ "KeyPins",
200
+ "DiscoveryIntroductionRequest",
201
+ "DiscoveryIntroductionResponse",
202
+ "DiscoveryQueryResponse",
203
+ "Envelope",
204
+ "EnvelopeError",
205
+ "EnvelopePolicyError",
206
+ "EnvelopeReplayCache",
207
+ "ENCRYPTED_ENVELOPE_TYPE",
208
+ "EncryptedEnvelope",
209
+ "EncryptionError",
210
+ "FollowupGrantStore",
211
+ "GroupComplete",
212
+ "GroupInvitation",
213
+ "GroupLeave",
214
+ "GroupMembershipUpdate",
215
+ "HIGH_RISK_LIFETIME_DAYS",
216
+ "HPKE_ALGORITHM",
217
+ "IdentityBinding",
218
+ "IdentityBindingStore",
219
+ "IdentityFile",
220
+ "InsecureTransportError",
221
+ "InboundPolicyError",
222
+ "KeyChangeRejected",
223
+ "OutboundContactStore",
224
+ "PendingConsent",
225
+ "PendingIntroductionRow",
226
+ "PendingIntroductions",
227
+ "PendingInbound",
228
+ "PendingOutbound",
229
+ "PendingProposalStore",
230
+ "PendingResponses",
231
+ "PendingVerificationRow",
232
+ "PendingVerifications",
233
+ "ROUTING_ENVELOPE_TYPE",
234
+ "SERVICE_CATALOG_PAYLOAD_TYPE",
235
+ "RelationshipAccept",
236
+ "RelationshipDecline",
237
+ "RelationshipProposal",
238
+ "RelationshipRecord",
239
+ "RelationshipRevocationRecord",
240
+ "RelationshipRevoke",
241
+ "RelationshipStore",
242
+ "ServiceCatalog",
243
+ "ServiceCatalogCache",
244
+ "ServiceCatalogPayload",
245
+ "ServiceDefinition",
246
+ "ServiceFollowup",
247
+ "ServiceFollowupGrant",
248
+ "ServiceRequest",
249
+ "ServiceRequestGroupIndex",
250
+ "ServiceRequestStore",
251
+ "ServiceResponse",
252
+ "ServiceResponseStatus",
253
+ "StoredAttestation",
254
+ "StoredFollowupGrant",
255
+ "StoredServiceRequest",
256
+ "StoredServiceResponse",
257
+ "TrustListCache",
258
+ "UnsupportedPayloadType",
259
+ "VALID_RELATIONSHIP_TYPES",
260
+ "ValidationFailure",
261
+ "VerificationAttestation",
262
+ "VerifyConfirmResponse",
263
+ "VerifyStartResponse",
264
+ "VerifiedIdentity",
265
+ "VerifierClientError",
266
+ "VerifierPubkeyCache",
267
+ "VerifierTrustListEntry",
268
+ "VerifyStartResult",
269
+ "ValidatedChat",
270
+ "ValidatedEnvelope",
271
+ "WILDCARD",
272
+ "broadcast_to_conversation",
273
+ "build_chat_envelope",
274
+ "build_followup_envelope",
275
+ "build_followup_grant_envelope",
276
+ "build_group_complete_envelope",
277
+ "build_group_invitation_envelope",
278
+ "build_group_leave_envelope",
279
+ "build_group_membership_update_envelope",
280
+ "build_introduction_response_envelope",
281
+ "build_relationship_accept_envelope",
282
+ "build_relationship_decline_envelope",
283
+ "build_relationship_proposal_envelope",
284
+ "build_relationship_revoke_envelope",
285
+ "build_service_catalog_envelope",
286
+ "build_service_request_envelope",
287
+ "build_service_response_envelope",
288
+ "confirm_email_verification",
289
+ "confirm_sms_verification",
290
+ "decode_b64url",
291
+ "did_web_document_url",
292
+ "did_web_domain",
293
+ "decrypt_envelope",
294
+ "derive_encryption_keypair",
295
+ "encode_b64url",
296
+ "encrypt_envelope",
297
+ "encryption_key_id",
298
+ "encryption_public_from_private",
299
+ "envelope_replay_key",
300
+ "extract_searcher_identities",
301
+ "generate_keypair",
302
+ "generate_encryption_keypair",
303
+ "is_high_risk_scope",
304
+ "load_or_generate",
305
+ "parse_iso_duration",
306
+ "parse_rfc3339",
307
+ "parse_trusted_verifiers",
308
+ "query_discovery",
309
+ "require_secure_url",
310
+ "resolve_did_web_key",
311
+ "seed_to_keypair",
312
+ "should_auto_renew",
313
+ "sign",
314
+ "start_email_verification",
315
+ "start_sms_verification",
316
+ "token_lifetime_days",
317
+ "trusted_verifiers_supporting",
318
+ "unwrap_chat_envelope",
319
+ "validate_inbound_chat",
320
+ "validate_inbound_envelope",
321
+ "validate_service_payload",
322
+ "validate_envelope_iat",
323
+ "verifier_relay_address",
324
+ "verify",
325
+ "verify_envelope",
326
+ "wrap_routing_envelope",
327
+ ]
aap/address.py ADDED
@@ -0,0 +1,88 @@
1
+ """AAP address: <localpart>^<domain>.
2
+
3
+ Localpart accepts ASCII alphanumerics, '.', '-', '_'. Case-insensitive
4
+ — normalised to lowercase on parse so ``Chris-work`` and ``chris-work``
5
+ route to the same agent. Max length 64.
6
+
7
+ Domain accepts ASCII alphanumerics, '.', '-'. Normalised to lowercase
8
+ on parse (DNS labels are case-insensitive). Max length 253.
9
+
10
+ The ``^`` separator was chosen because it (a) is easy to type
11
+ (shift+6 on the number row), (b) is shell- and URL-safe in practice,
12
+ and (c) appears in neither the localpart nor the domain grammar, so
13
+ the split is unambiguous. The format intentionally does not resemble
14
+ an email address.
15
+
16
+ DNS-level checks (label length, leading/trailing hyphen, IDN punycode)
17
+ happen at resolution time, not parse time.
18
+ """
19
+
20
+ from dataclasses import dataclass
21
+
22
+ _LOCALPART_MAX = 64
23
+ _DOMAIN_MAX = 253
24
+ # `+` is allowed in the localpart so derivative addresses like
25
+ # `chris+work^…` parse cleanly. The address-claim system uses the
26
+ # part before the first `+` as the base; for parsing purposes here `+`
27
+ # is just another permitted character.
28
+ _ALLOWED_LOCALPART_EXTRA = frozenset(".-_+")
29
+ _ALLOWED_DOMAIN_EXTRA = frozenset(".-")
30
+
31
+
32
+ def _valid_localpart_char(c: str) -> bool:
33
+ return (c.isalnum() and c.isascii()) or (c in _ALLOWED_LOCALPART_EXTRA)
34
+
35
+
36
+ def _valid_domain_char(c: str) -> bool:
37
+ return (c.isalnum() and c.isascii()) or (c in _ALLOWED_DOMAIN_EXTRA)
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class Address:
42
+ localpart: str
43
+ domain: str
44
+
45
+ @classmethod
46
+ def parse(cls, s: str) -> "Address":
47
+ if "^" not in s:
48
+ raise ValueError(f"AAP address must contain '^': {s!r}")
49
+ localpart, domain = s.rsplit("^", 1)
50
+ if not localpart:
51
+ raise ValueError("localpart cannot be empty")
52
+ if not domain:
53
+ raise ValueError("domain cannot be empty")
54
+ if len(localpart) > _LOCALPART_MAX:
55
+ raise ValueError(
56
+ f"localpart too long ({len(localpart)} > {_LOCALPART_MAX})"
57
+ )
58
+ if not all(_valid_localpart_char(c) for c in localpart):
59
+ raise ValueError(f"localpart contains invalid characters: {localpart!r}")
60
+ localpart = localpart.lower()
61
+ if len(domain) > _DOMAIN_MAX:
62
+ raise ValueError(f"domain too long ({len(domain)} > {_DOMAIN_MAX})")
63
+ domain = domain.lower()
64
+ if not all(_valid_domain_char(c) for c in domain):
65
+ raise ValueError(f"domain contains invalid characters: {domain!r}")
66
+ return cls(localpart=localpart, domain=domain)
67
+
68
+ @classmethod
69
+ def parse_user_input(
70
+ cls,
71
+ s: str,
72
+ *,
73
+ default_domain: str = "agentaddress.org",
74
+ ) -> "Address":
75
+ """Parse human/LLM-entered address text.
76
+
77
+ A trailing caret is shorthand for the hosted Agent Address namespace:
78
+ ``chris^`` expands to ``chris^agentaddress.org``. The expanded value is
79
+ then passed through strict parsing so protocol validation remains in one
80
+ place.
81
+ """
82
+ value = s.strip()
83
+ if value.endswith("^"):
84
+ value = f"{value}{default_domain}"
85
+ return cls.parse(value)
86
+
87
+ def __str__(self) -> str:
88
+ return f"{self.localpart}^{self.domain}"