Async Usage
Use AsyncSolwyn for async applications — context managers, event loops, and provider examples
import asyncio
import os
from openai import AsyncOpenAI
from solwyn import AsyncSolwyn
async def main():
async with AsyncSolwyn(
AsyncOpenAI(),
api_key=os.environ["SOLWYN_API_KEY"],
) as client:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
asyncio.run(main())AsyncSolwyn provides the same API as Solwyn but with async/await support. Use it when your application runs in an async event loop (FastAPI, aiohttp, etc.).
Context manager
Always use async with to ensure resources are properly cleaned up:
async with AsyncSolwyn(
AsyncOpenAI(),
api_key=os.environ["SOLWYN_API_KEY"],
) as client:
# client is ready -- reporter is started
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
# client.close() is called automaticallyThe async with block calls __aenter__() which starts the background metadata reporter, and __aexit__() which flushes pending reports and closes HTTP connections.
If you cannot use a context manager, call await client.close() explicitly:
client = AsyncSolwyn(
AsyncOpenAI(),
api_key=os.environ["SOLWYN_API_KEY"],
)
try:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
finally:
await client.close()Changed in 0.4.0. This pattern used to be quietly lossy: without __aenter__, the reporter never started its flush loop, so events and settlements sat in the queue until close() — and server-side spend tracking drifted for the life of the client. The flush loop now starts on the first enqueue, so the client above reports normally. await client.close() is still required to flush what remains and surrender any held budget leases. See Spend delivery.
Per-provider async
The async surface mirrors the sync wrapper for every provider: pass the provider's async client to AsyncSolwyn() and call it the same way you would synchronously. Each provider page carries its own async example and any provider-specific notes:
- OpenAI —
AsyncOpenAI(). - Anthropic —
AsyncAnthropic(). - Google Gemini —
genai.Client(...). - Amazon Bedrock — uses aioboto3; the aioboto3 client is itself an async context manager, and async streaming iterates
result["stream"]withasync for. - Together AI —
AsyncTogether(), detected natively like its sync counterpart. - OpenAI-compatible providers —
AsyncOpenAI(base_url=...).
Event loop notes
AsyncSolwynmust be used within a running async event loop.- The background metadata reporter uses
asyncio.create_task()to send batches without blocking your LLM calls. - Changed in 0.4.0: that flush loop now starts on the first enqueue, not only on an explicit
start(). Previously, anAsyncSolwynconstructed withoutasync withqueued events and settlements silently untilclose(), which drifted server-side spend tracking. If there is no running loop when an event is enqueued, the item stays queued and the SDK logsreporter.enqueue_without_event_looponce per reporter. Enqueueing never raises. See Spend delivery. - Do not mix
Solwyn(sync) andAsyncSolwyn(async) in the same event loop. UseSolwynfor synchronous code andAsyncSolwynfor async code. asyncio.run(main())creates and manages the event loop. If you are using a framework like FastAPI, the framework manages the event loop for you -- just useasync within your lifespan or dependency injection.
Concurrent calls
AsyncSolwyn supports concurrent LLM calls with asyncio.gather:
import asyncio
import os
from openai import AsyncOpenAI
from solwyn import AsyncSolwyn
async def main():
async with AsyncSolwyn(
AsyncOpenAI(),
api_key=os.environ["SOLWYN_API_KEY"],
) as client:
tasks = [
client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"Count to {i}"}],
)
for i in range(1, 4)
]
responses = await asyncio.gather(*tasks)
for r in responses:
print(r.choices[0].message.content)
asyncio.run(main())Each concurrent call independently checks budget, reports metadata, and updates the circuit breaker.
Streaming
Stream LLM responses through Solwyn — works transparently with all five native providers plus OpenAI-compatible endpoints
Spend delivery
How usage and settlement leave your process — at-least-once delivery, retry and backoff, shutdown and exit behavior, and what happens to spend that cannot be delivered.