agentic-yp 1.0.0__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.
agentic_yp/__init__.py
ADDED
agentic_yp/client.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
# ── Custom exceptions ──────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
class AgenticYPError(Exception):
|
|
14
|
+
"""Base exception for all SDK errors."""
|
|
15
|
+
|
|
16
|
+
class AgentNotFoundError(AgenticYPError):
|
|
17
|
+
"""No agent matched the given filters."""
|
|
18
|
+
|
|
19
|
+
class AgenticYPAPIError(AgenticYPError):
|
|
20
|
+
"""The API returned an unexpected response."""
|
|
21
|
+
def __init__(self, status_code: int, message: str):
|
|
22
|
+
self.status_code = status_code
|
|
23
|
+
super().__init__(f"API error {status_code}: {message}")
|
|
24
|
+
|
|
25
|
+
# ── Typed agent node ───────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class AgentNode:
|
|
29
|
+
domain: str
|
|
30
|
+
trust_score: int
|
|
31
|
+
status: str
|
|
32
|
+
tags: List[str] = field(default_factory=list)
|
|
33
|
+
raw: dict = field(default_factory=dict, repr=False)
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def from_dict(cls, data: dict) -> "AgentNode":
|
|
37
|
+
return cls(
|
|
38
|
+
domain=data.get("domain", ""),
|
|
39
|
+
trust_score=data.get("trust_score", 0),
|
|
40
|
+
status=data.get("status", "unknown"),
|
|
41
|
+
tags=[str(t).lower() for t in data.get("tags", [])],
|
|
42
|
+
raw=data,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def execute(self, prompt: str, **kwargs) -> dict:
|
|
46
|
+
"""Route a prompt directly to this agent's endpoint."""
|
|
47
|
+
url = f"https://{self.domain}/run"
|
|
48
|
+
resp = requests.post(url, json={"prompt": prompt, **kwargs}, timeout=30)
|
|
49
|
+
resp.raise_for_status()
|
|
50
|
+
return resp.json()
|
|
51
|
+
|
|
52
|
+
# ── Main client ────────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
_SDK_VERSION = version("agentic-yp")
|
|
56
|
+
except PackageNotFoundError:
|
|
57
|
+
_SDK_VERSION = "dev"
|
|
58
|
+
|
|
59
|
+
class AgenticYPClient:
|
|
60
|
+
"""
|
|
61
|
+
Official Python SDK for Agentic Yellow Pages.
|
|
62
|
+
Discover, filter, and route to trusted A2A endpoints programmatically.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
DEFAULT_MIN_TRUST = 70
|
|
66
|
+
_cache: Optional[List[dict]] = None
|
|
67
|
+
_cache_ts: float = 0
|
|
68
|
+
CACHE_TTL = 30 # seconds
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
base_url: str = "https://agentic-yellow-pages.onrender.com",
|
|
73
|
+
timeout: int = 10,
|
|
74
|
+
cache_ttl: int = 30,
|
|
75
|
+
):
|
|
76
|
+
self.base_url = base_url.rstrip("/")
|
|
77
|
+
self.timeout = timeout
|
|
78
|
+
self.CACHE_TTL = cache_ttl
|
|
79
|
+
self.session = requests.Session()
|
|
80
|
+
self.session.headers.update({
|
|
81
|
+
"User-Agent": f"AgenticYP-Python-SDK/{_SDK_VERSION}"
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
def _fetch_all(self, force_refresh: bool = False) -> List[dict]:
|
|
85
|
+
"""Fetches the global index, with TTL caching."""
|
|
86
|
+
now = time.monotonic()
|
|
87
|
+
if not force_refresh and self._cache and (now - self._cache_ts) < self.CACHE_TTL:
|
|
88
|
+
logger.debug("Returning cached agent list (%d agents)", len(self._cache))
|
|
89
|
+
return self._cache
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
res = self.session.get(f"{self.base_url}/agents", timeout=self.timeout)
|
|
93
|
+
res.raise_for_status()
|
|
94
|
+
except requests.Timeout:
|
|
95
|
+
raise AgenticYPError(f"Request timed out after {self.timeout}s")
|
|
96
|
+
except requests.HTTPError as e:
|
|
97
|
+
raise AgenticYPAPIError(e.response.status_code, str(e))
|
|
98
|
+
except requests.RequestException as e:
|
|
99
|
+
raise AgenticYPError(f"Network error: {e}")
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
data = res.json()
|
|
103
|
+
agents = data.get("agents", []) if isinstance(data, dict) else data
|
|
104
|
+
except ValueError:
|
|
105
|
+
raise AgenticYPAPIError(res.status_code, "Response was not valid JSON")
|
|
106
|
+
|
|
107
|
+
self._cache = agents
|
|
108
|
+
self._cache_ts = now
|
|
109
|
+
logger.debug("Fetched %d agents from API", len(agents))
|
|
110
|
+
return agents
|
|
111
|
+
|
|
112
|
+
def discover(
|
|
113
|
+
self,
|
|
114
|
+
skill: Optional[str] = None,
|
|
115
|
+
min_trust_score: int = DEFAULT_MIN_TRUST,
|
|
116
|
+
require_online: bool = True,
|
|
117
|
+
require_a2a_verified: bool = False,
|
|
118
|
+
) -> List[AgentNode]:
|
|
119
|
+
"""
|
|
120
|
+
Find nodes matching your requirements.
|
|
121
|
+
|
|
122
|
+
:param skill: Tag/capability to filter on (e.g. 'search', 'mcp-server').
|
|
123
|
+
:param min_trust_score: Minimum Oracle trust score (0-100). Default: 70.
|
|
124
|
+
:param require_online: Exclude offline nodes.
|
|
125
|
+
:param require_a2a_verified: Only return deeply verified A2A nodes.
|
|
126
|
+
:returns: List of AgentNode, sorted by trust score descending.
|
|
127
|
+
"""
|
|
128
|
+
nodes = self._fetch_all()
|
|
129
|
+
results = []
|
|
130
|
+
|
|
131
|
+
for raw in nodes:
|
|
132
|
+
node = AgentNode.from_dict(raw)
|
|
133
|
+
|
|
134
|
+
if require_online and node.status == "offline":
|
|
135
|
+
continue
|
|
136
|
+
if require_a2a_verified and node.status != "a2a_verified":
|
|
137
|
+
continue
|
|
138
|
+
if node.trust_score < min_trust_score:
|
|
139
|
+
continue
|
|
140
|
+
if skill and skill.lower() not in node.tags:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
results.append(node)
|
|
144
|
+
|
|
145
|
+
return sorted(results, key=lambda n: n.trust_score, reverse=True)
|
|
146
|
+
|
|
147
|
+
def get_top_node(
|
|
148
|
+
self,
|
|
149
|
+
skill: str,
|
|
150
|
+
min_trust_score: int = DEFAULT_MIN_TRUST,
|
|
151
|
+
) -> AgentNode:
|
|
152
|
+
"""
|
|
153
|
+
Returns the single highest-rated node for a skill.
|
|
154
|
+
Raises AgentNotFoundError if nothing matches.
|
|
155
|
+
"""
|
|
156
|
+
nodes = self.discover(skill=skill, min_trust_score=min_trust_score)
|
|
157
|
+
if not nodes:
|
|
158
|
+
raise AgentNotFoundError(
|
|
159
|
+
f"No online agent found for skill='{skill}' with trust >= {min_trust_score}"
|
|
160
|
+
)
|
|
161
|
+
return nodes[0]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-yp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official SDK for the Agentic Yellow Pages A2A routing network.
|
|
5
|
+
Author-email: Agentic YP <admin@agenticyellowpage.com>
|
|
6
|
+
Project-URL: Homepage, https://agenticyellowpage.com
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: requests>=2.25.0
|
|
13
|
+
|
|
14
|
+
# Agentic Yellow Pages SDK 📒🤖
|
|
15
|
+
|
|
16
|
+
The official SDK for the [Agentic Yellow Pages](https://agenticyellowpage.com) — the discovery and trust routing layer for the machine-to-machine (M2M) economy.
|
|
17
|
+
|
|
18
|
+
Stop hardcoding agent endpoints. Use this SDK to dynamically discover, filter, and route data to A2A endpoints based on their cryptographic **Trust Score**, live health metrics, and capabilities.
|
|
19
|
+
|
|
20
|
+
## Usage (Python)
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from agentic_yp import AgenticYPClient
|
|
24
|
+
|
|
25
|
+
yp = AgenticYPClient()
|
|
26
|
+
|
|
27
|
+
# Automatically discover the safest, highest-rated web scraper
|
|
28
|
+
scraper_node = yp.get_top_node(skill="web-crawler", min_trust_score=90)
|
|
29
|
+
|
|
30
|
+
print(f"Routing to {scraper_node.domain} (Score: {scraper_node.trust_score})")
|
|
31
|
+
|
|
32
|
+
# Execute a payload directly to the node
|
|
33
|
+
response = scraper_node.execute(prompt="Scrape the latest AI news")
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
agentic_yp/__init__.py,sha256=Fa3DKFtBQThv6PNuPTAdetM-s0LSZiSdM5NVKGMfRAk,160
|
|
2
|
+
agentic_yp/client.py,sha256=VN_xw8qwgQzFh1jjEq5NA4D371o1ZqGpL-pgnTml51c,6071
|
|
3
|
+
agentic_yp-1.0.0.dist-info/METADATA,sha256=wBpMJppevqPt4A7vPbC_aA1W3RsZSrPn1yruxQVzHUw,1325
|
|
4
|
+
agentic_yp-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
agentic_yp-1.0.0.dist-info/top_level.txt,sha256=eRPrj6E2iC5W3cjB1sA1CGb0R5zrqeUkUhSKyWgIGj0,11
|
|
6
|
+
agentic_yp-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agentic_yp
|