One-line integration for Python developers using Anthropic or OpenAI SDKs directly.
pip install agentassert-typec-sdkfrom anthropic import Anthropic
from agentassert_typec_sdk import wrap
# Wrap your existing client with contract enforcement
client = wrap(Anthropic(), "contract.yaml")
# All calls are now contract-enforced
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)That's it. One line. Every messages.create() call runs through the contract evaluator.
| Client | Module | Async |
|---|---|---|
Anthropic |
anthropic.Anthropic |
✅ (via AsyncAnthropic) |
AsyncAnthropic |
anthropic.AsyncAnthropic |
✅ |
OpenAI |
openai.OpenAI |
✅ (via AsyncOpenAI) |
AsyncOpenAI |
openai.AsyncOpenAI |
✅ |
from openai import OpenAI
from agentassert_typec_sdk import wrap
client = wrap(OpenAI(), "contract.yaml")
response = client.chat.completions.create(
model="gpt-5-pro",
messages=[{"role": "user", "content": "Summarize this article"}]
)import asyncio
from anthropic import AsyncAnthropic
from agentassert_typec_sdk import wrap
async def main():
client = wrap(AsyncAnthropic(), "contract.yaml")
response = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
asyncio.run(main())Streaming works identically to the unwrapped client:
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a poem"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Post-action evaluation (drift update, Θ scoring) runs after the stream completes.
When a contract violation occurs, a ContractBreachError is raised:
from agentassert_typec_core.exceptions import ContractBreachError
try:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Run: rm -rf /"}]
)
except ContractBreachError as e:
print(f"Blocked: {e.violation_name}")
print(f"Reason: {e.reason}")
print(f"Tool: {e.tool}")
# Access structured data
d = e.to_dict()
# {"violation_name": "tool_blocklist", "reason": "...", ...}Create multiple wrapped clients for different use cases:
# Safety contract for general use
safe_client = wrap(Anthropic(), "safety-minimal.yaml")
# Strict governance for production builds
prod_client = wrap(Anthropic(), "full-governance.yaml")Each wrapped client has its own SessionMonitor, drift tracker, and Θ scorer.
For clients other than Anthropic or OpenAI, use the HTTP proxy instead:
agentassert-proxy proxy start --contract contract.yaml
export OPENAI_BASE_URL=http://localhost:9000/openaiThe proxy works with any language, any framework, any client — as long as it speaks HTTP.
| Parameter | Type | Description |
|---|---|---|
client |
Anthropic | AsyncAnthropic | OpenAI | AsyncOpenAI |
The client to wrap. |
contract_path |
str |
Path to a contract YAML file. |
Returns: A wrapped client with identical API to the original, plus contract enforcement.
Raises:
ContractLoadError— if the contract YAML is invalidTypeError— if the client type is unsupported
The wrapper intercepts messages.create() (Anthropic) and chat.completions.create() (OpenAI):
- Builds a
PreActionevent with the tool name ("anthropic.messages.create") and request args - Dispatches to the core evaluator →
ALLOW,MODIFY, orDENY - If
DENY: raisesContractBreachErrorbefore any API call - If
ALLOW/MODIFY: forwards to the real client, captures the response - Builds a
PostActionevent → updates drift, Θ, violations - Returns the response unchanged
No provider round-trips are wasted on blocked requests.