agent-control-evaluator-cisco 7.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,90 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+
24
+ # Virtual environments
25
+ venv/
26
+ env/
27
+ ENV/
28
+ .venv
29
+
30
+ # UV
31
+ .uv/
32
+ uv.lock
33
+
34
+ # IDEs
35
+ .vscode/
36
+ .idea/
37
+ *.swp
38
+ *.swo
39
+ *~
40
+ .DS_Store
41
+ coverage-*.xml
42
+
43
+ # Testing
44
+ .pytest_cache/
45
+ .coverage
46
+ coverage-*.xml
47
+ htmlcov/
48
+ .tox/
49
+ .mypy_cache/
50
+ .ruff_cache/
51
+
52
+ # Playwright
53
+ playwright-report/
54
+ playwright/.cache/
55
+ test-results/
56
+
57
+ # Environment variables
58
+ .env
59
+ .env.local
60
+ .env.*.local
61
+
62
+ # Logs
63
+ *.log
64
+ logs/
65
+
66
+ # Database
67
+ *.db
68
+ *.sqlite3
69
+ server/openapi.json
70
+ server/.generated/
71
+
72
+ # Temporary files
73
+ tmp/
74
+ temp/
75
+ *.tmp
76
+
77
+ # OS
78
+ .DS_Store
79
+ Thumbs.db
80
+
81
+ # Intellij
82
+ *.iml
83
+
84
+ ## CLAUDE
85
+ .claude
86
+
87
+ # Local notes
88
+ rearch_plan.md
89
+
90
+ node_modules
@@ -0,0 +1,29 @@
1
+ .PHONY: help test lint lint-fix typecheck check build
2
+
3
+ PACKAGE := agent-control-evaluator-cisco
4
+
5
+ help:
6
+ @echo "Agent Control Evaluator - Cisco AI Defense - Makefile commands"
7
+ @echo " make test - run pytest"
8
+ @echo " make lint - run ruff check"
9
+ @echo " make lint-fix - run ruff check --fix"
10
+ @echo " make typecheck - run mypy"
11
+ @echo " make check - run test, lint, and typecheck"
12
+ @echo " make build - build package"
13
+
14
+ test:
15
+ uv run --with pytest --with pytest-asyncio --with pytest-cov --package $(PACKAGE) pytest tests --cov=src --cov-report=xml:../../../coverage-evaluators-cisco.xml -q
16
+
17
+ lint:
18
+ uv run --with ruff --package $(PACKAGE) ruff check --config ../../../pyproject.toml src/
19
+
20
+ lint-fix:
21
+ uv run --with ruff --package $(PACKAGE) ruff check --config ../../../pyproject.toml --fix src/
22
+
23
+ typecheck:
24
+ uv run --with mypy --package $(PACKAGE) mypy --config-file ../../../pyproject.toml src/
25
+
26
+ check: test lint typecheck
27
+
28
+ build:
29
+ uv build
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-control-evaluator-cisco
3
+ Version: 7.7.0
4
+ Summary: Cisco AI Defense evaluator for agent-control
5
+ Author: Cisco AI Defense Team
6
+ License: Apache-2.0
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: agent-control-evaluators>=7.7.0
9
+ Requires-Dist: agent-control-models>=7.7.0
10
+ Requires-Dist: httpx>=0.24.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
13
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
14
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
15
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
16
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Agent Control Evaluator - Cisco AI Defense
20
+
21
+ External evaluator that calls Cisco AI Defense Chat Inspection via REST and maps `InspectResponse.is_safe` to Agent Control decisions.
22
+
23
+ - Entry point name: `cisco.ai_defense`
24
+ - Transport: direct HTTP (httpx)
25
+
26
+ ## Installation
27
+
28
+ Canonical install path:
29
+
30
+ ```bash
31
+ pip install "agent-control-evaluators[cisco]"
32
+ ```
33
+
34
+ Fallback direct wheel install:
35
+
36
+ ```bash
37
+ pip install agent-control-evaluator-cisco
38
+ ```
39
+
40
+ For local development:
41
+
42
+ ```bash
43
+ uv pip install -e evaluators/contrib/cisco
44
+ ```
45
+
46
+ - Build wheel from the repo root (contrib package only):
47
+
48
+ ```bash
49
+ make engine-build
50
+ (cd evaluators/contrib/cisco && make build)
51
+ ```
52
+
53
+ To run the server with this evaluator enabled, see `examples/cisco_ai_defense/README.md` for setup and seeding instructions.
54
+
55
+ ## Configuration
56
+
57
+ Set the `AI_DEFENSE_API_KEY` environment variable:
58
+
59
+ ```bash
60
+ export AI_DEFENSE_API_KEY="<your_key>"
61
+ ```
62
+
63
+ Evaluator config fields (all optional unless stated):
64
+
65
+ - `api_key_env: str = "AI_DEFENSE_API_KEY"`
66
+ - `region: "us" | "ap" | "eu" | None = "us"` (ignored if `api_url` set)
67
+ - `api_url: str | None = None` (full endpoint override; e.g., `https://us.../api/v1/inspect/chat`)
68
+ - `timeout_ms: int = 15000`
69
+ - `on_error: "allow" | "deny" = "allow"` (fail-open or fail-closed on transport/response errors)
70
+ - `payload_field: "input" | "output" | None = None`
71
+ - When set, synthesizes a single message from that field; `input` → `role=user`, `output` → `role=assistant`.
72
+ - `messages_strategy: "single" | "history" = "history"`
73
+ - `history` forwards an existing `messages` list in the selected data if present; falls back to single otherwise.
74
+ - `metadata: dict[str, Any] | None = None` (forwarded to API per OpenAPI spec)
75
+ - `inspect_config: dict[str, Any] | None = None` (forwarded to API per OpenAPI spec)
76
+ - `include_raw_response: bool = false` (when true, includes the full provider response under `metadata.raw`)
77
+
78
+ ## Available Evaluators
79
+
80
+ | Name | Description |
81
+ |------|-------------|
82
+ | `cisco.ai_defense` | Cisco AI Defense Chat Inspection |
83
+
84
+ Behavior mapping:
85
+
86
+ - `is_safe == false` → `EvaluatorResult.matched = true` (e.g., a `deny` action will block)
87
+ - `is_safe == true` → `matched = false`
88
+ - Errors or invalid responses → `matched = (on_error == "deny")`; error details in `metadata` (no `error` field is set; engine honors `matched` per `on_error`)
89
+
90
+ ## Minimal server control configuration
91
+
92
+ Example using `messages_strategy: "history"` (for inputs that already have a `messages` list):
93
+
94
+ ```
95
+ {
96
+ "description": "Apply Cisco AI Defense Security, Safety, and Privacy guardrails",
97
+ "enabled": true,
98
+ "execution": "server",
99
+ "scope": { "step_types": ["llm"], "stages": ["pre", "post"] },
100
+ "condition": {
101
+ "selector": { "path": "input" },
102
+ "evaluator": {
103
+ "name": "cisco.ai_defense",
104
+ "config": {
105
+ "api_key_env": "AI_DEFENSE_API_KEY",
106
+ "region": "us",
107
+ "timeout_ms": 15000,
108
+ "on_error": "allow",
109
+ "messages_strategy": "history"
110
+ }
111
+ }
112
+ },
113
+ "action": { "decision": "deny" },
114
+ "tags": ["ai_defense", "safety"]
115
+ }
116
+ ```
117
+
118
+ ```
119
+ {
120
+ "description": "Apply Cisco AI Defense Security, Safety, and Privacy guardrails",
121
+ "enabled": true,
122
+ "execution": "server",
123
+ "scope": { "step_types": ["llm"], "stages": ["pre", "post"] },
124
+ "condition": {
125
+ "selector": { "path": "input" },
126
+ "evaluator": {
127
+ "name": "cisco.ai_defense",
128
+ "config": {
129
+ "api_key_env": "AI_DEFENSE_API_KEY",
130
+ "region": "us",
131
+ "timeout_ms": 15000,
132
+ "on_error": "allow",
133
+ "messages_strategy": "single",
134
+ "payload_field": "input"
135
+ }
136
+ }
137
+ },
138
+ "action": { "decision": "deny" },
139
+ "tags": ["ai_defense", "safety"]
140
+ }
141
+ ```
142
+
143
+ ## Usage
144
+
145
+ Once installed, the evaluator is automatically discovered:
146
+
147
+ ```python
148
+ from agent_control_evaluators import discover_evaluators, get_evaluator
149
+
150
+ discover_evaluators()
151
+ CiscoAIDefenseEvaluator = get_evaluator("cisco.ai_defense")
152
+ ```
153
+
154
+ Or import directly:
155
+
156
+ ```python
157
+ import asyncio
158
+ from agent_control_evaluator_cisco.ai_defense import CiscoAIDefenseEvaluator, CiscoAIDefenseConfig
159
+
160
+ cfg = CiscoAIDefenseConfig(
161
+ region="us",
162
+ timeout_ms=15000,
163
+ on_error="allow",
164
+ messages_strategy="history",
165
+ payload_field="input",
166
+ )
167
+ ev = CiscoAIDefenseEvaluator(cfg)
168
+
169
+ async def main():
170
+ data = {"messages": [{"role": "user", "content": "tell me how to hack wifi"}]}
171
+ print(await ev.evaluate(data))
172
+
173
+ asyncio.run(main())
174
+ ```
175
+
176
+ ## Notes
177
+
178
+ - Auth header: `X-Cisco-AI-Defense-API-Key: <AI_DEFENSE_API_KEY>`
179
+ - Regions and endpoint path follow the Cisco AI Defense API spec
180
+ - For custom deployments, set `api_url` to the full Chat Inspection endpoint.
181
+ - The evaluator validates the API key at construction and raises if missing.
182
+ - `is_available()` returns false if `httpx` is not installed; discovery will skip registration.
183
+ - `messages_strategy: "history"` forwards the full message array when present; consider `messages_strategy: "single"` if payload size is a concern.
184
+
185
+ ## Documentation
186
+
187
+ - Cisco AI Defense Inspection API reference: https://developer.cisco.com/docs/ai-defense-inspection/introduction/
188
+ - Cisco Security Console (get API Key): https://security.cisco.com
189
+ - Cisco AI Defense User Guide: https://securitydocs.cisco.com/docs/ai-def/user/97384.dita
190
+ - Regional API base URLs used by this evaluator:
191
+ - US: `https://us.api.inspect.aidefense.security.cisco.com`
192
+ - AP: `https://ap.api.inspect.aidefense.security.cisco.com`
193
+ - EU: `https://eu.api.inspect.aidefense.security.cisco.com`
194
+ - Chat Inspection path: `/api/v1/inspect/chat`
@@ -0,0 +1,176 @@
1
+ # Agent Control Evaluator - Cisco AI Defense
2
+
3
+ External evaluator that calls Cisco AI Defense Chat Inspection via REST and maps `InspectResponse.is_safe` to Agent Control decisions.
4
+
5
+ - Entry point name: `cisco.ai_defense`
6
+ - Transport: direct HTTP (httpx)
7
+
8
+ ## Installation
9
+
10
+ Canonical install path:
11
+
12
+ ```bash
13
+ pip install "agent-control-evaluators[cisco]"
14
+ ```
15
+
16
+ Fallback direct wheel install:
17
+
18
+ ```bash
19
+ pip install agent-control-evaluator-cisco
20
+ ```
21
+
22
+ For local development:
23
+
24
+ ```bash
25
+ uv pip install -e evaluators/contrib/cisco
26
+ ```
27
+
28
+ - Build wheel from the repo root (contrib package only):
29
+
30
+ ```bash
31
+ make engine-build
32
+ (cd evaluators/contrib/cisco && make build)
33
+ ```
34
+
35
+ To run the server with this evaluator enabled, see `examples/cisco_ai_defense/README.md` for setup and seeding instructions.
36
+
37
+ ## Configuration
38
+
39
+ Set the `AI_DEFENSE_API_KEY` environment variable:
40
+
41
+ ```bash
42
+ export AI_DEFENSE_API_KEY="<your_key>"
43
+ ```
44
+
45
+ Evaluator config fields (all optional unless stated):
46
+
47
+ - `api_key_env: str = "AI_DEFENSE_API_KEY"`
48
+ - `region: "us" | "ap" | "eu" | None = "us"` (ignored if `api_url` set)
49
+ - `api_url: str | None = None` (full endpoint override; e.g., `https://us.../api/v1/inspect/chat`)
50
+ - `timeout_ms: int = 15000`
51
+ - `on_error: "allow" | "deny" = "allow"` (fail-open or fail-closed on transport/response errors)
52
+ - `payload_field: "input" | "output" | None = None`
53
+ - When set, synthesizes a single message from that field; `input` → `role=user`, `output` → `role=assistant`.
54
+ - `messages_strategy: "single" | "history" = "history"`
55
+ - `history` forwards an existing `messages` list in the selected data if present; falls back to single otherwise.
56
+ - `metadata: dict[str, Any] | None = None` (forwarded to API per OpenAPI spec)
57
+ - `inspect_config: dict[str, Any] | None = None` (forwarded to API per OpenAPI spec)
58
+ - `include_raw_response: bool = false` (when true, includes the full provider response under `metadata.raw`)
59
+
60
+ ## Available Evaluators
61
+
62
+ | Name | Description |
63
+ |------|-------------|
64
+ | `cisco.ai_defense` | Cisco AI Defense Chat Inspection |
65
+
66
+ Behavior mapping:
67
+
68
+ - `is_safe == false` → `EvaluatorResult.matched = true` (e.g., a `deny` action will block)
69
+ - `is_safe == true` → `matched = false`
70
+ - Errors or invalid responses → `matched = (on_error == "deny")`; error details in `metadata` (no `error` field is set; engine honors `matched` per `on_error`)
71
+
72
+ ## Minimal server control configuration
73
+
74
+ Example using `messages_strategy: "history"` (for inputs that already have a `messages` list):
75
+
76
+ ```
77
+ {
78
+ "description": "Apply Cisco AI Defense Security, Safety, and Privacy guardrails",
79
+ "enabled": true,
80
+ "execution": "server",
81
+ "scope": { "step_types": ["llm"], "stages": ["pre", "post"] },
82
+ "condition": {
83
+ "selector": { "path": "input" },
84
+ "evaluator": {
85
+ "name": "cisco.ai_defense",
86
+ "config": {
87
+ "api_key_env": "AI_DEFENSE_API_KEY",
88
+ "region": "us",
89
+ "timeout_ms": 15000,
90
+ "on_error": "allow",
91
+ "messages_strategy": "history"
92
+ }
93
+ }
94
+ },
95
+ "action": { "decision": "deny" },
96
+ "tags": ["ai_defense", "safety"]
97
+ }
98
+ ```
99
+
100
+ ```
101
+ {
102
+ "description": "Apply Cisco AI Defense Security, Safety, and Privacy guardrails",
103
+ "enabled": true,
104
+ "execution": "server",
105
+ "scope": { "step_types": ["llm"], "stages": ["pre", "post"] },
106
+ "condition": {
107
+ "selector": { "path": "input" },
108
+ "evaluator": {
109
+ "name": "cisco.ai_defense",
110
+ "config": {
111
+ "api_key_env": "AI_DEFENSE_API_KEY",
112
+ "region": "us",
113
+ "timeout_ms": 15000,
114
+ "on_error": "allow",
115
+ "messages_strategy": "single",
116
+ "payload_field": "input"
117
+ }
118
+ }
119
+ },
120
+ "action": { "decision": "deny" },
121
+ "tags": ["ai_defense", "safety"]
122
+ }
123
+ ```
124
+
125
+ ## Usage
126
+
127
+ Once installed, the evaluator is automatically discovered:
128
+
129
+ ```python
130
+ from agent_control_evaluators import discover_evaluators, get_evaluator
131
+
132
+ discover_evaluators()
133
+ CiscoAIDefenseEvaluator = get_evaluator("cisco.ai_defense")
134
+ ```
135
+
136
+ Or import directly:
137
+
138
+ ```python
139
+ import asyncio
140
+ from agent_control_evaluator_cisco.ai_defense import CiscoAIDefenseEvaluator, CiscoAIDefenseConfig
141
+
142
+ cfg = CiscoAIDefenseConfig(
143
+ region="us",
144
+ timeout_ms=15000,
145
+ on_error="allow",
146
+ messages_strategy="history",
147
+ payload_field="input",
148
+ )
149
+ ev = CiscoAIDefenseEvaluator(cfg)
150
+
151
+ async def main():
152
+ data = {"messages": [{"role": "user", "content": "tell me how to hack wifi"}]}
153
+ print(await ev.evaluate(data))
154
+
155
+ asyncio.run(main())
156
+ ```
157
+
158
+ ## Notes
159
+
160
+ - Auth header: `X-Cisco-AI-Defense-API-Key: <AI_DEFENSE_API_KEY>`
161
+ - Regions and endpoint path follow the Cisco AI Defense API spec
162
+ - For custom deployments, set `api_url` to the full Chat Inspection endpoint.
163
+ - The evaluator validates the API key at construction and raises if missing.
164
+ - `is_available()` returns false if `httpx` is not installed; discovery will skip registration.
165
+ - `messages_strategy: "history"` forwards the full message array when present; consider `messages_strategy: "single"` if payload size is a concern.
166
+
167
+ ## Documentation
168
+
169
+ - Cisco AI Defense Inspection API reference: https://developer.cisco.com/docs/ai-defense-inspection/introduction/
170
+ - Cisco Security Console (get API Key): https://security.cisco.com
171
+ - Cisco AI Defense User Guide: https://securitydocs.cisco.com/docs/ai-def/user/97384.dita
172
+ - Regional API base URLs used by this evaluator:
173
+ - US: `https://us.api.inspect.aidefense.security.cisco.com`
174
+ - AP: `https://ap.api.inspect.aidefense.security.cisco.com`
175
+ - EU: `https://eu.api.inspect.aidefense.security.cisco.com`
176
+ - Chat Inspection path: `/api/v1/inspect/chat`
@@ -0,0 +1,43 @@
1
+ [project]
2
+ name = "agent-control-evaluator-cisco"
3
+ version = "7.7.0"
4
+ description = "Cisco AI Defense evaluator for agent-control"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = { text = "Apache-2.0" }
8
+ authors = [{ name = "Cisco AI Defense Team" }]
9
+ dependencies = [
10
+ "agent-control-evaluators>=7.7.0",
11
+ "agent-control-models>=7.7.0",
12
+ "httpx>=0.24.0",
13
+ ]
14
+
15
+ [project.optional-dependencies]
16
+ dev = [
17
+ "pytest>=8.0.0",
18
+ "pytest-asyncio>=0.23.0",
19
+ "pytest-cov>=4.0.0",
20
+ "ruff>=0.1.0",
21
+ "mypy>=1.8.0",
22
+ ]
23
+
24
+ [project.entry-points."agent_control.evaluators"]
25
+ "cisco.ai_defense" = "agent_control_evaluator_cisco.ai_defense:CiscoAIDefenseEvaluator"
26
+
27
+ [build-system]
28
+ requires = ["hatchling"]
29
+ build-backend = "hatchling.build"
30
+
31
+ [tool.hatch.build.targets.wheel]
32
+ packages = ["src/agent_control_evaluator_cisco"]
33
+
34
+ [tool.ruff]
35
+ line-length = 100
36
+ target-version = "py312"
37
+
38
+ [tool.ruff.lint]
39
+ select = ["E", "F", "I"]
40
+
41
+ [tool.uv.sources]
42
+ agent-control-evaluators = { path = "../../builtin", editable = true }
43
+ agent-control-models = { path = "../../../models", editable = true }
@@ -0,0 +1,5 @@
1
+ from .config import CiscoAIDefenseConfig
2
+ from .evaluator import CiscoAIDefenseEvaluator
3
+
4
+ __all__ = ["CiscoAIDefenseEvaluator", "CiscoAIDefenseConfig"]
5
+
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ # Thin REST client for Cisco AI Defense Chat Inspection.
4
+ # Uses httpx.AsyncClient and the OpenAPI-defined endpoint/header.
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ try:
9
+ import httpx
10
+
11
+ AI_DEFENSE_HTTPX_AVAILABLE = True
12
+ except ImportError: # Narrow to import error only
13
+ httpx = None # type: ignore
14
+ AI_DEFENSE_HTTPX_AVAILABLE = False
15
+
16
+
17
+ # Regions from ai_defense_api.json "servers" section
18
+ REGION_BASE_URLS: dict[str, str] = {
19
+ "us": "https://us.api.inspect.aidefense.security.cisco.com",
20
+ "ap": "https://ap.api.inspect.aidefense.security.cisco.com",
21
+ "eu": "https://eu.api.inspect.aidefense.security.cisco.com",
22
+ }
23
+
24
+
25
+ def build_endpoint(base_url: str) -> str:
26
+ base = base_url.rstrip("/")
27
+ return f"{base}/api/v1/inspect/chat"
28
+
29
+
30
+ @dataclass
31
+ class AIDefenseClient:
32
+ """Minimal async client for Cisco AI Defense Chat Inspection.
33
+
34
+ Attributes:
35
+ api_key: API key used for authentication header
36
+ endpoint_url: Full URL to POST /api/v1/inspect/chat
37
+ timeout_s: Timeout in seconds
38
+ """
39
+
40
+ api_key: str = field(repr=False)
41
+ endpoint_url: str
42
+ timeout_s: float
43
+
44
+ _client: httpx.AsyncClient | None = field( # type: ignore[name-defined]
45
+ default=None,
46
+ repr=False,
47
+ compare=False,
48
+ )
49
+
50
+ async def _get_client(self) -> httpx.AsyncClient: # type: ignore[name-defined]
51
+ if not AI_DEFENSE_HTTPX_AVAILABLE: # pragma: no cover
52
+ raise RuntimeError("httpx not installed; cannot call Cisco AI Defense REST API")
53
+ if self._client is None or self._client.is_closed:
54
+ self._client = httpx.AsyncClient(timeout=self.timeout_s)
55
+ return self._client
56
+
57
+ async def chat_inspect(
58
+ self,
59
+ messages: list[dict[str, str]],
60
+ metadata: dict[str, Any] | None = None,
61
+ inspect_config: dict[str, Any] | None = None,
62
+ headers: dict[str, str] | None = None,
63
+ ) -> dict[str, Any]:
64
+ client = await self._get_client()
65
+
66
+ req_headers: dict[str, str] = {
67
+ "X-Cisco-AI-Defense-API-Key": self.api_key,
68
+ "Content-Type": "application/json",
69
+ "Accept": "application/json",
70
+ }
71
+ if headers:
72
+ req_headers.update(headers)
73
+
74
+ payload: dict[str, Any] = {"messages": messages}
75
+ if metadata is not None:
76
+ payload["metadata"] = metadata
77
+ if inspect_config is not None:
78
+ payload["config"] = inspect_config
79
+
80
+ resp = await client.post(self.endpoint_url, json=payload, headers=req_headers)
81
+ resp.raise_for_status()
82
+ data = resp.json()
83
+ if not isinstance(data, dict):
84
+ raise RuntimeError("Invalid response payload: not a JSON object")
85
+ return data
86
+
87
+ async def aclose(self) -> None:
88
+ if self._client and not self._client.is_closed:
89
+ await self._client.aclose()
90
+
91
+ async def close(self) -> None:
92
+ """Close the HTTP client and release resources."""
93
+ await self.aclose()
94
+
95
+ async def __aenter__(self) -> AIDefenseClient:
96
+ """Async context manager entry."""
97
+ return self
98
+
99
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
100
+ """Async context manager exit."""
101
+ await self.close()
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal
4
+
5
+ from agent_control_evaluators import EvaluatorConfig
6
+ from pydantic import Field
7
+
8
+
9
+ class CiscoAIDefenseConfig(EvaluatorConfig):
10
+ """Configuration for Cisco AI Defense evaluator (REST).
11
+
12
+ Attributes:
13
+ api_key_env: Env var name for API key
14
+ region: Optional server region (us, ap, eu); ignored if api_url set
15
+ api_url: Optional full endpoint override
16
+ timeout_ms: Request timeout (milliseconds)
17
+ on_error: Error policy (allow=fail-open, deny=fail-closed)
18
+ payload_field: Force single-message role: input→user, output→assistant
19
+ messages_strategy: "single" (synthesize) or "history" (pass-through messages)
20
+ metadata: Optional metadata object to include (OpenAPI spec)
21
+ inspect_config: Optional Inspect API config passthrough (see OpenAPI spec)
22
+ """
23
+
24
+ api_key_env: str = "AI_DEFENSE_API_KEY"
25
+ region: Literal["us", "ap", "eu"] | None = "us"
26
+ api_url: str | None = None
27
+ timeout_ms: int = Field(default=15_000, ge=1)
28
+ on_error: Literal["allow", "deny"] = "allow"
29
+ payload_field: Literal["input", "output"] | None = None
30
+ messages_strategy: Literal["single", "history"] = "history"
31
+ metadata: dict[str, Any] | None = None
32
+ inspect_config: dict[str, Any] | None = None
33
+ include_raw_response: bool = False