fix(video): normalize Gemini Omni file URIs; document provider in PROVIDERS.md

Review findings from PR #333:

P1: _download_via_uri assumed output_video.uri is always files/<id>.
The API can return a full resource URI or a ready-made
.../files/<id>:download?alt=media download URL, which produced an
invalid poll path with a second :download appended. New
_file_id_from_uri() extracts the bare id from every documented shape;
regression tests cover the full-URL form plus a parametrized matrix of
URI shapes.

P2: docs/PROVIDERS.md still described the Google key as TTS + Imagen
only. The shared-key section now covers gemini_omni_video (model id,
~$0.10/sec pricing table, paid-tier-only, edit-turn billing note), and
the env snippet, provider-to-tool mapping, and capability coverage
tables include the new provider.
This commit is contained in:
calesthio
2026-07-08 23:45:47 -07:00
parent 34d1053526
commit 2ef18e77a9
3 changed files with 74 additions and 10 deletions

View File

@@ -296,9 +296,24 @@ class GeminiOmniVideo(BaseTool):
return item
return None
@staticmethod
def _file_id_from_uri(uri: str) -> str:
"""Extract the bare file id from any documented URI shape.
The API may return ``files/<id>``, a full
``https://.../v1beta/files/<id>`` resource URI, or a ready-made
download URL ``.../files/<id>:download?alt=media``. Polling and
download both need just ``<id>``.
"""
path = uri.split("?", 1)[0].rstrip("/")
marker = "files/"
idx = path.rfind(marker)
tail = path[idx + len(marker):] if idx != -1 else path.split("/")[-1]
return tail.split(":", 1)[0]
def _download_via_uri(self, requests_mod: Any, api_key: str, uri: str) -> bytes:
"""Poll a Files API entry until ACTIVE, then download its bytes."""
file_id = uri.rstrip("/").split("/")[-1]
file_id = self._file_id_from_uri(uri)
headers = {"x-goog-api-key": api_key}
deadline = time.time() + _MAX_POLL_SECONDS
while True: