Files
sentryagent-idp/sdk-python
SentryAgent.ai Developer c93562e685 feat(phase-2): workstream 2 — Python SDK (sentryagent-idp)
Sync (requests) and async (httpx) clients with identical API surface
to the Node.js SDK.

Delivered:
- pyproject.toml — python>=3.9, hatchling build, mypy strict config
- types.py — all 14-endpoint request/response dataclasses
- errors.py — AgentIdPError with from_api_error, from_oauth2_error, network_error
- token_manager.py — thread-safe sync TokenManager, 60s refresh buffer
- async_token_manager.py — asyncio-safe AsyncTokenManager (httpx)
- _request.py — shared sync/async request helper (DRY)
- services/agents.py — AgentRegistryClient + AsyncAgentRegistryClient (5 methods each)
- services/credentials.py — CredentialClient + AsyncCredentialClient (4 methods each)
- services/token.py — TokenClient + AsyncTokenClient (introspect + revoke)
- services/audit.py — AuditClient + AsyncAuditClient (query + get)
- client.py — AgentIdPClient + AsyncAgentIdPClient
- __init__.py — barrel exports
- README.md — installation, quick start, full API reference

QA gates:
- mypy --strict: 0 errors (12 source files)
- pytest: 57/57 passed
- Coverage: 90.83% (required >= 80%)
- All 14 endpoints covered (sync + async)
- AgentIdPError raised on all failure paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 15:11:27 +00:00
..

sentryagent-idp

Python SDK for the SentryAgent.ai AgentIdP — the open-source Identity Provider for AI agents.

Handles token acquisition and caching automatically. Covers all 14 AgentIdP API endpoints. Provides both synchronous (requests) and asynchronous (httpx) clients.


Requirements

  • Python 3.9 or later
  • A running AgentIdP server
  • A registered agent with a valid client_id and client_secret

Installation

pip install sentryagent-idp

Quick start

Synchronous

from sentryagent_idp import AgentIdPClient

client = AgentIdPClient(
    base_url="http://localhost:3000",
    client_id="your-agent-id",       # the agent's agentId (UUID)
    client_secret="your-client-secret",
)

# List agents — token is acquired and cached automatically
result = client.agents.list_agents()
print(result.data)

Asynchronous

import asyncio
from sentryagent_idp import AsyncAgentIdPClient

async def main() -> None:
    client = AsyncAgentIdPClient(
        base_url="http://localhost:3000",
        client_id="your-agent-id",
        client_secret="your-client-secret",
    )
    result = await client.agents.list_agents()
    print(result.data)

asyncio.run(main())

Configuration

client = AgentIdPClient(
    base_url="http://localhost:3000",
    client_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    client_secret="your-client-secret",
    # Optional: restrict scopes. Defaults to all four.
    scopes=["agents:read", "tokens:read"],
)
Parameter Required Description
base_url Yes Base URL of the AgentIdP server
client_id Yes The agent's agentId (UUID)
client_secret Yes The credential secret
scopes No OAuth 2.0 scopes to request. Defaults to all four.

Token management

The SDK fetches and caches access tokens automatically. A new token is requested when the cached token is within 60 seconds of expiry.

# Force a fresh token on the next request (e.g. after rotating credentials)
client.clear_token_cache()

Agent Registry

from sentryagent_idp import RegisterAgentRequest, UpdateAgentRequest

# Register a new agent
agent = client.agents.register_agent(RegisterAgentRequest(
    email="classifier-v2@myorg.ai",
    agent_type="classifier",
    version="2.0.0",
    capabilities=["text-classification", "sentiment-analysis"],
    owner="platform-team",
    deployment_env="production",
))
print(agent.agent_id)  # UUID assigned by AgentIdP

# List agents
result = client.agents.list_agents(status="active", limit=20)

# Get a single agent
agent = client.agents.get_agent("a1b2c3d4-...")

# Update an agent
updated = client.agents.update_agent("a1b2c3d4-...", UpdateAgentRequest(
    version="2.1.0",
    capabilities=["text-classification", "sentiment-analysis", "intent-detection"],
))

# Decommission (irreversible)
client.agents.decommission_agent("a1b2c3d4-...")

Credentials

# Generate a credential — client_secret shown once, store it securely
cred = client.credentials.generate_credential("a1b2c3d4-...")
print(cred.client_secret)  # only available here

# List credentials
result = client.credentials.list_credentials("a1b2c3d4-...")

# Rotate — same credential_id, new secret, old secret immediately invalid
rotated = client.credentials.rotate_credential("a1b2c3d4-...", "cred-uuid")
print(rotated.client_secret)  # new secret — store immediately

# Revoke
client.credentials.revoke_credential("a1b2c3d4-...", "cred-uuid")

Token operations

# Introspect — check whether a token is active
result = client.tokens.introspect_token(some_token)
if result.active:
    print(f"Token valid, expires at {result.exp}")
else:
    print("Token is expired or revoked")

# Revoke — immediately invalidates the token
client.tokens.revoke_token(some_token)

Audit log

# Query audit events
result = client.audit.query_audit_log(
    agent_id="a1b2c3d4-...",
    action="token.issued",
    outcome="success",
    from_date="2026-03-01T00:00:00Z",
    to_date="2026-03-31T23:59:59Z",
    limit=50,
)

# Get a single event
event = client.audit.get_audit_event("event-uuid")

Error handling

All API errors are raised as AgentIdPError:

from sentryagent_idp import AgentIdPClient, AgentIdPError

try:
    client.agents.get_agent("non-existent-id")
except AgentIdPError as err:
    print(err.code)        # e.g. "AgentNotFoundError"
    print(err.http_status) # e.g. 404
    print(str(err))        # human-readable description

Available scopes

Scope What it allows
agents:read Read agent records
agents:write Create, update, decommission agents
tokens:read Introspect tokens
audit:read Query audit logs

License

Apache 2.0 — see LICENSE in the repository root.