Skip to main content

MrProbe / Agent Guard customer observation SDK — ship your agent's response back to MrProbe in 6 lines.

Project description

agentguard-observe

Customer-side observation SDK for MrProbe / Agent Guard (POST /api/v1/observe).

Ship your agent's response back to MrProbe in 6 lines so red-team campaigns get live, signed, retry-safe, secret-redacted observations from your agent runtime — wherever it runs (FastAPI, Vertex AI, Bedrock Lambda, Azure Function, custom HTTP).

Status: v0.1.0 — design-partner ready for Email Agents on Microsoft 365 Outlook and Google Workspace Gmail. The same SDK is the Pillar 4 surface for every other agent-type epic (Document/RAG, Salesforce, ServiceNow, etc.) — internally tracked as MRPRBE-303. Pre-1.0 because the wire-shape (e.g. llm_response field name) may evolve through design-partner feedback before we commit to the 1.0 stability contract.


Install

From PyPI (recommended)

pip install agentguard-observe

Pin in requirements.txt:

agentguard-observe==0.1.0

From the GitHub release (alternative — hash-pinned)

pip install \
  https://github.com/QDEXConsulting/agent-guard/releases/download/agentguard-observe-v0.1.0/agentguard_observe-0.1.0-py3-none-any.whl \
  --hash=sha256:<copy-from-the-release-page>

The SHA-256 of every published wheel + sdist is printed in the release notes on the GitHub Releases page. Include the --hash line for supply-chain verification.

From source (during development / dogfooding)

git clone https://github.com/QDEXConsulting/agent-guard.git
pip install -e ./agent-guard/sdk/agentguard_observe

Six-line happy path

import os
from agentguard_observe import Client

client = Client(
    api_key=os.environ["AGENTGUARD_API_KEY"],            # bearer identifier (shown once at agent registration)
    agent_id=os.environ["AGENTGUARD_AGENT_ID"],          # the agent's UUID
    signing_secret=os.environ["AGENTGUARD_SIGNING_SECRET"], # HMAC key — see "Fetching your signing secret" below
)

# ... your agent processes the inbound and produces a reply ...

client.observe(
    attack_id=inbound_headers["X-AgentGuard-ID"],  # echoed back from the test message
    response_text=reply.text,                       # what your LLM said
    action="email_forward",                          # what your agent DID (or "none")
    action_status="executed",                        # "executed" | "blocked" | "none"
    action_target="alice@example.com",              # who/what the action affected
)

That's the entire integration. The SDK signs the request, retries on transient failures, and redacts common secret shapes from response_text / action_target before they leave your VPC.

Asyncio variant (FastAPI / Vertex AI Agents / asyncio runtimes)

from agentguard_observe import AsyncClient

async with AsyncClient(
    api_key=KEY,
    agent_id=AGENT_ID,
    signing_secret=SIGNING_SECRET,
) as client:
    await client.observe(attack_id="...", response_text=reply.text)

The surface is identical — every method is awaitable.


Fetching your signing secret

The signing secret is a SEPARATE value from your API key. The API key is your bearer identifier (transmitted in the X-AgentGuard-Key header on every request); the signing secret is the HMAC key used to compute the request signature and is never transmitted on the wire. Together they give MrProbe cryptographic proof that a /v1/observe payload originated from your customer deployment and wasn't tampered with in transit.

One-time fetch (after registering your agent):

curl -H "Authorization: Bearer $YOUR_JWT" \
     https://api.mrprobe.dev/api/v1/agents/$AGENT_ID/webhook/signing-secret

The response is:

{
  "agent_id": "...",
  "signing_secret": "<64 hex chars>",
  "derivation": "HKDF-SHA256(master_key, api_key, info='agentguard-observe-v1')"
}

Store the value in your secret manager (AWS Secrets Manager / GCP Secret Manager / HashiCorp Vault / Kubernetes Secret) and load it as AGENTGUARD_SIGNING_SECRET in your runtime. The endpoint is idempotent — calling it again returns the same value, so a customer who lost the secret can re-fetch it without rotating the api_key.

Why not just use the API key as the HMAC secret? Because then capturing one signed request (TLS-terminating proxy logs, mistakenly logged headers, etc.) gives an attacker the secret AND the ability to forge any future request — defeating the whole point of HMAC. With the values separated, capturing a signed request reveals only the api_key + ts + nonce + sig + body, none of which let the attacker recover the signing secret.


What the SDK does for you

Concern What we do Why
Authentication Adds X-AgentGuard-Key header from your API key (bearer identifier) BE looks up the agent row by api_key
Request signing HMAC-SHA256 over {ts, nonce, method, path, sha256(body)} keyed by signing_secret; X-AgentGuard-Signature: v1=<hex> Replay protection (BE rejects requests outside ±5 min) and tamper detection. signing_secret is held only by you, never transmitted
Retry on transient failure 3 attempts, full-jitter exponential backoff (250 ms → 8 s cap) Handles MrProbe deploys + DNS blips without manual retry code
Outbound redaction Regex-strips JWTs, AWS keys, GCP private keys, OpenAI / Anthropic / Google / Stripe / GitHub / Slack tokens before send Prevents your agent from accidentally exfiltrating secrets to MrProbe
Eager validation Length + enum checks at the call site 422-round-trip turns into a ValueError with a clear message
Connection pooling One httpx.Client (or AsyncClient) per Client instance Single keep-alive socket; sub-50ms calls

What the SDK does NOT do (intentional v1 scope):

  • No custom in-memory queue / batch / drain semantics — every observe() is a single immediate POST. If you need batching, wrap the SDK in your own queue.
  • No automatic correlation between inbound + outbound. You pass attack_id explicitly so a future SDK refactor can't invent a hidden-state bug.
  • No DLP — the redaction bank is intentionally small (well-known token shapes only). Layer your own DLP in front for full coverage.

Testing your integration

After registering an Email Agent in MrProbe, run a canary attack against your registered agent:

  1. In the MrProbe UI, open the agent → Connection check → "Send canary".
  2. MrProbe sends a benign test message to your mailbox.
  3. Your agent processes it (no harm — the canary contains no instructions).
  4. Your agent calls client.observe(...) with the canary's attack_id.
  5. MrProbe shows a green tick on the End-to-end ready card.

Both halves of the loop must be green before you run a real security campaign.


Connection check from agentguard_observe

from agentguard_observe import Client

with Client(
    api_key=KEY,
    agent_id=AGENT_ID,
    signing_secret=SIGNING_SECRET,
) as client:
    # No-op observation against a sentinel attack id — verifies auth +
    # signing without polluting any real campaign.
    try:
        client.observe(attack_id="canary-sdk-selftest")
        print("✓ SDK can reach MrProbe and authenticate")
    except Exception as exc:
        print(f"✗ SDK self-test failed: {exc}")

Configuration

Argument Default Description
api_key (required) The webhook key surfaced at agent registration. Treat as a secret.
agent_id (required) The agent's UUID.
base_url https://api.mrprobe.dev Override for on-prem / EU-residency / staging.
timeout_s 10.0 Per-request timeout.
retry RetryPolicy(max_attempts=3, base_delay_s=0.25, max_delay_s=8.0) Tune via from agentguard_observe.retry import RetryPolicy.
redact True Set False to disable outbound secret redaction (NOT RECOMMENDED).
sign True Set False to send unsigned requests during the 30-day deprecation window.
http_client None Pass your own httpx.Client / httpx.AsyncClient to share its connection pool.

Sample apps

The samples/ directory ships two complete reference integrations that mirror what the v1 customer base actually deploys:

More samples (Bedrock Lambda, Azure Function, Express middleware) ship in v1.1 — file an issue or ping support@sniffr.ai if you need them sooner.


Versioning + wire-format guarantee

The SDK follows semver. The wire format (request body, headers, signing algorithm) is part of the SDK's public API — any incompatible change on either the SDK or the BE bumps the major version of both, and the SDK ships a vN+1 signing-string variant alongside vN for at least 30 days of overlap.


Licence

MIT — vendor freely.


Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentguard_observe-0.1.0.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentguard_observe-0.1.0-py3-none-any.whl (31.5 kB view details)

Uploaded Python 3

File details

Details for the file agentguard_observe-0.1.0.tar.gz.

File metadata

  • Download URL: agentguard_observe-0.1.0.tar.gz
  • Upload date:
  • Size: 45.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for agentguard_observe-0.1.0.tar.gz
Algorithm Hash digest
SHA256 df45e9dcbf75fe9fbc24d976ad0653c0036f9524bb4a6615ac2413e3eca0309d
MD5 4ed3722a673aaf34c68fcf2ba7b6b217
BLAKE2b-256 ac4d8ed368e8a11208b14fb3734513589f5c114fad9e0afa50240568cec2e610

See more details on using hashes here.

File details

Details for the file agentguard_observe-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agentguard_observe-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e654e121f537e44a863dd99245cfb6494ce9a54fb964e24c000efe502fe0f70e
MD5 5794f2b056331278b168c1b48c1b1163
BLAKE2b-256 bd547dea44b398c2e5f14331bfb5f98062c5b710e8ae42220f73c5b6f99ea097

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page