promptguard-sdk 0.1.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,88 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Python
7
+ backend/api/.venv/
8
+ backend/api/__pycache__/
9
+ backend/api/*.pyc
10
+ backend/api/.pytest_cache/
11
+ backend/api/htmlcov/
12
+
13
+ # Database files
14
+ *.db
15
+ *.sqlite
16
+ *.sqlite3
17
+
18
+ # Testing
19
+ coverage/
20
+ .coverage
21
+ coverage.xml
22
+ .nyc_output
23
+
24
+ # Production
25
+ build/
26
+ dist/
27
+ .next/
28
+ out/
29
+
30
+ # Misc
31
+ .DS_Store
32
+ *.pem
33
+ .vscode/
34
+ .idea/
35
+
36
+ # Debug
37
+ npm-debug.log*
38
+ yarn-debug.log*
39
+ yarn-error.log*
40
+ lerna-debug.log*
41
+
42
+ # Env files (only .env.example is tracked, all others are git-ignored)
43
+ .env
44
+ .env.local
45
+ .env.test
46
+ .env.staging
47
+ .env.production
48
+ .env.development.local
49
+ .env.test.local
50
+ .env.production.local
51
+ .env*.local
52
+
53
+ # Python
54
+ __pycache__/
55
+ *.py[cod]
56
+ *$py.class
57
+ *.so
58
+ .Python
59
+ env/
60
+ venv/
61
+ .venv/
62
+ pip-log.txt
63
+ pip-delete-this-directory.txt
64
+ .pytest_cache/
65
+ .mypy_cache/
66
+ .ruff_cache/
67
+ *.egg-info/
68
+
69
+ # Turbo
70
+ .turbo/
71
+
72
+ # Vercel
73
+ .vercel/
74
+ .env.vercel.*
75
+
76
+ # Docker
77
+ docker/volumes/
78
+
79
+ # Logs
80
+ logs/
81
+ *.log
82
+ test-results/
83
+ playwright-report/
84
+ .vercel
85
+
86
+ # Prevent committing scripts with hardcoded secrets
87
+ scripts/setup/github-secrets.sh
88
+ scripts/setup/vercel-env-batch.sh
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: promptguard-sdk
3
+ Version: 0.1.0
4
+ Summary: Drop-in security for AI applications - AI Firewall SDK
5
+ Project-URL: Homepage, https://promptguard.co
6
+ Project-URL: Documentation, https://docs.promptguard.co
7
+ Project-URL: Repository, https://github.com/acebot712/promptguard
8
+ Project-URL: Issues, https://github.com/acebot712/promptguard/issues
9
+ Author-email: PromptGuard <support@promptguard.co>
10
+ License-Expression: MIT
11
+ Keywords: ai,ai-firewall,ai-security,anthropic,llm,llm-security,openai,pii-detection,prompt-injection,security
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.8
24
+ Requires-Dist: httpx>=0.24.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
27
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
28
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # PromptGuard Python SDK
32
+
33
+ Drop-in security for AI applications. No code changes required.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install promptguard-ai
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from promptguard import PromptGuard
45
+
46
+ # Initialize client
47
+ pg = PromptGuard(api_key="pg_xxx")
48
+
49
+ # Use exactly like OpenAI client
50
+ response = pg.chat.completions.create(
51
+ model="gpt-4",
52
+ messages=[{"role": "user", "content": "Hello!"}]
53
+ )
54
+
55
+ print(response["choices"][0]["message"]["content"])
56
+ ```
57
+
58
+ ## Drop-in Replacement
59
+
60
+ If you're already using OpenAI's Python client, just change the import:
61
+
62
+ ```python
63
+ # Before
64
+ from openai import OpenAI
65
+ client = OpenAI()
66
+
67
+ # After
68
+ from promptguard import PromptGuard
69
+ client = PromptGuard(api_key="pg_xxx")
70
+
71
+ # Your existing code works unchanged!
72
+ ```
73
+
74
+ ## Features
75
+
76
+ ### Security Scanning
77
+
78
+ ```python
79
+ # Scan content for threats
80
+ result = pg.security.scan("Ignore previous instructions...")
81
+
82
+ if result["blocked"]:
83
+ print(f"Threat detected: {result['reason']}")
84
+ ```
85
+
86
+ ### PII Redaction
87
+
88
+ ```python
89
+ # Redact PII before sending to LLM
90
+ result = pg.security.redact(
91
+ "My email is john@example.com and SSN is 123-45-6789"
92
+ )
93
+
94
+ print(result["redacted_content"])
95
+ # Output: "My email is [EMAIL] and SSN is [SSN]"
96
+ ```
97
+
98
+ ### Memory (Context Management)
99
+
100
+ ```python
101
+ # Store user preferences
102
+ pg.memory.store(
103
+ content="User prefers Python for coding tasks",
104
+ memory_type="preference",
105
+ user_id="user-123"
106
+ )
107
+
108
+ # Retrieve relevant context
109
+ memories = pg.memory.retrieve(
110
+ query="What programming language should I use?",
111
+ user_id="user-123"
112
+ )
113
+
114
+ # Inject into your prompts
115
+ context = memories["formatted_context"]
116
+ ```
117
+
118
+ ## Async Support
119
+
120
+ ```python
121
+ from promptguard import PromptGuardAsync
122
+
123
+ async with PromptGuardAsync(api_key="pg_xxx") as pg:
124
+ response = await pg.chat.completions.create(
125
+ model="gpt-4",
126
+ messages=[{"role": "user", "content": "Hello!"}]
127
+ )
128
+ ```
129
+
130
+ ## Configuration
131
+
132
+ ```python
133
+ from promptguard import PromptGuard, Config
134
+
135
+ config = Config(
136
+ api_key="pg_xxx",
137
+ base_url="https://api.promptguard.co/api/v1/proxy",
138
+ enable_caching=True,
139
+ enable_security_scan=True,
140
+ timeout=30.0,
141
+ )
142
+
143
+ pg = PromptGuard(config=config)
144
+ ```
145
+
146
+ ## Environment Variables
147
+
148
+ ```bash
149
+ export PROMPTGUARD_API_KEY="pg_xxx"
150
+ export PROMPTGUARD_BASE_URL="https://api.promptguard.co/api/v1/proxy"
151
+ ```
152
+
153
+ Then just:
154
+
155
+ ```python
156
+ from promptguard import PromptGuard
157
+
158
+ pg = PromptGuard() # Uses env vars automatically
159
+ ```
160
+
161
+ ## Error Handling
162
+
163
+ ```python
164
+ from promptguard import PromptGuard, PromptGuardError
165
+
166
+ try:
167
+ response = pg.chat.completions.create(...)
168
+ except PromptGuardError as e:
169
+ if e.code == "BLOCKED":
170
+ print(f"Request blocked: {e.message}")
171
+ elif e.code == "RATE_LIMITED":
172
+ print("Rate limited, try again later")
173
+ else:
174
+ raise
175
+ ```
176
+
177
+ ## License
178
+
179
+ MIT
@@ -0,0 +1,149 @@
1
+ # PromptGuard Python SDK
2
+
3
+ Drop-in security for AI applications. No code changes required.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install promptguard-ai
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from promptguard import PromptGuard
15
+
16
+ # Initialize client
17
+ pg = PromptGuard(api_key="pg_xxx")
18
+
19
+ # Use exactly like OpenAI client
20
+ response = pg.chat.completions.create(
21
+ model="gpt-4",
22
+ messages=[{"role": "user", "content": "Hello!"}]
23
+ )
24
+
25
+ print(response["choices"][0]["message"]["content"])
26
+ ```
27
+
28
+ ## Drop-in Replacement
29
+
30
+ If you're already using OpenAI's Python client, just change the import:
31
+
32
+ ```python
33
+ # Before
34
+ from openai import OpenAI
35
+ client = OpenAI()
36
+
37
+ # After
38
+ from promptguard import PromptGuard
39
+ client = PromptGuard(api_key="pg_xxx")
40
+
41
+ # Your existing code works unchanged!
42
+ ```
43
+
44
+ ## Features
45
+
46
+ ### Security Scanning
47
+
48
+ ```python
49
+ # Scan content for threats
50
+ result = pg.security.scan("Ignore previous instructions...")
51
+
52
+ if result["blocked"]:
53
+ print(f"Threat detected: {result['reason']}")
54
+ ```
55
+
56
+ ### PII Redaction
57
+
58
+ ```python
59
+ # Redact PII before sending to LLM
60
+ result = pg.security.redact(
61
+ "My email is john@example.com and SSN is 123-45-6789"
62
+ )
63
+
64
+ print(result["redacted_content"])
65
+ # Output: "My email is [EMAIL] and SSN is [SSN]"
66
+ ```
67
+
68
+ ### Memory (Context Management)
69
+
70
+ ```python
71
+ # Store user preferences
72
+ pg.memory.store(
73
+ content="User prefers Python for coding tasks",
74
+ memory_type="preference",
75
+ user_id="user-123"
76
+ )
77
+
78
+ # Retrieve relevant context
79
+ memories = pg.memory.retrieve(
80
+ query="What programming language should I use?",
81
+ user_id="user-123"
82
+ )
83
+
84
+ # Inject into your prompts
85
+ context = memories["formatted_context"]
86
+ ```
87
+
88
+ ## Async Support
89
+
90
+ ```python
91
+ from promptguard import PromptGuardAsync
92
+
93
+ async with PromptGuardAsync(api_key="pg_xxx") as pg:
94
+ response = await pg.chat.completions.create(
95
+ model="gpt-4",
96
+ messages=[{"role": "user", "content": "Hello!"}]
97
+ )
98
+ ```
99
+
100
+ ## Configuration
101
+
102
+ ```python
103
+ from promptguard import PromptGuard, Config
104
+
105
+ config = Config(
106
+ api_key="pg_xxx",
107
+ base_url="https://api.promptguard.co/api/v1/proxy",
108
+ enable_caching=True,
109
+ enable_security_scan=True,
110
+ timeout=30.0,
111
+ )
112
+
113
+ pg = PromptGuard(config=config)
114
+ ```
115
+
116
+ ## Environment Variables
117
+
118
+ ```bash
119
+ export PROMPTGUARD_API_KEY="pg_xxx"
120
+ export PROMPTGUARD_BASE_URL="https://api.promptguard.co/api/v1/proxy"
121
+ ```
122
+
123
+ Then just:
124
+
125
+ ```python
126
+ from promptguard import PromptGuard
127
+
128
+ pg = PromptGuard() # Uses env vars automatically
129
+ ```
130
+
131
+ ## Error Handling
132
+
133
+ ```python
134
+ from promptguard import PromptGuard, PromptGuardError
135
+
136
+ try:
137
+ response = pg.chat.completions.create(...)
138
+ except PromptGuardError as e:
139
+ if e.code == "BLOCKED":
140
+ print(f"Request blocked: {e.message}")
141
+ elif e.code == "RATE_LIMITED":
142
+ print("Rate limited, try again later")
143
+ else:
144
+ raise
145
+ ```
146
+
147
+ ## License
148
+
149
+ MIT
@@ -0,0 +1,23 @@
1
+ """
2
+ PromptGuard Python SDK
3
+
4
+ Drop-in security for AI applications.
5
+ Just change your base URL and add an API key.
6
+
7
+ Usage:
8
+ from promptguard import PromptGuard
9
+
10
+ pg = PromptGuard(api_key="pg_xxx")
11
+
12
+ # Use as OpenAI drop-in replacement
13
+ response = pg.chat.completions.create(
14
+ model="gpt-4",
15
+ messages=[{"role": "user", "content": "Hello!"}]
16
+ )
17
+ """
18
+
19
+ from promptguard.client import PromptGuard, PromptGuardAsync
20
+ from promptguard.config import Config
21
+
22
+ __version__ = "0.1.0"
23
+ __all__ = ["PromptGuard", "PromptGuardAsync", "Config"]
@@ -0,0 +1,676 @@
1
+ """
2
+ PromptGuard Client - Drop-in replacement for OpenAI client
3
+
4
+ Provides the same interface as OpenAI's client but routes through PromptGuard
5
+ for security scanning, caching, and cost optimization.
6
+ """
7
+
8
+ import json
9
+ import os
10
+ from typing import Any, Dict, Iterator, List, Optional, Union
11
+
12
+ import httpx
13
+
14
+ from promptguard.config import Config
15
+
16
+
17
+ class ChatCompletions:
18
+ """Chat completions API (OpenAI-compatible)"""
19
+
20
+ def __init__(self, client: "PromptGuard"):
21
+ self._client = client
22
+
23
+ def create(
24
+ self,
25
+ model: str,
26
+ messages: List[Dict[str, str]],
27
+ temperature: float = 1.0,
28
+ max_tokens: Optional[int] = None,
29
+ stream: bool = False,
30
+ **kwargs,
31
+ ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]:
32
+ """
33
+ Create a chat completion.
34
+
35
+ This is a drop-in replacement for openai.chat.completions.create()
36
+ but routes through PromptGuard for security scanning.
37
+
38
+ Args:
39
+ model: Model name (e.g., "gpt-4", "claude-3-sonnet")
40
+ messages: List of message dicts with role and content
41
+ temperature: Sampling temperature
42
+ max_tokens: Maximum tokens to generate
43
+ stream: Whether to stream the response
44
+ **kwargs: Additional parameters passed to the model
45
+
46
+ Returns:
47
+ Completion response (same format as OpenAI)
48
+ """
49
+ payload = {
50
+ "model": model,
51
+ "messages": messages,
52
+ "temperature": temperature,
53
+ **kwargs,
54
+ }
55
+
56
+ if max_tokens:
57
+ payload["max_tokens"] = max_tokens
58
+
59
+ if stream:
60
+ return self._stream_completion(payload)
61
+
62
+ response = self._client._request("POST", "/chat/completions", json=payload)
63
+ return response
64
+
65
+ def _stream_completion(
66
+ self,
67
+ payload: Dict[str, Any],
68
+ ) -> Iterator[Dict[str, Any]]:
69
+ """Stream a chat completion"""
70
+ payload["stream"] = True
71
+
72
+ with self._client._client.stream(
73
+ "POST",
74
+ f"{self._client.config.base_url}/chat/completions",
75
+ json=payload,
76
+ headers=self._client._get_headers(),
77
+ ) as response:
78
+ for line in response.iter_lines():
79
+ if line.startswith("data: "):
80
+ data = line[6:]
81
+ if data == "[DONE]":
82
+ break
83
+ yield json.loads(data)
84
+
85
+
86
+ class Chat:
87
+ """Chat API namespace"""
88
+
89
+ def __init__(self, client: "PromptGuard"):
90
+ self.completions = ChatCompletions(client)
91
+
92
+
93
+ class Completions:
94
+ """Legacy completions API (OpenAI-compatible)"""
95
+
96
+ def __init__(self, client: "PromptGuard"):
97
+ self._client = client
98
+
99
+ def create(
100
+ self,
101
+ model: str,
102
+ prompt: str,
103
+ max_tokens: Optional[int] = None,
104
+ temperature: float = 1.0,
105
+ **kwargs,
106
+ ) -> Dict[str, Any]:
107
+ """Create a completion (legacy API)"""
108
+ payload = {
109
+ "model": model,
110
+ "prompt": prompt,
111
+ "temperature": temperature,
112
+ **kwargs,
113
+ }
114
+
115
+ if max_tokens:
116
+ payload["max_tokens"] = max_tokens
117
+
118
+ return self._client._request("POST", "/completions", json=payload)
119
+
120
+
121
+ class Embeddings:
122
+ """Embeddings API"""
123
+
124
+ def __init__(self, client: "PromptGuard"):
125
+ self._client = client
126
+
127
+ def create(
128
+ self,
129
+ model: str,
130
+ input: Union[str, List[str]],
131
+ **kwargs,
132
+ ) -> Dict[str, Any]:
133
+ """Create embeddings"""
134
+ payload = {
135
+ "model": model,
136
+ "input": input,
137
+ **kwargs,
138
+ }
139
+
140
+ return self._client._request("POST", "/embeddings", json=payload)
141
+
142
+
143
+ class Security:
144
+ """PromptGuard-specific security APIs"""
145
+
146
+ def __init__(self, client: "PromptGuard"):
147
+ self._client = client
148
+
149
+ def scan(
150
+ self,
151
+ content: str,
152
+ content_type: str = "prompt",
153
+ ) -> Dict[str, Any]:
154
+ """
155
+ Scan content for security issues.
156
+
157
+ Args:
158
+ content: Text to scan
159
+ content_type: "prompt" or "response"
160
+
161
+ Returns:
162
+ Scan result with threats detected
163
+ """
164
+ return self._client._request(
165
+ "POST",
166
+ "/security/scan",
167
+ json={"content": content, "type": content_type},
168
+ )
169
+
170
+ def redact(
171
+ self,
172
+ content: str,
173
+ pii_types: Optional[List[str]] = None,
174
+ ) -> Dict[str, Any]:
175
+ """
176
+ Redact PII from content.
177
+
178
+ Args:
179
+ content: Text to redact
180
+ pii_types: Specific PII types to redact (default: all)
181
+
182
+ Returns:
183
+ Redacted content
184
+ """
185
+ return self._client._request(
186
+ "POST",
187
+ "/security/redact",
188
+ json={"content": content, "pii_types": pii_types},
189
+ )
190
+
191
+
192
+ class Memory:
193
+ """PromptGuard Memory API"""
194
+
195
+ def __init__(self, client: "PromptGuard"):
196
+ self._client = client
197
+
198
+ def store(
199
+ self,
200
+ agent_id: str,
201
+ content: str,
202
+ session_id: Optional[str] = None,
203
+ metadata: Optional[Dict[str, Any]] = None,
204
+ importance: float = 0.5,
205
+ ) -> Dict[str, Any]:
206
+ """
207
+ Store a memory for an AI agent.
208
+
209
+ Args:
210
+ agent_id: Unique identifier for the agent
211
+ content: Content to store in memory
212
+ session_id: Optional session identifier
213
+ metadata: Optional metadata dict
214
+ importance: Importance score (0.0 to 1.0)
215
+
216
+ Returns:
217
+ Dict with entry_id and status
218
+ """
219
+ return self._client._request(
220
+ "POST",
221
+ "/memory/store",
222
+ json={
223
+ "agent_id": agent_id,
224
+ "content": content,
225
+ "session_id": session_id,
226
+ "metadata": metadata,
227
+ "importance": importance,
228
+ },
229
+ )
230
+
231
+ def retrieve(
232
+ self,
233
+ agent_id: str,
234
+ query: str,
235
+ top_k: int = 5,
236
+ min_relevance: float = 0.5,
237
+ session_id: Optional[str] = None,
238
+ ) -> Dict[str, Any]:
239
+ """
240
+ Retrieve relevant memories for an AI agent.
241
+
242
+ Args:
243
+ agent_id: Unique identifier for the agent
244
+ query: Query string to match against memories
245
+ top_k: Number of results to return
246
+ min_relevance: Minimum relevance score
247
+ session_id: Optional session filter
248
+
249
+ Returns:
250
+ Dict with memories and stats
251
+ """
252
+ return self._client._request(
253
+ "POST",
254
+ "/memory/retrieve",
255
+ json={
256
+ "agent_id": agent_id,
257
+ "query": query,
258
+ "top_k": top_k,
259
+ "min_relevance": min_relevance,
260
+ "session_id": session_id,
261
+ },
262
+ )
263
+
264
+ def clear(
265
+ self,
266
+ agent_id: str,
267
+ session_id: Optional[str] = None,
268
+ ) -> Dict[str, Any]:
269
+ """
270
+ Clear memories for an agent.
271
+
272
+ Args:
273
+ agent_id: Unique identifier for the agent
274
+ session_id: Optional - clear only this session
275
+
276
+ Returns:
277
+ Dict with deletion status
278
+ """
279
+ url = f"/memory/{agent_id}"
280
+ if session_id:
281
+ url += f"?session_id={session_id}"
282
+ return self._client._request("DELETE", url)
283
+
284
+ def stats(self) -> Dict[str, Any]:
285
+ """Get memory system statistics"""
286
+ return self._client._request("GET", "/memory/stats")
287
+
288
+
289
+ class Scrape:
290
+ """PromptGuard Secure Web Scraping API"""
291
+
292
+ def __init__(self, client: "PromptGuard"):
293
+ self._client = client
294
+
295
+ def url(
296
+ self,
297
+ url: str,
298
+ render_js: bool = False,
299
+ extract_text: bool = True,
300
+ timeout: int = 30,
301
+ ) -> Dict[str, Any]:
302
+ """
303
+ Securely scrape a URL with threat scanning.
304
+
305
+ Args:
306
+ url: URL to scrape
307
+ render_js: Whether to render JavaScript
308
+ extract_text: Whether to extract clean text
309
+ timeout: Request timeout in seconds
310
+
311
+ Returns:
312
+ Dict with content and threat analysis
313
+ """
314
+ return self._client._request(
315
+ "POST",
316
+ "/scrape",
317
+ json={
318
+ "url": url,
319
+ "render_js": render_js,
320
+ "extract_text": extract_text,
321
+ "timeout": timeout,
322
+ },
323
+ )
324
+
325
+ def batch(
326
+ self,
327
+ urls: List[str],
328
+ **kwargs,
329
+ ) -> Dict[str, Any]:
330
+ """
331
+ Batch scrape multiple URLs.
332
+
333
+ Args:
334
+ urls: List of URLs to scrape
335
+ **kwargs: Same options as single scrape
336
+
337
+ Returns:
338
+ Dict with job_id for tracking
339
+ """
340
+ return self._client._request(
341
+ "POST",
342
+ "/scrape/batch",
343
+ json={"urls": urls, **kwargs},
344
+ )
345
+
346
+
347
+ class Agent:
348
+ """PromptGuard AI Agent Security API"""
349
+
350
+ def __init__(self, client: "PromptGuard"):
351
+ self._client = client
352
+
353
+ def validate_tool(
354
+ self,
355
+ agent_id: str,
356
+ tool_name: str,
357
+ arguments: Dict[str, Any],
358
+ session_id: Optional[str] = None,
359
+ ) -> Dict[str, Any]:
360
+ """
361
+ Validate a tool call before execution.
362
+
363
+ Args:
364
+ agent_id: Unique identifier for the agent
365
+ tool_name: Name of the tool being called
366
+ arguments: Arguments being passed to the tool
367
+ session_id: Optional session identifier
368
+
369
+ Returns:
370
+ Dict with allowed status, risk score, and warnings
371
+ """
372
+ return self._client._request(
373
+ "POST",
374
+ "/agent/validate-tool",
375
+ json={
376
+ "agent_id": agent_id,
377
+ "tool_name": tool_name,
378
+ "arguments": arguments,
379
+ "session_id": session_id,
380
+ },
381
+ )
382
+
383
+ def analyze_behavior(
384
+ self,
385
+ agent_id: str,
386
+ recent_actions: List[Dict[str, Any]],
387
+ session_id: Optional[str] = None,
388
+ ) -> Dict[str, Any]:
389
+ """
390
+ Analyze agent behavior for anomalies.
391
+
392
+ Args:
393
+ agent_id: Unique identifier for the agent
394
+ recent_actions: List of recent tool calls/actions
395
+ session_id: Optional session identifier
396
+
397
+ Returns:
398
+ Dict with anomaly analysis
399
+ """
400
+ return self._client._request(
401
+ "POST",
402
+ "/agent/analyze-behavior",
403
+ json={
404
+ "agent_id": agent_id,
405
+ "recent_actions": recent_actions,
406
+ "session_id": session_id,
407
+ },
408
+ )
409
+
410
+ def stats(self, agent_id: str) -> Dict[str, Any]:
411
+ """Get statistics for an agent"""
412
+ return self._client._request("GET", f"/agent/{agent_id}/stats")
413
+
414
+
415
+ class RedTeam:
416
+ """PromptGuard Red Team Testing API"""
417
+
418
+ def __init__(self, client: "PromptGuard"):
419
+ self._client = client
420
+ # Note: RedTeam API requires internal/admin access
421
+ self._base = "/internal/redteam"
422
+
423
+ def list_tests(self) -> Dict[str, Any]:
424
+ """List all available red team tests"""
425
+ return self._client._request("GET", f"{self._base}/tests")
426
+
427
+ def run_test(
428
+ self,
429
+ test_name: str,
430
+ target_preset: str = "default",
431
+ ) -> Dict[str, Any]:
432
+ """
433
+ Run a specific red team test.
434
+
435
+ Args:
436
+ test_name: Name of the test to run
437
+ target_preset: Policy preset to test against
438
+
439
+ Returns:
440
+ Test result with decision and details
441
+ """
442
+ return self._client._request(
443
+ "POST",
444
+ f"{self._base}/test/{test_name}",
445
+ json={"target_preset": target_preset},
446
+ )
447
+
448
+ def run_all(
449
+ self,
450
+ target_preset: str = "default",
451
+ ) -> Dict[str, Any]:
452
+ """
453
+ Run all red team tests.
454
+
455
+ Args:
456
+ target_preset: Policy preset to test against
457
+
458
+ Returns:
459
+ Summary with all test results
460
+ """
461
+ return self._client._request(
462
+ "POST",
463
+ f"{self._base}/test-all",
464
+ json={"target_preset": target_preset},
465
+ )
466
+
467
+ def run_custom(
468
+ self,
469
+ prompt: str,
470
+ target_preset: str = "default",
471
+ ) -> Dict[str, Any]:
472
+ """
473
+ Run a custom adversarial prompt test.
474
+
475
+ Args:
476
+ prompt: Custom adversarial prompt to test
477
+ target_preset: Policy preset to test against
478
+
479
+ Returns:
480
+ Test result
481
+ """
482
+ return self._client._request(
483
+ "POST",
484
+ f"{self._base}/test-custom",
485
+ json={
486
+ "custom_prompt": prompt,
487
+ "target_preset": target_preset,
488
+ },
489
+ )
490
+
491
+
492
+ class PromptGuard:
493
+ """
494
+ PromptGuard client - Drop-in security for AI applications.
495
+
496
+ Usage:
497
+ from promptguard import PromptGuard
498
+
499
+ # Initialize client
500
+ pg = PromptGuard(api_key="pg_xxx")
501
+
502
+ # Use like OpenAI client
503
+ response = pg.chat.completions.create(
504
+ model="gpt-4",
505
+ messages=[{"role": "user", "content": "Hello!"}]
506
+ )
507
+
508
+ # Security-specific features
509
+ scan_result = pg.security.scan("Check this content")
510
+
511
+ # Memory features
512
+ pg.memory.store("User prefers Python", memory_type="preference")
513
+ """
514
+
515
+ def __init__(
516
+ self,
517
+ api_key: Optional[str] = None,
518
+ base_url: Optional[str] = None,
519
+ config: Optional[Config] = None,
520
+ timeout: float = 30.0,
521
+ ):
522
+ """
523
+ Initialize PromptGuard client.
524
+
525
+ Args:
526
+ api_key: PromptGuard API key (or set PROMPTGUARD_API_KEY env var)
527
+ base_url: API base URL (default: https://api.promptguard.co/api/v1/proxy)
528
+ config: Optional Config object
529
+ timeout: Request timeout in seconds
530
+ """
531
+ self.config = config or Config(
532
+ api_key=api_key or os.environ.get("PROMPTGUARD_API_KEY", ""),
533
+ base_url=base_url or os.environ.get(
534
+ "PROMPTGUARD_BASE_URL",
535
+ "https://api.promptguard.co/api/v1/proxy"
536
+ ),
537
+ )
538
+
539
+ if not self.config.api_key:
540
+ raise ValueError(
541
+ "API key required. Pass api_key parameter or set PROMPTGUARD_API_KEY environment variable."
542
+ )
543
+
544
+ self._client = httpx.Client(timeout=timeout)
545
+
546
+ # API namespaces (OpenAI-compatible)
547
+ self.chat = Chat(self)
548
+ self.completions = Completions(self)
549
+ self.embeddings = Embeddings(self)
550
+
551
+ # PromptGuard-specific APIs
552
+ self.security = Security(self)
553
+ self.memory = Memory(self)
554
+ self.scrape = Scrape(self)
555
+ self.agent = Agent(self)
556
+ self.redteam = RedTeam(self)
557
+
558
+ def _get_headers(self) -> Dict[str, str]:
559
+ """Get request headers"""
560
+ return {
561
+ "Authorization": f"Bearer {self.config.api_key}",
562
+ "Content-Type": "application/json",
563
+ "X-PromptGuard-SDK": "python",
564
+ "X-PromptGuard-Version": "0.1.0",
565
+ }
566
+
567
+ def _request(
568
+ self,
569
+ method: str,
570
+ path: str,
571
+ **kwargs,
572
+ ) -> Dict[str, Any]:
573
+ """Make API request"""
574
+ url = f"{self.config.base_url}{path}"
575
+ headers = self._get_headers()
576
+
577
+ response = self._client.request(
578
+ method,
579
+ url,
580
+ headers=headers,
581
+ **kwargs,
582
+ )
583
+
584
+ if response.status_code >= 400:
585
+ error_data = response.json() if response.content else {}
586
+ raise PromptGuardError(
587
+ message=error_data.get("error", {}).get("message", "Request failed"),
588
+ code=error_data.get("error", {}).get("code", "UNKNOWN"),
589
+ status_code=response.status_code,
590
+ )
591
+
592
+ return response.json()
593
+
594
+ def close(self):
595
+ """Close the client"""
596
+ self._client.close()
597
+
598
+ def __enter__(self):
599
+ return self
600
+
601
+ def __exit__(self, *args):
602
+ self.close()
603
+
604
+
605
+ class PromptGuardAsync:
606
+ """Async version of PromptGuard client"""
607
+
608
+ def __init__(
609
+ self,
610
+ api_key: Optional[str] = None,
611
+ base_url: Optional[str] = None,
612
+ config: Optional[Config] = None,
613
+ timeout: float = 30.0,
614
+ ):
615
+ self.config = config or Config(
616
+ api_key=api_key or os.environ.get("PROMPTGUARD_API_KEY", ""),
617
+ base_url=base_url or os.environ.get(
618
+ "PROMPTGUARD_BASE_URL",
619
+ "https://api.promptguard.co/api/v1/proxy"
620
+ ),
621
+ )
622
+
623
+ if not self.config.api_key:
624
+ raise ValueError("API key required")
625
+
626
+ self._client = httpx.AsyncClient(timeout=timeout)
627
+
628
+ async def _request(
629
+ self,
630
+ method: str,
631
+ path: str,
632
+ **kwargs,
633
+ ) -> Dict[str, Any]:
634
+ """Make async API request"""
635
+ url = f"{self.config.base_url}{path}"
636
+ headers = {
637
+ "Authorization": f"Bearer {self.config.api_key}",
638
+ "Content-Type": "application/json",
639
+ }
640
+
641
+ response = await self._client.request(
642
+ method,
643
+ url,
644
+ headers=headers,
645
+ **kwargs,
646
+ )
647
+
648
+ if response.status_code >= 400:
649
+ error_data = response.json() if response.content else {}
650
+ raise PromptGuardError(
651
+ message=error_data.get("error", {}).get("message", "Request failed"),
652
+ code=error_data.get("error", {}).get("code", "UNKNOWN"),
653
+ status_code=response.status_code,
654
+ )
655
+
656
+ return response.json()
657
+
658
+ async def close(self):
659
+ """Close the client"""
660
+ await self._client.aclose()
661
+
662
+ async def __aenter__(self):
663
+ return self
664
+
665
+ async def __aexit__(self, *args):
666
+ await self.close()
667
+
668
+
669
+ class PromptGuardError(Exception):
670
+ """Error from PromptGuard API"""
671
+
672
+ def __init__(self, message: str, code: str, status_code: int):
673
+ self.message = message
674
+ self.code = code
675
+ self.status_code = status_code
676
+ super().__init__(f"{code}: {message}")
@@ -0,0 +1,35 @@
1
+ """
2
+ PromptGuard SDK Configuration
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Optional
7
+
8
+
9
+ @dataclass
10
+ class Config:
11
+ """Configuration for PromptGuard SDK"""
12
+
13
+ # Authentication
14
+ api_key: str
15
+
16
+ # API endpoint
17
+ base_url: str = "https://api.promptguard.co/api/v1/proxy"
18
+
19
+ # Features
20
+ enable_caching: bool = True
21
+ enable_security_scan: bool = True
22
+ enable_memory: bool = True
23
+
24
+ # Timeouts (seconds)
25
+ timeout: float = 30.0
26
+
27
+ # Retry settings
28
+ max_retries: int = 3
29
+ retry_delay: float = 1.0
30
+
31
+ # Project settings
32
+ project_id: Optional[str] = None
33
+
34
+ # Debug
35
+ debug: bool = False
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "promptguard-sdk"
7
+ version = "0.1.0"
8
+ description = "Drop-in security for AI applications - AI Firewall SDK"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ { name = "PromptGuard", email = "support@promptguard.co" }
14
+ ]
15
+ keywords = [
16
+ "ai",
17
+ "security",
18
+ "llm",
19
+ "prompt-injection",
20
+ "openai",
21
+ "anthropic",
22
+ "ai-firewall",
23
+ "pii-detection",
24
+ "llm-security",
25
+ "ai-security",
26
+ ]
27
+ classifiers = [
28
+ "Development Status :: 4 - Beta",
29
+ "Intended Audience :: Developers",
30
+ "License :: OSI Approved :: MIT License",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3.8",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ "Topic :: Security",
38
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
39
+ ]
40
+ dependencies = [
41
+ "httpx>=0.24.0",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ dev = [
46
+ "pytest>=7.0.0",
47
+ "pytest-asyncio>=0.21.0",
48
+ "ruff>=0.1.0",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://promptguard.co"
53
+ Documentation = "https://docs.promptguard.co"
54
+ Repository = "https://github.com/acebot712/promptguard"
55
+ Issues = "https://github.com/acebot712/promptguard/issues"
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ packages = ["promptguard"]
59
+
60
+ [tool.ruff]
61
+ line-length = 100
62
+ target-version = "py38"