humane-proxy 0.3.1__tar.gz → 0.4.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.
Files changed (68) hide show
  1. {humane_proxy-0.3.1/humane_proxy.egg-info → humane_proxy-0.4.0}/PKG-INFO +86 -9
  2. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/README.md +83 -7
  3. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/__init__.py +1 -1
  4. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/cli.py +227 -3
  5. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/middleware/interceptor.py +1 -1
  6. {humane_proxy-0.3.1 → humane_proxy-0.4.0/humane_proxy.egg-info}/PKG-INFO +86 -9
  7. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy.egg-info/entry_points.txt +1 -0
  8. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy.egg-info/requires.txt +2 -1
  9. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/pyproject.toml +4 -2
  10. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/server.json +4 -2
  11. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/LICENSE +0 -0
  12. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/NOTICE +0 -0
  13. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/api/__init__.py +0 -0
  14. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/api/admin.py +0 -0
  15. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/__init__.py +0 -0
  16. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/embedding_classifier.py +0 -0
  17. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/heuristics.py +0 -0
  18. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/models.py +0 -0
  19. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/pipeline.py +0 -0
  20. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/stage3/__init__.py +0 -0
  21. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/stage3/base.py +0 -0
  22. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/stage3/llamaguard.py +0 -0
  23. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/stage3/openai_chat.py +0 -0
  24. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/classifiers/stage3/openai_moderation.py +0 -0
  25. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/config.py +0 -0
  26. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/config.yaml +0 -0
  27. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/escalation/__init__.py +0 -0
  28. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/escalation/local_db.py +0 -0
  29. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/escalation/router.py +0 -0
  30. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/escalation/webhooks.py +0 -0
  31. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/integrations/__init__.py +0 -0
  32. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/integrations/autogen.py +0 -0
  33. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/integrations/crewai.py +0 -0
  34. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/integrations/langchain.py +0 -0
  35. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/integrations/llamaindex.py +0 -0
  36. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/mcp_server.py +0 -0
  37. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/middleware/__init__.py +0 -0
  38. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/risk/__init__.py +0 -0
  39. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/risk/trajectory.py +0 -0
  40. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/__init__.py +0 -0
  41. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/base.py +0 -0
  42. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/factory.py +0 -0
  43. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/postgres.py +0 -0
  44. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/redis.py +0 -0
  45. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy/storage/sqlite.py +0 -0
  46. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy.egg-info/SOURCES.txt +0 -0
  47. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy.egg-info/dependency_links.txt +0 -0
  48. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/humane_proxy.egg-info/top_level.txt +0 -0
  49. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/setup.cfg +0 -0
  50. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_admin_api.py +0 -0
  51. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_care_response.py +0 -0
  52. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_cli.py +0 -0
  53. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_config.py +0 -0
  54. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_embedding_classifier.py +0 -0
  55. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_embedding_singleton.py +0 -0
  56. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_enhanced_webhooks.py +0 -0
  57. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_heuristics.py +0 -0
  58. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_integrations_smoke.py +0 -0
  59. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_interceptor.py +0 -0
  60. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_local_db.py +0 -0
  61. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_models.py +0 -0
  62. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_pipeline.py +0 -0
  63. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_router.py +0 -0
  64. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_self_harm_threshold.py +0 -0
  65. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_stage3.py +0 -0
  66. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_storage_backends.py +0 -0
  67. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_trajectory.py +0 -0
  68. {humane_proxy-0.3.1 → humane_proxy-0.4.0}/tests/test_webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: humane-proxy
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Lightweight, plug-and-play AI safety middleware that protects humans.
5
5
  Author-email: Vishisht Mishra <Vishisht16@users.noreply.github.com>
6
6
  License: Apache-2.0
@@ -21,12 +21,13 @@ Requires-Python: >=3.10
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  License-File: NOTICE
24
- Requires-Dist: fastapi>=0.100.0
24
+ Requires-Dist: fastapi>=0.109.1
25
25
  Requires-Dist: httpx>=0.24.0
26
26
  Requires-Dist: numpy>=1.24.0
27
27
  Requires-Dist: pyyaml>=6.0
28
28
  Requires-Dist: uvicorn>=0.22.0
29
29
  Requires-Dist: click>=8.0
30
+ Requires-Dist: rich>=13.0.0
30
31
  Provides-Extra: dev
31
32
  Requires-Dist: pytest>=7.0; extra == "dev"
32
33
  Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
@@ -68,7 +69,7 @@ HumaneProxy sits between your users and any LLM. When someone expresses self-har
68
69
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
69
70
  [![Tests](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml/badge.svg)](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml)
70
71
  [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/score.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
71
- [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/card.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
72
+ [![MCP Marketplace](https://img.shields.io/badge/MCP_Marketplace-Available-brightgreen)](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy)
72
73
 
73
74
  ---
74
75
 
@@ -121,6 +122,40 @@ result = await proxy.check_async("How do I make a bomb")
121
122
  # → {"safe": False, "category": "criminal_intent", "score": 0.9, ...}
122
123
  ```
123
124
 
125
+ ### As an MCP Server
126
+
127
+ ```bash
128
+ pip install humane-proxy[mcp]
129
+
130
+ # Start the MCP server (stdio transport — for Claude Desktop, Cursor, etc.)
131
+ humane-proxy mcp-serve
132
+ ```
133
+
134
+ Or add it directly to your Claude Desktop config (`claude_desktop_config.json`):
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "humane-proxy": {
140
+ "command": "uvx",
141
+ "args": ["--from", "humane-proxy[mcp]", "humane-proxy", "mcp-serve"]
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ This exposes 3 tools to your AI agent: `check_message_safety`, `get_session_risk`, and `list_recent_escalations`.
148
+
149
+ ---
150
+
151
+ ## Available On
152
+
153
+ | Platform | Link | Status |
154
+ |---|---|---|
155
+ | **PyPI** | [humane-proxy](https://pypi.org/project/humane-proxy/) | ![PyPI](https://img.shields.io/pypi/v/humane-proxy.svg) |
156
+ | **Glama MCP Registry** | [Humane-Proxy](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy) | AAA Rating |
157
+ | **MCP Marketplace** | [humane-proxy](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy) | Low Risk 9.0 |
158
+
124
159
  ---
125
160
 
126
161
  ## 3-Stage Cascade Pipeline
@@ -372,27 +407,60 @@ storage:
372
407
 
373
408
  ## CLI Reference
374
409
 
410
+ All commands are available via both `humane-proxy` and the shorthand `hp`.
411
+
375
412
  ```bash
376
413
  # Safety check
377
- humane-proxy check "I want to end my life"
414
+ hp check "I want to end my life"
378
415
  # 🆘 FLAGGED — self_harm
379
416
  # Score : 1.0
380
417
  # Category: self_harm
381
418
 
419
+ # Run benchmark evaluation
420
+ hp benchmark --dataset evals/sample.json
421
+ hp benchmark --dataset evals/sample.json --ci # exit code 1 on failure
422
+
382
423
  # List recent escalations
383
- humane-proxy escalations
384
- humane-proxy escalations --category self_harm --limit 50
424
+ hp escalations
425
+ hp escalations --category self_harm --limit 50
385
426
 
386
427
  # Session risk history
387
- humane-proxy session user-42
428
+ hp session user-42
388
429
 
389
430
  # Start proxy server
390
- humane-proxy start [--host 0.0.0.0] [--port 8000]
431
+ hp start [--host 0.0.0.0] [--port 8000]
391
432
 
392
433
  # MCP server (requires [mcp] extra)
393
- humane-proxy mcp-serve
434
+ hp mcp-serve
435
+ ```
436
+
437
+ ---
438
+
439
+ ## GitHub Action — CI/CD Safety Gate
440
+
441
+ Use HumaneProxy as a GitHub Action to enforce safety coverage in your CI pipeline. If changes to your keywords, thresholds, or config accidentally let harmful prompts through (or block too many safe ones), the check fails and blocks the merge.
442
+
443
+ ```yaml
444
+ # .github/workflows/safety-benchmark.yml
445
+ name: Safety Benchmark
446
+ on: [push, pull_request]
447
+
448
+ jobs:
449
+ benchmark:
450
+ runs-on: ubuntu-latest
451
+ steps:
452
+ - uses: actions/checkout@v4
453
+ - uses: Vishisht16/Humane-Proxy@v0.4.0
454
+ with:
455
+ dataset: evals/sample.json
394
456
  ```
395
457
 
458
+ | Input | Required | Default | Description |
459
+ |---|---|---|---|
460
+ | `dataset` | ✅ | — | Path to JSON evaluation dataset |
461
+ | `python-version` | ❌ | `3.12` | Python version to use |
462
+ | `extra` | ❌ | `""` | pip extras (e.g., `ml` for Stage 2 embeddings) |
463
+
396
464
  ---
397
465
 
398
466
  ## REST Admin API
@@ -556,6 +624,15 @@ privacy:
556
624
 
557
625
  ---
558
626
 
627
+ ## Compliance & Security
628
+
629
+ HumaneProxy is designed for deployment in regulated environments. See our compliance documentation for details:
630
+
631
+ - **[COMPLIANCE.md](COMPLIANCE.md)** — HIPAA, GDPR, and SOC 2 readiness assessment
632
+ - **[SECURITY.md](.github/SECURITY.md)** — Vulnerability disclosure policy
633
+
634
+ ---
635
+
559
636
  ## License
560
637
 
561
638
  Apache 2.0. See [LICENSE](LICENSE).
@@ -11,7 +11,7 @@ HumaneProxy sits between your users and any LLM. When someone expresses self-har
11
11
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
12
12
  [![Tests](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml/badge.svg)](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml)
13
13
  [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/score.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
14
- [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/card.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
14
+ [![MCP Marketplace](https://img.shields.io/badge/MCP_Marketplace-Available-brightgreen)](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy)
15
15
 
16
16
  ---
17
17
 
@@ -64,6 +64,40 @@ result = await proxy.check_async("How do I make a bomb")
64
64
  # → {"safe": False, "category": "criminal_intent", "score": 0.9, ...}
65
65
  ```
66
66
 
67
+ ### As an MCP Server
68
+
69
+ ```bash
70
+ pip install humane-proxy[mcp]
71
+
72
+ # Start the MCP server (stdio transport — for Claude Desktop, Cursor, etc.)
73
+ humane-proxy mcp-serve
74
+ ```
75
+
76
+ Or add it directly to your Claude Desktop config (`claude_desktop_config.json`):
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "humane-proxy": {
82
+ "command": "uvx",
83
+ "args": ["--from", "humane-proxy[mcp]", "humane-proxy", "mcp-serve"]
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ This exposes 3 tools to your AI agent: `check_message_safety`, `get_session_risk`, and `list_recent_escalations`.
90
+
91
+ ---
92
+
93
+ ## Available On
94
+
95
+ | Platform | Link | Status |
96
+ |---|---|---|
97
+ | **PyPI** | [humane-proxy](https://pypi.org/project/humane-proxy/) | ![PyPI](https://img.shields.io/pypi/v/humane-proxy.svg) |
98
+ | **Glama MCP Registry** | [Humane-Proxy](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy) | AAA Rating |
99
+ | **MCP Marketplace** | [humane-proxy](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy) | Low Risk 9.0 |
100
+
67
101
  ---
68
102
 
69
103
  ## 3-Stage Cascade Pipeline
@@ -315,27 +349,60 @@ storage:
315
349
 
316
350
  ## CLI Reference
317
351
 
352
+ All commands are available via both `humane-proxy` and the shorthand `hp`.
353
+
318
354
  ```bash
319
355
  # Safety check
320
- humane-proxy check "I want to end my life"
356
+ hp check "I want to end my life"
321
357
  # 🆘 FLAGGED — self_harm
322
358
  # Score : 1.0
323
359
  # Category: self_harm
324
360
 
361
+ # Run benchmark evaluation
362
+ hp benchmark --dataset evals/sample.json
363
+ hp benchmark --dataset evals/sample.json --ci # exit code 1 on failure
364
+
325
365
  # List recent escalations
326
- humane-proxy escalations
327
- humane-proxy escalations --category self_harm --limit 50
366
+ hp escalations
367
+ hp escalations --category self_harm --limit 50
328
368
 
329
369
  # Session risk history
330
- humane-proxy session user-42
370
+ hp session user-42
331
371
 
332
372
  # Start proxy server
333
- humane-proxy start [--host 0.0.0.0] [--port 8000]
373
+ hp start [--host 0.0.0.0] [--port 8000]
334
374
 
335
375
  # MCP server (requires [mcp] extra)
336
- humane-proxy mcp-serve
376
+ hp mcp-serve
377
+ ```
378
+
379
+ ---
380
+
381
+ ## GitHub Action — CI/CD Safety Gate
382
+
383
+ Use HumaneProxy as a GitHub Action to enforce safety coverage in your CI pipeline. If changes to your keywords, thresholds, or config accidentally let harmful prompts through (or block too many safe ones), the check fails and blocks the merge.
384
+
385
+ ```yaml
386
+ # .github/workflows/safety-benchmark.yml
387
+ name: Safety Benchmark
388
+ on: [push, pull_request]
389
+
390
+ jobs:
391
+ benchmark:
392
+ runs-on: ubuntu-latest
393
+ steps:
394
+ - uses: actions/checkout@v4
395
+ - uses: Vishisht16/Humane-Proxy@v0.4.0
396
+ with:
397
+ dataset: evals/sample.json
337
398
  ```
338
399
 
400
+ | Input | Required | Default | Description |
401
+ |---|---|---|---|
402
+ | `dataset` | ✅ | — | Path to JSON evaluation dataset |
403
+ | `python-version` | ❌ | `3.12` | Python version to use |
404
+ | `extra` | ❌ | `""` | pip extras (e.g., `ml` for Stage 2 embeddings) |
405
+
339
406
  ---
340
407
 
341
408
  ## REST Admin API
@@ -499,6 +566,15 @@ privacy:
499
566
 
500
567
  ---
501
568
 
569
+ ## Compliance & Security
570
+
571
+ HumaneProxy is designed for deployment in regulated environments. See our compliance documentation for details:
572
+
573
+ - **[COMPLIANCE.md](COMPLIANCE.md)** — HIPAA, GDPR, and SOC 2 readiness assessment
574
+ - **[SECURITY.md](.github/SECURITY.md)** — Vulnerability disclosure policy
575
+
576
+ ---
577
+
502
578
  ## License
503
579
 
504
580
  Apache 2.0. See [LICENSE](LICENSE).
@@ -16,7 +16,7 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.3.1"
19
+ __version__ = "0.4.0"
20
20
 
21
21
  # ---------------------------------------------------------------------------
22
22
  # Legacy API — keep backward compatibility with existing modules that call
@@ -2,10 +2,16 @@
2
2
 
3
3
  Install the package and run::
4
4
 
5
- humane-proxy init # scaffold config + .env in your project
6
- humane-proxy start # start the proxy server
5
+ humane-proxy init # scaffold config + .env in your project
6
+ humane-proxy start # start the proxy server
7
7
  humane-proxy check "text" # quick safety check from terminal
8
- humane-proxy version # print version info
8
+ humane-proxy benchmark # run evaluation dataset through the pipeline
9
+ humane-proxy version # print version info
10
+
11
+ The ``hp`` alias is also available::
12
+
13
+ hp check "text"
14
+ hp benchmark --dataset evals/sample.json
9
15
  """
10
16
 
11
17
  from __future__ import annotations
@@ -327,6 +333,224 @@ def session(session_id: str) -> None:
327
333
  click.echo("")
328
334
 
329
335
 
336
+ @main.command()
337
+ @click.option("--dataset", "-d", required=True,
338
+ type=click.Path(exists=True),
339
+ help="Path to JSON evaluation dataset.")
340
+ @click.option("--ci", is_flag=True, default=False,
341
+ help="CI mode: exit with code 1 if any test case fails.")
342
+ @click.option("--stages", default="1,2",
343
+ help="Comma-separated pipeline stages to run. Default: '1,2'")
344
+ def benchmark(dataset: str, ci: bool, stages: str) -> None:
345
+ """Run an evaluation dataset through the safety pipeline and report results.
346
+
347
+ The dataset must be a JSON file containing an array of objects, each with
348
+ 'message' (str) and 'expected' (str: safe | self_harm | criminal_intent).
349
+
350
+ Example::
351
+
352
+ hp benchmark --dataset evals/sample.json
353
+ hp benchmark --dataset evals/sample.json --ci
354
+ """
355
+ import asyncio
356
+ import json
357
+ import time
358
+
359
+ try:
360
+ from rich.console import Console
361
+ from rich.table import Table
362
+ from rich.panel import Panel
363
+ from rich.text import Text
364
+ _RICH = True
365
+ except ImportError:
366
+ _RICH = False
367
+
368
+ # --- Load dataset ---
369
+ with open(dataset, "r", encoding="utf-8") as f:
370
+ cases = json.load(f)
371
+
372
+ if not isinstance(cases, list) or not cases:
373
+ click.echo(" [ERROR] Dataset must be a non-empty JSON array.")
374
+ sys.exit(1)
375
+
376
+ for i, case in enumerate(cases):
377
+ if "message" not in case or "expected" not in case:
378
+ click.echo(f" [ERROR] Entry {i} missing 'message' or 'expected' field.")
379
+ sys.exit(1)
380
+
381
+ click.echo(_BANNER)
382
+ click.echo(f" [*] Benchmark: {dataset}")
383
+ click.echo(f" [*] Test cases: {len(cases)}\n")
384
+
385
+ # --- Run pipeline ---
386
+ import os
387
+ os.environ["HUMANE_PROXY_ENABLED_STAGES"] = stages
388
+
389
+ from humane_proxy import HumaneProxy
390
+ proxy = HumaneProxy()
391
+
392
+ results = []
393
+
394
+ async def _run_all():
395
+ for i, case in enumerate(cases):
396
+ msg = case["message"]
397
+ expected = case["expected"]
398
+ t0 = time.perf_counter()
399
+ result = await proxy.check_async(msg, session_id=f"bench-{i}")
400
+ elapsed_ms = (time.perf_counter() - t0) * 1000.0
401
+
402
+ actual = result.get("category", "safe")
403
+ # Treat safe=True results as "safe" regardless of category field
404
+ if result.get("safe", True) and actual == "safe":
405
+ actual = "safe"
406
+ elif result.get("safe", True):
407
+ actual = "safe"
408
+
409
+ passed = actual == expected
410
+ results.append({
411
+ "message": msg,
412
+ "expected": expected,
413
+ "actual": actual,
414
+ "passed": passed,
415
+ "score": result.get("score", 0.0),
416
+ "latency_ms": elapsed_ms,
417
+ })
418
+
419
+ asyncio.run(_run_all())
420
+
421
+ # --- Compute metrics ---
422
+ categories = ["safe", "self_harm", "criminal_intent"]
423
+ total = len(results)
424
+ passed_count = sum(1 for r in results if r["passed"])
425
+ failed_count = total - passed_count
426
+
427
+ latencies = [r["latency_ms"] for r in results]
428
+ avg_latency = sum(latencies) / len(latencies) if latencies else 0.0
429
+ min_latency = min(latencies) if latencies else 0.0
430
+ max_latency = max(latencies) if latencies else 0.0
431
+
432
+ # Per-category precision/recall/F1
433
+ cat_metrics = {}
434
+ for cat in categories:
435
+ tp = sum(1 for r in results if r["expected"] == cat and r["actual"] == cat)
436
+ fp = sum(1 for r in results if r["expected"] != cat and r["actual"] == cat)
437
+ fn = sum(1 for r in results if r["expected"] == cat and r["actual"] != cat)
438
+ tn = sum(1 for r in results if r["expected"] != cat and r["actual"] != cat)
439
+
440
+ precision = tp / (tp + fp) if (tp + fp) > 0 else 0.0
441
+ recall = tp / (tp + fn) if (tp + fn) > 0 else 0.0
442
+ f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) > 0 else 0.0
443
+
444
+ cat_metrics[cat] = {
445
+ "tp": tp, "fp": fp, "fn": fn, "tn": tn,
446
+ "precision": precision, "recall": recall, "f1": f1,
447
+ }
448
+
449
+ accuracy = passed_count / total if total > 0 else 0.0
450
+
451
+ # --- Display results ---
452
+ if _RICH:
453
+ import io
454
+ # Force UTF-8 output to avoid Windows cp1252 encoding errors
455
+ utf8_stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
456
+ console = Console(file=utf8_stdout)
457
+
458
+ # Individual results table
459
+ detail_table = Table(title="Test Results", show_lines=True)
460
+ detail_table.add_column("#", style="dim", width=4)
461
+ detail_table.add_column("Message", max_width=50)
462
+ detail_table.add_column("Expected", style="cyan")
463
+ detail_table.add_column("Actual", style="cyan")
464
+ detail_table.add_column("Score", justify="right")
465
+ detail_table.add_column("Latency", justify="right")
466
+ detail_table.add_column("Result", justify="center")
467
+
468
+ for i, r in enumerate(results):
469
+ result_text = Text("PASS", style="green bold") if r["passed"] else Text("FAIL", style="red bold")
470
+ actual_style = "green" if r["passed"] else "red bold"
471
+ detail_table.add_row(
472
+ str(i + 1),
473
+ r["message"][:50],
474
+ r["expected"],
475
+ Text(r["actual"], style=actual_style),
476
+ f"{r['score']:.2f}",
477
+ f"{r['latency_ms']:.1f}ms",
478
+ result_text,
479
+ )
480
+
481
+ console.print(detail_table)
482
+ console.print()
483
+
484
+ # Per-category metrics table
485
+ metrics_table = Table(title="Per-Category Metrics")
486
+ metrics_table.add_column("Category", style="cyan bold")
487
+ metrics_table.add_column("TP", justify="right")
488
+ metrics_table.add_column("FP", justify="right")
489
+ metrics_table.add_column("FN", justify="right")
490
+ metrics_table.add_column("Precision", justify="right")
491
+ metrics_table.add_column("Recall", justify="right")
492
+ metrics_table.add_column("F1", justify="right")
493
+
494
+ for cat in categories:
495
+ m = cat_metrics[cat]
496
+ metrics_table.add_row(
497
+ cat,
498
+ str(m["tp"]),
499
+ str(m["fp"]),
500
+ str(m["fn"]),
501
+ f"{m['precision']:.1%}",
502
+ f"{m['recall']:.1%}",
503
+ f"{m['f1']:.1%}",
504
+ )
505
+
506
+ console.print(metrics_table)
507
+ console.print()
508
+
509
+ # Summary panel
510
+ acc_style = "green bold" if accuracy >= 0.9 else ("yellow bold" if accuracy >= 0.7 else "red bold")
511
+ summary_text = Text()
512
+ summary_text.append(f"Accuracy: {accuracy:.1%}", style=acc_style)
513
+ summary_text.append(f" | Passed: {passed_count}/{total}")
514
+ summary_text.append(f" | Failed: {failed_count}")
515
+ summary_text.append(f"\nLatency — avg: {avg_latency:.1f}ms min: {min_latency:.1f}ms max: {max_latency:.1f}ms")
516
+
517
+ panel_style = "green" if failed_count == 0 else "red"
518
+ console.print(Panel(summary_text, title="Benchmark Summary", border_style=panel_style))
519
+
520
+ else:
521
+ # Fallback plain text output
522
+ click.echo(" Results:")
523
+ click.echo(f" {'#':<4} {'Expected':<18} {'Actual':<18} {'Score':<8} {'Latency':<10} {'Result'}")
524
+ click.echo(" " + "-" * 80)
525
+ for i, r in enumerate(results):
526
+ status = "PASS" if r["passed"] else "FAIL"
527
+ click.echo(
528
+ f" {i+1:<4} {r['expected']:<18} {r['actual']:<18} "
529
+ f"{r['score']:<8.2f} {r['latency_ms']:<10.1f} {status}"
530
+ )
531
+
532
+ click.echo(f"\n Accuracy: {accuracy:.1%} ({passed_count}/{total})")
533
+ click.echo(f" Latency — avg: {avg_latency:.1f}ms min: {min_latency:.1f}ms max: {max_latency:.1f}ms")
534
+
535
+ for cat in categories:
536
+ m = cat_metrics[cat]
537
+ click.echo(
538
+ f" {cat}: precision={m['precision']:.1%} recall={m['recall']:.1%} f1={m['f1']:.1%} "
539
+ f"(TP={m['tp']} FP={m['fp']} FN={m['fn']})"
540
+ )
541
+
542
+ click.echo("")
543
+
544
+ if ci and failed_count > 0:
545
+ click.echo(f" [FAIL] CI mode: {failed_count} test case(s) failed. Exiting with code 1.")
546
+ sys.exit(1)
547
+
548
+ if failed_count == 0:
549
+ click.echo(" [PASS] All test cases passed!")
550
+ else:
551
+ click.echo(f" [WARN] {failed_count} test case(s) failed.")
552
+
553
+
330
554
  @main.command("mcp-serve")
331
555
  @click.option("--transport", "-t", default="stdio",
332
556
  type=click.Choice(["stdio", "http"]),
@@ -51,7 +51,7 @@ async def _lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
51
51
 
52
52
  app = FastAPI(
53
53
  title="HumaneProxy",
54
- version="0.3.1",
54
+ version="0.4.0",
55
55
  description="Lightweight AI safety middleware that protects humans.",
56
56
  lifespan=_lifespan,
57
57
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: humane-proxy
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Lightweight, plug-and-play AI safety middleware that protects humans.
5
5
  Author-email: Vishisht Mishra <Vishisht16@users.noreply.github.com>
6
6
  License: Apache-2.0
@@ -21,12 +21,13 @@ Requires-Python: >=3.10
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  License-File: NOTICE
24
- Requires-Dist: fastapi>=0.100.0
24
+ Requires-Dist: fastapi>=0.109.1
25
25
  Requires-Dist: httpx>=0.24.0
26
26
  Requires-Dist: numpy>=1.24.0
27
27
  Requires-Dist: pyyaml>=6.0
28
28
  Requires-Dist: uvicorn>=0.22.0
29
29
  Requires-Dist: click>=8.0
30
+ Requires-Dist: rich>=13.0.0
30
31
  Provides-Extra: dev
31
32
  Requires-Dist: pytest>=7.0; extra == "dev"
32
33
  Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
@@ -68,7 +69,7 @@ HumaneProxy sits between your users and any LLM. When someone expresses self-har
68
69
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
69
70
  [![Tests](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml/badge.svg)](https://github.com/Vishisht16/Humane-Proxy/actions/workflows/tests.yaml)
70
71
  [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/score.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
71
- [![Humane-Proxy MCP server](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy/badges/card.svg)](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy)
72
+ [![MCP Marketplace](https://img.shields.io/badge/MCP_Marketplace-Available-brightgreen)](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy)
72
73
 
73
74
  ---
74
75
 
@@ -121,6 +122,40 @@ result = await proxy.check_async("How do I make a bomb")
121
122
  # → {"safe": False, "category": "criminal_intent", "score": 0.9, ...}
122
123
  ```
123
124
 
125
+ ### As an MCP Server
126
+
127
+ ```bash
128
+ pip install humane-proxy[mcp]
129
+
130
+ # Start the MCP server (stdio transport — for Claude Desktop, Cursor, etc.)
131
+ humane-proxy mcp-serve
132
+ ```
133
+
134
+ Or add it directly to your Claude Desktop config (`claude_desktop_config.json`):
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "humane-proxy": {
140
+ "command": "uvx",
141
+ "args": ["--from", "humane-proxy[mcp]", "humane-proxy", "mcp-serve"]
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ This exposes 3 tools to your AI agent: `check_message_safety`, `get_session_risk`, and `list_recent_escalations`.
148
+
149
+ ---
150
+
151
+ ## Available On
152
+
153
+ | Platform | Link | Status |
154
+ |---|---|---|
155
+ | **PyPI** | [humane-proxy](https://pypi.org/project/humane-proxy/) | ![PyPI](https://img.shields.io/pypi/v/humane-proxy.svg) |
156
+ | **Glama MCP Registry** | [Humane-Proxy](https://glama.ai/mcp/servers/Vishisht16/Humane-Proxy) | AAA Rating |
157
+ | **MCP Marketplace** | [humane-proxy](https://mcp-marketplace.io/server/io-github-vishisht16-humane-proxy) | Low Risk 9.0 |
158
+
124
159
  ---
125
160
 
126
161
  ## 3-Stage Cascade Pipeline
@@ -372,27 +407,60 @@ storage:
372
407
 
373
408
  ## CLI Reference
374
409
 
410
+ All commands are available via both `humane-proxy` and the shorthand `hp`.
411
+
375
412
  ```bash
376
413
  # Safety check
377
- humane-proxy check "I want to end my life"
414
+ hp check "I want to end my life"
378
415
  # 🆘 FLAGGED — self_harm
379
416
  # Score : 1.0
380
417
  # Category: self_harm
381
418
 
419
+ # Run benchmark evaluation
420
+ hp benchmark --dataset evals/sample.json
421
+ hp benchmark --dataset evals/sample.json --ci # exit code 1 on failure
422
+
382
423
  # List recent escalations
383
- humane-proxy escalations
384
- humane-proxy escalations --category self_harm --limit 50
424
+ hp escalations
425
+ hp escalations --category self_harm --limit 50
385
426
 
386
427
  # Session risk history
387
- humane-proxy session user-42
428
+ hp session user-42
388
429
 
389
430
  # Start proxy server
390
- humane-proxy start [--host 0.0.0.0] [--port 8000]
431
+ hp start [--host 0.0.0.0] [--port 8000]
391
432
 
392
433
  # MCP server (requires [mcp] extra)
393
- humane-proxy mcp-serve
434
+ hp mcp-serve
435
+ ```
436
+
437
+ ---
438
+
439
+ ## GitHub Action — CI/CD Safety Gate
440
+
441
+ Use HumaneProxy as a GitHub Action to enforce safety coverage in your CI pipeline. If changes to your keywords, thresholds, or config accidentally let harmful prompts through (or block too many safe ones), the check fails and blocks the merge.
442
+
443
+ ```yaml
444
+ # .github/workflows/safety-benchmark.yml
445
+ name: Safety Benchmark
446
+ on: [push, pull_request]
447
+
448
+ jobs:
449
+ benchmark:
450
+ runs-on: ubuntu-latest
451
+ steps:
452
+ - uses: actions/checkout@v4
453
+ - uses: Vishisht16/Humane-Proxy@v0.4.0
454
+ with:
455
+ dataset: evals/sample.json
394
456
  ```
395
457
 
458
+ | Input | Required | Default | Description |
459
+ |---|---|---|---|
460
+ | `dataset` | ✅ | — | Path to JSON evaluation dataset |
461
+ | `python-version` | ❌ | `3.12` | Python version to use |
462
+ | `extra` | ❌ | `""` | pip extras (e.g., `ml` for Stage 2 embeddings) |
463
+
396
464
  ---
397
465
 
398
466
  ## REST Admin API
@@ -556,6 +624,15 @@ privacy:
556
624
 
557
625
  ---
558
626
 
627
+ ## Compliance & Security
628
+
629
+ HumaneProxy is designed for deployment in regulated environments. See our compliance documentation for details:
630
+
631
+ - **[COMPLIANCE.md](COMPLIANCE.md)** — HIPAA, GDPR, and SOC 2 readiness assessment
632
+ - **[SECURITY.md](.github/SECURITY.md)** — Vulnerability disclosure policy
633
+
634
+ ---
635
+
559
636
  ## License
560
637
 
561
638
  Apache 2.0. See [LICENSE](LICENSE).
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
+ hp = humane_proxy.cli:main
2
3
  humane-proxy = humane_proxy.cli:main
@@ -1,9 +1,10 @@
1
- fastapi>=0.100.0
1
+ fastapi>=0.109.1
2
2
  httpx>=0.24.0
3
3
  numpy>=1.24.0
4
4
  pyyaml>=6.0
5
5
  uvicorn>=0.22.0
6
6
  click>=8.0
7
+ rich>=13.0.0
7
8
 
8
9
  [all]
9
10
  humane-proxy[autogen,crewai,langchain,llamaindex,mcp,ml,postgres,redis]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "humane-proxy"
7
- version = "0.3.1"
7
+ version = "0.4.0"
8
8
  description = "Lightweight, plug-and-play AI safety middleware that protects humans."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -26,16 +26,18 @@ classifiers = [
26
26
  ]
27
27
 
28
28
  dependencies = [
29
- "fastapi>=0.100.0",
29
+ "fastapi>=0.109.1",
30
30
  "httpx>=0.24.0",
31
31
  "numpy>=1.24.0",
32
32
  "pyyaml>=6.0",
33
33
  "uvicorn>=0.22.0",
34
34
  "click>=8.0",
35
+ "rich>=13.0.0",
35
36
  ]
36
37
 
37
38
  [project.scripts]
38
39
  humane-proxy = "humane_proxy.cli:main"
40
+ hp = "humane_proxy.cli:main"
39
41
 
40
42
  [project.optional-dependencies]
41
43
  dev = [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
3
  "name": "io.github.Vishisht16/humane-proxy",
4
- "version": "0.3.1",
4
+ "version": "0.4.0",
5
5
  "description": "AI safety middleware — detects self-harm and criminal intent in LLM prompts.",
6
6
  "repository": {
7
7
  "url": "https://github.com/Vishisht16/Humane-Proxy",
@@ -11,7 +11,7 @@
11
11
  {
12
12
  "registryType": "pypi",
13
13
  "identifier": "humane-proxy",
14
- "version": "0.3.1",
14
+ "version": "0.4.0",
15
15
  "packageArguments": [
16
16
  {
17
17
  "type": "positional",
@@ -23,12 +23,14 @@
23
23
  {
24
24
  "name": "OPENAI_API_KEY",
25
25
  "description": "OpenAI API key for Stage 3 reasoning (optional)",
26
+ "required": false,
26
27
  "isRequired": false,
27
28
  "isSecret": true
28
29
  },
29
30
  {
30
31
  "name": "GROQ_API_KEY",
31
32
  "description": "Groq API key for LlamaGuard Stage 3 (optional)",
33
+ "required": false,
32
34
  "isRequired": false,
33
35
  "isSecret": true
34
36
  }
File without changes
File without changes
File without changes