Skip to content

Feat/flow batchexecute migration - #39

Merged
crisng95 merged 7 commits into
mainfrom
feat/flow-batchexecute-migration
Sep 7, 2026
Merged

crisng95 merged 7 commits into
mainfrom
feat/flow-batchexecute-migration

Conversation

@crisng95

@crisng95 crisng95 commented Sep 7, 2026

Copy link
Copy Markdown
Owner

No description provided.

crisng95 and others added 7 commits September 6, 2026 22:49
Flow moved off labs.google in September 2026 and stopped minting the
`Bearer ya29.…` the aisandbox-pa REST API needed. The rewritten frontend
signs every call with the session cookie plus a per-page `at` token
against one batchexecute endpoint, so nothing can be replayed from here:
the agent builds the envelope, the extension runs it in the Flow tab.

flow_batch.py holds the codec, the request builders and the readers,
ported from the flowgen bridge along with the traps that cost it hours —
the poll's third uuid is the scene and not the media, "Media not found."
is a complaint rather than a verdict, the listing decides where the poll
only hints, a media id arrives before the clip is fetchable, and image
aspect (1 = square) does not share video aspect's encoding (1 = portrait).

flow_client keeps its old surface and answers in the old REST shapes, so
the worker's parsers, the operation poller and the DB writers never learn
which transport ran. The legacy path stays behind USE_BATCH_RPC=0 as a
post-mortem tool. Upscale, r2v and start+end-frame chaining have no
captured payload and now fail as UNSUPPORTED_ON_BATCH_API instead of
reaching for the dead bearer; FLOW_ALLOW_DEGRADED=1 drops the latter two
to plain i2v.

refresh_project_urls stops being a stub — the media rpc re-signs a stored
id, which is exactly what /fk-refresh-urls always wanted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
Only the page can sign a batchexecute call, so the new `batch_rpc`
handler mints a reCAPTCHA through the existing grecaptcha bridge and
runs the POST in the tab's MAIN world, where `at` / `f.sid` / `bl` live.
The project listing is past 17 MB for the one entry we want, so the
runner cuts it to an 800-byte window around the operation id before
handing it back rather than pushing the rest through the bridge.

Every tab lookup now goes through one `flowUrls` list that includes
flow.google.com. Matching only the old URL is what produced
`CAPTCHA_FAILED: NO_FLOW_TAB` against a Flow tab sitting right there.

Captcha solving tries each Flow tab in turn and reloads discarded ones
instead of returning on the first miss — one stale tab used to veto every
generation.

The bearer capture, the aisandbox-pa proxy and the telemetry are kept for
USE_BATCH_RPC=0 and an old pinned tab, and are labelled as such.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
project.createProject went with the migration — the labs.google tRPC
endpoint it lived on is unauthenticated now, and calling it just fails.
Every batchexecute call is scoped to a project, so one is made once in
the Flow UI and its uuid supplied per project as `flow_project_id` or
pinned as FLOW_PROJECT_ID.

Reading the id back is split out so it works either way: the batch path
answers `{"projectId": …}`, the legacy tRPC path buried it under
result/data/json/result.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
An unported capability and a missing Flow project are configuration
answers, not something five retries can reach — UNSUPPORTED_ON_BATCH_API
and NO_FLOW_PROJECT now fail once instead of burning the retry budget on
every scene of a pipeline run.

The other direction for the poll: an operation can report "Media not
found." and still deliver a finished clip, so the complaint is carried
alongside a still-pending round and only quoted if we time out, where it
is the one piece of context worth having.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
The two transports answer a media lookup differently: the batch path
hands back a freshly signed url, the legacy REST path inlined the bytes
as base64. Try the url first and keep the encoded content as the
fallback, so an expired scene url still resolves on either path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
What the migration changes for whoever runs this next: a Flow project has
to be pinned, one signed-in flow.google.com tab has to stay open, and
`flow_key_present: false` is now normal rather than a fault.

fk-doctor gains the batch path's error taxonomy — NO_AT_TOKEN,
NO_FLOW_PROJECT, UNSUPPORTED_ON_BATCH_API — and loses the advice that
sent people looking for a bearer token that is not coming back. The
skills whose behaviour actually changed say so where you would hit it:
chaining and upscale name what they cannot do and offer the degraded
fallback, change-model explains that only the quality tier survives the
fold onto the three accepted names, refresh-urls describes what it does
now that it works.

docs/CAPTURE.md is the way back for the three unported payloads: record
the action, diff the slots, throw the capture away. Guessing at Google's
positional payloads does not work — a reference image in the wrong slot
is accepted and then silently ignored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
main gained Omni Flash, multi-profile extension failover, the Low Priority
workflow schema and the review CLI providers while this branch was porting
Flow onto batchexecute. Four textual conflicts, and three places where the
merge was clean but wrong:

`_send` now routes only through extensions that captured a bearer token.
No profile on the batch path ever captures one — it authenticates with the
session cookie in the page — so every request would have answered
NO_FLOW_KEY. The token requirement follows the transport now, and the
failover list learned the batch path's profile-local failures (NO_AT_TOKEN,
FLOW_TAB_DISCARDED), which is exactly the "this tab can't, another can"
class it was built for.

The retry shortcut reads a bare uuid as a Low Priority workflow name it
cannot re-poll, and resubmits. Batch operation ids are bare uuids, and they
*are* recoverable — the status poll finds them in the project listing — so
on that path a retry would have abandoned a running render and paid for a
second one. The heuristic is now per-transport.

Omni Flash speaks the pre-migration REST and tRPC endpoints and has no
captured batchexecute payload, so it joins upscale, r2v and chaining in
failing with UNSUPPORTED_ON_BATCH_API instead of dying on a 401 five
retries deep. Its wire-contract tests are pinned to the legacy path, where
those contracts are still exactly right, and the batch path's refusal is
covered on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JkgMuy89iJ9qc1NkRdPk5
@crisng95
crisng95 merged commit ce37f4b into main Sep 7, 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant