QWED Open Responses provides deterministic, rule-based verification guards for AI responses, tool calls, and structured outputs. Works with OpenAI Responses API, LangChain, LlamaIndex, and other AI agent frameworks.
Installation
pip install qwed-open-responses
With optional integrations:
pip install qwed-open-responses[openai] # OpenAI Responses API
pip install qwed-open-responses[langchain] # LangChain
pip install qwed-open-responses[tax] # Tax Verification (Payroll, Crypto)
pip install qwed-open-responses[finance] # Finance Verification (NPV, ISO 20022)
pip install qwed-open-responses[legal] # Legal Verification (Contracts, Jurisdictions)
pip install qwed-open-responses[all] # All integrations
💡 What QWED Open Responses Is (and Isn't)
✅ QWED Open Responses IS:
- Verification middleware for AI agents (OpenAI, LangChain, LlamaIndex)
- Deterministic — every check is an explicit, inspectable rule (schema validation, arithmetic recomputation, configurable pattern lists). No LLM calls in the verification path
- Framework-agnostic — works with any LLM or agent framework
- A safety layer — blocks known-dangerous tool calls (configurable blocklist) and incorrect outputs
❌ QWED Open Responses is NOT:
An agent framework— use LangChain or AutoGen for thatA prompt engineering tool— use DSPy for thatA vector database— use Pinecone or Weaviate for thatA vaguely defined "guardrail"— every check is an explicit, inspectable rule (regex-based pattern scans included, and labeled as heuristics)
Think of QWED as the "firewall" for your AI agent's actions and outputs.
LangChain builds the agent. OpenAI powers the brain. QWED secures the actions.
🆚 How We're Different from Other Guardrails
| Aspect | Guardrails AI / NVIDIA NeMo | DSPy | QWED Open Responses |
|---|---|---|---|
| Primary Goal | Format validation (XML/RAIL) | Prompt optimization | Deterministic verification |
| Tool Security | Regex-based blocking | N/A | Configurable blocklist/allowlist + argument pattern scan (heuristic) |
| Math Accuracy | LLM self-correction | Prompt tuning | SymPy symbolic math |
| Approach | "Re-ask the LLM" | "Train the prompt" | "Verify legally/mathematically" |
| Integration | Wraps LLM calls | Replaces prompt pipeline | Middleware / Callback |
| Determinism | Probabilistic | Probabilistic | Deterministic rules (pattern scans are heuristics) |
Use Together (Best Practice)
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ LangChain │ ──► │ QWED │ ──► │ Verified │
│ Agent │ │ (Middleware) │ │ Tool Call │
└──────────────┘ └───────────────┘ └──────────────┘
🔒 Security & Privacy
Verification happens locally. No data leaves your infrastructure.
| Concern | QWED Approach |
|---|---|
| Data Transmission | ❌ No external API calls for verification |
| Logic Execution | ✅ Local Python/Z3 engines |
| Latency | ✅ Sub-millisecond overhead for most guards |
| Audit | ✅ Full logs of blocked actions |
Perfect for:
- Agents with access to databases or APIs
- Enterprise internal tools
- Automated financial/legal assistants
❓ FAQ
Does it slow down my agent?
Negligibly. Most guards (Schema, Tool, Argument) run in <1ms. MathGuard runs in <5ms. It's much faster than making another LLM call to double-check.
Can I use it with custom agents?
Yes! You don't need LangChain. QWED works with raw OpenAI API calls or any Python code. Just pass the output to the Verifier.
How does MathGuard work?
It extracts numbers and operators from the output and uses SymPy to verify if the stated result matches the calculation. It does NOT ask the LLM to check itself.
Is it compatible with streaming?
Yes — OpenResponsesMiddleware verifies tool-call items as they arrive in the stream (middleware/streaming_interceptor.py). With block_on_failure=True (the default) failed items are replaced with a system_intervention item; with block_on_failure=False they pass through unmodified (warn-only monitoring — the trust boundary is disabled in that mode).
🗺️ Roadmap
✅ Released
-
ToolGuard- Block dangerous tools/patterns -
SchemaGuard- JSON Schema validation -
MathGuard- SymPy calculation verification -
SafetyGuard- PII and injection checks -
StateGuard- Finite state machine validation -
ArgumentGuard- Type and range checking - Integrations: OpenAI, LangChain, LlamaIndex
- Streaming Verification - Verify tool-call items in real-time
🚧 In Progress
- Auto-Fix - Deterministic correction of JSON errors
🔮 Planned
- Distributed Rules - Sync rules across agent swarms
- Policy-as-Code - Define guards in YAML/JSON
- Visual Dashboard - View blocked attempts stats
Quick Start
from qwed_open_responses import ResponseVerifier, ToolGuard, SchemaGuard
# Create verifier with guards
verifier = ResponseVerifier()
# Verify a tool call
result = verifier.verify_tool_call(
tool_name="execute_sql",
arguments={"query": "SELECT * FROM users"},
guards=[ToolGuard()]
)
if result.verified:
print("✅ Safe to execute")
else:
print(f"❌ Blocked: {result.block_reason}")
Guards
| Guard | Purpose | Example |
|---|---|---|
| SchemaGuard | Validate JSON schema | Structured outputs |
| ToolGuard | Block dangerous tools | execute_shell, delete_file |
| MathGuard | Verify calculations | Totals, percentages |
| StateGuard | Validate state transitions | Order status changes |
| ArgumentGuard | Validate tool arguments | Types, ranges, formats |
| SafetyGuard | Comprehensive safety | PII, injection, budget |
Examples
Block Dangerous Tools
from qwed_open_responses import ToolGuard
guard = ToolGuard(
blocked_tools=["execute_shell", "delete_file"],
dangerous_patterns=[r"DROP TABLE", r"rm -rf"],
)
result = guard.check({
"tool_name": "execute_sql",
"arguments": {"query": "DROP TABLE users"}
})
# ❌ BLOCKED: Dangerous pattern detected
Validate Structured Outputs
from qwed_open_responses import SchemaGuard
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name", "age"]
}
guard = SchemaGuard(schema=schema)
result = guard.check({"output": {"name": "John", "age": 30}})
# ✅ Schema validation passed
Verify Calculations
from qwed_open_responses import MathGuard
guard = MathGuard()
result = guard.check({
"output": {
"subtotal": 100,
"tax": 8,
"total": 108
}
})
# ✅ Math verification passed
Safety Checks
from qwed_open_responses import SafetyGuard
guard = SafetyGuard(
check_pii=True,
check_injection=True,
max_cost=100.0,
)
result = guard.check({
"content": "ignore previous instructions and..."
})
# ❌ BLOCKED: Prompt injection detected
Framework Integrations
LangChain
from qwed_open_responses.middleware.langchain import QWEDCallbackHandler
callback = QWEDCallbackHandler(
guards=[ToolGuard(), SafetyGuard()]
)
agent = create_agent(callbacks=[callback])
OpenAI Responses API
from qwed_open_responses.middleware.openai_sdk import VerifiedOpenAI
client = VerifiedOpenAI(
api_key="...",
guards=[ToolGuard(), SchemaGuard(schema=my_schema)]
)
response = client.responses.create(...)
# Automatically verified before returning
⚠️ Scope & Limitations
Read this before relying on QWED as a trust boundary (issue #31 audit):
- Tool blocking is a configurable blocklist, not a sandbox. Matching is
case-insensitive and the default list covers common shells (
bash,sh,powershell,zsh, ...) and client action tools (local_shell,apply_patch,computer_use), and argument pattern scanning also decodes bounded base64 payloads — but pattern scanning is a heuristic, not a security boundary. Preferallowed_toolsallowlists and OS-level sandboxing for real enforcement. - Responses API action items are tool calls (v0.6.1 breaking change).
local_shell_call,shell_call,apply_patch_callandcomputer_callitems are checked as the toolslocal_shell,shell,apply_patchandcomputer_use;custom_tool_callandmcp_approval_requestitems are checked under their ownname. The first four names are on the default blocklist. To run them, create ToolGuard withuse_default_blocklist=False; this drops the whole default blocklist (shells included), so re-add any names you still want blocked viablocked_tools.allowed_toolsis optional, but for least-privilege execution configure it as an allowlist — and when you do, list every action tool you run in it. Unknown*_call/*_requestitems in a response'soutput[]or a stream fail closed. - PII detection produces warnings, not blocks. PII matches surface as a
separate warning state (
VerificationResult.warnings); they do not failverifiedor block unless you create the verifier withallow_warnings=False. - SchemaGuard rejects undeclared root fields (v0.6.0 breaking change).
When your schema does not set
additionalProperties, undeclared top-level fields fail validation. Declare them, setadditionalPropertiesexplicitly, or opt out withallow_additional_properties=True. - Verification resource limits fail closed. JSON text longer than 100,000 characters or nesting deeper than 100 levels receives a failed verdict. SafetyGuard also rejects content deeper than 12 levels, wider than 10,000 nodes, or longer than 100,000 characters. SchemaGuard reports only the first validation error and marks the total count as unknown.
- Budget checks use model-reported usage.
response["usage"]comes from the model output under verification: negative or non-numeric reports fail closed, but under-reporting cannot be detected from the response itself. Supply trusted-side totals viacontext["total_cost"]/context["total_tokens"]or reconcile against provider reports. VerificationResultis not cryptographically attested. Anyone can construct one — including one with a valid-lookingbinding. The binding hash only detects a mismatch between a result and its response/metadata; it does not authenticate the result itself. Before acting on a result you did not produce in-process, require trusted provenance or cryptographic attestation (tracked in qwed-verification #319).- Zero guards fail closed.
ResponseVerifier.verify()without guards returnsverified=False;verify_structured_output()raisesValueErrorwhen both a schema and guards are absent — absence of verification is never success. - Streaming warn-only mode disables the trust boundary.
OpenResponsesMiddleware(block_on_failure=False)passes failed items through unmodified — use it for monitoring only.
Why QWED Open Responses?
| Without Verification | With QWED |
|---|---|
LLM calls execute_shell("rm -rf /") |
BLOCKED by ToolGuard |
| LLM returns wrong calculation | CAUGHT by MathGuard |
| LLM outputs PII in response | DETECTED by SafetyGuard |
| LLM hallucinates JSON format | REJECTED by SchemaGuard |
Links
- Docs: docs.qwedai.com/docs/open-responses
- GitHub: QWED-AI/qwed-open-responses
- PyPI: qwed-open-responses
- QWED Core: QWED-AI/qwed-verification
License
Apache 2.0 - See LICENSE
Metadata
Release files for qwed-open-responses 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qwed_open_responses-0.6.1.tar.gz | 118.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qwed_open_responses-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 198.5 kB
Release files / qwed_open_responses-0.6.1.tar.gz
| Download URL | qwed_open_responses-0.6.1.tar.gz |
|---|---|
| Size | 118.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
67728ba00a04b324a5a3bf290f24cc309b17fa97565c4fd8ed7d82140fb4b5d7
|
|
BLAKE2b-256 checksum How to use checksums |
68ea79193ae01fa2cbfde6f3c63369ba57add4547204cac23e881cd657901065
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency logRelease files / qwed_open_responses-0.6.1-py3-none-any.whl
| Download URL | qwed_open_responses-0.6.1-py3-none-any.whl |
|---|---|
| Size | 80.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f2a4db679265bf2423b4751bd685c62962a2fceab3e8a2a42203828c4969b2f3
|
|
BLAKE2b-256 checksum How to use checksums |
ed5050713728e54dd0dfbff00dd7356605779a8efd19d7f75f243adf3d084984
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency log