needlepath 0.2.2__tar.gz → 0.2.3__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.
- {needlepath-0.2.2 → needlepath-0.2.3}/CHANGELOG.md +42 -10
- {needlepath-0.2.2 → needlepath-0.2.3}/PKG-INFO +70 -20
- {needlepath-0.2.2 → needlepath-0.2.3}/README.md +69 -19
- {needlepath-0.2.2 → needlepath-0.2.3}/pyproject.toml +1 -1
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/__init__.py +6 -4
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/client.py +200 -29
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/errors.py +13 -4
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/features.py +5 -3
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/result.py +96 -11
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/version.py +1 -1
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_fail_open.py +151 -0
- needlepath-0.2.3/tests/test_guardrails.py +326 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_system_one_adapter.py +6 -6
- {needlepath-0.2.2 → needlepath-0.2.3}/.gitignore +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/LICENSE +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/integrations/__init__.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/integrations/system_one.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/models.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/py.typed +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/testing.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/src/needlepath/transport.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_async_parity.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_config_and_guards.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_live_endpoint.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_no_secret_leak.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_r4_contract.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_retries.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_shadow_mode.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_simple_shape.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_urllib_transport.py +0 -0
- {needlepath-0.2.2 → needlepath-0.2.3}/tests/test_wire_compatibility.py +0 -0
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
## 0.2.2
|
|
2
|
-
|
|
3
|
-
### Changed
|
|
4
|
-
|
|
5
|
-
- First published build carrying the `sanitized_fallback` and `blocked`
|
|
6
|
-
security-screening outcomes, `security_mode` on requests and the
|
|
7
|
-
`security_action` receipt field (see the API release notes). 0.2.1 predates
|
|
8
|
-
them and classifies a screened fallback as `selection_unsafe`.
|
|
9
|
-
|
|
10
1
|
# Changelog
|
|
11
2
|
|
|
12
3
|
All notable changes to the `needlepath` Python package are documented here.
|
|
@@ -14,7 +5,48 @@ All notable changes to the `needlepath` Python package are documented here.
|
|
|
14
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
15
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
16
7
|
|
|
17
|
-
## [
|
|
8
|
+
## [0.2.3] - 2026-11-04
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`outcome: blocked` is applied, never passed through.** A governed
|
|
13
|
+
workspace answers a record its policy withholds with top-level
|
|
14
|
+
`outcome: "blocked"`, zero records, an empty render and a `governance`
|
|
15
|
+
block. By shape that is an empty selection, and `classify` returned
|
|
16
|
+
`EMPTY_SELECTION`, a passthrough, so every adapter delivered the withheld
|
|
17
|
+
record. `classify` now reads `blocked` first and returns `Reason.BLOCKED`,
|
|
18
|
+
an applied result with nothing to deliver: adapters install the verdict (a
|
|
19
|
+
notice, a placeholder, or no context) and never the original. Benign, not a
|
|
20
|
+
failure. A blocked verdict is enforced in shadow mode too: shadow never
|
|
21
|
+
restores a withheld record, so the result stays `reason: blocked`,
|
|
22
|
+
`applied: true` with `shadow: true`, `outcome` and `governance` on the
|
|
23
|
+
receipt.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **Workspace guardrails.** `NeedlepathGuardrailError`, raised when the
|
|
28
|
+
service answers `guardrails_unavailable`, when a `governance` block is
|
|
29
|
+
malformed, or when a protected delivery (workspace policies applied,
|
|
30
|
+
raw-context fallback forbidden) cannot be applied. `guardrails_required=True`
|
|
31
|
+
on either client additionally stops on transport errors, timeouts and
|
|
32
|
+
missing enforcement evidence; it is never sent on the wire. A protected
|
|
33
|
+
delivery is applied even in shadow mode and cannot be `declined()` back to
|
|
34
|
+
the original. A blocked verdict is the exception on purpose: it is applied
|
|
35
|
+
as an empty delivery and never raises.
|
|
36
|
+
- **`SelectionResult.metadata()` carries the whole receipt.** `outcome`,
|
|
37
|
+
`security_action`, `usage` and `governance` are now part of the
|
|
38
|
+
metadata-only receipt, verbatim and only when the response has them, so an
|
|
39
|
+
adapter that writes nothing but `metadata()` still shows what the engine
|
|
40
|
+
decided, what it billed and what its policies withheld.
|
|
41
|
+
|
|
42
|
+
## [0.2.2] - 2026-11-03
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- First published build carrying the `sanitized_fallback` and `blocked`
|
|
47
|
+
security-screening outcomes, `security_mode` on requests and the
|
|
48
|
+
`security_action` receipt field (see the API release notes). 0.2.1 predates
|
|
49
|
+
them and classifies a screened fallback as `selection_unsafe`.
|
|
18
50
|
|
|
19
51
|
### Added
|
|
20
52
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: needlepath
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Framework-free client for the Needlepath hosted context-selection service.
|
|
5
5
|
Project-URL: Homepage, https://nextmoca.com
|
|
6
6
|
Author: Next Moca Global, Inc.
|
|
@@ -72,8 +72,51 @@ result = client.select(
|
|
|
72
72
|
context = result.rendered_context if result.applied else my_original_context
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
original context.
|
|
75
|
+
Ordinary unprotected failures return `result.applied=False`, allowing your
|
|
76
|
+
original context. A record your workspace policy withholds comes back as
|
|
77
|
+
`result.reason == "blocked"` with `result.applied=True` and an empty
|
|
78
|
+
`rendered_context`: the verdict is "deliver nothing from these records", and
|
|
79
|
+
that is what you install. Workspace guardrail failures (the service could not
|
|
80
|
+
enforce, or returned a protected response that cannot be applied) raise
|
|
81
|
+
`NeedlepathGuardrailError`; stop the model request instead of substituting the
|
|
82
|
+
original context.
|
|
83
|
+
|
|
84
|
+
### Workspace guardrails
|
|
85
|
+
|
|
86
|
+
The framework integrations (LangChain/LangGraph, Strands, LiteLLM and
|
|
87
|
+
LlamaIndex) install a blocked verdict as a withheld notice in place of the
|
|
88
|
+
record, or as no context, and let the agent continue; they propagate
|
|
89
|
+
`NeedlepathGuardrailError` rather than falling back to the original.
|
|
90
|
+
`guardrails_required` is a core-client option: pass a client you constructed
|
|
91
|
+
with it to the integration.
|
|
92
|
+
|
|
93
|
+
For a workspace with guardrails, update the SDK and construct either the sync
|
|
94
|
+
or async client with `guardrails_required=True`:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
client = NeedlepathClient(
|
|
98
|
+
operating_point="np-2026-08-r4",
|
|
99
|
+
guardrails_required=True,
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This local fallback setting is never sent to the server and cannot disable
|
|
104
|
+
workspace policies. It stops on transport errors, timeouts, invalid requests,
|
|
105
|
+
and missing or malformed enforcement evidence. An authoritative admin pause
|
|
106
|
+
(`enabled=False`) or active configuration with zero policies is honored.
|
|
107
|
+
|
|
108
|
+
Regardless of this setting, invalid governance metadata or
|
|
109
|
+
`guardrails_unavailable` raises a sanitized `NeedlepathGuardrailError`. A
|
|
110
|
+
blocked response never raises: it is applied as an empty delivery
|
|
111
|
+
(`reason: "blocked"`), in shadow mode too, and the receipt's `governance`
|
|
112
|
+
block says what was withheld and under which policy revision.
|
|
113
|
+
When the server forbids raw-context fallback, only its permitted selected
|
|
114
|
+
context is applied, including in shadow mode and after engine recovery.
|
|
115
|
+
`result.declined(...)` cannot restore the original context for a protected
|
|
116
|
+
response. Do not catch a guardrail exception or a response rewrite error and
|
|
117
|
+
continue with raw records. Existing clients
|
|
118
|
+
must update and enable this setting to stop safely when an outage prevents
|
|
119
|
+
the server from returning any enforcement evidence.
|
|
77
120
|
|
|
78
121
|
### Async
|
|
79
122
|
|
|
@@ -134,6 +177,7 @@ Do not send prompts, context, model output, answers, or free-form notes.
|
|
|
134
177
|
| `max_retries` | — | `2` |
|
|
135
178
|
| `max_request_bytes` | — | `6 * 1024 * 1024` |
|
|
136
179
|
| `shadow` | — | `False` |
|
|
180
|
+
| `guardrails_required` | — | `False` |
|
|
137
181
|
|
|
138
182
|
The base URL is a **documented default, not a hard-coded one**: a durable custom
|
|
139
183
|
domain replaces it, and swapping it is a config change rather than a release.
|
|
@@ -143,12 +187,13 @@ constraint; loopback is exempt so the localhost benchmark adapter still works.
|
|
|
143
187
|
|
|
144
188
|
## The four binding rules, and where they live
|
|
145
189
|
|
|
146
|
-
### 1. Fail open
|
|
190
|
+
### 1. Fail open for ordinary unprotected requests
|
|
147
191
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
192
|
+
With the default configuration and no workspace protection evidence, a timeout,
|
|
193
|
+
5xx, violated contract, empty selection, or stood-down gate returns a
|
|
194
|
+
`SelectionResult` with `applied=False`, the exception on `.error`, and a
|
|
195
|
+
machine-readable `.reason`. The workspace guardrail contract above takes
|
|
196
|
+
precedence over these optimization fallbacks.
|
|
152
197
|
|
|
153
198
|
```python
|
|
154
199
|
if not result.applied:
|
|
@@ -178,18 +223,19 @@ Treat an unrecognized reason as "do not apply". `result.failed` separates the
|
|
|
178
223
|
error paths from the benign declines, which is the distinction that decides
|
|
179
224
|
whether a passthrough deserves a `WARNING` or a `DEBUG`.
|
|
180
225
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
226
|
+
An ordinary empty selection degrades to passthrough. A blocked verdict is
|
|
227
|
+
applied as an empty delivery (`reason: "blocked"`, `applied=True`), never a
|
|
228
|
+
passthrough and never an exception. An empty selection under workspace
|
|
229
|
+
protection that is not a blocked verdict raises and must stop the model request.
|
|
184
230
|
|
|
185
|
-
**`select_or_raise()` exists** for
|
|
186
|
-
|
|
187
|
-
|
|
231
|
+
**`select_or_raise()` exists** for diagnostics and benchmarks that must not
|
|
232
|
+
silently substitute a passthrough for a measurement. Framework adapters use
|
|
233
|
+
`select()` with its explicit guardrail exception contract.
|
|
188
234
|
|
|
189
235
|
### 2. Pin the operating point
|
|
190
236
|
|
|
191
|
-
`operating_point` is required at construction
|
|
192
|
-
|
|
237
|
+
`operating_point` is required at construction; an invalid configuration raises.
|
|
238
|
+
Failing open on an ordinary unprotected bad request is degradation a
|
|
193
239
|
customer absorbs; failing open on "no operating point was pinned" accepts
|
|
194
240
|
exactly the behaviour drift the rule exists to prevent. It fails at wire-up,
|
|
195
241
|
never under load.
|
|
@@ -215,10 +261,14 @@ that passes at 5.99 MB can still be rejected upstream. Lower
|
|
|
215
261
|
client = NeedlepathClient(operating_point="np-2026-08-r4", shadow=True)
|
|
216
262
|
```
|
|
217
263
|
|
|
218
|
-
The call is made exactly as a live call would be
|
|
219
|
-
operating point
|
|
220
|
-
|
|
221
|
-
|
|
264
|
+
The call is made exactly as a live call would be, with the same body, billing,
|
|
265
|
+
and operating point. Ordinary unprotected selections are reported without
|
|
266
|
+
being applied (`reason: "shadow"`). A blocked verdict is enforced in shadow
|
|
267
|
+
mode too: shadow never restores a withheld record, so the result stays
|
|
268
|
+
`reason: "blocked"`, `applied=True`, with `shadow: true`, `outcome` and
|
|
269
|
+
`governance` on the receipt. A protected delivery likewise takes precedence:
|
|
270
|
+
only its permitted selected context may be used, or the request stops with
|
|
271
|
+
`NeedlepathGuardrailError`.
|
|
222
272
|
|
|
223
273
|
`budget.mode = "shadow"` is **not on the wire yet**. `BudgetSpec.mode` on the
|
|
224
274
|
published contract accepts `fixed` and `adaptive` only; adding `shadow` is a
|
|
@@ -43,8 +43,51 @@ result = client.select(
|
|
|
43
43
|
context = result.rendered_context if result.applied else my_original_context
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
original context.
|
|
46
|
+
Ordinary unprotected failures return `result.applied=False`, allowing your
|
|
47
|
+
original context. A record your workspace policy withholds comes back as
|
|
48
|
+
`result.reason == "blocked"` with `result.applied=True` and an empty
|
|
49
|
+
`rendered_context`: the verdict is "deliver nothing from these records", and
|
|
50
|
+
that is what you install. Workspace guardrail failures (the service could not
|
|
51
|
+
enforce, or returned a protected response that cannot be applied) raise
|
|
52
|
+
`NeedlepathGuardrailError`; stop the model request instead of substituting the
|
|
53
|
+
original context.
|
|
54
|
+
|
|
55
|
+
### Workspace guardrails
|
|
56
|
+
|
|
57
|
+
The framework integrations (LangChain/LangGraph, Strands, LiteLLM and
|
|
58
|
+
LlamaIndex) install a blocked verdict as a withheld notice in place of the
|
|
59
|
+
record, or as no context, and let the agent continue; they propagate
|
|
60
|
+
`NeedlepathGuardrailError` rather than falling back to the original.
|
|
61
|
+
`guardrails_required` is a core-client option: pass a client you constructed
|
|
62
|
+
with it to the integration.
|
|
63
|
+
|
|
64
|
+
For a workspace with guardrails, update the SDK and construct either the sync
|
|
65
|
+
or async client with `guardrails_required=True`:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
client = NeedlepathClient(
|
|
69
|
+
operating_point="np-2026-08-r4",
|
|
70
|
+
guardrails_required=True,
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This local fallback setting is never sent to the server and cannot disable
|
|
75
|
+
workspace policies. It stops on transport errors, timeouts, invalid requests,
|
|
76
|
+
and missing or malformed enforcement evidence. An authoritative admin pause
|
|
77
|
+
(`enabled=False`) or active configuration with zero policies is honored.
|
|
78
|
+
|
|
79
|
+
Regardless of this setting, invalid governance metadata or
|
|
80
|
+
`guardrails_unavailable` raises a sanitized `NeedlepathGuardrailError`. A
|
|
81
|
+
blocked response never raises: it is applied as an empty delivery
|
|
82
|
+
(`reason: "blocked"`), in shadow mode too, and the receipt's `governance`
|
|
83
|
+
block says what was withheld and under which policy revision.
|
|
84
|
+
When the server forbids raw-context fallback, only its permitted selected
|
|
85
|
+
context is applied, including in shadow mode and after engine recovery.
|
|
86
|
+
`result.declined(...)` cannot restore the original context for a protected
|
|
87
|
+
response. Do not catch a guardrail exception or a response rewrite error and
|
|
88
|
+
continue with raw records. Existing clients
|
|
89
|
+
must update and enable this setting to stop safely when an outage prevents
|
|
90
|
+
the server from returning any enforcement evidence.
|
|
48
91
|
|
|
49
92
|
### Async
|
|
50
93
|
|
|
@@ -105,6 +148,7 @@ Do not send prompts, context, model output, answers, or free-form notes.
|
|
|
105
148
|
| `max_retries` | — | `2` |
|
|
106
149
|
| `max_request_bytes` | — | `6 * 1024 * 1024` |
|
|
107
150
|
| `shadow` | — | `False` |
|
|
151
|
+
| `guardrails_required` | — | `False` |
|
|
108
152
|
|
|
109
153
|
The base URL is a **documented default, not a hard-coded one**: a durable custom
|
|
110
154
|
domain replaces it, and swapping it is a config change rather than a release.
|
|
@@ -114,12 +158,13 @@ constraint; loopback is exempt so the localhost benchmark adapter still works.
|
|
|
114
158
|
|
|
115
159
|
## The four binding rules, and where they live
|
|
116
160
|
|
|
117
|
-
### 1. Fail open
|
|
161
|
+
### 1. Fail open for ordinary unprotected requests
|
|
118
162
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
163
|
+
With the default configuration and no workspace protection evidence, a timeout,
|
|
164
|
+
5xx, violated contract, empty selection, or stood-down gate returns a
|
|
165
|
+
`SelectionResult` with `applied=False`, the exception on `.error`, and a
|
|
166
|
+
machine-readable `.reason`. The workspace guardrail contract above takes
|
|
167
|
+
precedence over these optimization fallbacks.
|
|
123
168
|
|
|
124
169
|
```python
|
|
125
170
|
if not result.applied:
|
|
@@ -149,18 +194,19 @@ Treat an unrecognized reason as "do not apply". `result.failed` separates the
|
|
|
149
194
|
error paths from the benign declines, which is the distinction that decides
|
|
150
195
|
whether a passthrough deserves a `WARNING` or a `DEBUG`.
|
|
151
196
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
197
|
+
An ordinary empty selection degrades to passthrough. A blocked verdict is
|
|
198
|
+
applied as an empty delivery (`reason: "blocked"`, `applied=True`), never a
|
|
199
|
+
passthrough and never an exception. An empty selection under workspace
|
|
200
|
+
protection that is not a blocked verdict raises and must stop the model request.
|
|
155
201
|
|
|
156
|
-
**`select_or_raise()` exists** for
|
|
157
|
-
|
|
158
|
-
|
|
202
|
+
**`select_or_raise()` exists** for diagnostics and benchmarks that must not
|
|
203
|
+
silently substitute a passthrough for a measurement. Framework adapters use
|
|
204
|
+
`select()` with its explicit guardrail exception contract.
|
|
159
205
|
|
|
160
206
|
### 2. Pin the operating point
|
|
161
207
|
|
|
162
|
-
`operating_point` is required at construction
|
|
163
|
-
|
|
208
|
+
`operating_point` is required at construction; an invalid configuration raises.
|
|
209
|
+
Failing open on an ordinary unprotected bad request is degradation a
|
|
164
210
|
customer absorbs; failing open on "no operating point was pinned" accepts
|
|
165
211
|
exactly the behaviour drift the rule exists to prevent. It fails at wire-up,
|
|
166
212
|
never under load.
|
|
@@ -186,10 +232,14 @@ that passes at 5.99 MB can still be rejected upstream. Lower
|
|
|
186
232
|
client = NeedlepathClient(operating_point="np-2026-08-r4", shadow=True)
|
|
187
233
|
```
|
|
188
234
|
|
|
189
|
-
The call is made exactly as a live call would be
|
|
190
|
-
operating point
|
|
191
|
-
|
|
192
|
-
|
|
235
|
+
The call is made exactly as a live call would be, with the same body, billing,
|
|
236
|
+
and operating point. Ordinary unprotected selections are reported without
|
|
237
|
+
being applied (`reason: "shadow"`). A blocked verdict is enforced in shadow
|
|
238
|
+
mode too: shadow never restores a withheld record, so the result stays
|
|
239
|
+
`reason: "blocked"`, `applied=True`, with `shadow: true`, `outcome` and
|
|
240
|
+
`governance` on the receipt. A protected delivery likewise takes precedence:
|
|
241
|
+
only its permitted selected context may be used, or the request stops with
|
|
242
|
+
`NeedlepathGuardrailError`.
|
|
193
243
|
|
|
194
244
|
`budget.mode = "shadow"` is **not on the wire yet**. `BudgetSpec.mode` on the
|
|
195
245
|
published contract accepts `fixed` and `adaptive` only; adding `shadow` is a
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
Three properties this package guarantees, because the framework adapters built
|
|
14
14
|
on it are only as safe as it is:
|
|
15
15
|
|
|
16
|
-
1.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
1. Ordinary unprotected failures return ``applied=False`` with recorded errors.
|
|
17
|
+
A blocked verdict is applied (``reason: blocked``, nothing delivered) and
|
|
18
|
+
never raises. Workspace protection or ``guardrails_required`` failures
|
|
19
|
+
instead raise ``NeedlepathGuardrailError``; raw-context fallback is forbidden.
|
|
20
20
|
2. **The operating point is pinned in the constructor**, or construction fails.
|
|
21
21
|
3. **The 6 MB payload cap is measured client-side**, before the request leaves.
|
|
22
22
|
|
|
@@ -50,6 +50,7 @@ from .errors import (
|
|
|
50
50
|
NeedlepathConfigError,
|
|
51
51
|
NeedlepathContractError,
|
|
52
52
|
NeedlepathError,
|
|
53
|
+
NeedlepathGuardrailError,
|
|
53
54
|
NeedlepathHTTPError,
|
|
54
55
|
NeedlepathPayloadTooLargeError,
|
|
55
56
|
NeedlepathTimeoutError,
|
|
@@ -87,6 +88,7 @@ from .transport import (
|
|
|
87
88
|
from .version import __version__
|
|
88
89
|
|
|
89
90
|
__all__ = [
|
|
91
|
+
"NeedlepathGuardrailError",
|
|
90
92
|
"__version__",
|
|
91
93
|
# clients
|
|
92
94
|
"NeedlepathClient",
|