Chore/flow drop legacy rest - #49
Merged
Merged
Conversation
Flow moved to flow.google.com in September 2026 and stopped minting the `Bearer ya29.…` the aisandbox-pa REST path needed. That path has been unreachable ever since, kept behind USE_BATCH_RPC=0 as a post-mortem tool. Keeping it cost more than it was worth. A dead implementation sitting beside a live one is a template: the Omni module was written against it, so when the migration landed on FlowClient it missed Omni entirely, and Omni frame and reference generation have been returning UNSUPPORTED_ON_BATCH_API since. Deleting the template is what stops the next copy. Removed: the ten _legacy_* methods, the twelve `if not USE_BATCH_RPC` branches in FlowClient (ten dispatching to those methods, one returning an inline note from refresh_project_urls, and upscale_image's, which arrived with the migrated image API this rebased onto), _build_url/_client_context, ENDPOINTS, GOOGLE_FLOW_API, GOOGLE_API_KEY, the browser-fingerprint pools and agent/services/headers.py that fed them, the tRPC polling branch in omni_flash, and omni_flash's _annotate_polling, whose only callers were the REST submits. RECAPTCHA_SITE_KEY went too: it had no Python caller, and the extension hardcodes its own copy in injected.js, so the env var was a knob that changed nothing. Git history has all of it if a payload is ever needed. One deliberate behavior change, in the unported Omni modes. Previously the capability check ran first, so a bad duration on frame-to-video answered 502 UNSUPPORTED_ON_BATCH_API. Now validation runs first, so it answers 400 "duration 5s is unsupported". A caller who can fix the duration should hear about the duration; the gap it cannot fix comes after. No caller exists today either way — the pipeline uses model_family=veo. The extension keeps its api_request and trpc_request handlers, so an extension updated ahead of its agent still serves an older one. To be clear about what that is worth: on any profile that postdates the migration nothing in the extension reaches aisandbox-pa either — sendTelemetry early-returns without a flowKey that is no longer minted. So the host permission is held by the backward-compat proxy alone, and the two now share one lifetime: when the oldest agent in the wild speaks batch_rpc, the handlers and manifest.json's aisandbox-pa entry go together. That is a manifest bump and a user-visible reload, so it is its own change. Tests: test_omni_flash.py was pinned to the legacy path by a module-level autouse fixture setting USE_BATCH_RPC=False, so all 34 of its tests would have errored on the missing attribute. 10 asserted REST or tRPC contracts for code this commit deletes and went with it; the remaining 24 — the model-key mapping, the input validation, the batch-path tests — were kept, and one new test pins the seven-reference boundary that a deleted test used to cover. Two tests added for the retry branch in generate_scene_video. It used to be gated on `bare_uuid and not USE_BATCH_RPC`, so it was dead on the only transport that exists and had no coverage — and it is the one branch where a wrong answer abandons a render Flow is already paying for and starts a second. Checked by forcing the branch off: the test fails. A comment in operations.py that described that resubmit was removed too; left in place it reads as an instruction to reintroduce it. agent/services/flow_client.py 1290 -> 921 agent/services/omni_flash.py 672 -> 350 agent/config.py 158 -> 111 211 passed, 3 failed — the 3 are pre-existing on main (test_processor.py patches processor._retry_state, which does not exist). Golden envelope tests pass, so the Veo submit payload is unchanged byte-for-byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DB27wvPQ195KGiQ6VZfCDf
Six tests failed for reasons unrelated to the code under test, and one of them hung the interpreter. test_processor.py patched `agent.worker.processor._retry_state`, a module global that no longer exists: retry state became the instance attribute `self._retry_after` plus an explicit `retry_after` parameter on _handle_failure. mock.patch refuses a missing attribute without create=True, so all three tests raised AttributeError before their bodies ran. The assertions were always fine — _handle_failure(rid, req, result) still matches the signature — so the patch line just goes. test_result_handler.py mocked crud.update_scene but not crud.get_scene, which c071cb8 added at result_handler.py:61 for the chain cascade. Since April those three tests hit a real database with no schema, hence "no such table: scene". They now mock get_scene returning None — the no-parent case, which keeps update_scene's assert_awaited_once true. That accidental connection was also why `pytest tests/unit` never exited: aiosqlite services each connection on a non-daemon worker thread, and this one was never closed, so the thread outlived the session. Piping the run hid it, because the summary sat in the pipe buffer while the process refused to die. 266 passed, and the process exits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
A live 2K export failed with `SPrCad: NO_INJECTION_RESULT` and the taxonomy had no entry for it, so diagnosing it meant reading background.js from scratch — the one thing this skill exists to prevent. The string comes from extension/background.js:540, where executeScript resolved with no frame result: the Flow tab was gone or still booting, so the envelope never ran. It landed on the first captcha-bearing RPC after an agent restart and cleared on retry. The row records what the evidence ruled out, because all three are easy to reach for and wrong: a failed captcha mint reports CAPTCHA_FAILED, an oversized payload is not it (MAX_RPC_TEXT is 32 MB), and a structured-clone failure surfaces as 500 rather than 502. Auto-handling is the generic branch in processor.py — retried with backoff, counted against MAX_RETRIES — not the captcha branch's ten free attempts. Also added to the auto-invoke trigger list, so the next one routes here instead of being guessed at. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
43b0406 changed background.js and injected.js without bumping the manifest, so /health reported 0.3.1 for both the pre- and post-merge build. There was no way to tell a stale extension from a current one — which is the first question you ask when an RPC misbehaves. background.js:229 reports getManifest().version, so the bump makes it answerable; reload the extension once and /health says 0.3.2. README gets the status at the top, where someone landing on the repo sees it before anything else: the batchexecute transport is verified end to end against the live API — image generation, 2K export and i2v — and the four unported capabilities fail loudly rather than guessing. That list is taken from the guards themselves, not from the docs, because the docs disagreed. flow_client.py blocks start+end chaining, r2v and video upscale; omni_flash.py:33 blocks Omni frame/reference. CLAUDE.md calls the third one "4K upscale", which reads as the image export — and that one in fact works, verified at 1536x2752 from a 768x1376 source. CAPTURE.md lists a fourth item the image API merge has since ported. The Architecture callout's v0.3.0+ was aligned to v0.3.2+ so the two do not contradict. Also ignore extension/_metadata/, which Chrome generates when it loads the unpacked extension. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
This was referenced Sep 17, 2026
crisng95
added a commit
that referenced
this pull request
Sep 17, 2026
First release since v1.1.0 (2026-05-09), and it is one arc: Flow moved to flow.google.com in September 2026 and stopped minting the bearer the old REST API needed, so the transport was rebuilt on batchexecute (#39), the dead REST path deleted (#49), the image API migrated (#42), and the Omni image-conditioned modes ported back on top of it (#48/#50). Also fixes a version drift this release would otherwise have deepened. ccf89c6 put "0.2.0" in two places in agent/main.py; 939b956 bumped only the FastAPI line, so /health has reported 0.2.0 ever since while the app said 1.1.0 — three releases stale, on the endpoint CLAUDE.md tells you to curl before anything else. /health now reads app.version, so there is one string to bump instead of two literals that agree only by luck. extension/manifest.json is deliberately not bumped. It tracks the extension's own lifecycle, it is at 0.3.2, and a bump there forces a user-visible reload. Verified: 272 passed; /health and app.version both report 1.2.0, checked by calling the handler rather than reading the source. Not verified: the Omni envelopes from #48. They are live-verified per that PR and the tests lock their shape, but nothing has submitted through a signed-in Flow tab since the merge resolution. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Removes the
aisandbox-pa.googleapis.comREST transport, which has had noreachable caller since Flow moved to
flow.google.comin September 2026 andstopped minting the
Bearer ya29.…it needed. Net −1043 lines.Keeping a dead implementation beside a live one turned out to cost more than it
saved: the Omni module was written against the REST path, so when the migration
landed on
FlowClientit missed Omni entirely, and Omni frame/referencegeneration has been returning
UNSUPPORTED_ON_BATCH_APIever since. Deletingthe template is what stops the next copy.
Removed: the ten
_legacy_*methods, the twelveif not USE_BATCH_RPCbranchesin
FlowClient,_build_url/_client_context,ENDPOINTS,GOOGLE_FLOW_API,GOOGLE_API_KEY, the browser-fingerprint pools andagent/services/headers.pythat fed them, the tRPC polling branch in
omni_flash, and_annotate_polling,whose only callers were the REST submits.
RECAPTCHA_SITE_KEYwent too — noPython caller, and the extension hardcodes its own copy in
injected.js.The extension keeps its
api_request/trpc_requestproxies for now. No currentagent sends them, but an older agent in the wild might; retiring them is a
manifest.jsonbump and a user-visible reload, so it is its own change.Commits
d56a5ccd009dc2f4e2265/fk-doctortheNO_INJECTION_RESULTerror0c45b39Verified against the live Flow API
Not just unit tests — the whole path was exercised end to end through a
signed-in Flow tab, since that is the only thing that can sign these calls:
generate-image2ad427aa-…, proper UUIDexport-image2Kgenerate-video(i2v, veo)cf6f80cd-…get_media,credits_legacy_*methodsUNSUPPORTED_ON_BATCH_API— fails loudly, as intendedEvery response arrived over
POST /api/ext/callbackwithmatch=yes, i.e. theprimary delivery path, not the WS fallback.
Worth a reviewer's attention
One defect came from the rebase, not from either parent. This branch deleted
the
USE_BATCH_RPCdefinition while the migrated image API (#42) added a newif not USE_BATCH_RPC:guard insideupscale_image. Different files, so gitmerged both cleanly and
upscale_imageraisedNameErroron every call. It isremoved here the same way as the other eleven guards, and the 2K export above is
that code path running for real.
The four unported capabilities are listed from the guards, not the docs,
because the docs disagree.
flow_client.pyblocks start+end chaining, r2v andvideo upscale;
omni_flash.py:33blocks Omni frame/reference.CLAUDE.mdcalls the third "4K upscale", which reads as the image export — and that one
works (see the 2K result above).
docs/CAPTURE.mdalso still lists an item theimage API merge has since ported. Flagging rather than fixing: correcting those
two docs is not this PR's job.
Tests
266 passed, and the suite now exits.Two mocks had drifted behind refactors and were failing for reasons unrelated to
this change:
test_processor.pypatchedprocessor._retry_state, a module global replacedby
self._retry_afterplus aretry_afterparameter.mock.patchrejects amissing attribute, so three tests raised
AttributeErrorbefore their bodies ran.test_result_handler.pymockedcrud.update_scenebut notcrud.get_scene,which
c071cb8added for the chain cascade in April. Those three tests had beenhitting a real schema-less database ever since.
That second one also explains why
pytest tests/unitnever exited:aiosqliteservices each connection on a non-daemon thread, and the connection opened by
accident was never closed, so it outlived the session. Piping the run hid it —
the summary sat in the pipe buffer while the process refused to die.
Not in this PR
extension/manifest.json'saisandbox-pahost entry, and the two legacyproxies in
background.js— they share one lifetime and need a reload.CLAUDE.md's "4K upscale" wording anddocs/CAPTURE.md's stale entry.drawtexttest failures on a stock Homebrewffmpeg: that build shipswithout
--enable-libfreetype, so text-overlay skills needffmpeg-fullonPATH. Environmental, pre-existing, unrelated.
Reviewer notes
/healthshould then report0.3.2.Before this PR it reported
0.3.1for both the pre- and post-Expand migrated image API: model selection, edits and 2K export #42 build, so astale extension was indistinguishable from a current one.
flow_key_present: falsein/api/flow/statusis normal on this transport;there is no bearer to capture.
"Media not found."is not a failure — finishedjobs report it. Confirm via the media record instead.
🤖 Generated with Claude Code