Repository navigation
Conversation
Port the jHPbke (create) and QI2zvc (delete) RPCs captured off the Flow UI: - flow_batch: RPC_CREATE_PROJECT/RPC_DELETE_PROJECT, request builders, and read_created_project_id (slot 0, uuid fullmatch, raises otherwise). - flow_client.create_project mints a project via jHPbke when unpinned (pin still reused first); rejects non-default tool_name on batch; delete_project via QI2zvc. - projects DELETE route: preflight get_project (404 before any RPC), remote-first delete of every project except the pinned/shared one, local row kept on failure. Verified: 100 unit tests + a live create/delete round trip on Flow.
A pinned or request-supplied Flow project id may already have a local row; the bare INSERT then raised UNIQUE constraint failed and surfaced as a 500. Return the existing row when the id is already tracked.
feat: OmniVoice TTS từ xa + tạo/xoá Flow project trên batchexecute
…ion-deploy fix(extension): prevent idle Flow tab leaks
…nivoice-tts Revert "feat: OmniVoice TTS từ xa + tạo/xoá Flow project trên batchexecute"
Port Omni Flash text-to-video to migrated Flow API
The batch builders are about to gain a caller: Omni will submit through the same generate_video that Veo uses, differing only by a model key. That refactor can drop a trailing null and still look fine — Flow accepts a malformed payload and then ignores it, which reads exactly like success. test_flow_batch.py asserts positions, and positions survive that. So assert the whole string instead. Checked by flipping SURFACE_ID 22 -> 23: all three goldens fail, and all 48 position tests pass. Also adds requirements-dev.txt — the test deps were undeclared, so a fresh checkout could not run the suite that guards any of this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DB27wvPQ195KGiQ6VZfCDf
test(flow): lock the wire envelopes before consolidating the Flow API surface
Expand migrated image API: model selection, edits and 2K export
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
Chore/flow drop legacy rest
…batch API Closes the gap the REST removal documented: Omni's image-conditioned modes were written against the pre-migration REST endpoints, so the migration to `FlowClient` missed them and they have been answering `UNSUPPORTED_ON_BATCH_API` since. crisng95#48 captured their batchexecute payloads — `eb1hJf` (first frame), `nprQif` (first+last), `MZZa6b` (references) — and this merge lands them. crisng95#48 was cut from a49831f, before the REST transport was removed, and preserved the dual-transport shape on purpose: "the legacy REST implementations are kept below for non-batch deployments." On current main that half does not merely conflict, it does not import — `agent.config.USE_BATCH_RPC`, `agent/services/headers.py` and `FlowClient._build_url`/`_client_context` are all gone. So the resolution keeps crisng95#48's batch submits byte for byte, including the captured envelopes and the 360p model-key suffixes, and deletes the REST half rather than trying to revive it: - dropped the REST bodies of `_submit_omni_frame_video` and `generate_omni_flash_video`, the tRPC poller behind `check_omni_flash_status`, `_annotate_polling`, `_fetch_project_initial_data` and `_fetch_media_url` - unwrapped the two surviving `if USE_BATCH_RPC:` blocks and removed the flag's five imports and four references - dropped both `model_key = _load_model_key(...)` assignments: their only consumer was the REST body's `videoModelKey`. `_load_model_key` itself stays, tested directly, and `models.json` still carries all three modes - 709 lines to 417; imports are back to main's set Tests needed the same treatment, and two of them needed judgement rather than deletion. crisng95#48's suite was pinned to the REST path by a module-level autouse fixture setting `USE_BATCH_RPC=False`, so several tests that never name the flag still exercised the old poller. Dropped the seven REST/tRPC wire-contract tests; converted `..._returns_signed_url_without_buffering_video` and `..._missing_media_is_pending` onto the batch poller, because what they pin still matters — the poller must hand back Flow's signed url instead of buffering the clip, and a media record without a `/video/` url is pending, not done. Dropped `..._requires_project_id_for_legacy_descriptors`: the batch poller deliberately resolves a missing project id instead of refusing. The seven-reference boundary existed on both sides in a form that no longer applies — main asserted it reached the capability gap, crisng95#48 asserted it through the REST body — so it is rewritten against the batch submit. Seven is the limit, not one past it, and with r2v live it has to reach the wire or an off-by-one in the validator reads as a Flow refusal. Docs followed the behaviour, since the merge falsifies claims main shipped yesterday: README's note and capability table, CLAUDE.md, and the `UNSUPPORTED_ON_BATCH_API: Omni Flash` row in `/fk-doctor`, an error string nothing can produce any more. The unported set is now three, all on the Veo path, and Veo chaining/r2v callers get pointed at the Omni modes that cover the same shot. CLAUDE.md's "4K upscale" was corrected to video upscale while there: it read as the image export, which works. 272 passed, up from 266, and the suite exits. Not verified: the captured envelopes themselves. crisng95#48 reports them live-verified on 2026-09-14 and the tests lock their shape, but proving the wire format needs a real submit through a signed-in Flow tab, which this merge did not do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
Merge crisng95#48: restore Omni frame/first+last/reference on the batch API
The sponsor block sat between the badges and the project title, above everything that explains what Flow Kit is — including the note admitting it was put there because nobody scrolls past the badges. Removed, along with the two QR images it was the only referrer of; `git log` still has them if it comes back. `.github/FUNDING.yml` is left alone: `ko_fi: crisnguyen95` drives GitHub's own Sponsor button on the repo page, which is a separate surface from README copy and its own decision. The changelog goes before `## License` rather than at the top, so it does not push Quick Start down the page. Entries are taken from merge commits and tag dates, not written from memory, and the September rows are one arc: Flow moved to flow.google.com, so the transport was rebuilt, the REST path deleted, and the Omni modes ported back on top of it. Links are relative (`../../pull/N`) because the badges point at tuannguyenhoangit-droid/google-flow-agent while origin is crisng95/flowkit — a relative link resolves correctly on either. Also ignore `.omc/`, the oh-my-claudecode session state. It is tooling output, not project content, and without this a plain `git add -A` sweeps ~800 lines of it into the index. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
Flow Kit -> Muse2APIProvider -> muse2api -> muse.ai. A new `muse2api` MediaProvider renders scene/reference images and i2v video through a muse2api gateway (https://github.com/crisng95/muse2api): - agent/services/muse2api_client.py: async HTTP client for /v1/images/generations, /v1/videos (+ task polling) and /v1/media, Bearer auth, OpenAI error bodies surfaced as "muse2api <code>". Input frames are sent inline as data URLs so the gateway can run on another host. - agent/sdk/services/muse2api_provider.py: translates ProviderJobs, downloads results into output/_shared/muse2api/ as file:// URLs with minted UUID media_ids (Flow-shaped results, pipeline unchanged). Chained end frames and r2v fail loudly unless MUSE2API_ALLOW_DEGRADED=1; edit/upscale/audio are not offered. - Registered in ProviderRegistry; available once MUSE2API_URL is set. - Config, README, fk-provider/fk-doctor and generation skills updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MfvQsdxJhWw15u6Zm51YJM
Spell out that the muse2api gateway is a separate service Flow Kit does not ship or start: clone crisng95/muse2api, configure the browser driver, start it, import a muse.ai account, verify /readyz, then point Flow Kit at it with MUSE2API_URL / MUSE2API_KEY. Adds a pointer from Quick Start and the env-var table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MfvQsdxJhWw15u6Zm51YJM
…locked") Two coroutines hitting get_db() before the connection existed both saw None and both connected; the second overwrote the global, so the first ran its PRAGMAs (including wal_checkpoint) on the second's connection while a statement was open on it. That failed intermittently with "sqlite3.OperationalError: database table is locked" in test_assistant_provider on CI (Python 3.10, also on main in run crisng95#33) and leaked a connection whose worker thread can keep the interpreter alive. Connect under a per-event-loop init lock (separate from _db_lock, which crud holds while calling get_db), set up a local, and publish it only when ready. Adds a regression test counting connect() calls under concurrent first callers; it fails without this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MfvQsdxJhWw15u6Zm51YJM
…-1567a3 Add muse2api media provider for muse.ai rendering
…id-vowel OmniVoice returns audio that stops at the last voiced sample: zero release tail, final vowel clipped. Any pipeline that trims video to narrator length then cuts exactly where the voice is still ringing, which reads as an abrupt scene change. Fade the last 60 ms and append 0.4 s of silence inside the save path so every wav ends cleanly and downstream trims get a breath.
A scene whose narration runs 7.6s cannot breathe inside an 8s clip; the only post fix is a frozen last frame, which reads as a glitch. Pass scene.duration into job.extra and round it UP to the next supported Omni Flash step (4/6/8/10) in the provider — rounding down would clip the voice. Veo ignores the field. Defaults unchanged.
fix: resolve file:// URLs correctly on Windows
…ss, provider platform, and upload api
Comprehensive System Bug Fixes & Windows Cross-Platform Hardening
…, and production skills - Add 5 new production skills: fk-scriptwriter, fk-character-bible, fk-action-choreography, fk-cinematic-transitions, fk-sound-design - Add scripts for film mastering (build_master_film), hardsub burning (generate_subtitles), series manifest (series_manifest), and SFX layering (sfx_layering) - Add sync_skills and validate_skills for tool parity across Antigravity IDE and Claude Code - Upgrade fk-concat-fit-narrator with bumper transitions, audio ducking, and hardsubs - Upgrade fk-gen-narrator with Edge-TTS neural voice profiles and pacing controls - Upgrade fk-review-video with automatic prompt healing loop - Fix manifest synchronization in agent/api/projects.py to merge all chapters - Fix polling timeout guard in agent/worker/processor.py - Support Antigravity IDE target in setup.py (.agents/skills) - Clean up git tracking for large scratch dumps and update .gitignore
feat(skills,pipeline): add cinematic series tooling, per-project manifest manager, and production skills
…NO_BANANA_2 nickname
Banana 2 (NARWHAL) answers [5] NOT_FOUND on ogiZ0b in every project since
early October 2026. BELUGA (the UI's beluga_display) is its successor and
generates normally on the batch path.
- IMAGE_MODELS accepts BELUGA and BELUGA_THINKING_{LOW,MED,HIGH}.
- NANO_BANANA_2_1 -> BELUGA; NANO_BANANA_2 now lands on BELUGA too. NARWHAL
still passes through when named explicitly.
- Default image model is unchanged (NANO_BANANA_PRO / GEM_PIX_2).
Verified live on 2026-10-24: BELUGA 200, NANO_BANANA_2 via the new mapping
200, NARWHAL [5]. BELUGA_THINKING_* not exercised live.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The provider dropped every reference image on the assumption that the gateway took none. It does: /v1/images/generations accepts `image` as a data URL or a list of them, and the browser driver attaches them to the muse.ai chat. Scenes rendered through muse2api therefore lost their characters. - Muse2APIClient.generate_image takes `images` and sends them as `image`, capped at MAX_IMAGE_REFS (4). - The provider dedupes the job's refs, keeps the first four (logging the rest) and inlines them as data URLs. - An unreadable or unreachable ref now fails the job instead of rendering the scene without its character; httpx errors on input fetch are caught like OSError/ValueError (this also covers a video's start frame). - README and /fk-provider describe the new behaviour and the billing note for gateways with wallets enabled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ck retries Issue crisng95#67 reports accounts whose manual Flow UI generation was blocked after FlowKit testing; retrying into the block is a suspected cause. - The generation hold after PUBLIC_ERROR_UNUSUAL_ACTIVITY is written to flow_generation_hold.json and restored on start, so a restart no longer lifts it. FLOW_UNUSUAL_ACTIVITY_COOLDOWN_S defaults to 3600 (was 120). A shorter hold never replaces a longer one or its reason. - [HIJACK] extension_hijack_detected was requeued forever without counting; it now fails once retry_count reaches 3. - Any "unusual_activity" spelling is terminal; a bare code no longer falls into the 10x reCAPTCHA retry loop. - POST /api/flow/clear-hijack clears the file too; /api/flow/status reports the hold's reason. Takes the persistent-hold and bounded-retry ideas of crisng95#68 onto the current batch transport. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(flow): keep the unusual-activity hold across restarts, bound hijack retries
feat(image): add Nano Banana 2.1 (BELUGA), retire NARWHAL from the NANO_BANANA_2 nickname
feat(muse2api): send entity reference images with scene images
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs: account-safety hold and BELUGA image model
Merge the full upstream history with fork changes, resolving overlapping code in favor of upstream and restoring regression-tested Flow API features. Preserve production remote-worker changes separately.
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.
Goal
Bring the fork's
mainup to upstreamcrisng95/flowkit@19cb87dwithout losing the fork's existing 39 commits and its self-hosted Flow API work.This is an integration candidate, not a production deployment. Merge commit
efc953chas both upstream19cb87dand fork7be6093as parents.Integration and compatibility fixes
p0UkFb) and the/api/flow/export-video/check-export-statusAPIs.get_credits(refresh=...)) and ensured an unavailable account balance is not reported as zero.USE_BATCH_RPC.docs/FORK_SYNC.mdto describe safe separation from production.FLOW_BROWSER_BACKEND=playwright_ui), with fresh-upload picker caching. Standard extension transport stays the default.flow_poll.pyfor both;POST /api/flow/check-statussupportsmode=export; the oldcheck-export-statusandcheck-upscale-statusroutes are retained as compatibility aliases. Project-less exports now resolve the leased session project.Validation
tests/unitsuite (excludingtest_youtube.py; optionalgoogleapiclientis missing from the production host's existing Python venv).agent.main.app, generated OpenAPI successfully, and verified 101 API paths, including export, credits, upscale and upstream routes.node --checkfor extension JS, andgit diff --checkpassed.64adb1d: Python 3.10 and 3.13 both passed (run 40726928013). The runner workflow now skips preinstalled ffmpeg/fonts and bounds apt setup; same correction was proposed upstream in PR #82.Deployment safety / deliberately deferred
/opt/flowkitcheckout directly; it has 12 modified tracked files and local untracked source/runtime data.