v0.25.0 — deployment controls for HTTP workers
Four capabilities vgi-rpc had gained but VGI never exposed, plus the dependency floor that makes the last of them work.
--max-externalized-response-bytes
Caps a single externalized response — the payload uploaded to blob storage and replaced on the wire by a pointer — so a worker can be deployed behind a load balancer, API gateway, or object-store policy that will not carry an arbitrary body.
Unlike --max-stream-response-bytes, which is soft for producer streams because a continuation token carries the overshoot to the next turn, this cap is hard on every method type with no continuation escape: bytes already uploaded cannot be un-uploaded.
Available on create_app, vgi-serve, Worker.main --http, and the fixture server, and carried to granian children through export_serve_config. Default is no cap — the header's absence is what tells a client there is no ceiling.
Token introspection — Worker.resolve_token()
Optionally exposes POST {prefix}/__introspect_token__, resolving an opaque bearer credential to a principal for a reverse proxy that terminates the only public listener.
The route does not exist until the hook is overridden — absent, not routed-and-refusing. Detected by comparing against the base implementation rather than a flag, because a flag can be set without a lookup behind it.
Enabling it requires --introspect-principals / VGI_INTROSPECT_PRINCIPALS, with no permissive default and a startup failure when missing: authenticating and introspecting are different capabilities, and "any authenticated caller" lets any user resolve any other user's credential to its owner.
AuthUnavailableError
Re-exported from vgi.auth and documented for custom authenticate callbacks generally. It is deliberately not a ValueError — chain_authenticate advances on ValueError, so a sidecar outage raised as one reads as "not my credential, try the next" and ends up a 401 from the end of the chain, turning a thirty-second blip into a fleet-wide re-login storm.
Access-log sampling and async emission
--access-log-sample, --access-log-async, --access-log-queue-size, with VGI_WORKER_ACCESS_LOG_* equivalents resolved inside configure_worker_logging so every worker entry point honours them identically.
The sampler goes on a handler dedicated to vgi_rpc.access rather than the shared stderr handler — in VGI that handler also carries vgi and vgi_rpc, and dropping half of a traceback is not a saving. Trace correlation needs no configuration: vgi-rpc reads whatever span is current at emit time, so trace_id / span_id appear as soon as VGI_OTEL_ENABLED=1.
Dependency
Floor raised to vgi-rpc 0.39.1 rather than 0.39.0: --access-log-async raised RuntimeError: cannot set daemon status of active thread at startup in every release that shipped it, so the option VGI now surfaces would have been dead on arrival. Fixed upstream in Query-farm/vgi-rpc-python@27842b0.