agentmesh-proxy 0.2.1__tar.gz → 0.3.2__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.
- agentmesh_proxy-0.3.2/.dockerignore +20 -0
- agentmesh_proxy-0.3.2/Dockerfile +18 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/PKG-INFO +99 -10
- agentmesh_proxy-0.3.2/PRIVACY.md +39 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/README.md +92 -7
- agentmesh_proxy-0.3.2/agentmesh/cache/__init__.py +1 -0
- agentmesh_proxy-0.3.2/agentmesh/cache/redis_backend.py +184 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/cache/semantic.py +3 -3
- agentmesh_proxy-0.3.2/agentmesh/compliance/pdf_report.py +284 -0
- agentmesh_proxy-0.3.2/agentmesh/integrations/__init__.py +1 -0
- agentmesh_proxy-0.3.2/agentmesh/integrations/saml_handler.py +226 -0
- agentmesh_proxy-0.3.2/agentmesh/integrations/webhooks.py +249 -0
- agentmesh_proxy-0.3.2/agentmesh/monitoring/anomaly_detector.py +236 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/embedder.py +1 -1
- agentmesh_proxy-0.3.2/agentmesh/optimizer/health_monitor.py +190 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/policy/engine.py +10 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/proxy/server.py +175 -3
- agentmesh_proxy-0.3.2/agentmesh/security/injection_detector.py +228 -0
- agentmesh_proxy-0.3.2/agentmesh/security/pii_scanner.py +270 -0
- agentmesh_proxy-0.3.2/agentmesh/security/toxicity_filter.py +178 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/manifest.json +1 -2
- agentmesh_proxy-0.3.2/dashboard_out.txt +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/cookbook.md +2 -2
- agentmesh_proxy-0.3.2/docs/devto-article.md +142 -0
- agentmesh_proxy-0.3.2/docs/linkedin-company-post.md +63 -0
- agentmesh_proxy-0.3.2/docs/linkedin-post.md +67 -0
- agentmesh_proxy-0.3.2/docs/linkedin-profile.md +203 -0
- agentmesh_proxy-0.3.2/docs/medium-article.md +267 -0
- agentmesh_proxy-0.3.2/docs/social-assets/AnilLinkedinProfile_Nov2025.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/author_card.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/devto_cover.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/li_hero.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/m_pipeline.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/sub_cover.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/sub_problem.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/x1_hero.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/x2_benchmark.png +0 -0
- agentmesh_proxy-0.3.2/docs/social-assets/x3_semantic.png +0 -0
- agentmesh_proxy-0.3.2/docs/substack-article.md +71 -0
- agentmesh_proxy-0.3.2/docs/x-thread.md +118 -0
- agentmesh_proxy-0.3.2/examples/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/dashboard_web.py +1 -1
- agentmesh_proxy-0.3.2/generate_store_assets.py +240 -0
- agentmesh_proxy-0.3.2/hf-space/.gitattributes +35 -0
- {agentmesh_proxy-0.2.1/spaces → agentmesh_proxy-0.3.2/hf-space}/README.md +2 -2
- {agentmesh_proxy-0.2.1/spaces → agentmesh_proxy-0.3.2/hf-space}/app.py +8 -12
- agentmesh_proxy-0.3.2/hf-space/requirements.txt +1 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/pyproject.toml +5 -3
- agentmesh_proxy-0.3.2/spaces/README.md +57 -0
- agentmesh_proxy-0.3.2/spaces/app.py +218 -0
- agentmesh_proxy-0.3.2/spaces/requirements.txt +1 -0
- agentmesh_proxy-0.3.2/store_assets/marquee_1400x560.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/promo_small_440x280.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/screenshot_1280x800.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/screenshot_promo_640x400.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/store_icon_128.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/store_icon_from_promo.png +0 -0
- agentmesh_proxy-0.3.2/store_assets/store_icon_from_screenshot.png +0 -0
- agentmesh_proxy-0.3.2/tests/__init__.py +0 -0
- agentmesh_proxy-0.2.1/agentmesh/cache/__init__.py +0 -5
- agentmesh_proxy-0.2.1/agentmesh/integrations/__init__.py +0 -1
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/.github/workflows/ci.yml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/.github/workflows/codeql.yml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/.gitignore +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/CHANGELOG.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/CONTRIBUTING.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/LICENSE +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/SECURITY.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/attribution/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/attribution/chargebacks.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/audit/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/audit/trail.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/bridge/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/bridge/bpmn.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/budget/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/budget/enforcer.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/cli.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/compliance/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/compliance/reporter.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/core.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/events/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/events/bus.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/autogen.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/crewai.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/google_adk.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/haystack.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/langgraph.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/nvidia_nim.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/openai_agents.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/integrations/pydantic_ai.py +0 -0
- {agentmesh_proxy-0.2.1/examples → agentmesh_proxy-0.3.2/agentmesh/monitoring}/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/circuit_breaker.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/compressor.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/cost_optimizer.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/multi_vendor.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/normalizer.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/optimizer/router.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/policy/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/policy/schema.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/proxy/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/proxy/forwarder.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/proxy/middleware.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/quota/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/quota/engine.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/quota/escalation.py +0 -0
- {agentmesh_proxy-0.2.1/tests → agentmesh_proxy-0.3.2/agentmesh/security}/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/server.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/__init__.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/customer_service.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/enterprise.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/fintech.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/healthcare.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/nvidia_nim.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh/templates/research.yaml +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/_metadata/generated_indexed_rulesets/_ruleset1 +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/background/service_worker.js +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/content/interceptor.js +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/content/styles.css +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/generate_icons.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/icons/icon128.png +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/icons/icon16.png +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/icons/icon48.png +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/popup/popup.css +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/popup/popup.html +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/popup/popup.js +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/agentmesh-extension/rules/redirect_rules.json +0 -0
- /agentmesh_proxy-0.2.1/dashboard_err.txt → /agentmesh_proxy-0.3.2/c/357/200/272Usersanilsprojectsagentmeshagentmeshcache__init__.py" +0 -0
- /agentmesh_proxy-0.2.1/dashboard_out.txt → /agentmesh_proxy-0.3.2/dashboard_err.txt +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/architecture.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/blog-how-i-cut-agent-bill-70-percent.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/demo.gif +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/deploying-to-kubernetes.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/getting-started.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/docs/policy-reference.md +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/benchmark.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/dashboard_terminal.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/demo.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/make_demo_gif.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/quickstart.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/simulation.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/examples/test_extension_e2e.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_async.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_attribution.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_cache.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_compliance.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_core.py +0 -0
- {agentmesh_proxy-0.2.1 → agentmesh_proxy-0.3.2}/tests/test_templates.py +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
FROM python:3.11-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
# Install core deps first for layer caching
|
|
6
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
7
|
+
RUN pip install --no-cache-dir "agentmesh-proxy[semantic]==0.2.1"
|
|
8
|
+
|
|
9
|
+
# Copy source (for SDK / CLI usage on top of installed package)
|
|
10
|
+
COPY agentmesh/ ./agentmesh/
|
|
11
|
+
COPY examples/ ./examples/
|
|
12
|
+
|
|
13
|
+
EXPOSE 8080
|
|
14
|
+
|
|
15
|
+
ENV AGENTMESH_HOST=0.0.0.0
|
|
16
|
+
ENV AGENTMESH_PORT=8080
|
|
17
|
+
|
|
18
|
+
CMD ["python", "-m", "agentmesh.cli", "serve", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentmesh-proxy
|
|
3
|
-
Version: 0.2
|
|
4
|
-
Summary: Governance proxy for every AI tool — semantic cache, token quotas, vendor routing,
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Governance proxy for every AI tool — PII/PHI masking, prompt injection detection, anomaly alerts, semantic cache, token quotas, vendor routing, compliance reports
|
|
5
5
|
Project-URL: Homepage, https://github.com/anilatambharii/agentmesh
|
|
6
6
|
Project-URL: Documentation, https://github.com/anilatambharii/agentmesh/tree/main/docs
|
|
7
7
|
Project-URL: Repository, https://github.com/anilatambharii/agentmesh
|
|
@@ -34,7 +34,7 @@ Requires-Dist: pydantic>=2.0
|
|
|
34
34
|
Requires-Dist: pyyaml>=6.0
|
|
35
35
|
Requires-Dist: uvicorn>=0.29
|
|
36
36
|
Provides-Extra: all
|
|
37
|
-
Requires-Dist: agentmesh[compression,crewai,langgraph,openai,otel,semantic]; extra == 'all'
|
|
37
|
+
Requires-Dist: agentmesh[compression,crewai,langgraph,openai,otel,pdf,redis,semantic]; extra == 'all'
|
|
38
38
|
Provides-Extra: compression
|
|
39
39
|
Requires-Dist: llmlingua>=0.2; extra == 'compression'
|
|
40
40
|
Provides-Extra: crewai
|
|
@@ -59,6 +59,10 @@ Requires-Dist: openai>=1.50; extra == 'openai'
|
|
|
59
59
|
Provides-Extra: otel
|
|
60
60
|
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25; extra == 'otel'
|
|
61
61
|
Requires-Dist: opentelemetry-sdk>=1.25; extra == 'otel'
|
|
62
|
+
Provides-Extra: pdf
|
|
63
|
+
Requires-Dist: reportlab>=4.0; extra == 'pdf'
|
|
64
|
+
Provides-Extra: redis
|
|
65
|
+
Requires-Dist: redis>=5.0; extra == 'redis'
|
|
62
66
|
Provides-Extra: semantic
|
|
63
67
|
Requires-Dist: sentence-transformers>=2.6; extra == 'semantic'
|
|
64
68
|
Description-Content-Type: text/markdown
|
|
@@ -74,6 +78,9 @@ Description-Content-Type: text/markdown
|
|
|
74
78
|
[](https://pepy.tech/project/agentmesh-proxy)
|
|
75
79
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
76
80
|
[](https://www.python.org/downloads/)
|
|
81
|
+
[](https://huggingface.co/spaces/AmbhariiLabs/agentmesh)
|
|
82
|
+
|
|
83
|
+
> ⭐ **If AgentMesh saves your team money or unblocks a compliance requirement, a GitHub star helps others find it.** [Star on GitHub →](https://github.com/anilatambharii/agentmesh)
|
|
77
84
|
|
|
78
85
|
---
|
|
79
86
|
|
|
@@ -81,6 +88,88 @@ Description-Content-Type: text/markdown
|
|
|
81
88
|
|
|
82
89
|
---
|
|
83
90
|
|
|
91
|
+
## Built for teams that ship AI at scale
|
|
92
|
+
|
|
93
|
+
| If you're a... | AgentMesh gives you... |
|
|
94
|
+
|---|---|
|
|
95
|
+
| **Platform / AI Infra team** (Google, Meta, NVIDIA, Anthropic) | A drop-in governance sidecar for your internal LLM gateway |
|
|
96
|
+
| **Enterprise CTO / VP Eng** | One policy file that enforces cost caps, compliance, and security across every AI tool your engineers use |
|
|
97
|
+
| **Healthcare / Legal / Finance team** | HIPAA PHI masking + EU AI Act compliance reports out of the box |
|
|
98
|
+
| **FinOps / Finance** | Per-team chargeback reports — know exactly which team spent what on AI |
|
|
99
|
+
| **Security team** | Prompt injection detection + PII scanning + output toxicity filter on every request |
|
|
100
|
+
| **Solo engineer / startup** | 75% cost reduction on day one, zero code changes to your agents |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Enterprise Governance Features
|
|
105
|
+
|
|
106
|
+
AgentMesh ships a complete enterprise security and compliance stack — no third-party SaaS required.
|
|
107
|
+
|
|
108
|
+
| Feature | Module | What it does |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| **PII / PHI / PCI masking** | `agentmesh/security/pii_scanner.py` | Scans every prompt for SSN, credit cards, medical records, AWS keys, JWTs — masks or blocks before the LLM sees them |
|
|
111
|
+
| **Prompt injection detection** | `agentmesh/security/injection_detector.py` | 14 rules covering DAN, roleplay jailbreaks, role confusion, encoding tricks — HIGH risk blocked automatically |
|
|
112
|
+
| **Output toxicity filter** | `agentmesh/security/toxicity_filter.py` | Post-call scan of LLM responses for hate speech, hallucinations, policy leaks, refusal bypasses |
|
|
113
|
+
| **Cost anomaly detection** | `agentmesh/monitoring/anomaly_detector.py` | Sliding-window burn rate, spend spike, runaway agent loop, cache miss flood — fires alerts in real time |
|
|
114
|
+
| **Slack / PagerDuty alerts** | `agentmesh/integrations/webhooks.py` | Fire-and-forget alerts on anomalies, quota blocks, injection detections — never blocks the request path |
|
|
115
|
+
| **Redis distributed cache** | `agentmesh/cache/redis_backend.py` | Shared semantic cache across multiple proxy instances — falls back to in-memory if Redis is unavailable |
|
|
116
|
+
| **SAML / SSO identity** | `agentmesh/integrations/saml_handler.py` | Extracts team/user identity from SAML assertions, OIDC JWTs, or pre-verified proxy headers |
|
|
117
|
+
| **Vendor health monitor** | `agentmesh/optimizer/health_monitor.py` | Per-vendor circuit breaker — automatically routes around degraded APIs |
|
|
118
|
+
| **EU AI Act / HIPAA reports** | `agentmesh/compliance/pdf_report.py` | One-click compliance reports for EU AI Act, HIPAA, SOC2, NIST AI RMF — Markdown and PDF |
|
|
119
|
+
| **Chargeback export** | `agentmesh/attribution/chargebacks.py` | Per-team, per-month, per-model cost attribution — CSV and JSON for internal billing |
|
|
120
|
+
|
|
121
|
+
### Quick config
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from agentmesh.proxy.server import ProxyConfig, build_proxy_app
|
|
125
|
+
|
|
126
|
+
app = build_proxy_app(ProxyConfig(
|
|
127
|
+
vendors=["anthropic", "openai", "google"],
|
|
128
|
+
|
|
129
|
+
# Security
|
|
130
|
+
pii_mode="mask", # "mask" | "redact" | "block"
|
|
131
|
+
block_injections=True, # block HIGH-risk prompt injection
|
|
132
|
+
toxicity_filter=True, # filter harmful LLM output
|
|
133
|
+
|
|
134
|
+
# Monitoring
|
|
135
|
+
anomaly_detection=True,
|
|
136
|
+
slack_webhook="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
|
|
137
|
+
pagerduty_key="YOUR_PD_ROUTING_KEY",
|
|
138
|
+
|
|
139
|
+
# Infrastructure
|
|
140
|
+
redis_url="redis://your-redis:6379/0", # distributed cache
|
|
141
|
+
sso_enabled=True, # JWT/SAML identity extraction
|
|
142
|
+
|
|
143
|
+
# Deterministic mode — temperature=0 per team
|
|
144
|
+
deterministic_teams={"healthcare": "claude-haiku-4-5", "legal": "claude-sonnet-4-6"},
|
|
145
|
+
))
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
New governance response headers:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
X-AgentMesh-PII-Findings: 3 # entities masked in this prompt
|
|
152
|
+
X-AgentMesh-PII-Types: EMAIL,SSN # types detected
|
|
153
|
+
X-AgentMesh-Injection-Risk: high # injection detected (request blocked)
|
|
154
|
+
X-AgentMesh-Toxicity: TOXICITY # output toxicity type
|
|
155
|
+
X-AgentMesh-Toxicity-Action: redacted # redacted | blocked
|
|
156
|
+
X-AgentMesh-Anomaly: RUNAWAY_LOOP
|
|
157
|
+
X-AgentMesh-SSO-Source: jwt # jwt | saml | header
|
|
158
|
+
X-AgentMesh-Deterministic: true
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Compliance report (one line)
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from agentmesh.compliance.pdf_report import ComplianceReporter, Framework
|
|
165
|
+
|
|
166
|
+
reporter = ComplianceReporter(policy=your_policy, audit_trail=your_audit)
|
|
167
|
+
reporter.generate_pdf(Framework.HIPAA, output_path="hipaa_report.pdf")
|
|
168
|
+
reporter.generate_pdf(Framework.EU_AI_ACT, output_path="eu_ai_act_report.pdf")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
84
173
|
## What it does
|
|
85
174
|
|
|
86
175
|
AgentMesh sits between your engineers and every LLM API. It enforces token budgets, semantically caches repeated prompts, and routes calls to the cheapest capable model — without touching a single line of agent code.
|
|
@@ -99,7 +188,7 @@ Your LangGraph / CrewAI / AutoGen agents OpenA
|
|
|
99
188
|
## Benchmark — real numbers, demo mode, no API keys needed
|
|
100
189
|
|
|
101
190
|
```bash
|
|
102
|
-
pip install agentmesh-proxy
|
|
191
|
+
pip install agentmesh-proxy sentence-transformers
|
|
103
192
|
python examples/benchmark.py
|
|
104
193
|
```
|
|
105
194
|
|
|
@@ -318,15 +407,15 @@ Your agents (LangGraph etc.) ─────────────────
|
|
|
318
407
|
┌─────────▼──────────┐
|
|
319
408
|
│ AgentMesh Proxy │
|
|
320
409
|
│ │
|
|
321
|
-
│ 1.
|
|
410
|
+
│ 1. Circuit breaker│ kill runaway loops first
|
|
322
411
|
│ 2. Quota check │ pre-call estimation
|
|
323
|
-
│ 3.
|
|
324
|
-
│ 4.
|
|
412
|
+
│ 3. Exact cache │ SHA-256 → 0 tokens
|
|
413
|
+
│ 4. Semantic cache │ sentence-transformers cosine
|
|
325
414
|
│ 5. Vendor route │ cheapest capable model
|
|
326
|
-
│ 6.
|
|
327
|
-
│ 7. LLM call │
|
|
415
|
+
│ 6. Provider cache │ Anthropic cache_control
|
|
416
|
+
│ 7. LLM call │ only if all caches missed
|
|
328
417
|
│ 8. Cache store │ semantic + exact
|
|
329
|
-
│ 9.
|
|
418
|
+
│ 9. Audit log │ Ed25519 tamper-evident
|
|
330
419
|
└─────────┬──────────┘
|
|
331
420
|
│
|
|
332
421
|
┌─────────────┼──────────────┐
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Privacy Policy — AgentMesh
|
|
2
|
+
|
|
3
|
+
**Last updated: June 2026**
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
AgentMesh does not collect, transmit, or store any personal data on external servers. All data stays on your local machine.
|
|
8
|
+
|
|
9
|
+
## What the Chrome extension does
|
|
10
|
+
|
|
11
|
+
The AgentMesh Chrome extension:
|
|
12
|
+
|
|
13
|
+
- Intercepts prompts you type into ChatGPT, Claude.ai, and Gemini **before** they are sent
|
|
14
|
+
- Forwards those prompts to a **locally running proxy** on your own machine (localhost:8080 by default)
|
|
15
|
+
- Displays governance metadata (cache hit/miss, quota usage, tokens saved) in a popup
|
|
16
|
+
|
|
17
|
+
## Data collected
|
|
18
|
+
|
|
19
|
+
| Data | Where it goes | Stored externally? |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Prompt text | Local proxy only (localhost) | No |
|
|
22
|
+
| Cache hit/miss stats | chrome.storage.local (your browser) | No |
|
|
23
|
+
| Tokens saved / cost saved | chrome.storage.local (your browser) | No |
|
|
24
|
+
| Proxy port setting | chrome.storage.sync (your Google account) | No |
|
|
25
|
+
|
|
26
|
+
## What we do NOT do
|
|
27
|
+
|
|
28
|
+
- We do not send any data to AgentMesh servers (there are none)
|
|
29
|
+
- We do not collect analytics or telemetry
|
|
30
|
+
- We do not sell, share, or transmit any user data to third parties
|
|
31
|
+
- We do not store prompt content beyond the local proxy cache on your machine
|
|
32
|
+
|
|
33
|
+
## Local proxy
|
|
34
|
+
|
|
35
|
+
The AgentMesh proxy runs entirely on your own machine. Prompt data sent to `localhost` never leaves your device unless you explicitly forward it to an LLM API (Anthropic, OpenAI, Google) — the same call your browser would have made anyway.
|
|
36
|
+
|
|
37
|
+
## Contact
|
|
38
|
+
|
|
39
|
+
Questions? Open an issue at [github.com/anilatambharii/agentmesh/issues](https://github.com/anilatambharii/agentmesh/issues) or email anil@ambharii.com.
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
[](https://pepy.tech/project/agentmesh-proxy)
|
|
10
10
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
11
11
|
[](https://www.python.org/downloads/)
|
|
12
|
+
[](https://huggingface.co/spaces/AmbhariiLabs/agentmesh)
|
|
13
|
+
|
|
14
|
+
> ⭐ **If AgentMesh saves your team money or unblocks a compliance requirement, a GitHub star helps others find it.** [Star on GitHub →](https://github.com/anilatambharii/agentmesh)
|
|
12
15
|
|
|
13
16
|
---
|
|
14
17
|
|
|
@@ -16,6 +19,88 @@
|
|
|
16
19
|
|
|
17
20
|
---
|
|
18
21
|
|
|
22
|
+
## Built for teams that ship AI at scale
|
|
23
|
+
|
|
24
|
+
| If you're a... | AgentMesh gives you... |
|
|
25
|
+
|---|---|
|
|
26
|
+
| **Platform / AI Infra team** (Google, Meta, NVIDIA, Anthropic) | A drop-in governance sidecar for your internal LLM gateway |
|
|
27
|
+
| **Enterprise CTO / VP Eng** | One policy file that enforces cost caps, compliance, and security across every AI tool your engineers use |
|
|
28
|
+
| **Healthcare / Legal / Finance team** | HIPAA PHI masking + EU AI Act compliance reports out of the box |
|
|
29
|
+
| **FinOps / Finance** | Per-team chargeback reports — know exactly which team spent what on AI |
|
|
30
|
+
| **Security team** | Prompt injection detection + PII scanning + output toxicity filter on every request |
|
|
31
|
+
| **Solo engineer / startup** | 75% cost reduction on day one, zero code changes to your agents |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Enterprise Governance Features
|
|
36
|
+
|
|
37
|
+
AgentMesh ships a complete enterprise security and compliance stack — no third-party SaaS required.
|
|
38
|
+
|
|
39
|
+
| Feature | Module | What it does |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| **PII / PHI / PCI masking** | `agentmesh/security/pii_scanner.py` | Scans every prompt for SSN, credit cards, medical records, AWS keys, JWTs — masks or blocks before the LLM sees them |
|
|
42
|
+
| **Prompt injection detection** | `agentmesh/security/injection_detector.py` | 14 rules covering DAN, roleplay jailbreaks, role confusion, encoding tricks — HIGH risk blocked automatically |
|
|
43
|
+
| **Output toxicity filter** | `agentmesh/security/toxicity_filter.py` | Post-call scan of LLM responses for hate speech, hallucinations, policy leaks, refusal bypasses |
|
|
44
|
+
| **Cost anomaly detection** | `agentmesh/monitoring/anomaly_detector.py` | Sliding-window burn rate, spend spike, runaway agent loop, cache miss flood — fires alerts in real time |
|
|
45
|
+
| **Slack / PagerDuty alerts** | `agentmesh/integrations/webhooks.py` | Fire-and-forget alerts on anomalies, quota blocks, injection detections — never blocks the request path |
|
|
46
|
+
| **Redis distributed cache** | `agentmesh/cache/redis_backend.py` | Shared semantic cache across multiple proxy instances — falls back to in-memory if Redis is unavailable |
|
|
47
|
+
| **SAML / SSO identity** | `agentmesh/integrations/saml_handler.py` | Extracts team/user identity from SAML assertions, OIDC JWTs, or pre-verified proxy headers |
|
|
48
|
+
| **Vendor health monitor** | `agentmesh/optimizer/health_monitor.py` | Per-vendor circuit breaker — automatically routes around degraded APIs |
|
|
49
|
+
| **EU AI Act / HIPAA reports** | `agentmesh/compliance/pdf_report.py` | One-click compliance reports for EU AI Act, HIPAA, SOC2, NIST AI RMF — Markdown and PDF |
|
|
50
|
+
| **Chargeback export** | `agentmesh/attribution/chargebacks.py` | Per-team, per-month, per-model cost attribution — CSV and JSON for internal billing |
|
|
51
|
+
|
|
52
|
+
### Quick config
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from agentmesh.proxy.server import ProxyConfig, build_proxy_app
|
|
56
|
+
|
|
57
|
+
app = build_proxy_app(ProxyConfig(
|
|
58
|
+
vendors=["anthropic", "openai", "google"],
|
|
59
|
+
|
|
60
|
+
# Security
|
|
61
|
+
pii_mode="mask", # "mask" | "redact" | "block"
|
|
62
|
+
block_injections=True, # block HIGH-risk prompt injection
|
|
63
|
+
toxicity_filter=True, # filter harmful LLM output
|
|
64
|
+
|
|
65
|
+
# Monitoring
|
|
66
|
+
anomaly_detection=True,
|
|
67
|
+
slack_webhook="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
|
|
68
|
+
pagerduty_key="YOUR_PD_ROUTING_KEY",
|
|
69
|
+
|
|
70
|
+
# Infrastructure
|
|
71
|
+
redis_url="redis://your-redis:6379/0", # distributed cache
|
|
72
|
+
sso_enabled=True, # JWT/SAML identity extraction
|
|
73
|
+
|
|
74
|
+
# Deterministic mode — temperature=0 per team
|
|
75
|
+
deterministic_teams={"healthcare": "claude-haiku-4-5", "legal": "claude-sonnet-4-6"},
|
|
76
|
+
))
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
New governance response headers:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
X-AgentMesh-PII-Findings: 3 # entities masked in this prompt
|
|
83
|
+
X-AgentMesh-PII-Types: EMAIL,SSN # types detected
|
|
84
|
+
X-AgentMesh-Injection-Risk: high # injection detected (request blocked)
|
|
85
|
+
X-AgentMesh-Toxicity: TOXICITY # output toxicity type
|
|
86
|
+
X-AgentMesh-Toxicity-Action: redacted # redacted | blocked
|
|
87
|
+
X-AgentMesh-Anomaly: RUNAWAY_LOOP
|
|
88
|
+
X-AgentMesh-SSO-Source: jwt # jwt | saml | header
|
|
89
|
+
X-AgentMesh-Deterministic: true
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Compliance report (one line)
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from agentmesh.compliance.pdf_report import ComplianceReporter, Framework
|
|
96
|
+
|
|
97
|
+
reporter = ComplianceReporter(policy=your_policy, audit_trail=your_audit)
|
|
98
|
+
reporter.generate_pdf(Framework.HIPAA, output_path="hipaa_report.pdf")
|
|
99
|
+
reporter.generate_pdf(Framework.EU_AI_ACT, output_path="eu_ai_act_report.pdf")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
19
104
|
## What it does
|
|
20
105
|
|
|
21
106
|
AgentMesh sits between your engineers and every LLM API. It enforces token budgets, semantically caches repeated prompts, and routes calls to the cheapest capable model — without touching a single line of agent code.
|
|
@@ -34,7 +119,7 @@ Your LangGraph / CrewAI / AutoGen agents OpenA
|
|
|
34
119
|
## Benchmark — real numbers, demo mode, no API keys needed
|
|
35
120
|
|
|
36
121
|
```bash
|
|
37
|
-
pip install agentmesh-proxy
|
|
122
|
+
pip install agentmesh-proxy sentence-transformers
|
|
38
123
|
python examples/benchmark.py
|
|
39
124
|
```
|
|
40
125
|
|
|
@@ -253,15 +338,15 @@ Your agents (LangGraph etc.) ─────────────────
|
|
|
253
338
|
┌─────────▼──────────┐
|
|
254
339
|
│ AgentMesh Proxy │
|
|
255
340
|
│ │
|
|
256
|
-
│ 1.
|
|
341
|
+
│ 1. Circuit breaker│ kill runaway loops first
|
|
257
342
|
│ 2. Quota check │ pre-call estimation
|
|
258
|
-
│ 3.
|
|
259
|
-
│ 4.
|
|
343
|
+
│ 3. Exact cache │ SHA-256 → 0 tokens
|
|
344
|
+
│ 4. Semantic cache │ sentence-transformers cosine
|
|
260
345
|
│ 5. Vendor route │ cheapest capable model
|
|
261
|
-
│ 6.
|
|
262
|
-
│ 7. LLM call │
|
|
346
|
+
│ 6. Provider cache │ Anthropic cache_control
|
|
347
|
+
│ 7. LLM call │ only if all caches missed
|
|
263
348
|
│ 8. Cache store │ semantic + exact
|
|
264
|
-
│ 9.
|
|
349
|
+
│ 9. Audit log │ Ed25519 tamper-evident
|
|
265
350
|
└─────────┬──────────┘
|
|
266
351
|
│
|
|
267
352
|
┌─────────────┼──────────────┐
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Redis Distributed Cache Backend
|
|
3
|
+
|
|
4
|
+
Drop-in replacement for the in-memory CostOptimizer cache.
|
|
5
|
+
Enables shared cache across multiple AgentMesh proxy instances.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- Exact match cache (SHA-256 key → JSON blob)
|
|
9
|
+
- Semantic cache (vector stored as JSON array alongside blob)
|
|
10
|
+
- TTL support (configurable per cache tier)
|
|
11
|
+
- Atomic get+set via Redis pipelines
|
|
12
|
+
- Graceful fallback to in-memory if Redis is unavailable
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
from agentmesh.cache.redis_backend import RedisCache
|
|
16
|
+
|
|
17
|
+
cache = RedisCache(url="redis://localhost:6379/0", ttl_seconds=3600)
|
|
18
|
+
cache.put("my-key", {"content": "Hello"}, model="claude-haiku-4-5", tokens=100)
|
|
19
|
+
hit = cache.get("my-key")
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import hashlib
|
|
25
|
+
import json
|
|
26
|
+
import logging
|
|
27
|
+
import time
|
|
28
|
+
from typing import Any, Dict, Optional, Tuple
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
_REDIS_AVAILABLE = False
|
|
33
|
+
try:
|
|
34
|
+
import redis as _redis
|
|
35
|
+
_REDIS_AVAILABLE = True
|
|
36
|
+
except ImportError:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RedisCache:
|
|
41
|
+
"""
|
|
42
|
+
Redis-backed distributed cache for AgentMesh.
|
|
43
|
+
|
|
44
|
+
Falls back to a local dict if Redis is unavailable so the proxy
|
|
45
|
+
keeps running without a Redis dependency.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
url: Redis URL e.g. "redis://localhost:6379/0"
|
|
49
|
+
or "rediss://user:pass@host:6380/0" for TLS
|
|
50
|
+
ttl_seconds: Default TTL for cache entries (default 3600)
|
|
51
|
+
key_prefix: Namespace prefix for all keys (default "agentmesh:")
|
|
52
|
+
max_local_fallback: In-memory fallback entries when Redis is down
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
url: str = "redis://localhost:6379/0",
|
|
58
|
+
ttl_seconds: int = 3600,
|
|
59
|
+
key_prefix: str = "agentmesh:",
|
|
60
|
+
max_local_fallback: int = 1000,
|
|
61
|
+
):
|
|
62
|
+
self.ttl = ttl_seconds
|
|
63
|
+
self.prefix = key_prefix
|
|
64
|
+
self._local: Dict[str, Any] = {} # fallback
|
|
65
|
+
self._local_ts: Dict[str, float] = {}
|
|
66
|
+
self._max_local = max_local_fallback
|
|
67
|
+
self._client = None
|
|
68
|
+
|
|
69
|
+
if _REDIS_AVAILABLE:
|
|
70
|
+
try:
|
|
71
|
+
self._client = _redis.from_url(
|
|
72
|
+
url, decode_responses=True,
|
|
73
|
+
socket_connect_timeout=2,
|
|
74
|
+
socket_timeout=1,
|
|
75
|
+
)
|
|
76
|
+
self._client.ping()
|
|
77
|
+
logger.info("RedisCache connected to %s", url)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
logger.warning("RedisCache: Redis unavailable (%s) — using local fallback", e)
|
|
80
|
+
self._client = None
|
|
81
|
+
else:
|
|
82
|
+
logger.warning("RedisCache: redis-py not installed. Run: pip install redis")
|
|
83
|
+
|
|
84
|
+
# ── Public API (mirrors CostOptimizer cache interface) ────────────────────
|
|
85
|
+
|
|
86
|
+
def get(self, key: str) -> Optional[dict]:
|
|
87
|
+
"""Return cached response dict or None."""
|
|
88
|
+
rkey = self._rkey(key)
|
|
89
|
+
if self._client:
|
|
90
|
+
try:
|
|
91
|
+
raw = self._client.get(rkey)
|
|
92
|
+
if raw:
|
|
93
|
+
return json.loads(raw)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.debug("Redis get error: %s", e)
|
|
96
|
+
# Fallback
|
|
97
|
+
if key in self._local:
|
|
98
|
+
if time.monotonic() - self._local_ts[key] < self.ttl:
|
|
99
|
+
return self._local[key]
|
|
100
|
+
del self._local[key]
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def put(self, key: str, value: dict, model: str = "", tokens: int = 0) -> None:
|
|
104
|
+
"""Store a response dict with TTL."""
|
|
105
|
+
rkey = self._rkey(key)
|
|
106
|
+
blob = json.dumps(value)
|
|
107
|
+
if self._client:
|
|
108
|
+
try:
|
|
109
|
+
self._client.setex(rkey, self.ttl, blob)
|
|
110
|
+
return
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.debug("Redis put error: %s", e)
|
|
113
|
+
# Fallback — evict oldest if full
|
|
114
|
+
if len(self._local) >= self._max_local:
|
|
115
|
+
oldest = min(self._local_ts, key=self._local_ts.get)
|
|
116
|
+
self._local.pop(oldest, None)
|
|
117
|
+
self._local_ts.pop(oldest, None)
|
|
118
|
+
self._local[key] = value
|
|
119
|
+
self._local_ts[key] = time.monotonic()
|
|
120
|
+
|
|
121
|
+
def get_semantic(self, key: str) -> Optional[Tuple[dict, list]]:
|
|
122
|
+
"""Return (response, embedding_vector) or None."""
|
|
123
|
+
rkey = self._rkey(f"sem:{key}")
|
|
124
|
+
if self._client:
|
|
125
|
+
try:
|
|
126
|
+
raw = self._client.get(rkey)
|
|
127
|
+
if raw:
|
|
128
|
+
data = json.loads(raw)
|
|
129
|
+
return data.get("response"), data.get("embedding", [])
|
|
130
|
+
except Exception as e:
|
|
131
|
+
logger.debug("Redis get_semantic error: %s", e)
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
def put_semantic(self, key: str, response: dict, embedding: list) -> None:
|
|
135
|
+
"""Store a response + its embedding vector."""
|
|
136
|
+
rkey = self._rkey(f"sem:{key}")
|
|
137
|
+
blob = json.dumps({"response": response, "embedding": embedding})
|
|
138
|
+
if self._client:
|
|
139
|
+
try:
|
|
140
|
+
self._client.setex(rkey, self.ttl, blob)
|
|
141
|
+
return
|
|
142
|
+
except Exception as e:
|
|
143
|
+
logger.debug("Redis put_semantic error: %s", e)
|
|
144
|
+
|
|
145
|
+
def invalidate(self, key: str) -> None:
|
|
146
|
+
rkey = self._rkey(key)
|
|
147
|
+
if self._client:
|
|
148
|
+
try:
|
|
149
|
+
self._client.delete(rkey, self._rkey(f"sem:{key}"))
|
|
150
|
+
except Exception:
|
|
151
|
+
pass
|
|
152
|
+
self._local.pop(key, None)
|
|
153
|
+
|
|
154
|
+
def flush(self) -> int:
|
|
155
|
+
"""Clear all AgentMesh keys. Returns count deleted."""
|
|
156
|
+
if self._client:
|
|
157
|
+
try:
|
|
158
|
+
keys = self._client.keys(f"{self.prefix}*")
|
|
159
|
+
if keys:
|
|
160
|
+
return self._client.delete(*keys)
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
n = len(self._local)
|
|
164
|
+
self._local.clear()
|
|
165
|
+
self._local_ts.clear()
|
|
166
|
+
return n
|
|
167
|
+
|
|
168
|
+
def stats(self) -> dict:
|
|
169
|
+
info = {"backend": "redis" if self._client else "local_fallback",
|
|
170
|
+
"local_entries": len(self._local)}
|
|
171
|
+
if self._client:
|
|
172
|
+
try:
|
|
173
|
+
i = self._client.info("memory")
|
|
174
|
+
info["redis_used_memory"] = i.get("used_memory_human", "unknown")
|
|
175
|
+
info["redis_keys"] = self._client.dbsize()
|
|
176
|
+
except Exception:
|
|
177
|
+
pass
|
|
178
|
+
return info
|
|
179
|
+
|
|
180
|
+
# ── Internal ──────────────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
def _rkey(self, key: str) -> str:
|
|
183
|
+
h = hashlib.sha256(key.encode()).hexdigest()[:32]
|
|
184
|
+
return f"{self.prefix}{h}"
|
|
@@ -75,13 +75,13 @@ class SemanticCache:
|
|
|
75
75
|
``embedder`` callable to use OpenAI / Cohere / local embeddings.
|
|
76
76
|
|
|
77
77
|
Args:
|
|
78
|
-
similarity_threshold: Cosine similarity above which a hit is declared (0.
|
|
78
|
+
similarity_threshold: Cosine similarity above which a hit is declared (0.70 for sentence-transformers MiniLM; raise for the char-bigram fallback)
|
|
79
79
|
ttl_seconds: Cache entries expire after this duration
|
|
80
80
|
max_entries: Maximum number of entries to retain (LRU eviction)
|
|
81
81
|
embedder: Optional callable (text) -> List[float] for production embeddings
|
|
82
82
|
|
|
83
83
|
Example:
|
|
84
|
-
cache = SemanticCache(similarity_threshold=0.
|
|
84
|
+
cache = SemanticCache(similarity_threshold=0.70)
|
|
85
85
|
cached = cache.get("What is the capital of France?")
|
|
86
86
|
if cached:
|
|
87
87
|
return cached # free!
|
|
@@ -91,7 +91,7 @@ class SemanticCache:
|
|
|
91
91
|
|
|
92
92
|
def __init__(
|
|
93
93
|
self,
|
|
94
|
-
similarity_threshold: float = 0.
|
|
94
|
+
similarity_threshold: float = 0.70,
|
|
95
95
|
ttl_seconds: int = 3600,
|
|
96
96
|
max_entries: int = 10_000,
|
|
97
97
|
embedder: Optional[Callable[[str], List[float]]] = None,
|