Metadata-Version: 2.4
Name: axiorank
Version: 0.17.0
Summary: Official Python SDK for AxioRank. Zero-Trust for AI agents: route every tool call through one governed control plane.
Project-URL: Homepage, https://axiorank.com
Project-URL: Documentation, https://app.axiorank.com/docs
Project-URL: Source, https://github.com/frostyhand/AxioRank
Project-URL: Issues, https://github.com/frostyhand/AxioRank/issues
Author: AxioRank
License: MIT
License-File: LICENSE
Keywords: agent,agent-security,ai,axiorank,firewall,gateway,guardrails,llm,mcp,security,zero-trust
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1,>=0.27
Provides-Extra: adk
Requires-Dist: google-adk>=1.0; extra == 'adk'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == 'anthropic'
Provides-Extra: crewai
Requires-Dist: crewai>=0.100; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: cryptography>=42; extra == 'dev'
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: google-genai
Requires-Dist: google-genai>=1.0; extra == 'google-genai'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3; extra == 'langchain'
Provides-Extra: litellm
Requires-Dist: litellm>=1.60; extra == 'litellm'
Provides-Extra: llamaindex
Requires-Dist: llama-index-core>=0.10; extra == 'llamaindex'
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
Provides-Extra: pydantic-ai
Requires-Dist: pydantic-ai>=1.0; extra == 'pydantic-ai'
Provides-Extra: smolagents
Requires-Dist: smolagents>=1.0; extra == 'smolagents'
Provides-Extra: strands
Requires-Dist: strands-agents>=1.0; extra == 'strands'
Provides-Extra: verify
Requires-Dist: cryptography>=42; extra == 'verify'
Description-Content-Type: text/markdown

# axiorank

Catch leaked secrets, prompt injection, destructive commands, and PII in your AI
agent's tool calls. This runs the same detection engine the hosted
[AxioRank](https://axiorank.com) gateway runs, in-process, with no API key and no
signup.

Parity with the TypeScript [`@axiorank/sdk`](https://www.npmjs.com/package/@axiorank/sdk).

## Install

```bash
pip install axiorank
```

## Try it first (no API key)

See what AxioRank catches before you sign up. No key, no network:

```bash
python -m axiorank demo
```

In code, `inspect()` returns an advisory verdict (the default posture: deny on a
live secret, a destructive operation, or risk at or above 75):

```python
from axiorank import inspect

r = inspect("aws.s3.putObject", {
    "body": "AKIAIOSFODNN7EXAMPLE",
    "webhook": "http://attacker.example/exfil",
})
print(r.decision, r.risk)  # "deny" 96
print([s.detector for s in r.signals])  # ["secret.aws_access_key", ...]
```

`inspect_text(tool, text)` does the same for a tool's **output**, catching
indirect prompt injection before your agent ingests it.

## Enforce centrally

`inspect()` shows what is risky locally. To **enforce** it with your own policy,
an audit trail, approvals, and kill-chain correlation, create a free key at
[axiorank.com](https://www.axiorank.com) and route calls through the gateway.

## AI Gateway (no code change)

This SDK governs **tool calls**. To govern **model calls** with no code change,
use the hosted **AI Gateway**: a drop-in, OpenAI-compatible proxy. Point your
existing client's `base_url` at it and add one header, and every prompt and
completion is scored, policy-checked, spend-metered, and audited.

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://app.axiorank.com/api/proxy/v1",
    api_key="sk-...",  # forwarded upstream, never stored
    default_headers={"X-AxioRank-Key": "axr_live_..."},
)
```

Azure OpenAI, Anthropic, Amazon Bedrock, Google Gemini, and Vertex are supported
too. See the [AI Gateway docs](https://www.axiorank.com/docs/ai-gateway).

## Quickstart (sync)

```python
import os
from axiorank import AxioRank

axio = AxioRank(api_key=os.environ["AXIORANK_API_KEY"])  # looks like axr_live_...

# Get the decision and act on it yourself:
result = axio.tool_call("github.push", {"repo": "myrepo"})
if result.decision == "deny":
    print(f"Blocked: {result.reason} (risk {result.risk})")
else:
    ...  # proceed with the real tool call
```

### `enforce()`: guard in one line

```python
from axiorank import AxioRank, AxioRankDeniedError

axio = AxioRank(api_key=os.environ["AXIORANK_API_KEY"])

try:
    axio.enforce("aws.delete_bucket", {"name": "prod-data"})
    delete_bucket("prod-data")  # only runs if AxioRank allowed it
except AxioRankDeniedError as e:
    log.warning("AxioRank blocked the call: %s", e.result.reason)
```

A `require_approval` policy holds the call for a human; `tool_call`/`enforce`
transparently wait out the hold and resolve to the final `allow`/`deny`.

## Quickstart (async)

```python
import os
from axiorank import AsyncAxioRank

async def main():
    async with AsyncAxioRank(api_key=os.environ["AXIORANK_API_KEY"]) as axio:
        result = await axio.tool_call("stripe.refund", {"amount": 5000})
        print(result.decision, result.risk)
```

## Preflight an external server before trusting it

```python
result = axio.verify_card(url="https://mcp.acme.com")
print(result.decision, result.identity.signature_valid, result.protocol)

# Or guard in one line; raises AxioRankCardDeniedError on `deny`:
axio.enforce_card(url="https://mcp.acme.com")
```

## Anthropic Messages API

The Anthropic SDK doesn't run your tools; your loop does. Guard the dispatch
step and send back the `tool_result` dicts it returns. Defaults to
`on_deny="return"`; the adapter never imports `anthropic` itself.

```python
import anthropic
from axiorank import AxioRank
from axiorank.integrations.anthropic import guard_tool_handlers

client = anthropic.Anthropic()
axio = AxioRank(api_key=os.environ["AXIORANK_API_KEY"])
dispatch = guard_tool_handlers({"deploy": lambda i: deploy(i["service"])}, axio)

msg = client.messages.create(model="claude-opus-4-8", tools=tools, messages=messages)
results = [dispatch(b) for b in msg.content if b.type == "tool_use"]
# send `results` back as the next user message
```

Async client? Use `guard_tool_handlers_async` (or `guard_tool_use` /
`guard_tool_use_async` to guard a single block).

## LangChain

```bash
pip install "axiorank[langchain]"
```

```python
from axiorank import AxioRank
from axiorank.integrations.langchain import AxioRankCallbackHandler

axio = AxioRank(api_key=os.environ["AXIORANK_API_KEY"])

# Every tool the agent runs is checked against your policies first; a blocked
# tool raises and the step fails.
agent_executor.invoke(
    {"input": "..."},
    config={"callbacks": [AxioRankCallbackHandler(axio)]},
)
```

Prefer a model-readable refusal over a raised exception? Wrap individual tools:

```python
from axiorank.integrations.langchain import guard_tool

safe_tool = guard_tool(my_tool, axio, on_deny="return")
```

## LlamaIndex

```bash
pip install "axiorank[llamaindex]"
```

```python
from axiorank.integrations.llamaindex import guard_tool

# Wrap any FunctionTool: its arguments are scored before it runs, and the
# schema, name, and description are preserved, so it is a drop-in replacement.
safe_tool = guard_tool(my_tool, axio)                      # raises on deny
recoverable = guard_tool(my_tool, axio, on_deny="return")  # model-readable refusal
```

## Pydantic AI

```bash
pip install "axiorank[pydantic-ai]"
```

```python
from axiorank.integrations.pydantic_ai import guard_tool

# Wrap a Tool; its name, description, and signature (schema) are preserved.
safe_tool = guard_tool(my_tool, axio)                       # sync tool
safe_async = guard_tool(my_tool, async_client=axio_async)   # async tool
```

## OpenAI Agents (Python)

```bash
pip install "axiorank[openai-agents]"
```

```python
from axiorank import AsyncAxioRank
from axiorank.integrations.openai_agents import guard_tool

axio = AsyncAxioRank(api_key=os.environ["AXIORANK_API_KEY"])

# The SDK runs tools async; a deny returns a refusal the model can re-plan around.
safe_tool = guard_tool(my_function_tool, axio, on_deny="return")
```

## More framework integrations

Every adapter follows the same wrapping pattern, scoring a tool's arguments
before it runs. Install the extra you use; the adapters are lazy-imported.

| Framework | Install | Import |
| --- | --- | --- |
| CrewAI | `pip install "axiorank[crewai]"` | `axiorank.integrations.crewai` |
| AutoGen / AG2 | `pip install axiorank` (framework-free) | `axiorank.integrations.autogen` |
| Google ADK | `pip install "axiorank[adk]"` | `axiorank.integrations.adk` (`guard_tool` + the runtime `AxioRankPlugin`) |
| Google Gemini | `pip install "axiorank[google-genai]"` | `axiorank.integrations.google_genai` (`guard_function_handlers`) |
| smolagents | `pip install "axiorank[smolagents]"` | `axiorank.integrations.smolagents` |
| LiteLLM proxy | `pip install "axiorank[litellm]"` | `axiorank.integrations.litellm` (one guardrail governs every framework behind the proxy) |
| Strands Agents | `pip install "axiorank[strands]"` | `axiorank.integrations.strands` |

## Verify inbound agents

The flip side of guarding outbound calls: verify the AI agents reaching into a
surface **you** operate. Authenticate with a surface **site key** (`axr_site_...`),
not your agent key. For an MCP server, A2A agent, HTTP API, or webhook, supply the
caller's identity material directly:

```python
from axiorank import verify_surface

result = verify_surface(
    {"surface_kind": "mcp_server", "operation": "tools/call", "agent_card": incoming_card},
    api_key=os.environ["AXIORANK_SITE_KEY"],
)
if result.decision != "allow":
    raise rpc_error(result.challenge)
```

For an inbound website / HTTP request, pass the request metadata (the Web Bot Auth
signature headers are lifted out for you):

```python
from axiorank import verify_request

result = verify_request(
    method=request.method,
    authority=request.host,
    path=request.path,
    headers=dict(request.headers),
    api_key=os.environ["AXIORANK_SITE_KEY"],
)
if result.decision != "allow":
    abort(401)
```

Both have `verify_surface_async` / `verify_request_async` for ASGI handlers
(FastAPI, Starlette), and both fail open: only a misconfigured site key (401)
raises; any transport failure resolves to the `on_error` verdict.

## Webhooks

Verify and parse AxioRank webhook events in one call:

```python
from axiorank import construct_event

event = construct_event(raw_body, request.headers.get("axiorank-signature"), secret)
# raises AxioRankWebhookSignatureError on a bad, stale, or missing signature
```

## Verify an audit receipt offline

`verify_receipt(receipt, jwks)` checks an AxioRank audit receipt with no network
call (RFC 6962 Merkle inclusion, Ed25519 signed tree head, delegation provenance).
Install the Ed25519 support: `pip install "axiorank[verify]"`.

## Configuration

| Argument           | Default                       | Notes                                            |
| ------------------ | ----------------------------- | ------------------------------------------------ |
| `api_key`          | - (required)                  | Your agent's key (`axr_live_...`).               |
| `base_url`         | `https://app.axiorank.com`    | Point at your own deployment.                    |
| `timeout`          | `10.0`                        | Per-request timeout, in seconds.                 |
| `approval_timeout` | `300.0`                       | Max wait for a human to resolve a hold, seconds. |
| `client`           | a fresh `httpx.Client`        | Inject your own `httpx` client (tests, proxies). |

## License

MIT
