diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f5fcbe..2ce7cad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## 0.5.0 — 2026-07-06 + +### Added +- **Media endpoints on the FastAPI sidecar** (#14). The proxy only exposed + `/v1/images/generations`, so OpenAI-compatible clients (LiteLLM) could not + reach the gateway's video/audio models. Adds: + - `POST /v1/videos/generations` + - `POST /v1/audio/speech` + - `POST /v1/audio/generations` (music) + - `POST /v1/audio/sound-effects` + + The adapter dispatches Base (dedicated `VideoClient`/`MusicClient`/ + `SpeechClient`) vs Solana (unified `SolanaLLMClient`) per request; sync SDK + clients run in a shared thread pool. Validated live end-to-end on Solana + mainnet. + +### Changed +- **Require `blockrun-llm[solana]>=1.5.0`** for the `solana` extra — Solana + media (`SolanaLLMClient.video/music/speech/sound_effect`) landed in the SDK's + 1.5.0 release (blockrun-llm #16; also carries #17 rpc_batch cache fix, #18 + `solana<0.40` pin, #19 media hardening). Older SDKs degrade Solana media to a + clear 501, not a 500. The core `blockrun-llm>=1.4.7` floor is unchanged — Base + media clients predate it. +- Synced `__version__` (was stale at 0.4.2). + +### Hardened (#15, media-endpoints review follow-up) +- `ValueError → 400` on **all** media routes via a shared `_media_endpoint` + helper (was video-only; music-with-lyrics 500'd instead of returning the SDK's + clear message). +- Solana media on a pre-1.5.0 SDK degrades to a clear **501** upgrade hint + instead of an `AttributeError` 500. +- Long media (video 60–900s, music 60–210s) moved to a dedicated 8-thread pool + (`BLOCKRUN_LONG_MEDIA_THREADS`); all media routes gated behind their own + semaphore (`BLOCKRUN_MEDIA_MAX_CONCURRENT`, default 20) so a video burst can no + longer starve images or brick chat/messages. +- Client-supplied `budget_seconds`/`timeout` clamped to the 900s server cap + (was forwarded verbatim — one request body could pin a worker for a day); + every media call wrapped in `asyncio.wait_for` so the coroutine + semaphore + permit always release even if the SDK thread wedges (504). +- Media calls now audit-log via `log_proxy_call` and surface the in-body + settlement txHash as `x-blockrun-settlement` (paid media traffic was invisible + to spend reconciliation). NB: media SDK responses don't expose `cost_usd` yet, + so media audit rows log `cost_usd=None` with only the settlement txHash. +- Full negative-path pytest suites for all 5 media routes + adapter + dispatch/clamp/guard/ceiling tests. + ## 0.4.7 — 2026-06-26 ### Added diff --git a/blockrun_litellm/__init__.py b/blockrun_litellm/__init__.py index 6e363a9..1325193 100644 --- a/blockrun_litellm/__init__.py +++ b/blockrun_litellm/__init__.py @@ -26,4 +26,4 @@ from blockrun_litellm.provider import BlockRunLLM, register __all__ = ["BlockRunLLM", "register", "enable_local_logging"] -__version__ = "0.4.2" +__version__ = "0.5.0" diff --git a/pyproject.toml b/pyproject.toml index 6ed6376..d310eb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "blockrun-litellm" -version = "0.4.7" +version = "0.5.0" description = "LiteLLM adapter for BlockRun — call x402-paid AI models via LiteLLM (custom provider or local OpenAI-compatible proxy)" readme = "README.md" license = "MIT" @@ -40,9 +40,10 @@ dependencies = [ # Re-exported here so `pip install 'blockrun-litellm[solana]'` pulls the # x402 SVM toolchain that SolanaLLMClient needs (x402 SDK + solders). # NB: Solana *media* (SolanaLLMClient.video/music/speech/sound_effect) needs the -# blockrun-llm release carrying BlockRunAI/blockrun-llm#16 — bump this floor when -# it ships. Until then the adapter degrades those calls to a clear 501, not a 500. -solana = ["blockrun-llm[solana]>=1.4.7"] +# blockrun-llm release carrying BlockRunAI/blockrun-llm#16, shipped in 1.5.0 +# (also carries #17 rpc_batch cache fix, #18 solana<0.40 pin, #19 media +# hardening). Older SDKs degrade Solana media to a clear 501, not a 500. +solana = ["blockrun-llm[solana]>=1.5.0"] proxy = [ "fastapi>=0.110.0", "uvicorn[standard]>=0.27.0",