consequence-gate 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: consequence-gate
3
+ Version: 0.1.0
4
+ Summary: Speculative outcome-simulation layer for AI agent tool calls — predicts consequence (blast radius, irreversibility, velocity) before execution and steers agents toward safer alternatives.
5
+ Author-email: Anandkrishnan Shnn <anandkrshnn@gmail.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/anandkrshnn-ai/consequence-gate
8
+ Project-URL: Documentation, https://github.com/anandkrshnn-ai/consequence-gate#readme
9
+ Project-URL: Repository, https://github.com/anandkrshnn-ai/consequence-gate
10
+ Project-URL: Issues, https://github.com/anandkrshnn-ai/consequence-gate/issues
11
+ Keywords: ai-agents,ai-safety,ai-governance,langchain,langgraph,mcp,agent-security,runtime-governance
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: langchain>=0.3.0
25
+ Requires-Dist: langchain-agents>=0.3.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
29
+ Requires-Dist: black>=23.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
31
+ Provides-Extra: strands
32
+ Requires-Dist: strands-agents>=0.1.0; extra == "strands"
33
+ Provides-Extra: mcp
34
+ Provides-Extra: langgraph
35
+ Requires-Dist: langgraph>=0.2.0; extra == "langgraph"
36
+
37
+ # consequence-gate
38
+
39
+ A speculative outcome-simulation layer for AI agent tool calls. It sits
40
+ **upstream** of static runtime access gates (AgentWall, AWS Strands
41
+ `BeforeToolCallEvent`, MCP proxies, Prisma AIRS) and asks a different
42
+ question than they do.
43
+
44
+ Static gates ask: *does this call match an allowed pattern?*
45
+ `consequence-gate` asks: *what will this call actually do, and is that
46
+ outcome safe?*
47
+
48
+ ## Why this exists
49
+
50
+ Static runtime gates are fast (sub-millisecond) and effective at schema
51
+ validation, RBAC, and pattern matching -- but a schema-valid,
52
+ policy-compliant call can still be consequence-catastrophic. A
53
+ `process_claim(amount=50000)` call can pass every static check while
54
+ pushing an account over its daily velocity limit via an irreversible
55
+ instant transfer. `consequence-gate` projects the *outcome* of a call
56
+ (balance deltas, row-count blast radius, FK cascade depth,
57
+ irreversibility) before the call reaches your existing static gate, and
58
+ either passes it through, asks a human, denies it outright, or steers
59
+ the agent toward a pre-vetted safer alternative.
60
+
61
+ This is explicitly **not** a replacement for AgentWall / Strands / MCP
62
+ proxies -- it's a prediction layer that runs before them, in the same
63
+ pipeline.
64
+
65
+ ## Core contracts
66
+
67
+ - **No silent argument mutation.** Steering returns structured guidance
68
+ and a suggested alternative call; the agent (or a human) still has to
69
+ commit to it. This preserves the audit property that every executed
70
+ call was one the agent explicitly chose.
71
+ - **Idempotency keys are derived from the transaction's own natural key**
72
+ (e.g. `claim_id`, or `table + filter hash`), never a fresh random token
73
+ per retry -- otherwise a lost-response retry looks like a brand-new
74
+ transaction instead of a duplicate.
75
+ - **Hard retry cap on STEER.** Regardless of guidance quality, retries
76
+ are capped (default: 2) before forcing escalation to a human, as a
77
+ backstop against loop-thrashing.
78
+ - **Confidence-gated escalation.** Low-confidence projections route to
79
+ `ASK`, never to a confident-looking `ALLOW` or `DENY` -- an
80
+ unfounded heuristic is worse than admitting uncertainty.
81
+
82
+ ## Modules
83
+
84
+ - `consequence_gate.simulators.financial` -- **functional**: disbursement / claim / refund
85
+ velocity and irreversibility modeling.
86
+ - `consequence_gate.simulators.database` -- **functional**: row-count blast radius via the
87
+ DB's own query planner (`EXPLAIN`, not hardcoded selectivity constants)
88
+ and recursive `ON DELETE CASCADE` graph walking.
89
+ - `consequence_gate.simulators.communications` -- **functional**: outbound email/SMS/notification
90
+ blast radius, unsubscribe suppression compliance, canary cohort analysis, sender reputation impact.
91
+ - `consequence_gate.core` -- shared models, the confidence/threshold
92
+ evaluator, and the idempotency-locked circuit breaker.
93
+ - `consequence_gate.integrations.strands_hook` -- **functional**: AWS Strands
94
+ `BeforeToolCallEvent` adapter with full `ALLOW`/`DENY`/`ASK`/`STEER` lifecycle.
95
+ - `consequence_gate.integrations.mcp_proxy` -- **functional**: MCP stdio proxy
96
+ intercepting `tools/call` requests, returning JSON-RPC errors or `isError=true` tool results.
97
+ - `consequence_gate.integrations.langgraph_hook` -- **functional**: LangGraph middleware
98
+ (`@wrap_tool_call`) intercepting tool execution with full `ALLOW`/`DENY`/`ASK`/`STEER` lifecycle.
99
+ - `consequence_gate.backtest` -- offline JSONL trace replay harness and
100
+ four-quadrant FP/FN/TN report generator, for evaluating this layer
101
+ against historical execution logs with zero production integration.
102
+
103
+ ## Quickstart
104
+
105
+ ### Installation
106
+
107
+ ```bash
108
+ pip install -e ".[dev]"
109
+ pytest
110
+ python examples/run_backtest_demo.py
111
+ ```
112
+
113
+ ### AWS Strands Integration
114
+
115
+ ```python
116
+ from consequence_gate.integrations.strands_hook import create_financial_gate_hook
117
+ from strands.agents import Agent
118
+
119
+ hook = create_financial_gate_hook(
120
+ daily_tier_limit_inr=25000.0,
121
+ instant_wire_threshold=10000.0,
122
+ max_retries=2,
123
+ context_provider=lambda event: {
124
+ "account_rolling_24h_spend": get_current_spend(event),
125
+ "kyc_verified": is_kyc_verified(event),
126
+ },
127
+ )
128
+
129
+ agent = Agent(hooks=[hook])
130
+ response = agent("Process this claim for 50,000 INR")
131
+ ```
132
+
133
+ ### MCP Proxy Integration
134
+
135
+ Run as a standalone proxy in front of any MCP server:
136
+
137
+ ```bash
138
+ # Financial disbursement gate
139
+ python -m consequence_gate.integrations.examples.run_mcp_proxy financial \\
140
+ --downstream-command "npx -y @modelcontextprotocol/server-postgres postgresql://localhost/mydb" \\
141
+ --daily-tier-limit 25000 \\
142
+ --instant-wire-threshold 10000
143
+ ```
144
+
145
+ Configure in Claude Desktop / Cursor / Windsurf:
146
+
147
+ ```json
148
+ {
149
+ "mcpServers": {
150
+ "my-consequence-gate": {
151
+ "command": "python",
152
+ "args": ["-m", "consequence_gate.integrations.examples.run_mcp_proxy", "financial", "--downstream-command", "npx -y @modelcontextprotocol/server-postgres postgresql://localhost/mydb"]
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### LangGraph Integration
159
+
160
+ ```python
161
+ from langchain.agents import create_agent
162
+ from consequence_gate.integrations.langgraph_hook import create_financial_gate_middleware
163
+
164
+ middleware = create_financial_gate_middleware(
165
+ daily_tier_limit_inr=25000.0,
166
+ instant_wire_threshold=10000.0,
167
+ max_retries=2,
168
+ )
169
+
170
+ agent = create_agent(
171
+ model="claude-sonnet-4",
172
+ tools=[my_tool],
173
+ middleware=[middleware],
174
+ )
175
+ ```
176
+
177
+ Run the example:
178
+
179
+ ```bash
180
+ python -m consequence_gate.integrations.examples.run_langgraph
181
+ ```
182
+
183
+ ### Database Deletion Gate (Strands)
184
+
185
+ ```python
186
+ from consequence_gate.integrations.strands_hook import create_database_gate_hook
187
+
188
+ hook = create_database_gate_hook(
189
+ max_autonomous_delete_rows=100,
190
+ db_conn=get_db_connection(),
191
+ max_retries=2,
192
+ context_provider=lambda event: {
193
+ "table_metadata": get_table_metadata(event),
194
+ },
195
+ )
196
+
197
+ agent = Agent(hooks=[hook])
198
+ ```
199
+
200
+ ### Communications Blast Gate (Strands)
201
+
202
+ ```python
203
+ from consequence_gate.integrations.strands_hook import create_communication_gate_hook
204
+
205
+ hook = create_communication_gate_hook(
206
+ max_autonomous_recipients=10000,
207
+ canary_min_size=100,
208
+ canary_max_bounce_rate=0.05,
209
+ canary_max_complaint_rate=0.01,
210
+ context_provider=lambda event: {
211
+ "segment_counts": get_segment_counts(event),
212
+ "recent_unsubscribes": get_recent_unsubscribes(event),
213
+ "historical_bounce_rate": 0.02,
214
+ "historical_complaint_rate": 0.005,
215
+ },
216
+ )
217
+
218
+ agent = Agent(hooks=[hook])
219
+ ```
220
+
221
+ ## Decision Matrix
222
+
223
+ | Decision | Strands | MCP | LangGraph |
224
+ |----------|---------|-----|-----------|
225
+ | `ALLOW` | Executes normally | Forwarded to downstream MCP server | Tool executes via handler(request) |
226
+ | `DENY` | `BLOCKED: <reason>` | JSON-RPC error (code=-32603) | Raises `ValueError("BLOCKED: ...")` |
227
+ | `ASK` | `ESCALATION_REQUIRED: <reason>` | `isError=true` tool result | Raises `ValueError("ESCALATION_REQUIRED: ...")` |
228
+ | `STEER` | `STEER_GUIDANCE: <guidance>\nSuggested alternative...` | `isError=true` + guidance | `ToolMessage(content="STEER_GUIDANCE: ...", status="error")` |
229
+
230
+ ## Backtest Workflow
231
+
232
+ Before deploying to production, run an offline backtest against historical
233
+ execution traces:
234
+
235
+ 1. Export 1,000-5,000 tool-call traces as JSONL (see `examples/backtest_sample_traces.jsonl`)
236
+ 2. Run `python examples/run_backtest_demo.py` against your traces
237
+ 3. Review the four-quadrant breakdown:
238
+ - True Negative: correctly allowed benign operations
239
+ - False Negative Caught: schema-valid calls that would have breached limits
240
+ - False Positive Relieved: over-blocking that the simulator would have avoided
241
+ - Steer Recovery Rate: percentage of blocked turns that could have completed via guidance
242
+
243
+ ## Status
244
+
245
+ - **Financial simulator**: functional with unit tests
246
+ - **Database simulator**: functional with unit tests (EXPLAIN-based row estimation, recursive FK cascade walk)
247
+ - **Communications simulator**: functional with unit tests (blast radius, unsubscribe compliance, canary cohorts, reputation impact)
248
+ - **Strands integration**: functional with unit tests (full `ALLOW`/`DENY`/`ASK`/`STEER` lifecycle)
249
+ - **MCP integration**: functional with unit tests (stdio transport, JSON-RPC error handling)
250
+ - **LangGraph integration**: functional with unit tests (`@wrap_tool_call` middleware pattern)
251
+
252
+ ## License
253
+
254
+ Apache-2.0
@@ -0,0 +1,24 @@
1
+ consequence_gate/__init__.py,sha256=capa7egh8wyDQuuVT-KewzvT9Kl6bf_CYTlxe6i9yh4,112
2
+ consequence_gate/cli.py,sha256=Asv4pJv9EEzZPMIJeCpn2RNg4ZTfk2oCCN3vT6x7mqU,3021
3
+ consequence_gate/backtest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ consequence_gate/backtest/harness.py,sha256=cukzr9XdP2ZvfI_5WJZgHijS9tYXYP265uhimCyBlcg,1668
5
+ consequence_gate/backtest/reporter.py,sha256=6t06MCLKAXQNX81_oSPagTDAO2icSeJNuVxLg7-fOpw,796
6
+ consequence_gate/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ consequence_gate/core/circuit_breaker.py,sha256=D-xftZPMYMgKnIGjJeMZNcaba3ZjZhtHK-e_EBnUJ5s,2242
8
+ consequence_gate/core/evaluator.py,sha256=Zd65nydgN9v36cLgVPGl7RUho0175hFN5XqWAjtHvqc,1050
9
+ consequence_gate/core/models.py,sha256=eoxOFZiUaIFgoGLW1z_3I13vNXkIJttns_glC3j0b0g,1124
10
+ consequence_gate/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ consequence_gate/integrations/langgraph_hook.py,sha256=FRtLaFfUSBGlnFZ79Z60BoihsJDQ_4xGE7sCF4CvoMg,7577
12
+ consequence_gate/integrations/mcp_proxy.py,sha256=ASKc0LgAC6avPZd_0IPTzUsyQ4hdfJovd2C5ee0c-40,12247
13
+ consequence_gate/integrations/strands_hook.py,sha256=3vKYILbDJgSSwFAlKkGE1yk7VYkVl3RmVPR0pGZ8xOU,9106
14
+ consequence_gate/integrations/examples/run_langgraph.py,sha256=T4bxiyhz1QDxggOEWbZEe22eyYYg_9RLd2BbaZvUwyo,2002
15
+ consequence_gate/integrations/examples/run_mcp_proxy.py,sha256=NQVfnpyqmeZ-uMP38j65WBc_xQ3N-yHeMze3mG2P4KQ,4217
16
+ consequence_gate/simulators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ consequence_gate/simulators/communications.py,sha256=70-QRo3dcXOxmz0T8wxBi6FOVTdHThCgDs-FftntfNo,12312
18
+ consequence_gate/simulators/database.py,sha256=81OAgZ8tnmW9NZehOkgbjPyGOdtnZBCYNfkAvB7Loww,7245
19
+ consequence_gate/simulators/financial.py,sha256=AWrW17NWDqdBgnZ5_IHbffGKQR5SV_Vtx38kXUghamE,4890
20
+ consequence_gate-0.1.0.dist-info/METADATA,sha256=zQ7Mw7H6qF-5brB0kJrHR8uZS-DIAanRF4f73v0AUyU,10290
21
+ consequence_gate-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
22
+ consequence_gate-0.1.0.dist-info/entry_points.txt,sha256=Xh5eptmtjTupU4XYaiEmp0Levcyb1sZJDQ7o6QyYbhQ,63
23
+ consequence_gate-0.1.0.dist-info/top_level.txt,sha256=9a5mtcWJWPK2BVse-gSSwKFGyFzPLL77S3LsQkfCZ-g,17
24
+ consequence_gate-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ consequence-gate = consequence_gate.cli:main
@@ -0,0 +1 @@
1
+ consequence_gate