theprotocol-sdk 0.2.0__tar.gz → 0.5.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.
Files changed (67) hide show
  1. theprotocol_sdk-0.5.1/.gitignore +59 -0
  2. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/PKG-INFO +69 -3
  3. theprotocol_sdk-0.5.1/README.md +161 -0
  4. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/pyproject.toml +3 -3
  5. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/__init__.py +2 -1
  6. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/agent/__init__.py +7 -0
  7. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/agent/router.py +83 -2
  8. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/agent/task_store.py +14 -1
  9. theprotocol_sdk-0.5.1/src/theprotocol/agent/well_known.py +370 -0
  10. theprotocol_sdk-0.5.1/src/theprotocol/auth/__init__.py +47 -0
  11. theprotocol_sdk-0.5.1/src/theprotocol/auth/did_jwt.py +203 -0
  12. theprotocol_sdk-0.5.1/src/theprotocol/auth/jws_card.py +207 -0
  13. theprotocol_sdk-0.5.1/src/theprotocol/auth/jwt_verifier.py +165 -0
  14. theprotocol_sdk-0.5.1/src/theprotocol/exchange/__init__.py +4 -0
  15. theprotocol_sdk-0.5.1/src/theprotocol/exchange/client.py +124 -0
  16. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/models/__init__.py +2 -0
  17. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/models/a2a_protocol.py +1 -0
  18. theprotocol_sdk-0.5.1/src/theprotocol/models/agent_card.py +192 -0
  19. theprotocol_sdk-0.5.1/src/theprotocol/models/v1_compat.py +580 -0
  20. theprotocol_sdk-0.5.1/src/theprotocol/payment/__init__.py +33 -0
  21. theprotocol_sdk-0.5.1/src/theprotocol/payment/authenticator.py +483 -0
  22. theprotocol_sdk-0.5.1/src/theprotocol/payment/client.py +123 -0
  23. theprotocol_sdk-0.5.1/src/theprotocol/payment/mtls_client.py +139 -0
  24. theprotocol_sdk-0.5.1/src/theprotocol/payment/verifier.py +193 -0
  25. theprotocol_sdk-0.5.1/src/theprotocol/registry/__init__.py +20 -0
  26. theprotocol_sdk-0.5.1/src/theprotocol/registry/cost_composition.py +143 -0
  27. theprotocol_sdk-0.5.1/src/theprotocol/transfer/__init__.py +4 -0
  28. theprotocol_sdk-0.5.1/src/theprotocol/transfer/client.py +117 -0
  29. theprotocol_sdk-0.5.1/tests/registry/__init__.py +0 -0
  30. theprotocol_sdk-0.5.1/tests/registry/test_cost_composition.py +156 -0
  31. theprotocol_sdk-0.5.1/tests/test_artifact_roundtrip.py +44 -0
  32. theprotocol_sdk-0.5.1/tests/test_auth.py +266 -0
  33. theprotocol_sdk-0.5.1/tests/test_did_jwt.py +157 -0
  34. theprotocol_sdk-0.5.1/tests/test_jws_card.py +132 -0
  35. theprotocol_sdk-0.5.1/tests/test_transfer.py +70 -0
  36. theprotocol_sdk-0.5.1/tests/test_v1_compat.py +190 -0
  37. theprotocol_sdk-0.5.1/tests/test_verifier_reuse.py +65 -0
  38. theprotocol_sdk-0.5.1/tests/test_well_known.py +268 -0
  39. theprotocol_sdk-0.2.0/.gitignore +0 -31
  40. theprotocol_sdk-0.2.0/README.md +0 -95
  41. theprotocol_sdk-0.2.0/src/theprotocol/models/agent_card.py +0 -91
  42. theprotocol_sdk-0.2.0/src/theprotocol/models/v1_compat.py +0 -230
  43. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/LICENSE +0 -0
  44. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/examples/simple_agent.py +0 -0
  45. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/agent/base.py +0 -0
  46. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/agent/decorators.py +0 -0
  47. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/__init__.py +0 -0
  48. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/acp.py +0 -0
  49. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/anp/__init__.py +0 -0
  50. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/anp/auth.py +0 -0
  51. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/anp/bridge.py +0 -0
  52. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/anp/did_wba.py +0 -0
  53. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/anp/translation.py +0 -0
  54. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/base.py +0 -0
  55. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/google_a2a.py +0 -0
  56. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/bridges/mcp.py +0 -0
  57. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/client/__init__.py +0 -0
  58. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/client/a2a_client.py +0 -0
  59. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/client/credentials.py +0 -0
  60. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/src/theprotocol/exceptions.py +0 -0
  61. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_agent.py +0 -0
  62. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_bridge_acp.py +0 -0
  63. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_bridge_anp.py +0 -0
  64. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_bridge_google_a2a.py +0 -0
  65. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_bridge_mcp.py +0 -0
  66. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_credentials.py +0 -0
  67. {theprotocol_sdk-0.2.0 → theprotocol_sdk-0.5.1}/tests/test_models.py +0 -0
@@ -0,0 +1,59 @@
1
+ # TheProtocol — Root .gitignore
2
+ # Created: 2026-03-09 (§4.1 Credentials Rotation)
3
+
4
+ # !! NEVER COMMIT SECRETS / LOCAL CONFIG !!
5
+ # All env files except *.example templates. Covers .env, .env.production,
6
+ # .env.frame-b, .env.frame-c, .env.operator, .env.docker, and nested
7
+ # AgentVault/.../.env — while keeping the committed *.env.example templates.
8
+ .env
9
+ .env.*
10
+ !.env.example
11
+ # Local agent / MCP config — these carry live API keys
12
+ .mcp.json
13
+ .claude/
14
+
15
+ # Session logs (operational, not source)
16
+ sessionlogs2026/
17
+
18
+ # Debug/runtime artifacts
19
+ logs/
20
+ *.log
21
+ APEX_PREDATOR_JOBS.log
22
+
23
+ # Node
24
+ node_modules/
25
+
26
+ # Python
27
+ __pycache__/
28
+ *.pyc
29
+ *.pyo
30
+ *.pyd
31
+ .venv/
32
+ *.egg-info/
33
+ dist/
34
+ build/
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
39
+
40
+ # Backups / snapshots — carry stale secrets + bloat
41
+ # (e.g. *.bak-pre-*, PRODUCTION_DOCS.bak-*, CLAUDE.md.bak-*, main.py.bak-*)
42
+ *.bak*
43
+ *.pre-*
44
+
45
+ # §2026-06-29 OSS secrets scrub (#153) — internal AI-operational docs + credential
46
+ # references that carry live secrets and MUST NOT ship to a public repo. These are
47
+ # operator/agent briefings, not platform source.
48
+ CLAUDE.md
49
+ CLAUDE_ADMIN.md
50
+ MY_APEX_PREDATOR_TOOLING.md
51
+ PRODUCTION_DOCS/CREDENTIALS_REFERENCE.md
52
+ # Sim/dev credential blobs
53
+ scripts/sim_credentials.json
54
+ **/*credentials*.json
55
+
56
+ # Throwaway FE screenshot/diag scripts (scratch, carry prod creds)
57
+ AgentVault/agentvault_registry/src/agentvault_registry/static/new_registry_frontend/shot_*.mjs
58
+ AgentVault/agentvault_registry/src/agentvault_registry/static/new_registry_frontend/diag_*.mjs
59
+ AgentVault/agentvault_registry/src/agentvault_registry/static/new_registry_frontend/gate_*.mjs
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: theprotocol-sdk
3
- Version: 0.2.0
4
- Summary: TheProtocol SDK — Build and call A2A agents. Protocol bridges for ACP, ADK, and more.
3
+ Version: 0.5.1
4
+ Summary: A2A v1.0 SDK — Build sovereign AI agents with DID identity. Protocol bridges for Google A2A, ANP, MCP. Works with Vertex AI, AWS AgentCore, LangGraph, CrewAI.
5
5
  Project-URL: Homepage, https://theprotocol.cloud
6
6
  Project-URL: Documentation, https://api.theprotocol.cloud/docs
7
7
  Project-URL: Repository, https://github.com/theprotocol/theprotocol-sdk
8
8
  Author-email: TheProtocol <sdk@theprotocol.cloud>
9
9
  License: Apache-2.0
10
10
  License-File: LICENSE
11
- Keywords: a2a,agents,ai,mcp,protocol,theprotocol
11
+ Keywords: a2a,a2a-protocol,agent-to-agent,agents,ai-agents,crewai,did,fastapi,federation,json-rpc,langchain,mcp,sovereign,theprotocol,vertex-ai
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: Apache Software License
@@ -127,6 +127,72 @@ Any platform that speaks A2A v1.0 can call your agent directly:
127
127
 
128
128
  No additional bridges needed. The SDK's JSON-RPC endpoint is the universal interface.
129
129
 
130
+ ## Smart Send (one call, any destination) — new in 0.5.0
131
+
132
+ The registry auto-routes value movement: local / cross-registry 2PC / async / cross-frame FX (AVT↔BVT) — derived from the federated agent-card cache. You never pick an endpoint.
133
+
134
+ ```python
135
+ from theprotocol.transfer import TransferClient
136
+
137
+ client = TransferClient("https://api.theprotocol.cloud")
138
+ plan = await client.preview(agent_jwt, "did:theprotocol:receiver", "2.5")
139
+ print(plan["method"], plan["currency_sent"], "->", plan["currency_received"])
140
+
141
+ result = await client.send(agent_jwt, "did:theprotocol:receiver", "2.5",
142
+ message="invoice 42", idempotency_key="inv-42")
143
+ print(result["status"], result["transfer_id"])
144
+ ```
145
+
146
+ `backend="async"` opts a same-currency remote transfer into the locked→settled rail; FX and local routes are decided by the registry. Non-2xx raises `SmartSendError` with the registry's status code and structured detail.
147
+
148
+ ## Changelog
149
+
150
+ **0.5.1** (2026-07-09)
151
+ - FastAPI ≥ 0.139 / Starlette 1.x compatibility: `serve_well_known_card` federated mode no longer relies on the removed `add_event_handler` API — startup registration now degrades gracefully (`add_event_handler` → `router.on_startup` → lifespan-context wrap). Verified 173/173 tests on both fastapi 0.111 (floor) and 0.139.
152
+
153
+ **0.5.0** (2026-06-12)
154
+ - NEW `theprotocol.transfer.TransferClient` — unified smart send (`POST /api/v1/teg/send`): auto-routed local / 2PC / async / cross-frame FX, `preview()` dry-runs, idempotency-key passthrough, `SmartSendError`.
155
+ - `PaymentVerifier(reject_reused_tokens=True)` — opt-in single-acceptance enforcement per process (P25-001 refinement). Default behavior unchanged (registry verify-on-CONSUMED stays valid for delivery retries).
156
+ - A2A v1.0 surface from the 2026-05-12 migration ships in this version: unified `A2AAuthenticator` (mTLS → agent-JWT → payment fanout), `theprotocol.auth.did_jwt` EdDSA helpers, v1.0-native `AgentCard` with dual-shape compatibility, Part `kind` discriminators.
157
+
158
+ ## Payment & mTLS Authentication
159
+
160
+ Enforce payment on your agent's A2A endpoints and authenticate callers via SPIFFE mTLS:
161
+
162
+ ```python
163
+ # Agent side — require payment tokens on all A2A calls
164
+ from theprotocol.payment import PaymentVerifier
165
+ from theprotocol.agent import create_a2a_router
166
+ from fastapi import Depends
167
+
168
+ verifier = PaymentVerifier(
169
+ registry_url="https://api.theprotocol.cloud",
170
+ agent_did="did:theprotocol:my-agent",
171
+ )
172
+ router = create_a2a_router(my_agent, dependencies=[Depends(verifier)])
173
+ ```
174
+
175
+ ```python
176
+ # Caller side — acquire payment token before calling an agent
177
+ from theprotocol.payment import PaymentClient
178
+
179
+ client = PaymentClient("https://api.theprotocol.cloud")
180
+ token = await client.get_token(agent_jwt, target_did="...", amount="0.5")
181
+ headers = {"X-Payment-Token": token}
182
+ ```
183
+
184
+ ```python
185
+ # mTLS — authenticate agent-to-agent calls with SPIFFE SVIDs
186
+ from theprotocol.payment import A2AAuthenticator, MtlsAgentClient
187
+
188
+ # Verify incoming mTLS + payment tokens (hybrid auth)
189
+ auth = A2AAuthenticator(registry_url="https://api.theprotocol.cloud")
190
+
191
+ # Make outbound mTLS calls using your agent's SVID
192
+ client = MtlsAgentClient(cert_dir="/certs")
193
+ result = await client.call(target_url, payload)
194
+ ```
195
+
130
196
  ## MCP Tools
131
197
 
132
198
  For governance, staking, transfers, and discovery — use [MCP tools](https://api.theprotocol.cloud/mcp/sse) (19 tools via Claude Desktop or any MCP client).
@@ -0,0 +1,161 @@
1
+ # theprotocol-sdk
2
+
3
+ **A2A v1.0** — Build and call AI agents on [TheProtocol](https://theprotocol.cloud). Native protocol bridges for Google A2A, ANP, and MCP.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install theprotocol-sdk # Client only (call agents)
9
+ pip install theprotocol-sdk[server] # + FastAPI router (build agents)
10
+ pip install theprotocol-sdk[anp] # + Ed25519 crypto for ANP DID:WBA
11
+ pip install theprotocol-sdk[all] # Everything
12
+ ```
13
+
14
+ ## Build an Agent
15
+
16
+ ```python
17
+ from theprotocol.agent import BaseA2AAgent, create_a2a_router
18
+ from fastapi import FastAPI
19
+
20
+ class MyAgent(BaseA2AAgent):
21
+ async def handle_task_send(self, task_id, message):
22
+ return "task-1"
23
+ async def handle_task_get(self, task_id): ...
24
+ async def handle_task_cancel(self, task_id): return True
25
+ async def handle_subscribe_request(self, task_id): yield
26
+
27
+ app = FastAPI()
28
+ app.include_router(create_a2a_router(MyAgent()))
29
+ ```
30
+
31
+ Your agent speaks A2A v1.0 out of the box. It accepts both `message/send` (v1.0) and `tasks/send` (v0.3) for backward compatibility.
32
+
33
+ ## Call a Remote Agent
34
+
35
+ ```python
36
+ from theprotocol.client import A2AClient, KeyManager
37
+ from theprotocol.models import Message, TextPart
38
+
39
+ async with A2AClient() as client:
40
+ task_id = await client.initiate_task(agent_card, message, key_manager)
41
+ task = await client.get_task_status(agent_card, task_id, key_manager)
42
+ print(task.state) # TASK_STATE_COMPLETED
43
+ ```
44
+
45
+ The client sends v1.0 wire format and accepts responses from both v1.0 and v0.3 agents.
46
+
47
+ ## Dockerize
48
+
49
+ ```dockerfile
50
+ FROM python:3.11-slim
51
+ WORKDIR /app
52
+ RUN pip install --no-cache-dir theprotocol-sdk[server] uvicorn
53
+ COPY agent.py .
54
+ EXPOSE 9500
55
+ CMD ["uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "9500"]
56
+ ```
57
+
58
+ Register on TheProtocol and your agent gets a permanent DID, OAuth credentials, and a 1,000 AVT genesis grant.
59
+
60
+ ## Protocol Bridges
61
+
62
+ Translate between A2A and other agent protocols:
63
+
64
+ | Bridge | Protocol | Use Case |
65
+ |--------|----------|----------|
66
+ | `GoogleA2ABridge` | Google A2A REST | Expose agents via REST binding (Vertex AI, AgentCore) |
67
+ | `ANPBridge` | Agent Network Protocol | DID:WBA identity linking, Ed25519 auth |
68
+ | `MCPBridge` | Model Context Protocol | Expose agents as MCP tool servers |
69
+ | `ACPBridge` | ACP (deprecated) | Legacy BeeAI compat — use GoogleA2ABridge instead |
70
+
71
+ ```python
72
+ from theprotocol.bridges.google_a2a import GoogleA2ABridge
73
+ from theprotocol.bridges.anp import ANPBridge
74
+ from theprotocol.bridges.mcp import MCPBridge
75
+ ```
76
+
77
+ ## Platform Compatibility
78
+
79
+ Any platform that speaks A2A v1.0 can call your agent directly:
80
+
81
+ - **Google Vertex AI** — native A2A support
82
+ - **AWS Bedrock AgentCore** — native A2A support
83
+ - **LangGraph Cloud** — native A2A support
84
+ - **CrewAI** — native A2A support
85
+ - **Azure AI Foundry** — A2A in preview
86
+
87
+ No additional bridges needed. The SDK's JSON-RPC endpoint is the universal interface.
88
+
89
+ ## Smart Send (one call, any destination) — new in 0.5.0
90
+
91
+ The registry auto-routes value movement: local / cross-registry 2PC / async / cross-frame FX (AVT↔BVT) — derived from the federated agent-card cache. You never pick an endpoint.
92
+
93
+ ```python
94
+ from theprotocol.transfer import TransferClient
95
+
96
+ client = TransferClient("https://api.theprotocol.cloud")
97
+ plan = await client.preview(agent_jwt, "did:theprotocol:receiver", "2.5")
98
+ print(plan["method"], plan["currency_sent"], "->", plan["currency_received"])
99
+
100
+ result = await client.send(agent_jwt, "did:theprotocol:receiver", "2.5",
101
+ message="invoice 42", idempotency_key="inv-42")
102
+ print(result["status"], result["transfer_id"])
103
+ ```
104
+
105
+ `backend="async"` opts a same-currency remote transfer into the locked→settled rail; FX and local routes are decided by the registry. Non-2xx raises `SmartSendError` with the registry's status code and structured detail.
106
+
107
+ ## Changelog
108
+
109
+ **0.5.1** (2026-07-09)
110
+ - FastAPI ≥ 0.139 / Starlette 1.x compatibility: `serve_well_known_card` federated mode no longer relies on the removed `add_event_handler` API — startup registration now degrades gracefully (`add_event_handler` → `router.on_startup` → lifespan-context wrap). Verified 173/173 tests on both fastapi 0.111 (floor) and 0.139.
111
+
112
+ **0.5.0** (2026-06-12)
113
+ - NEW `theprotocol.transfer.TransferClient` — unified smart send (`POST /api/v1/teg/send`): auto-routed local / 2PC / async / cross-frame FX, `preview()` dry-runs, idempotency-key passthrough, `SmartSendError`.
114
+ - `PaymentVerifier(reject_reused_tokens=True)` — opt-in single-acceptance enforcement per process (P25-001 refinement). Default behavior unchanged (registry verify-on-CONSUMED stays valid for delivery retries).
115
+ - A2A v1.0 surface from the 2026-05-12 migration ships in this version: unified `A2AAuthenticator` (mTLS → agent-JWT → payment fanout), `theprotocol.auth.did_jwt` EdDSA helpers, v1.0-native `AgentCard` with dual-shape compatibility, Part `kind` discriminators.
116
+
117
+ ## Payment & mTLS Authentication
118
+
119
+ Enforce payment on your agent's A2A endpoints and authenticate callers via SPIFFE mTLS:
120
+
121
+ ```python
122
+ # Agent side — require payment tokens on all A2A calls
123
+ from theprotocol.payment import PaymentVerifier
124
+ from theprotocol.agent import create_a2a_router
125
+ from fastapi import Depends
126
+
127
+ verifier = PaymentVerifier(
128
+ registry_url="https://api.theprotocol.cloud",
129
+ agent_did="did:theprotocol:my-agent",
130
+ )
131
+ router = create_a2a_router(my_agent, dependencies=[Depends(verifier)])
132
+ ```
133
+
134
+ ```python
135
+ # Caller side — acquire payment token before calling an agent
136
+ from theprotocol.payment import PaymentClient
137
+
138
+ client = PaymentClient("https://api.theprotocol.cloud")
139
+ token = await client.get_token(agent_jwt, target_did="...", amount="0.5")
140
+ headers = {"X-Payment-Token": token}
141
+ ```
142
+
143
+ ```python
144
+ # mTLS — authenticate agent-to-agent calls with SPIFFE SVIDs
145
+ from theprotocol.payment import A2AAuthenticator, MtlsAgentClient
146
+
147
+ # Verify incoming mTLS + payment tokens (hybrid auth)
148
+ auth = A2AAuthenticator(registry_url="https://api.theprotocol.cloud")
149
+
150
+ # Make outbound mTLS calls using your agent's SVID
151
+ client = MtlsAgentClient(cert_dir="/certs")
152
+ result = await client.call(target_url, payload)
153
+ ```
154
+
155
+ ## MCP Tools
156
+
157
+ For governance, staking, transfers, and discovery — use [MCP tools](https://api.theprotocol.cloud/mcp/sse) (19 tools via Claude Desktop or any MCP client).
158
+
159
+ ## License
160
+
161
+ Apache-2.0
@@ -4,15 +4,15 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "theprotocol-sdk"
7
- version = "0.2.0"
8
- description = "TheProtocol SDK — Build and call A2A agents. Protocol bridges for ACP, ADK, and more."
7
+ version = "0.5.1"
8
+ description = "A2A v1.0 SDK — Build sovereign AI agents with DID identity. Protocol bridges for Google A2A, ANP, MCP. Works with Vertex AI, AWS AgentCore, LangGraph, CrewAI."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
11
11
  requires-python = ">=3.10"
12
12
  authors = [
13
13
  {name = "TheProtocol", email = "sdk@theprotocol.cloud"},
14
14
  ]
15
- keywords = ["agents", "a2a", "protocol", "ai", "mcp", "theprotocol"]
15
+ keywords = ["agents", "a2a", "a2a-protocol", "agent-to-agent", "ai-agents", "mcp", "did", "sovereign", "federation", "vertex-ai", "langchain", "crewai", "fastapi", "json-rpc", "theprotocol"]
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",
@@ -5,6 +5,7 @@ Usage:
5
5
  from theprotocol.models import Message, Task, AgentCard
6
6
  from theprotocol.agent import BaseA2AAgent, create_a2a_router
7
7
  from theprotocol.client import A2AClient, KeyManager
8
+ from theprotocol.transfer import TransferClient # smart send (auto-routed value movement)
8
9
  """
9
10
 
10
- __version__ = "0.1.0"
11
+ __version__ = "0.5.1"
@@ -15,3 +15,10 @@ try:
15
15
  __all__.append("create_a2a_router")
16
16
  except ImportError:
17
17
  pass
18
+
19
+ # A2A v1.0 §4.1.2 well-known discovery — also requires fastapi.
20
+ try:
21
+ from .well_known import serve_well_known_card
22
+ __all__.append("serve_well_known_card")
23
+ except ImportError:
24
+ pass
@@ -1,9 +1,21 @@
1
1
  """FastAPI router factory for A2A agents.
2
- Accepts both A2A v1.0 and v0.3 wire formats. Responds in v1.0."""
2
+ Accepts both A2A v1.0 and v0.3 wire formats. Responds in v1.0.
3
+
4
+ Payment enforcement (f045):
5
+ When REGISTRY_URL env var is set, a PaymentVerifier is automatically
6
+ injected into the router dependencies. This means every SDK-based agent
7
+ gets payment verification by default when deployed to the network.
8
+
9
+ - REGISTRY_URL set → payment verification ON (required=True by default)
10
+ - PAYMENT_REQUIRED=false → verification runs but doesn't reject (log only)
11
+ - REGISTRY_URL not set → no verification (dev/testing mode)
12
+ - Price=0 agents: caller still gets a 0 AVT token (proves identity), no funds move
13
+ """
3
14
 
4
15
  import json
5
16
  import inspect
6
17
  import logging
18
+ import os
7
19
  from typing import Any, Dict, Optional, Union, List, Callable, AsyncGenerator
8
20
 
9
21
  import pydantic
@@ -87,10 +99,19 @@ def create_a2a_router(
87
99
  tags: Optional[List[str]] = None,
88
100
  task_store: Optional[BaseTaskStore] = None,
89
101
  dependencies: Optional[list] = None,
102
+ payment_required: Optional[bool] = None,
90
103
  ) -> APIRouter:
91
104
  """
92
105
  Create a FastAPI router that exposes an A2A agent via JSON-RPC 2.0.
93
106
 
107
+ Payment enforcement is automatic when REGISTRY_URL env var is set:
108
+ - REGISTRY_URL → PaymentVerifier injected (agents must receive payment tokens)
109
+ - AGENT_DID → identifies this agent for token target validation
110
+ - PAYMENT_REQUIRED=false → verify but don't reject (log only mode)
111
+ - TRUSTED_REGISTRIES → comma-separated URLs for cross-registry tokens
112
+
113
+ Override with payment_required=False to explicitly disable.
114
+
94
115
  Example::
95
116
 
96
117
  from theprotocol.agent import BaseA2AAgent, create_a2a_router
@@ -102,7 +123,11 @@ def create_a2a_router(
102
123
  ...
103
124
 
104
125
  app = FastAPI()
126
+ # Payment verification is automatic if REGISTRY_URL is set
105
127
  app.include_router(create_a2a_router(MyAgent()))
128
+
129
+ # Explicitly disable payment verification
130
+ app.include_router(create_a2a_router(MyAgent(), payment_required=False))
106
131
  """
107
132
  if tags is None:
108
133
  tags = ["A2A Protocol"]
@@ -110,7 +135,60 @@ def create_a2a_router(
110
135
  task_store = InMemoryTaskStore()
111
136
  store = task_store
112
137
 
113
- router = APIRouter(prefix=prefix, tags=tags, dependencies=dependencies or [])
138
+ # Build dependencies list
139
+ all_deps = list(dependencies or [])
140
+
141
+ # Auto-inject PaymentVerifier if REGISTRY_URL is configured
142
+ _registry_url = os.environ.get("REGISTRY_URL", "")
143
+ _agent_did = os.environ.get("AGENT_DID", "")
144
+ _pay_required = payment_required
145
+ if _pay_required is None:
146
+ _pay_required = os.environ.get("PAYMENT_REQUIRED", "true").lower() != "false"
147
+
148
+ if _registry_url and _agent_did and _pay_required is not False:
149
+ try:
150
+ from ..payment.verifier import PaymentVerifier
151
+ _trusted_raw = os.environ.get("TRUSTED_REGISTRIES", "")
152
+ _trusted = [u.strip() for u in _trusted_raw.split(",") if u.strip()] if _trusted_raw else None
153
+ _verifier = PaymentVerifier(
154
+ registry_url=_registry_url,
155
+ agent_did=_agent_did,
156
+ required=bool(_pay_required),
157
+ trusted_registries=_trusted,
158
+ )
159
+ all_deps.append(Depends(_verifier))
160
+ logger.info(
161
+ f"[A2A Router] PaymentVerifier auto-injected "
162
+ f"(registry={_registry_url}, did={_agent_did[:30]}, required={_pay_required})"
163
+ )
164
+ except ImportError:
165
+ logger.warning("[A2A Router] PaymentVerifier import failed — payment module not installed")
166
+ except Exception as e:
167
+ logger.warning(f"[A2A Router] PaymentVerifier setup failed: {e}")
168
+ elif _registry_url and not _agent_did:
169
+ logger.warning("[A2A Router] REGISTRY_URL set but AGENT_DID missing — payment verification disabled")
170
+
171
+ # f052: Auto-inject A2AAuthenticator if SPIRE socket is available (IRONHAND)
172
+ _spiffe_socket = os.environ.get("SPIFFE_ENDPOINT_SOCKET", "")
173
+ _enable_mtls = os.environ.get("ENABLE_MTLS", "").lower() == "true"
174
+ if _spiffe_socket and _enable_mtls:
175
+ try:
176
+ from ..payment.authenticator import A2AAuthenticator
177
+ _authenticator = A2AAuthenticator(
178
+ payment_verifier=_verifier if "_verifier" in dir() else None,
179
+ required=False,
180
+ )
181
+ all_deps.append(Depends(_authenticator))
182
+ logger.info(
183
+ f"[A2A Router] A2AAuthenticator auto-injected (mTLS enabled, "
184
+ f"socket={_spiffe_socket[:40]})"
185
+ )
186
+ except ImportError:
187
+ logger.warning("[A2A Router] A2AAuthenticator import failed — mTLS module not installed")
188
+ except Exception as e:
189
+ logger.warning(f"[A2A Router] A2AAuthenticator setup failed: {e}")
190
+
191
+ router = APIRouter(prefix=prefix, tags=tags, dependencies=all_deps)
114
192
 
115
193
  # Discover @a2a_method decorated handlers
116
194
  decorated: Dict[str, Callable] = {}
@@ -118,6 +196,9 @@ def create_a2a_router(
118
196
  if hasattr(method, '_a2a_method_name'):
119
197
  decorated[getattr(method, '_a2a_method_name')] = method
120
198
 
199
+ # Register on both the bare prefix and the trailing slash so `POST /a2a`
200
+ # works without a 307 redirect (which drops the POST body for many clients).
201
+ @router.post("", summary="A2A JSON-RPC Endpoint", include_in_schema=False)
121
202
  @router.post("/", summary="A2A JSON-RPC Endpoint")
122
203
  async def handle_request(request: Request) -> Response:
123
204
  req_id = None
@@ -101,7 +101,13 @@ class BaseTaskStore(ABC):
101
101
 
102
102
 
103
103
  class InMemoryTaskStore(BaseTaskStore):
104
- """In-memory task store. Suitable for development and single-process agents."""
104
+ """In-memory task store. Suitable for development and single-process agents.
105
+
106
+ Bounded: keeps at most ``_MAX_TASKS`` tasks, evicting oldest-first (FIFO) on
107
+ insert so long-running agents don't leak memory over time.
108
+ """
109
+
110
+ _MAX_TASKS = 2000
105
111
 
106
112
  def __init__(self):
107
113
  self._tasks: Dict[str, TaskContext] = {}
@@ -119,6 +125,13 @@ class InMemoryTaskStore(BaseTaskStore):
119
125
  ctx = TaskContext(task_id=task_id, current_state=TaskState.SUBMITTED)
120
126
  self._tasks[task_id] = ctx
121
127
  self._listeners[task_id] = []
128
+ # Bounded GC: evict oldest entries (FIFO) to cap memory.
129
+ while len(self._tasks) > self._MAX_TASKS:
130
+ old_id = next(iter(self._tasks))
131
+ if old_id == task_id:
132
+ break
133
+ self._tasks.pop(old_id, None)
134
+ self._listeners.pop(old_id, None)
122
135
  await self.notify_status_update(task_id, TaskState.SUBMITTED)
123
136
  return ctx
124
137