Quick start
from qwed_finance import OpenResponsesIntegration
qwed = OpenResponsesIntegration()
# Get OpenAI-compatible tools schema
tools = qwed.get_tools_schema()
# Handle tool call from LLM
result = qwed.handle_tool_call(
tool_name="calculate_npv",
arguments={"cashflows": [-1000, 300, 400], "rate": 0.1}
)
print(result.status) # ToolCallStatus.COMPUTED
print(result.result) # {"npv": "$180.42", "verified": False, "computed": True, ...}
Built-in tool calls (NPV, loan, AML, options) return ToolCallStatus.COMPUTED — meaning the result was computed deterministically but not verified against an LLM claim. Only tools with a custom verification_fn that compare against an LLM output can return ToolCallStatus.APPROVED.
Fail-closed default
Since v2.1.0: Tools registered without a verification_fn are rejected by default. This enforces the QWED principle: “Verification decides IF.”
# ❌ This tool will be REJECTED — no verification function
qwed.register_tool(
name="transfer_funds",
description="Transfer money",
parameters={"amount": {"type": "number"}},
# Missing verification_fn!
)
result = qwed.handle_tool_call("transfer_funds", {"amount": 999})
# result.status == ToolCallStatus.REJECTED
# result.error == "No verification function registered..."
# result.receipt is not None (rejection is audited)
| Status | Meaning | verified in output |
|---|
APPROVED | Verified against LLM claim and passed | true |
COMPUTED | Computed deterministically, NOT compared to LLM claim | false |
REJECTED | Verification failed or no verification_fn registered | N/A (error) |
MODIFIED | Arguments were corrected before approval | true |
ERROR | System error prevented verification | N/A (error) |
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ LLM │────▶│ QWED │────▶│ Verified Result │
│ Tool Call │ │ Intercept │ │ (with receipt) │
└─────────────┘ └─────────────┘ └─────────────────┘
│
Has verification_fn?
╱ ╲
YES NO
│ │
Execute fn REJECTED
(try/except) (audited)
│
Return result
APPROVED / COMPUTED
- LLM emits tool call with arguments
- QWED intercepts and checks for a registered
verification_fn
- If no
verification_fn → REJECTED (fail-closed, audited)
- If
verification_fn exists → execute with error boundary
- Returns verified result with cryptographic receipt
| Tool | Description | Engine | Status |
|---|
calculate_npv | Net Present Value | SymPy | COMPUTED |
calculate_loan_payment | Monthly loan payment | SymPy | COMPUTED |
check_aml_compliance | AML threshold check | Z3 | COMPUTED |
price_option | Black-Scholes pricing | Calculus | COMPUTED |
All built-in tools return COMPUTED status because they perform deterministic calculations without comparing against an LLM claim.
AML country consistency
The check_aml_compliance tool delegates to ComplianceGuard.high_risk_countries for its sanctions list, ensuring a single source of truth across the entire QWED-Finance system.
The price_option tool rejects non-positive inputs for spot_price, strike_price, time_to_expiry, and volatility before computing, preventing ZeroDivisionError at the math boundary.
Black-Scholes single source of truth
Since N-01 fix: price_option delegates to DerivativesGuard.verify_black_scholes() — the same mpmath (30 dp) implementation used by direct guard calls. This guarantees that pricing through the OpenResponses integration and pricing through DerivativesGuard produce identical outputs for identical inputs.
Previously, the integration shipped its own IEEE-754 float-based Black-Scholes routine (math.log/exp/sqrt/erf). Same formula, two precision paths — same input could yield two different outputs depending on call site. The duplicate has been removed.
The tool result now reports the computed price and delta Greek straight from the guard’s quantized Decimal output:
result = qwed.handle_tool_call("price_option", {
"spot_price": 100,
"strike_price": 100,
"time_to_expiry": 1.0,
"risk_free_rate": 0.05,
"volatility": 0.2,
"option_type": "call",
})
print(result.result["price"]) # e.g. "$10.4506" — mpmath, deterministic
print(result.result["delta"]) # e.g. "0.6368" — Decimal-quantized string
Item wrapper (streaming)
Format results for streaming compatibility:
# Handle tool call
result = qwed.handle_tool_call("calculate_npv", args)
# Format as Open Responses Item
item = qwed.format_for_responses_api(result, tool_call_id="call_abc123")
COMPUTED item structure
{
"type": "tool_result",
"id": "call_abc123",
"tool_use_id": "calculate_npv",
"content": {
"mime_type": "application/json",
"text": "{\"result\": {\"npv\": \"$180.42\"}, \"verification\": {\"status\": \"computed_only\", \"verified\": false, \"note\": \"Result was computed deterministically but NOT verified against an LLM claim.\", \"engine\": \"SymPy\", \"receipt_id\": \"abc-123\", \"input_hash\": \"...\"}}"
},
"is_error": false
}
APPROVED item structure
{
"type": "tool_result",
"id": "call_abc123",
"tool_use_id": "my_custom_tool",
"content": {
"mime_type": "application/json",
"text": "{\"result\": {...}, \"verification\": {\"status\": \"verified\", \"verified\": true, \"engine\": \"Z3\", \"receipt_id\": \"def-456\", \"input_hash\": \"...\"}}"
},
"is_error": false
}
OpenAI integration
from openai import OpenAI
client = OpenAI()
qwed = OpenResponsesIntegration()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Calculate NPV of $1000 investment"}],
tools=qwed.get_tools_schema(), # QWED verified tools
tool_choice="auto"
)
# Intercept and verify tool calls
for tool_call in response.choices[0].message.tool_calls:
verified = qwed.handle_tool_call(
tool_call.function.name,
tool_call.function.arguments
)
if verified.status == ToolCallStatus.COMPUTED:
print(f"Computed: {verified.result}")
elif verified.status == ToolCallStatus.APPROVED:
print(f"Verified: {verified.result}")
else:
print(f"Failed: {verified.error}")
Register your own verified tools. A verification_fn is required — tools without one are rejected.
from qwed_finance import VerifiedToolCall, ToolCallStatus
def verify_my_calculation(args):
# Your verification logic here
computed = do_deterministic_math(args)
return VerifiedToolCall(
status=ToolCallStatus.APPROVED,
tool_name="my_tool",
original_args=args,
verified_args=args,
result={"value": computed}
)
qwed.register_tool(
name="my_tool",
description="My custom calculation",
parameters={"type": "object", "properties": {...}},
verification_fn=verify_my_calculation # Required!
)
If your verification_fn raises an exception, it will be caught by the error boundary and return ToolCallStatus.ERROR with a descriptive message — the agent loop will not crash.
Audit trail
All tool call outcomes — including rejections — produce cryptographic receipts:
# Get all receipts
summary = qwed.audit_log.summary()
# Export for compliance
json_log = qwed.audit_log.export_json()
Rejected tool calls (missing verification_fn) are also audited with a receipt containing the rejection reason, ensuring complete compliance traceability.