Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions agentscore/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class Subject(TypedDict):
chain: str
chains: list[str]
address: str


Expand All @@ -23,12 +23,20 @@ class Classification(TypedDict):


class Score(TypedDict):
value: int | None
grade: Grade | None
scored_at: str | None
status: ReputationStatus
version: str


class ChainScore(TypedDict):
value: int | None
grade: Grade | None
confidence: float | None
dimensions: dict[str, float] | None
scored_at: str | None
status: ReputationStatus
version: str


Expand Down Expand Up @@ -105,13 +113,19 @@ class AgentSummary(TypedDict):
grade: Grade


class ChainEntry(TypedDict):
chain: str
score: ChainScore
classification: Classification
identity: Identity
activity: Activity
evidence_summary: EvidenceSummary


class ReputationResponse(TypedDict):
subject: Subject
classification: Classification
score: Score
identity: Identity | None
activity: Activity | None
evidence_summary: EvidenceSummary | None
chains: list[ChainEntry]
data_semantics: str
caveats: list[str]
updated_at: str | None
Expand All @@ -131,17 +145,17 @@ class DecisionPolicy(TypedDict, total=False):

class AssessResponse(TypedDict):
subject: Subject
classification: Classification
score: Score
identity: Identity | None
activity: Activity | None
evidence_summary: EvidenceSummary | None
data_semantics: str
caveats: list[str]
updated_at: str | None
chains: list[ChainEntry]
decision: str | None
decision_reasons: list[str]
on_the_fly: bool
data_semantics: str
caveats: list[str]
updated_at: str | None
operator_score: OperatorScore | None
reputation: Reputation | None
agents: list[AgentSummary]


class AgentRecord(TypedDict):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "agentscore-py"
version = "1.2.0"
version = "1.3.0"
description = "Python client for the AgentScore trust and reputation API"
readme = "README.md"
license = "MIT"
Expand Down
28 changes: 12 additions & 16 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,24 @@ def test_constructor_default_timeout():
# ---------------------------------------------------------------------------

REPUTATION_PAYLOAD = {
"subject": {"chain": "base", "address": ADDRESS},
"classification": {
"entity_type": "wallet",
"confidence": 0.9,
"is_known": True,
"is_known_erc8004_agent": False,
"has_candidate_payment_activity": True,
"has_verified_payment_activity": False,
"reasons": [],
},
"subject": {"chains": ["base"], "address": ADDRESS},
"score": {
"status": "scored",
"value": 75,
"grade": "B",
"confidence": 0.85,
"dimensions": None,
"scored_at": "2024-01-01T00:00:00Z",
"status": "scored",
"version": "1",
},
"identity": None,
"activity": None,
"evidence_summary": None,
"chains": [
{
"chain": "base",
"score": {"value": 75, "grade": "B"},
"classification": {"entity_type": "wallet", "confidence": 0.9},
"identity": {},
"activity": {},
"evidence_summary": {},
},
],
"data_semantics": "live",
"caveats": [],
"updated_at": "2024-01-01T00:00:00Z",
Expand Down
114 changes: 114 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os

import pytest

from agentscore import AgentScore

API_KEY = os.environ.get("AGENTSCORE_API_KEY")
BASE_URL = os.environ.get("AGENTSCORE_BASE_URL", "http://api.dev.agentscore.internal")
TEST_ADDRESS = "0x339559a2d1cd15059365fc7bd36b3047bba480e0"

pytestmark = pytest.mark.skipif(not API_KEY, reason="AGENTSCORE_API_KEY not set")


def test_get_reputation_shape():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS)

assert "chains" in rep["subject"]
assert isinstance(rep["subject"]["chains"], list)
assert len(rep["subject"]["chains"]) > 0

assert "value" in rep["score"]
assert "grade" in rep["score"]
assert "scored_at" in rep["score"]
assert "status" in rep["score"]
assert "version" in rep["score"]
assert "confidence" not in rep["score"]
assert "dimensions" not in rep["score"]

assert "chains" in rep
assert isinstance(rep["chains"], list)
assert len(rep["chains"]) > 0

chain = rep["chains"][0]
assert "chain" in chain
assert "score" in chain
assert "classification" in chain
assert "identity" in chain
assert "activity" in chain
assert "evidence_summary" in chain

assert "agents" in rep
assert isinstance(rep["agents"], list)


def test_get_reputation_chain_filter():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS, chain="base")

assert rep["subject"]["chains"] == ["base"]
assert len(rep["chains"]) == 1
assert rep["chains"][0]["chain"] == "base"


def test_get_reputation_chain_entry_full_fields():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS)
chain = rep["chains"][0]

assert "confidence" in chain["score"]
assert "dimensions" in chain["score"]
assert "as_verified_payer" in chain["activity"]
assert "active_days" in chain["activity"]
assert "first_candidate_tx_at" in chain["activity"]


def test_get_reputation_metadata_fields():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS)

assert "caveats" in rep
assert "data_semantics" in rep
assert "updated_at" in rep


def test_assess_operator_level():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
result = client.assess(TEST_ADDRESS)

assert "decision" in result
assert isinstance(result["decision_reasons"], list)
assert isinstance(result["chains"], list)
assert isinstance(result["agents"], list)
assert "classification" not in result


def test_assess_policy_deny():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
result = client.assess(TEST_ADDRESS, policy={"min_score": 999})

assert result["decision"] == "deny"
assert len(result["decision_reasons"]) > 0


def test_get_reputation_operator_score():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS)
op = rep.get("operator_score")
if not op:
pytest.skip("no operator_score on test address")
assert isinstance(op["score"], int)
assert isinstance(op["grade"], str)
assert isinstance(op["agent_count"], int)
assert isinstance(op["chains_active"], list)


def test_get_reputation_reputation_field():
client = AgentScore(api_key=API_KEY, base_url=BASE_URL)
rep = client.get_reputation(TEST_ADDRESS)
r = rep.get("reputation")
if not r:
pytest.skip("no reputation on test address")
assert isinstance(r["feedback_count"], int)
assert isinstance(r["client_count"], int)
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading