gateframe 0.2.0__tar.gz → 0.2.1__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.
- {gateframe-0.2.0 → gateframe-0.2.1}/LICENSE +1 -1
- {gateframe-0.2.0 → gateframe-0.2.1}/PKG-INFO +325 -289
- {gateframe-0.2.0 → gateframe-0.2.1}/README.md +46 -10
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/__init__.py +3 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/audit/log.py +4 -0
- gateframe-0.2.1/gateframe/audit/trend.py +275 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/cli/main.py +16 -0
- gateframe-0.2.1/gateframe/cli/trend.py +53 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/context.py +50 -26
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/contract.py +5 -1
- gateframe-0.2.1/gateframe/core/retry.py +106 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/rules/semantic.py +37 -3
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/PKG-INFO +325 -289
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/SOURCES.txt +3 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/pyproject.toml +1 -1
- {gateframe-0.2.0 → gateframe-0.2.1}/setup.cfg +4 -4
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/audit/__init__.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/audit/exporters.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/cli/__init__.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/cli/inspect.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/cli/replay.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/__init__.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/escalation.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/failure.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/core/rule.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/integrations/__init__.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/integrations/anthropic.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/integrations/langchain.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/integrations/litellm.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/integrations/openai.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/rules/__init__.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/rules/boundary.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/rules/confidence.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe/rules/structural.py +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/dependency_links.txt +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/entry_points.txt +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/requires.txt +0 -0
- {gateframe-0.2.0 → gateframe-0.2.1}/gateframe.egg-info/top_level.txt +0 -0
|
@@ -1,289 +1,325 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: gateframe
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Behavioral validation for LLM outputs in production workflows.
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
Keywords: llm,validation,behavioral,workflow,ai
|
|
7
|
-
Classifier: Development Status :: 3 - Alpha
|
|
8
|
-
Classifier: Intended Audience :: Developers
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Classifier: Typing :: Typed
|
|
15
|
-
Requires-Python: >=3.10
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
License-File: LICENSE
|
|
18
|
-
Requires-Dist: pydantic<3.0,>=2.0
|
|
19
|
-
Requires-Dist: structlog>=23.0
|
|
20
|
-
Provides-Extra: dev
|
|
21
|
-
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
|
-
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
23
|
-
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
24
|
-
Provides-Extra: anthropic
|
|
25
|
-
Requires-Dist: anthropic>=0.30.0; extra == "anthropic"
|
|
26
|
-
Provides-Extra: openai
|
|
27
|
-
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
28
|
-
Provides-Extra: litellm
|
|
29
|
-
Requires-Dist: litellm>=1.0.0; extra == "litellm"
|
|
30
|
-
Provides-Extra: otlp
|
|
31
|
-
Requires-Dist: opentelemetry-api>=1.20.0; extra == "otlp"
|
|
32
|
-
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "otlp"
|
|
33
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0; extra == "otlp"
|
|
34
|
-
Provides-Extra: langchain
|
|
35
|
-
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
36
|
-
Dynamic: license-file
|
|
37
|
-
|
|
38
|
-
# Gateframe
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
audit.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
from
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
validator =
|
|
197
|
-
result = validator.validate(
|
|
198
|
-
|
|
199
|
-
#
|
|
200
|
-
from gateframe.integrations.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gateframe
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Behavioral validation for LLM outputs in production workflows.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: llm,validation,behavioral,workflow,ai
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
19
|
+
Requires-Dist: structlog>=23.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
24
|
+
Provides-Extra: anthropic
|
|
25
|
+
Requires-Dist: anthropic>=0.30.0; extra == "anthropic"
|
|
26
|
+
Provides-Extra: openai
|
|
27
|
+
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
28
|
+
Provides-Extra: litellm
|
|
29
|
+
Requires-Dist: litellm>=1.0.0; extra == "litellm"
|
|
30
|
+
Provides-Extra: otlp
|
|
31
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == "otlp"
|
|
32
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "otlp"
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0; extra == "otlp"
|
|
34
|
+
Provides-Extra: langchain
|
|
35
|
+
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# Gateframe
|
|
39
|
+
|
|
40
|
+
[](https://github.com/baranylcn/gateframe/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/gateframe/)
|
|
42
|
+
[](https://pypi.org/project/gateframe/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
|
|
45
|
+
Behavioral validation for LLM outputs in production workflows.
|
|
46
|
+
|
|
47
|
+
Schema validation, "does this JSON have the right keys?", is a solved problem. Instructor, Pydantic AI, and similar tools handle it well. gateframe solves a different problem: **does this output behave correctly given the context it was generated in?** Does it stay within the decision boundaries this workflow requires? When it fails, does it fail in a way your system can recover from, or does it fail silently?
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from pydantic import BaseModel
|
|
51
|
+
from gateframe import (
|
|
52
|
+
ValidationContract,
|
|
53
|
+
StructuralRule,
|
|
54
|
+
BoundaryRule,
|
|
55
|
+
ConfidenceRule,
|
|
56
|
+
AllowedValues,
|
|
57
|
+
FailureMode,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TriageDecision(BaseModel):
|
|
62
|
+
action: str
|
|
63
|
+
priority: str
|
|
64
|
+
confidence: float
|
|
65
|
+
rationale: str
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
contract = ValidationContract(
|
|
69
|
+
name="triage_decision",
|
|
70
|
+
rules=[
|
|
71
|
+
StructuralRule(schema=TriageDecision),
|
|
72
|
+
BoundaryRule(
|
|
73
|
+
check=AllowedValues("action", {"treat", "observe", "refer", "discharge"}),
|
|
74
|
+
name="action_boundary",
|
|
75
|
+
failure_message="Action must be one of: treat, observe, refer, discharge.",
|
|
76
|
+
),
|
|
77
|
+
ConfidenceRule(field="confidence", minimum=0.7),
|
|
78
|
+
],
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
result = contract.validate(
|
|
82
|
+
{
|
|
83
|
+
"action": "prescribe", # not in allowed set -> HARD_FAIL
|
|
84
|
+
"priority": "high",
|
|
85
|
+
"confidence": 0.52, # below 0.7 -> SOFT_FAIL
|
|
86
|
+
"rationale": "...",
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
print(result.passed) # False
|
|
91
|
+
for failure in result.failures:
|
|
92
|
+
print(f"[{failure.failure_mode.value}] {failure.rule_name}: {failure.message}")
|
|
93
|
+
# [hard_fail] action_boundary: Action must be one of: treat, observe, refer, discharge.
|
|
94
|
+
# [soft_fail] confidence_check: Confidence 0.52 is below minimum threshold 0.7.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## The problem
|
|
100
|
+
|
|
101
|
+
Most LLM pipelines validate outputs the same way: parse the JSON, check the schema, move on. That catches structural errors. It misses the errors that actually cause production incidents:
|
|
102
|
+
|
|
103
|
+
- A model recommends an action that is structurally valid but outside its authorized scope
|
|
104
|
+
- Confidence is low but the workflow proceeds as if it weren't
|
|
105
|
+
- A soft failure in step 2 silently degrades the reliability of everything downstream
|
|
106
|
+
- A validation failure gives you `False`, and no context for debugging
|
|
107
|
+
|
|
108
|
+
gateframe makes these failures explicit, structured, and recoverable.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Failure modes
|
|
113
|
+
|
|
114
|
+
gateframe distinguishes four failure types instead of binary pass/fail.
|
|
115
|
+
|
|
116
|
+
**`HARD_FAIL`**, Stop. The output violates a hard constraint that cannot be auto-recovered.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Model chose an action outside its authorized scope
|
|
120
|
+
BoundaryRule(
|
|
121
|
+
check=AllowedValues("action", {"treat", "observe", "refer"}),
|
|
122
|
+
failure_mode=FailureMode.HARD_FAIL, # default for BoundaryRule
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**`SOFT_FAIL`**, Flag and continue with degraded confidence. Something is off but not critical enough to halt.
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Model confidence is low, continue but track the degradation
|
|
130
|
+
ConfidenceRule(
|
|
131
|
+
field="confidence",
|
|
132
|
+
minimum=0.7,
|
|
133
|
+
failure_mode=FailureMode.SOFT_FAIL, # default for ConfidenceRule
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**`RETRY`**, Re-prompt with the failure context. The output is likely fixable by trying again.
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# Malformed output that might parse correctly on a second attempt
|
|
141
|
+
StructuralRule(schema=MyOutput, failure_mode=FailureMode.RETRY)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**`SILENT_FAIL`**, The most dangerous kind. The output looks valid but violates a semantic or boundary rule. gateframe makes these visible instead of letting them pass through undetected.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
SemanticRule(
|
|
148
|
+
check=lambda output, **ctx: output["severity"] != "low" or output["escalated"] is False,
|
|
149
|
+
failure_mode=FailureMode.SILENT_FAIL,
|
|
150
|
+
failure_message="Low-severity cases should not be auto-escalated.",
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Multi-step workflow validation
|
|
157
|
+
|
|
158
|
+
Validation state carries forward across steps. A soft failure in step 2 degrades the confidence score that step 4 sees.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from gateframe import WorkflowContext, ValidationContract, EscalationRouter
|
|
162
|
+
from gateframe.audit.log import AuditLog
|
|
163
|
+
|
|
164
|
+
ctx = WorkflowContext(workflow_id="incident_response_001", escalation_threshold=0.5)
|
|
165
|
+
router = EscalationRouter()
|
|
166
|
+
audit = AuditLog()
|
|
167
|
+
|
|
168
|
+
# Step 1
|
|
169
|
+
result1 = contract_step1.validate(output1)
|
|
170
|
+
ctx.update(result1)
|
|
171
|
+
audit.record(result1, workflow_context=ctx)
|
|
172
|
+
|
|
173
|
+
# Step 2, ctx carries forward degraded confidence from step 1
|
|
174
|
+
result2 = contract_step2.validate(output2)
|
|
175
|
+
ctx.update(result2)
|
|
176
|
+
audit.record(result2, workflow_context=ctx)
|
|
177
|
+
|
|
178
|
+
print(ctx.confidence) # degraded from 1.0 by soft failures
|
|
179
|
+
print(ctx.threshold_breached) # True if confidence < escalation_threshold
|
|
180
|
+
|
|
181
|
+
if ctx.threshold_breached:
|
|
182
|
+
escalation = router.route_threshold_breach(ctx)
|
|
183
|
+
print(escalation.route.value) # "human_review", "abort", etc.
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Provider integrations
|
|
189
|
+
|
|
190
|
+
gateframe validates outputs from any provider. Integrations are thin wrappers, gateframe does not import any LLM SDK at the core level.
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
# OpenAI
|
|
194
|
+
from gateframe.integrations.openai import OpenAIValidator
|
|
195
|
+
|
|
196
|
+
validator = OpenAIValidator(contract, parse_json=True)
|
|
197
|
+
result = validator.validate(openai_completion)
|
|
198
|
+
|
|
199
|
+
# Anthropic
|
|
200
|
+
from gateframe.integrations.anthropic import AnthropicValidator
|
|
201
|
+
|
|
202
|
+
validator = AnthropicValidator(contract, parse_json=True)
|
|
203
|
+
result = validator.validate(anthropic_message)
|
|
204
|
+
|
|
205
|
+
# LiteLLM
|
|
206
|
+
from gateframe.integrations.litellm import LiteLLMValidator
|
|
207
|
+
|
|
208
|
+
validator = LiteLLMValidator(contract, parse_json=True)
|
|
209
|
+
result = validator.validate(litellm_response)
|
|
210
|
+
|
|
211
|
+
# LangChain
|
|
212
|
+
from gateframe.integrations.langchain import LangChainValidator
|
|
213
|
+
|
|
214
|
+
validator = LangChainValidator(contract, parse_json=False)
|
|
215
|
+
result = validator.validate(chain_output)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Install the integration you need:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
pip install "gateframe[openai]"
|
|
222
|
+
pip install "gateframe[anthropic]"
|
|
223
|
+
pip install "gateframe[litellm]"
|
|
224
|
+
pip install "gateframe[langchain]"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Audit trail
|
|
230
|
+
|
|
231
|
+
Every validation event is logged with structured context. Use the built-in exporters or implement your own.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from gateframe.audit.log import AuditLog
|
|
235
|
+
from gateframe.audit.exporters import JsonFileExporter
|
|
236
|
+
|
|
237
|
+
audit = AuditLog(exporters=[JsonFileExporter("audit.jsonl")])
|
|
238
|
+
audit.record(result, workflow_context=ctx)
|
|
239
|
+
audit.flush()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Each entry includes: timestamp, contract name, rules applied, rules failed, failure details, workflow ID, and accumulated confidence score.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Trend analysis
|
|
247
|
+
|
|
248
|
+
`ContractTrendAnalyzer` reads an existing JSONL audit log and computes per-contract pass-rate trends across workflow runs. Use it to detect reliability regressions before they become incidents.
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from pathlib import Path
|
|
252
|
+
from gateframe.audit.trend import ContractTrendAnalyzer
|
|
253
|
+
|
|
254
|
+
analyzer = ContractTrendAnalyzer(Path("audit.jsonl"), window=20)
|
|
255
|
+
report = analyzer.analyze()
|
|
256
|
+
|
|
257
|
+
if report.any_regression:
|
|
258
|
+
for ct in report.regressions:
|
|
259
|
+
print(f"{ct.contract_name}: {ct.direction} (slope={ct.slope:.4f})")
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The `window` parameter controls how many most-recent workflow runs are included. A contract is flagged as regressing when its pass-rate slope falls below `-0.02` (two percentage points per run) by default.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## When to use gateframe
|
|
267
|
+
|
|
268
|
+
Use it when:
|
|
269
|
+
- You need to validate LLM output behavior beyond schema checks, decision boundaries, scope enforcement, semantic constraints
|
|
270
|
+
- You need structured, recoverable failure records rather than bare exceptions
|
|
271
|
+
- You're running multi-step workflows where soft failures in early steps should affect confidence downstream
|
|
272
|
+
- You need an audit trail for post-incident debugging
|
|
273
|
+
|
|
274
|
+
Don't use it when:
|
|
275
|
+
- You only need schema extraction from LLM outputs, use [Instructor](https://github.com/jxnl/instructor) or [Pydantic AI](https://ai.pydantic.dev/)
|
|
276
|
+
- You need offline model evaluation or benchmarking, use [DeepEval](https://github.com/confident-ai/deepeval) or [RAGAS](https://github.com/explodinggradients/ragas)
|
|
277
|
+
- You need content safety filtering, use a dedicated guardrails tool
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Installation
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
pip install gateframe
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
For development:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
git clone https://github.com/baranylcn/gateframe.git
|
|
291
|
+
cd gateframe
|
|
292
|
+
pip install -e ".[dev]"
|
|
293
|
+
python -m pytest tests/ -v
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Examples
|
|
299
|
+
|
|
300
|
+
**[triage_workflow](examples/triage_workflow/)**, 3-step medical triage pipeline. Demonstrates StructuralRule, BoundaryRule, ConfidenceRule, and WorkflowContext together. Step 2 has confidence below threshold, shows how SOFT_FAIL degrades the workflow score without halting it.
|
|
301
|
+
|
|
302
|
+
**[rag_output](examples/rag_output/)**, RAG answer validation with two scenarios. Scenario B demonstrates simultaneous soft failures (low confidence + ungrounded answer) and how they accumulate in the workflow context.
|
|
303
|
+
|
|
304
|
+
**[agent_pipeline](examples/agent_pipeline/)**, 4-step agent workflow with escalation. Demonstrates how multiple soft failures across steps push cumulative confidence below the escalation threshold.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## CLI
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Inspect a contract file, lists all contracts and their rules
|
|
312
|
+
gateframe inspect contracts.py
|
|
313
|
+
|
|
314
|
+
# Replay an audit log
|
|
315
|
+
gateframe replay audit.jsonl
|
|
316
|
+
|
|
317
|
+
# Detect pass-rate regressions across workflow runs
|
|
318
|
+
gateframe trend audit.jsonl --window 20
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## License
|
|
324
|
+
|
|
325
|
+
MIT, see [LICENSE](LICENSE).
|