uais-wai (1.0.1)
Installation
pip install --index-url --extra-index-url https://pypi.org/simple uais-waiAbout this package
WAI (Watcher AI) Python SDK — fire-and-forget event ingest, diagnose, trace for UAIS ecosystem apps
uais-wai — WAI Python SDK
Python client for the WAI (Watcher AI) observability + intervention platform.
Hatayı ben yönetirim, hata beni değil.
Install
uais-wai is published to UAIS' internal Gitea package registry, not
public PyPI — a plain pip install uais-wai will fail (no matching
distribution / 401). You need both the internal index (for uais-wai
itself) and public PyPI (for its transitive dependencies, e.g. httpx,
pydantic) — --extra-index-url is required, a single --index-url alone
is not enough:
pip install \
--index-url "https://admin:${GITEA_PKG_READ_TOKEN}@gitea.uais.ai/api/packages/uais/pypi/simple/" \
--extra-index-url "https://pypi.org/simple/" \
uais-wai
# with FastAPI adapter
pip install ... 'uais-wai[fastapi]'
# with SQLAlchemy adapter
pip install ... 'uais-wai[sqlalchemy]'
GITEA_PKG_READ_TOKEN is the read-only package-registry token distributed to
sibling projects (source of truth: uais-platform/platform-config.md) — it
is not a per-repo git credential, only a package-pull token. For a CI
pipeline, put the same two flags in pip.conf:
[global]
index-url = https://admin:${GITEA_PKG_READ_TOKEN}@gitea.uais.ai/api/packages/uais/pypi/simple/
extra-index-url = https://pypi.org/simple/
Python 3.12+.
Quickstart
import os
from uais_wai import WAIClient
wai = WAIClient(
endpoint="https://wai.uais.ai",
tenant_id="example", # app_uid bound to your tenant
api_key=os.environ["WAI_API_KEY"],
environment=os.getenv("WAI_ENV", "production"),
app_version=os.getenv("APP_VERSION"),
# SLA tuning (defaults shown)
diagnose_timeout_ms=3000,
diagnose_default_action="escalate", # what to return on diagnose timeout
local_buffer_size=1000,
flush_interval_ms=500,
)
# Fire-and-forget event (returns immediately; batched in the background).
await wai.event(
source="db",
severity="error",
category="db.query.slow",
payload={"reason": "lock_timeout", "query_ms": 5200},
context={"workspace_id": "ws-1"},
)
# Fire-and-forget metric.
await wai.metric("llm.latency_ms", 1230.5, unit="ms",
labels={"provider": "openrouter", "model": "anthropic/claude-sonnet-4.5"})
# Blocking diagnose (bounded by diagnose_timeout_ms).
try:
do_thing()
except Exception as exc:
diagnosis = await wai.diagnose(error=exc, context={"workspace_id": "ws-1", "operation": "db_write"})
if diagnosis.timed_out:
log.warning("WAI slow; using local default: %s", diagnosis.action)
if diagnosis.action == "retry":
retry_with(diagnosis.payload.get("backoff_ms", 500))
elif diagnosis.action == "fallback":
run_fallback(diagnosis.payload)
else:
escalate(diagnosis)
await wai.diagnose_outcome(diagnosis.id, success=True)
Tracing
async with wai.trace("agent_turn", attributes={"role": "architect"}) as span:
span.set_attribute("retries", 0)
response = await llm.complete(...)
span.event("llm_call", attributes={"model": "claude"})
Spans nest automatically — wai.event() calls inside a trace() block
inherit the trace + span IDs.
FastAPI
from uais_wai.fastapi import WAIMiddleware
app.add_middleware(WAIMiddleware, client=wai, slow_threshold_ms=1000)
Emits per-request http.latency_ms metric, plus events on 5xx, slow
requests, and unhandled exceptions. Each request opens a trace so handler
events get the same trace_id.
SQLAlchemy
from sqlalchemy import create_engine
from uais_wai.sqlalchemy import attach_wai
engine = create_engine(DSN)
attach_wai(engine, wai, slow_query_ms=500)
Emits db.query.slow, db.deadlock.detected, db.pool.exhausted,
db.connection.failed. Works with sync + async engines.
Behavior guarantees
| Concern | What the SDK does |
|---|---|
| Backend down | Events buffer locally; client never crashes |
| Buffer full | Drop newest; emit wai.ratelimit.local_buffer_full when reconnected |
| 429 rate limit | Honors Retry-After + X-RateLimit-*, exponential backoff |
| Diagnose timeout | Returns Diagnosis(timed_out=True, action=diagnose_default_action) + fires wai.diagnose.timeout event |
| Network partition | Auto-reconnect on next event |
| PII | Stack traces + payloads scrubbed for UUIDs, secrets, emails before send |
Shutdown
await wai.close() # flushes buffer + closes connections
# or
async with WAIClient(...) as wai:
... # auto-close on exit
License
Apache-2.0.