Skip to main content

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)

Tool call statuses

StatusMeaningverified in output
APPROVEDVerified against LLM claim and passedtrue
COMPUTEDComputed deterministically, NOT compared to LLM claimfalse
REJECTEDVerification failed or no verification_fn registeredN/A (error)
MODIFIEDArguments were corrected before approvaltrue
ERRORSystem error prevented verificationN/A (error)

Tool call flow

┌─────────────┐     ┌─────────────┐     ┌─────────────────┐
│    LLM       │────▶│    QWED     │────▶│  Verified Result │
│  Tool Call   │     │  Intercept  │     │  (with receipt)  │
└─────────────┘     └─────────────┘     └─────────────────┘

                  Has verification_fn?
                    ╱           ╲
                  YES            NO
                   │              │
              Execute fn      REJECTED
              (try/except)    (audited)

            Return result
         APPROVED / COMPUTED
  1. LLM emits tool call with arguments
  2. QWED intercepts and checks for a registered verification_fn
  3. If no verification_fnREJECTED (fail-closed, audited)
  4. If verification_fn exists → execute with error boundary
  5. Returns verified result with cryptographic receipt

Available built-in tools

ToolDescriptionEngineStatus
calculate_npvNet Present ValueSymPyCOMPUTED
calculate_loan_paymentMonthly loan paymentSymPyCOMPUTED
check_aml_complianceAML threshold checkZ3COMPUTED
price_optionBlack-Scholes pricingCalculusCOMPUTED
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.

Black-Scholes input validation

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}")

Custom tools

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.