feat: serve a generated OpenAPI spec from every Python runner - #69
feat: serve a generated OpenAPI spec from every Python runner#69rickstaa wants to merge 2 commits into
Conversation
Discovery gives a caller an app id and a URL and nothing about the interface, so the only way to learn what an app accepts is to read its source. FastAPI derives the schema from the request and response models and serves it at /openapi.json, which the orchestrator proxies like any other endpoint, so a caller can fetch it from the discovered url. Exploratory: one example only, to size the change before deciding whether the convention is worth adopting across the repo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Discovery gives a caller an app id and a URL and nothing about the interface, so the only way to learn what an app accepts is to read its source. FastAPI derives the schema from the request and response models and serves it at /openapi.json, which the orchestrator proxies like any other endpoint. Converts the four examples that run a server of ours. vllm and api-proxy are static runners with no code of ours, so they cannot participate. Exploratory, to size the change rather than to merge as is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Closing. Not because of cost, which is what I set out to measure and was wrong about: the conversion is net +32 lines across 12 files, essentially a wash, because declarative validation deletes more than the models add. Closing because it is too opinionated for this repo. Four of the six examples would use one framework, which reads as a requirement, and it directly contradicts what the examples exist to say: your app is a plain service and being on the network does not change how you write it. It also hides a real feature, that the SDK is framework-agnostic ( Branch stays up for reference. Findings are summarised on #33. |
Exploratory, for #33. Converts the four examples that run a server of ours, to size the change before deciding whether the convention is worth adopting. Not proposing to merge as is.
Cost
Line count is essentially a wash. The Pydantic models cost lines and delete more:
await request.json(), theisinstance(payload, dict)guards, theHTTPBadRequestraises and theweb.json_responsewrapping all disappear because validation becomes declarative.echoeven loses its hand-rolled_parse_modevalidator and theMODESfrozenset, replaced by aLiteralon the model.Dependencies:
fastapi+uvicorneverywhere, pluswebsocketsfor realtime-transcription.vllmandapi-proxycannot participate: one runs the stockvllm/vllm-openaiimage, the other is nginx. Neither has code of ours to generate a spec from.Verified end to end
Each app was rebuilt and exercised on the offchain stack:
{'message': 'Hello, Rick!'}through the orchestrator--mode blurand--mode robotboth complete, robot returnsh264+opus[FINAL]The spec is reachable from the discovered url with a plain GET, no protocol change and no
metadataentry:Two things worth knowing before deciding
WebSockets get no spec. OpenAPI 3.1 has no representation for them, so
realtime-transcriptionserves/openapi.jsonwith an emptypaths. The one example whose interface is least guessable is the one this does not document. Its wire protocol stays in the README.Declarative validation is not a drop-in.
echo's blur sweep sendsradius=0, which the aiohttp version silently clamped viamax(1, min(99, ...)). Expressing that asField(ge=1)turned it into a 422 and broke the sweep. Fixed by clamping in the handler as before, but it is a live example of behaviour changing under a mechanical-looking conversion.The trade
Size is not the argument against this, which is what I expected to find and did not. The trade is that the examples currently demonstrate "your app is a plain service, being on the network does not change how you write it", and this makes them demonstrate a framework choice as well. Every runner gains
build_app(), a lifespan contextmanager and a model layer that exist for the spec rather than for Livepeer.Also worth noting for the paid path: fetching
/openapi.jsonis a real call, so on a single-shot runner it reserves a session and is billable, the same asvllm's/v1/models.