Skip to main content
These workflows show the SDK’s APIs working together the way a real integration does — not isolated snippets. Each one is copy-paste ready against a valid credential.

1. Provision a working Agent (control-plane, one-time setup)

The canonical provisioning flow: Provider → Skill → Knowledge → Agent (with attachments) → verify. All control-plane calls (no external_user_id).
Create a Knowledge base, embed a document, then run the same similarity search an attached Agent would use internally.
upload_documents() is synchronous — it returns only once embedding finishes (expect it to take longer for larger/more files; up to 10 files × 20MB, PDF/TXT/MD/JSON/CSV).

3. OAuth connection flow for an MCP server

For an authType: "oauth" MCP: register it, then drive the owner- or user-mode browser flow. This is the two-step pattern your backend and frontend cooperate on.
Then, once connected, test_connection() populates the MCP’s tool/resource inventory:

4. Human-in-the-loop tool approval flow

An Agent configured with a sensitive tool pauses for approval. Drive the full approve/reject round-trip on the same Thread.
Note the flow: thread_id must match the run that paused; resume’s shape must match the interrupt’s kind (hitl → {"decisions": [...]}, clarification → {"answers": [...], "text": ...}).

5. Per-user conversation history with files

The runtime-plane pattern: one client per request, threads persisted explicitly, files attached to a conversation.
threads.list() then shows each user’s Threads most-recently-active-first, with the Agent populated as an object.

6. Error handling: resilient provisioning

Retry with an idempotency key after ambiguous failures, and handle the typed errors distinctly:

7. Connection pooling at high request volume

Constructing a client is cheap — no connection happens at construction time — so build a fresh, per-request instance scoped to whoever is making the request (every recipe above does exactly that). But if you don’t share anything, each instance opens its own httpx connection pool, so no TCP/TLS connection is ever reused across requests. At high volume, build one httpx.Client/httpx.AsyncClient at app startup and pass it to every per-request client via http_client=:
This is safe even if individual requests use async with on their own client — closing one of those never closes a client you passed in via http_client=; only a client the SDK created for you gets closed. Close shared_http_client yourself, once, at app shutdown.

8. Flask

No special handling — construct the client once at module scope and use it in your view functions.

9. FastAPI

Construct the client per-request via a Depends() provider so it plugs into FastAPI’s own dependency-injection system — the SDK itself needs no FastAPI-specific support, and this uses the async client since FastAPI route handlers are async def. Shares one httpx.AsyncClient across every request (see Connection pooling above) since a real API is likely to see meaningful request volume.

10. Django

Wire a module-level singleton, same idea as Flask — Django views are sync by default, so the sync PersonaClient is the natural fit.
Keep PERSONA_CREDENTIAL in your environment / secrets manager and read it into settings.py (os.environ["PERSONA_CREDENTIAL"]) — never commit it, and never expose it via a template context processor a browser can read.