Skip to content

Commit ac89838

Browse files
vvillait88claude
andcommitted
Remove stats/agents endpoints, fix types for API parity (v1.4.0)
- Remove get_stats(), get_agents() and async variants - Fix score value types from int to float (API returns JS Number) - Fix EvidenceSummary to match actual API fields (8 fields) - Add RedactedClassification for free tier chain entries - Make ChainEntry identity optional (free tier redaction) - Make OperatorScore agent_count/chains_active optional (free tier) - Fix ReputationStatus to match API values (scored/stale/known_unscored) - Make AssessResponse.chains required - Remove invalid top-level fields from ReputationResponse - Bump to v1.4.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b2132d4 commit ac89838

9 files changed

Lines changed: 104 additions & 373 deletions

File tree

‎.coverage‎

52 KB
Binary file not shown.

‎README.md‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ base_rep = client.get_reputation("0x1234...", chain="base")
2828
# On-the-fly assessment with policy (paid)
2929
result = client.assess("0x1234...", policy={"min_grade": "B", "min_score": 35})
3030
print(result["decision"], result["decision_reasons"])
31-
32-
# Browse agents
33-
agents = client.get_agents(chain="base", limit=10)
34-
print(len(agents["items"]), agents["count"])
35-
36-
# Ecosystem stats
37-
stats = client.get_stats()
38-
print(stats["erc8004"]["known_agents"])
3931
```
4032

4133
### Async

‎agentscore/__init__.py‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,26 @@
33
from agentscore.client import AgentScore
44
from agentscore.errors import AgentScoreError
55
from agentscore.types import (
6-
AgentRecord,
7-
AgentsListResponse,
86
AssessResponse,
97
DecisionPolicy,
108
EntityType,
119
Grade,
1210
Reputation,
1311
ReputationResponse,
14-
ReputationResponseFull,
1512
ReputationStatus,
16-
StatsERC8004,
17-
StatsPayments,
18-
StatsReputation,
19-
StatsResponse,
2013
)
2114

2215
__version__ = _pkg_version("agentscore-py")
2316

2417
__all__ = [
25-
"AgentRecord",
2618
"AgentScore",
2719
"AgentScoreError",
28-
"AgentsListResponse",
2920
"AssessResponse",
3021
"DecisionPolicy",
3122
"EntityType",
3223
"Grade",
3324
"Reputation",
3425
"ReputationResponse",
35-
"ReputationResponseFull",
3626
"ReputationStatus",
37-
"StatsERC8004",
38-
"StatsPayments",
39-
"StatsReputation",
40-
"StatsResponse",
4127
"__version__",
4228
]

‎agentscore/client.py‎

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99

1010
if TYPE_CHECKING:
1111
from agentscore.types import (
12-
AgentsListResponse,
1312
AssessResponse,
1413
DecisionPolicy,
15-
ReputationResponseFull,
16-
StatsResponse,
14+
ReputationResponse,
1715
)
1816

1917

@@ -86,7 +84,7 @@ def _handle_response(self, response: httpx.Response) -> dict:
8684

8785
# --- Sync methods ---
8886

89-
def get_reputation(self, address: str, chain: str | None = None) -> ReputationResponseFull:
87+
def get_reputation(self, address: str, chain: str | None = None) -> ReputationResponse:
9088
"""Get cached reputation for an address (free, read-only). Optionally filter by chain."""
9189
params: dict[str, str] = {}
9290
if chain:
@@ -114,22 +112,9 @@ def assess(
114112
response = client.post("/v1/assess", json=body)
115113
return self._handle_response(response)
116114

117-
def get_agents(self, **filters: Any) -> AgentsListResponse:
118-
"""Browse agents (free)."""
119-
params = {k: str(v).lower() if isinstance(v, bool) else str(v) for k, v in filters.items() if v is not None}
120-
client = self._get_sync_client()
121-
response = client.get("/v1/agents", params=params)
122-
return self._handle_response(response)
123-
124-
def get_stats(self) -> StatsResponse:
125-
"""Get ecosystem stats (free)."""
126-
client = self._get_sync_client()
127-
response = client.get("/v1/stats")
128-
return self._handle_response(response)
129-
130115
# --- Async methods ---
131116

132-
async def aget_reputation(self, address: str, chain: str | None = None) -> ReputationResponseFull:
117+
async def aget_reputation(self, address: str, chain: str | None = None) -> ReputationResponse:
133118
"""Get cached reputation for an address (free, read-only). Optionally filter by chain."""
134119
params: dict[str, str] = {}
135120
if chain:
@@ -157,19 +142,6 @@ async def aassess(
157142
response = await client.post("/v1/assess", json=body)
158143
return self._handle_response(response)
159144

160-
async def aget_agents(self, **filters: Any) -> AgentsListResponse:
161-
"""Browse agents (free)."""
162-
params = {k: str(v).lower() if isinstance(v, bool) else str(v) for k, v in filters.items() if v is not None}
163-
client = self._get_async_client()
164-
response = await client.get("/v1/agents", params=params)
165-
return self._handle_response(response)
166-
167-
async def aget_stats(self) -> StatsResponse:
168-
"""Get ecosystem stats (free)."""
169-
client = self._get_async_client()
170-
response = await client.get("/v1/stats")
171-
return self._handle_response(response)
172-
173145
def close(self):
174146
if self._sync_client:
175147
self._sync_client.close()

‎agentscore/types.py‎

Lines changed: 37 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Grade = Literal["A", "B", "C", "D", "F"]
66
EntityType = Literal["agent", "service", "hybrid", "wallet", "bot", "unknown"]
7-
ReputationStatus = Literal["unknown", "known_unscored", "scored", "stale", "indexing"]
7+
ReputationStatus = Literal["scored", "stale", "known_unscored"]
88

99

1010
class Subject(TypedDict):
@@ -23,23 +23,26 @@ class Classification(TypedDict):
2323

2424

2525
class Score(TypedDict):
26-
value: int | None
26+
value: float | None
2727
grade: Grade | None
2828
scored_at: str | None
2929
status: ReputationStatus
3030
version: str
3131

3232

33-
class ChainScore(TypedDict):
34-
value: int | None
33+
class _ChainScoreRequired(TypedDict):
34+
value: float | None
3535
grade: Grade | None
36-
confidence: float | None
37-
dimensions: dict[str, float] | None
3836
scored_at: str | None
3937
status: ReputationStatus
4038
version: str
4139

4240

41+
class ChainScore(_ChainScoreRequired, total=False):
42+
confidence: float | None
43+
dimensions: dict[str, float] | None
44+
45+
4346
class Identity(TypedDict):
4447
ens_name: str | None
4548
website_url: str | None
@@ -71,36 +74,27 @@ class Reputation(TypedDict):
7174
last_feedback_at: str | None
7275

7376

74-
class EvidenceSummary(TypedDict, total=False):
75-
candidate_tx_count: int
76-
confirmed_or_likely_tx: int
77-
endpoint_count: int
78-
github_stars: int
79-
github_url: str | None
80-
has_a2a_agent_card: bool
81-
has_ens: bool
82-
has_github: bool
83-
has_website: bool
84-
healthy_endpoints: int
85-
is_erc8004: bool
77+
class EvidenceSummary(TypedDict):
8678
metadata_kind: str | None
87-
metadata_quality: str | None
88-
multi_chain_count: int
89-
reputation_feedback_count: int
90-
reputation_trust_avg: float | None
91-
reputation_uptime_avg: float | None
92-
reputation_activity_avg: float | None
93-
reputation_client_count: int
94-
verified_tx_count: int
79+
has_a2a_agent_card: bool
80+
website_url: str | None
81+
website_reachable: bool
9582
website_mentions_mcp: bool
9683
website_mentions_x402: bool
97-
website_reachable: bool
98-
website_url: str | None
84+
github_url: str | None
85+
github_stars: int | None
86+
87+
88+
class RedactedClassification(TypedDict):
89+
entity_type: EntityType
9990

10091

101-
class OperatorScore(TypedDict):
102-
score: int
92+
class _OperatorScoreRequired(TypedDict):
93+
score: float
10394
grade: Grade
95+
96+
97+
class OperatorScore(_OperatorScoreRequired, total=False):
10498
agent_count: int
10599
chains_active: list[str]
106100

@@ -109,20 +103,23 @@ class AgentSummary(TypedDict):
109103
token_id: int
110104
chain: str
111105
name: str | None
112-
score: int
106+
score: float
113107
grade: Grade
114108

115109

116-
class ChainEntry(TypedDict):
110+
class _ChainEntryRequired(TypedDict):
117111
chain: str
118112
score: ChainScore
119-
classification: Classification
113+
classification: Classification | RedactedClassification
114+
115+
116+
class ChainEntry(_ChainEntryRequired, total=False):
120117
identity: Identity
121118
activity: Activity
122119
evidence_summary: EvidenceSummary
123120

124121

125-
class ReputationResponse(TypedDict):
122+
class _ReputationResponseRequired(TypedDict):
126123
subject: Subject
127124
score: Score
128125
chains: list[ChainEntry]
@@ -131,10 +128,10 @@ class ReputationResponse(TypedDict):
131128
updated_at: str | None
132129

133130

134-
class ReputationResponseFull(ReputationResponse, total=False):
131+
class ReputationResponse(_ReputationResponseRequired, total=False):
132+
reputation: Reputation
135133
operator_score: OperatorScore
136134
agents: list[AgentSummary]
137-
reputation: Reputation
138135

139136

140137
class DecisionPolicy(TypedDict, total=False):
@@ -143,7 +140,7 @@ class DecisionPolicy(TypedDict, total=False):
143140
require_verified_payment_activity: bool
144141

145142

146-
class AssessResponse(TypedDict):
143+
class _AssessResponseRequired(TypedDict):
147144
subject: Subject
148145
score: Score
149146
chains: list[ChainEntry]
@@ -153,64 +150,9 @@ class AssessResponse(TypedDict):
153150
data_semantics: str
154151
caveats: list[str]
155152
updated_at: str | None
153+
154+
155+
class AssessResponse(_AssessResponseRequired, total=False):
156156
operator_score: OperatorScore | None
157157
reputation: Reputation | None
158158
agents: list[AgentSummary]
159-
160-
161-
class AgentRecord(TypedDict):
162-
chain: str
163-
token_id: int
164-
owner_address: str
165-
agent_wallet: str | None
166-
name: str | None
167-
description: str | None
168-
metadata_quality: str
169-
score: int | None
170-
grade: Grade | None
171-
entity_type: EntityType | None
172-
endpoint_count: int
173-
website_url: str | None
174-
github_url: str | None
175-
has_candidate_payment_activity: bool
176-
has_verified_payment_activity: bool
177-
agents_sharing_owner: int | None
178-
updated_at: str
179-
180-
181-
class AgentsListResponse(TypedDict):
182-
items: list[AgentRecord]
183-
next_cursor: str | None
184-
count: int
185-
version: str
186-
187-
188-
class StatsPayments(TypedDict):
189-
addresses_with_candidate_payment_activity: int
190-
addresses_with_verified_payment_activity: int
191-
total_candidate_transactions: int
192-
total_verified_transactions: int
193-
verification_status_summary: dict[str, int]
194-
195-
196-
class StatsERC8004(TypedDict):
197-
known_agents: int
198-
by_chain: dict[str, int]
199-
metadata_quality_distribution: dict[str, int]
200-
201-
202-
class StatsReputation(TypedDict):
203-
total_addresses: int
204-
scored_addresses: int
205-
entity_distribution: dict[str, int]
206-
score_distribution: dict[str, int]
207-
208-
209-
class StatsResponse(TypedDict, total=False):
210-
version: str
211-
as_of_time: str
212-
data_semantics: str
213-
erc8004: StatsERC8004
214-
reputation: StatsReputation
215-
payments: StatsPayments
216-
caveats: list[str]

‎pyproject.toml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "agentscore-py"
7-
version = "1.3.0"
7+
version = "1.4.0"
88
description = "Python client for the AgentScore trust and reputation API"
99
readme = "README.md"
1010
license = "MIT"
@@ -44,4 +44,6 @@ dev = [
4444
"ruff>=0.11.0",
4545
"vulture>=2.15",
4646
"pytest-cov>=6.0",
47+
"respx>=0.22.0",
48+
"pytest-asyncio>=1.2.0",
4749
]

0 commit comments

Comments
 (0)