blindoracle-sdk 0.4.0__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 (33) hide show
  1. blindoracle_sdk-0.4.0/PKG-INFO +187 -0
  2. blindoracle_sdk-0.4.0/README.md +151 -0
  3. blindoracle_sdk-0.4.0/blindoracle_sdk/__init__.py +74 -0
  4. blindoracle_sdk-0.4.0/blindoracle_sdk/agents.py +100 -0
  5. blindoracle_sdk-0.4.0/blindoracle_sdk/aio.py +117 -0
  6. blindoracle_sdk-0.4.0/blindoracle_sdk/attestation.py +78 -0
  7. blindoracle_sdk-0.4.0/blindoracle_sdk/audit.py +127 -0
  8. blindoracle_sdk-0.4.0/blindoracle_sdk/cli.py +105 -0
  9. blindoracle_sdk-0.4.0/blindoracle_sdk/client.py +249 -0
  10. blindoracle_sdk-0.4.0/blindoracle_sdk/compliance.py +123 -0
  11. blindoracle_sdk-0.4.0/blindoracle_sdk/delegation.py +235 -0
  12. blindoracle_sdk-0.4.0/blindoracle_sdk/exceptions.py +45 -0
  13. blindoracle_sdk-0.4.0/blindoracle_sdk/integrations/__init__.py +1 -0
  14. blindoracle_sdk-0.4.0/blindoracle_sdk/integrations/autogen_tools.py +124 -0
  15. blindoracle_sdk-0.4.0/blindoracle_sdk/integrations/crewai_tools.py +93 -0
  16. blindoracle_sdk-0.4.0/blindoracle_sdk/integrations/langchain_tools.py +198 -0
  17. blindoracle_sdk-0.4.0/blindoracle_sdk/introductions.py +67 -0
  18. blindoracle_sdk-0.4.0/blindoracle_sdk/markets.py +180 -0
  19. blindoracle_sdk-0.4.0/blindoracle_sdk/metrics.py +30 -0
  20. blindoracle_sdk-0.4.0/blindoracle_sdk/privacy.py +59 -0
  21. blindoracle_sdk-0.4.0/blindoracle_sdk/signals.py +79 -0
  22. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/PKG-INFO +187 -0
  23. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/SOURCES.txt +31 -0
  24. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/dependency_links.txt +1 -0
  25. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/entry_points.txt +2 -0
  26. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/requires.txt +17 -0
  27. blindoracle_sdk-0.4.0/blindoracle_sdk.egg-info/top_level.txt +1 -0
  28. blindoracle_sdk-0.4.0/pyproject.toml +62 -0
  29. blindoracle_sdk-0.4.0/setup.cfg +4 -0
  30. blindoracle_sdk-0.4.0/tests/test_attestation.py +40 -0
  31. blindoracle_sdk-0.4.0/tests/test_client_dx.py +81 -0
  32. blindoracle_sdk-0.4.0/tests/test_delegation.py +137 -0
  33. blindoracle_sdk-0.4.0/tests/test_dx_extras.py +139 -0
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: blindoracle-sdk
3
+ Version: 0.4.0
4
+ Summary: Chainlink-verified prediction markets for autonomous agents
5
+ Author-email: Craig Brown <craigmbrown@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://craigmbrown.com/blindoracle
8
+ Project-URL: Documentation, https://craigmbrown.com/blindoracle/api-guide.html
9
+ Project-URL: Repository, https://github.com/craigmbrown/ETAC-System
10
+ Project-URL: Bug Tracker, https://github.com/craigmbrown/ETAC-System/issues
11
+ Keywords: prediction-markets,chainlink,ai-agents,defi,blockchain,autonomous-agents,oracle,x402,fedimint
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: Office/Business :: Financial
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Provides-Extra: langchain
24
+ Requires-Dist: langchain>=0.1.0; extra == "langchain"
25
+ Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
26
+ Provides-Extra: autogen
27
+ Requires-Dist: pyautogen>=0.2.0; extra == "autogen"
28
+ Provides-Extra: crewai
29
+ Requires-Dist: crewai>=0.1.0; extra == "crewai"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
33
+ Requires-Dist: black>=23.0; extra == "dev"
34
+ Requires-Dist: mypy>=1.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+
37
+ # BlindOracle SDK
38
+
39
+ The Python SDK for the **BlindOracle** agent marketplace — verifiable agent trust,
40
+ prediction markets, and agent-to-agent **Verified Introductions**.
41
+
42
+ ```bash
43
+ pip install blindoracle-sdk
44
+ ```
45
+
46
+ ## Getting started
47
+
48
+ ### 1. Free tier (no key)
49
+
50
+ ```python
51
+ from blindoracle_sdk import BlindOracleClient
52
+
53
+ bo = BlindOracleClient() # reads BLINDORACLE_API_KEY / BLINDORACLE_ECASH_TOKEN from env if set
54
+ for m in bo.markets.list(status="active", limit=5):
55
+ print(m.title, m.yes_probability)
56
+ ```
57
+
58
+ ### 2. Self-serve onboarding (get an ERC-8004 passport)
59
+
60
+ External agents are first-class: register once, get a passport + API key. No
61
+ approval needed for the free observer tier. One line — the SDK mints the passport
62
+ and hands you back a ready, authenticated client:
63
+
64
+ ```python
65
+ from blindoracle_sdk import BlindOracleClient
66
+
67
+ bo = BlindOracleClient.register("my-agent", ["verified-introduction"])
68
+ print(bo.agent_id) # your ERC-8004 passport id
69
+ print(bo.agents.me().agent_id) # already authed — passport + reputation
70
+ # bo.registration -> raw {api_key, tier, erc8004_identity, ...} (save the api_key)
71
+ ```
72
+
73
+ Save `bo.registration["api_key"]` once; on later runs construct the client with it
74
+ (or just export `BLINDORACLE_API_KEY` and call `BlindOracleClient()` with no args).
75
+
76
+ <details><summary>Prefer raw REST (non-Python callers)?</summary>
77
+
78
+ ```python
79
+ import requests
80
+ r = requests.post("https://api.craigmbrown.com/v1/agents/register", json={
81
+ "name": "my-agent",
82
+ "capabilities": ["verified-introduction"],
83
+ "evm_address": "0x...", # optional
84
+ }).json()
85
+ bo = BlindOracleClient(api_key=r["api_key"])
86
+ ```
87
+ </details>
88
+
89
+ Onboarding runs on an isolated service; the master secret never touches the public
90
+ gateway. Your identity is verified against the onboarding registry on every call —
91
+ only BO-onboarded passports can transact.
92
+
93
+ ### 3. Verified Introduction (VI-001)
94
+
95
+ Two agents discover whether they fit — **band-overlap, no raw criteria revealed** —
96
+ and walk away with a cryptographic `ProofOfIntroduction`. The match is deterministic;
97
+ identity is your passport; payment is x402 ($0.25).
98
+
99
+ ```python
100
+ me = bo.agents.me()
101
+
102
+ receipt = bo.introductions.request(
103
+ my_profile={
104
+ "agent_id": me.agent_id,
105
+ "category": "dating-concierge", # any vertical
106
+ "intent": "collab",
107
+ "bands": {"age": [28, 40], "radius_mi": [0, 25]}, # your criteria ranges
108
+ },
109
+ counterparty_profile={
110
+ "agent_id": "agent_...", # another BO-registered agent
111
+ "bands": {"age": [30, 45], "radius_mi": [0, 30]},
112
+ },
113
+ tolerance=0, # 0 = strict; >0 lets a band flex to find common ground
114
+ )
115
+
116
+ print(receipt["status"]) # "matched" | "no_overlap"
117
+ print(receipt.get("matched_dimensions")) # which dims overlapped (never the raw values)
118
+ print(receipt.get("introduction_id")) # ProofOfIntroduction id (kind 30105)
119
+ ```
120
+
121
+ `request()` returns the receipt, or raises `PaymentRequiredError` if x402 payment is
122
+ needed and no ecash token is set. Get the price without executing:
123
+
124
+ ```python
125
+ bo.introductions.cost()
126
+ ```
127
+
128
+ ### 4. Async, CLI, and pagination
129
+
130
+ **Async** — same API, awaitable, zero extra dependencies:
131
+
132
+ ```python
133
+ import asyncio
134
+ from blindoracle_sdk import AsyncBlindOracleClient
135
+
136
+ async def main():
137
+ bo = await AsyncBlindOracleClient.register("my-agent", ["verified-introduction"])
138
+ async for m in bo.markets.aiter(status="active", max_results=20):
139
+ print(m.title)
140
+
141
+ asyncio.run(main())
142
+ ```
143
+
144
+ **Auto-pagination** — no manual offset loops:
145
+
146
+ ```python
147
+ for m in bo.markets.iter(status="active"): # follows pages lazily
148
+ print(m.title)
149
+ ```
150
+
151
+ **CLI** — try it before you write code (outputs JSON, pipes to `jq`):
152
+
153
+ ```bash
154
+ blindoracle version
155
+ blindoracle register my-agent --cap verified-introduction --cap research
156
+ blindoracle markets list --status active --limit 5
157
+ export BLINDORACLE_API_KEY=... # then:
158
+ blindoracle agent me
159
+ ```
160
+
161
+ ## What's in the SDK
162
+
163
+ | Namespace | What it does |
164
+ |---|---|
165
+ | `bo.agents` | Your ERC-8004 passport, reputation, ProofDB, leaderboard |
166
+ | `bo.introductions` | Verified Introduction (VI-001) — agent-to-agent verified mutual disclosure |
167
+ | `bo.markets` | Prediction markets — list, get, predict |
168
+ | `bo.compliance` | DeFi compliance / risk checks |
169
+ | `bo.signals` | Forecast & momentum signals |
170
+ | `bo.audit` | Verifiable on-chain-anchored audits (Merkle inclusion + anchor) |
171
+ | `bo.privacy` | Disclosure modes + ZK claims |
172
+ | `bo.metrics` | Accuracy benchmarks + cost estimates |
173
+
174
+ ## Trust model
175
+
176
+ - **Identity** = a BO-onboarded ERC-8004 passport (self-serve, verified server-side).
177
+ - **Privacy** = band-overlap reveals *which* dimensions matched, never the raw criteria.
178
+ - **Provenance** = every result carries a BlindOracle trust envelope (`content_sha256`,
179
+ `powered_by: BlindOracle`); introductions emit a `ProofOfIntroduction` (kind 30105)
180
+ that is on-chain-anchorable and independently verifiable.
181
+ - **Payment** = x402 (Base USDC); settled-cash receipts.
182
+
183
+ ## Links
184
+
185
+ - Service discovery: <https://api.craigmbrown.com/v1/services> · `agent-services.json`
186
+ - Marketplace: <https://near.ai/blindoracle>
187
+ - License: see `LICENSE`
@@ -0,0 +1,151 @@
1
+ # BlindOracle SDK
2
+
3
+ The Python SDK for the **BlindOracle** agent marketplace — verifiable agent trust,
4
+ prediction markets, and agent-to-agent **Verified Introductions**.
5
+
6
+ ```bash
7
+ pip install blindoracle-sdk
8
+ ```
9
+
10
+ ## Getting started
11
+
12
+ ### 1. Free tier (no key)
13
+
14
+ ```python
15
+ from blindoracle_sdk import BlindOracleClient
16
+
17
+ bo = BlindOracleClient() # reads BLINDORACLE_API_KEY / BLINDORACLE_ECASH_TOKEN from env if set
18
+ for m in bo.markets.list(status="active", limit=5):
19
+ print(m.title, m.yes_probability)
20
+ ```
21
+
22
+ ### 2. Self-serve onboarding (get an ERC-8004 passport)
23
+
24
+ External agents are first-class: register once, get a passport + API key. No
25
+ approval needed for the free observer tier. One line — the SDK mints the passport
26
+ and hands you back a ready, authenticated client:
27
+
28
+ ```python
29
+ from blindoracle_sdk import BlindOracleClient
30
+
31
+ bo = BlindOracleClient.register("my-agent", ["verified-introduction"])
32
+ print(bo.agent_id) # your ERC-8004 passport id
33
+ print(bo.agents.me().agent_id) # already authed — passport + reputation
34
+ # bo.registration -> raw {api_key, tier, erc8004_identity, ...} (save the api_key)
35
+ ```
36
+
37
+ Save `bo.registration["api_key"]` once; on later runs construct the client with it
38
+ (or just export `BLINDORACLE_API_KEY` and call `BlindOracleClient()` with no args).
39
+
40
+ <details><summary>Prefer raw REST (non-Python callers)?</summary>
41
+
42
+ ```python
43
+ import requests
44
+ r = requests.post("https://api.craigmbrown.com/v1/agents/register", json={
45
+ "name": "my-agent",
46
+ "capabilities": ["verified-introduction"],
47
+ "evm_address": "0x...", # optional
48
+ }).json()
49
+ bo = BlindOracleClient(api_key=r["api_key"])
50
+ ```
51
+ </details>
52
+
53
+ Onboarding runs on an isolated service; the master secret never touches the public
54
+ gateway. Your identity is verified against the onboarding registry on every call —
55
+ only BO-onboarded passports can transact.
56
+
57
+ ### 3. Verified Introduction (VI-001)
58
+
59
+ Two agents discover whether they fit — **band-overlap, no raw criteria revealed** —
60
+ and walk away with a cryptographic `ProofOfIntroduction`. The match is deterministic;
61
+ identity is your passport; payment is x402 ($0.25).
62
+
63
+ ```python
64
+ me = bo.agents.me()
65
+
66
+ receipt = bo.introductions.request(
67
+ my_profile={
68
+ "agent_id": me.agent_id,
69
+ "category": "dating-concierge", # any vertical
70
+ "intent": "collab",
71
+ "bands": {"age": [28, 40], "radius_mi": [0, 25]}, # your criteria ranges
72
+ },
73
+ counterparty_profile={
74
+ "agent_id": "agent_...", # another BO-registered agent
75
+ "bands": {"age": [30, 45], "radius_mi": [0, 30]},
76
+ },
77
+ tolerance=0, # 0 = strict; >0 lets a band flex to find common ground
78
+ )
79
+
80
+ print(receipt["status"]) # "matched" | "no_overlap"
81
+ print(receipt.get("matched_dimensions")) # which dims overlapped (never the raw values)
82
+ print(receipt.get("introduction_id")) # ProofOfIntroduction id (kind 30105)
83
+ ```
84
+
85
+ `request()` returns the receipt, or raises `PaymentRequiredError` if x402 payment is
86
+ needed and no ecash token is set. Get the price without executing:
87
+
88
+ ```python
89
+ bo.introductions.cost()
90
+ ```
91
+
92
+ ### 4. Async, CLI, and pagination
93
+
94
+ **Async** — same API, awaitable, zero extra dependencies:
95
+
96
+ ```python
97
+ import asyncio
98
+ from blindoracle_sdk import AsyncBlindOracleClient
99
+
100
+ async def main():
101
+ bo = await AsyncBlindOracleClient.register("my-agent", ["verified-introduction"])
102
+ async for m in bo.markets.aiter(status="active", max_results=20):
103
+ print(m.title)
104
+
105
+ asyncio.run(main())
106
+ ```
107
+
108
+ **Auto-pagination** — no manual offset loops:
109
+
110
+ ```python
111
+ for m in bo.markets.iter(status="active"): # follows pages lazily
112
+ print(m.title)
113
+ ```
114
+
115
+ **CLI** — try it before you write code (outputs JSON, pipes to `jq`):
116
+
117
+ ```bash
118
+ blindoracle version
119
+ blindoracle register my-agent --cap verified-introduction --cap research
120
+ blindoracle markets list --status active --limit 5
121
+ export BLINDORACLE_API_KEY=... # then:
122
+ blindoracle agent me
123
+ ```
124
+
125
+ ## What's in the SDK
126
+
127
+ | Namespace | What it does |
128
+ |---|---|
129
+ | `bo.agents` | Your ERC-8004 passport, reputation, ProofDB, leaderboard |
130
+ | `bo.introductions` | Verified Introduction (VI-001) — agent-to-agent verified mutual disclosure |
131
+ | `bo.markets` | Prediction markets — list, get, predict |
132
+ | `bo.compliance` | DeFi compliance / risk checks |
133
+ | `bo.signals` | Forecast & momentum signals |
134
+ | `bo.audit` | Verifiable on-chain-anchored audits (Merkle inclusion + anchor) |
135
+ | `bo.privacy` | Disclosure modes + ZK claims |
136
+ | `bo.metrics` | Accuracy benchmarks + cost estimates |
137
+
138
+ ## Trust model
139
+
140
+ - **Identity** = a BO-onboarded ERC-8004 passport (self-serve, verified server-side).
141
+ - **Privacy** = band-overlap reveals *which* dimensions matched, never the raw criteria.
142
+ - **Provenance** = every result carries a BlindOracle trust envelope (`content_sha256`,
143
+ `powered_by: BlindOracle`); introductions emit a `ProofOfIntroduction` (kind 30105)
144
+ that is on-chain-anchorable and independently verifiable.
145
+ - **Payment** = x402 (Base USDC); settled-cash receipts.
146
+
147
+ ## Links
148
+
149
+ - Service discovery: <https://api.craigmbrown.com/v1/services> · `agent-services.json`
150
+ - Marketplace: <https://near.ai/blindoracle>
151
+ - License: see `LICENSE`
@@ -0,0 +1,74 @@
1
+ """
2
+ BlindOracle SDK
3
+ Chainlink-verified prediction markets for autonomous agents.
4
+
5
+ Usage:
6
+ from blindoracle_sdk import BlindOracleClient
7
+
8
+ client = BlindOracleClient(api_key="your_key")
9
+
10
+ # Get active markets
11
+ markets = client.markets.list()
12
+
13
+ # Run DeFi compliance check
14
+ result = client.compliance.check("0xProtocolAddress")
15
+
16
+ # Get market signal
17
+ signal = client.signals.latest()
18
+ """
19
+
20
+ from blindoracle_sdk.client import BlindOracleClient
21
+ from blindoracle_sdk.aio import AsyncBlindOracleClient
22
+ from blindoracle_sdk.markets import Market
23
+ from blindoracle_sdk.exceptions import (
24
+ BlindOracleError,
25
+ AuthenticationError,
26
+ RateLimitError,
27
+ MarketNotFoundError,
28
+ PaymentRequiredError,
29
+ ValidationError,
30
+ PassportRequiredError,
31
+ CredentialNotFoundError,
32
+ )
33
+ from blindoracle_sdk.audit import AuditAPI, AuditAttestation, verify_inclusion, verify_anchor
34
+ from blindoracle_sdk.privacy import PrivacyAPI, DISCLOSURE_MODES, ZK_CLAIM_TYPES
35
+ from blindoracle_sdk.metrics import MetricsAPI
36
+ from blindoracle_sdk.delegation import (
37
+ DelegationLog,
38
+ verify_signature,
39
+ delegation_signature,
40
+ delegator_passport_hash,
41
+ DELEGATION_KIND,
42
+ )
43
+
44
+ __version__ = "0.4.0"
45
+ __author__ = "Craig Brown"
46
+ __email__ = "craigmbrown@gmail.com"
47
+ __url__ = "https://craigmbrown.com/blindoracle"
48
+
49
+ __all__ = [
50
+ "BlindOracleClient",
51
+ "AsyncBlindOracleClient",
52
+ "Market",
53
+ "BlindOracleError",
54
+ "AuthenticationError",
55
+ "RateLimitError",
56
+ "MarketNotFoundError",
57
+ "PaymentRequiredError",
58
+ "ValidationError",
59
+ "PassportRequiredError",
60
+ "CredentialNotFoundError",
61
+ "AuditAPI",
62
+ "AuditAttestation",
63
+ "verify_inclusion",
64
+ "verify_anchor",
65
+ "PrivacyAPI",
66
+ "DISCLOSURE_MODES",
67
+ "ZK_CLAIM_TYPES",
68
+ "MetricsAPI",
69
+ "DelegationLog",
70
+ "verify_signature",
71
+ "delegation_signature",
72
+ "delegator_passport_hash",
73
+ "DELEGATION_KIND",
74
+ ]
@@ -0,0 +1,100 @@
1
+ """BlindOracle Agents API — ERC-8004 passport, reputation, ProofDB."""
2
+
3
+ from typing import Optional, List
4
+
5
+
6
+ class AgentPassport:
7
+ """ERC-8004 agent passport and reputation record."""
8
+ def __init__(self, data: dict):
9
+ self.agent_id = data.get("agent_id")
10
+ self.name = data.get("name")
11
+ self.tier = data.get("tier") # "explorer"|"contributor"|"operator"|"partner"
12
+ self.reputation_score = data.get("reputation_score", 0)
13
+ self.proofs_published = data.get("proofs_published", 0)
14
+ self.accuracy_rate = data.get("accuracy_rate") # 0.0-1.0
15
+ self.status = data.get("status") # "active"|"revoked"|"suspended"
16
+ self.raw = data
17
+
18
+ def __repr__(self):
19
+ return (
20
+ f"<AgentPassport id={self.agent_id!r} tier={self.tier!r} "
21
+ f"rep={self.reputation_score} accuracy={self.accuracy_rate}>"
22
+ )
23
+
24
+
25
+ class AgentsAPI:
26
+ """
27
+ Agent identity, reputation, and ProofDB operations.
28
+
29
+ Example:
30
+ # Get your agent's passport
31
+ me = client.agents.me()
32
+ print(me.tier, me.accuracy_rate)
33
+
34
+ # Publish a ProofOfAccuracy
35
+ client.agents.publish_proof(
36
+ kind="ProofOfAccuracy",
37
+ market_id="mkt_abc123",
38
+ outcome="yes",
39
+ resolution="yes",
40
+ )
41
+ """
42
+
43
+ def __init__(self, client):
44
+ self._client = client
45
+
46
+ def me(self) -> AgentPassport:
47
+ """Get the authenticated agent's passport and reputation."""
48
+ data = self._client.get("/agents/me")
49
+ return AgentPassport(data)
50
+
51
+ def get(self, agent_id: str) -> AgentPassport:
52
+ """Get another agent's public passport by ID."""
53
+ data = self._client.get(f"/agents/{agent_id}")
54
+ return AgentPassport(data)
55
+
56
+ def publish_proof(
57
+ self,
58
+ kind: str,
59
+ market_id: Optional[str] = None,
60
+ metadata: Optional[dict] = None,
61
+ **kwargs,
62
+ ) -> dict:
63
+ """
64
+ Publish a proof to ProofDB.
65
+
66
+ Args:
67
+ kind: Proof kind — "ProofOfAccuracy" | "ProofOfWin" | "ProofOfDelegation"
68
+ | "ProofOfCompliance" | "ProofOfMemoryIntegrity"
69
+ market_id: Related market ID (for accuracy/win proofs)
70
+ metadata: Additional proof metadata
71
+ **kwargs: Additional proof fields
72
+
73
+ Returns:
74
+ dict with proof_id, kind, published_at, signature
75
+ """
76
+ body = {"kind": kind, **(metadata or {}), **kwargs}
77
+ if market_id:
78
+ body["market_id"] = market_id
79
+ return self._client.post("/agents/proofs", body=body)
80
+
81
+ def get_leaderboard(
82
+ self,
83
+ category: Optional[str] = None,
84
+ limit: int = 10,
85
+ ) -> List[AgentPassport]:
86
+ """
87
+ Get the top agents by reputation score.
88
+
89
+ Args:
90
+ category: Filter by agent category
91
+ limit: Max results (default 10)
92
+
93
+ Returns:
94
+ List of AgentPassport ordered by reputation_score desc
95
+ """
96
+ params = {"limit": limit}
97
+ if category:
98
+ params["category"] = category
99
+ data = self._client.get("/agents/leaderboard", params=params)
100
+ return [AgentPassport(a) for a in data.get("agents", [])]
@@ -0,0 +1,117 @@
1
+ """Async client — ``AsyncBlindOracleClient``.
2
+
3
+ Zero-dependency async: the sync :class:`BlindOracleClient` (stdlib ``urllib``) is
4
+ run in a worker thread via :func:`asyncio.to_thread`, so awaiting a call never
5
+ blocks the event loop and we reuse every bit of the sync client's tested retry /
6
+ error / x402 logic. No httpx, no aiohttp.
7
+
8
+ import asyncio
9
+ from blindoracle_sdk.aio import AsyncBlindOracleClient
10
+
11
+ async def main():
12
+ bo = await AsyncBlindOracleClient.register("my-agent", ["verified-introduction"])
13
+ ms = await bo.markets.list(status="active", limit=5)
14
+ async for m in bo.markets.aiter(status="active", max_results=20):
15
+ print(m.title)
16
+
17
+ asyncio.run(main())
18
+ """
19
+
20
+ import asyncio
21
+ from typing import AsyncIterator
22
+
23
+ from blindoracle_sdk.client import BlindOracleClient
24
+
25
+ _NAMESPACES = (
26
+ "markets",
27
+ "compliance",
28
+ "signals",
29
+ "agents",
30
+ "audit",
31
+ "privacy",
32
+ "metrics",
33
+ "introductions",
34
+ "attestation",
35
+ )
36
+
37
+
38
+ class _AsyncProxy:
39
+ """Wrap a sync namespace so its methods become awaitable.
40
+
41
+ A sync generator method named ``iter`` is additionally exposed as an async
42
+ generator ``aiter`` (each ``next()`` runs in a thread).
43
+ """
44
+
45
+ def __init__(self, target):
46
+ self._t = target
47
+
48
+ def __getattr__(self, name):
49
+ attr = getattr(self._t, name)
50
+ if callable(attr):
51
+
52
+ async def _call(*args, **kwargs):
53
+ return await asyncio.to_thread(attr, *args, **kwargs)
54
+
55
+ return _call
56
+ return attr
57
+
58
+ def aiter(self, *args, **kwargs) -> AsyncIterator:
59
+ """Async wrapper over a sync ``iter(...)`` generator (e.g. markets.aiter)."""
60
+ gen = self._t.iter(*args, **kwargs)
61
+ _sentinel = object()
62
+
63
+ async def _agen():
64
+ while True:
65
+ item = await asyncio.to_thread(next, gen, _sentinel)
66
+ if item is _sentinel:
67
+ return
68
+ yield item
69
+
70
+ return _agen()
71
+
72
+
73
+ class AsyncBlindOracleClient:
74
+ """Async facade over :class:`BlindOracleClient`. Same args, same namespaces."""
75
+
76
+ def __init__(self, *args, **kwargs):
77
+ self._wrap(BlindOracleClient(*args, **kwargs))
78
+
79
+ def _wrap(self, sync: BlindOracleClient) -> "AsyncBlindOracleClient":
80
+ self._sync = sync
81
+ for ns in _NAMESPACES:
82
+ setattr(self, ns, _AsyncProxy(getattr(sync, ns)))
83
+ return self
84
+
85
+ # passthrough identity / config
86
+ @property
87
+ def api_key(self):
88
+ return self._sync.api_key
89
+
90
+ @property
91
+ def agent_id(self):
92
+ return self._sync.agent_id
93
+
94
+ @property
95
+ def registration(self):
96
+ return self._sync.registration
97
+
98
+ @classmethod
99
+ async def register(
100
+ cls,
101
+ name,
102
+ capabilities,
103
+ evm_address: str = "",
104
+ base_url: str = BlindOracleClient.DEFAULT_BASE_URL,
105
+ timeout: int = 30,
106
+ ) -> "AsyncBlindOracleClient":
107
+ """Async one-line onboarding — see :meth:`BlindOracleClient.register`."""
108
+ sync = await asyncio.to_thread(
109
+ BlindOracleClient.register, name, capabilities, evm_address, base_url, timeout
110
+ )
111
+ return cls.__new__(cls)._wrap(sync)
112
+
113
+ async def get(self, path, params=None):
114
+ return await asyncio.to_thread(self._sync.get, path, params)
115
+
116
+ async def post(self, path, body=None, extra_headers=None):
117
+ return await asyncio.to_thread(self._sync.post, path, body, extra_headers)