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.
- promptguard_sdk-0.1.0/.gitignore +88 -0
- promptguard_sdk-0.1.0/PKG-INFO +179 -0
- promptguard_sdk-0.1.0/README.md +149 -0
- promptguard_sdk-0.1.0/promptguard/__init__.py +23 -0
- promptguard_sdk-0.1.0/promptguard/client.py +676 -0
- promptguard_sdk-0.1.0/promptguard/config.py +35 -0
- promptguard_sdk-0.1.0/pyproject.toml +62 -0
|
@@ -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"
|