Metadata-Version: 2.4
Name: cisco-aidefense-google-adk
Version: 1.0.0
Summary: Cisco AI Defense plugin for Google ADK — native callback-based LLM and MCP inspection
License: Apache-2.0
License-File: LICENSE
Author: Cisco AI Defense
Author-email: ai-defense@cisco.com
Requires-Python: >=3.10,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
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: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Provides-Extra: dev
Provides-Extra: examples
Requires-Dist: cisco-aidefense-sdk (>=2.1.1)
Requires-Dist: google-adk (>=1.0.0,<3.0.0)
Requires-Dist: google-genai (>=1.14.0,<3.0.0)
Requires-Dist: mcp (>=1.6.0) ; extra == "examples"
Requires-Dist: pytest (>=7.0) ; extra == "dev"
Requires-Dist: pytest-asyncio (>=0.23) ; extra == "dev"
Requires-Dist: python-dotenv (>=1.0.0) ; extra == "examples"
Project-URL: Homepage, https://github.com/cisco-ai-defense/ai-defense-google-adk
Project-URL: Repository, https://github.com/cisco-ai-defense/ai-defense-google-adk
Description-Content-Type: text/markdown

# ai-defense-google-adk

Cisco AI Defense plugin for [Google ADK](https://google.github.io/adk-docs/) — native callback-based LLM and MCP tool inspection.

This package integrates [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html) runtime inspection directly into the ADK Runner lifecycle using a `BasePlugin` and per-agent callbacks. It supports both LLM prompt/response inspection and MCP tool call inspection, with monitor and enforce modes, plus optional violation callbacks and structured enforcement metadata.

## Use Cases

- **Runtime protection for Gemini calls**: Inspect user prompts before model calls and model outputs after generation, then allow or block based on policy (Monitor or Enforce).
- **Tool and MCP call inspection**: Inspect tool call requests before execution and tool responses after execution, and block unsafe tool behavior in Enforce mode with clear metadata.
- **Auditable decision trace and alerts**: Capture decision context (action, severity, classifications, request\_id/event\_id) and optionally trigger an `on_violation` callback for monitoring and incident response.

## Prerequisites

- [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html) account and API key
- Python >= 3.10
- [Google ADK](https://google.github.io/adk-docs/) >= 1.0.0

## Installation

```bash
pip install cisco-aidefense-google-adk
```

## Quick Start (one-liner)

The fastest way to add AI Defense to any ADK agent:

```python
from aidefense_google_adk import defend

# Defend an agent (attaches all 4 callbacks automatically)
agent = defend(agent, mode="enforce")

# Or get a plugin for the App
plugin = defend(mode="enforce")
app = App(name="my_app", root_agent=agent, plugins=[plugin])
```

Set the `AI_DEFENSE_API_KEY` environment variable (and `AI_DEFENSE_MCP_API_KEY` for tool inspection) and you're done.

### Environment Variables

| Variable | Used by | Description |
|----------|---------|-------------|
| `AI_DEFENSE_API_KEY` | Raw client (LLM) | API key for prompt/response inspection |
| `AI_DEFENSE_MCP_API_KEY` | Raw client (MCP) | API key for tool call inspection |
| `AI_DEFENSE_RUNTIME_URL` | Raw client | Custom runtime endpoint URL |
| `AI_DEFENSE_MODE` | Raw client | Default mode (`monitor` / `enforce` / `off`) |
| `AI_DEFENSE_API_MODE_LLM_API_KEY` | Inspector (LLM) | API key for LLM inspection via agentsec |
| `AI_DEFENSE_API_MODE_MCP_API_KEY` | Inspector (MCP) | API key for MCP inspection via agentsec |
| `AI_DEFENSE_API_MODE_LLM_ENDPOINT` | Inspector (LLM) | Endpoint for LLM inspection |
| `AI_DEFENSE_API_MODE_MCP_ENDPOINT` | Inspector (MCP) | Endpoint for MCP inspection |

To see inspection logs without configuring Python logging:

```python
from aidefense_google_adk import configure_logging
configure_logging()
```

### Plugin (Tier 2) — Global, applies to all agents

```python
import os
from google.adk.agents import LlmAgent
from google.adk.apps import App
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService

from aidefense_google_adk import CiscoAIDefensePlugin

agent = LlmAgent(model="gemini-2.5-flash", name="assistant", instruction="...")

# API key auto-resolves from AI_DEFENSE_API_KEY env var
app = App(
    name="my_app",
    root_agent=agent,
    plugins=[
        CiscoAIDefensePlugin(mode="enforce"),
    ],
)
runner = Runner(app=app, session_service=InMemorySessionService())
```

### Agent Callbacks (Tier 1) — Per-agent

```python
from aidefense_google_adk import make_aidefense_callbacks

# API key auto-resolves from AI_DEFENSE_API_KEY env var
cbs = make_aidefense_callbacks(mode="enforce")

agent = LlmAgent(model="gemini-2.5-flash", name="assistant", instruction="...")
cbs.apply_to(agent)  # wires all 4 callbacks in one call
```

## Modes

| Mode | Behavior |
|------|----------|
| `monitor` | Inspect all traffic, log violations, never block (default) |
| `enforce` | Inspect all traffic, block requests/responses that violate policy |
| `off` | Skip inspection entirely |

Modes can be set globally or per-channel:

```python
CiscoAIDefensePlugin(
    mode="monitor",          # default for both
    llm_mode="enforce",      # override for LLM only
    mcp_mode="off",          # override for tools only
)
```

## Callbacks Covered

| ADK Callback | Raw Client | Inspector | What it inspects |
|---|---|---|---|
| `before_model_callback` | `ChatInspectionClient.inspect_prompt()` | `LLMInspector.ainspect_conversation()` | User prompt before LLM call |
| `after_model_callback` | `ChatInspectionClient.inspect_response()` | `LLMInspector.ainspect_conversation()` | LLM response after generation |
| `before_tool_callback` | `MCPInspectionClient.inspect()` | `MCPInspector.ainspect_request()` | Tool call request before execution |
| `after_tool_callback` | `MCPInspectionClient.inspect()` | `MCPInspector.ainspect_response()` | Tool call result after execution |

## Violation Callback

Receive notification of every violation regardless of mode:

```python
def handle_violation(result):
    print(f"Violation: {result.action} / {result.severity}")

CiscoAIDefensePlugin(
    mode="monitor",
    on_violation=handle_violation,
)
```

## Enforced Tool Block Payloads

In `enforce` mode, blocked tool callbacks keep the legacy `error` field and
also return structured metadata when Cisco AI Defense provides it:

```python
{
    "error": "Tool response from 'query_database' blocked by Cisco AI Defense policy.",
    "blocked": True,
    "action": "Block",
    "stage": "tool_response",
    "severity": "HIGH",
    "classifications": ["PRIVACY_VIOLATION"],
    "rules": [{"rule_name": "PII", "classification": "PRIVACY_VIOLATION"}],
    "event_id": "...",
    "request_id": "...",
}
```

This makes it easier to audit or render enforced tool decisions without
reconstructing the decision from logs.

## Inspector-based Integration (agentsec)

In addition to the raw-client modules above, this package provides
**Inspector-based** variants that use `LLMInspector` / `MCPInspector` from
the agentsec SDK layer. These add:

- Automatic retry with exponential backoff
- Fail-open / fail-closed semantics
- Structured `Decision` objects with severity, classifications, rules, and event IDs
- Auto-resolution of API keys and endpoints from environment variables

### AgentsecPlugin (Tier 2) — Global, applies to all agents

```python
from aidefense_google_adk import AgentsecPlugin

# API key auto-resolves from AI_DEFENSE_API_MODE_LLM_API_KEY env var
app = App(
    name="my_app",
    root_agent=agent,
    plugins=[
        AgentsecPlugin(
            mode="enforce",
            fail_open=True,
            retry_total=3,
            retry_backoff=0.5,
        ),
    ],
)
runner = Runner(app=app, session_service=InMemorySessionService())
```

### Agentsec Callbacks (Tier 1) — Per-agent

```python
from aidefense_google_adk import make_agentsec_callbacks

# API key auto-resolves from AI_DEFENSE_API_MODE_LLM_API_KEY env var
cbs = make_agentsec_callbacks(
    mode="enforce",
    fail_open=True,
)

agent = LlmAgent(
    model="gemini-2.5-flash",
    name="assistant",
    instruction="...",
    before_model_callback=cbs.before_model,
    after_model_callback=cbs.after_model,
    before_tool_callback=cbs.before_tool,
    after_tool_callback=cbs.after_tool,
)
```

### Violation Callback with Decision Objects

The Inspector-based modules pass `Decision` objects (not raw `InspectResponse`)
to the `on_violation` callback:

```python
def handle_violation(decision):
    print(f"Action: {decision.action}")
    print(f"Severity: {decision.severity}")
    print(f"Classifications: {decision.classifications}")
    print(f"Rules: {decision.rules}")
    print(f"Event ID: {decision.event_id}")

AgentsecPlugin(
    mode="monitor",
    on_violation=handle_violation,
)
```

### Which Approach Should I Use?

| Feature | Raw Client (`CiscoAIDefensePlugin`) | Inspector (`AgentsecPlugin`) |
|---------|-------------------------------------|------------------------------|
| Retry with backoff | Via `Config(retry_config={...})` (HTTP-level) | Built-in application-level (`retry_total`, `retry_backoff`) |
| Fail-open / fail-closed | Configurable via `fail_open` param | Configurable via `fail_open` param |
| Violation data | `InspectResponse` (`.is_safe`, `.action`, `.severity`, `.classifications`, `.rules`, `.event_id`) | `Decision` (`.allows()`, `.severity`, `.classifications`, `.rules`, `.event_id`) |
| API key resolution | `AI_DEFENSE_API_KEY` (LLM) + `AI_DEFENSE_MCP_API_KEY` (MCP) | `AI_DEFENSE_API_MODE_LLM_API_KEY` + `AI_DEFENSE_API_MODE_MCP_API_KEY` |
| Custom endpoint | Via `Config` object (full HTTP/TLS/pool control) | Via `endpoint` string param |
| Best for | Full control over HTTP config (TLS, pool, headers) | Simpler API with application-level retry |

## Additional agentsec Approaches

### Monkey-patching with `agentsec.protect()`

Two lines of code before importing ADK — all LLM and MCP calls are
transparently inspected:

```python
from aidefense.runtime import agentsec

agentsec.protect(
    api_mode={
        "llm": {"mode": "monitor"},
        "mcp": {"mode": "monitor"},
    },
)

# Now import and use ADK as usual — calls are already patched
from google.adk.agents import LlmAgent
```

See [`examples/agentsec_protect.py`](examples/agentsec_protect.py) for a
complete runnable example.

### Manual Inspector Wiring

Wire the agentsec inspectors into ADK's per-agent callback hooks directly
for maximum customization:

```python
from aidefense.runtime.agentsec.inspectors import LLMInspector, MCPInspector

llm_inspector = LLMInspector()
mcp_inspector = MCPInspector()

async def before_model_callback(*, callback_context, llm_request):
    decision = await llm_inspector.ainspect_conversation(messages, metadata)
    if not decision.allows():
        return blocked_response(decision.reasons)
    return None

agent = LlmAgent(
    model="gemini-2.5-flash",
    name="assistant",
    instruction="...",
    before_model_callback=before_model_callback,
    # ... other callbacks
)
```

See [`examples/agentsec_callbacks.py`](examples/agentsec_callbacks.py) for a
complete runnable example.

### Running the agentsec Examples

```bash
pip install cisco-aidefense-google-adk[examples]
cd examples
cp .env.example .env    # fill in your API keys
python agentsec_plugin.py              # AgentsecPlugin (Tier 2)
python agentsec_plugin.py --callbacks  # make_agentsec_callbacks (Tier 1)
python agentsec_protect.py             # monkey-patching approach
python agentsec_callbacks.py           # manual Inspector wiring
```

## Resources

- [GitHub Repository](https://github.com/cisco-ai-defense/ai-defense-google-adk)
- [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html)
- [Google ADK Documentation](https://google.github.io/adk-docs/)
- [cisco-aidefense-sdk on PyPI](https://pypi.org/project/cisco-aidefense-sdk/)

## Development

```bash
pip install -e ".[dev]"
pytest
```

## License

Distributed under the `Apache 2.0` License. See [LICENSE](https://github.com/cisco-ai-defense/ai-defense-google-adk/tree/main/LICENSE) for more information.

