pyveil 0.2.2__tar.gz → 0.2.4__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 (113) hide show
  1. {pyveil-0.2.2 → pyveil-0.2.4}/AGENTS.md +23 -0
  2. {pyveil-0.2.2 → pyveil-0.2.4}/CHANGELOG.md +28 -0
  3. {pyveil-0.2.2 → pyveil-0.2.4}/PKG-INFO +152 -4
  4. {pyveil-0.2.2 → pyveil-0.2.4}/README.md +135 -1
  5. {pyveil-0.2.2 → pyveil-0.2.4}/docs/README.md +3 -0
  6. {pyveil-0.2.2 → pyveil-0.2.4}/docs/cookbook.md +200 -8
  7. {pyveil-0.2.2 → pyveil-0.2.4}/docs/evaluation.html +1 -1
  8. {pyveil-0.2.2 → pyveil-0.2.4}/docs/index.html +16 -1
  9. pyveil-0.2.4/docs/integrations/anthropic.md +136 -0
  10. pyveil-0.2.4/docs/integrations/ollama.md +134 -0
  11. pyveil-0.2.4/docs/integrations/openai.md +136 -0
  12. {pyveil-0.2.2 → pyveil-0.2.4}/docs/llms.txt +9 -0
  13. {pyveil-0.2.2 → pyveil-0.2.4}/docs/manual.html +151 -9
  14. pyveil-0.2.4/docs/release-checklist.md +57 -0
  15. pyveil-0.2.4/examples/anthropic.env.example +9 -0
  16. pyveil-0.2.4/examples/anthropic.example.yaml +12 -0
  17. pyveil-0.2.4/examples/anthropic.py +6 -0
  18. pyveil-0.2.4/examples/ollama.env.example +11 -0
  19. pyveil-0.2.4/examples/ollama.example.yaml +15 -0
  20. pyveil-0.2.4/examples/ollama.py +10 -0
  21. pyveil-0.2.4/examples/openai.env.example +9 -0
  22. pyveil-0.2.4/examples/openai.example.yaml +12 -0
  23. pyveil-0.2.4/examples/openai.py +6 -0
  24. {pyveil-0.2.2 → pyveil-0.2.4}/llms.txt +10 -0
  25. {pyveil-0.2.2 → pyveil-0.2.4}/pyproject.toml +23 -3
  26. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/__init__.py +1 -1
  27. pyveil-0.2.4/pyveil/integrations/_provider.py +356 -0
  28. pyveil-0.2.4/pyveil/integrations/anthropic.py +266 -0
  29. pyveil-0.2.4/pyveil/integrations/ollama.py +450 -0
  30. pyveil-0.2.4/pyveil/integrations/openai.py +254 -0
  31. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.egg-info/PKG-INFO +152 -4
  32. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.egg-info/SOURCES.txt +20 -0
  33. pyveil-0.2.4/pyveil.egg-info/requires.txt +47 -0
  34. pyveil-0.2.4/tests/test_anthropic_example.py +327 -0
  35. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_cli.py +16 -1
  36. pyveil-0.2.4/tests/test_ollama_example.py +381 -0
  37. pyveil-0.2.4/tests/test_openai_example.py +302 -0
  38. pyveil-0.2.4/tests/test_provider_contracts.py +142 -0
  39. pyveil-0.2.2/docs/release-checklist.md +0 -43
  40. pyveil-0.2.2/pyveil.egg-info/requires.txt +0 -24
  41. {pyveil-0.2.2 → pyveil-0.2.4}/CONTRIBUTING.md +0 -0
  42. {pyveil-0.2.2 → pyveil-0.2.4}/LICENSE +0 -0
  43. {pyveil-0.2.2 → pyveil-0.2.4}/MANIFEST.in +0 -0
  44. {pyveil-0.2.2 → pyveil-0.2.4}/SECURITY.md +0 -0
  45. {pyveil-0.2.2 → pyveil-0.2.4}/docs/detector-provenance.md +0 -0
  46. {pyveil-0.2.2 → pyveil-0.2.4}/docs/faq.md +0 -0
  47. {pyveil-0.2.2 → pyveil-0.2.4}/docs/guides/index.html +0 -0
  48. {pyveil-0.2.2 → pyveil-0.2.4}/docs/guides/mcp-pii-redaction.html +0 -0
  49. {pyveil-0.2.2 → pyveil-0.2.4}/docs/guides/python-llm-pii-redaction.html +0 -0
  50. {pyveil-0.2.2 → pyveil-0.2.4}/docs/guides/pyveil-vs-presidio.html +0 -0
  51. {pyveil-0.2.2 → pyveil-0.2.4}/docs/guides/style.css +0 -0
  52. {pyveil-0.2.2 → pyveil-0.2.4}/docs/integrations/logging.md +0 -0
  53. {pyveil-0.2.2 → pyveil-0.2.4}/docs/integrations/mcp.md +0 -0
  54. {pyveil-0.2.2 → pyveil-0.2.4}/docs/integrations/tracing.md +0 -0
  55. {pyveil-0.2.2 → pyveil-0.2.4}/docs/known-limitations.md +0 -0
  56. {pyveil-0.2.2 → pyveil-0.2.4}/docs/media/favicon.svg +0 -0
  57. {pyveil-0.2.2 → pyveil-0.2.4}/docs/media/pyveil-awesome-demo.gif +0 -0
  58. {pyveil-0.2.2 → pyveil-0.2.4}/docs/media/social-preview.html +0 -0
  59. {pyveil-0.2.2 → pyveil-0.2.4}/docs/media/social-preview.png +0 -0
  60. {pyveil-0.2.2 → pyveil-0.2.4}/docs/redaction-reference.md +0 -0
  61. {pyveil-0.2.2 → pyveil-0.2.4}/docs/roadmap.md +0 -0
  62. {pyveil-0.2.2 → pyveil-0.2.4}/docs/robots.txt +0 -0
  63. {pyveil-0.2.2 → pyveil-0.2.4}/docs/sitemap.xml +0 -0
  64. {pyveil-0.2.2 → pyveil-0.2.4}/docs/threat-model.md +0 -0
  65. {pyveil-0.2.2 → pyveil-0.2.4}/evaluation/README.md +0 -0
  66. {pyveil-0.2.2 → pyveil-0.2.4}/evaluation/corpus.json +0 -0
  67. {pyveil-0.2.2 → pyveil-0.2.4}/evaluation/evaluate.py +0 -0
  68. {pyveil-0.2.2 → pyveil-0.2.4}/examples/azure_openai.env.example +0 -0
  69. {pyveil-0.2.2 → pyveil-0.2.4}/examples/azure_openai.example.yaml +0 -0
  70. {pyveil-0.2.2 → pyveil-0.2.4}/examples/azure_openai.py +0 -0
  71. {pyveil-0.2.2 → pyveil-0.2.4}/examples/basic_usage.py +0 -0
  72. {pyveil-0.2.2 → pyveil-0.2.4}/examples/custom_rules.py +0 -0
  73. {pyveil-0.2.2 → pyveil-0.2.4}/examples/fastapi_middleware.py +0 -0
  74. {pyveil-0.2.2 → pyveil-0.2.4}/examples/litellm_proxy_filter.py +0 -0
  75. {pyveil-0.2.2 → pyveil-0.2.4}/examples/llm_client_boundary.py +0 -0
  76. {pyveil-0.2.2 → pyveil-0.2.4}/examples/log_filter.py +0 -0
  77. {pyveil-0.2.2 → pyveil-0.2.4}/examples/mcp_server_wrapper.py +0 -0
  78. {pyveil-0.2.2 → pyveil-0.2.4}/examples/mcp_tool_result.py +0 -0
  79. {pyveil-0.2.2 → pyveil-0.2.4}/examples/memory_write.py +0 -0
  80. {pyveil-0.2.2 → pyveil-0.2.4}/examples/openai_agents_guardrail.py +0 -0
  81. {pyveil-0.2.2 → pyveil-0.2.4}/examples/redact_json.py +0 -0
  82. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/__main__.py +0 -0
  83. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/cli.py +0 -0
  84. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/constants.py +0 -0
  85. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/core.py +0 -0
  86. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/detectors.py +0 -0
  87. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/exceptions.py +0 -0
  88. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/findings.py +0 -0
  89. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/integrations/__init__.py +0 -0
  90. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/integrations/azure_openai.py +0 -0
  91. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/integrations/logging.py +0 -0
  92. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/integrations/mcp.py +0 -0
  93. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/levels.py +0 -0
  94. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/masker.py +0 -0
  95. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/masking.py +0 -0
  96. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/patterns.py +0 -0
  97. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/placeholders.py +0 -0
  98. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/policy.py +0 -0
  99. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/py.typed +0 -0
  100. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/rules.py +0 -0
  101. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil/utils.py +0 -0
  102. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.egg-info/dependency_links.txt +0 -0
  103. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.egg-info/entry_points.txt +0 -0
  104. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.egg-info/top_level.txt +0 -0
  105. {pyveil-0.2.2 → pyveil-0.2.4}/pyveil.yaml +0 -0
  106. {pyveil-0.2.2 → pyveil-0.2.4}/setup.cfg +0 -0
  107. {pyveil-0.2.2 → pyveil-0.2.4}/setup.py +0 -0
  108. {pyveil-0.2.2 → pyveil-0.2.4}/tests/__init__.py +0 -0
  109. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_azure_openai_example.py +0 -0
  110. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_custom_rules.py +0 -0
  111. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_masker.py +0 -0
  112. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_patterns.py +0 -0
  113. {pyveil-0.2.2 → pyveil-0.2.4}/tests/test_utils.py +0 -0
@@ -19,6 +19,10 @@ Do not turn pyveil into a general DLP suite, gateway, Presidio clone, or prompt-
19
19
  - Run CLI demo: `python3 -m pyveil demo`
20
20
  - Run CLI locally: `PYVEIL_SECRET=dev-secret python3 -m pyveil redact <file>`
21
21
  - Run detector evaluation: `python3 evaluation/evaluate.py --check`
22
+ - Run the OpenAI boundary without a key: `PYVEIL_SECRET=dev-secret OPENAI_MODEL=gpt-5.6-luna python3 -m pyveil.integrations.openai --dry-run`
23
+ - Run the Anthropic boundary without a key: `PYVEIL_SECRET=dev-secret ANTHROPIC_MODEL=claude-haiku-4-5 python3 -m pyveil.integrations.anthropic --dry-run`
24
+ - Run the Ollama boundary without a model call: `PYVEIL_SECRET=dev-secret python3 -m pyveil.integrations.ollama --dry-run`
25
+ - Run offline provider SDK contracts: `uv run --extra openai --extra anthropic --extra test pytest tests/test_provider_contracts.py -m provider_contract --no-cov`
22
26
 
23
27
  ## Architecture
24
28
 
@@ -72,6 +76,9 @@ This repository includes files meant for coding agents and LLM readers:
72
76
  - [docs/evaluation.html](docs/evaluation.html)
73
77
  - [docs/guides/](docs/guides/)
74
78
  - [docs/integrations/mcp.md](docs/integrations/mcp.md)
79
+ - [docs/integrations/openai.md](docs/integrations/openai.md)
80
+ - [docs/integrations/anthropic.md](docs/integrations/anthropic.md)
81
+ - [docs/integrations/ollama.md](docs/integrations/ollama.md)
75
82
  - [docs/integrations/logging.md](docs/integrations/logging.md)
76
83
  - [docs/integrations/tracing.md](docs/integrations/tracing.md)
77
84
 
@@ -88,6 +95,9 @@ Examples:
88
95
  - [examples/fastapi_middleware.py](examples/fastapi_middleware.py)
89
96
  - [examples/litellm_proxy_filter.py](examples/litellm_proxy_filter.py)
90
97
  - [examples/azure_openai.py](examples/azure_openai.py)
98
+ - [examples/openai.py](examples/openai.py)
99
+ - [examples/anthropic.py](examples/anthropic.py)
100
+ - [examples/ollama.py](examples/ollama.py)
91
101
 
92
102
  ## Development
93
103
 
@@ -95,8 +105,15 @@ Examples:
95
105
  uv run --extra dev ruff check .
96
106
  uv run --extra dev mypy pyveil tests
97
107
  uv run --extra test pytest
108
+ uv run --extra openai --extra anthropic --extra test \
109
+ pytest tests/test_provider_contracts.py -m provider_contract --no-cov
98
110
  ```
99
111
 
112
+ The dependency-free core is tested on Python 3.8 through 3.14. The current
113
+ official OpenAI and Anthropic SDKs require Python 3.9+, so their serialization
114
+ contract matrix covers Python 3.9 through 3.14. Their keyless dry-runs remain
115
+ usable on Python 3.8 because provider SDK imports happen only for live calls.
116
+
100
117
  Full local release check:
101
118
 
102
119
  ```bash
@@ -104,6 +121,12 @@ for v in 3.8 3.9 3.10 3.11 3.12 3.13 3.14; do
104
121
  UV_PROJECT_ENVIRONMENT="/tmp/pyveil-venv-$v" uv run --python "$v" --extra test pytest -q --disable-warnings --no-cov
105
122
  done
106
123
 
124
+ for v in 3.9 3.10 3.11 3.12 3.13 3.14; do
125
+ UV_PROJECT_ENVIRONMENT="/tmp/pyveil-provider-$v" uv run --python "$v" \
126
+ --extra openai --extra anthropic --extra test \
127
+ pytest tests/test_provider_contracts.py -m provider_contract -q --no-cov
128
+ done
129
+
107
130
  uv run --extra dev python -m build
108
131
  uv run --extra dev python -m twine check dist/*
109
132
  ```
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.4 - 2026-07-16
4
+
5
+ ### Added
6
+
7
+ - Installable OpenAI Responses API and Anthropic Messages API redaction
8
+ templates with env, `.env`, YAML, and keyless dry-run support.
9
+ - Offline contract tests that exercise the official provider SDKs through
10
+ local mock HTTP transports without credentials, network requests, or spend.
11
+ - A Python 3.9 through 3.14 provider-contract CI matrix while preserving the
12
+ dependency-free Python 3.8 through 3.14 core matrix.
13
+
14
+ ## 0.2.3 - 2026-07-16
15
+
16
+ Local Ollama boundary release.
17
+
18
+ ### Added
19
+
20
+ - Installable Ollama chat integration with env, `.env`, and YAML configuration,
21
+ a dry-run boundary, response metrics, and configurable context/keep-alive limits.
22
+ - A tested `qwen3.5:4b` local-model recipe sized for a 16GB Apple silicon Mac.
23
+
24
+ ### Changed
25
+
26
+ - Added an optional `ollama` dependency group while keeping the core package
27
+ dependency-free.
28
+ - Expanded the README, Cookbook, web Manual, and agent-facing navigation with
29
+ a complete local-model request path and measured memory/latency trade-offs.
30
+
3
31
  ## 0.2.2 - 2026-07-15
4
32
 
5
33
  Azure OpenAI adoption release.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyveil
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Local PII and secret redaction for Python LLM apps, AI agents, tool calls, and MCP
5
5
  Author-email: Hyeon Sang Jeon <wingnut0310@gmail.com>
6
6
  Maintainer-email: Hyeon Sang Jeon <wingnut0310@gmail.com>
@@ -36,9 +36,21 @@ Requires-Python: >=3.8
36
36
  Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
38
  Provides-Extra: azure-openai
39
- Requires-Dist: openai>=1.66.0; extra == "azure-openai"
39
+ Requires-Dist: openai<3.0.0,>=1.66.0; extra == "azure-openai"
40
40
  Requires-Dist: python-dotenv>=1.0.0; extra == "azure-openai"
41
41
  Requires-Dist: PyYAML>=6.0.0; extra == "azure-openai"
42
+ Provides-Extra: openai
43
+ Requires-Dist: openai<3.0.0,>=2.45.0; python_version >= "3.9" and extra == "openai"
44
+ Requires-Dist: python-dotenv>=1.0.0; extra == "openai"
45
+ Requires-Dist: PyYAML>=6.0.0; extra == "openai"
46
+ Provides-Extra: anthropic
47
+ Requires-Dist: anthropic<1.0.0,>=0.116.0; python_version >= "3.9" and extra == "anthropic"
48
+ Requires-Dist: python-dotenv>=1.0.0; extra == "anthropic"
49
+ Requires-Dist: PyYAML>=6.0.0; extra == "anthropic"
50
+ Provides-Extra: ollama
51
+ Requires-Dist: ollama<1.0.0,>=0.6.2; extra == "ollama"
52
+ Requires-Dist: python-dotenv>=1.0.0; extra == "ollama"
53
+ Requires-Dist: PyYAML>=6.0.0; extra == "ollama"
42
54
  Provides-Extra: dev
43
55
  Requires-Dist: build>=1.2.0; extra == "dev"
44
56
  Requires-Dist: pytest>=7.0.0; extra == "dev"
@@ -47,7 +59,9 @@ Requires-Dist: black>=23.0.0; extra == "dev"
47
59
  Requires-Dist: ruff>=0.1.0; extra == "dev"
48
60
  Requires-Dist: twine>=5.0.0; extra == "dev"
49
61
  Requires-Dist: mypy>=1.0.0; extra == "dev"
50
- Requires-Dist: openai>=1.66.0; extra == "dev"
62
+ Requires-Dist: ollama<1.0.0,>=0.6.2; extra == "dev"
63
+ Requires-Dist: openai<3.0.0,>=2.45.0; python_version >= "3.9" and extra == "dev"
64
+ Requires-Dist: anthropic<1.0.0,>=0.116.0; python_version >= "3.9" and extra == "dev"
51
65
  Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
52
66
  Requires-Dist: PyYAML>=6.0.0; extra == "dev"
53
67
  Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
@@ -140,6 +154,138 @@ response = call_llm(safe.data) # Your provider SDK call
140
154
  The provider receives the same list and dictionary shape, with sensitive values
141
155
  replaced before serialization or transmission.
142
156
 
157
+ ## OpenAI And Claude: Keyless Contract-Tested Templates
158
+
159
+ Install provider-specific templates without adding either SDK to pyveil's
160
+ zero-dependency core:
161
+
162
+ ```bash
163
+ pip install "pyveil[openai]" # OpenAI Responses API
164
+ pip install "pyveil[anthropic]" # Claude Messages API
165
+ ```
166
+
167
+ Both integrations redact locally at the final SDK boundary and return the exact
168
+ provider input for inspection:
169
+
170
+ ```python
171
+ from pyveil.integrations.openai import ask_openai, load_settings
172
+
173
+ settings = load_settings()
174
+ result = ask_openai(
175
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
176
+ settings,
177
+ )
178
+
179
+ print(result.redacted_input) # exact client.responses.create(...) input
180
+ print(result.output_text)
181
+ ```
182
+
183
+ ```python
184
+ from pyveil.integrations.anthropic import ask_anthropic, load_settings
185
+
186
+ settings = load_settings()
187
+ result = ask_anthropic(
188
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
189
+ settings,
190
+ )
191
+
192
+ print(result.redacted_input) # exact client.messages.create(...) content
193
+ print(result.output_text)
194
+ ```
195
+
196
+ No API key is needed to prove either boundary:
197
+
198
+ ```bash
199
+ PYVEIL_SECRET=docs-demo-secret OPENAI_MODEL=gpt-5.6-luna \
200
+ python -m pyveil.integrations.openai --dry-run
201
+
202
+ PYVEIL_SECRET=docs-demo-secret ANTHROPIC_MODEL=claude-haiku-4-5 \
203
+ python -m pyveil.integrations.anthropic --dry-run
204
+ ```
205
+
206
+ ```text
207
+ sent-to-openai: ... [EMAIL:17c25f8a4fe3] ... [PHONE:3f6dc5a3c9f3].
208
+ sent-to-anthropic: ... [EMAIL:0b77abd1b26b] ... [PHONE:ec56e2456ba2].
209
+ provider-response: skipped (--dry-run)
210
+ ```
211
+
212
+ The repository also exercises the real official SDKs through local mock HTTP
213
+ transports and asserts against the serialized `/v1/responses` and `/v1/messages`
214
+ JSON bodies. These tests use no credentials, make no network requests, and
215
+ cannot incur provider spend. A live paid API call has **not** been claimed.
216
+ Historical provider models are not a free fallback and may be retired; keep the
217
+ model ID configurable and use dry-run or mock contracts for cost-free checks.
218
+
219
+ Current OpenAI and Anthropic SDKs require Python 3.9+. The pyveil core and both
220
+ keyless dry-run paths remain compatible with Python 3.8 through 3.14. Use the
221
+ checked-in [OpenAI guide](docs/integrations/openai.md) and
222
+ [Anthropic / Claude guide](docs/integrations/anthropic.md) for configuration,
223
+ offline verification, and boundary notes.
224
+
225
+ ## Ollama: Local End To End
226
+
227
+ Run a local model behind the same redaction boundary. The optional integration
228
+ uses Ollama's official Python client and defaults to `qwen3.5:4b`, a Q4_K_M
229
+ 4.7B model that fits comfortably on a 16GB Apple silicon Mac with a 4K context:
230
+
231
+ ```bash
232
+ pip install "pyveil[ollama]"
233
+ ollama pull qwen3.5:4b
234
+ ```
235
+
236
+ ```python
237
+ from pyveil.integrations.ollama import ask_ollama, load_settings
238
+
239
+ settings = load_settings() # OLLAMA_* + PYVEIL_* environment variables
240
+ result = ask_ollama(
241
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
242
+ settings,
243
+ )
244
+
245
+ print(result.redacted_input) # The exact prompt sent to Ollama
246
+ print(result.output_text) # The local model response
247
+ ```
248
+
249
+ Prove the boundary without loading a model:
250
+
251
+ ```bash
252
+ PYVEIL_SECRET=docs-demo-secret \
253
+ python -m pyveil.integrations.ollama --dry-run
254
+ ```
255
+
256
+ ```text
257
+ mode: dry-run
258
+ model: qwen3.5:4b
259
+ host: http://127.0.0.1:11434
260
+ sent-to-ollama: Write a one-sentence support follow-up for [EMAIL:71c6727a7fa2] or [PHONE:b4b889df07ce].
261
+ findings: EMAIL=1, PHONE=1
262
+ ollama-response: skipped (--dry-run)
263
+ ```
264
+
265
+ For a live local call, set `PYVEIL_SECRET` and run the module. Configuration
266
+ priority is process environment, `.env`, YAML, then defaults:
267
+
268
+ ```bash
269
+ PYVEIL_SECRET=a-long-random-hmac-secret \
270
+ python -m pyveil.integrations.ollama
271
+
272
+ python -m pyveil.integrations.ollama \
273
+ --config examples/ollama.example.yaml --env-file .env
274
+ ```
275
+
276
+ The checked-in [`.env` template](examples/ollama.env.example) and
277
+ [YAML template](examples/ollama.example.yaml) expose model, host, context,
278
+ output length, temperature, timeout, and keep-alive. pyveil caps the default
279
+ context at 4096 and uses `keep_alive=0`, so one-shot calls release model memory;
280
+ set `OLLAMA_KEEP_ALIVE=5m` for faster repeated calls.
281
+
282
+ Observed on this project's M1 Mac mini with 16GB memory and Ollama 0.31.2:
283
+ `qwen3.5:4b` used about 3.2GB at a 4096-token context, a cold request took
284
+ 8.1 seconds, and a warm request took 1.3 seconds. These are local measurements,
285
+ not portable performance guarantees. See the
286
+ [Ollama integration guide](docs/integrations/ollama.md) for the full setup and
287
+ memory trade-offs.
288
+
143
289
  ## Azure OpenAI: End To End
144
290
 
145
291
  Install the optional Azure example dependencies, then load configuration from
@@ -226,7 +372,7 @@ evaluator:
226
372
  python evaluation/evaluate.py --check
227
373
  ```
228
374
 
229
- For corpus v1, pyveil 0.2.2 matches all 36 expected findings across 39 cases
375
+ For corpus v1, pyveil 0.2.4 matches all 36 expected findings across 39 cases
230
376
  (33 positive, 6 negative), with no corpus false positives, false negatives,
231
377
  labeled-value leaks, or non-empty `Finding.raw` values.
232
378
 
@@ -368,6 +514,8 @@ is parsed and traversed structurally.
368
514
  | --- | --- |
369
515
  | Any LLM provider | [Provider-neutral client wrapper](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/llm_client_boundary.py) |
370
516
  | OpenAI Agents SDK | [Input guardrail example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/openai_agents_guardrail.py) |
517
+ | OpenAI Responses API | [Installable integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/openai.py) and [keyless contract guide](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/openai.md) |
518
+ | Anthropic / Claude | [Installable integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/anthropic.py) and [keyless contract guide](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/anthropic.md) |
371
519
  | Azure OpenAI | [Runnable env/YAML integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/azure_openai.py) and [short example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/azure_openai.py) |
372
520
  | LiteLLM | [Proxy filter example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/litellm_proxy_filter.py) |
373
521
  | FastAPI | [Request middleware example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/fastapi_middleware.py) |
@@ -81,6 +81,138 @@ response = call_llm(safe.data) # Your provider SDK call
81
81
  The provider receives the same list and dictionary shape, with sensitive values
82
82
  replaced before serialization or transmission.
83
83
 
84
+ ## OpenAI And Claude: Keyless Contract-Tested Templates
85
+
86
+ Install provider-specific templates without adding either SDK to pyveil's
87
+ zero-dependency core:
88
+
89
+ ```bash
90
+ pip install "pyveil[openai]" # OpenAI Responses API
91
+ pip install "pyveil[anthropic]" # Claude Messages API
92
+ ```
93
+
94
+ Both integrations redact locally at the final SDK boundary and return the exact
95
+ provider input for inspection:
96
+
97
+ ```python
98
+ from pyveil.integrations.openai import ask_openai, load_settings
99
+
100
+ settings = load_settings()
101
+ result = ask_openai(
102
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
103
+ settings,
104
+ )
105
+
106
+ print(result.redacted_input) # exact client.responses.create(...) input
107
+ print(result.output_text)
108
+ ```
109
+
110
+ ```python
111
+ from pyveil.integrations.anthropic import ask_anthropic, load_settings
112
+
113
+ settings = load_settings()
114
+ result = ask_anthropic(
115
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
116
+ settings,
117
+ )
118
+
119
+ print(result.redacted_input) # exact client.messages.create(...) content
120
+ print(result.output_text)
121
+ ```
122
+
123
+ No API key is needed to prove either boundary:
124
+
125
+ ```bash
126
+ PYVEIL_SECRET=docs-demo-secret OPENAI_MODEL=gpt-5.6-luna \
127
+ python -m pyveil.integrations.openai --dry-run
128
+
129
+ PYVEIL_SECRET=docs-demo-secret ANTHROPIC_MODEL=claude-haiku-4-5 \
130
+ python -m pyveil.integrations.anthropic --dry-run
131
+ ```
132
+
133
+ ```text
134
+ sent-to-openai: ... [EMAIL:17c25f8a4fe3] ... [PHONE:3f6dc5a3c9f3].
135
+ sent-to-anthropic: ... [EMAIL:0b77abd1b26b] ... [PHONE:ec56e2456ba2].
136
+ provider-response: skipped (--dry-run)
137
+ ```
138
+
139
+ The repository also exercises the real official SDKs through local mock HTTP
140
+ transports and asserts against the serialized `/v1/responses` and `/v1/messages`
141
+ JSON bodies. These tests use no credentials, make no network requests, and
142
+ cannot incur provider spend. A live paid API call has **not** been claimed.
143
+ Historical provider models are not a free fallback and may be retired; keep the
144
+ model ID configurable and use dry-run or mock contracts for cost-free checks.
145
+
146
+ Current OpenAI and Anthropic SDKs require Python 3.9+. The pyveil core and both
147
+ keyless dry-run paths remain compatible with Python 3.8 through 3.14. Use the
148
+ checked-in [OpenAI guide](docs/integrations/openai.md) and
149
+ [Anthropic / Claude guide](docs/integrations/anthropic.md) for configuration,
150
+ offline verification, and boundary notes.
151
+
152
+ ## Ollama: Local End To End
153
+
154
+ Run a local model behind the same redaction boundary. The optional integration
155
+ uses Ollama's official Python client and defaults to `qwen3.5:4b`, a Q4_K_M
156
+ 4.7B model that fits comfortably on a 16GB Apple silicon Mac with a 4K context:
157
+
158
+ ```bash
159
+ pip install "pyveil[ollama]"
160
+ ollama pull qwen3.5:4b
161
+ ```
162
+
163
+ ```python
164
+ from pyveil.integrations.ollama import ask_ollama, load_settings
165
+
166
+ settings = load_settings() # OLLAMA_* + PYVEIL_* environment variables
167
+ result = ask_ollama(
168
+ "Write a follow-up for alice@example.com or 010-1234-5678.",
169
+ settings,
170
+ )
171
+
172
+ print(result.redacted_input) # The exact prompt sent to Ollama
173
+ print(result.output_text) # The local model response
174
+ ```
175
+
176
+ Prove the boundary without loading a model:
177
+
178
+ ```bash
179
+ PYVEIL_SECRET=docs-demo-secret \
180
+ python -m pyveil.integrations.ollama --dry-run
181
+ ```
182
+
183
+ ```text
184
+ mode: dry-run
185
+ model: qwen3.5:4b
186
+ host: http://127.0.0.1:11434
187
+ sent-to-ollama: Write a one-sentence support follow-up for [EMAIL:71c6727a7fa2] or [PHONE:b4b889df07ce].
188
+ findings: EMAIL=1, PHONE=1
189
+ ollama-response: skipped (--dry-run)
190
+ ```
191
+
192
+ For a live local call, set `PYVEIL_SECRET` and run the module. Configuration
193
+ priority is process environment, `.env`, YAML, then defaults:
194
+
195
+ ```bash
196
+ PYVEIL_SECRET=a-long-random-hmac-secret \
197
+ python -m pyveil.integrations.ollama
198
+
199
+ python -m pyveil.integrations.ollama \
200
+ --config examples/ollama.example.yaml --env-file .env
201
+ ```
202
+
203
+ The checked-in [`.env` template](examples/ollama.env.example) and
204
+ [YAML template](examples/ollama.example.yaml) expose model, host, context,
205
+ output length, temperature, timeout, and keep-alive. pyveil caps the default
206
+ context at 4096 and uses `keep_alive=0`, so one-shot calls release model memory;
207
+ set `OLLAMA_KEEP_ALIVE=5m` for faster repeated calls.
208
+
209
+ Observed on this project's M1 Mac mini with 16GB memory and Ollama 0.31.2:
210
+ `qwen3.5:4b` used about 3.2GB at a 4096-token context, a cold request took
211
+ 8.1 seconds, and a warm request took 1.3 seconds. These are local measurements,
212
+ not portable performance guarantees. See the
213
+ [Ollama integration guide](docs/integrations/ollama.md) for the full setup and
214
+ memory trade-offs.
215
+
84
216
  ## Azure OpenAI: End To End
85
217
 
86
218
  Install the optional Azure example dependencies, then load configuration from
@@ -167,7 +299,7 @@ evaluator:
167
299
  python evaluation/evaluate.py --check
168
300
  ```
169
301
 
170
- For corpus v1, pyveil 0.2.2 matches all 36 expected findings across 39 cases
302
+ For corpus v1, pyveil 0.2.4 matches all 36 expected findings across 39 cases
171
303
  (33 positive, 6 negative), with no corpus false positives, false negatives,
172
304
  labeled-value leaks, or non-empty `Finding.raw` values.
173
305
 
@@ -309,6 +441,8 @@ is parsed and traversed structurally.
309
441
  | --- | --- |
310
442
  | Any LLM provider | [Provider-neutral client wrapper](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/llm_client_boundary.py) |
311
443
  | OpenAI Agents SDK | [Input guardrail example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/openai_agents_guardrail.py) |
444
+ | OpenAI Responses API | [Installable integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/openai.py) and [keyless contract guide](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/openai.md) |
445
+ | Anthropic / Claude | [Installable integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/anthropic.py) and [keyless contract guide](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/anthropic.md) |
312
446
  | Azure OpenAI | [Runnable env/YAML integration](https://github.com/hyeonsangjeon/pyveil/blob/main/pyveil/integrations/azure_openai.py) and [short example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/azure_openai.py) |
313
447
  | LiteLLM | [Proxy filter example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/litellm_proxy_filter.py) |
314
448
  | FastAPI | [Request middleware example](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/fastapi_middleware.py) |
@@ -12,6 +12,9 @@ Start with:
12
12
  - [Threat model](threat-model.md)
13
13
  - [FAQ](faq.md)
14
14
  - [Cookbook](cookbook.md)
15
+ - [OpenAI keyless and live integration](integrations/openai.md)
16
+ - [Anthropic / Claude keyless and live integration](integrations/anthropic.md)
17
+ - [Ollama local-model integration](integrations/ollama.md)
15
18
  - [Azure OpenAI env/YAML integration](../pyveil/integrations/azure_openai.py)
16
19
  - [Redaction reference](redaction-reference.md)
17
20
  - [Known limitations](known-limitations.md)